Định tuyến nhanh và NAT trong Linux

Khi địa chỉ IPv4 cạn kiệt, nhiều nhà khai thác viễn thông phải đối mặt với nhu cầu cung cấp cho khách hàng của họ quyền truy cập mạng bằng cách dịch địa chỉ. Trong bài viết này, tôi sẽ cho bạn biết cách bạn có thể đạt được hiệu suất NAT cấp nhà cung cấp trên các máy chủ thông thường.

Một chút lịch sử

Chủ đề cạn kiệt không gian địa chỉ IPv4 không còn mới nữa. Tại một thời điểm nào đó, danh sách chờ xuất hiện trong RIPE, sau đó các sàn giao dịch xuất hiện trên các khối địa chỉ được giao dịch và các giao dịch được ký kết để cho thuê chúng. Dần dần, các nhà khai thác viễn thông bắt đầu cung cấp dịch vụ truy cập Internet bằng cách sử dụng dịch thuật địa chỉ và cổng. Một số không quản lý được đủ địa chỉ để cấp địa chỉ “trắng” cho mỗi người đăng ký, trong khi những người khác bắt đầu tiết kiệm tiền bằng cách từ chối mua địa chỉ trên thị trường thứ cấp. Các nhà sản xuất thiết bị mạng ủng hộ ý tưởng này bởi vì chức năng này thường yêu cầu các mô-đun hoặc giấy phép mở rộng bổ sung. Ví dụ: trong dòng bộ định tuyến MX của Juniper (ngoại trừ MX104 và MX204 mới nhất), bạn có thể thực hiện NAPT trên thẻ dịch vụ MS-MIC riêng, Cisco ASR1k yêu cầu giấy phép CGN, Cisco ASR9k yêu cầu mô-đun A9K-ISM-100 riêng và giấy phép A9K-CGN -LIC cho anh ta. Nói chung, niềm vui tốn rất nhiều tiền.

IPBảng

Nhiệm vụ thực hiện NAT không yêu cầu tài nguyên máy tính chuyên dụng, nó có thể được giải quyết bằng các bộ xử lý đa năng, chẳng hạn như được cài đặt trong bất kỳ bộ định tuyến gia đình nào. Ở quy mô của một nhà khai thác viễn thông, vấn đề này có thể được giải quyết bằng cách sử dụng các máy chủ thông thường chạy FreeBSD (ipfw/pf) hoặc GNU/Linux (iptables). Chúng tôi sẽ không xem xét FreeBSD, bởi vì... Tôi đã ngừng sử dụng hệ điều hành này cách đây khá lâu, vì vậy chúng tôi sẽ sử dụng GNU/Linux.

Kích hoạt dịch địa chỉ không hề khó khăn chút nào. Trước tiên, bạn cần đăng ký quy tắc trong iptables trong bảng nat:

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

Hệ điều hành sẽ tải mô-đun nf_conntrack, mô-đun này sẽ giám sát tất cả các kết nối đang hoạt động và thực hiện các chuyển đổi cần thiết. Có một số sự tinh tế ở đây. Thứ nhất, vì chúng ta đang nói về NAT ở quy mô của một nhà khai thác viễn thông nên cần phải điều chỉnh thời gian chờ, vì với các giá trị mặc định, kích thước của bảng dịch sẽ nhanh chóng tăng lên đến các giá trị thảm khốc. Dưới đây là ví dụ về cài đặt tôi đã sử dụng trên máy chủ của mình:

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

Và thứ hai, vì kích thước mặc định của bảng dịch không được thiết kế để hoạt động trong điều kiện của nhà khai thác viễn thông nên cần phải tăng kích thước này:

net.netfilter.nf_conntrack_max = 3145728

Cũng cần tăng số lượng nhóm cho bảng băm lưu trữ tất cả các chương trình phát sóng (đây là một tùy chọn trong mô-đun nf_conntrack):

options nf_conntrack hashsize=1572864

Sau những thao tác đơn giản này, người ta sẽ thu được một thiết kế hoàn toàn hoạt động có thể dịch một số lượng lớn địa chỉ khách hàng sang một nhóm địa chỉ bên ngoài. Tuy nhiên, hiệu quả của giải pháp này còn nhiều điều đáng mong đợi. Trong lần thử đầu tiên sử dụng GNU/Linux cho NAT (khoảng năm 2013), tôi đã có thể đạt được hiệu suất khoảng 7Gbit/s ở tốc độ 0.8Mpps trên mỗi máy chủ (Xeon E5-1650v2). Kể từ thời điểm đó, nhiều tối ưu hóa khác nhau đã được thực hiện trong ngăn xếp mạng hạt nhân GNU/Linux, hiệu suất của một máy chủ trên cùng phần cứng đã tăng lên gần 18-19 Gbit/s ở tốc độ 1.8-1.9 Mpps (đây là những giá trị tối đa) , nhưng nhu cầu về lưu lượng truy cập được xử lý bởi một máy chủ tăng nhanh hơn nhiều. Do đó, các kế hoạch đã được phát triển để cân bằng tải trên các máy chủ khác nhau, nhưng tất cả điều này làm tăng độ phức tạp của việc thiết lập, duy trì và duy trì chất lượng dịch vụ được cung cấp.

LSNG

Ngày nay, một xu hướng thời thượng trong “túi chuyển số” phần mềm là sử dụng DPDK và XDP. Rất nhiều bài viết đã được viết về chủ đề này, nhiều bài phát biểu khác nhau đã được đưa ra và các sản phẩm thương mại đang xuất hiện (ví dụ: SKAT của VasExperts). Nhưng do nguồn lực lập trình hạn chế của các nhà khai thác viễn thông, việc tự mình tạo ra bất kỳ “sản phẩm” nào dựa trên các khuôn khổ này là khá khó khăn. Sẽ khó khăn hơn nhiều để vận hành một giải pháp như vậy trong tương lai, đặc biệt là các công cụ chẩn đoán sẽ phải được phát triển. Ví dụ: tcpdump tiêu chuẩn với DPDK sẽ không hoạt động như vậy và nó sẽ không “nhìn thấy” các gói được gửi trở lại dây bằng XDP. Giữa tất cả các cuộc thảo luận về công nghệ mới để xuất chuyển tiếp gói tới không gian người dùng, chúng không được chú ý. báo cáo и Điều Pablo Neira Ayuso, người bảo trì iptables, về sự phát triển của tính năng giảm tải dòng chảy trong nftables. Chúng ta hãy xem xét cơ chế này chi tiết hơn.

Ý tưởng chính là nếu bộ định tuyến chuyển các gói từ một phiên theo cả hai hướng của luồng (phiên TCP đã chuyển sang trạng thái THÀNH LẬP), thì không cần phải chuyển các gói tiếp theo của phiên này thông qua tất cả các quy tắc tường lửa, bởi vì tất cả các lần kiểm tra này sẽ vẫn kết thúc với việc gói được chuyển tiếp sang định tuyến. Và chúng tôi thực sự không cần phải chọn một tuyến đường - chúng tôi đã biết chúng tôi cần gửi các gói đến giao diện nào và máy chủ nào trong phiên này. Tất cả những gì còn lại là lưu trữ thông tin này và sử dụng nó để định tuyến ở giai đoạn đầu của quá trình xử lý gói. Khi thực hiện NAT, cần lưu trữ thêm thông tin về các thay đổi về địa chỉ và cổng được dịch bởi mô-đun nf_conntrack. Có, tất nhiên, trong trường hợp này, nhiều cảnh sát khác nhau và các quy tắc thông tin và thống kê khác trong iptables ngừng hoạt động, nhưng trong khuôn khổ nhiệm vụ của một NAT thường trực riêng biệt hoặc, ví dụ: biên giới, điều này không quá quan trọng, bởi vì các dịch vụ được phân phối giữa các thiết bị.

Cấu hình

Để sử dụng chức năng này chúng ta cần:

  • Sử dụng kernel mới. Mặc dù thực tế là bản thân chức năng này đã xuất hiện trong kernel 4.16, nhưng trong một thời gian khá dài, nó rất “thô” và thường xuyên gây ra sự hoảng loạn cho kernel. Mọi thứ ổn định vào khoảng tháng 2019 năm 4.19.90, khi hạt nhân LTS 5.4.5 và XNUMX được phát hành.
  • Viết lại các quy tắc iptables ở định dạng nftables bằng phiên bản nftables khá gần đây. Hoạt động chính xác trong phiên bản 0.9.0

Nếu mọi thứ về nguyên tắc đều rõ ràng ở điểm đầu tiên, thì điều chính là đừng quên đưa mô-đun vào cấu hình trong quá trình lắp ráp (CONFIG_NFT_FLOW_OFFLOAD=m), thì điểm thứ hai yêu cầu giải thích. Các quy tắc của nftables được mô tả hoàn toàn khác so với trong iptables. Tài liệu tiết lộ gần như tất cả các điểm, cũng có những điểm đặc biệt bộ chuyển đổi quy tắc từ iptables đến nftables. Vì vậy, tôi sẽ chỉ đưa ra một ví dụ về thiết lập NAT và giảm tải luồng. Một truyền thuyết nhỏ chẳng hạn: , - đây là các giao diện mạng mà lưu lượng truy cập đi qua; trong thực tế có thể có nhiều hơn hai giao diện mạng. , - địa chỉ bắt đầu và kết thúc của dãy địa chỉ “trắng”.

Cấu hình NAT rất đơn giản:

#! /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
        }
}

Với việc giảm tải dòng chảy thì phức tạp hơn một chút, nhưng khá dễ hiểu:

#! /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;
        }
}

Trên thực tế, đó là toàn bộ thiết lập. Bây giờ tất cả lưu lượng TCP/UDP sẽ rơi vào bảng fastnat và được xử lý nhanh hơn nhiều.

Những phát hiện

Để làm rõ việc này “nhanh hơn bao nhiêu”, tôi sẽ đính kèm ảnh chụp màn hình tải trên hai máy chủ thực, có cùng phần cứng (Xeon E5-1650v2), được cấu hình giống hệt nhau, sử dụng cùng nhân Linux, nhưng thực hiện NAT trong iptables (NAT4) và trong nftables (NAT5).

Định tuyến nhanh và NAT trong Linux

Không có biểu đồ số lượng gói mỗi giây trong ảnh chụp màn hình, nhưng trong cấu hình tải của các máy chủ này, kích thước gói trung bình là khoảng 800 byte, vì vậy các giá trị có thể lên tới 1.5Mpps. Như bạn có thể thấy, máy chủ có nftables có dự trữ hiệu suất rất lớn. Hiện tại, máy chủ này xử lý tốc độ lên tới 30Gbit/s ở tốc độ 3Mpps và rõ ràng có khả năng đáp ứng giới hạn mạng vật lý là 40Gbps, đồng thời có tài nguyên CPU miễn phí.

Tôi hy vọng tài liệu này sẽ hữu ích cho các kỹ sư mạng đang cố gắng cải thiện hiệu suất máy chủ của họ.

Nguồn: www.habr.com

Thêm một lời nhận xét