OVS Phần 9: Tunnel VXLAN/GRE/Geneve — Đối Chiếu Trực Tiếp Với VXLAN/EVPN Vật Lý
Phần 9/21 trong loạt Open vSwitch (OVS) — nối tiếp Phần 8, nơi bạn đã đào sâu
vlan_modevà cách một trunk port giữ nguyên VLAN tag giữa hai OVS bridge. Bài này chuyển hẳn sang một lớp khác của OVS — không còn switching thuần trong một L2 domain, mà là tunnel: đóng gói cả một khung Ethernet vào trong một gói IP khác để nó "đi xuyên" qua một mạng L3 trung gian, y hệt nguyên lý bạn đã học ở loạt EVPN và ở GRE Tunnel, chỉ khác nơi việc đóng gói đó diễn ra. Đây cũng là bài quan trọng nhất của Module 2, vì nó nối thẳng vào kiến thức VXLAN/EVPN bạn đã có sẵn trên fabric vật lý. Đọc xong, Bài 10 sẽ chuyển sang bonding/LACP trên OVS.
Mục tiêu bài học: sau bài này bạn dựng được một VXLAN tunnel thật giữa hai OVS host bằng đúng cú pháp ovs-vsctl, phân biệt rõ khi nào OVS đóng vai trò VTEP (host-based) và khi nào vai trò đó thuộc về leaf switch (network-based) — chính là đối lập trung tâm Bài 1 Mục 2 mới chỉ nhắc thoáng qua, hiểu đúng lý do kỹ thuật (không phải "vì mới hơn") khiến OVN chọn Geneve làm mặc định thay vì VXLAN, và biết GRE trên OVS khác gì GRE bạn đã cấu hình trên Junos.
Ba câu hỏi mà bài này trả lời:
- OVS làm VTEP (host-based) khác gì leaf switch làm VTEP (network-based) — ai giữ EVPN adjacency, ai thật sự nhìn thấy MAC của từng VM?
- Cú pháp thật để tạo một VXLAN port trên OVS là gì, và OVS dùng UDP port nào theo mặc định?
- Vì sao OVN chọn Geneve thay vì VXLAN hay GRE làm encapsulation mặc định — con số cụ thể nào đứng sau quyết định đó?
Mục lục
- 1. Nhắc lại nhanh: VXLAN, VTEP, VNI bạn đã biết từ EVPN, và OVS thêm gì vào bức tranh
- 2. Đối lập trung tâm: VTEP host-based trên OVS và VTEP network-based trên leaf switch
- 3. Dựng VXLAN port thật trên OVS: cú pháp, option, và cổng UDP mặc định
- 4. Geneve: header TLV mở rộng, và vì sao OVN chọn nó làm mặc định
- 5. GRE trên OVS: khác gì GRE truyền thống đã học ở Junos
- 6. CLI lab: dựng tunnel VXLAN thật giữa hai host, verify bằng tcpdump
- Bài tập cuối bài
1. Nhắc lại nhanh: VXLAN, VTEP, VNI bạn đã biết từ EVPN, và OVS thêm gì vào bức tranh
Loạt EVPN cùng repo đã dựng đầy đủ bộ khái niệm nền: VXLAN đóng gói một khung Ethernet vào một gói UDP để "kéo dài" một L2 segment qua một mạng L3; VTEP (VXLAN Tunnel Endpoint) là điểm đầu/cuối thực hiện việc encap/decap đó; VNI (VXLAN Network Identifier) là số định danh phân biệt segment nào với segment nào bên trong cùng một tunnel. Nếu những thuật ngữ này còn mơ hồ, dừng lại đọc EVPN Phần 1, Mục 3 và Mục 5 trước — bài này không giảng lại chúng.
Điều EVPN Phần 1 ngầm giả định — mà đến giờ mới nói thẳng ra — là VTEP nằm ở đâu. Toàn bộ ví dụ ở đó (Loopback1 trên leaf, MAC VRF là một VLAN cục bộ trên switch) đều gắn VTEP vào một con switch vật lý ASIC. Nhưng bản thân khái niệm VTEP không đòi hỏi phải là phần cứng — nó chỉ là "một thứ gì đó biết encap một khung Ethernet vào VXLAN rồi gửi đi, và biết decap chiều ngược lại". Bài 1 Mục 2 đã nêu đúng một câu sẽ được đào sâu ở đây: "Tunneling tích hợp sẵn — VXLAN, GRE, Geneve được hỗ trợ như một loại port ngay trong OVS, không cần công cụ ngoài". Nói cách khác: OVS tự nó có thể làm VTEP, hoàn toàn bằng phần mềm, chạy ngay bên trong hypervisor — không cần một con ASIC nào cả.
Có một hệ quả kỹ thuật đáng chú ý ngay từ Mục này, trước khi đi vào cấu hình: khi OVS tự làm VTEP mà không có một controller nào đứng phía sau (chưa nói tới OVN, để dành Bài 17), nó học MAC theo đúng kiểu flood & learn cổ điển — giống hệt cách một Linux bridge học MAC trên một VLAN thường. Tài liệu FAQ chính thức của OVS nói thẳng giới hạn này: "There is currently no support for the multicast aspects of VXLAN. To get around the lack of multicast support, it is possible to pre-provision MAC to IP address mappings either manually or from a controller." Nghĩa là OVS không tự động replicate traffic BUM (broadcast/unknown-unicast/multicast) qua một multicast group ở underlay như đặc tả VXLAN gốc (RFC 7348) cho phép — nó chỉ hỗ trợ tunnel point-to-point unicast, và việc "ai ở IP nào giữ MAC nào" phải được biết trước, bằng tay hoặc bằng một controller. Đây chính xác là bài toán mà EVPN giải quyết ở phía leaf switch bằng BGP (route MAC thay vì flood, như EVPN Phần 1 Mục 5 đã trình bày) — và cũng chính xác là bài toán mà OVN giải quyết ở phía OVS (Bài 17, dùng Southbound DB thay cho BGP). Ghi nhớ sự tương đồng này: dù chạy trên switch vật lý hay trên OVS, vấn đề cốt lõi của một overlay VXLAN thuần túy luôn là "làm sao biết MAC nào ở đâu mà không cần flood" — chỉ khác cơ chế giải quyết.
2. Đối lập trung tâm: VTEP host-based trên OVS và VTEP network-based trên leaf switch
💡 Hình dung như thế này: VTEP host-based giống việc mỗi nhân viên tự đóng gói bưu kiện của mình tại bàn làm việc trước khi đưa ra bưu điện — bưu điện (leaf switch) chỉ thấy một kiện hàng đã dán tem, không biết bên trong có bao nhiêu món đồ nhỏ. VTEP network-based giống việc nhân viên chỉ đưa đồ vật thô cho bưu điện, và chính bưu điện là nơi đóng gói, dán tem, và giữ sổ theo dõi từng món đồ của từng nhân viên. Cùng một việc "đóng gói", chỉ khác ai làm và ai phải mở sổ theo dõi.
Đây là đối lập Bài 1 Mục 2 đã gieo hạt: "overlay có thể được terminate ở OVS (host-based VXLAN) hoặc ở leaf switch (network-based VXLAN)". Giờ mới là lúc mổ xẻ nó ra cho hết, vì đây là quyết định kiến trúc ảnh hưởng tới mọi thứ phía dưới — ai giữ EVPN adjacency, ai scale bảng MAC, ai chịu trách nhiệm khi tunnel lỗi.
Host-based (VTEP trong OVS): VM gửi packet ra vNIC, tới OVS bridge — bridge này vừa switching vừa đóng luôn vai trò VTEP nhờ port type=vxlan (Mục 3 sẽ cấu hình thật). Gói VXLAN đã đóng gói xong đi ra uplink NIC như một gói IP/UDP bình thường, và tới leaf switch hoàn toàn không mang dấu vết gì của VM bên trong — leaf chỉ thấy đúng một địa chỉ IP nguồn/đích (địa chỉ VTEP của host) trên một luồng UDP cổng 4789. Từ góc nhìn leaf switch, một host chạy 50 VM cũng chỉ xuất hiện như một endpoint IP duy nhất. Hệ quả trực tiếp: leaf switch không cần biết gì về VXLAN/EVPN cả — nó chỉ cần route được IP, tức là bất kỳ switch L3 tầm trung nào, kể cả loại cũ không có ASIC hỗ trợ VXLAN, cũng đóng vai trò leaf được. Đổi lại, mỗi hypervisor giờ phải tự vận hành một control-plane learn MAC (Mục 1 vừa nói): với hàng trăm hypervisor, đây là lý do thực tế mà OVN (Bài 17) hay Neutron (Bài 18) tồn tại — không ai muốn tự tay ovs-appctl tnl/arp/set cho từng cặp host.
Network-based (VTEP ở leaf): OVS bridge chỉ switching/VLAN thuần túy, hoàn toàn không có port type=vxlan nào — VM traffic rời host dưới dạng một khung Ethernet có VLAN tag bình thường, giống hệt như một server bare-metal cắm dây thẳng vào leaf. Chính leaf switch (một ASIC có hỗ trợ VXLAN/EVPN phần cứng) mới là nơi đóng gói VXLAN, giữ BGP EVPN adjacency thật với các leaf khác (đúng nội dung EVPN Phần 1 Mục 3-5), và học MAC của từng VM theo cách một switch vật lý vẫn luôn làm — chỉ khác là giờ nó phân phối MAC đó qua route BGP thay vì flood ra dây vật lý. Đội network giữ được toàn quyền quan sát/ACL/mirror tới tận từng MAC VM ngay tại leaf — thứ họ hoàn toàn mất quyền nhìn thấy ở mô hình host-based (traffic bên trong tunnel là "hộp đen" với leaf). Đánh đổi: mỗi VLAN tenant giờ phải "chạm" tới tận leaf switch thật — nếu VM di chuyển (Bài 1 Mục 1 đã nói lý do vMotion cần layer 2) sang một hypervisor cắm vào leaf khác, VLAN đó phải tồn tại sẵn ở leaf mới, và số lượng tenant network bị giới hạn bởi trần 4094 VLAN ID trên đúng đoạn cáp từ host lên leaf (trừ khi dùng dot1q-tunnel đã nhắc ở Bài 8).
Thực tế, ranh giới này không tuyệt đối nhị phân. Tài liệu FAQ chính thức của OVN — bộ điều khiển sẽ học kỹ ở Bài 17 — xác nhận cả hai mô hình có thể cùng tồn tại trong một fabric: "OVN does support VXLAN for use with ASIC-based top of rack switches, using ovn-controller-vtep(8) and the OVSDB VTEP schema described in vtep(5), but this limits the features available from OVN to the subset available from the VTEP schema." Nghĩa là một fabric OVN thật có thể vừa có hypervisor làm VTEP host-based (dùng Geneve, Mục 4 sẽ nói vì sao), vừa có một ToR switch vật lý làm VTEP network-based (dùng VXLAN qua chuẩn hardware VTEP schema) cho các server bare-metal không chạy được OVS — đây chính là mảnh ghép đầu tiên của kiến trúc hybrid mà Bài 21 sẽ tổng kết đầy đủ.
3. Dựng VXLAN port thật trên OVS: cú pháp, option, và cổng UDP mặc định
Cú pháp gốc, đúng theo tài liệu FAQ chính thức của OVS:
sudo ovs-vsctl add-br br0
sudo ovs-vsctl add-port br0 vxlan0 \
-- set interface vxlan0 type=vxlan \
options:remote_ip=192.168.1.2 options:key=100
Ba phần quan trọng nhất, theo đúng schema ovs-vswitchd.conf.db (mã nguồn vswitch.xml):
options:remote_ip— bắt buộc. Là địa chỉ VTEP đầu xa. Schema nói rõ ràng: "An IPv4 or IPv6 address (not a DNS name)... Only unicast endpoints are supported." Có thể dùng từ khóaflowthay vì một IP cố định, để tunnel chấp nhận packet từ bất kỳ VTEP nào và quyết định đích đến theo actionset_fieldtrong một flow OpenFlow — đây chính là cách một controller như OVN dựng một tunnel "dùng chung" cho nhiều remote peer thay vì phải tạo một port riêng cho mỗi cặp host.options:key— tương đương VNI. Schema định nghĩa nó là "Shorthand to set in_key and out_key at the same time", và độ dài hợp lệ là "A positive 24-bit (for Geneve and VXLAN)" — khớp đúng 24-bit VNI mà EVPN Phần 1 đã nói khi giải thích MAC VRF/Layer 2 VNI. Dùngkey=flownếu muốn VNI được set động qua actionset_tunnelthay vì cố định.options:dst_port— tùy chọn, đổi cổng UDP đích. Schema ghi rõ: "Optional. The tunnel transport layer destination port, for UDP based tunnel protocols (Geneve, VXLAN)" — chú ý cụm "UDP based": tùy chọn này không áp dụng cho GRE (Mục 5 sẽ nói lý do).
Về câu hỏi cổng UDP mặc định: FAQ chính thức trả lời thẳng, không mơ hồ: "By default, Open vSwitch will use the assigned IANA port for VXLAN, which is 4789." Đây đúng là cổng RFC 7348 đã chuẩn hóa — không có lịch sử OVS từng dùng một mặc định khác. Tuy nhiên có một chi tiết lịch sử liên quan đáng biết: bản thân module VXLAN trong kernel Linux ra đời trước khi IANA chính thức gán cổng 4789, nên từng dùng tạm cổng 8472 làm mặc định; một số triển khai VXLAN cũ (và cả ví dụ minh họa ngay trong tài liệu OVS) vẫn dùng 8472 làm cổng tùy biến để tương thích ngược với các thiết bị/triển khai đời trước IANA. Chính ví dụ cấu hình mẫu của OVS minh họa đúng tình huống này:
sudo ovs-vsctl add-port br0 vxlan1 \
-- set interface vxlan1 type=vxlan \
options:remote_ip=192.168.1.2 options:key=flow options:dst_port=8472
Nói cách khác: mặc định của OVS luôn là 4789; dst_port=8472 chỉ xuất hiện khi bạn cố tình cần nói chuyện với một đầu tunnel cũ chưa theo chuẩn IANA — không phải hành vi mặc định của bất kỳ phiên bản OVS nào. Đối chiếu schema hiện tại (nhánh phát triển mới nhất) với cùng ví dụ đã xuất hiện trong tài liệu OVS từ nhiều năm trước cho thấy cú pháp cốt lõi remote_ip/key/dst_port không hề đổi qua các version — thay đổi duy nhất theo thời gian là OVS bổ sung thêm các loại tunnel mới (gtpu, srv6, bareudp...) chứ không sửa cú pháp cũ.
4. Geneve: header TLV mở rộng, và vì sao OVN chọn nó làm mặc định
Cú pháp tạo port Geneve gần như giống hệt VXLAN — chỉ đổi type=:
sudo ovs-vsctl add-port br0 geneve0 \
-- set interface geneve0 type=geneve \
options:remote_ip=192.168.1.2 options:key=100
Geneve cũng là một giao thức chạy trên UDP, nên options:dst_port áp dụng được y hệt VXLAN — schema đã trích ở Mục 3 gộp chung cả hai: "for UDP based tunnel protocols (Geneve, VXLAN)". Chuẩn Geneve (RFC 8926) được IANA gán cổng UDP well-known là 6081. Tài liệu schema vswitch.xml không lặp lại con số này riêng cho Geneve theo cách đã làm rõ với VXLAN (4789), nhưng mã nguồn thật của OVS thì có: file lib/netdev-vport.c định nghĩa thẳng #define GENEVE_DST_PORT 6081, và constant này chính là giá trị được gán vào dst_port mỗi khi tạo port Geneve mà không truyền options:dst_port (tnl_cfg.dst_port = htons(GENEVE_DST_PORT)). Nói cách khác, 6081 không phải suy luận theo quy ước đặt tên — đó là giá trị hard-code mặc định trong chính OVS, khớp đúng với port IANA đã gán cho Geneve.
Khác biệt thật sự nằm ở phần header. VXLAN có một header cố định 8 byte: 24-bit VNI và phần còn lại gần như chỉ để dành (reserved) — không có chỗ cho bất kỳ metadata tùy biến nào khác ngoài VNI. Geneve giải quyết đúng giới hạn đó bằng cách chỉ giữ lại phần cố định tối thiểu (VNI 24-bit, tương tự VXLAN), rồi cho phép gắn thêm một chuỗi TLV (Type-Length-Value) options có độ dài thay đổi ngay sau đó — bất kỳ ai cũng có thể định nghĩa thêm option riêng mà không cần sửa chuẩn gốc.
💡 Hình dung như thế này: Header VXLAN giống một cái phong bì in sẵn, chỉ có đúng một ô trống để điền số VNI — hết ô là hết chỗ, không viết thêm được gì khác. Header Geneve giống một phong bì có cùng ô VNI đó, nhưng sau ô VNI là một xấp giấy note dán kèm tùy ý: cần ghi thêm gì (ingress port, egress port, hay bất cứ metadata nào tương lai cần) thì dán thêm note vào, không phải in lại phong bì mới.
Đây chính xác là lý do OVN chọn Geneve, và tài liệu FAQ chính thức của dự án OVN nói rõ đến từng bit, không hề mơ hồ. OVN cần mang ba mẩu metadata cùng lúc qua mạng vật lý giữa các hypervisor:
- Logical datapath ID — 24-bit, dùng đúng trường VNI để chứa.
- Logical ingress port — 15-bit, chỉ tồn tại được nhờ Geneve có chỗ chứa option riêng.
- Logical egress port — 16-bit, cũng cần một option riêng.
FAQ tính thẳng: "Together, these metadata require 24 + 15 + 16 = 55 bits. GRE provides 32 bits, VXLAN provides 24, and VLAN only provides 12." 55 bit vượt xa những gì VXLAN (24-bit, chỉ đủ cho một mình VNI, không còn chỗ cho hai trường ingress/egress port) hay GRE (32-bit Key field theo RFC 2890) có thể mang cùng lúc. Tài liệu còn liệt kê những phương án "vá tạm" từng được cân nhắc — ví dụ "16 bits of logical datapaths + 16 bits of logical egress ports" vừa đủ nhét vào 32-bit GRE key, hoặc "12 bits of logical datapaths + 12 bits of logical egress ports" vừa đủ nhét vào 24-bit VXLAN VNI — nhưng kết luận thẳng: "These compromises wouldn't suit every site, since some deployments may need to allocate more bits to the datapath or egress port identifiers." Nói ngắn gọn: không phải Geneve "mới hơn nên tốt hơn" — mà vì VXLAN và GRE có header cố định, còn OVN cần một khoảng chứa metadata mở rộng được theo yêu cầu triển khai, và chỉ Geneve trong ba lựa chọn có TLV option đáp ứng đúng nhu cầu đó.
5. GRE trên OVS: khác gì GRE truyền thống đã học ở Junos
Nếu bạn đã đọc GRE Tunnel, cấu trúc header GRE (RFC 2784, RFC 2890) không cần nhắc lại — 4 byte cố định, Key field 32-bit tùy chọn, Sequence Number tùy chọn. Câu hỏi ở đây chỉ là: GRE chạy trên OVS có gì khác GRE chạy trên một gr-0/0/0 của Junos.
sudo ovs-vsctl add-port br0 gre0 \
-- set interface gre0 type=gre options:remote_ip=192.168.1.2 options:key=100
Khác biệt thực chất nhất nằm ở chính định nghĩa loại interface: schema OVS mô tả gre là "Generic Routing Encapsulation (GRE) over IPv4 tunnel, configurable to encapsulate layer 2 or layer 3 traffic." Cụm "layer 2 or layer 3" là điểm mấu chốt. gr-0/0/0 trên Junos mà GRE Tunnel đã cấu hình là một interface định tuyến thuần túy — chỉ có family inet, chỉ mang được gói IP (layer 3), không bao giờ là một port trên một bridge. Ngược lại, gre0 trên OVS nằm thẳng trên một bridge switching — mặc định nó bridge cả khung Ethernet (layer 2) qua tunnel, y hệt cách vxlan0/geneve0 vừa cấu hình ở trên hoạt động. Đây là lý do GRE trên OVS có thể dùng để nối hai OVS bridge thành một L2 domain duy nhất — việc gr-0/0/0 không làm được vì bản chất nó không phải một bridge port.
Vài khác biệt nhỏ hơn, đều lấy trực tiếp từ schema:
options:keylà 32-bit trên GRE, không phải 24-bit như Geneve/VXLAN — khớp đúng độ dài Key field RFC 2890 đã học ở GRE Tunnel, chỉ khác là giờ nó còn đóng vai trò tương đương VNI (phân biệt segment) chứ không chỉ để multiplex traffic flow như mục đích ban đầu RFC 2890 mô tả.- Không có
options:dst_port— vì GRE không chạy trên UDP, nó dùng thẳng IP protocol 47 (đúng như GRE Tunnel đã nói ở Mục 1), nên hoàn toàn không có khái niệm cổng transport để đổi. ip6gre— một loại interface riêng cho GRE chạy trên IPv6 transport thay vì IPv4, nhưng schema lưu ý nó "encapsulate layer 2 traffic" — chỉ L2, không có tùy chọn L3 như bản IPv4.
Một điểm dễ hiểu lầm cần đính chính ngay: GRE Tunnel Mục 1 liệt kê "encapsulate traffic multicast" như một use case phổ biến của GRE — nhưng đó là nói về việc đóng gói payload multicast bên trong một tunnel unicast, không phải bản thân tunnel endpoint là multicast. Trên OVS, ràng buộc remote_ip chỉ chấp nhận unicast áp dụng đồng loạt cho cả ba loại tunnel — schema liệt kê chung một đoạn cho geneve, bareudp, gre, ip6gre, vxlan, srv6: "Only unicast endpoints are supported." Nói cách khác, GRE trên OVS không có lợi thế "multicast-native" nào so với VXLAN/Geneve — cả ba đều là tunnel point-to-point unicast thuần túy khi chạy trên OVS.
Còn giám sát trạng thái tunnel — GRE Tunnel Mục 8 đã giải thích vì sao QFX/EX không hỗ trợ GRE keepalive (một extension riêng của Cisco, không nằm trong RFC). OVS không triển khai lại đúng cơ chế GRE keepalive kiểu Cisco đó cho bất kỳ loại tunnel nào — thay vào đó, OVS có cơ chế giám sát chuẩn hóa hơn: BFD (Bidirectional Forwarding Detection, RFC 5880/5881), cấu hình được trực tiếp trên cột bfd của bất kỳ Interface nào, kể cả gre/vxlan/geneve. Tài liệu schema mô tả nó "như một lựa chọn thay thế phổ biến hơn và tuân chuẩn hơn CFM" — CFM (Connectivity Fault Management, chuẩn IEEE 802.1ag) là một cơ chế giám sát liên kết Ethernet ra đời trước BFD, ít được triển khai thực tế hơn — để phát hiện lỗi kết nối point-to-point — đây là câu trả lời hiện đại hơn cho đúng nhu cầu mà GRE keepalive từng cố giải quyết, chỉ khác là chuẩn hóa qua RFC thay vì một mẹo riêng của một vendor.
6. CLI lab: dựng tunnel VXLAN thật giữa hai host, verify bằng tcpdump
Lab này cần hai host/VM thật có thể ping thấy nhau qua IP (transport network) — không dồn cả hai "host" giả lập vào chung một network namespace/bảng định tuyến duy nhất trên một máy. Lý do kỹ thuật: nếu cả hai địa chỉ VTEP (ví dụ 10.10.10.11 và 10.10.10.12) cùng tồn tại trong một bảng định tuyến, kernel sẽ coi cả hai là "địa chỉ cục bộ" và không bao giờ thật sự gửi gói VXLAN ra khỏi máy để bạn quan sát bằng tcpdump — hai host thật (hoặc hai VM lab riêng biệt) là cách duy nhất để hành vi tunnel đúng như trên fabric thật. Bên trong mỗi host, VM vẫn giả lập bằng network namespace theo đúng mẫu Bài 4/5 (veth<N>-ovs gắn vào bridge, veth<N> đưa vào namespace).
Trên host1 (transport IP 10.10.10.11):
sudo ovs-vsctl add-br br0
# "VM1" giả lập bằng namespace, đúng mẫu Bài 4/5
sudo ip netns add vm1
sudo ip link add veth0 type veth peer name veth0-ovs
sudo ip link set veth0 netns vm1
sudo ovs-vsctl add-port br0 veth0-ovs
sudo ip link set veth0-ovs up
sudo ip netns exec vm1 ip addr add 10.0.0.1/24 dev veth0
sudo ip netns exec vm1 ip link set veth0 up
sudo ip netns exec vm1 ip link set lo up
# Port VXLAN — VNI 100, trỏ sang host2
sudo ovs-vsctl add-port br0 vxlan0 \
-- set interface vxlan0 type=vxlan \
options:remote_ip=10.10.10.12 options:key=100
Trên host2 (transport IP 10.10.10.12), cấu hình đối xứng:
sudo ovs-vsctl add-br br0
sudo ip netns add vm2
sudo ip link add veth0 type veth peer name veth0-ovs
sudo ip link set veth0 netns vm2
sudo ovs-vsctl add-port br0 veth0-ovs
sudo ip link set veth0-ovs up
sudo ip netns exec vm2 ip addr add 10.0.0.2/24 dev veth0
sudo ip netns exec vm2 ip link set veth0 up
sudo ip netns exec vm2 ip link set lo up
sudo ovs-vsctl add-port br0 vxlan0 \
-- set interface vxlan0 type=vxlan \
options:remote_ip=10.10.10.11 options:key=100
Xác nhận cấu hình đã ghi đúng vào OVSDB (Bài 5):
sudo ovs-vsctl show
# Output minh họa (host1)
Bridge br0
Port vxlan0
Interface vxlan0
type: vxlan
options: {key="100", remote_ip="10.10.10.12"}
Port veth0-ovs
Interface veth0-ovs
Port br0
Interface br0
type: internal
(Output minh họa — cấu trúc đúng theo lệnh thật, số liệu cụ thể tùy máy.)
Ping từ vm1 sang vm2 qua tunnel, đồng thời bắt gói trên interface transport (eth0) của host1 ở một cửa sổ terminal khác:
# Terminal 1 — host1
sudo ip netns exec vm1 ping -c 3 10.0.0.2
# Terminal 2 — host1, bắt gói ngay trên NIC transport, không phải trên br0
sudo tcpdump -i eth0 -vv udp port 4789
# ===== Output minh họa =====
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.412 ms
64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.389 ms
64 bytes from 10.0.0.2: icmp_seq=3 ttl=64 time=0.401 ms
10:22:41.118203 IP (tos 0x0, ttl 64, id 4821, offset 0, flags [DF], length 134)
10.10.10.11.52318 > 10.10.10.12.4789: VXLAN, flags [I] (0x08), vni 100
IP 10.0.0.1 > 10.0.0.2: ICMP echo request, id 21, seq 1, length 64
# =============================
(Output minh họa — cấu trúc đúng theo lệnh thật: outer IP src/dst là hai địa chỉ transport, cổng đích UDP đúng 4789, "vni 100" khớp đúng options:key=100 đã cấu hình, inner IP src/dst mới là 10.0.0.1/10.0.0.2 của hai namespace. Số liệu cụ thể — port nguồn ephemeral, ttl, id — tùy máy.) Đây chính là bằng chứng trực tiếp cho điều Mục 2 đã nói: eth0 (transport NIC) hoàn toàn không biết gì về 10.0.0.1/10.0.0.2 — với nó, cả cuộc hội thoại chỉ là một luồng UDP giữa hai IP host, y hệt cách một leaf switch nhìn một tunnel host-based.
Nếu chỉ nhớ được một điều sau bài này, hãy nhớ: cả ba loại tunnel — VXLAN, Geneve, GRE — trên OVS đều chỉ là một port biết đóng/bóc một outer header quanh khung Ethernet gốc; khác biệt thật giữa chúng nằm ở đúng cấu trúc header đó (Geneve có TLV mở rộng, GRE không chạy UDP), không nằm ở việc chúng "làm gì". Và với bất kỳ thiết bị nào đứng giữa transport network — leaf switch hay chỉ một tcpdump như vừa chạy — một OVS host làm VTEP luôn chỉ hiện ra như một địa chỉ IP duy nhất đang nói chuyện UDP, không hơn.
Bài tập cuối bài
- Trên
host2, đổi VNI củavxlan0sang một giá trị khác (options:key=200) trong khi vẫn giữ nguyênoptions:remote_ip=10.10.10.11— dùng đúng cú phápovs-vsctl set interface vxlan0 options:key=200đã học ở Bài 5. Ping lại từvm1sangvm2: xác nhận timeout, dùremote_ipở cả hai phía vẫn đúng và outer IP/UDP vẫn tới nơi bình thường (tự kiểm bằngtcpdumpnhư Mục 6 để thấy gói VXLAN vẫn đến, chỉ khác giá trịvni). Giải thích bằng lời tại sao — liên hệ trực tiếp với bài học VLAN mismatch ở Bài 5 Mục 3: hai VNI khác nhau tạo ra hai "miền broadcast" tách biệt hoàn toàn trong OVSDB/datapath, y hệt cách hai VLAN tag khác nhau cô lập hai port trên cùng một bridge. - Đổi VNI của
host2về lại100, xác nhận ping thông trở lại — dùng để loại trừ khả năng lỗi ở bước 1 đến từ nguyên nhân khác ngoài VNI mismatch. - Thử đổi
type=vxlanthànhtype=genevetrên cả hai host (giữ nguyênremote_ip/key), lặp lại lab Mục 6, và tự chạytcpdump -i eth0 udp port 6081thay vì 4789. Ghi lại điểm khác biệt duy nhất bạn quan sát được trong outputtcpdumpso với VXLAN — nếu không thấy khác biệt đáng kể ở mức ping ICMP đơn giản, đó là dấu hiệu đúng: khác biệt thật sự giữa hai giao thức chỉ lộ ra khi có metadata TLV cần mang theo (Mục 4), một bài ping ICMP trần trụi không tận dụng được lợi thế đó.
Nguồn tham khảo
- Cú pháp VXLAN port (
add-port ... type=vxlan options:remote_ip=... options:key=...), OVS "hiện chưa hỗ trợ khía cạnh multicast của VXLAN" nên phải pre-provision MAC-to-IP thủ công hoặc qua một controller, và mặc định dùng đúng cổng IANA 4789 (có ví dụ override về 8472 để tương thích ngược) — 2026, VXLANs FAQ, docs.openvswitch.org. - Cột
options:remote_ipchỉ chấp nhận unicast endpoint cho mọi loại tunnel (geneve,bareudp,gre,ip6gre,vxlan,srv6);options:keydài 24-bit cho Geneve/VXLAN, 32-bit cho GRE;options:dst_portchỉ áp dụng cho tunnel chạy trên UDP (Geneve, VXLAN); định nghĩagrelà "over IPv4 tunnel, configurable to encapsulate layer 2 or layer 3 traffic",ip6grechỉ mang layer 2 qua IPv6; BFD (RFC 5880/5881) là "a more popular and standards compliant alternative to CFM" để giám sát liên kết point-to-point — mã nguồn tài liệu schema, vswitch.xml, github.com/openvswitch/ovs. - RFC 7348 định nghĩa VXLAN và gán UDP destination port 4789 — 8/2014, RFC 7348, rfc-editor.org.
- RFC 8926 định nghĩa Geneve; IANA gán UDP port 6081 làm well-known destination port cho Geneve — 5/2021, RFC 8926, rfc-editor.org.
- OVS thật sự dùng 6081 làm
dst_portmặc định khi tạo porttype=genevemà không truyềnoptions:dst_port— hard-code qua constant#define GENEVE_DST_PORT 6081(đối chiếu vớiVXLAN_DST_PORT 4789cùng file) — 2026, lib/netdev-vport.c, github.com/openvswitch/ovs. - Lý do OVN chọn Geneve thay vì VXLAN/GRE/VLAN: cần mang logical datapath ID (24-bit) + logical ingress port (15-bit) + logical egress port (16-bit), tổng 55-bit metadata, trong khi "GRE provides 32 bits, VXLAN provides 24, and VLAN only provides 12 bits"; OVN vẫn hỗ trợ VXLAN riêng cho ASIC-based top-of-rack switch qua
ovn-controller-vtep(8)và VTEP schema, dù giới hạn tính năng xuống đúng những gì schema đó hỗ trợ — General FAQ, docs.ovn.org. - Cookbook cấu hình tunnel 2-host chính thức (
add-port br0 gre0 -- set interface gre0 type=gre options:remote_ip=...), lưu ý không add NIC transport (eth0) vào chính OVS bridge — Connecting VMs Using Tunnels, docs.openvswitch.org. - Mô hình tách riêng
br-int/br-phychỉ bắt buộc khi chạy datapath userspace/DPDK để mượn được bảng định tuyến/ARP của kernel — không cần thiết với kernel datapath (dùng trong lab Mục 6) — Connecting VMs Using Tunnels (Userspace), docs.openvswitch.org.
Tiếp theo: Module 2, Bài 10 — Bonding/LACP trên OVS.