GRE Tunnel trên Junos
Mục lục
- 1. GRE là gì và giải quyết vấn đề gì?
- 2. Cấu trúc GRE header (RFC 2784)
- 3. Cơ chế encapsulation và de-encapsulation
- 4. Overhead, MTU và fragmentation
- 5. GRE Key và Sequence Number (RFC 2890)
- 6. Cấu hình GRE trên Junos
- 7. Kiểm tra GRE tunnel hoạt động
- 8. Hạn chế theo dòng thiết bị
- 9. Class of Service (CoS) trên GRE
- 10. Firewall filters trên GRE
1. GRE là gì và giải quyết vấn đề gì?
Giả sử bạn có hai văn phòng, mỗi nơi một dải mạng nội bộ riêng, và giữa hai nơi chỉ có Internet công cộng để nối. Bạn muốn hai router ở hai đầu nói chuyện với nhau như thể chúng đang cắm chung một sợi cáp — chạy được OSPF, gửi được multicast, giữ được một liên kết point-to-point ổn định — trong khi bản thân Internet ở giữa chỉ biết định tuyến IP thông thường và chẳng quan tâm gì đến việc đó. Đây chính xác là bài toán mà GRE (Generic Routing Encapsulation) sinh ra để giải quyết.
GRE, chuẩn hóa theo RFC 2784, tạo ra một liên kết ảo point-to-point bằng cách gói (encapsulate) một gói tin bất kỳ vào bên trong một gói IP khác. Nhờ vậy, hai router hai đầu tunnel nhìn nhau như một hop trực tiếp, bất kể bên dưới đi qua bao nhiêu router thật.
💡 Hình dung như thế này: GRE giống như bạn bỏ một lá thư viết tay (gói tin gốc) vào trong một phong bì thứ hai có ghi địa chỉ người nhận thật (outer IP header), rồi gửi qua bưu điện công cộng (Internet). Bưu điện chỉ đọc được phong bì ngoài để giao đúng nơi — không biết và không cần biết bên trong phong bì có gì. Khi phong bì tới nơi, người nhận bóc lớp ngoài ra, lấy đúng lá thư gốc, rồi xử lý tiếp như thể lá thư đó chưa từng bị bọc lại.
Ba use case phổ biến nhất của GRE trong thực tế:
- Vận chuyển traffic riêng tư qua mạng công cộng — dữ liệu nội bộ đi qua Internet mà vẫn giữ được cấu trúc IP gốc.
- Cho các giao thức định tuyến chạy được qua Internet — OSPF hay RIP vốn cần liên kết trực tiếp giữa hai neighbor, và GRE tạo ra đúng liên kết ảo đó.
- Encapsulate traffic multicast — nhiều mạng công cộng không route multicast, nên gói nó vào trong một gói unicast GRE là cách phổ biến để "lách" qua giới hạn này.
Một điểm quan trọng cần nắm ngay từ đầu: GRE tunnel là stateless. Mỗi đầu tunnel gửi gói đi mà không hề biết đầu bên kia có đang "sống" hay không — không có bắt tay, không có cơ chế theo dõi trạng thái kết nối tích hợp sẵn trong RFC gốc. Điều này sẽ quay lại quan trọng ở Mục 8, khi nói vì sao Junos QFX/EX không hỗ trợ GRE keepalive.
2. Cấu trúc GRE header (RFC 2784)
Muốn hiểu vì sao GRE làm được điều ở Mục 1, phải mở gói tin ra xem thực sự có gì bên trong header của nó. RFC 2784 định nghĩa header GRE cơ bản gói gọn trong đúng 4 byte bắt buộc, cộng thêm tối đa 4 byte tùy chọn — rất gọn so với những gì nó làm được.
Header bắt buộc gồm 4 trường nằm trong 32 bit đầu tiên:
- C (Checksum Present) — 1 bit. Bật lên nếu gói có kèm Checksum, tắt thì không.
- Reserved0 — 12 bit, luôn phải gửi và nhận bằng 0.
- Version — 3 bit, với GRE cơ bản luôn bằng 0.
- Protocol Type — 2 byte, cho biết payload bên trong là loại gì. Khi payload là IPv4, giá trị này bắt buộc phải là 0x0800 (đúng giá trị EtherType dùng cho IPv4).
Nếu bit C được bật lên 1, thêm 32 bit optional nữa xuất hiện ngay sau: Checksum (kiểm tra lỗi one's-complement) và Reserved1 (luôn bằng 0). Nếu C = 0, hai trường này không tồn tại — gói tin chỉ có đúng 4 byte header.
Nhìn vào cấu trúc này, chỉ với 4 byte tối thiểu, GRE đã đủ để nói "đây là một gói được tunnel, và bên trong nó là loại giao thức gì" — mọi thứ khác (tìm đường, đảm bảo tới nơi) đều giao phó hết cho outer IP header, không phải bản thân GRE header lo.
3. Cơ chế encapsulation và de-encapsulation
Nắm được cấu trúc header rồi, giờ ghép nó vào bức tranh toàn cảnh: một gói tin thật đi qua GRE tunnel trải qua đúng ba bước.
Bước 1 — Tại router nguồn (encapsulation). Gói dữ liệu gốc được gửi tới tunnel interface. Interface này đóng gói dữ liệu đó vào trong một GRE packet (thêm 4 byte header vừa học ở Mục 2), rồi thêm tiếp một outer IP header bọc ngoài cùng. Gói tin sau đó được forward đi hoàn toàn dựa trên destination address ghi trong outer IP header — router không quan tâm gói tin gốc bên trong đang chứa gì.
Bước 2 — Gói tin di chuyển qua mạng công cộng. Với mọi router trung gian trên đường đi, đây chỉ là một gói IP bình thường, được định tuyến như bất kỳ gói IP nào khác.
Bước 3 — Tại router đầu xa (de-encapsulation). Outer IP header và GRE header bị loại bỏ. Gói tin được định tuyến tiếp dựa trên inner IP header — chính là header của gói dữ liệu gốc ban đầu, y hệt như thể nó chưa từng bị bọc lại.
Điểm mấu chốt cần nhớ: gói tin gốc không hề bị thay đổi. Nó chỉ tạm thời bị bọc thêm hai lớp header ở bước 2, rồi được trả về nguyên trạng ở bước 3. Toàn bộ "phép thuật" của GRE nằm ở chỗ hai lớp bọc thêm đó, không phải ở việc chỉnh sửa dữ liệu gốc.
4. Overhead, MTU và fragmentation
Bọc thêm hai lớp header nghe có vẻ đơn giản, nhưng nó kéo theo một hệ quả mà rất nhiều người triển khai GRE lần đầu bỏ sót: hai lớp đó không tự nhiên sinh ra từ hư không — chúng chiếm chỗ trong đúng cái MTU vật lý sẵn có.
Cụ thể, GRE cộng thêm 24 byte overhead cho mỗi gói: 20 byte outer IPv4 header + 4 byte GRE header. Nếu physical interface có MTU 1500 byte (giá trị phổ biến nhất), thì phần còn lại dành cho gói tin gốc chỉ còn 1476 byte.
Hệ quả thực tế chia làm hai nhánh, tùy vào bit DF (Don't Fragment) trên gói gốc:
- Nếu DF = 1 và gói tin (sau khi cộng thêm GRE + outer IP) vượt quá 1476 byte, gói bị drop âm thầm — đây chính là kịch bản gây ra hiện tượng "kết nối treo lơ lửng, ping nhỏ thì được, tải trang/SSH thì không" mà nhiều người mất hàng giờ mới lần ra nguyên nhân.
- Nếu DF = 0, router nguồn sẽ fragment gói tin trước khi thêm GRE header, rồi router đầu xa phải reassemble lại khi de-encapsulate — việc reassembly này có thể gây tốn CPU đáng kể nếu traffic lớn.
Một lỗi thường gặp khi vận hành GRE kết hợp thêm IPsec (tunnel trong tunnel) là cộng dồn quên mất lớp overhead của cả hai: một khuyến nghị phổ biến trong thực tế vận hành là đặt MTU tunnel về khoảng 1400 byte để có đủ khoảng đệm cho cả tổ hợp GRE + IPsec phổ biến nhất, thay vì chỉ trừ đúng 24 byte của riêng GRE.
5. GRE Key và Sequence Number (RFC 2890)
Header 4 byte ở Mục 2 là bản GRE tối giản nhất, nhưng có hai vấn đề nó chưa giải quyết được: làm sao phân biệt nhiều traffic flow cùng chạy chung một cặp source/destination IP, và làm sao biết gói tin có bị rớt thứ tự dọc đường không. RFC 2890 bổ sung thêm hai trường tùy chọn để giải hai bài toán này, mỗi trường được bật bằng một bit cờ riêng ngay trong 12 bit Reserved0 ở Mục 2 (cụ thể là bit K và bit S).
Key field dùng để định danh một traffic flow cụ thể bên trong tunnel — nói cách khác, nó cho phép nhiều "luồng logic" khác nhau multiplex (dùng chung) cùng một cặp source/destination IP mà vẫn phân biệt được với nhau, thay vì phải mở một tunnel vật lý riêng cho mỗi luồng.
Sequence Number field giúp phía nhận xác định đúng thứ tự gói tin đã được gửi đi. Cơ chế hoạt động: bên nhận lưu lại số sequence cuối cùng đã nhận đúng thứ tự (khởi tạo bằng 2³²-1 lúc tunnel mới thiết lập); gói tiếp theo chỉ được chấp nhận nếu sequence number của nó đúng bằng "số cuối cùng + 1" (modulo 2³²) — gói nào tới không đúng thứ tự bị âm thầm loại bỏ. RFC mô tả đặc tính này là "unreliable but in-order": không đảm bảo gói không bị mất, nhưng đảm bảo gói nào lọt qua thì đúng thứ tự.
Hai trường này độc lập với nhau về mặt bật/tắt (không bắt buộc đi kèm nhau), nhưng trên thực tế phần lớn thiết bị/vendor hỗ trợ chúng như một cặp tính năng đi chung, vì cùng phục vụ mục tiêu kiểm soát traffic flow chặt chẽ hơn bản GRE tối giản ban đầu.
6. Cấu hình GRE trên Junos
Đã hiểu bên trong gói tin GRE có gì, giờ chuyển sang phần thực chiến: dựng một GRE tunnel giữa hai router chạy Junos. Toàn bộ cấu hình xoay quanh một pseudo-interface tên gr-0/0/0.
Bước 1 — Cấu hình tunnel port (nếu thiết bị yêu cầu). Một số dòng thiết bị cần khai báo trước một PIC/port chuyên dùng cho tunnel:
set fpc slot pic pic-number tunnel-port port-number tunnel-services
Bước này không cần thiết trên QFX10000, vì interface gr-0/0/0 được tạo tự động sẵn trên dòng này.
Bước 2 — Tạo GRE interface. Interface bắt buộc phải mang đúng tên gr-0/0/0 (đây là pseudo-interface, không map trực tiếp vào một cổng vật lý):
set interfaces gr-0/0/0 unit 0 family inet address 192.168.100.1/30
IP address gán ở đây (192.168.100.1/30 trong ví dụ) là địa chỉ của chính tunnel interface — dùng để hai đầu tunnel "nhìn thấy nhau" ở layer 3 bên trong tunnel, khác hoàn toàn với tunnel source/destination ở hai bước dưới.
Bước 3 — Khai báo tunnel source. Đây là địa chỉ IP thật (thường là loopback hoặc IP interface vật lý) mà router dùng làm nguồn khi đóng gói outer IP header:
set interfaces gr-0/0/0 unit 0 tunnel source 10.1.1.1
Bước 4 — Khai báo tunnel destination. Địa chỉ IP thật của đầu xa — bắt buộc phải reachable được thông qua static routing hoặc dynamic routing, nếu không tunnel sẽ không bao giờ lên:
set interfaces gr-0/0/0 unit 0 tunnel destination 10.2.2.2
Lặp lại đúng bốn bước trên ở R2, chỉ đảo ngược source/destination, là đủ để dựng xong một GRE tunnel point-to-point cơ bản.
7. Kiểm tra GRE tunnel hoạt động
Sau khi cấu hình xong cả hai đầu, việc đầu tiên bạn nên làm không phải là ping ngay qua tunnel, mà là kiểm tra bản thân interface gr-0/0/0 đã lên chưa:
show interfaces gr-0/0/0
# Output minh họa (rút gọn)
Physical interface: gr-0/0/0, Enabled, Physical link is Up
Link-level type: GRE, MTU: 1476, Speed: Unlimited
Device flags : Present Running
Logical interface gr-0/0/0.0
Flags: Point-To-Point SNMP-Traps
Input packets : 15234, Output packets : 15298
Protocol inet, MTU: 1476
Flags: Sendbcast-pkt-to-re
Addresses, Flags: Is-Preferred Is-Primary
Local: 192.168.100.1, Remote: 192.168.100.2
(Output minh họa — cấu trúc và tên field đúng theo lệnh thật, số liệu cụ thể chỉ mang tính ví dụ.)
Vài điểm cần chú ý ngay trong output này:
- MTU: 1476 — đúng con số đã tính ở Mục 4 (1500 - 24 byte overhead), tự động được Junos áp cho logical interface.
- Flags: Point-To-Point — xác nhận đây đúng là một liên kết ảo điểm-điểm, đúng bản chất GRE đã nói ở Mục 1.
- Input packets / Output packets tăng dần qua các lần chạy lại lệnh — đây là cách nhanh nhất để biết tunnel có đang thực sự truyền traffic hay chỉ "lên" về mặt trạng thái nhưng không có gói nào đi qua.
Nếu Physical link báo Down hoặc packet counter đứng yên dù đã gửi traffic thử, nghi ngờ đầu tiên nên đặt vào tunnel destination — kiểm tra lại nó có thực sự reachable qua bảng định tuyến hay không, đúng như điều kiện bắt buộc đã nêu ở Mục 6.
8. Hạn chế theo dòng thiết bị
GRE tuy đơn giản về mặt chuẩn, nhưng mỗi dòng thiết bị Junos lại có một tập giới hạn triển khai (implementation limit) riêng — và đây thường là nơi gây bất ngờ nhất khi scale một thiết kế GRE từ vài tunnel thử nghiệm lên hàng trăm tunnel production.
QFX Series
- Số lượng tunnel tối đa: QFX5100 hỗ trợ 512 tunnel nếu chỉ dùng IPv4/IPv6, hoặc 333 tunnel nếu kết hợp thêm giao thức khác.
- Không hỗ trợ: MPLS over GRE, GRE keepalive, GRE key (chính là Key field ở Mục 5), BGP dynamic tunnel; outer IP header bắt buộc phải là IPv4.
- ECMP: nếu tunnel được cấu hình trỏ tới một ECMP next-hop (nhiều đường có cùng chi phí) thay vì một unicast next-hop cụ thể, GRE encapsulation sẽ fail — đây là lỗi cấu hình phổ biến khi ai đó cố gắng load-balance traffic GRE giống như traffic thường.
EX Series
- Số lượng tunnel tối đa: 500 tunnel với IPv4/IPv6, hoặc 333 tunnel nếu dùng kèm giao thức khác. Số lượng tunnel source cũng bị giới hạn: tối đa 20 source IP × 20 destination IP, tương đương trần 400 tunnel.
- Không hỗ trợ: MPLS over GRE, GRE keepalive, GRE key, BFD over GRE ở distributed mode.
- OSPF: bật OSPF trực tiếp trên GRE interface sẽ tạo ra hai equal-cost route tới cùng một đích — một qua tunnel, một qua underlay vật lý. Khi traffic chọn đi qua tunnel interface, bản thân tunnel lại có thể fail vì lý do khác, kéo theo route đang dùng biến mất đột ngột. Khuyến nghị chung: dùng static route trỏ vào tunnel thay vì để OSPF tự chọn, hoặc tắt hẳn OSPF trên tunnel interface.
Vì sao QFX/EX không hỗ trợ GRE keepalive?
Đây là chi tiết đáng nói riêng, vì nó lý giải luôn tính chất stateless đã nhắc ở Mục 1. GRE keepalive không nằm trong RFC 2784 hay RFC 2890 — đây vốn là một cơ chế mở rộng riêng của Cisco. Cách nó hoạt động khá tinh tế: router gửi một gói GRE có Protocol Type = 0 và không kèm payload nào cả, gói này được encapsulate và gửi qua tunnel tới đầu xa; đầu xa — kể cả khi không hề hỗ trợ GRE keepalive — vẫn de-encapsulate gói đó như một gói GRE bình thường rồi forward tiếp dựa trên inner header, và vô tình gửi nó quay ngược lại chính router đã gửi ban đầu. Router gốc nhận lại gói, kiểm tra Protocol Type = 0, và biết được: "đầu xa vẫn còn sống, vì gói của tôi đã đi vòng về được." Trên dòng QFX/EX, đúng cơ chế kiểu Cisco này không được triển khai.
GRE keepalive không vắng mặt hoàn toàn trên Junos — dòng SRX (security devices/firewall) có hỗ trợ, nhưng qua một cơ chế khác hẳn: cấu hình tại [edit protocols oam gre-tunnel interface <tên>] với hai tham số bắt buộc đi cùng nhau là keepalive-time (1–50 giây) và hold-time (5–250 giây, phải ≥ gấp đôi keepalive-time) — đây là một giao thức OAM trao đổi thật giữa hai đầu tunnel, không dùng mẹo tự-decapsulate như Cisco.
Chung cho cả hai dòng
- Firewall filter áp dụng được ở cả ingress lẫn egress, nhưng có giới hạn khi filter theo inner header so với outer header (chi tiết ở Mục 10).
- Trên Virtual Chassis, tên GRE interface không đổi khi số thứ tự (member number) của member thay đổi.
9. Class of Service (CoS) trên GRE
CoS trên GRE phải xử lý riêng ở hai đầu, vì bản chất traffic đã bị bọc thêm header giữa chừng — classifier ở giữa đường sẽ nhìn thấy outer header chứ không phải traffic gốc.
Chi tiết áp dụng tại từng điểm:
- Tại tunnel source: có thể áp dụng CoS scheduler (lấy dữ liệu phân loại từ classification ở ingress port vật lý), hoặc áp dụng cả scheduler lẫn rewrite rule (khi phân loại lại dựa trên chính GRE port). Rewrite rule ở đây nghĩa là việc ghi lại giá trị CoS (như DSCP hay 802.1p) vào gói tin trước khi gửi tiếp, để thiết bị chặng sau đọc đúng độ ưu tiên.
- Giới hạn quan trọng: không thể dùng BA classifier (behavior aggregate classifier — cơ chế phân loại traffic dựa thẳng vào giá trị CoS sẵn có trong header, ví dụ DSCP) trực tiếp trên interface
gr-. Muốn phân loại traffic trên GRE interface, phải dùng firewall filter thay thế. - Tại tunnel remote: áp dụng đầy đủ CoS classifier, scheduler, và rewrite rule ngay trên egress port vật lý, y như một luồng traffic thông thường không liên quan gì tunnel.
10. Firewall filters trên GRE
Vì gói tin GRE luôn có hai lớp header tồn tại song song — outer (dùng để định tuyến gói đã tunnel) và inner (chính là gói gốc) — firewall filter trên GRE phải xác định rõ đang lọc theo lớp nào.
Hai cách áp dụng chính, tùy loại endpoint:
- Filter theo outer header — áp tại điểm gói tin còn đang ở dạng đã encapsulate (ví dụ lọc theo chính outer source/destination IP, trước khi nó được de-encapsulate).
- Filter theo inner header — áp sau khi gói đã được de-encapsulate về đúng gói gốc, lọc như thể đang xử lý traffic thông thường không hề đi qua tunnel.
Ngoài hai cách trên, Junos còn cho phép một hướng tiếp cận khác đáng chú ý: dùng firewall filter để tự de-encapsulate GRE traffic mà không cần cấu hình hẳn một tunnel interface (gr-0/0/0). Lợi ích chính của cách này là khả năng mở rộng (scalability) — không bị ràng buộc bởi trần số lượng tunnel interface đã nêu ở Mục 8, phù hợp khi cần xử lý số lượng traffic flow GRE rất lớn mà không muốn quản lý từng interface riêng lẻ.
Nguồn tham khảo
Nguồn gốc: Juniper Networks — Junos OS Documentation, "GRE Tunnel" (link).
- Cấu trúc GRE header 4 byte bắt buộc (C, Reserved0, Version, Protocol Type) và Checksum/Reserved1 tùy chọn — RFC 2784, rfc-editor.org/rfc/rfc2784.
- Key field (multiplexing traffic flow) và Sequence Number field (in-order, unreliable) — RFC 2890, rfc-editor.org/rfc/rfc2890.
- GRE overhead 24 byte, MTU 1476 byte với physical MTU 1500, khuyến nghị MTU 1400 khi kết hợp IPsec — 2026, Cisco: Resolve IPv4 Fragmentation, MTU, MSS, and PMTUD Issues with GRE and IPsec.
- GRE keepalive là mở rộng riêng của Cisco, không nằm trong RFC 2784/2890, cơ chế gửi gói Protocol Type = 0 để tự kiểm tra vòng lặp — 2026, Cisco: Understand GRE Tunnel Keepalives.
- Junos SRX hỗ trợ GRE keepalive qua
protocols oam gre-tunnel interface, tham sốkeepalive-time(1–50s) vàhold-time(5–250s, ≥ 2× keepalive-time) — Juniper: Configuring GRE Keepalive Time.