Брзо рутирање и NAT во Linux

Како што се исцрпуваат IPv4 адресите, многу телекомуникациски оператори се соочуваат со потребата да им овозможат на своите клиенти пристап до мрежа користејќи превод на адреси. Во оваа статија ќе ви кажам како можете да ги добиете перформансите на NAT со степен на носач на серверите за стоки.

Малку историја

Темата за исцрпување на адресниот простор на IPv4 повеќе не е нова. Во одреден момент, списоците на чекање се појавија во RIPE, потоа се појавија размени на кои се тргуваа блокови на адреси и беа склучени договори за нивно закуп. Постепено, телекомуникациските оператори почнаа да обезбедуваат услуги за пристап до Интернет користејќи превод на адреса и пристаниште. Некои не успеаја да добијат доволно адреси за да издадат „бела“ адреса на секој претплатник, додека други почнаа да заштедуваат пари одбивајќи да купуваат адреси на секундарниот пазар. Производителите на мрежна опрема ја поддржаа оваа идеја, бидејќи оваа функционалност обично бара дополнителни модули за продолжување или лиценци. На пример, во линијата MX рутери на Juniper (освен најновите MX104 и MX204), можете да извршите NAPT на посебна MS-MIC сервисна картичка, Cisco ASR1k бара лиценца CGN, Cisco ASR9k бара посебен модул A9K-ISM-100 и A9K-CGN лиценца -LIC за него. Во принцип, задоволството чини многу пари.

IPTables

Задачата за извршување на NAT не бара специјализирани компјутерски ресурси, таа може да се реши со процесори за општа намена, кои се инсталирани, на пример, во кој било домашен рутер. На скалата на телекомуникациски оператор, овој проблем може да се реши со користење на сервери за стоки што работат на 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 на скалата на телекомуникацискиот оператор, неопходно е да се прилагодат временските прекини, бидејќи со стандардните вредности големината на табелата за превод брзо ќе порасне до катастрофални вредности. Подолу е пример за поставките што ги користев на моите сервери:

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

Исто така, потребно е да се зголеми бројот на корпи за хаш-табелата што ги складира сите емитувања (ова е опција во модулот 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. Напишани се многу написи на оваа тема, се одржаа многу различни говори и се појавуваат комерцијални производи (на пример, SKAT од VasExperts). Но, со оглед на ограничените програмски ресурси на телекомуникациските оператори, доста е проблематично да креирате каков било „производ“ врз основа на овие рамки самостојно. Ќе биде многу потешко да се работи со такво решение во иднина, особено ќе треба да се развијат дијагностички алатки. На пример, стандардниот tcpdump со DPDK нема да работи исто така и нема да ги „гледа“ пакетите испратени назад до жиците со помош на XDP. Среде сите разговори за нови технологии за излез на препраќање пакети до корисничкиот простор, тие останаа незабележани извештаи и Член Пабло Неира Ајусо, одржувач на iptables, за развојот на исфрлање на проток во nftables. Ајде внимателно да го разгледаме овој механизам.

Главната идеја е дека ако рутерот префрлил пакети од една сесија во двете насоки на протокот (TCP сесијата отишла во состојба ESTABLISHED), тогаш нема потреба да се пренесуваат следните пакети од оваа сесија низ сите правила на заштитен ѕид, бидејќи сите овие проверки сепак ќе завршат со трансфер на пакетот понатаму на рутирање. И ние всушност не треба да избираме рута - веќе знаеме до кој интерфејс и до кој домаќин треба да испратиме пакети во рамките на оваа сесија. Останува само да се складираат овие информации и да се користат за рутирање во рана фаза на обработка на пакети. При извршување на NAT, потребно е дополнително да се складираат информации за промените во адресите и портите преведени од модулот nf_conntrack. Да, се разбира, во овој случај разни полицајци и други информации и статистички правила во iptables престануваат да работат, но во рамките на задачата на посебна постојана NAT или, на пример, граница, тоа не е толку важно, бидејќи службите се дистрибуираат низ уредите.

Конфигурација

За да ја користиме оваа функција ни треба:

  • Користете свежо јадро. И покрај фактот што самата функционалност се појави во кернелот 4.16, долго време беше многу „сурова“ и редовно предизвикуваше паника во кернелот. Сè се стабилизираше околу декември 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
        }
}

Со испуштање на проток, тоа е малку покомплицирано, но сосема разбирливо:

#! /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 има огромна резерва за перформанси. Во моментов, овој сервер обработува до 30 Gbit/s со 3Mpps и очигледно е способен да го исполни ограничувањето на физичката мрежа од 40 Gbps, додека има бесплатни ресурси на процесорот.

Се надевам дека овој материјал ќе биде корисен за мрежните инженери кои се обидуваат да ги подобрат перформансите на нивните сервери.

Извор: www.habr.com

Додадете коментар