VXLAN/GENEVE 오버레이 네트워크

Linux 커널 VXLAN/GENEVE 오버레이 네트워크 심층 분석: VXLAN(RFC 7348) UDP 터널링, GENEVE(RFC 8926) 가변 TLV 캡슐화, VTEP 구성과 FDB 학습, 멀티캐스트/유니캐스트 BUM 복제, BGP EVPN 연동, 커널 내부 데이터 경로와 핵심 자료구조, NIC 오프로드 및 성능 튜닝까지 실무 관점으로 다룹니다.

전제 조건: 네트워크 스택, Linux Bridge 문서를 먼저 읽으세요. VXLAN은 L3 위에 L2 오버레이를 구성하는 터널링 기술이고, GENEVE는 VXLAN의 확장형 차세대 프로토콜입니다.
일상 비유: VXLAN은 서로 다른 건물(데이터센터) 사이를 터널로 연결해 같은 층처럼 보이게 만드는 것과 같습니다. GENEVE는 그 터널에 짐표(TLV 옵션)를 자유롭게 붙일 수 있는 확장형 터널입니다.

핵심 요약

  • VXLAN (24비트 VNI) — 최대 1,677만 개 논리 네트워크, UDP 4789 포트, L2 over L3 오버레이 네트워크의 기반입니다. RFC 7348로 표준화되어 있습니다.
  • GENEVE (RFC 8926) — VXLAN/NVGRE/STT의 장점을 통합하고 가변 길이 TLV 옵션으로 확장성을 극대화한 차세대 오버레이 프로토콜입니다. UDP 6081 포트를 사용합니다.
  • VTEP (Virtual Tunnel Endpoint) — 오버레이 터널의 양 끝점으로, 캡슐화/역캡슐화를 수행합니다. Linux에서는 vxlan/geneve 타입 netdev가 VTEP 역할을 합니다.
  • FDB 학습 — VXLAN/GENEVE에서 원격 MAC-VTEP 매핑을 학습하는 방식으로, 동적(data plane), 정적(수동), 컨트롤 플레인(BGP EVPN) 방식이 있습니다.
  • NIC 오프로드 — 최신 NIC(mlx5, ice 등)은 VXLAN/GENEVE 캡슐화/역캡슐화를 하드웨어에서 수행하여 CPU 부하를 크게 줄입니다.

단계별 이해

  1. VXLAN 오버레이 생성
    ip link add vxlan100 type vxlan id 100 dstport 4789 local 10.0.0.1 remote 10.0.0.2로 유니캐스트 VXLAN 터널을 생성합니다.
  2. 오버레이 브리지 구성
    VXLAN 디바이스를 브리지에 연결하고 bridge fdb append 00:00:00:00:00:00 dev vxlan100 dst <VTEP>로 BUM 트래픽 복제 대상을 등록합니다.
  3. GENEVE 터널 생성
    ip link add geneve100 type geneve id 100 remote 10.0.0.2 dstport 6081로 GENEVE 터널을 구성합니다.
  4. MTU 및 오프로드 확인
    물리 NIC MTU를 점보 프레임(9000)으로 설정하고, ethtool --show-tunnels eth0으로 터널 오프로드 상태를 확인합니다.
관련 표준: RFC 7348 (VXLAN), RFC 8926 (GENEVE), RFC 7432 (BGP EVPN), RFC 8365 (EVPN Overlay), RFC 9136 (VXLAN-GPE) — 이 문서에서 다루는 오버레이 네트워크 프로토콜의 핵심 규격입니다. 종합 목록은 참고자료 — 표준 & 규격 섹션을 참고하세요.

오버레이 네트워크 개요

오버레이 네트워크(Overlay Network)는 기존 물리(언더레이) 네트워크 위에 논리적인 가상 네트워크를 구성하는 기술입니다. 원본 이더넷 프레임을 UDP 등으로 캡슐화하여 L3 네트워크를 통해 전달하므로, 물리적 위치와 무관하게 동일한 L2 도메인을 구성할 수 있습니다.

오버레이 네트워크가 필요한 이유

전통적인 VLAN(802.1Q)은 12비트 VID로 최대 4,094개의 논리 네트워크만 지원합니다. 대규모 데이터센터와 클라우드 환경에서는 수만~수백만 테넌트를 격리해야 하므로 VLAN만으로는 한계가 있습니다. 또한 VLAN은 L2 도메인 내에서만 동작하기 때문에 L3 경계를 넘어서는 네트워크 확장이 불가능합니다.

한계VLAN (802.1Q)VXLAN/GENEVE 오버레이
네트워크 ID 공간4,094개 (12비트)16,777,216개 (24비트 VNI)
L3 경계 횡단불가 (L2 브로드캐스트 도메인 한정)가능 (UDP 캡슐화로 IP 라우팅 통과)
멀티테넌트 격리수천 규모 한계수백만 규모 지원
데이터센터 간 연결DCI 전용 장비 필요IP 연결만 있으면 가능
확장성STP 도메인 크기 제약IP ECMP로 수평 확장
주요 사용처: VXLAN/GENEVE 오버레이는 Kubernetes/Docker 컨테이너 네트워크(Flannel, Calico, Cilium), OpenStack Neutron, VMware NSX, AWS VPC, OVN/OVS 기반 SDN에서 핵심 데이터플레인으로 사용됩니다.

Linux 커널은 drivers/net/vxlan/drivers/net/geneve.c에서 각각 VXLAN과 GENEVE를 구현합니다. 두 프로토콜 모두 struct net_device 기반의 가상 네트워크 디바이스로 동작하며, ip link add 명령으로 생성합니다. 물리 NIC의 터널 오프로드를 활용하면 CPU 부담 없이 와이어레이트에 가까운 성능을 달성할 수 있습니다.

오버레이 네트워크 캡슐화 개념 VTEP A (10.0.0.1) VM/컨테이너 오버레이 IP: 10.200.0.1 캡슐화 언더레이 네트워크 (L3) Outer IP + UDP(4789/6081) + VXLAN/GENEVE Header + Inner Ethernet Frame 역캡슐화 VTEP B (10.0.0.2) VM/컨테이너 오버레이 IP: 10.200.0.2 VXLAN (RFC 7348) 고정 8B 헤더, UDP 4789 24비트 VNI, 광범위한 HW 지원 Flannel, EVPN, 대부분의 SDN GENEVE (RFC 8926) 가변 헤더(TLV), UDP 6081 24비트 VNI + 확장 옵션 OVS, Cilium, AWS VPC, NSX
오버레이 네트워크: VTEP 간 캡슐화/역캡슐화로 L3 위에 L2 네트워크 구성

VLAN 기초 — 오버레이 이해를 위한 배경

VLAN(Virtual LAN, IEEE 802.1Q)은 이더넷 프레임에 4바이트 태그를 삽입하여 하나의 물리적 네트워크를 여러 논리적 브로드캐스트 도메인으로 분리하는 기술입니다. 12비트 VLAN ID(VID)로 최대 4,094개의 세그먼트를 지원합니다. VXLAN/GENEVE 오버레이를 이해하려면 VLAN의 기본 개념 — 태깅, 트렁킹, 브로드캐스트 도메인 분리 — 을 먼저 파악하는 것이 중요합니다.

오버레이 네트워크에서 VLAN은 여전히 중요한 역할을 합니다. 언더레이 네트워크의 트래픽 분리, VLAN-aware 브리지를 통한 VID-VNI 매핑(bridge vlan tunnel), 그리고 VTEP이 연결된 물리 네트워크의 트렁크 구성 등에서 VLAN 지식이 필수적입니다. 다만 대규모 멀티테넌트 환경에서는 VLAN의 4,094개 제한이 병목이 되므로, 24비트 VNI를 제공하는 VXLAN/GENEVE로 확장합니다.

상세 문서: VLAN(802.1Q) 프레임 구조, 태깅 처리, QoS, Q-in-Q 등의 상세 내용은 802.1Q VLAN 심화 페이지를 참조하세요.

Bridge VLAN Filtering — 오버레이 연동 기초

VLAN-aware 브리지는 포트별로 허용 VLAN을 필터링하며, 각 포트에 PVID(Port VLAN ID)와 tagged/untagged 설정을 적용합니다. 오버레이 네트워크에서 Bridge VLAN Filtering은 특히 중요한데, VXLAN external 모드에서 VLAN-Tunnel 매핑(bridge vlan tunnel add)을 통해 VID와 VNI를 1:1로 자동 변환할 수 있기 때문입니다. 하나의 VXLAN 디바이스로 여러 VNI를 처리하는 멀티테넌트 구성의 핵심입니다.

Bridge VLAN Filtering의 기본 동작은 물리 스위치의 access/trunk 포트 개념과 동일합니다. Ingress 경로에서 untagged 프레임에 PVID를 할당하고, VLAN 필터(br_allowed_ingress)를 통과한 프레임만 FDB 학습과 포워딩을 진행합니다. Egress 경로에서는 출력 포트의 VLAN 설정에 따라 태그를 유지하거나 제거합니다.

상세 문서: Bridge VLAN Filtering, PVID 설정, STP, IGMP Snooping 등의 상세 내용은 Linux Bridge 심화 페이지를 참조하세요.

VXLAN (Virtual Extensible LAN)

VXLAN(RFC 7348)은 L2 이더넷 프레임을 UDP로 캡슐화하여 L3 네트워크 위에 가상 L2 오버레이를 구성하는 네트워크 가상화 기술입니다. 기존 VLAN이 12비트 VID로 4,094개의 세그먼트만 지원하는 한계를 극복하여, 24비트 VNI로 최대 16,777,216 (224)개의 논리 네트워크를 지원합니다. 데이터센터의 멀티테넌트 환경, 컨테이너 오버레이 네트워크(Flannel, Calico VXLAN 모드), SDN 솔루션의 핵심 기반 기술입니다.

관련 RFC: RFC 7348 (VXLAN), RFC 7432 (BGP EVPN), RFC 8365 (EVPN Overlay), RFC 9136 (VXLAN-GPE). Linux 커널의 VXLAN 구현은 drivers/net/vxlan/ 디렉토리에 위치하며, vxlan_core.c가 핵심 로직을 담당합니다.

VXLAN 아키텍처와 용어

VXLAN 오버레이/언더레이 아키텍처 Overlay Network (VNI 100: 10.200.0.0/24) VM-A / Container 10.200.0.1 MAC: aa:bb:cc:11:22:33 VM-B / Container 10.200.0.2 MAC: dd:ee:ff:44:55:66 L2 연결 (동일 브로드캐스트 도메인) VTEP-A local: 192.168.1.10 vxlan100 + br-vxlan VTEP-B local: 192.168.1.20 vxlan100 + br-vxlan Underlay Network (L3 IP: 192.168.1.0/24) 물리 스위치 / 라우터 — IP 라우팅으로 VTEP 간 연결 UDP:4789 VXLAN Tunnel Outer IP + UDP + VXLAN Header + Inner Frame
용어설명
VNI (VXLAN Network Identifier)24비트 논리 네트워크 식별자 (0~16,777,215). VLAN ID에 해당하며, 동일 VNI = 동일 L2 도메인
VTEP (VXLAN Tunnel Endpoint)VXLAN 캡슐화/역캡슐화를 수행하는 엔드포인트. Linux에서는 vxlan 타입 net_device
Overlay NetworkVXLAN으로 구성된 가상 L2 네트워크. 테넌트/애플리케이션별 격리
Underlay NetworkVTEP 간 IP 연결을 제공하는 물리적 L3 네트워크
BUM 트래픽Broadcast, Unknown unicast, Multicast — 목적지를 모르는 트래픽. 멀티캐스트 그룹 또는 헤드엔드 복제로 처리
FDB (Forwarding Database)내부 MAC 주소 → 원격 VTEP IP 매핑 테이블. bridge fdb로 관리
Headend Replication멀티캐스트 없이 BUM 트래픽을 알려진 모든 VTEP에 유니캐스트로 복제 전송
오버레이 vs 언더레이: VXLAN의 핵심은 분리(separation)입니다. 오버레이 네트워크의 VM/컨테이너는 물리적 토폴로지를 인식하지 않으며, 동일 VNI 내에서 마치 같은 L2 스위치에 연결된 것처럼 통신합니다. 언더레이 네트워크는 순수 IP 라우팅만 처리하면 되므로, 물리 네트워크 설계가 크게 단순화됩니다.

VXLAN 패킷 포맷

구간크기핵심 필드설명
Outer Ethernet14 bytesdst/src MAC, EtherType언더레이 다음 홉으로 전달되는 L2 헤더
Outer IP20 bytes (IPv4) / 40 bytes (IPv6)src/dst IP, Protocol=17VTEP 간 L3 경로 식별
UDP8 bytessrc port(해시), dst port=4789ECMP 분산을 위한 엔트로피 + VXLAN 식별
VXLAN Header8 bytesFlags, VNI(24)오버레이 네트워크 식별자 전달
Inner Ethernet14 bytes + payload원본 dst/src MAC, EtherType테넌트 L2 프레임 원형 보존 (FCS 제외)
Outer Ethernet 14 bytes Outer IP 20/40 bytes UDP 8 bytes VXLAN Header Flags + VNI(24) Inner Ethernet + Payload 원본 L2 프레임 Outer UDP dst port: 4789 (IANA 기본값), src port: hash 기반(ECMP 분산) VXLAN Header (8 bytes) Byte 0: R|R|R|R|I|R|R|R + Reserved(24) Byte 4~6: VNI (24 bits), Byte 7: Reserved (8 bits) I(bit 4)=1 이어야 VNI 유효. Reserved는 0으로 설정. 총 오버헤드: IPv4 50 bytes / IPv6 70 bytes
소스 포트 엔트로피: VXLAN 외부 UDP 소스 포트는 내부 프레임의 L2/L3/L4 헤더를 해시하여 결정합니다. 이는 언더레이 네트워크의 ECMP(Equal-Cost Multi-Path) 라우팅에서 여러 경로로 트래픽을 분산시키는 데 필수적입니다. Linux에서는 skb_get_hash()를 사용하며, 포트 범위는 커널의 net.ipv4.ip_local_port_range 설정을 따릅니다.

커널 내부 자료구조

/* include/net/vxlan.h — VXLAN 핵심 자료구조 */

/* VXLAN 헤더 (on-wire 형식) */
struct vxlanhdr {
    __be32 vx_flags;   /* VXLAN_HF_VNI (bit 27, 0x08000000) 설정 시 VNI 유효 */
    __be32 vx_vni;     /* 상위 24비트: VNI, 하위 8비트: reserved */
};

/* VXLAN 디바이스 구성 파라미터 */
struct vxlan_config {
    union vxlan_addr  remote_ip;     /* 원격 VTEP IP (유니캐스트 시) */
    union vxlan_addr  saddr;         /* 로컬 VTEP IP */
    __be32            vni;           /* VXLAN Network Identifier */
    int               remote_ifindex;/* 송신 디바이스 ifindex */
    __be16            dst_port;      /* UDP 목적지 포트 (기본 4789) */
    __u16             port_min;      /* 소스 포트 범위 하한 */
    __u16             port_max;      /* 소스 포트 범위 상한 */
    __u8              tos;           /* 외부 IP TOS (1=inherit) */
    __u8              ttl;           /* 외부 IP TTL (0=inherit) */
    __u32             flags;         /* VXLAN_F_* 플래그 */
    __u32             label;         /* IPv6 flow label */
    unsigned short    age_interval;  /* FDB 엔트리 만료 시간 (초) */
    unsigned int      addrmax;       /* FDB 최대 엔트리 수 */
    __u8              df;            /* DF 비트 제어 */
};

/* VXLAN 디바이스 — net_device의 private 데이터 */
struct vxlan_dev {
    struct hlist_node  hlist4;      /* vxlan_net의 해시 테이블 (IPv4) */
    struct hlist_node  hlist6;      /* vxlan_net의 해시 테이블 (IPv6) */
    struct list_head   next;        /* 전역 VXLAN 디바이스 리스트 */
    struct vxlan_sock  __rcu *vn4_sock; /* IPv4 UDP 소켓 */
    struct vxlan_sock  __rcu *vn6_sock; /* IPv6 UDP 소켓 */
    struct net_device  *dev;        /* 연관된 net_device */
    struct vxlan_rdst  default_dst; /* 기본 원격 목적지 */
    struct timer_list  age_timer;   /* FDB 에이징 타이머 */
    struct hlist_head  fdb_head[FDB_HASH_SIZE]; /* FDB 해시 테이블 */
    unsigned int       addrcnt;     /* 현재 FDB 엔트리 수 */
    struct vxlan_config cfg;        /* 디바이스 구성 */
};

/* VXLAN FDB 엔트리 — 내부 MAC → 원격 VTEP 매핑 */
struct vxlan_fdb {
    struct hlist_node hlist;        /* vxlan_dev->fdb_head 해시 체인 */
    struct rcu_head   rcu;          /* RCU 해제 */
    unsigned long     updated;      /* 마지막 갱신 jiffies (에이징 기준) */
    unsigned long     used;         /* 마지막 참조 jiffies */
    struct list_head  remotes;      /* vxlan_rdst 리스트 (다중 VTEP 가능) */
    u8                eth_addr[ETH_ALEN]; /* 내부 MAC 주소 */
    u16               state;        /* NUD_REACHABLE, NUD_STALE 등 */
    __be32            vni;          /* collect_metadata 모드 시 VNI */
    u16               flags;        /* NTF_SELF, NTF_VXLAN_ADDED 등 */
};

/* VXLAN 원격 목적지 (하나의 FDB 엔트리에 여러 VTEP 가능) */
struct vxlan_rdst {
    union vxlan_addr  remote_ip;    /* 원격 VTEP IP */
    __be16            remote_port;  /* 원격 UDP 포트 */
    __be32            remote_vni;   /* 원격 VNI (보통 동일) */
    u32               remote_ifindex; /* 송신 인터페이스 */
    struct list_head  list;         /* vxlan_fdb->remotes 리스트 */
    struct rcu_head   rcu;
};

/* VXLAN UDP 소켓 — 여러 VXLAN 디바이스가 공유 가능 */
struct vxlan_sock {
    struct hlist_node  hlist;      /* 전역 소켓 해시 */
    struct socket      *sock;      /* UDP 소켓 */
    struct hlist_head  vni_list[VNI_HASH_SIZE]; /* VNI별 디바이스 룩업 */
    refcount_t        refcnt;     /* 참조 카운트 */
    u32               flags;      /* VXLAN_F_* 플래그 */
};
소켓 공유: 동일 UDP 포트를 사용하는 여러 VXLAN 디바이스는 하나의 vxlan_sock을 공유합니다. 수신 시 vxlan_sock->vni_list를 통해 VNI별로 올바른 vxlan_dev를 찾아 역캡슐화합니다. 이 설계 덕분에 수천 개의 VNI를 하나의 UDP 소켓으로 효율적으로 처리할 수 있습니다.

VXLAN 디바이스 플래그 (VXLAN_F_*)

플래그ip link 옵션설명
VXLAN_F_LEARN(기본 on)수신 패킷의 inner src MAC → outer src IP를 FDB에 자동 학습
VXLAN_F_PROXYproxyARP/NDP proxy — FDB에 있는 MAC의 ARP 요청에 VTEP이 대리 응답
VXLAN_F_L2MISSl2missFDB miss 시 netlink 알림 발생 (외부 컨트롤러 연동)
VXLAN_F_L3MISSl3missARP 테이블 miss 시 netlink 알림 발생
VXLAN_F_RSCrscRoute Short Circuit — ARP 응답의 MAC을 FDB에 학습
VXLAN_F_COLLECT_METADATAexternal메타데이터 모드 — tc/BPF에서 VNI/목적지를 동적 결정
VXLAN_F_UDP_ZERO_CSUM6_TXudp6zerocsumtxIPv6 송신 시 UDP checksum을 0으로 설정
VXLAN_F_UDP_ZERO_CSUM6_RXudp6zerocsumrxIPv6 수신 시 UDP checksum 0을 허용
VXLAN_F_GBPgbpGroup Based Policy — VXLAN 헤더에 정책 태그 삽입
VXLAN_F_GPEgpeGeneric Protocol Extension — 내부 프로토콜 지정 가능

VXLAN 송신 경로 (Tx Path)

VXLAN 패킷 송신 흐름 (vxlan_xmit) 애플리케이션 / socket TCP/IP 스택 → 내부 이더넷 프레임 생성 vxlan_xmit() ndo_start_xmit 콜백 — dst MAC으로 FDB 룩업 FDB 룩업 dst MAC HIT vxlan_rdst 원격 VTEP IP 획득 MISS BUM 처리 default_dst flood vxlan_xmit_one() 목적지 VTEP별 캡슐화 수행 캡슐화 단계 소스 포트 해시 계산 VXLAN 헤더 push (flags I=1 + VNI) UDP 헤더 push (dst_port 4789) 외부 IP 경로 ip_route_output udp_tunnel_xmit_skb() → ip_local_out() → NF_INET_LOCAL_OUT → 언더레이 라우팅 ip6 경로: udp_tunnel6_xmit_skb() / ip6_route_output() 물리 NIC → 와이어 언더레이 네트워크를 통해 원격 VTEP 전송 최종 캡슐화 구조: [ 외부 Ethernet | 외부 IP | UDP (4789) | VXLAN 헤더 (8B, VNI) | 내부 Ethernet | 내부 IP | Payload ]
/* drivers/net/vxlan/vxlan_core.c — VXLAN 송신 메인 */
static netdev_tx_t vxlan_xmit(struct sk_buff *skb,
                               struct net_device *dev)
{
    struct vxlan_dev *vxlan = netdev_priv(dev);
    struct ethhdr *eth;
    struct vxlan_fdb *f;
    struct vxlan_rdst *rdst, *fdst;

    eth = eth_hdr(skb);

    /* 1. 내부 프레임의 dst MAC으로 FDB 룩업 */
    f = vxlan_find_mac(vxlan, eth->h_dest, vni);

    if (f) {
        /* FDB hit — 알려진 유니캐스트 목적지 */
        fdst = vxlan_fdb_find_rdst(f, &remote_ip, port, vni, ifindex);
        vxlan_xmit_one(skb, dev, vni, fdst, did_rsc);
    } else if (is_multicast_ether_addr(eth->h_dest)) {
        /* 멀티캐스트/브로드캐스트 — 모든 원격 VTEP에 복제 전송 */
        vxlan_xmit_one(skb, dev, vni, &vxlan->default_dst, 0);
    } else {
        /* Unknown unicast (FDB miss) */
        if (vxlan->cfg.flags & VXLAN_F_L2MISS)
            vxlan_fdb_miss(vxlan, eth->h_dest); /* netlink 알림 */
        /* default_dst의 remote 리스트로 flood */
        vxlan_xmit_one(skb, dev, vni, &vxlan->default_dst, 0);
    }
    return NETDEV_TX_OK;
}

/* 단일 VTEP으로의 캡슐화 및 송신 */
static void vxlan_xmit_one(
    struct sk_buff *skb,
    struct net_device *dev,
    __be32 default_vni,
    struct vxlan_rdst *rdst,
    bool did_rsc)
{
    struct vxlan_dev *vxlan = netdev_priv(dev);
    struct vxlanhdr *vxh;
    struct rtable *rt;
    __be16 src_port, dst_port;
    __be32 vni;

    /* 소스 포트: 내부 프레임 해시 기반 (ECMP 분산) */
    src_port = udp_flow_src_port(dev_net(dev), skb,
                                  vxlan->cfg.port_min,
                                  vxlan->cfg.port_max, true);
    dst_port = rdst->remote_port ? : vxlan->cfg.dst_port;
    vni = rdst->remote_vni ? : default_vni;

    /* IP 라우팅 조회 */
    rt = vxlan_get_route(vxlan, dev, sock4, skb, ...);

    /* VXLAN 헤더 추가 */
    vxh = (struct vxlanhdr *)__skb_push(skb, sizeof(*vxh));
    vxh->vx_flags = htonl(VXLAN_HF_VNI);
    vxh->vx_vni = vxlan_vni_field(vni);

    /* UDP 터널 캡슐화 + IP 송신 */
    udp_tunnel_xmit_skb(rt, sock4->sk, skb,
                        saddr, rdst->remote_ip.sin.sin_addr.s_addr,
                        tos, ttl, df, src_port, dst_port,
                        xnet, !net_eq(vxlan->net, dev_net(dev)));
}

VXLAN 수신 경로 (Rx Path)

물리 NIC → NAPI → netif_receive_skb()
    ↓
IP 프로토콜 처리 → UDP 디멀티플렉싱
    ↓
udp_rcv() → udp_queue_rcv_skb()
    ↓
vxlan_rcv() ← vxlan_sock의 UDP 소켓 콜백 (encap_rcv)
    ├─ 1. VXLAN 헤더 유효성 검사 (I 플래그, 최소 길이)
    ├─ 2. VNI 추출 → vxlan_vs_find_vni()로 vxlan_dev 룩업
    ├─ 3. VXLAN 헤더 pull (skb->data를 inner frame으로 이동)
    ├─ 4. inner src MAC 학습 (VXLAN_F_LEARN 설정 시)
    │      vxlan_snoop() → FDB에 src MAC → outer src IP 매핑 추가/갱신
    ├─ 5. skb 메타데이터 설정
    │      skb->dev = vxlan_dev->dev
    │      skb->protocol = eth_type_trans()
    └─ 6. netif_rx() → 내부 프레임을 네트워크 스택에 재주입
              ↓
         브리지 처리 (vxlan이 bridge port인 경우)
              ↓
         로컬 VM/컨테이너에 전달
/* drivers/net/vxlan/vxlan_core.c — VXLAN 수신 */
static int vxlan_rcv(struct sock *sk,
                      struct sk_buff *skb)
{
    struct vxlan_dev *vxlan;
    struct vxlan_sock *vs;
    struct vxlanhdr *vxh;
    __be32 vni;

    vs = rcu_dereference_sk_user_data(sk);

    /* VXLAN 헤더 파싱 */
    vxh = (struct vxlanhdr *)(udp_hdr(skb) + 1);

    /* I 플래그 검증 */
    if (!(ntohl(vxh->vx_flags) & VXLAN_HF_VNI)) {
        pr_warn_ratelimited("invalid vxlan flags %#x\\n",
                            ntohl(vxh->vx_flags));
        goto drop;
    }

    /* VNI 추출 및 VXLAN 디바이스 룩업 */
    vni = vxlan_vni(vxh->vx_vni);
    vxlan = vxlan_vs_find_vni(vs, skb->dev->ifindex, vni);
    if (!vxlan)
        goto drop;

    /* VXLAN 헤더 제거, inner frame 노출 */
    skb_pull(skb, VXLAN_HLEN);  /* 8 bytes */

    /* 소스 MAC 학습 (dynamic FDB entry) */
    if (vxlan->cfg.flags & VXLAN_F_LEARN)
        vxlan_snoop(skb->dev, &saddr, eth_hdr(skb)->h_source,
                    skb->ifindex, vni);

    /* inner frame을 네트워크 스택에 재주입 */
    skb->protocol = eth_type_trans(skb, vxlan->dev);
    netif_rx(skb);

    return 0;
drop:
    kfree_skb(skb);
    return 0;
}

FDB (Forwarding Database) 학습과 관리

VXLAN FDB는 내부 MAC 주소를 원격 VTEP IP로 매핑하는 핵심 테이블입니다. 브리지의 FDB와 개념은 같지만, 목적지가 포트 번호가 아닌 원격 VTEP의 IP 주소라는 점이 다릅니다.

방식동작
동적 학습VXLAN_F_LEARN 설정 시, 수신 패킷의 inner src MAC
(Data Plane)→ outer src IP를 자동 학습. 에이징 타이머 적용.
정적 설정bridge fdb add로 수동 등록.
(Static)에이징 없음, 재부팅 시 재설정 필요.
nolearning +동적 학습 비활성화, 모든 매핑을 수동 관리.
정적 FDB대규모 환경에서 FDB 폭증 방지, 보안 향상.
L2MISS/L3MISSFDB miss 시 netlink 알림 → 외부 컨트롤러가
+ 컨트롤러FDB 엔트리를 동적으로 주입 (SDN 패턴).
BGP EVPNBGP Type-2 Route로 MAC/IP 바인딩을 분산 학습.
(Control Plane)FRR/BIRD 등이 커널 FDB를 자동 관리.
# --- FDB 관리 명령 ---

# 전체 FDB 조회
bridge fdb show dev vxlan100

# 00:00:00:00:00:00 = BUM 트래픽 대상 (헤드엔드 복제 목적지)
bridge fdb append 00:00:00:00:00:00 dev vxlan100 dst 10.0.0.2
bridge fdb append 00:00:00:00:00:00 dev vxlan100 dst 10.0.0.3
bridge fdb append 00:00:00:00:00:00 dev vxlan100 dst 10.0.0.4

# 특정 MAC → VTEP 정적 매핑
bridge fdb add aa:bb:cc:dd:ee:ff dev vxlan100 dst 10.0.0.2 self permanent
bridge fdb del aa:bb:cc:dd:ee:ff dev vxlan100 dst 10.0.0.2

# 동적 학습된 엔트리 확인 (상태: offload/self/permanent)
bridge fdb show dev vxlan100 | column -t

# FDB 에이징 시간 설정 (기본 300초)
ip link set vxlan100 type vxlan ageing 600

# FDB 최대 엔트리 수 제한
ip link set vxlan100 type vxlan maxaddress 1024

# 동적 FDB 플러시 (정적 엔트리는 유지)
bridge fdb flush dev vxlan100 dynamic
/* drivers/net/vxlan/vxlan_core.c — FDB 동적 학습 (수신 시) */
static bool vxlan_snoop(struct net_device *dev,
                        union vxlan_addr *src_ip,
                        const u8 *src_mac,
                        u32 src_ifindex, __be32 vni)
{
    struct vxlan_dev *vxlan = netdev_priv(dev);
    struct vxlan_fdb *f;

    f = __vxlan_find_mac(vxlan, src_mac, vni);
    if (likely(f)) {
        struct vxlan_rdst *rdst = first_remote_rcu(f);

        /* 이미 알려진 MAC — VTEP IP가 변경되었으면 갱신 */
        if (vxlan_addr_equal(&rdst->remote_ip, src_ip))
            return false;  /* 변경 없음 */

        /* MAC 이동 감지 — VTEP 변경 */
        rdst->remote_ip = *src_ip;
        f->updated = jiffies;
    } else {
        /* 신규 MAC 학습 */
        vxlan_fdb_create(vxlan, src_mac, src_ip, NUD_REACHABLE,
                        NTF_SELF, vxlan->cfg.dst_port,
                        vni, vni, src_ifindex,
                        NTF_VXLAN_ADDED, &f);
    }
    return true;
}

BUM 트래픽 처리

BUM(Broadcast, Unknown unicast, Multicast) 트래픽은 VXLAN 환경에서 가장 까다로운 문제입니다. 물리 네트워크에서는 스위치가 BUM 프레임을 모든 포트로 flood하지만, VXLAN 오버레이에서는 VTEP이 어떤 원격 VTEP에 전송해야 하는지 결정해야 합니다.

방식설정장점단점
멀티캐스트 그룹 group 239.1.1.1 자동 VTEP 디스커버리, 설정 간단 언더레이에 멀티캐스트 지원 필요, WAN 환경 제약
헤드엔드 복제
(Ingress Replication)
nolearning +
FDB 00:00:00:00:00:00 엔트리
멀티캐스트 불필요, L3 라우팅만으로 충분 VTEP 수에 비례하는 복제 오버헤드, 수동 관리 필요
BGP EVPN FRR/BIRD + EVPN 설정 자동 VTEP 디스커버리 + MAC 학습, ARP suppression BGP 인프라 필요, 설정 복잡도 높음
SDN 컨트롤러 l2miss + netlink 연동 중앙 집중 제어, 정교한 정책 적용 가능 컨트롤러 가용성 의존, 구현 복잡
# === 방법 1: 멀티캐스트 기반 VXLAN ===
# 동일 멀티캐스트 그룹의 모든 VTEP이 BUM 트래픽을 수신
ip link add vxlan100 type vxlan \
    id 100 \
    group 239.1.1.1 \
    dstport 4789 \
    dev eth0 \
    ttl 10

# 멀티캐스트 그룹 참여 확인
ip maddr show dev eth0

# === 방법 2: 헤드엔드 복제 (유니캐스트 flood) ===
# 멀티캐스트 없이, 알려진 모든 VTEP에 유니캐스트로 복제
ip link add vxlan100 type vxlan \
    id 100 \
    local 10.0.0.1 \
    dstport 4789 \
    nolearning \
    proxy

# BUM 대상 VTEP 등록 (00:00:00:00:00:00 = flood 대상)
bridge fdb append 00:00:00:00:00:00 dev vxlan100 dst 10.0.0.2
bridge fdb append 00:00:00:00:00:00 dev vxlan100 dst 10.0.0.3
bridge fdb append 00:00:00:00:00:00 dev vxlan100 dst 10.0.0.4

# VTEP 제거 (노드 해제 시)
bridge fdb del 00:00:00:00:00:00 dev vxlan100 dst 10.0.0.4

# === 방법 3: L2MISS 알림 기반 (SDN 연동) ===
ip link add vxlan100 type vxlan \
    id 100 \
    local 10.0.0.1 \
    dstport 4789 \
    nolearning \
    l2miss \
    l3miss

# netlink 이벤트 모니터링 (컨트롤러가 수신)
ip monitor neigh dev vxlan100
# 출력 예: miss aa:bb:cc:dd:ee:ff STALE
# → 컨트롤러가 bridge fdb add로 매핑 주입

VXLAN 기본 구성

# --- 유니캐스트 VXLAN (point-to-point) ---
ip link add vxlan100 type vxlan \
    id 100 \
    local 10.0.0.1 \
    remote 10.0.0.2 \
    dstport 4789 \
    dev eth0

ip addr add 192.168.100.1/24 dev vxlan100
ip link set vxlan100 up

# --- 멀티캐스트 VXLAN (BUM 트래픽 자동 학습) ---
ip link add vxlan100 type vxlan \
    id 100 \
    group 239.1.1.1 \
    dstport 4789 \
    dev eth0 \
    ttl 10

# --- 브리지 + VXLAN (L2 확장, 가장 일반적) ---
ip link add br-vxlan type bridge
ip link add vxlan100 type vxlan id 100 local 10.0.0.1 dstport 4789 nolearning
ip link set vxlan100 master br-vxlan
ip link set vxlan100 up
ip link set br-vxlan up

# FDB 엔트리 수동 설정 (헤드엔드 복제)
bridge fdb append 00:00:00:00:00:00 dev vxlan100 dst 10.0.0.2
bridge fdb append 00:00:00:00:00:00 dev vxlan100 dst 10.0.0.3

# 특정 MAC → VTEP 매핑
bridge fdb add aa:bb:cc:dd:ee:ff dev vxlan100 dst 10.0.0.2

# VXLAN 상태 확인
ip -d link show vxlan100
bridge fdb show dev vxlan100

IPv6 언더레이 VXLAN

VXLAN은 IPv6 언더레이를 완전히 지원합니다. IPv6 언더레이를 사용하면 글로벌 주소 공간을 활용한 대규모 오버레이 네트워크 구성이 가능합니다. 단, IPv6 헤더 크기(40바이트)로 인해 오버헤드가 70바이트로 증가합니다.

# IPv6 언더레이 VXLAN 구성
ip link add vxlan100 type vxlan \
    id 100 \
    local fd00::1 \
    remote fd00::2 \
    dstport 4789 \
    dev eth0 \
    udp6zerocsumtx \
    udp6zerocsumrx

ip addr add 10.200.0.1/24 dev vxlan100
ip link set vxlan100 up

# IPv6 멀티캐스트 VXLAN
ip link add vxlan200 type vxlan \
    id 200 \
    group ff05::100 \
    dstport 4789 \
    dev eth0 \
    ttl 10 \
    udp6zerocsumtx \
    udp6zerocsumrx

# IPv6 + 브리지 조합
ip link add br-v6 type bridge
ip link add vxlan300 type vxlan \
    id 300 \
    local fd00::1 \
    dstport 4789 \
    nolearning \
    udp6zerocsumtx \
    udp6zerocsumrx
ip link set vxlan300 master br-v6
ip link set vxlan300 up
ip link set br-v6 up

bridge fdb append 00:00:00:00:00:00 dev vxlan300 dst fd00::2
bridge fdb append 00:00:00:00:00:00 dev vxlan300 dst fd00::3
UDP checksum과 IPv6: IPv4에서 UDP checksum은 선택사항이지만, IPv6에서는 기본적으로 사용이 요구됩니다. udp6zerocsumtx/udp6zerocsumrx 옵션은 RFC 6935/6936에서 정의한 예외 시나리오에 따라 VXLAN 트래픽의 UDP checksum을 생략하여 성능을 향상시킵니다. NIC의 하드웨어 checksum offload가 지원되면 이 옵션 없이도 성능 저하가 미미합니다.

VXLAN-GPE (Generic Protocol Extension)

VXLAN-GPE(RFC 9136)는 표준 VXLAN을 확장하여 내부 페이로드의 프로토콜을 명시적으로 지정할 수 있게 합니다. 표준 VXLAN은 항상 이더넷 프레임을 캡슐화하지만, VXLAN-GPE는 IPv4, IPv6, NSH(Network Service Header), MPLS 등을 직접 캡슐화할 수 있어 SFC(Service Function Chaining)와 같은 고급 네트워크 기능에 사용됩니다.

VXLAN-GPE Header (8 bytes, RFC 9136) Flags: R,R,Ver(2),I,P,B,O Reserved (24 bits) Next Protocol (8) VNI (24 bits) Reserved (8 bits) Ver: 버전(현재 0), I: VNI 유효, P: Next Protocol 유효, B: BUM 비트, O: OAM 비트 Next Protocol: 0x01 IPv4, 0x02 IPv6, 0x03 Ethernet, 0x04 NSH, 0x05 MPLS
# VXLAN-GPE 디바이스 생성
ip link add vxlan-gpe0 type vxlan \
    id 500 \
    local 10.0.0.1 \
    remote 10.0.0.2 \
    dstport 4790 \
    gpe

# GPE는 IANA 포트 4790 사용 (표준 VXLAN은 4789)
# collect_metadata(external) 모드와 결합하여 BPF에서 활용 가능
ip link add vxlan-gpe1 type vxlan \
    external \
    dstport 4790 \
    gpe
/* include/net/vxlan.h — GPE 관련 정의 */
struct vxlanhdr_gpe {
    __u8   vx_flags;       /* Ver=0, I, P, B, O 플래그 */
    __u8   reserved[2];
    __u8   np;             /* Next Protocol */
    __be32 vx_vni;         /* VNI << 8 */
};

#define VXLAN_GPE_NP_IPV4   0x01
#define VXLAN_GPE_NP_IPV6   0x02
#define VXLAN_GPE_NP_ETHERNET 0x03
#define VXLAN_GPE_NP_NSH    0x04
#define VXLAN_GPE_NP_MPLS   0x05

VXLAN GBP (Group Based Policy)

VXLAN GBP(draft-smith-vxlan-group-policy)는 VXLAN 헤더의 예약 필드를 활용하여 보안 그룹 태그를 전달합니다. 소스/목적지 그룹 ID를 기반으로 마이크로세그멘테이션 정책을 적용할 수 있으며, Cilium 등의 CNI에서 네트워크 정책 적용에 사용합니다.

VXLAN GBP Header (8 bytes) Flags: G,R,R,R,I,R,R,R,R,D,R,R,A,R,R,R Group Policy ID (16 bits) VNI (24 bits) Reserved (8 bits) G: GBP Extension 활성화, D: Don't Learn, A: Policy Applied Group Policy ID: 16비트 보안 그룹 식별자 (0~65535)
# GBP 활성화된 VXLAN 생성
ip link add vxlan-gbp type vxlan \
    id 100 \
    local 10.0.0.1 \
    dstport 4789 \
    gbp

# iptables/nftables에서 GBP 태그 기반 필터링
iptables -A FORWARD -m set --match-set allowed_groups src \
    -j ACCEPT
iptables -A FORWARD -j DROP

VXLAN + EVPN (BGP Control Plane)

EVPN(Ethernet VPN, RFC 7432)은 BGP를 Control Plane으로 사용하여 VXLAN의 MAC/IP 학습, VTEP 디스커버리, BUM 최적화를 자동화합니다. 데이터 플레인의 flood & learn 방식을 대체하여 확장성과 수렴 시간을 크게 개선합니다.

EVPN Route Types (VXLAN 관련):

Type-2 (MAC/IP Advertisement):
  - MAC 주소 + IP 주소 + VNI를 BGP로 광고
  - 수신 VTEP이 FDB에 자동 등록 (data plane 학습 불필요)
  - ARP suppression: VTEP이 알려진 IP의 ARP 요청에 대리 응답

Type-3 (Inclusive Multicast Ethernet Tag):
  - VTEP의 존재를 광고 (BUM 트래픽 대상 목록 자동 구축)
  - Ingress Replication 리스트를 자동 관리

Type-5 (IP Prefix Route):
  - L3 VXLAN (Symmetric IRB): VNI 간 라우팅을 위한 IP prefix 광고
  - 테넌트별 VRF + L3 VNI를 통한 인터-서브넷 라우팅

EVPN 동작 흐름:
  VM-A boots → VTEP-A가 MAC/IP 학습 → Type-2 BGP Update 전파
      → VTEP-B가 수신 → 커널 FDB에 자동 추가
      → VM-B → VM-A 통신 시 data plane flood 불필요
# === FRR (Free Range Routing)을 이용한 EVPN 설정 예시 ===

# 1. 커널: VXLAN + 브리지 구성 (nolearning 필수)
ip link add br100 type bridge
ip link add vxlan100 type vxlan \
    id 100 \
    local 10.0.0.1 \
    dstport 4789 \
    nolearning

ip link set vxlan100 master br100
ip link set vxlan100 up
ip link set br100 up

# L3 VNI (대칭 IRB 라우팅용)
ip link add br-l3vni type bridge
ip link add vxlan-l3 type vxlan \
    id 9999 \
    local 10.0.0.1 \
    dstport 4789 \
    nolearning

ip link set vxlan-l3 master br-l3vni
ip link set vxlan-l3 up
ip link set br-l3vni up

# VRF 생성
ip link add vrf-tenant1 type vrf table 100
ip link set vrf-tenant1 up
ip link set br100 master vrf-tenant1
ip link set br-l3vni master vrf-tenant1
# 2. FRR 설정 (vtysh / frr.conf)

router bgp 65001
  bgp router-id 10.0.0.1
  no bgp default ipv4-unicast
  neighbor SPINE peer-group
  neighbor SPINE remote-as 65100
  neighbor 10.0.0.254 peer-group SPINE
  !
  address-family l2vpn evpn
    neighbor SPINE activate
    advertise-all-vni
  exit-address-family
!
router bgp 65001 vrf tenant1
  !
  address-family ipv4 unicast
    redistribute connected
  exit-address-family
  !
  address-family l2vpn evpn
    advertise ipv4 unicast
  exit-address-family
!
vni 100
  rd 10.0.0.1:100
  route-target import 65001:100
  route-target export 65001:100
# 3. EVPN 상태 확인 (vtysh)
show bgp l2vpn evpn summary
show bgp l2vpn evpn route type macip
show bgp l2vpn evpn route type multicast
show bgp l2vpn evpn route type prefix
show evpn vni
show evpn mac vni 100
show evpn arp-cache vni 100

# 커널 FDB에 BGP가 주입한 엔트리 확인
bridge fdb show dev vxlan100 | grep offload
# 출력 예: aa:bb:cc:dd:ee:ff dev vxlan100 dst 10.0.0.2 self offload
ARP Suppression: EVPN Type-2 경로에 IP가 포함되면, VTEP은 알려진 MAC/IP에 대한 ARP 요청을 로컬에서 대리 응답합니다. 이로써 오버레이 네트워크의 ARP 브로드캐스트 트래픽이 크게 감소하며, 대규모 환경에서 성능이 향상됩니다. bridge link set dev vxlan100 neigh_suppress on으로 활성화합니다.

collect_metadata (external) 모드

collect_metadata(external) 모드는 단일 VXLAN 디바이스로 여러 VNI를 처리할 수 있게 합니다. VNI와 목적지 VTEP을 패킷별로 동적으로 결정하며, tc-flower, BPF, OVS(Open vSwitch) 등의 프로그래머블 데이터 플레인에서 사용됩니다.

# external 모드 VXLAN (VNI/목적지를 tc/BPF에서 결정)
ip link add vxlan-ext type vxlan \
    external \
    dstport 4789

ip link set vxlan-ext up

# tc-flower로 트래픽 제어 (VNI/목적지 동적 설정)
tc qdisc add dev vxlan-ext clsact
tc filter add dev vxlan-ext egress \
    flower dst_mac aa:bb:cc:dd:ee:ff \
    action tunnel_key set \
        id 100 \
        src_ip 10.0.0.1 \
        dst_ip 10.0.0.2 \
        dst_port 4789 \
    action mirred egress redirect dev vxlan-ext
/* BPF에서 VXLAN 메타데이터 설정 (tc BPF 프로그램) */
SEC("tc")
int vxlan_encap(struct __sk_buff *skb)
{
    struct bpf_tunnel_key key = {};

    key.tunnel_id = 100;          /* VNI */
    key.remote_ipv4 = 0x0A000002; /* 10.0.0.2 */
    key.tunnel_tos = 0;
    key.tunnel_ttl = 64;

    bpf_skb_set_tunnel_key(skb, &key, sizeof(key),
                           BPF_F_ZERO_CSUM_TX);
    return TC_ACT_OK;
}

/* 수신 측: 터널 메타데이터 읽기 */
SEC("tc")
int vxlan_decap(struct __sk_buff *skb)
{
    struct bpf_tunnel_key key = {};

    bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0);
    /* key.tunnel_id = VNI, key.remote_ipv4 = 소스 VTEP */

    /* VNI 기반 정책 적용 */
    if (key.tunnel_id == 100)
        return TC_ACT_OK;
    return TC_ACT_SHOT;
}

성능 최적화

MTU 설정

MTU 주의: VXLAN은 50바이트(IPv4) 또는 70바이트(IPv6)의 오버헤드를 추가합니다. 내부 MTU가 1500이면 물리 NIC의 MTU는 최소 1550(IPv4) 또는 1570(IPv6) 이상이어야 합니다. 점보 프레임을 강력히 권장합니다.
# 권장: 물리 NIC에 점보 프레임 설정
ip link set eth0 mtu 9000

# VXLAN 디바이스 MTU (자동 계산되지만 명시 설정 권장)
ip link set vxlan100 mtu 8950   # 9000 - 50 (VXLAN overhead)

# Path MTU Discovery 문제 시 DF 비트 제어
ip link add vxlan100 type vxlan id 100 ... df unset  # DF=0 (fragmentation 허용)
ip link add vxlan100 type vxlan id 100 ... df set     # DF=1 (PMTUD 활성화)
ip link add vxlan100 type vxlan id 100 ... df inherit # inner IP의 DF 상속

NIC 오프로드

# NIC의 VXLAN 오프로드 지원 확인
ethtool -k eth0 | grep -E "(tx-udp_tnl|rx-udp_tnl|vxlan)"

# 일반적인 오프로드 기능:
#   tx-udp_tnl-segmentation     : VXLAN TSO (내부 TCP 세그멘테이션)
#   tx-udp_tnl-csum-segmentation: TSO + 외부 UDP checksum
#   rx-udp-gro-forwarding       : UDP GRO (VXLAN 수신 병합)

# 오프로드 포트 등록 확인
ethtool --show-tunnels eth0
# 출력 예:
#   port 4789, VXLAN

# GRO 활성화 (수신 성능 향상)
ethtool -K eth0 rx-udp-gro-forwarding on

# VXLAN 통계 확인
ip -s link show dev vxlan100
# ethtool 카운터 (NIC별 상이)
ethtool -S eth0 | grep -i vxlan
/* drivers/net/vxlan/vxlan_core.c — NIC에 오프로드 포트 등록 */
static void vxlan_push_rx_ports(struct net_device *dev)
{
    struct vxlan_sock *vs;

    /* 물리 NIC에 VXLAN UDP 포트 알림 → NIC이 하드웨어 파싱 수행 */
    rcu_read_lock();
    hlist_for_each_entry_rcu(vs, &vn->sock_list[0], hlist)
        udp_tunnel_push_rx_port(dev, vs->sock,
                                UDP_TUNNEL_TYPE_VXLAN);
    rcu_read_unlock();
}

/* NIC 드라이버 예시: VXLAN 오프로드 포트 등록 콜백 */
static void nic_add_vxlan_port(struct net_device *dev,
                                struct udp_tunnel_info *ti)
{
    /* NIC ASIC에 VXLAN 포트 프로그래밍 */
    /* → 하드웨어가 외부 헤더를 파싱하여 inner payload를 직접 처리 */
    /* → RSS (내부 5-tuple 기반), checksum offload, TSO 가능 */
    hw_register_vxlan_port(adapter, ntohs(ti->port));
}

커널 튜닝 파라미터

# VXLAN 관련 sysctl 튜닝

# UDP 수신 버퍼 확대 (대량 VXLAN 트래픽)
sysctl -w net.core.rmem_max=26214400
sysctl -w net.core.rmem_default=26214400

# conntrack이 필요 없는 경우 VXLAN 인터페이스에서 비활성화
iptables -t raw -A PREROUTING -i vxlan+ -j NOTRACK
iptables -t raw -A OUTPUT -o vxlan+ -j NOTRACK

# VXLAN FDB 에이징 최적화
ip link set vxlan100 type vxlan ageing 300   # 기본값

# 네트워크 네임스페이스간 이동 허용
sysctl -w net.core.netns_local=0

VXLAN 트러블슈팅

# === 1단계: VXLAN 디바이스 상태 확인 ===
ip -d link show vxlan100
# 확인 항목: id(VNI), group/remote, local, dstport, learning, proxy

# === 2단계: FDB 테이블 검증 ===
bridge fdb show dev vxlan100
# 필수 확인: 00:00:00:00:00:00 엔트리 (BUM flood 대상)
# permanent = 정적, offload = EVPN/HW 주입

# === 3단계: 언더레이 연결성 확인 ===
# VTEP IP 간 ping (기본 연결 확인)
ping 10.0.0.2

# UDP 4789 도달 가능 여부
ncat -u 10.0.0.2 4789

# 방화벽 확인 (VXLAN UDP 포트)
iptables -L -n -v | grep 4789
nft list ruleset | grep 4789

# === 4단계: 패킷 캡처 ===
# 외부 캡슐화된 VXLAN 패킷 (언더레이)
tcpdump -i eth0 -nn "udp port 4789" -c 10

# 내부 프레임 (오버레이, VTEP에서 역캡슐화 후)
tcpdump -i vxlan100 -nn -c 10

# VXLAN 헤더까지 상세 출력
tcpdump -i eth0 -nn -e -v "udp port 4789"

# === 5단계: 통계 및 카운터 ===
ip -s link show dev vxlan100
# TX/RX packets, bytes, errors, dropped 확인

# VXLAN 전용 통계
nstat -a | grep -i Vxlan
# VxlanInPkts, VxlanOutPkts, VxlanInErrors 등

# ethtool 확장 통계 (NIC별)
ethtool -S eth0 | grep -i vxlan

# === 6단계: 일반적인 문제와 해결 ===

# 문제: ping은 되지만 TCP 연결 안됨 → MTU 문제
# 해결:
ip link set eth0 mtu 9000
ip link set vxlan100 mtu 8950
# 또는 inner의 MSS 조정:
iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
    -j TCPMSS --clamp-mss-to-pmtu

# 문제: 멀티캐스트 VXLAN에서 BUM 전달 안됨
# 확인: 언더레이 멀티캐스트 라우팅
ip mroute show
ip maddr show dev eth0
# 스위치의 IGMP snooping 설정 확인

# 문제: EVPN FDB 동기화 안됨
# 확인: BGP 세션 상태
vtysh -c "show bgp l2vpn evpn summary"
vtysh -c "show bgp l2vpn evpn route type macip"

# 문제: MAC flapping 감지
dmesg | grep -i "moved from"
# bridge: vxlan100: xx:xx:xx:xx:xx:xx moved from port X to port Y
tcpdump 팁: Wireshark에서 VXLAN 패킷을 분석할 때, udp.port == 4789 필터로 캡처한 후 Decode As → VXLAN을 선택하면 내부 이더넷 프레임까지 파싱됩니다. tshark에서는 tshark -d udp.port==4789,vxlan -r capture.pcap으로 디코딩할 수 있습니다.

GENEVE (Generic Network Virtualization Encapsulation)

GENEVE(RFC 8926)는 IETF NVO3 워킹그룹이 설계한 차세대 네트워크 가상화 캡슐화 프로토콜입니다. VXLAN, NVGRE, STT의 장점을 통합하고, 가변 길이 옵션(TLV)으로 확장성을 극대화한 것이 핵심 특징입니다. Open vSwitch(OVS)의 기본 터널 프로토콜이며, VMware NSX, AWS VPC, Cilium 등에서 채택하고 있습니다.

GENEVE vs VXLAN: GENEVE는 VXLAN의 상위 호환으로 설계되었습니다. VXLAN은 고정 8바이트 헤더이지만, GENEVE는 가변 길이 옵션(TLV)을 통해 보안 태그, QoS 정보, 디버깅 메타데이터 등을 유연하게 전달할 수 있습니다. 새로운 오버레이 네트워크 설계 시 GENEVE를 우선 고려하는 것이 권장됩니다.

GENEVE 패킷 포맷

GENEVE 헤더 포맷 (RFC 8926) Outer Ethernet 14B Outer IP 20/40B UDP 8B (6081) GENEVE Header 8B + Options Options (TLV) 0~252B Inner Frame 원본 L2 GENEVE 고정 헤더 (8 bytes) Ver (2b) 현재: 0 Opt Len (6b) ×4 bytes O|C|Rsvd (8b) OAM, Critical Protocol Type (16b) 0x6558=Ethernet VNI (24b) + Rsvd (8b) 네트워크 식별자 O=OAM 패킷, C=Critical 옵션 포함 (처리 불가 시 드롭 필수) Opt Len: 옵션 길이를 4바이트 단위로 표현 (최대 63 → 252바이트) GENEVE TLV 옵션 구조 (가변 길이) Option Class (16b) 벤더/표준 식별 Type (8b) 옵션 종류 R|R|R|Len (8b) ×4 bytes Option Data (0~124 bytes) 보안 태그, QoS 정보, 디버깅 메타데이터 등 Option Class 예: 0x0100 (Linux), 0x0101 (OVS), 0x0102 (VMware NSX) 여러 TLV를 연속으로 배치 가능 — VXLAN에 없는 핵심 확장성
GENEVE 헤더: 8바이트 고정 헤더 + 가변 길이 TLV 옵션
필드크기설명
Version2비트프로토콜 버전 (현재 0)
Opt Len6비트옵션 길이 (4바이트 단위, 0~63 → 0~252바이트)
O (OAM)1비트OAM 패킷 표시 (관리/진단용)
C (Critical)1비트Critical 옵션 포함 (미지원 시 반드시 드롭)
Protocol Type16비트내부 페이로드 타입 (0x6558=Ethernet, 0x0800=IPv4, 0x86DD=IPv6)
VNI24비트Virtual Network Identifier (VXLAN VNI와 동일 개념)
Reserved8비트예약 (0으로 설정)
Options가변TLV(Type-Length-Value) 옵션 (Class + Type + Length + Data)

GENEVE Linux 커널 구현

/* include/net/geneve.h — GENEVE 핵심 자료구조 */

struct genevehdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
    u8 opt_len:6;     /* 옵션 길이 (×4 bytes) */
    u8 ver:2;          /* 버전 (0) */
    u8 rsvd1:6;
    u8 critical:1;     /* C 비트 */
    u8 oam:1;          /* O 비트 */
#else
    u8 ver:2;
    u8 opt_len:6;
    u8 oam:1;
    u8 critical:1;
    u8 rsvd1:6;
#endif
    __be16 proto_type;  /* ETH_P_TEB(0x6558)=Ethernet */
    u8     vni[3];      /* Virtual Network Identifier */
    u8     rsvd2;       /* 예약 */
    struct geneve_opt options[]; /* 가변 길이 TLV 옵션 */
};

/* TLV 옵션 구조 */
struct geneve_opt {
    __be16 opt_class;   /* 벤더/표준 식별자 */
    u8     type;        /* 옵션 타입 */
#if defined(__LITTLE_ENDIAN_BITFIELD)
    u8     length:5;    /* 데이터 길이 (×4 bytes) */
    u8     r3:1;
    u8     r2:1;
    u8     r1:1;
#else
    u8     r1:1;
    u8     r2:1;
    u8     r3:1;
    u8     length:5;
#endif
    u8     opt_data[];  /* 옵션 데이터 */
};

/* GENEVE 디바이스 구조 */
struct geneve_dev {
    struct hlist_node  hlist;     /* geneve_net 해시 */
    struct net         *net;      /* 네트워크 네임스페이스 */
    struct net_device  *dev;      /* 연관 netdev */
    struct geneve_sock __rcu *sock4; /* IPv4 UDP 소켓 */
    struct geneve_sock __rcu *sock6; /* IPv6 UDP 소켓 */
    struct list_head   next;      /* 전역 디바이스 리스트 */
    struct ip_tunnel_info info;   /* 터널 정보 */
    bool               collect_md; /* metadata 모드 */
    bool               use_udp6_rx_checksums;
    bool               ttl_inherit;
    enum ifla_geneve_df df;      /* DF 비트 설정 */
    bool               inner_proto_inherit;
};

GENEVE 구성

# === GENEVE 기본 구성 ===

# 포인트-투-포인트 GENEVE 터널
ip link add geneve100 type geneve \
    id 100 \
    remote 10.0.0.2 \
    dstport 6081       # IANA 표준 포트

ip addr add 10.200.0.1/24 dev geneve100
ip link set geneve100 up

# === GENEVE + 브리지 (L2 확장) ===
ip link add br-geneve type bridge
ip link add geneve200 type geneve \
    id 200 \
    remote 10.0.0.2 \
    dstport 6081

ip link set geneve200 master br-geneve
ip link set geneve200 up
ip link set br-geneve up

# === external 모드 (OVS/tc/BPF 연동) ===
ip link add geneve-ext type geneve \
    external \
    dstport 6081

# IPv6 언더레이
ip link add geneve300 type geneve \
    id 300 \
    remote fd00::2 \
    dstport 6081

# === TLV 옵션과 함께 사용 (tc/BPF에서 설정) ===
# external 모드 GENEVE에서 BPF로 TLV 옵션 추가
ip link add geneve-tlv type geneve external dstport 6081
ip link set geneve-tlv up

# tc filter에서 tunnel 옵션 설정
tc qdisc add dev geneve-tlv clsact
tc filter add dev geneve-tlv egress \
    flower dst_mac aa:bb:cc:dd:ee:ff \
    action tunnel_key set \
        id 100 \
        src_ip 10.0.0.1 \
        dst_ip 10.0.0.2 \
        dst_port 6081 \
        geneve_opts 0102:1:0a0b0c0d \
    action mirred egress redirect dev geneve-tlv

# GENEVE 디바이스 상세 확인
ip -d link show geneve100
# geneve id 100 remote 10.0.0.2 dstport 6081 ...

# GENEVE 통계
ip -s link show dev geneve100
/* BPF에서 GENEVE TLV 옵션 설정/읽기 */
SEC("tc")
int geneve_encap_with_opts(struct __sk_buff *skb)
{
    struct bpf_tunnel_key key = {};
    struct {
        struct geneve_opt opt;
        __be32 data;
    } geneve_opts;

    key.tunnel_id = 100;
    key.remote_ipv4 = 0x0A000002;  /* 10.0.0.2 */
    key.tunnel_ttl = 64;

    bpf_skb_set_tunnel_key(skb, &key, sizeof(key), 0);

    /* GENEVE TLV 옵션 추가 */
    geneve_opts.opt.opt_class = bpf_htons(0x0102); /* 커스텀 class */
    geneve_opts.opt.type = 1;
    geneve_opts.opt.length = 1;  /* 4 bytes */
    geneve_opts.data = bpf_htonl(0xDEADBEEF);

    bpf_skb_set_tunnel_opt(skb, &geneve_opts,
                           sizeof(geneve_opts));
    return TC_ACT_OK;
}

오버레이 프로토콜 비교

Linux 커널이 지원하는 주요 네트워크 오버레이 프로토콜의 특성을 비교합니다.

특성VXLANGENEVEGRE/NVGRESTT
RFCRFC 7348RFC 8926RFC 2890/7637비표준 (RFC 없음)
캡슐화UDP (4789)UDP (6081)IP Protocol 47TCP-like (7471)
헤더 크기8B 고정8B + 옵션(가변)4~8B18B
네트워크 ID24비트 VNI24비트 VNI24비트 VSID/Key64비트 Context ID
확장성GBP/GPE로 제한적TLV 옵션으로 무한 확장없음없음
ECMP 지원UDP src port 해시UDP src port 해시GRE Key 해시TCP-like src port
NIC 오프로드광범위 지원점점 확대 중대부분 지원제한적
멀티캐스트그룹 기반 BUM유니캐스트 권장그룹 기반유니캐스트만
IPv4 오버헤드50B50B + 옵션38~42B76B
IPv6 오버헤드70B70B + 옵션58~62B96B
주요 사용처데이터센터, 컨테이너OVS, NSX, AWS VPC레거시, 사이트간 VPNVMware (레거시)
커널 소스drivers/net/vxlan/drivers/net/geneve.cnet/ipv4/ip_gre.c미지원
프로토콜 선택 가이드:
  • VXLAN — 가장 넓은 HW 오프로드 지원, BGP EVPN 생태계 성숙. 물리 스위치 기반 데이터센터에 최적.
  • GENEVE — TLV 확장성, OVS 기본 프로토콜. 소프트웨어 정의 네트워킹(SDN)에 최적. 새 프로젝트에 권장.
  • GRE — 단순 사이트 간 터널, 레거시 호환성. 새 오버레이 네트워크에는 비권장.
# === 오버레이 프로토콜별 성능 비교 테스트 ===

# VXLAN 처리량 테스트
iperf3 -c 10.200.0.2 -t 30 -P 4  # VXLAN 인터페이스 통해

# GENEVE 처리량 테스트
iperf3 -c 10.201.0.2 -t 30 -P 4  # GENEVE 인터페이스 통해

# GRE 처리량 테스트
iperf3 -c 10.202.0.2 -t 30 -P 4  # GRE 인터페이스 통해

# 오버헤드 측정: 각 프로토콜의 실제 MTU 확인
ping -M do -s 1450 10.200.0.2  # VXLAN (MTU 1450 + 50 = 1500)
ping -M do -s 1450 10.201.0.2  # GENEVE (옵션 없이 동일)
ping -M do -s 1462 10.202.0.2  # GRE (MTU 1462 + 38 = 1500)

# NIC 오프로드 지원 확인
ethtool --show-tunnels eth0
# Tunnel information for eth0:
#   port 4789, VXLAN    ← VXLAN 오프로드 활성화
#   port 6081, GENEVE   ← GENEVE 오프로드 활성화

switchdev 오버레이 오프로드 개요

switchdev 프레임워크와 eSwitch는 VXLAN/GENEVE 오버레이 네트워크의 성능을 극대화하는 핵심 기술입니다. NVIDIA/Mellanox ConnectX-5/6/7(mlx5), Intel E810(ice) 등의 SmartNIC은 VXLAN/GENEVE 캡슐화/역캡슐화를 하드웨어에서 직접 수행하여 CPU 부하를 크게 줄입니다. TC flower 규칙으로 tunnel_key set 액션을 설치하면 eSwitch가 패킷을 와이어레이트로 터널링합니다.

eSwitch switchdev 모드에서는 VF/SF별 Representor 포트가 생성되어, OVS나 TC flower를 통해 오버레이 터널 규칙을 하드웨어에 오프로드할 수 있습니다. 특히 conntrack offload와 결합하면 설정된 연결(ESTABLISHED)의 VXLAN/GENEVE 패킷이 커널을 완전히 우회하여 NIC에서 직접 처리됩니다.

상세 문서: switchdev 프레임워크, eSwitch 모드 전환, Representor 포트, TC Flower 오프로드 등의 상세 내용은 eSwitch 심화 페이지를 참조하세요.

실전 구성 예제

VXLAN 멀티노드 오버레이

여러 노드에 걸쳐 VXLAN 오버레이 네트워크를 구성하는 기본 예제입니다.

# --- 노드 A (10.0.0.1) ---
ip link add br-overlay type bridge
ip link add vxlan42 type vxlan \
    id 42 local 10.0.0.1 dstport 4789 nolearning

ip link set vxlan42 master br-overlay
ip link set vxlan42 up
ip link set br-overlay up

# 원격 VTEP 등록 (BUM 복제 대상)
bridge fdb append 00:00:00:00:00:00 dev vxlan42 dst 10.0.0.2
bridge fdb append 00:00:00:00:00:00 dev vxlan42 dst 10.0.0.3

# 컨테이너 veth를 오버레이 브리지에 연결
ip link add veth-a type veth peer name veth-a-br
ip link set veth-a-br master br-overlay
ip link set veth-a-br up

ip netns add overlay-ns
ip link set veth-a netns overlay-ns
ip netns exec overlay-ns ip addr add 10.200.0.1/24 dev veth-a
ip netns exec overlay-ns ip link set veth-a up

# --- 노드 B (10.0.0.2) ---
# 동일 구성, local=10.0.0.2, IP=10.200.0.2/24

# 결과: 10.200.0.1 ↔ 10.200.0.2가 L3 네트워크를 통해 L2 통신

GENEVE 오버레이 구성

# --- GENEVE 기본 구성 ---
ip link add geneve100 type geneve id 100 \
    remote 10.0.0.2 dstport 6081

ip link add br-geneve type bridge
ip link set geneve100 master br-geneve
ip link set geneve100 up
ip link set br-geneve up

# 로컬 엔드포인트 연결
ip link add veth-g type veth peer name veth-g-br
ip link set veth-g-br master br-geneve
ip link set veth-g-br up

ip netns add geneve-ns
ip link set veth-g netns geneve-ns
ip netns exec geneve-ns ip addr add 10.201.0.1/24 dev veth-g
ip netns exec geneve-ns ip link set veth-g up

VXLAN + VLAN-Tunnel 매핑 (멀티테넌트)

# VLAN-aware 브리지 + external VXLAN으로 다중 VNI 처리
ip link add br0 type bridge vlan_filtering 1 vlan_default_pvid 0
ip link add vxlan0 type vxlan external dstport 4789 local 10.0.0.1
ip link set vxlan0 master br0
ip link set vxlan0 up
ip link set br0 up

# VLAN ↔ VNI 매핑
bridge vlan add vid 10 dev vxlan0
bridge vlan tunnel add dev vxlan0 vid 10 tunnel_id 100010
bridge vlan add vid 20 dev vxlan0
bridge vlan tunnel add dev vxlan0 vid 20 tunnel_id 100020

# 원격 VTEP FDB
bridge fdb append 00:00:00:00:00:00 dev vxlan0 dst 10.0.0.2 self
bridge fdb append 00:00:00:00:00:00 dev vxlan0 dst 10.0.0.3 self

# VM/컨테이너 access 포트
ip link set tap-vm1 master br0
bridge vlan add vid 10 dev tap-vm1 pvid untagged

오버레이 진단 명령

# VXLAN/GENEVE 디바이스 목록
ip -d link show type vxlan
ip -d link show type geneve

# VXLAN FDB (원격 VTEP 매핑)
bridge fdb show dev vxlan100

# VXLAN/GENEVE 통계
ip -s link show dev vxlan100
nstat -a | grep -i vxlan

# 터널 오프로드 확인
ethtool --show-tunnels eth0

# VLAN-Tunnel 매핑 확인
bridge vlan tunnel show dev vxlan0

# 패킷 캡처 (VXLAN 내부 프레임 확인)
tcpdump -i eth0 -nn udp port 4789 -s 0
tcpdump -i eth0 -nn udp port 6081 -s 0

# VTEP IP 연결 확인
ping -c 3 10.0.0.2    # 언더레이 연결

# MTU 검증 (Path MTU Discovery)
ping -M do -s 1450 10.200.0.2  # 오버레이 IP, VXLAN MTU 확인

# ip monitor로 실시간 이벤트 추적
ip monitor link | grep -E "vxlan|geneve"

관련 커널 설정

# VXLAN
CONFIG_VXLAN=m

# GENEVE
CONFIG_GENEVE=m

# Bridge (오버레이 브리지용)
CONFIG_BRIDGE=m
CONFIG_BRIDGE_VLAN_FILTERING=y

# UDP 터널 지원
CONFIG_NET_UDP_TUNNEL=m

# switchdev (오프로드)
CONFIG_NET_SWITCHDEV=y

보안 고려사항

VXLAN/GENEVE 오버레이 네트워크는 기본적으로 암호화나 인증 메커니즘을 제공하지 않습니다. 언더레이 네트워크의 보안이 오버레이 전체의 보안 기반이 되므로, 적절한 방어 조치가 필수적입니다.

VXLAN/GENEVE 보안

오버레이 보안 경고: VXLAN과 GENEVE는 기본적으로 암호화/인증을 제공하지 않습니다. 언더레이 네트워크에서 UDP 4789/6081 포트에 접근할 수 있는 공격자는 오버레이 트래픽을 도청, 변조, 주입할 수 있습니다. 반드시 추가적인 보안 조치가 필요합니다.
위협설명대응
트래픽 도청언더레이에서 VXLAN UDP 패킷을 캡처하면 내부 프레임이 평문으로 노출IPsec 터널로 언더레이 암호화, MACsec, WireGuard
VNI 스캐닝공격자가 다양한 VNI로 패킷을 전송하여 활성 VNI를 탐색방화벽에서 VTEP IP 화이트리스트, nolearning
VTEP 스푸핑공격자가 VTEP IP를 위조하여 FDB를 오염시키고 트래픽을 가로챔nolearning + 정적 FDB, BGP EVPN (인증된 경로만 학습)
BUM 증폭대량 unknown unicast로 flood 트래픽 증폭FDB 크기 제한 (maxaddress), ARP suppression
MAC 이동 공격MAC 주소를 위조하여 트래픽을 자신의 VTEP으로 리디렉션nolearning, 정적 FDB, MAC flapping 감지
# === VXLAN 보안 강화 설정 ===

# 1. 동적 학습 비활성화 (FDB 오염 방지)
ip link add vxlan100 type vxlan \
    id 100 local 10.0.0.1 dstport 4789 \
    nolearning  # ← 핵심! 수신 패킷에서 MAC 학습 안함

# 2. FDB 크기 제한
ip link set vxlan100 type vxlan maxaddress 256

# 3. 방화벽: VXLAN 포트를 알려진 VTEP만 허용
nft add rule inet filter input \
    udp dport 4789 \
    ip saddr { 10.0.0.2, 10.0.0.3, 10.0.0.4 } \
    accept
nft add rule inet filter input udp dport 4789 drop

# 4. IPsec으로 언더레이 암호화 (ESP 터널)
# VTEP 간 IPsec SA 설정
ip xfrm state add src 10.0.0.1 dst 10.0.0.2 \
    proto esp spi 0x1001 mode transport \
    enc "aes" 0x$(openssl rand -hex 16) \
    auth "hmac(sha256)" 0x$(openssl rand -hex 32)

ip xfrm policy add src 10.0.0.1 dst 10.0.0.2 \
    proto udp dport 4789 dir out \
    tmpl src 10.0.0.1 dst 10.0.0.2 proto esp mode transport

# 5. MACsec (Layer 2 암호화 — 같은 L2 세그먼트에서)
ip link add macsec0 link eth0 type macsec \
    encrypt on
# MACsec 위에 VXLAN/GENEVE 구성

# 6. MAC flapping 감지 (dmesg 모니터링)
dmesg -w | grep "moved from"
# bridge: vxlan100: xx:xx:xx:xx:xx:xx moved from port X to port Y

성능 벤치마킹

VXLAN/GENEVE 오버레이의 캡슐화 오버헤드를 정량적으로 파악하기 위한 벤치마킹 방법론과 주요 튜닝 포인트입니다.

오버레이 계층별 성능 오버헤드

구성상대 처리량상대 지연CPU 사용주요 병목
물리 NIC 직접 (베이스라인)100%1x낮음NIC 하드웨어 한계
VLAN 서브인터페이스~99%~1.0x매우 낮음HW 오프로드 시 거의 무시
Linux Bridge (VLAN-aware)~95-98%~1.1x낮음FDB 룩업, VLAN 처리
VXLAN (HW 오프로드)~90-95%~1.2x낮음캡슐화 오버헤드
VXLAN (SW 처리)~70-85%~1.5x중간CPU 캡슐화/역캡슐화
GENEVE (SW 처리)~70-85%~1.5x중간VXLAN과 유사
OVS + VXLAN~65-80%~1.5-2x중~높음OVS 매칭 + 캡슐화
OVS + GENEVE + CT offload~85-95%~1.2x낮음초기 연결만 SW
주의: 위 수치는 일반적인 참고값이며, 실제 성능은 NIC 모델, 드라이버 버전, 커널 버전, 워크로드 패턴(패킷 크기, 연결 수 등)에 따라 크게 달라집니다. 반드시 실제 환경에서 벤치마킹해야 합니다.

핵심 성능 튜닝 체크리스트

# === 1. MTU 최적화 (가장 중요) ===
# 점보 프레임으로 오버레이 오버헤드 흡수
ip link set eth0 mtu 9000
ip link set vxlan100 mtu 8950  # 9000 - 50 (VXLAN IPv4)
ip link set br0 mtu 8950

# === 2. NIC 오프로드 확인 ===
ethtool -k eth0 | grep -E "(tx-udp_tnl|rx-gro|tx-checksum|scatter)"
# 모든 오프로드 활성화 확인

# === 3. RSS/RPS 튜닝 (멀티코어 분산) ===
# NIC RSS가 VXLAN inner 해시를 지원하는지 확인
ethtool -n eth0 rx-flow-hash udp4
# 미지원 시 RPS로 소프트웨어 분산
echo "f" > /sys/class/net/vxlan100/queues/rx-0/rps_cpus

# === 4. conntrack 비활성화 (오버레이에서 불필요 시) ===
nft add rule inet raw prerouting iifname "vxlan*" notrack
nft add rule inet raw output oifname "vxlan*" notrack

# === 5. UDP 버퍼 확대 ===
sysctl -w net.core.rmem_max=26214400
sysctl -w net.core.rmem_default=26214400
sysctl -w net.core.wmem_max=26214400

# === 6. GRO (Generic Receive Offload) 활성화 ===
ethtool -K eth0 rx-udp-gro-forwarding on

# === 7. VXLAN FDB 최적화 ===
# nolearning으로 데이터 플레인 FDB 학습 비활성화
# → 컨트롤 플레인(EVPN 등)에서만 FDB 관리
ip link set vxlan100 type vxlan nolearning

# === 8. Busy polling (지연 민감 워크로드) ===
sysctl -w net.core.busy_poll=50
sysctl -w net.core.busy_read=50

# === 벤치마킹 명령 ===
# 처리량 테스트
iperf3 -c 10.200.0.2 -t 30 -P 8 --bidir

# 지연 시간 테스트
ping -c 100 -i 0.01 10.200.0.2 | tail -1

# PPS(Packets Per Second) 테스트
iperf3 -c 10.200.0.2 -t 30 -u -b 10G -l 64

# CPU 사용률 모니터링
mpstat -P ALL 1

흔한 실수와 모범 사례

실수증상해결
VXLAN MTU 미조정 ping은 되는데 TCP(대용량) 전송 실패, Path MTU black hole 물리 MTU 9000 + VXLAN MTU 8950 또는 MSS clamping
VXLAN FDB 00:00:00:00:00:00 누락 BUM 트래픽(ARP 등) 미전달, 초기 ARP 실패로 연결 불가 bridge fdb append 00:00:00:00:00:00 dev vxlan100 dst <VTEP>
방화벽에서 VXLAN/GENEVE UDP 차단 VTEP 간 ping은 되는데 오버레이 통신 불가 nft add rule inet filter input udp dport { 4789, 6081 } accept
VXLAN learning + EVPN 충돌 MAC flapping, FDB 불일치, 트래픽 루프 EVPN 사용 시 반드시 nolearning 설정
GENEVE 포트 혼동 VXLAN(4789)과 GENEVE(6081) 포트를 혼용 프로토콜에 맞는 IANA 포트 사용 확인
언더레이 라우팅 미설정 VTEP 간 UDP 패킷이 전달되지 않음 ip route로 VTEP 간 IP 연결 확인, traceroute로 경로 검증
NIC 오프로드 미확인 CPU 사용률 높음, 처리량 저하 ethtool --show-tunnels eth0으로 VXLAN/GENEVE 오프로드 확인
VLAN-Tunnel 매핑 누락 external VXLAN에서 VNI가 0으로 전송됨 bridge vlan tunnel add dev vxlan0 vid 10 tunnel_id 100010
conntrack 오버헤드 오버레이 인터페이스에서 불필요한 conntrack 처리로 성능 저하 nft add rule inet raw prerouting iifname "vxlan*" notrack

모범 사례 요약

VXLAN/GENEVE 구성:
  • 물리 NIC에 점보 프레임(MTU 9000) 설정 → 오버레이 MTU 8950
  • EVPN 사용 시 반드시 nolearning — 데이터 플레인 학습 비활성화
  • 보안: nolearning + 정적 FDB + 방화벽 VTEP 화이트리스트
  • NIC 오프로드 확인: ethtool --show-tunnels eth0
  • conntrack이 불필요한 오버레이 인터페이스에서는 NOTRACK 적용
  • 새 프로젝트에서는 GENEVE를 우선 검토 (TLV 확장성)
  • UDP 수신 버퍼를 충분히 확보: sysctl -w net.core.rmem_max=26214400

이 주제와 관련된 다른 문서를 더 깊이 이해하고 싶다면 다음을 참고하세요.