Skip to main content

5.1. Networking: Cấu hình IPv4/IPv6, network service, bridge và bonding

Mục lục​


1. IPv4, IPv6 và CIDR notation​

Một thiết bị muốn trao đổi dữ liệu qua mạng thì phải có địa chỉ IP. IP viết tắt của Internet Protocol, và có hai phiên bản đang cùng tồn tại: IPv4 và IPv6. Chữ V trong tên là version.

Ở phiên bản 4, địa chỉ gồm bốn số, mỗi số nhận giá trị từ 0 tới 255. Giới hạn 255 không phải con số tùy ý: bên trong, máy tính dùng 8 bit cho mỗi số, và 8 bit biểu diễn được đúng dải 0 tới 255. Tám bit toàn 0 là số 0, tám bit toàn 1 là 255.

Vì vậy một địa chỉ như 192.168.1.101 thực chất là 32 bit nhị phân xếp liền nhau. Cách đọc nhị phân đó là chìa khóa để hiểu ký hiệu tiếp theo.

Đôi khi địa chỉ IP xuất hiện kèm một hậu tố gạch chéo, kiểu 192.168.1.101/24. Ký hiệu này gọi là CIDR notation, viết tắt của Classless Inter-Domain Routing. Số 24 cho biết 24 bit đầu của địa chỉ là prefix của network, tức địa chỉ của chính mạng đó. Nhìn sang dạng nhị phân sẽ thấy ngay 24 bit đầu trùng khớp với ba số đầu tiên, nên 192.168.1 là network prefix, còn số cuối 101 chỉ đúng một thiết bị trên mạng đó.

💡 Hình dung: địa chỉ IP giống số điện thoại có mã quốc gia. Gọi sang Ý phải bấm tiền tố +39 rồi mới tới dãy số của người cần gọi. Prefix /24 chính là phần mã quốc gia đó: ai cùng mã thì ở cùng một mạng, phần còn lại mới phân biệt từng máy.

IPv4 CIDR prefix and IPv6 notation192.168.1.101/24 in decimal and in binary192110000001681010100010000000110101100101Network prefix, the first 24 bitsHost partIPv6, 128 bits in 8 groups of hex digits2001:0db8:0000:0000:0000:ff00:0042:8329/64shortened form 2001:db8::ff00:42:8329/64Leading zeros are dropped, one run of zero groups becomes two colonsA prefix that is a multiple of 8 lines up with whole groups of digits

IPv6 đi theo hướng khác. Địa chỉ dài 128 bit thay vì 32 bit, và có ba điểm khác dễ nhận ra ngay:

  • Tám nhóm số thay vì bốn nhóm như IPv4.
  • Các nhóm viết ở hệ hexadecimal, không phải decimal. Hệ này có 16 chữ số: 0 tới 9 rồi A, B, C, D, E, F. Chữ A tương đương số 10 trong hệ thập phân, B là 11, C là 12, cho tới F là 15. Nhờ vậy FFFF tương đương 65.535 ở hệ thập phân, và toàn bit 1 ở hệ nhị phân.
  • Các nhóm phân cách bằng dấu hai chấm, không phải dấu chấm.

Địa chỉ IPv6 dài nên thường được viết rút gọn theo hai bước: bỏ hết các số 0 ở đầu mỗi nhóm (0db8 thành db8), rồi thu một dãy nhóm 0 liên tiếp thành hai dấu hai chấm liền nhau. IPv6 cũng dùng được CIDR notation, ví dụ hậu tố /64 nghĩa là 64 bit đầu là network prefix.

Với những prefix là bội số của 8 thì việc đối chiếu còn dễ. Một prefix lẻ như /20 thì không còn trùng khớp với ba số đầu của địa chỉ IPv4 nữa. Lúc đó cách nhanh nhất là tra một CIDR calculator hoặc subnet calculator trên mạng, thay vì tự tính nhầm rồi cấu hình sai cả dải mạng.


2. Đọc cấu hình mạng hiện tại bằng lệnh ip​

Lệnh ip trả lời được gần như mọi câu hỏi về cấu hình mạng hiện tại của máy. Bắt đầu bằng danh sách thiết bị mạng, trong thuật ngữ Linux gọi là network interface:

ip link

# Output (minh họa):
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
link/ether 08:00:27:ab:cd:ef brd ff:ff:ff:ff:ff:ff
3: enp0s8: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 08:00:27:11:22:33 brd ff:ff:ff:ff:ff:ff

Một số interface ứng với thiết bị thật như card Ethernet hay card wireless, số khác là thiết bị ảo. lo ở đầu danh sách là loopback interface, hoàn toàn ảo, dùng khi hệ thống cần kết nối tới chính nó: một chương trình muốn nói chuyện với database chạy cùng máy sẽ đi tới 127.0.0.1 qua thiết bị này. enp0s3 thì ngược lại, đại diện cho một card Ethernet thật.

Để xem địa chỉ IP đã gán cho từng interface:

ip address
ip addr
ip a

Ba cách viết cho cùng một kết quả. Output mặc định khá rối và khó dò, nên nên thêm tùy chọn màu -c:

ip -c a

Vị trí của -c có ý nghĩa: đặt ở giữa, ngay sau ip. Đặt ở cuối lệnh sẽ không có tác dụng. Trong output, phần cần quan tâm là các địa chỉ IPv4 và IPv6 của từng interface. Một interface đang ở trạng thái down nghĩa là chưa hoạt động, và thường cũng chưa có IP nào được cấu hình.

Bật interface và gán IP tạm thời​

Kích hoạt một interface đang down:

sudo ip link set dev enp0s8 up

Cú pháp của lệnh ip đi theo một mạch khá dễ nhớ: trước tiên khai báo muốn làm việc với đối tượng link, rồi set để đặt thuộc tính, rồi dev cùng tên thiết bị cần sửa, cuối cùng là up để nói rõ ý định kích hoạt.

Kiểm tra lại bằng ip -c a sẽ thấy interface đã up, và thường tự cấu hình luôn một địa chỉ IPv6 cho mình. Gán thêm địa chỉ IPv4 theo đúng mạch cú pháp đó: đối tượng là address, hành động là add, rồi IP kèm dải CIDR, cuối cùng là tên thiết bị.

sudo ip address add 10.0.0.9/24 dev enp0s8
sudo ip address add 2001:db8::abcd/64 dev enp0s8

Một network interface giữ được nhiều IP cùng lúc, nên lệnh trên không ghi đè địa chỉ cũ. Muốn bỏ một địa chỉ thì đổi add thành del, và muốn tắt thiết bị thì đổi up thành down:

sudo ip address del 10.0.0.9/24 dev enp0s8
sudo ip link set dev enp0s8 down

Vấn đề của cách này nằm ở chỗ mọi thay đổi chỉ tồn tại trong RAM: reboot server là mất sạch. Vì vậy ip chủ yếu dùng để thăm dò cấu hình hiện tại và thử nhanh một thiết lập mới, chứ không phải để cấu hình lâu dài.


3. Cấu hình mạng vĩnh viễn bằng netplan​

Cách làm cho cấu hình sống sót qua reboot phụ thuộc vào từng hệ điều hành. Mỗi bản phân phối có bộ công cụ riêng, và bộ công cụ đó còn thay đổi giữa các major version. Ubuntu hiện dùng netplan: một nhóm utility đọc file cấu hình rồi gửi chỉ thị xuống các công cụ mạng bên dưới. Trên Ubuntu Server Edition, netplan gửi chỉ thị cho network daemon của systemd, tên là systemd-networkd.

How netplan applies network settingsYAML config/etc/netplan/*.yaml99-mysettings.yamlnetplanreads YAML in ordersudo netplan trysystemd-networkdrenderer on UbuntuServer EditionNetwork interfacesIP, route, DNS setip a to verifynetplan try reverts the change if Enter is not pressed before the countdown endsnetplan apply has no rollback, a bad config can lock SSH out of the server

Xem toàn bộ cấu hình netplan đang có hiệu lực:

sudo netplan get

# Output (minh họa):
network:
version: 2
ethernets:
enp0s3:
dhcp4: true

Thiết lập dhcp4: true khiến thiết bị enp0s3 đi hỏi một DHCP server để lấy thiết lập mạng cho mình. Số 4 ở đây chỉ phần IPv4. DHCP server rất hay được dùng để tự cấu hình IP cho thiết bị trên một mạng: điện thoại nối Wi-Fi vào router ở nhà cũng đang hỏi DHCP daemon chạy trên router xem nên tự đặt IP nào.

Viết một file netplan mới​

Các file cấu hình netplan nằm trong thư mục /etc/netplan. Xem nội dung chúng cần quyền root:

ls /etc/netplan
sudo cat /etc/netplan/50-cloud-init.yaml

Bỏ sudo sẽ nhận permission denied. Nội dung đọc được chính là phần đã thấy ở netplan get phía trên.

Sửa thẳng file có sẵn cũng được, nhưng gọn hơn là tạo một file riêng cho thiết bị khác. Dùng file cũ làm template, rồi tạo file mới cho enp0s8:

sudo vim /etc/netplan/99-mysettings.yaml

Tiền tố số ở tên file là quy ước chuẩn, không phải thói quen cá nhân: netplan xử lý các file YAML trong thư mục này theo thứ tự alphabet, nên file bắt đầu bằng 99 sẽ được xử lý sau cùng, không có số nào lớn hơn trong thư mục để chen vào sau. Thao tác với vim xem thêm ở Part 2.3: Tìm file, xử lý text stream và vi.

Nội dung file sau khi sửa tên interface, tắt DHCP cho cả IPv4 lẫn IPv6, rồi gán địa chỉ tĩnh:

network:
version: 2
ethernets:
enp0s8:
dhcp4: false
dhcp6: false
addresses:
- 10.0.0.9/24
- 2001:db8::abcd/64

Phần dễ sai nhất ở đây là định dạng, cụ thể là số khoảng trắng đứng trước mỗi dòng. Thụt lề trong YAML quyết định quan hệ cha con: ethernets là cha của khối bên dưới nó, rồi enp0s8 là cha của các thiết lập dhcp4, dhcp6, addresses. Nhờ thụt lề đó netplan mới biết thuộc tính nào áp cho đối tượng nào.

Vim còn tự thêm hai khoảng trắng khi nhấn Enter, có lúc giúp đúng, có lúc lại thụt sai, nên vẫn phải tự soát lại từng dòng khi sửa file YAML.

Dấu - đứng trước mỗi địa chỉ đánh dấu đây là một phần tử của list. Bỏ dấu - đi thì netplan không phân biệt được đâu là phần tử, đâu là thuộc tính của phần tử: mỗi địa chỉ IP còn có thể mang thêm thuộc tính riêng viết ở dòng dưới, mà các dòng đó cũng thụt lề giống nhau. Có dấu - thì vị trí bắt đầu của từng phần tử trở nên rõ ràng, và các dòng không có dấu - ngay bên dưới được hiểu là thuộc tính của phần tử đó.

Áp dụng cấu hình với try thay vì apply​

Áp dụng ngay bằng sudo netplan apply thì được, nhưng nếu cấu hình sai thì mất luôn kết nối tới server. netplan có một lệnh an toàn hơn, cho một khoảng thời gian để rollback:

sudo netplan try

Lệnh này hiện một đồng hồ đếm ngược. Không nhấn Enter để xác nhận thì mọi thay đổi về mạng được trả lại trạng thái trước đó. Mất kết nối tới server vì cấu hình sai thì chỉ cần đợi hai phút rồi đăng nhập lại, thiết lập đã tự được revert. Thu ngắn cửa sổ chờ bằng --timeout, và hủy giữa chừng bằng Ctrl+C:

sudo netplan try --timeout 30

netplan cũng sẽ cảnh báo nếu quyền file quá mở:

sudo netplan try

# Output (rút gọn):
** (process:2104): WARNING **: Permissions for /etc/netplan/99-mysettings.yaml are too open. Netplan configuration should NOT be accessible by others.

Đây chỉ là warning và không chặn việc áp dụng cấu hình, nhưng dọn nó đi mất một lệnh:

sudo chmod 600 /etc/netplan/99-mysettings.yaml

Kiểm tra lại bằng ip -c a sẽ thấy thiết bị đã mang IPv4 và IPv6 mới, và cũng đã ở trạng thái up: netplan kích hoạt luôn interface giúp. Reboot server thì cấu hình được áp lại tự động, nên nó tồn tại cho tới khi có người sửa file. Chạy netplan get thêm một lần sẽ in ra toàn bộ cấu hình gộp từ cả file YAML cũ và file mới, xem được tất cả trong một chỗ.

Tra cứu từ khóa YAML của netplan​

File YAML của netplan dễ đọc nhưng khó viết: khó nhất là đoán ra đúng từ khóa cho từng thiết lập. Hai nguồn tra cứu sẵn có trên máy:

  • man netplan chứa khá nhiều ví dụ. Mở manual rồi nhấn / để tìm, ví dụ /address label dẫn tới đoạn minh họa cách khai một địa chỉ IP, hay /default routes rồi nhấn N để nhảy tới lần xuất hiện tiếp theo, dẫn tới đoạn ví dụ default route có thêm vài thiết lập như metric.
  • Thư mục /usr/share/doc có trên hầu hết bản cài Linux, chứa tài liệu bổ sung của các package. Với netplan, nó có sẵn một bộ file cấu hình mẫu.
ls /usr/share/doc/netplan/examples

# Output (rút gọn):
bonding.yaml bridge.yaml dhcp.yaml static.yaml ...

Hai file đáng xem trước là dhcp.yaml, minh họa một interface Ethernet lấy IP qua DHCP, và static.yaml, minh họa một interface Ethernet với thiết lập mạng tĩnh.


4. Name server, network route và file hosts​

Cùng file YAML đó còn khai được vài thiết lập hữu dụng khác. Thêm vào, nhớ thụt lề hai khoảng trắng so với dòng enp0s8 phía trên để đánh dấu đây là thiết lập của chính thiết bị đó:

network:
version: 2
ethernets:
enp0s8:
dhcp4: false
dhcp6: false
addresses:
- 10.0.0.9/24
- 2001:db8::abcd/64
nameservers:
addresses:
- 8.8.4.4
- 8.8.8.8
routes:
- to: 192.168.0.0/24
via: 10.0.0.100
- to: default
via: 10.0.0.1

Khối nameservers khai hai name server của Google. Name server, còn gọi là DNS server, có việc là dịch tên domain thành địa chỉ IP: gõ kodekloud.com vào trình duyệt thì máy tính không tự biết domain đó ứng với IP nào, nên phải hỏi một name server.

Khối routes khai hai network route, và ở đây dấu - mới phát huy hết tác dụng. Dòng via không có dấu - đứng trước, nên netplan hiểu nó là thuộc tính của phần tử ngay trên.

  • Route đầu nói rằng muốn tới bất kỳ IP nào trong mạng 192.168.0.0/24 thì liên hệ server tại 10.0.0.100. Server đó làm trung gian, chuyển dữ liệu từ mạng này sang mạng kia.
  • Route thứ hai là default route, dùng khi máy không tìm được route nào phù hợp trong những gì nó đang có. Với cấu hình hiện tại, máy không biết đi đường nào để gửi dữ liệu tới một IP như 20.20.20.20, nên nó rơi về default route và nhờ server tại 10.0.0.1 chuyển tiếp hộ.

Server ở default route thường được gọi là gateway, vì nó là cánh cửa đi ra thế giới bên ngoài. Router ở nhà cũng đang làm đúng việc đó khi đưa dữ liệu từ mạng nội bộ ra mọi mạng khác trên thế giới.

Sai sót thường gặp khi sửa file này là quên dấu hai chấm sau routes, và netplan sẽ báo lỗi YAML ngay khi áp dụng. Sau khi sudo netplan try chấp nhận thay đổi, kiểm tra route bằng:

ip route

# Output (minh họa):
default via 10.0.0.1 dev enp0s8 proto static
10.0.0.0/24 dev enp0s8 proto kernel scope link src 10.0.0.9
192.168.0.0/24 via 10.0.0.100 dev enp0s8 proto static

Default route qua gateway 10.0.0.1 cho thiết bị enp0s8 đã có mặt, cùng route qua gateway 10.0.0.100.

DNS resolver cho riêng interface và cho toàn máy​

Kiểm tra các resolver đang được cấu hình:

resolvectl status

Output cho thấy resolver 8.8.8.8 chỉ áp cho thiết bị enp0s8, vì nó được khai trong khối của thiết bị đó. Có lúc lại cần resolver áp cho mọi thiết bị mạng của máy. Lúc đó khai ở chỗ khác, trong file /etc/systemd/resolved.conf:

sudo vim /etc/systemd/resolved.conf

Tìm dòng DNS, bỏ dấu # ở đầu để uncomment, rồi điền danh sách server cách nhau bằng khoảng trắng:

DNS=1.1.1.1 9.9.9.9

Lưu file rồi restart resolver daemon của systemd:

sudo systemctl restart systemd-resolved

Chạy lại resolvectl status sẽ thấy resolver mới đã áp ở phạm vi global. Muốn output gọn hơn, ít chi tiết hơn, có một lệnh riêng:

resolvectl dns

# Output (minh họa):
Global: 1.1.1.1 9.9.9.9
Link 2 (enp0s3):
Link 3 (enp0s8): 8.8.4.4 8.8.8.8

Quản lý service bằng systemctl nói chi tiết ở Part 3.1: Boot, systemd service và bash script.

Đặt tên cho máy nội bộ qua file hosts​

DNS resolver xử lý được các domain như kodekloud.com, nhưng còn những hostname đơn giản của máy trong mạng nội bộ thì sao? Có một database server quanh đây mà không ai nhớ nổi IP của nó, trong khi một cái tên như dbserver thì dễ nhớ hơn nhiều. Việc này nằm ở file /etc/hosts:

sudo vim /etc/hosts

Thêm một dòng gồm IP, khoảng trắng, rồi hostname:

127.0.123.123 dbserver
1.2.3.4 example.com

Dòng đầu nói với máy rằng hostname dbserver ứng với IP đó, kiểm tra được ngay:

ping dbserver

# Output (rút gọn):
PING dbserver (127.0.123.123) 56(84) bytes of data.
64 bytes from dbserver (127.0.123.123): icmp_seq=1 ttl=64 time=0.031 ms

Dòng thứ hai khai cả một hostname phức tạp hơn, lừa cho hệ thống tin rằng example.com có IP 1.2.3.4. Đây là cách phổ biến để test một website trên máy local trước khi thật sự đưa nó lên host online.


5. Kiểm tra và quản lý network service​

Phần lớn server đều có vài service xử lý dữ liệu mạng theo cách này hay cách khác. SSH daemon là một ví dụ: nó chạy ở background, chờ kết nối mạng đi vào để cho người dùng đăng nhập từ xa. Câu hỏi vận hành thường trực là chương trình nào đang chờ kết nối, và chờ ở port nào.

Có hai utility làm việc này: ss và netstat. ss là công cụ hiện đại hơn; netstat cũ hơn và có thể bị loại khỏi các phiên bản hệ điều hành Linux sau này.

sudo ss -ltunp

# Output (minh họa):
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
udp UNCONN 0 0 127.0.0.53%lo:53 0.0.0.0:* users:(("systemd-resolve",pid=612,fd=14))
tcp LISTEN 0 4096 127.0.0.1:3306 0.0.0.0:* users:(("mariadbd",pid=1021,fd=21))
tcp LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=679,fd=3))
tcp LISTEN 0 128 [::]:22 [::]:* users:(("sshd",pid=679,fd=4))

Ý nghĩa từng tùy chọn:

  • -l liệt kê những gì đang listen, tức đang chờ dữ liệu mạng đi vào và sẵn sàng nhận kết nối.
  • -t liệt kê kết nối TCP.
  • -u liệt kê kết nối UDP.
  • -n in giá trị dạng số. Chạy ss -ltup mà bỏ -n thì output hiện tên service thay cho số port; có -n mới thấy đúng số port, ví dụ port 22 nơi SSH daemon đang chờ kết nối.
  • -p cho biết process nào gắn với từng dòng output.

Bình thường ss không cần quyền root. Riêng khi có -p thì phải thêm sudo, vì cần quyền root mới xem được các process thuộc về root đang listen.

💡 Hình dung: cách nhớ năm chữ cái là đọc chúng thành một câu: Listening, TCP, UDP, Numeric, Process. Đổi thứ tự thành -tunlp thì đọc thành "tuna lips", cũng chỉ là năm chữ cái đó. Quên thì gõ ss --help cho nhanh.

Trong output, cột đáng đọc trước là Local Address and Port. Một dòng 127.0.0.1:3306 nghĩa là chương trình chỉ chờ kết nối từ chính hệ thống này, không nhận kết nối từ máy khác. Nhờ vậy một web server như Nginx chạy cùng máy vẫn nối được tới database MariaDB qua 127.0.0.1 port 3306, trong khi MariaDB vẫn nằm trong một lớp bảo vệ, bỏ qua mọi kết nối từ thiết bị bên ngoài.

Ngược lại, các dòng hướng ra thế giới bên ngoài trông như 0.0.0.0:22, hoặc dạng viết tắt tương đương dành cho IPv6 là [::]:22. Trong output ở trên, SSH daemon nhận kết nối trên cả IPv4 lẫn IPv6; port 3306 do process mariadbd nhận, còn port 22 do process sshd nhận.

Từ đó kiểm tra trạng thái các service này:

systemctl status mariadb.service
systemctl status ssh.service

Chú ý tên service không có chữ d ở cuối. Trên Ubuntu, tên service lấy đúng tên chương trình, còn trên hệ điều hành khác như Red Hat thì tên service lại có chữ d: ssh.service của Ubuntu tương ứng sshd.service của Red Hat.

Dừng, tắt autostart, bật autostart và khởi động lại service vẫn là bộ lệnh systemctl quen thuộc:

sudo systemctl stop mariadb
sudo systemctl disable mariadb
sudo systemctl enable mariadb
sudo systemctl start mariadb

Sau khi dừng MariaDB, chạy lại sudo ss -ltunp sẽ thấy port 3306 không còn nhận kết nối nữa.

Cột process còn in kèm PID, dùng được với các lệnh khác. Biết SSH daemon chạy dưới PID 679 thì khai thác tiếp bằng ps, hoặc xem danh sách file mà process đó đang mở:

sudo lsof -p 679

PID cũng hữu dụng khi lọc log. Phần process và log hệ thống nằm ở Part 3.2: Process, log hệ thống và giám sát tài nguyên.

Cuối cùng, netstat dùng gần như cùng bộ tùy chọn với ss, nên lệnh sau cho kết quả tương đương:

sudo netstat -ltunp

Output của netstat được định dạng gọn gàng hơn một chút nên có người thích đọc nó hơn. Đổi lại, netstat không chắc có sẵn trên mọi hệ thống.


6. Bridge và bond khác nhau ở đâu?​

Cả bridge và bond đều làm một việc nghe giống nhau: lấy hai hay nhiều thiết bị mạng rồi dán chúng lại với nhau dưới tầng hệ điều hành, tạo ra một thiết bị mạng ảo. Khác biệt nằm ngay trong hai cái tên.

Bridge nghĩa là cây cầu, và nó làm đúng nghĩa đó: dựng một cây cầu giữa network 1 và network 2, cho các máy trên hai mạng riêng biệt nói chuyện với nhau như thể chúng ở cùng một mạng. Một server có hai card mạng, mỗi card cắm một sợi cáp đi về một mạng khác nhau; thêm cả hai interface vào một bridge là mọi server ở hai phía liên lạc được với nhau qua cây cầu đó. Bridge không giới hạn ở hai mạng, cần thì nối nhiều hơn.

Trong thuật ngữ mạng của Linux, bridge còn được gọi là controller, còn các thiết bị mạng tham gia bridge gọi là port.

A bridge joins two separate networksLinux serverbridge br0 as controllerenp0s8 portenp0s9 portNetwork 1Server 1Server 2Server 3Server 4Network 2Server 5Server 6Server 7Server 8Server 1 reaches Server 8 through br0 as if both were on one network

Bond thì ngược chiều. Nó cũng gộp hai hay nhiều thiết bị mạng, nhưng gộp hai hay nhiều đường đi tới cùng một mạng thành một đường duy nhất. Tùy bonding mode, việc gộp này mang lại những lợi ích khác nhau:

  1. Kết nối tới mạng bền hơn, vẫn chạy được khi một card mạng chết hoặc bị rút cáp.
  2. Tăng throughput. Một card hỗ trợ kết nối 1000M, gộp hai card lại thì đạt tốc độ cao hơn đáng kể, dù không tới đúng 2000M.
  3. Kết nối ổn định hơn. Một thiết bị mạng đơn lẻ có thể gặp vài nhịp chậm; bond ba thiết bị lại có khả năng triệt được những nhịp chậm đó.

Lý do bond tồn tại thấy rõ nhất qua một tình huống cụ thể. Một server có hai card mạng, hai sợi cáp đi về cùng một mạng trong office. Không có bond, Linux hiểu đây là hai kết nối riêng biệt tới cùng một nơi, và không được lợi gì từ việc có hai đường: chương trình phải tự chọn đúng một đường để đi. Nó chọn card thứ nhất, rồi sợi cáp bên trái bị cắt, và việc truyền dữ liệu thất bại.

Bond hai interface đó lại thì phần cứng không đổi: vẫn hai card, vẫn hai sợi cáp. Nhưng về phía software, mọi chương trình muốn ra mạng bên dưới chỉ thấy một network interface duy nhất, chính là bond vừa tạo, với một sợi dây duy nhất nối nó tới mạng. Cáp của interface thứ nhất bị cắt thì Linux chuyển sang dùng interface thứ hai, và chương trình không nhận ra điều gì đã xảy ra. Hệ điều hành giả vờ rằng chỉ có một sợi dây giữa server và mạng bên dưới, và việc cấu hình nhờ thế gọn hẳn: không cần dạy từng ứng dụng cách dùng card nào, đường nào, IP nào để tới cùng một đích; chỉ cần nói ứng dụng dùng interface đã bond.

Two cables to one network, with and without a bondTwo separate linksApplicationenp0s8enp0s9cable cutOffice networkTransfer fails, the app picked one pathOne bond, active-backupApplicationbond0 single interfaceenp0s8 primaryenp0s9 backupOffice networkKernel switches to enp0s9, link stays upA bridge joins networks, a bond joins routes to one network

Bảy bonding mode​

Linux xử lý traffic qua bond theo nhiều cách, và cách được chọn gọi là bonding mode. Hầu hết hệ điều hành Linux hiện hỗ trợ bảy mode, mã số từ mode 0 tới mode 6. Không khai mode thì một số hệ điều hành chọn mode 0, tên khác là round-robin.

Không phải mode nào cũng đẩy throughput lên cao hơn mức một card đơn lẻ đạt được. Mode làm được việc đó là mode 4, tên khác là IEEE 802.3ad. Chọn mode nào là một bài toán phức tạp, cần hiểu rõ toàn bộ mạng trong tổ chức, nhưng bản mô tả ngắn thì như sau.

ModeTênCách xử lý traffic
0round robinDùng các interface theo thứ tự tuần tự: một lượng dữ liệu đi qua interface 1, lượng tiếp theo qua interface 2, rồi lặp lại
1active backupDùng đúng một interface, giữ các interface còn lại ở trạng thái inactive làm backup. Interface active chết thì một backup trở thành active mới
2XORChọn interface dựa trên source và destination của packet. Thiết bị 1 tới thiết bị 2 luôn qua cùng một interface; thiết bị 1 tới thiết bị 3 có thể qua interface khác, nhưng luôn là interface đó cho mọi lần truyền
3broadcastMọi dữ liệu được gửi qua tất cả interface cùng lúc
4IEEE 802.3adĐẩy được tốc độ truyền lên trên mức một interface đơn lẻ hỗ trợ
5adaptive transmit load balancingLoad balance traffic đi ra từ bond, cố gửi dữ liệu qua interface đang ít việc nhất
6adaptive load balancingCố load balance cả traffic đi ra lẫn traffic đi vào

Trong ngữ cảnh một bond, mọi network interface được thêm vào nó cũng gọi là port, giống như với bridge. Nói gọn lại cho dễ phân biệt: bridge dán hai hay nhiều mạng lại để các thiết bị trên chúng nói chuyện với nhau như trên một mạng; bond dán hai hay nhiều kết nối tới cùng một mạng lại thành một đường duy nhất. Đó là use case điển hình, và dân quản trị mạng giỏi còn tìm ra nhiều cách dùng sáng tạo hơn.


7. Tạo bridge bằng netplan​

Thư mục ví dụ của netplan có sẵn một file cấu hình cho gần như mọi kiểu thiết lập mạng, và lần này file cần tới là bridge.yaml:

ls /usr/share/doc/netplan/examples
cat /usr/share/doc/netplan/examples/bridge.yaml

Copy nó vào thư mục cấu hình của netplan để làm template, rồi siết quyền file lại cho khỏi nhận warning:

sudo cp /usr/share/doc/netplan/examples/bridge.yaml /etc/netplan/99-bridge.yaml
sudo chmod 600 /etc/netplan/99-bridge.yaml

Trước khi sửa file, phải biết tên các interface sẽ dùng:

ip -c link

Ở đây enp0s3 là interface chính, không nên động vào vì đổi thiết lập mạng trên nó có thể làm đứt kết nối SSH đang dùng. Hai interface còn lại, enp0s8 và enp0s9, đang down và chưa dùng cho việc gì, nên thoải mái đem đi bridge.

sudo vim /etc/netplan/99-bridge.yaml

File mẫu chỉ bridge một interface, nên cần thêm interface thứ hai vào cả hai chỗ:

network:
version: 2
renderer: networkd
ethernets:
enp0s8:
dhcp4: null
enp0s9:
dhcp4: null
bridges:
br0:
dhcp4: true
interfaces:
- enp0s8
- enp0s9

Đọc từ trên xuống:

  • Khối ethernets liệt kê các thiết bị Ethernet. Đây là cách cho netplan biết enp0s8 và enp0s9 thuộc loại Ethernet; không khai thì netplan không biết kiểu thiết bị và không biết phải xử lý chúng ra sao.
  • dhcp4: null tắt tự cấu hình DHCP cho từng thiết bị Ethernet riêng lẻ, trong khi bridge thì lại bật. Vậy enp0s8 và enp0s9 không nhận IP, còn cái bridge dán chúng lại mới có IP. Cách chia này không bắt buộc, thực tế có rất nhiều biến thể.
  • Dòng bridges mở phần định nghĩa bridge, và br0 chỉ là cái tên tự chọn, thay bằng tên khác cũng được.
  • dhcp4: true trong khối br0 nói rằng chính bridge này sẽ tự cấu hình thiết lập IPv4 cho mình bằng cách hỏi DHCP server.
  • interfaces liệt kê các interface được thêm vào bridge, vẫn phải đúng tên lấy từ ip -c link.

Lưu file rồi áp dụng bằng sudo netplan try. Kiểm tra lại danh sách interface:

ip -c link

# Output (rút gọn):
3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master br0 state UP mode DEFAULT group default qlen 1000
4: enp0s9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master br0 state UP mode DEFAULT group default qlen 1000
5: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000

Có ba thay đổi đáng đọc. enp0s8 và enp0s9 đã chuyển sang trạng thái up, nghĩa là đang hoạt động và xử lý kết nối mạng. Cả hai đều mang chữ master br0, cho biết chúng thuộc về bridge br0 và là slave của nó, với br0 là master. Và br0 xuất hiện như một interface bổ sung trong danh sách.

Vì cấu hình bật DHCP cho bridge, chạy tiếp ip -c a sẽ thấy br0 đã có địa chỉ IPv4, cùng nhiều thiết lập IPv4 khác. ip route cho thấy route cũng đã được cấu hình cho bridge này.

Để giải phóng hai interface mà chuyển sang thử bond, xóa định nghĩa bridge khỏi netplan rồi xóa luôn interface bridge:

sudo rm /etc/netplan/99-bridge.yaml

Với một server thật thì reboot sẽ sạch hơn, vì nó bảo đảm mọi thiết lập mạng trước đó được reset hết; cho mục đích thử nghiệm thì xóa file và bỏ bridge interface là đủ.


8. Tạo bond bằng netplan​

Quy trình lặp lại y như với bridge: copy file ví dụ, siết quyền, rồi sửa.

sudo cp /usr/share/doc/netplan/examples/bonding.yaml /etc/netplan/99-bond.yaml
sudo chmod 600 /etc/netplan/99-bond.yaml
sudo vim /etc/netplan/99-bond.yaml

File ví dụ này thiếu vài dòng quan trọng. Áp dụng nguyên trạng thì netplan báo lỗi, nói rằng một số network interface chưa được định nghĩa, cụ thể là những cái viết dưới dòng interfaces. Nguyên nhân hợp lý: netplan không biết chúng thuộc loại thiết bị nào. Cách sửa là thêm khối ethernets vào, nằm dưới dòng renderer:

network:
version: 2
renderer: networkd
ethernets:
enp0s8:
dhcp4: null
enp0s9:
dhcp4: null
bonds:
bond0:
dhcp4: true
interfaces:
- enp0s8
- enp0s9
parameters:
mode: active-backup
primary: enp0s8

Khối ethernets chỉ nói với netplan rằng enp0s8 và enp0s9 nhắc tới phía dưới là thiết bị Ethernet, tức card mạng có dây. Trong một hệ thống thật, các interface này có thể được định nghĩa ở một file YAML khác hẳn: một file dành riêng cho thiết bị Ethernet, một file khác dành cho bond. Danh sách Ethernet đôi khi nằm ở đâu đó khác trong thư mục, nên khi đọc hay sửa file netplan thì phải nhớ điều này.

Phần còn lại:

  • Dòng bonds mở phần định nghĩa bond, và bond0 là tên tự chọn.
  • dhcp4: true bật tự cấu hình IPv4 cho bond.
  • interfaces liệt kê các network interface được thêm vào bond.
  • parameters khai các tham số của bond, và tham số quan trọng nhất là mode.

Giá trị hợp lệ cho mode ứng với bảy bonding mode đã nói ở mục trước: balance-rr cho round-robin tức mode 0, active-backup cho mode 1, balance-xor cho XOR mode 2, broadcast cho mode 3, 802.3ad cho IEEE 802.3ad mode 4, balance-tlb cho adaptive transmit load balancing mode 5, và balance-alb cho adaptive load balancing mode 6.

Ví dụ ở đây chọn active-backup, và khác với vài mode kia, mode này cần thêm một tham số nữa: interface nào là primary, tức active mặc định. Dòng primary: enp0s8 trả lời câu đó.

Cần nhắc lại danh sách giá trị mà netplan nhận cho mode thì tra manual:

man netplan

Nhấn / rồi tìm chữ bonding, nhảy tới kết quả thứ ba sẽ thấy đúng danh sách giá trị đó, kèm nhiều tham số khác dùng được cho một bonding interface.

Bond không có netplan try​

Áp dụng cấu hình bond thì gặp một khác biệt đáng chú ý:

sudo netplan try

# Output (rút gọn):
Config revert is not supported for this configuration.

netplan nói rằng không dùng được try vì cấu hình này không hỗ trợ revert hay undo nếu có sự cố. Chỉ còn một cách là bảo đảm cấu hình đúng trước khi chạy apply. Trên một hệ thống thật, phải chuẩn bị sẵn đường vào server khi SSH không còn hoạt động, ví dụ console của hypervisor hay nhà cung cấp cloud.

sudo netplan apply

Kiểm tra lại thiết lập IP sẽ thấy bond đã được tạo và nhận IP tự động, cùng chữ master bond0 bên cạnh hai interface, đúng kiểu đã thấy với bridge. Riêng bond còn một chỗ xem chi tiết hơn, là một thư mục đặc biệt trong /proc:

cat /proc/net/bonding/bond0

# Output (rút gọn):
Bonding Mode: fault-tolerance (active-backup)
Primary Slave: enp0s8 (primary_reselect always)
Currently Active Slave: enp0s8
Slave Interface: enp0s8
MII Status: up
Slave Interface: enp0s9
MII Status: up

Liệt kê interface thêm một lần nữa sẽ thấy bond0 nằm ngang hàng với các thiết bị Ethernet phía trên. Về phía Linux, một bridge hay bond có đặc biệt hơn một thiết bị Ethernet thường thì ở nhiều khía cạnh chúng vẫn được đối xử như nhau. Nghĩa là mọi lệnh ip dùng được cho interface Ethernet thường cũng dùng được cho bridge hay bond:

sudo ip address add 10.0.0.9/24 dev bond0
sudo ip link set dev bond0 down

Thêm, bớt, đổi thiết lập IP ngay lúc đang chạy đều được, đúng như ở mục 2. Với một điểm phải nhớ: thay đổi bằng lệnh ip chỉ là tạm thời và mất sau reboot. Muốn vĩnh viễn thì về lại file YAML của netplan.

Phần tiếp theo của domain Networking bàn tới việc chặn và chuyển hướng dữ liệu đi qua các interface này, ở Part 5.2: Firewall, port redirection và NAT.


Nguồn tham khảo​

Nguồn gốc: Khóa "Prep Course - Linux Foundation Certified System Administrator (LFCS) Certification" — phần "5. Networking" (IPv4 và IPv6 cơ bản, cấu hình IPv4/IPv6 và hostname resolution trên Ubuntu, start/stop/kiểm tra network service, lý thuyết bridge và bond, cấu hình bridge và bond bằng netplan), nền tảng KodeKloud. Giảng viên: Jeremy Morgan và Alexandru Andrei.