GRE 심화 (Generic Routing Encapsulation)
Linux 커널 GRE 서브시스템: RFC 2784/2890 프로토콜 구조, ip_gre/ip6_gre 커널 모듈, GRE/GRETAP/ERSPAN 터널 유형, 키·시퀀스·체크섬 옵션, Netfilter 연동, GSO/GRO 오프로드, PPTP, NVGRE, MTU/PMTUD 이슈, 성능 튜닝, 디버깅 종합 가이드.
GRE 개요
GRE(Generic Routing Encapsulation)는 임의의 네트워크 계층 프로토콜을 다른 네트워크 계층 프로토콜 위에 캡슐화하여 전송하는 터널링 프로토콜입니다. IP 프로토콜 번호 47을 사용하며, TCP/UDP와 달리 포트 개념이 없고 순수한 캡슐화 메커니즘으로 동작합니다.
| 특성 | GRE | IPSec (ESP) | VXLAN | WireGuard |
|---|---|---|---|---|
| 계층 | IP 프로토콜 47 | IP 프로토콜 50 | UDP 4789 | UDP 51820 |
| 캡슐화 대상 | L2/L3 모두 가능 | L3 전용 | L2 프레임 | L3 전용 |
| 암호화 | 없음 (IPSec 병용) | 내장 (AES-GCM 등) | 없음 (MACsec 병용) | 내장 (ChaCha20) |
| 오버헤드 | 4~16바이트 | 36~73바이트 | 50바이트 | 60바이트 |
| NAT 통과 | 불가 (포트 없음) | NAT-T (UDP 4500) | 가능 (UDP) | 가능 (UDP) |
| 멀티캐스트 | 지원 | 제한적 | 지원 | 미지원 |
| 커널 모듈 | ip_gre, ip6_gre | xfrm, esp4/6 | vxlan | wireguard |
GRE의 핵심 장점은 프로토콜 불가지론(protocol-agnostic)입니다. EtherType 필드를 통해 IPv4, IPv6, Ethernet, MPLS 등 다양한 페이로드를 캡슐화할 수 있으며, 라우팅 프로토콜의 멀티캐스트 패킷도 터널을 통해 전달할 수 있습니다.
GRE 패킷 구조
GRE 헤더 포맷 (RFC 2784 / RFC 2890)
RFC 2784는 원본 RFC 1701의 GRE 헤더를 단순화했으며, RFC 2890이 Key와 Sequence Number 확장을 추가했습니다. 커널 구현은 두 RFC를 모두 지원합니다.
/*
* GRE 헤더 구조 (RFC 2784 + RFC 2890 확장)
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |C| |K|S| Reserved0 | Ver | Protocol Type |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Checksum (optional) | Reserved1 (optional) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Key (optional) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Sequence Number (optional) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* C (bit 0) : Checksum 존재 여부
* K (bit 2) : Key 존재 여부
* S (bit 3) : Sequence Number 존재 여부
* Ver : 버전 (0 = RFC 2784, 1 = PPTP용 Enhanced GRE)
* Protocol Type : 캡슐화된 페이로드의 EtherType
*/
/* 커널 정의: include/net/gre.h */
struct gre_base_hdr {
__be16 flags; /* C, K, S 플래그 + Reserved + Ver */
__be16 protocol; /* 페이로드 EtherType (예: 0x0800=IPv4, 0x86DD=IPv6, 0x6558=TEB) */
};
| 플래그 비트 | 매크로 | 설명 | 추가 헤더 크기 |
|---|---|---|---|
| C (bit 0) | GRE_CSUM (0x8000) |
Checksum + Reserved1 필드 존재 | +4바이트 |
| K (bit 2) | GRE_KEY (0x2000) |
Key 필드 존재 (터널 식별/다중화) | +4바이트 |
| S (bit 3) | GRE_SEQ (0x1000) |
Sequence Number 필드 존재 (순서 보장) | +4바이트 |
| Ver (bits 13-15) | GRE_VERSION |
0 = 표준 GRE, 1 = Enhanced GRE (PPTP) | — |
전체 캡슐화 패킷 구조
커널 GRE 아키텍처
모듈 구조
Linux 커널의 GRE 구현은 여러 모듈로 계층화되어 있습니다:
/*
* 커널 GRE 모듈 계층 구조
*
* ┌─────────────────────────────────────────────────────┐
* │ 사용자 공간: iproute2 (ip tunnel / ip link) │
* └──────────────────────┬──────────────────────────────┘
* │ Netlink (RTM_NEWTUNNEL / RTM_NEWLINK)
* ┌──────────────────────┴──────────────────────────────┐
* │ net/ipv4/ip_gre.c — GRE/GRETAP over IPv4 │
* │ net/ipv6/ip6_gre.c — GRE/GRETAP over IPv6 │
* │ net/ipv4/ip_tunnel.c — 공통 터널 프레임워크 │
* │ drivers/net/gre/ — ERSPAN 전용 드라이버 │
* ├─────────────────────────────────────────────────────┤
* │ net/ipv4/gre_demux.c — GRE 프로토콜 디먹스 │
* │ include/net/gre.h — GRE 헤더/플래그 정의 │
* ├─────────────────────────────────────────────────────┤
* │ net/ipv4/ip_tunnel_core.c — iptunnel_xmit/rcv 공통 │
* │ include/net/ip_tunnels.h — struct ip_tunnel 정의 │
* └─────────────────────────────────────────────────────┘
*/
| 커널 모듈 | 소스 파일 | 역할 |
|---|---|---|
gre |
net/ipv4/gre_demux.c |
IP 프로토콜 47 수신 디먹싱, GRE 핸들러 등록 프레임워크 |
ip_gre |
net/ipv4/ip_gre.c |
IPv4 GRE/GRETAP/ERSPAN 터널 디바이스 구현 |
ip6_gre |
net/ipv6/ip6_gre.c |
IPv6 GRE/GRETAP/ERSPAN 터널 디바이스 구현 |
ip_tunnel |
net/ipv4/ip_tunnel.c |
IPv4 터널 공통 로직 (lookup, xmit, rcv, 통계) |
| — | net/ipv4/ip_tunnel_core.c |
iptunnel_xmit(), iptunnel_pull_header() 등 공통 함수 |
핵심 자료구조: struct ip_tunnel
/* include/net/ip_tunnels.h — GRE 터널 디바이스의 private 데이터 */
struct ip_tunnel {
struct ip_tunnel __rcu *next; /* 해시 체인의 다음 터널 */
struct hlist_node hash_node; /* 해시 테이블 연결 */
struct net_device *dev; /* 터널 net_device */
struct net *net; /* 네트워크 네임스페이스 */
unsigned long err_time; /* ICMP 에러 rate limit 타임스탬프 */
int err_count; /* ICMP 에러 카운트 */
struct ip_tunnel_parm parms; /* ★ 터널 파라미터 (src, dst, key, flags) */
/* 헤더 캐시 — 고속 경로에서 매번 헤더를 재구성하지 않기 위함 */
int hlen; /* GRE 헤더 길이 (4~16) */
int tun_hlen; /* 외부 IP + GRE 헤더 전체 길이 */
int mlink; /* 물리 디바이스 ifindex */
struct ip_tunnel_prl_entry __rcu *prl; /* ISATAP PRL (거의 미사용) */
struct gro_cells gro_cells; /* GRO 처리용 per-CPU 셀 */
bool collect_md; /* metadata 모드 (Collect Metadata) */
struct dst_cache dst_cache; /* 라우팅 캐시 */
struct ip_tunnel_key key; /* flow-based 터널 키 */
};
/* 터널 파라미터 — iproute2 'ip tunnel add' 시 설정 */
struct ip_tunnel_parm {
char name[IFNAMSIZ]; /* 터널 디바이스 이름 */
int link; /* 물리 디바이스 ifindex (0=auto) */
__be16 i_flags; /* 입력 GRE 플래그 (GRE_KEY, GRE_CSUM, GRE_SEQ) */
__be16 o_flags; /* 출력 GRE 플래그 */
__be32 i_key; /* 입력 GRE 키 */
__be32 o_key; /* 출력 GRE 키 */
struct iphdr iph; /* 외부 IP 헤더 템플릿 (saddr, daddr, ttl, tos) */
};
GRE 수신 경로 — 디먹싱
IP 레이어가 프로토콜 번호 47 패킷을 수신하면 gre_demux.c의 핸들러로 전달됩니다:
/* net/ipv4/gre_demux.c — GRE 수신 흐름 */
/* 1. IP 레이어에서 GRE 핸들러 호출 */
static int gre_rcv(struct sk_buff *skb)
{
const struct gre_protocol *proto;
u8 ver;
/* GRE 헤더에서 버전 필드 추출 */
ver = skb->data[1] & 0x7;
if (ver >= GREPROTO_MAX)
goto drop;
/* 등록된 버전별 핸들러 호출
* ver=0: ip_gre.c의 gre_rcv() → 표준 GRE
* ver=1: pptp.c의 pptp_rcv() → PPTP (Enhanced GRE) */
proto = rcu_dereference(gre_proto[ver]);
if (!proto || !proto->handler)
goto drop;
return proto->handler(skb);
...
}
/* 2. ip_gre.c에서의 GRE 패킷 처리 */
static int gre_rcv(struct sk_buff *skb)
{
struct tnl_ptk_info tpi;
/* GRE 헤더 파싱: flags, key, seq, protocol type 추출 */
if (gre_parse_header(skb, &tpi, NULL, htons(ETH_P_IP), 0) < 0)
goto drop;
/* ERSPAN 처리 (Protocol Type 0x88BE) */
if (tpi.proto == htons(ETH_P_ERSPAN) ||
tpi.proto == htons(ETH_P_ERSPAN2))
return erspan_rcv(skb, &tpi, hlen);
/* ip_tunnel_lookup()으로 매칭되는 터널 디바이스 탐색 */
return ip_tunnel_rcv(tunnel, skb, &tpi, tun->hlen);
}
GRE 송신 경로
/* net/ipv4/ip_gre.c — GRE 패킷 송신 */
static netdev_tx_t gre_tap_xmit(struct sk_buff *skb,
struct net_device *dev)
{
struct ip_tunnel *tunnel = netdev_priv(dev);
if (tunnel->collect_md) {
/* Metadata 모드: skb의 tunnel_info에서 dst/key 추출
* → OVS, TC tunnel_key 등 flow-based 터널에서 사용 */
gre_fb_xmit(skb, dev, htons(ETH_P_TEB));
} else {
/* 일반 모드: ip_tunnel_parm에서 dst/key 사용 */
gre_build_header(skb, tunnel->tun_hlen,
tunnel->parms.o_flags,
htons(ETH_P_TEB),
tunnel->parms.o_key,
htonl(tunnel->o_seqno++));
/* ip_tunnel_xmit() → 외부 IP 헤더 추가 + 라우팅 + 송신 */
ip_tunnel_xmit(skb, dev, &tunnel->parms.iph,
tunnel->parms.iph.protocol);
}
return NETDEV_TX_OK;
}
/* GRE 헤더 빌드 — 고속 경로 인라인 함수 */
static void gre_build_header(struct sk_buff *skb, int hdr_len,
__be16 flags, __be16 proto,
__be32 key, __be32 seq)
{
struct gre_base_hdr *greh;
skb_push(skb, hdr_len); /* 헤더 공간 확보 */
skb_reset_transport_header(skb); /* transport 헤더 = GRE 시작점 */
greh = (struct gre_base_hdr *)skb_transport_header(skb);
greh->flags = gre_tnl_flags_to_gre_flags(flags);
greh->protocol = proto;
/* 선택적 필드를 순서대로 채움 */
if (flags & TUNNEL_CSUM)
*ptr++ = 0; /* 체크섬은 나중에 계산 */
if (flags & TUNNEL_KEY)
*ptr++ = key;
if (flags & TUNNEL_SEQ)
*ptr++ = seq;
if (flags & TUNNEL_CSUM)
/* GRE 체크섬 계산 (GRE 헤더 + 페이로드 전체) */
*(__sum16 *)&greh[1] = gre_checksum(skb);
}
GRE 터널 유형
GRE 터널 (L3)
기본 GRE 터널은 L3(IP) 패킷을 캡슐화합니다. net_device 타입은 ARPHRD_IPGRE이며, L2 헤더 없이 IP 패킷을 직접 GRE로 감쌉니다.
# 기본 GRE 터널 생성 (L3 — point-to-point)
ip tunnel add gre1 mode gre \
local 10.0.0.1 remote 10.0.0.2 \
ttl 64
ip addr add 192.168.100.1/30 dev gre1
ip link set gre1 up
# 확인
ip tunnel show gre1
ip -d link show gre1
# 커널 내부: ip_gre.c → ipgre_newlink() → alloc_netdev()
# dev→type = ARPHRD_IPGRE
# dev→hard_header_len = 0 (L3 터널이므로 L2 헤더 없음)
# Protocol Type = 0x0800 (IPv4) 또는 0x86DD (IPv6)
GRETAP 터널 (L2)
GRETAP은 Ethernet 프레임 전체를 캡슐화하여 L2 브리징이 가능합니다. Protocol Type은 0x6558(TEB)이며, 브리지에 포트로 추가할 수 있습니다.
# GRETAP 터널 생성 (L2 — Ethernet 프레임 캡슐화)
ip link add gretap1 type gretap \
local 10.0.0.1 remote 10.0.0.2 \
ttl 64
ip link set gretap1 up
# L2 브리징에 참여
ip link add br0 type bridge
ip link set gretap1 master br0
ip link set eth1 master br0
ip link set br0 up
# → eth1과 gretap1이 같은 브로드캐스트 도메인을 공유
# 커널 내부: dev→type = ARPHRD_ETHER
# dev→hard_header_len = ETH_HLEN (14)
# Protocol Type = 0x6558 (Transparent Ethernet Bridging)
| 특성 | GRE (L3) | GRETAP (L2) |
|---|---|---|
| 캡슐화 대상 | IP 패킷 (L3) | Ethernet 프레임 (L2) |
| ARPHRD | ARPHRD_IPGRE | ARPHRD_ETHER |
| Protocol Type | 0x0800 (IPv4) / 0x86DD (IPv6) | 0x6558 (TEB) |
| 브리지 포트 | 불가 | 가능 |
| MAC 주소 | 없음 (point-to-point) | 있음 (자동 생성) |
| ARP | 불필요 (NOARP) | 정상 동작 |
| 오버헤드 | 외부IP(20) + GRE(4~16) | 외부IP(20) + GRE(4~16) + 내부ETH(14) |
| 대표 사용 사례 | site-to-site VPN, 라우팅 프로토콜 터널링 | L2 VPN, 원격 브리징, OVS 오버레이 |
IPv6 GRE (ip6_gre)
IPv6를 외부 전송 프로토콜로 사용하는 GRE 터널입니다. ip6_gre.c 모듈이 처리하며, ip6gre/ip6gretap 두 가지 모드를 지원합니다.
# IPv6 GRE 터널 (L3)
ip link add ip6gre1 type ip6gre \
local 2001:db8::1 remote 2001:db8::2
# IPv6 GRETAP 터널 (L2)
ip link add ip6gretap1 type ip6gretap \
local 2001:db8::1 remote 2001:db8::2
# 커널: net/ipv6/ip6_gre.c → ip6gre_newlink()
# 외부 IP 헤더가 IPv6 (40바이트)이므로 오버헤드 증가
ERSPAN (Encapsulated Remote SPAN)
ERSPAN은 GRE를 이용해 미러링된 트래픽을 원격으로 전송하는 프로토콜입니다. 네트워크 모니터링과 IDS/IPS 배치에 주로 사용됩니다.
| ERSPAN 버전 | Protocol Type | 추가 헤더 | 특징 |
|---|---|---|---|
| Type I | 0x88BE | 없음 | GRE Key 없이 단순 미러링 |
| Type II (v1) | 0x88BE | 8바이트 ERSPAN 헤더 | Session ID, VLAN, COS, 포트 인덱스 |
| Type III (v2) | 0x22EB | 12바이트 ERSPAN 헤더 + 선택적 서브헤더 | 타임스탬프 (100μs 해상도), BSO, FT, SGT |
# ERSPAN Type II 터널 (미러링 소스)
ip link add erspan1 type erspan \
local 10.0.0.1 remote 10.0.0.2 \
erspan_ver 1 erspan 100 # session ID = 100
# ERSPAN Type III 터널
ip link add erspan2 type erspan \
local 10.0.0.1 remote 10.0.0.2 \
erspan_ver 2 erspan_dir ingress erspan_hwid 0x7
ip link set erspan1 up
# tc mirror 액션으로 트래픽 미러링 연결
tc qdisc add dev eth0 ingress
tc filter add dev eth0 ingress protocol all \
matchall action mirred egress mirror dev erspan1
# 커널 내부: ip_gre.c → erspan_xmit()
# struct erspan_base_hdr + struct erspan_metadata
# GRE Key = (erspan_ver << 28) | session_id
/* include/net/erspan.h — ERSPAN 헤더 구조체 */
struct erspan_base_hdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 vlan_upper:4,
ver:4;
__u8 vlan:8;
__u8 session_id_upper:2,
t:1,
en:2,
cos:3;
__u8 session_id:8;
#else
...
#endif
};
/* ERSPAN Type III 확장 */
struct erspan_md2 {
__be32 timestamp; /* 100μs granularity */
__be16 sgt; /* Security Group Tag */
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 hwid_upper:2,
ft:5,
p:1;
__u8 o:1,
gra:2,
dir:1,
hwid:4;
#else
...
#endif
};
GRE 키, 시퀀스 번호, 체크섬
GRE Key를 이용한 터널 다중화
GRE Key는 동일한 src/dst IP 쌍에서 여러 논리 터널을 다중화하는 32비트 식별자입니다.
커널은 터널 lookup 시 (remote_ip, local_ip, key) 3-tuple로 매칭합니다.
# 같은 엔드포인트에 서로 다른 키로 다중 터널
ip link add gre-a type gre \
local 10.0.0.1 remote 10.0.0.2 key 100
ip link add gre-b type gre \
local 10.0.0.1 remote 10.0.0.2 key 200
# 입력/출력 키를 별도로 설정 (비대칭 키)
ip link add gre-asym type gre \
local 10.0.0.1 remote 10.0.0.2 \
ikey 100 okey 200
# 커널 내부: ip_tunnel_lookup()
# → hash(remote, local, key)로 O(1) 탐색
# fallback: wildcard remote (0.0.0.0) → 다중 피어 수용 가능
/* net/ipv4/ip_tunnel.c — 터널 lookup 로직 */
struct ip_tunnel *ip_tunnel_lookup(struct ip_tunnel_net *itn,
int link, __be16 flags, __be32 remote, __be32 local, __be32 key)
{
struct ip_tunnel *t, *cand = NULL;
struct hlist_head *head;
unsigned int hash;
/* 1차: (remote, local, key) 정확 매칭 */
hash = ip_tunnel_hash(key, remote);
head = &itn->tunnels[hash];
hlist_for_each_entry_rcu(t, head, hash_node) {
if (local == t->parms.iph.saddr &&
remote == t->parms.iph.daddr &&
key == t->parms.i_key)
return t; /* 정확 매칭 */
}
/* 2차: wildcard remote (0.0.0.0) 매칭 */
hash = ip_tunnel_hash(key, 0);
head = &itn->tunnels[hash];
hlist_for_each_entry_rcu(t, head, hash_node) {
if (local == t->parms.iph.saddr &&
key == t->parms.i_key)
cand = t;
}
/* 3차: fallback 터널 (gre0 등) */
...
return cand;
}
시퀀스 번호
GRE 시퀀스 번호는 패킷 순서 보장과 중복 탐지에 사용됩니다. 단, 커널의 기본 GRE 구현은 시퀀스 번호 검증 시 순서가 어긋난 패킷을 드롭합니다.
# 시퀀스 번호 활성화
ip link add gre1 type gre \
local 10.0.0.1 remote 10.0.0.2 seq
# 주의: 시퀀스 번호 활성화 시 out-of-order 패킷이 드롭됨
# ECMP 환경이나 비대칭 라우팅에서는 비활성화 권장
/* 수신 측 시퀀스 번호 검증 */
if (flags & TUNNEL_SEQ) {
if (ntohl(tpi->seq) < tunnel->i_seqno) {
/* 이전 시퀀스 → 드롭 (replay 또는 reordering) */
tunnel->dev->stats.rx_fifo_errors++;
tunnel->dev->stats.rx_errors++;
goto drop;
}
tunnel->i_seqno = ntohl(tpi->seq) + 1;
}
체크섬
GRE 체크섬은 GRE 헤더와 캡슐화된 페이로드 전체에 대한 무결성 검증입니다. 외부 IP 헤더의 체크섬과는 별도로 동작합니다.
# 체크섬 활성화
ip link add gre1 type gre \
local 10.0.0.1 remote 10.0.0.2 csum
# 입력/출력 별도 설정
ip link add gre1 type gre \
local 10.0.0.1 remote 10.0.0.2 \
icsum ocsum # 양방향 체크섬
tx-gre-csum-segmentation)를 지원하는 NIC에서는 영향이 적지만, 소프트웨어 전용 환경에서는 처리량이 10~20% 감소할 수 있습니다. 내부 페이로드가 이미 TCP/UDP 체크섬으로 보호되므로 대부분의 환경에서 GRE 체크섬은 불필요합니다.
고급 설정
Collect Metadata 모드 (Flow-Based Tunneling)
Collect Metadata 모드(external)는 터널 파라미터를 디바이스에 고정하지 않고, 각 패킷의 메타데이터에서 동적으로 추출합니다.
OVS(Open vSwitch), TC tunnel_key 액션, BPF 프로그램에서 활용합니다.
# Collect Metadata 모드 GRE 디바이스
ip link add gre-md type gre external
# TC를 이용한 flow-based 터널링
tc qdisc add dev gre-md ingress
tc filter add dev gre-md ingress \
flower enc_dst_ip 10.0.0.2 enc_key_id 100 \
action tunnel_key unset \
action mirred egress redirect dev eth0
# 송신 방향: 패킷에 터널 메타데이터 설정
tc qdisc add dev eth0 ingress
tc filter add dev eth0 ingress \
flower dst_ip 192.168.0.0/24 \
action tunnel_key set id 100 dst_ip 10.0.0.2 \
action mirred egress redirect dev gre-md
/* 커널 내부: collect_md 모드 송신 */
static netdev_tx_t gre_fb_xmit(struct sk_buff *skb,
struct net_device *dev,
__be16 proto)
{
struct ip_tunnel_info *tun_info;
/* skb에 연결된 tunnel metadata 추출 */
tun_info = skb_tunnel_info(skb);
if (!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX))
goto err_free_skb;
key = &tun_info->key;
/* key→u.ipv4.dst → 외부 목적지 IP
* key→tun_id → GRE Key
* key→tun_flags → GRE 플래그 (CSUM, KEY, SEQ) */
...
}
다중점 GRE (mGRE)
원격 주소를 지정하지 않은 GRE 터널은 여러 피어와 동적으로 통신할 수 있습니다. NHRP(Next Hop Resolution Protocol)와 결합하면 DMVPN(Dynamic Multipoint VPN) 구현이 가능합니다.
# mGRE 터널 (remote 미지정)
ip tunnel add mgre0 mode gre \
local 10.0.0.1 key 1000 \
ttl 64
# remote를 지정하지 않았으므로 wildcard 터널
# 패킷의 목적지 IP를 기반으로 NHRP가 next-hop 결정
# → 라우팅 테이블 또는 NHRP 캐시에서 외부 목적지 결정
ip addr add 172.16.0.1/24 dev mgre0
ip link set mgre0 up
# NHRP 데몬 (OpenNHRP 또는 FRR)이 필요
# Cisco DMVPN과 상호 운용 가능
GRE Keepalive
GRE keepalive는 터널 피어의 가용성을 확인하는 메커니즘입니다. 커널은 ip tunnel change으로 keepalive 간격을 설정할 수 있습니다.
# Keepalive 설정: 10초 간격, 3회 실패 시 down
ip tunnel change gre1 keepalive 10 3
# 커널 내부: keepalive는 빈 GRE 패킷을 자신에게 보내는 방식
# 피어가 살아 있으면 외부 IP를 반전하여 되돌려 보냄
# → 되돌아온 패킷 수신 = 피어 alive
GRE와 Netfilter/conntrack
nf_conntrack_proto_gre
GRE는 TCP/UDP와 달리 포트가 없으므로, conntrack은 GRE Key를 포트 대신 사용하여 연결을 추적합니다.
PPTP helper (nf_conntrack_pptp)는 GRE 콜 ID를 이용한 NAT를 지원합니다.
/* net/netfilter/nf_conntrack_proto_gre.c
*
* GRE conntrack 튜플:
* src: (src_ip, gre_key_or_call_id)
* dst: (dst_ip, gre_key_or_call_id)
*
* GRE v0 (표준): Key 필드를 식별자로 사용
* GRE v1 (PPTP): Call ID를 식별자로 사용
*/
/* conntrack 조회 */
conntrack -L -p gre
# 출력 예:
# gre 47 src=10.0.0.1 dst=10.0.0.2 srckey=0x00000064 dstkey=0x00000064
# src=10.0.0.2 dst=10.0.0.1 srckey=0x00000064 dstkey=0x00000064
nftables/iptables GRE 필터링
# nftables: GRE 프로토콜 필터링
nft add rule inet filter forward \
ip protocol gre accept
# GRE 키 기반 필터링 (raw 페이로드 매칭)
nft add rule inet filter forward \
ip protocol gre \
@th,32,32 100 accept # GRE Key = 100 (offset 32bit, 32bit width)
# iptables: GRE 프로토콜 허용
iptables -A FORWARD -p gre -j ACCEPT
# PPTP helper 로드 (GRE v1 NAT 지원)
modprobe nf_conntrack_pptp
modprobe nf_nat_pptp
# PPTP 서버로의 DNAT
iptables -t nat -A PREROUTING -p tcp --dport 1723 \
-j DNAT --to-destination 192.168.1.100
# → nf_conntrack_pptp가 GRE 세션을 자동 추적하여 NAT 수행
GRE 하드웨어/소프트웨어 오프로드
GSO (Generic Segmentation Offload)
GSO는 GRE 터널 내부의 대형 TCP 세그먼트를 지연 분할하여 처리량을 극대화합니다:
/* GSO 유형: include/linux/skbuff.h */
SKB_GSO_GRE /* GRE 터널의 GSO — 내부 IP 분할 */
SKB_GSO_GRE_CSUM /* GRE 체크섬 포함 GSO — HW가 GRE csum도 처리 */
/* NIC feature 플래그 */
NETIF_F_GSO_GRE /* tx-gre-segmentation */
NETIF_F_GSO_GRE_CSUM /* tx-gre-csum-segmentation */
# NIC의 GRE 오프로드 기능 확인
ethtool -k eth0 | grep gre
# tx-gre-segmentation: on
# tx-gre-csum-segmentation: on
# GRE 오프로드 비활성화 (디버깅용)
ethtool -K eth0 tx-gre-segmentation off
ethtool -K eth0 tx-gre-csum-segmentation off
GRO (Generic Receive Offload)
수신 측에서는 GRO가 여러 GRE 패킷을 하나의 큰 패킷으로 병합하여 프로토콜 스택 처리 효율을 높입니다:
/* net/ipv4/gre_offload.c — GRE GRO 콜백 */
static struct sk_buff *gre_gro_receive(
struct list_head *head, struct sk_buff *skb)
{
/* GRE 헤더 파싱 후, 동일한 flow (src/dst/key)의 패킷을 병합
* → 내부 TCP 세그먼트를 하나의 큰 skb로 결합
* → 프로토콜 스택을 한 번만 타므로 CPU 절약 */
...
}
/* ip_gre.c에서 GRO 셀 초기화 */
gro_cells_init(&tunnel->gro_cells, dev);
/* → per-CPU GRO 처리로 멀티코어 확장성 확보 */
| 오프로드 기능 | 방향 | ethtool 플래그 | 효과 |
|---|---|---|---|
| GSO (GRE) | TX | tx-gre-segmentation |
64KB 청크를 MTU 크기로 지연 분할 |
| GSO (GRE+csum) | TX | tx-gre-csum-segmentation |
GSO + HW GRE 체크섬 계산 |
| GRO | RX | rx-gro-hw (NIC별) |
수신 패킷 병합으로 인터럽트/스택 처리 감소 |
| RX Checksum | RX | rx-checksum |
내부/외부 체크섬 HW 검증 |
MTU와 단편화 (Path MTU Discovery)
GRE 캡슐화는 패킷 크기를 증가시키므로 MTU 관리가 매우 중요합니다. 잘못된 MTU 설정은 블랙홀, 성능 저하, 연결 실패의 주요 원인입니다.
MTU 계산
/*
* GRE 터널 MTU 계산
*
* 물리 MTU = 1500 (Ethernet)
*
* GRE (기본, 옵션 없음):
* 외부 IP(20) + GRE(4) = 24바이트 오버헤드
* → 터널 MTU = 1500 - 24 = 1476
*
* GRE + Key:
* 외부 IP(20) + GRE(4+4) = 28바이트
* → 터널 MTU = 1500 - 28 = 1472
*
* GRE + Key + Seq + Csum:
* 외부 IP(20) + GRE(4+4+4+4) = 36바이트
* → 터널 MTU = 1500 - 36 = 1464
*
* GRETAP + Key (L2):
* 외부 IP(20) + GRE(8) + 내부 Ethernet(14) = 42바이트
* → 터널 MTU = 1500 - 42 = 1458
*
* IPv6 GRE + Key:
* 외부 IPv6(40) + GRE(8) = 48바이트
* → 터널 MTU = 1500 - 48 = 1452
*/
| 터널 유형 | 오버헤드 | 터널 MTU (물리 1500) |
|---|---|---|
| GRE (기본) | 24바이트 | 1476 |
| GRE + Key | 28바이트 | 1472 |
| GRE + Key + Seq | 32바이트 | 1468 |
| GRE + Key + Seq + Csum | 36바이트 | 1464 |
| GRETAP (기본) | 38바이트 | 1462 |
| GRETAP + Key | 42바이트 | 1458 |
| IPv6 GRE (기본) | 44바이트 | 1456 |
| ERSPAN Type II | 50바이트 | 1450 |
| ERSPAN Type III | 54바이트 | 1446 |
Path MTU Discovery
# 터널 MTU 명시 설정
ip link set gre1 mtu 1400
# PMTUD 관련 커널 동작:
# 1. 외부 IP 헤더에 DF(Don't Fragment) 비트 설정 (기본값)
# 2. 중간 라우터가 ICMP "Fragmentation Needed" 반환
# 3. 커널이 터널 MTU를 동적으로 조정
# DF 비트 정책 설정
ip tunnel change gre1 pmtudisc # DF 비트 설정 (기본값 — PMTUD 활성화)
ip tunnel change gre1 nopmtudisc # DF 비트 해제 (단편화 허용)
# MSS clamping으로 블랙홀 방지
iptables -t mangle -A FORWARD -o gre1 \
-p tcp --tcp-flags SYN,RST SYN \
-j TCPMSS --clamp-mss-to-pmtu
# nftables 동일 설정
nft add rule inet mangle forward \
oifname "gre1" tcp flags syn / syn,rst \
tcp option maxseg size set rt mtu
/* net/ipv4/ip_tunnel.c — 터널 송신 시 MTU 처리 */
void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
const struct iphdr *tnl_params, u8 protocol)
{
...
/* DF 비트가 설정되어 있고 패킷이 MTU를 초과하면 */
if (tnl_params->frag_off & htons(IP_DF)) {
if (skb->len > mtu) {
/* ICMP "Fragmentation Needed" 발신자에게 전송 */
icmp_ndo_send(skb, ICMP_DEST_UNREACH,
ICMP_FRAG_NEEDED,
htonl(mtu));
goto tx_error;
}
}
...
}
nopmtudisc로 단편화 허용 (성능 감소).
GRE 변형 프로토콜
PPTP (Point-to-Point Tunneling Protocol)
PPTP는 Enhanced GRE(버전 1)를 사용하는 VPN 프로토콜입니다. TCP 1723 포트로 제어 채널을 설정하고, GRE v1으로 데이터를 전송합니다.
/*
* Enhanced GRE (Version 1) — PPTP 전용
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |C|R|K|S|s|Recur|A| Flags | Ver | Protocol Type (880B) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Key (Payload Length) | Key (Call ID) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Sequence Number (optional) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Acknowledgment Number (optional) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* Ver = 1 (Enhanced GRE)
* K = 1 항상 (Call ID가 Key 역할)
* Protocol Type = 0x880B (PPP)
* A 비트: Acknowledgment 필드 존재
*
* 커널 모듈: drivers/net/ppp/pptp.c
* conntrack: nf_conntrack_pptp, nf_nat_pptp
*/
# PPTP 관련 커널 모듈
modprobe ppp_generic
modprobe pptp
modprobe nf_conntrack_pptp # GRE v1 conntrack
modprobe nf_nat_pptp # PPTP NAT helper
# PPTP 서버는 pptpd, 클라이언트는 pptp-linux/NetworkManager 사용
# 보안 주의: PPTP의 MS-CHAPv2 인증은 취약 — IPSec/WireGuard 권장
NVGRE (Network Virtualization using GRE)
NVGRE(RFC 7637)는 데이터 센터에서 GRE Key의 상위 24비트를 VSID(Virtual Subnet ID)로 사용하여 멀티테넌트 네트워크를 구현합니다.
/*
* NVGRE 패킷 구조:
* ┌──────────┬────────────┬─────────────────┬──────────┐
* │ 외부 IP │ GRE (K=1) │ 내부 Ethernet │ 내부 IP │
* │ (20 B) │ (8 B) │ (14 B) │ + 데이터 │
* └──────────┴────────────┴─────────────────┴──────────┘
*
* GRE Key (32비트):
* ┌──────────────────────────────┬──────────┐
* │ VSID (24비트) │ FlowID │
* │ 가상 서브넷 식별자 │ (8비트) │
* └──────────────────────────────┴──────────┘
*
* VSID: 최대 16M 가상 네트워크 (VLAN의 4096 한계 극복)
* FlowID: ECMP 로드 밸런싱용 엔트로피 소스
*
* Protocol Type = 0x6558 (TEB) — GRETAP과 동일
*/
# Linux에서 NVGRE 시뮬레이션 (GRETAP + Key)
ip link add nvgre1 type gretap \
local 10.0.0.1 remote 10.0.0.2 \
key 0x000064ff # VSID=100 (0x64), FlowID=0xff
# 실제 NVGRE 구현은 OVS 또는 하드웨어 VTEP에서 주로 사용
GRE-in-UDP (RFC 8086)
GRE를 UDP로 감싸서 NAT 통과와 ECMP 로드 밸런싱 문제를 해결합니다:
/*
* GRE-in-UDP 패킷 구조:
* ┌──────────┬──────────┬──────────┬──────────────┐
* │ 외부 IP │ UDP │ GRE │ 내부 페이로드 │
* │ (20 B) │ (8 B) │ (4~16 B) │ │
* └──────────┴──────────┴──────────┴──────────────┘
*
* UDP 소스 포트: flow entropy (ECMP 분산용)
* UDP 목적지 포트: 고정 (예: 4754)
*
* 장점:
* - NAT 통과 가능 (UDP 포트 활용)
* - ECMP 로드 밸런싱 (UDP 소스 포트 해시)
* - 기존 GRE 인프라와 호환
*
* 커널: FOU(Foo-over-UDP) 프레임워크 활용
*/
# FOU (Foo-over-UDP) 수신 포트 설정
modprobe fou
ip fou add port 4754 ipproto 47 # GRE-in-UDP 수신
# GRE 터널 생성 + FOU 캡슐화
ip link add gre-fou type gre \
local 10.0.0.1 remote 10.0.0.2 \
encap fou encap-sport auto encap-dport 4754
ip link set gre-fou up
실전 활용 시나리오
사이트 간 VPN (GRE + IPSec)
GRE 단독으로는 암호화가 없으므로, 일반적으로 IPSec과 결합하여 사용합니다. GRE가 터널링을, IPSec이 암호화를 담당합니다.
# 1. GRE 터널 생성
ip tunnel add gre-vpn mode gre \
local 203.0.113.1 remote 198.51.100.1 \
ttl 64 key 1000
ip addr add 172.16.0.1/30 dev gre-vpn
ip link set gre-vpn up
ip route add 192.168.2.0/24 dev gre-vpn
# 2. IPSec으로 GRE 트래픽 암호화 (xfrm)
ip xfrm state add \
src 203.0.113.1 dst 198.51.100.1 \
proto esp spi 0x1000 mode transport \
enc "aes" 0x$(openssl rand -hex 16) \
auth "hmac(sha256)" 0x$(openssl rand -hex 32)
ip xfrm state add \
src 198.51.100.1 dst 203.0.113.1 \
proto esp spi 0x1001 mode transport \
enc "aes" 0x$(openssl rand -hex 16) \
auth "hmac(sha256)" 0x$(openssl rand -hex 32)
# 3. IPSec 정책: GRE 트래픽(프로토콜 47)만 암호화
ip xfrm policy add \
src 203.0.113.1 dst 198.51.100.1 \
proto gre dir out \
tmpl src 203.0.113.1 dst 198.51.100.1 \
proto esp mode transport
ip xfrm policy add \
src 198.51.100.1 dst 203.0.113.1 \
proto gre dir in \
tmpl src 198.51.100.1 dst 203.0.113.1 \
proto esp mode transport
# 결과 패킷 구조:
# [외부 IP] [ESP] [GRE] [내부 IP] [페이로드]
# → GRE 터널 전체가 ESP로 암호화됨
멀티캐스트 라우팅 프로토콜 터널링
GRE의 핵심 사용 사례 중 하나는 OSPF, RIP 등의 멀티캐스트/브로드캐스트 라우팅 프로토콜을 인터넷을 통해 전달하는 것입니다:
# OSPF 멀티캐스트를 GRE로 전달
ip tunnel add gre-ospf mode gre \
local 10.0.0.1 remote 10.0.0.2 \
ttl 64
ip addr add 172.16.0.1/30 dev gre-ospf
ip link set gre-ospf up
ip link set gre-ospf multicast on # 멀티캐스트 활성화
# FRRouting OSPF 설정에서 GRE 인터페이스 포함
# interface gre-ospf
# ip ospf area 0.0.0.0
# ip ospf network point-to-point
OVS (Open vSwitch) GRE 오버레이
# OVS에서 GRE 포트 추가
ovs-vsctl add-br br-int
ovs-vsctl add-port br-int gre0 -- \
set interface gre0 type=gre \
options:remote_ip=10.0.0.2 \
options:key=flow # flow-based key (OVS가 동적 결정)
# OVS는 내부적으로 collect_md 모드의 GRE 디바이스를 사용
# → OpenFlow 규칙으로 터널 엔드포인트와 키를 동적 지정
네트워크 네임스페이스 간 GRE
# 네임스페이스 생성
ip netns add ns1
ip netns add ns2
# veth 쌍으로 네임스페이스 연결
ip link add veth1 type veth peer name veth2
ip link set veth1 netns ns1
ip link set veth2 netns ns2
ip netns exec ns1 ip addr add 10.0.0.1/24 dev veth1
ip netns exec ns1 ip link set veth1 up
ip netns exec ns2 ip addr add 10.0.0.2/24 dev veth2
ip netns exec ns2 ip link set veth2 up
# 각 네임스페이스에서 GRE 터널 생성
ip netns exec ns1 ip tunnel add gre1 mode gre \
local 10.0.0.1 remote 10.0.0.2 key 42
ip netns exec ns1 ip addr add 172.16.0.1/30 dev gre1
ip netns exec ns1 ip link set gre1 up
ip netns exec ns2 ip tunnel add gre1 mode gre \
local 10.0.0.2 remote 10.0.0.1 key 42
ip netns exec ns2 ip addr add 172.16.0.2/30 dev gre1
ip netns exec ns2 ip link set gre1 up
# 테스트
ip netns exec ns1 ping -c 3 172.16.0.2
성능 튜닝
성능 최적화 체크리스트
| 항목 | 기본값 | 권장 설정 | 효과 |
|---|---|---|---|
| GSO/GRO | on (NIC 지원 시) | on 유지 | 처리량 2~5배 향상 |
| GRE 체크섬 | off | off 유지 | 체크섬 계산 오버헤드 제거 |
| 시퀀스 번호 | off | off (ECMP 환경) | reorder 드롭 방지 |
| MTU | 자동 계산 | 명시 설정 + MSS clamp | 단편화/블랙홀 방지 |
| TTL | inherit (내부 TTL) | 64 고정 | TTL 소진 루프 방지 |
| txqueuelen | 1000 | 5000~10000 (고대역폭) | 큐 오버플로 감소 |
| RPS/RFS | off | on (멀티코어) | 터널 수신 CPU 분산 |
| nopmtudisc | off (DF 설정) | off 유지 + MSS clamp | 최적 MTU 자동 탐색 |
# 성능 최적화 적용 예시
ip link set gre1 mtu 1400 # 보수적 MTU
ip link set gre1 txqueuelen 5000 # 큐 확장
ethtool -K eth0 tx-gre-segmentation on # GSO 활성화
# MSS clamping (PMTUD 블랙홀 방지)
nft add rule inet mangle forward \
oifname "gre1" tcp flags syn / syn,rst \
tcp option maxseg size set rt mtu
# RPS 활성화 (터널 수신 CPU 분산)
echo ff > /sys/class/net/gre1/queues/rx-0/rps_cpus
# conntrack 비활성화 (순수 L3 터널, NAT 불필요 시)
nft add rule inet raw prerouting ip protocol gre notrack
nft add rule inet raw output ip protocol gre notrack
GRE vs VXLAN 성능 비교
| 항목 | GRE | VXLAN |
|---|---|---|
| 캡슐화 오버헤드 | 24~36바이트 | 50바이트 |
| ECMP 해싱 | 불리 (IP proto 47, 포트 없음) | 유리 (UDP 소스 포트 엔트로피) |
| NAT 통과 | 불가 | 가능 (UDP) |
| CPU 사용 | 낮음 (단순 헤더) | 중간 (UDP 처리 추가) |
| HW 오프로드 | 광범위 지원 | 광범위 지원 |
| 멀티캐스트 | 네이티브 지원 | 외부 학습 필요 (FDB) |
디버깅
디버깅 도구
# 1. 터널 상태 확인
ip tunnel show
ip -d link show gre1
ip -s link show gre1 # RX/TX 바이트, 패킷, 에러 통계
# 2. tcpdump로 GRE 패킷 캡처
tcpdump -i eth0 proto gre -nn -v
# → 외부 IP + GRE 헤더 + 내부 패킷 확인
# 내부 패킷도 디코딩
tcpdump -i eth0 proto gre -nn -v -e
# GRE 터널 인터페이스에서 캡처 (디캡슐레이션된 패킷)
tcpdump -i gre1 -nn -v
# 3. ip route get으로 경로 확인
ip route get 192.168.100.2 dev gre1
# 4. 커널 로그 확인
dmesg | grep -i gre
journalctl -k | grep -i tunnel
# 5. conntrack 확인 (GRE 세션)
conntrack -L -p gre
# 6. PMTUD 확인 (ICMP 에러 모니터)
tcpdump -i eth0 'icmp[0] == 3 and icmp[1] == 4' -nn -v
# → ICMP Destination Unreachable, Fragmentation Needed
자주 발생하는 문제
| 증상 | 원인 | 해결 방법 |
|---|---|---|
| 터널 인터페이스 UP이나 ping 불가 | 방화벽에서 프로토콜 47 차단 | iptables -A INPUT -p gre -j ACCEPT |
| 소형 패킷은 통과, 대형 패킷 실패 | MTU 불일치 / PMTUD 블랙홀 | MTU 수동 설정 + MSS clamping |
| RX 패킷 카운터 증가하나 전달 안 됨 | rp_filter (역방향 경로 필터) | sysctl net.ipv4.conf.gre1.rp_filter=0 |
| 터널 생성 시 "RTNETLINK: File exists" | gre0 기본 디바이스 이름 충돌 | ip link 스타일 사용 또는 다른 이름 지정 |
| GRE over NAT 실패 | GRE는 포트 없어 NAT 불가 | GRE-in-UDP (FOU) 사용 |
| TTL 초과 루프 | 재귀 라우팅 (터널 경로가 터널 자체) | TTL 고정, 라우팅 테이블 확인 |
| conntrack 테이블 가득 참 | GRE 세션 누적 | nf_conntrack_max 증가 또는 GRE notrack |
| ECMP 환경에서 seq 드롭 | 시퀀스 번호 순서 어긋남 | 시퀀스 번호 비활성화 |
ftrace를 이용한 커널 내부 추적
# GRE 관련 커널 함수 추적
cd /sys/kernel/debug/tracing
# function_graph 트레이서 활성화
echo function_graph > current_tracer
echo 'ip_tunnel_xmit' >> set_graph_function
echo 'ip_tunnel_rcv' >> set_graph_function
echo 'gre_rcv' >> set_graph_function
echo 'gre_build_header' >> set_graph_function
echo 1 > tracing_on
# 터널을 통해 패킷 전송 후 결과 확인
cat trace
# kprobe로 GRE 터널 lookup 추적
echo 'p:gre_lookup ip_tunnel_lookup remote=%si local=%dx key=%cx' \
> kprobe_events
echo 1 > events/kprobes/gre_lookup/enable
cat trace_pipe
sysctl 파라미터
| 파라미터 | 기본값 | 설명 |
|---|---|---|
net.ipv4.conf.gre1.rp_filter |
1 (strict) | 역방향 경로 필터링. 비대칭 라우팅 시 0으로 설정 |
net.ipv4.conf.gre1.forwarding |
0 | 터널을 통한 IP 포워딩 활성화 필요 |
net.ipv4.conf.gre1.accept_local |
0 | 자신의 IP가 소스인 패킷 수신 허용 (keepalive 등) |
net.ipv4.conf.gre1.disable_policy |
0 | IPSec 정책 무시 (IPSec 미사용 시) |
net.ipv4.ip_forward |
0 | 전역 IP 포워딩 — GRE 라우터 역할 시 1 필수 |
net.ipv4.conf.all.send_redirects |
1 | ICMP 리디렉트 전송. GRE 라우터에서는 0 권장 |
net.ipv4.ip_no_pmtu_disc |
0 | 전역 PMTUD 비활성화 (비권장 — 터널별 설정 사용) |
# GRE 라우터 기본 sysctl 설정
sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv4.conf.gre1.rp_filter=0
sysctl -w net.ipv4.conf.gre1.forwarding=1
sysctl -w net.ipv4.conf.all.send_redirects=0
# 영구 적용 (/etc/sysctl.d/99-gre.conf)
net.ipv4.ip_forward = 1
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.all.send_redirects = 0
커널 소스 맵
| 파일 | 역할 |
|---|---|
include/net/gre.h | GRE 헤더 구조체, 플래그 매크로, gre_protocol 등록 API |
include/net/ip_tunnels.h | struct ip_tunnel, ip_tunnel_parm, 터널 API 선언 |
include/net/erspan.h | ERSPAN 헤더 구조체 (Type II/III) |
include/uapi/linux/if_tunnel.h | UAPI: 터널 ioctl/netlink 상수, ip_tunnel_parm |
net/ipv4/gre_demux.c | GRE 프로토콜 47 디먹싱, 버전별 핸들러 디스패치 |
net/ipv4/gre_offload.c | GRE GSO/GRO 오프로드 콜백 |
net/ipv4/ip_gre.c | IPv4 GRE/GRETAP/ERSPAN 터널 디바이스 드라이버 |
net/ipv4/ip_tunnel.c | IPv4 터널 공통 로직 (lookup, xmit, rcv, change, delete) |
net/ipv4/ip_tunnel_core.c | iptunnel_xmit/rcv, tunnel metadata, FOU 캡슐화 |
net/ipv6/ip6_gre.c | IPv6 GRE/GRETAP/ERSPAN 터널 디바이스 드라이버 |
drivers/net/ppp/pptp.c | PPTP (Enhanced GRE v1) 드라이버 |
net/netfilter/nf_conntrack_proto_gre.c | GRE conntrack 프로토콜 핸들러 |
net/ipv4/netfilter/nf_nat_pptp.c | PPTP NAT helper (GRE Call ID NAT) |