Хуткі роўтынг і NAT у Linux

Па меры вычарпання адрасоў IPv4 многія аператары сувязі сутыкнуліся з неабходнасцю арганізоўваць доступ сваіх кліентаў у сетку з дапамогай трансляцыі адрасоў. У гэтым артыкуле я раскажу, як можна атрымаць прадукцыйнасць узроўня Carrier Grade NAT на commodity серверах.

Трохі гісторыі

Тэма вычарпання адраснай прасторы IPv4 ужо не новая. У нейкі момант у RIPE з'явіліся чэргі чакання (waiting list), затым узніклі біржы, на якіх гандлявалі блокамі адрасоў і заключаліся здзелкі па іх арэндзе. Паступова аператары сувязі пачалі прадастаўляць паслугі доступу ў Інтэрнет з дапамогай трансляцыі адрасоў і партоў. Хтосьці не паспеў атрымаць дастаткова адрасоў, каб выдаць "белы" адрас кожнаму абаненту, а хтосьці пачаў эканоміць сродкі, адмовіўшыся ад пакупкі адрасоў на другасным рынку. Вытворцы сеткавага абсталявання падтрымалі гэтую ідэю, т.я. гэты функцыянал звычайна патрабуе дадатковых модуляў пашырэння ці ліцэнзій. Напрыклад, у Juniper у лінейцы маршрутызатараў MX (акрамя апошніх MX104 і MX204) выконваць NAPT можна на асобнай сэрвіснай карце MS-MIC, на Cisco ASR1k патрабуецца ліцэнзія СGN license, на Cisco ASR9k – асобны модуль A9K-ISM-100 і ліцэнзія A9K-CG -LIC да яго. Увогуле, задавальненне каштуе немалых грошай.

IPTables

Задача выканання NAT не патрабуе спецыялізаваных вылічальных рэсурсаў, яе ў стане вырашаць працэсары агульнага прызначэння, якія ўсталяваны, напрыклад, у любым хатнім роўтары. У маштабах аператара сувязі гэтую задачу можна вырашыць выкарыстоўваючы commodity серверы пад кіраваннем FreeBSD (ipfw/pf) ці GNU/Linux (iptables). Разглядаць FreeBSD не будзем, т.я. я даўнавата адмовіўся ад выкарыстання гэтай АС, так што спынімся на GNU/Linux.

Уключыць трансляцыю адрасоў зусім не складана. Для пачатку неабходна прапісаць правіла ў iptables у табліцу nat:

iptables -t nat -A POSTROUTING -s 100.64.0.0/10 -j SNAT --to <pool_start_addr>-<pool_end_addr> --persistent

Аперацыйная сістэма загрузіць модуль nf_conntrack, які будзе сачыць за ўсімі актыўнымі злучэннямі і выконваць неабходныя пераўтварэнні. Тут ёсць некалькі тонкасцей. Па-першае, паколькі гаворка ідзе аб NAT у маштабах аператара сувязі, то неабходна падкруціць timeout'ы, таму што са значэннямі па змаўчанні памер табліцы трансляцый дастаткова хутка вырасце да катастрафічных значэнняў. Ніжэй прыклад налад, якія я выкарыстоўваў на сваіх серверах:

net.ipv4.ip_forward = 1
net.ipv4.ip_local_port_range = 8192 65535

net.netfilter.nf_conntrack_generic_timeout = 300
net.netfilter.nf_conntrack_tcp_timeout_syn_sent = 60
net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 60
net.netfilter.nf_conntrack_tcp_timeout_established = 600
net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 60
net.netfilter.nf_conntrack_tcp_timeout_close_wait = 45
net.netfilter.nf_conntrack_tcp_timeout_last_ack = 30
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 120
net.netfilter.nf_conntrack_tcp_timeout_close = 10
net.netfilter.nf_conntrack_tcp_timeout_max_retrans = 300
net.netfilter.nf_conntrack_tcp_timeout_unacknowledged = 300
net.netfilter.nf_conntrack_udp_timeout = 30
net.netfilter.nf_conntrack_udp_timeout_stream = 60
net.netfilter.nf_conntrack_icmpv6_timeout = 30
net.netfilter.nf_conntrack_icmp_timeout = 30
net.netfilter.nf_conntrack_events_retry_timeout = 15
net.netfilter.nf_conntrack_checksum=0

І па-другое, паколькі па змаўчанні памер табліцы трансляцый не разлічаны на працу ва ўмовах аператара сувязі, яго неабходна павялічыць:

net.netfilter.nf_conntrack_max = 3145728

Таксама неабходна павялічыць і колькасць buckets для хэш-табліцы, якая захоўвае ўсе трансляцыі (гэта опцыя модуля nf_conntrack):

options nf_conntrack hashsize=1572864

Пасля гэтых няхітрых маніпуляцый атрымліваецца суцэль якая працуе канструкцыя, якая можа трансляваць вялікую колькасць кліенцкіх адрасоў у пул вонкавых. Аднак, прадукцыйнасць гэтага рашэння вымушае жадаць лепшага. У сваіх першых спробах выкарыстання GNU/Linux для NAT (прыкладна 2013) я змог атрымаць прадукцыйнасць каля 7Gbit/s пры 0.8Mpps на адзін сервер (Xeon E5-1650v2). З таго часу ў сеткавым стэку ядра GNU/Linux было зроблена шмат розных аптымізацый, прадукцыйнасць аднаго сервера на тым жа жалезе вырасла практычна да 18-19 Gbit/s пры 1.8-1.9 Mpps (гэта былі гранічныя значэнні), але запатрабаванне ў аб'ёме трафіку, апрацоўванага адным серверам, расла нашмат хутчэй. У выніку былі выпрацаваны схемы балансавання нагрузкі на розныя серверы, але ўсё гэта павялічыла складанасць наладкі, абслугоўвання і падтрымання якасці паслуг.

Табліцы NFT

Цяпер модным напрамкам у праграмным "перакладанні пакуначкаў" з'яўляецца выкарыстанне DPDK і XDP. На гэтую тэму напісана куча артыкулаў, зроблена шмат розных выступаў, з'яўляюцца камерцыйныя прадукты (напрыклад, Скат ад VasExperts). Але ва ўмовах абмежаваных рэсурсаў праграмістаў у аператараў сувязі, пілаваць самастойна якое-небудзь "падзел" на базе гэтых фрэймворкаў даволі праблематычна. Эксплуатаваць такое рашэнне ў далейшым будзе нашмат складаней, у прыватнасці, давядзецца распрацоўваць інструменты дыягностыкі. Напрыклад, штатны tcpdump з DPDK проста так не запрацуе, ды і пакеты, адпраўленыя назад у правады з дапамогай XDP, ён не "ўбачыць". На фоне ўсіх размоў пра новыя тэхналогіі вываду форвардынгу пакетаў у user-space, незаўважанымі засталіся. даклады и артыкулы Pablo Neira Ayuso, меінтэйнера iptables, пра распрацоўку flow offloading у nftables. Давайце разгледзім гэты механізм падрабязней.

Асноўная ідэя заключаецца ў тым, што калі роўтар прапусціў пакеты адной сесіі ў абодва бакі патоку (TCP сесія перайшла ў стан ESTABLISHED), то няма неабходнасці прапускаць наступныя пакеты гэтай сесіі праз усе правілы firewall, т.я. усе гэтыя праверкі ўсё роўна скончацца перадачай пакета далей у роўтынг. Ды і ўласна выбар маршруту выконваць не трэба - мы ўжо ведаем у які інтэрфейс і якому хасту трэба пераслаць пакеты межах гэтай сесіі. Застаецца толькі захаваць гэтую інфармацыю і выкарыстоўваць яе для маршрутызацыі на ранняй стадыі апрацоўкі пакета. Пры выкананні NAT неабходна дадаткова захаваць інфармацыю аб зменах адрасоў і партоў, пераўтвораных модулем nf_conntrack. Так, вядома, у гэтым выпадку перастаюць працаваць розныя полісеры і іншыя інфармацыйна-статыстычныя правілы ў iptables, але ў рамках задачы асобнага стаячага NAT ці, напрыклад, бордэра — гэта не так ужо важна, таму што сэрвісы размеркаваны па прыладах.

Канфігурацыя

Каб скарыстацца гэтай функцыяй нам трэба:

  • Выкарыстоўваць свежае ядро. Нягледзячы на ​​тое, што сам функцыянал з'явіўся яшчэ ў ядры 4.16, даволі доўга ён было вельмі волкі і рэгулярна выклікаў kernel panic. Стабілізавалася ўсё прыкладна ў снежні 2019 года, калі выйшлі LTS ядра 4.19.90 і 5.4.5.
  • Перапісаць правілы iptables у фармат nftables, выкарыстоўваючы дастаткова свежую версію nftables. Дакладна працуе ў версіі 0.9.0

Калі з першым пунктам усё ў прынцыпе зразумела, галоўнае не забыцца ўлучыць модуль у канфігурацыю пры зборцы (CONFIG_NFT_FLOW_OFFLOAD=m), то другі пункт патрабуе тлумачэнняў. Правілы nftables апісваюцца зусім не так, як у iptables. Дакументацыя раскрывае практычна ўсе моманты, таксама ёсць спецыяльныя канвертары правілаў з iptables у nftables. Таму я прывяду толькі прыклад наладкі NAT і flow offload. Невялікая легенда для прыкладу: , — гэта сеткавыя інтэрфейсы, праз якія праходзіць трафік, рэальна іх можа быць больш за два. , - пачатковы і канчатковы адрас дыяпазону "белых" адрасоў.

Канфігурацыя NAT вельмі простая:

#! /usr/sbin/nft -f

table nat {
        chain postrouting {
                type nat hook postrouting priority 100;
                oif <o_if> snat to <pool_addr_start>-<pool_addr_end> persistent
        }
}

З flow offload крыху складаней, але цалкам зразумела:

#! /usr/sbin/nft -f

table inet filter {
        flowtable fastnat {
                hook ingress priority 0
                devices = { <i_if>, <o_if> }
        }

        chain forward {
                type filter hook forward priority 0; policy accept;
                ip protocol { tcp , udp } flow offload @fastnat;
        }
}

Вось, уласна, і ўся настройка. Цяпер увесь TCP/UDP трафік будзе трапляць у табліцу fastnat і апрацоўвацца нашмат хутчэй.

Вынікі

Каб стала зразумела, наколькі гэта «нашмат хутчэй», я прыкладу скрыншот нагрузкі на два рэальных сервера, з аднолькавым начыннем (Xeon E5-1650v2), аднолькава настроеных, якія выкарыстоўваюць адно і тое ж ядро ​​Linux, але выконваюць NAT у iptables (NAT4) і ў nftables (NAT5).

Хуткі роўтынг і NAT у Linux

На скрыншоце няма графіка пакетаў у секунду, але ў профілі нагрузкі гэтых сервераў сярэдні памер пакета ў раёне 800 байт, таму значэнні даходзяць да 1.5Mpps. Як відаць, запас прадукцыйнасці ў сервера з nftables вялізны. На бягучы момант гэты сервер апрацоўвае да 30Gbit/s пры 3Mpps і відавочна здольны ўперціся ў фізічнае абмежаванне сеткі 40Gbps, маючы пры гэтым вольныя рэсурсы CPU.

Спадзяюся, гэты матэрыял будзе карысны сеткавым інжынерам, якія спрабуюць палепшыць прадукцыйнасць сваіх сервераў.

Крыніца: habr.com

Дадаць каментар