Open vSwitch (OVS) 커널 데이터패스 심화

Open vSwitch는 SDN(Software-Defined Networking) 환경의 핵심 가상 스위치입니다. 커널 데이터패스 모듈(openvswitch.ko)은 수백만 pps 수준의 패킷 포워딩을 담당하며, 유저스페이스 데몬(ovs-vswitchd)과 Netlink 채널로 연동하여 플로우 테이블을 관리합니다. 이 문서는 OVS 아키텍처, 커널 모듈 내부 구조, 데이터패스 파이프라인, Megaflow/Microflow 캐시 계층, upcall 메커니즘, conntrack(CT) 통합, 터널링, TC offload, DPDK 데이터패스, OpenFlow 프로토콜 연동, Netlink 프로토콜 상세, 성능 분석, 디버깅 기법, 운영 장애 대응 플레이북, 용량 계획(SLO), 멀티테넌시 보안 하드닝까지 전 영역을 심층 분석합니다.

전제 조건: 네트워크 스택, Netlink, Bridge/VLAN/Bonding 문서를 먼저 읽으세요. OVS는 커널 네트워크 스택 위에서 동작하는 가상 스위치이므로 sk_buff, Netlink 소켓, 브리지 개념에 대한 사전 이해가 필요합니다.
일상 비유: Open vSwitch는 프로그래밍 가능한 교통 관제 시스템과 비슷합니다. 일반 리눅스 브리지가 단순한 교차로 신호등이라면, OVS는 중앙 관제 센터(SDN 컨트롤러)의 명령에 따라 차선별 규칙(플로우 룰)을 동적으로 변경할 수 있는 고급 교통 시스템입니다. 자주 지나가는 차량 패턴은 캐시(Megaflow)에 기록하여 관제 센터에 매번 물어보지 않고 빠르게 처리합니다.

핵심 요약

  • openvswitch.ko -- 커널 데이터패스 모듈. 패킷 매칭과 액션 실행을 고속 처리합니다.
  • ovs-vswitchd -- 유저스페이스 스위치 데몬. OpenFlow 컨트롤러와 통신하고 플로우 룰을 관리합니다.
  • ovsdb-server -- OVS 구성 데이터베이스. 포트, 브리지, QoS 등 설정을 저장합니다.
  • Megaflow 캐시 -- 마스크 기반 와일드카드 매칭 캐시. 단일 플로우 엔트리로 다수 패킷을 처리합니다.
  • upcall -- 커널 캐시 미스 시 유저스페이스로 패킷을 전달하는 메커니즘입니다.

단계별 이해

  1. 패킷 수신
    NIC에서 패킷이 도착하면 OVS 커널 모듈의 vport를 통해 데이터패스에 진입합니다.
  2. 플로우 룩업
    커널은 Microflow 캐시 -> Megaflow 캐시 -> 정확한 플로우 테이블 순서로 매칭을 시도합니다.
  3. 캐시 히트 시 액션 실행
    매칭된 플로우의 액션(출력, VLAN 태깅, NAT 등)을 커널에서 직접 수행합니다.
  4. 캐시 미스 시 upcall
    매칭 실패 시 Netlink를 통해 ovs-vswitchd에 패킷을 전달하고, 데몬이 새 플로우를 설치합니다.
  5. 후속 패킷 고속 처리
    설치된 플로우 캐시에 의해 동일 패턴의 후속 패킷은 커널에서 직접 처리됩니다.

Open vSwitch 개요

OVS란 무엇인가

Open vSwitch(OVS)는 프로덕션 환경에서 사용되는 다계층 가상 스위치입니다. Apache 2.0 라이선스로 배포되며, 하드웨어 스위치와 동등한 수준의 기능을 소프트웨어로 구현합니다. VMware NSX, Red Hat OpenStack, Kubernetes(OVN) 등 주요 가상화/클라우드 플랫폼에서 핵심 네트워킹 컴포넌트로 활용됩니다.

OVS가 필요한 이유

리눅스 커널에는 이미 bridge 모듈이 있지만, 클라우드/SDN 환경에서는 몇 가지 한계가 있습니다.

기능리눅스 BridgeOpen vSwitch
OpenFlow 지원 미지원 완전 지원 (1.0 ~ 1.5)
플로우 기반 포워딩 MAC 학습 기반 L2-L4 다계층 매칭
터널 오버레이 제한적 (VXLAN 별도 설정) VXLAN/Geneve/GRE/STT 통합
중앙 집중 관리 각 호스트 개별 관리 OVSDB 프로토콜 원격 관리
QoS TC로 별도 구성 내장 QoS (큐잉, 미터링)
상태 기반 방화벽 Netfilter 별도 사용 CT 액션으로 통합
하드웨어 오프로드 제한적 TC flower / SmartNIC 오프로드
DPDK 데이터패스 미지원 OVS-DPDK PMD 지원
분산 가상 라우터 미지원 OVN을 통한 DVR 지원

OVS 역사와 발전

OVS는 2009년 Nicira Networks에서 시작되었습니다. 2012년 VMware가 Nicira를 인수한 뒤에도 오픈소스 프로젝트로 유지되어 활발히 발전하고 있습니다.

시기이벤트기술적 의미
2009 OVS 1.0 초기 릴리즈 커널 데이터패스 + 유저스페이스 컨트롤 플레인 아키텍처 확립
2012 VMware, Nicira 인수 NSX 플랫폼의 핵심 컴포넌트로 편입
2014 (Linux 3.3+) 커널 트리 통합 net/openvswitch/ 디렉터리로 메인라인 커널 편입
2015 Megaflow 캐시 도입 와일드카드 매칭으로 upcall 빈도 대폭 감소
2016 Conntrack(CT) 액션 지원 상태 기반 방화벽 기능 통합
2016 OVS-DPDK 안정화 유저스페이스 데이터패스로 수십 Mpps 달성
2018 TC flower offload 지원 SmartNIC 하드웨어 가속 경로 확립
2019 OVN (Open Virtual Network) 분리 분산 가상 라우팅/스위칭 독립 프로젝트
2023+ P4-OVS, eBPF 데이터패스 실험 차세대 프로그래밍 가능 데이터패스 탐색

커널 데이터패스 vs 유저스페이스 데이터패스

OVS는 두 가지 데이터패스 모드를 지원합니다. 커널 데이터패스(system)는 openvswitch.ko 모듈을 통해 커널 공간에서 패킷을 처리합니다. 유저스페이스 데이터패스(netdev)는 DPDK PMD 또는 AF_XDP를 사용하여 커널 바이패스로 패킷을 처리합니다.

특성커널 데이터패스 (system)유저스페이스 데이터패스 (netdev/DPDK)
패킷 처리 위치 커널 공간 (openvswitch.ko) 유저스페이스 (PMD 스레드)
성능 (64B 패킷) 수백만 pps 수천만 pps (DPDK)
지연 시간 수 마이크로초 수백 나노초
CPU 사용 트래픽 비례 (인터럽트 기반) 항상 100% (폴링 기반)
운영 복잡도 낮음 높음 (hugepage, CPU 격리 필요)
커널 스택 통합 완전 통합 (iptables, TC 등) 커널 바이패스 (별도 구성 필요)

OVS 전체 아키텍처

계층별 컴포넌트

OVS 아키텍처는 크게 세 계층으로 나뉩니다. 관리 평면(Management Plane)의 ovsdb-server, 제어 평면(Control Plane)의 ovs-vswitchd, 데이터 평면(Data Plane)의 커널 모듈입니다. 이들은 서로 다른 프로세스/모듈로 분리되어 있으며, 표준 프로토콜로 통신합니다.

계층컴포넌트역할통신 프로토콜
관리 평면 ovsdb-server 구성 데이터베이스 (브리지, 포트, QoS, 미러링 등) OVSDB 프로토콜 (JSON-RPC over TCP/Unix)
제어 평면 ovs-vswitchd OpenFlow 에이전트, 플로우 관리, 학습 OpenFlow (TCP 6653), Netlink (커널 통신)
데이터 평면 openvswitch.ko 패킷 매칭, 액션 실행, 캐싱 Generic Netlink (ovs-vswitchd와 통신)
외부 컨트롤러 SDN Controller (ONOS, ODL, Ryu 등) 네트워크 토폴로지, 정책 결정 OpenFlow (TCP 6653)
유저스페이스 (Userspace) 커널 공간 (Kernel Space) SDN Controller ovsdb-server ovs-vswitchd OpenFlow 에이전트 + 플로우 관리 + 학습 로직 ovs-vsctl / ovs-ofctl / ovs-dpctl OpenFlow OVSDB Generic Netlink (OVS_DATAPATH / OVS_VPORT / OVS_FLOW / OVS_PACKET) openvswitch.ko (커널 데이터패스) Megaflow 캐시 | Microflow 캐시 | 플로우 테이블 | 액션 처리 | CT 통합 vport-netdev vport-internal vport-vxlan vport-geneve vport-gre 물리 NIC / VM tap / 컨테이너 veth

주요 유저스페이스 컴포넌트

ovsdb-server: OVS 구성 정보를 저장하는 경량 데이터베이스 서버입니다. OVSDB 프로토콜(RFC 7047)을 구현하며, 브리지, 포트, 인터페이스, QoS, 미러링 등의 설정 데이터를 JSON 형식으로 관리합니다. /etc/openvswitch/conf.db에 영속적으로 저장됩니다.

ovs-vswitchd: OVS의 핵심 데몬으로, 세 가지 주요 역할을 수행합니다.

OVS 설치와 기본 설정

# OVS 커널 모듈 로드
modprobe openvswitch

# 데몬 시작
systemctl start openvswitch-switch

# 브리지 생성
ovs-vsctl add-br br0

# 물리 포트 추가
ovs-vsctl add-port br0 eth0

# VXLAN 터널 포트 추가
ovs-vsctl add-port br0 vxlan0 -- set interface vxlan0 \
    type=vxlan options:remote_ip=10.0.0.2 options:key=flow

# OpenFlow 컨트롤러 연결
ovs-vsctl set-controller br0 tcp:192.168.1.100:6653

# 현재 구성 확인
ovs-vsctl show

커널 모듈 구조

소스 디렉터리 구조

OVS 커널 모듈은 net/openvswitch/ 디렉터리에 위치합니다. 주요 소스 파일과 역할은 다음과 같습니다.

파일역할
datapath.c데이터패스 핵심 로직, Netlink 인터페이스, upcall
datapath.hdatapath 구조체, 매크로 정의
flow.c패킷에서 플로우 키 추출
flow.hsw_flow_key 구조체 정의
flow_table.c플로우 테이블 관리, 해시 테이블
flow_netlink.cNetlink 메시지 <-> 플로우 키/액션 변환
actions.cOVS 액션 실행 엔진
conntrack.cConntrack(CT) 통합 액션
vport.c가상 포트 추상화 계층
vport-netdev.c일반 net_device vport
vport-internal.c내부(브리지 자체) 포트
vport-vxlan.cVXLAN 터널 포트
vport-geneve.cGeneve 터널 포트
vport-gre.cGRE 터널 포트
meter.cOpenFlow 미터 테이블
openvswitch.ko 커널 모듈 Generic Netlink 인터페이스 datapath 코어 (ovs_dp_process_packet) 키 추출 -> 플로우 룩업 -> 액션 실행 / upcall Microflow 캐시 (EMC) Megaflow 캐시 (SMC) 플로우 테이블 (Exact Match) upcall (캐시 미스) 미스 미스 미스 액션 처리 엔진 (do_execute_actions) Output | Set | Push/Pop VLAN | CT | Sample | Recirc | Clone | Meter vport-netdev vport-internal vport-vxlan vport-geneve vport-gre

핵심 자료구조: struct datapath

/* net/openvswitch/datapath.h */
struct datapath {
    struct rcu_head     rcu;
    struct list_head    list_node;       /* 전역 데이터패스 목록 */

    struct flow_table   table;           /* 플로우 테이블 */

    struct hlist_head   *ports;          /* vport 해시 테이블 */
    struct dp_stats_percpu __percpu *stats_percpu; /* Per-CPU 통계 */
    struct dp_nlsk_pids __rcu *upcall_portids; /* upcall Netlink PID */

    u32              user_features;    /* 유저스페이스 피처 비트 */

    struct net       *net;              /* 네트워크 네임스페이스 */
    char             name[IFNAMSIZ];   /* 데이터패스 이름 (예: "ovs-system") */
};
코드 설명
  • 4행 list_node: 시스템 내 모든 OVS 데이터패스를 연결하는 리스트 노드입니다.
  • 6행 table: 이 데이터패스의 플로우 테이블 구조체. Megaflow/Microflow 캐시를 포함합니다.
  • 8행 ports: 이 데이터패스에 등록된 vport들의 해시 테이블. 포트 번호로 빠른 검색이 가능합니다.
  • 9행 stats_percpu: Per-CPU 통계로 캐시 히트, 캐시 미스, 에러 등 패킷 처리 카운터를 집계합니다.
  • 10행 upcall_portids: upcall을 수신할 유저스페이스 Netlink 포트 ID. 다수 핸들러 스레드 지원을 위해 배열 형태입니다.

vport 추상화 계층

vport는 OVS 커널 모듈의 포트 추상화입니다. 물리 NIC, VM 탭 디바이스, 내부 포트, 터널 포트 등 다양한 유형의 포트를 통일된 인터페이스로 다룹니다.

/* net/openvswitch/vport.h */
struct vport {
    struct net_device *dev;              /* 대응하는 net_device */
    struct datapath   *dp;               /* 소속 데이터패스 */
    struct vport_portids __rcu *upcall_portids; /* Per-vport upcall PID */
    u16               port_no;           /* OVS 포트 번호 */
    struct hlist_node hash_node;          /* 데이터패스 해시 */
    struct hlist_node dp_hash_node;       /* 전역 해시 */
    const struct vport_ops *ops;        /* 포트 타입별 연산 */
};

struct vport_ops {
    enum ovs_vport_type type;
    struct vport *(*create)(const struct vport_parms *);
    void (*destroy)(struct vport *);
    int (*set_options)(struct vport *, struct nlattr *[]);
    int (*get_options)(const struct vport *, struct sk_buff *);
    int (*send)(struct vport *, struct sk_buff *);
};

데이터패스 파이프라인

패킷 처리 흐름 개요

커널 데이터패스에서 패킷이 처리되는 과정은 다음과 같습니다. NIC에서 수신된 패킷은 vport의 rx_handler를 통해 OVS 데이터패스에 진입합니다. 데이터패스 코어는 패킷에서 플로우 키를 추출하고, 캐시 계층에서 매칭되는 플로우를 검색합니다. 히트 시 해당 플로우의 액션을 실행하고, 미스 시 upcall을 통해 유저스페이스에 판단을 위임합니다.

패킷 수신 (vport rx_handler) 플로우 키 추출 (ovs_flow_key_extract) Microflow 캐시 (EMC) 룩업 Megaflow 캐시 (SMC) 룩업 플로우 테이블 (mask_array) 검색 upcall -> ovs-vswitchd 액션 실행 (do_execute_actions) 패킷 출력 (vport send) 새 플로우 캐시 설치 히트 미스 히트 미스 미스 캐시 삽입

핵심 함수 호출 흐름

/* net/openvswitch/datapath.c - 패킷 처리 진입점 */
void ovs_dp_process_packet(struct sk_buff *skb,
                           struct sw_flow_key *key)
{
    struct datapath *dp = get_dp(dev_net(skb->dev), ovs_cb(skb)->input_vport->dp->dp_ifindex);
    struct sw_flow *flow;
    struct sw_flow_actions *sf_acts;
    struct dp_stats_percpu *stats;

    stats = this_cpu_ptr(dp->stats_percpu);

    /* 1단계: 플로우 룩업 (캐시 계층 통과) */
    flow = ovs_flow_tbl_lookup_stats(&dp->table, key, skb_get_hash(skb), &n_mask_hit, &n_cache_hit);

    if (unlikely(!flow)) {
        /* 캐시 미스: upcall 경로 */
        struct dp_upcall_info upcall;
        upcall.cmd = OVS_PACKET_CMD_MISS;
        upcall.portid = ovs_vport_find_upcall_portid(
            ovs_cb(skb)->input_vport, skb);
        ovs_dp_upcall(dp, skb, key, &upcall, 0);
        stats->n_missed++;
        consume_skb(skb);
        return;
    }

    /* 캐시 히트: 액션 실행 */
    ovs_flow_stats_update(flow, key->tp.flags, skb);
    sf_acts = rcu_dereference(flow->sf_acts);
    ovs_execute_actions(dp, skb, sf_acts, key);

    stats->n_hit++;
}
코드 설명
  • 12행 ovs_flow_tbl_lookup_stats()가 EMC -> SMC -> mask_array 순서로 플로우를 검색합니다. n_cache_hit으로 어느 캐시 단계에서 히트했는지 추적합니다.
  • 14-23행 매칭 실패 시 OVS_PACKET_CMD_MISS 명령으로 upcall을 발생시킵니다. ovs_vport_find_upcall_portid()는 라운드 로빈으로 핸들러 스레드를 선택합니다.
  • 26-29행 매칭 성공 시 ovs_flow_stats_update()로 플로우 통계를 갱신하고, RCU로 보호된 액션 리스트를 가져와 ovs_execute_actions()로 실행합니다.

플로우 키 추출

ovs_flow_key_extract()는 패킷 헤더를 파싱하여 sw_flow_key 구조체를 채웁니다. 이 키는 Ethernet(src/dst MAC, EtherType), IPv4/IPv6(src/dst IP, protocol, ToS, TTL), TCP/UDP/SCTP(src/dst port), ICMP(type/code), ARP, 터널 메타데이터 등 L2-L4 전체 필드를 포함합니다.

/* net/openvswitch/flow.c */
int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info,
                         struct sk_buff *skb,
                         struct sw_flow_key *key)
{
    int error;

    /* 1. 메타데이터: 입력 포트, 패킷 마크 등 */
    key->phy.priority = skb->priority;
    key->phy.in_port = OVS_CB(skb)->input_vport->port_no;
    key->phy.skb_mark = skb->mark;
    key->ovs_flow_hash = 0;
    key->recirc_id = 0;

    /* 2. 터널 정보 (터널 포트에서 수신한 경우) */
    if (tun_info) {
        ovs_flow_tun_info_init(key, tun_info);
    }

    /* 3. L2/L3/L4 헤더 파싱 */
    error = key_extract(skb, key);

    return error;
}

플로우 테이블 구조

핵심 자료구조

OVS 플로우 테이블의 핵심은 sw_flow, sw_flow_key, sw_flow_mask 세 구조체입니다. 플로우 테이블은 마스크 배열(mask_array)과 마스크별 해시 테이블 구조로 구성됩니다.

flow_table .mask_array .ti (table_instance) .mask_cache (EMC/SMC) .count .ufid_count mask_array mask[0]: L2 exact (0xFFFF...) mask[1]: L3 /24 wild mask[2]: L4 port wild table_instance (해시 테이블) bucket[0] -> flow_A -> flow_B bucket[1] -> flow_C bucket[2] -> (empty) bucket[N] -> flow_D -> flow_E sw_flow .key (sw_flow_key) .unmasked_key .mask (sw_flow_mask *) .sf_acts (sw_flow_actions *) .stats[] (Per-CPU 통계) .id (sw_flow_id - UFID) .flow_table.hash_node[] .rcu sw_flow_key .tun_key (터널 메타데이터) .phy (in_port, priority, mark) .eth (src MAC, dst MAC, type) .ip (src, dst, proto, tos, ttl) .tp (src port, dst port, flags) .ct (ct_state, zone, mark, labels) .recirc_id .ovs_flow_hash sw_flow_actions .actions_len .rcu .actions[] (nlattr 배열) Output | Set | Push VLAN | CT ...

sw_flow_key 구조체 상세

/* net/openvswitch/flow.h - 플로우 매칭 키 */
struct sw_flow_key {
    u8  tun_opts[IP_TUNNEL_OPTS_MAX]; /* 터널 옵션 데이터 */
    u8  tun_opts_len;

    struct {
        u32  priority;       /* sk_buff->priority */
        u16  in_port;        /* OVS 입력 포트 번호 */
        u32  skb_mark;       /* sk_buff->mark (fwmark) */
    } phy;

    u32  ovs_flow_hash;         /* skb hash (RSS) */
    u32  recirc_id;             /* 재순환 ID */

    struct {
        u8   src[ETH_ALEN];  /* 소스 MAC */
        u8   dst[ETH_ALEN];  /* 목적지 MAC */
        __be16 tci;           /* VLAN TCI */
        __be16 type;          /* EtherType */
        struct {
            __be16 tpid;
            __be16 tci;
        } cvlan;                 /* QinQ 이중 VLAN */
    } eth;

    union {
        struct {             /* IPv4 */
            __be32 src, dst;
            u8     proto, tos, ttl, frag;
        } ipv4;
        struct {             /* IPv6 */
            struct in6_addr src, dst;
            __be32 label;
            u8     proto, tclass, hlimit, frag;
        } ipv6;
        struct {             /* ARP */
            __be32 sip, tip;
            u8     sha[ETH_ALEN], tha[ETH_ALEN];
            u8     op;
        } arp;
    } ip;

    struct {
        __be16 src, dst;     /* L4 소스/목적지 포트 */
        __be16 flags;        /* TCP 플래그 또는 ICMP type/code */
    } tp;

    struct {
        u32    state;        /* CT 상태 (NEW, ESTABLISHED 등) */
        u16    zone;         /* CT 존 */
        u32    mark;         /* CT 마크 */
        struct ovs_key_ct_labels labels; /* CT 레이블 */
    } ct;
};

플로우 룩업 알고리즘

플로우 룩업은 마스크 배열(mask_array)을 순회하면서 각 마스크를 키에 적용한 뒤, 해시 테이블에서 정확한 매칭을 시도합니다. 이는 TSS(Tuple Space Search) 알고리즘의 변형입니다.

/* net/openvswitch/flow_table.c - 플로우 테이블 룩업 */
struct sw_flow *ovs_flow_tbl_lookup_stats(
    struct flow_table *tbl,
    const struct sw_flow_key *key,
    u32 skb_hash,
    u32 *n_mask_hit,
    u32 *n_cache_hit)
{
    struct mask_array *ma = rcu_dereference(tbl->mask_array);
    struct table_instance *ti = rcu_dereference(tbl->ti);
    struct sw_flow_mask *mask;
    struct sw_flow *flow;
    int i;

    /* 마스크 캐시(EMC/SMC)를 먼저 시도 -- 생략 */

    /* mask_array 순회: 각 마스크에 대해 해시 룩업 */
    for (i = 0; i < ma->max; i++) {
        mask = rcu_dereference(ma->masks[i]);
        if (!mask)
            continue;

        flow = masked_flow_lookup(ti, key, mask, n_mask_hit);
        if (flow)
            return flow;
    }

    return NULL;
}

Megaflow 캐시와 Microflow 캐시

2단계 캐시 계층 구조

OVS 커널 데이터패스는 성능 최적화를 위해 2단계 캐시 계층을 사용합니다. Microflow 캐시(EMC, Exact Match Cache)는 최근 사용된 개별 플로우의 정확한 매칭을 캐싱하며, Megaflow 캐시(SMC, Signature Match Cache)는 마스크 기반 와일드카드 매칭을 캐싱합니다.

특성Microflow 캐시 (EMC)Megaflow 캐시 (SMC)
매칭 방식 정확한 5-tuple 매칭 마스크 기반 와일드카드 매칭
엔트리 수 Per-CPU 8192개 (기본값) 커널 플로우 테이블 전체
룩업 비용 O(1) 해시 룩업 O(M) (M = 마스크 수)
캐시 범위 단일 플로우 (좁음) 다수 플로우 커버 (넓음)
적합한 트래픽 반복되는 동일 플로우 다양한 소스/목적지 조합
커널 변수 제어 유저스페이스 비활성화 가능 항상 활성
패킷 해시 (skb_hash) EMC (Exact Match Cache) Per-CPU 해시 테이블, 8192 엔트리 hash(key) -> exact match 비교 SMC (Signature Match Cache) 시그니처 매칭으로 Megaflow 엔트리 선택 mask_index 캐싱으로 마스크 순회 회피 mask_array 전체 순회 모든 마스크에 대해 해시 룩업 (O(M)) 액션 실행 upcall 히트 미스 히트 미스 미스 EMC 히트: ~20ns SMC 히트: ~100ns mask 순회: ~500ns-수us upcall: ~수십us-수ms

Megaflow의 핵심 개념: 와일드카드 매칭

Megaflow의 핵심 혁신은 하나의 캐시 엔트리로 다수의 패킷 플로우를 커버한다는 것입니다. 예를 들어, "10.0.1.0/24에서 10.0.2.0/24로 가는 모든 TCP 패킷"을 단일 Megaflow 엔트리로 표현할 수 있습니다. 이는 OpenFlow 테이블의 와일드카드 매칭 의미론을 커널 캐시에 반영한 것입니다.

Megaflow 도입 전후 비교: Megaflow 도입 전에는 모든 고유한 5-tuple이 별도의 커널 플로우 엔트리를 필요로 했습니다. 1000개의 소스 IP에서 1개의 서버로 접속하면 1000개의 엔트리가 필요했지만, Megaflow를 사용하면 소스 IP를 와일드카드로 표현하여 단 1개의 엔트리로 처리할 수 있습니다. 이로 인해 upcall 빈도가 수십~수백 배 감소하고 캐시 효율이 극적으로 향상됩니다.

EMC 비활성화와 SMC 모드 전환

# EMC 상태 확인
ovs-appctl dpif-netdev/pmd-stats-show

# EMC 비활성화 (대규모 플로우 환경에서 유용)
ovs-vsctl -- --id=@s create Flow_Sample_Collector_Set id=1 \
  -- set Open_vSwitch . other_config:emc-insert-inv-prob=0

# SMC 활성화 (OVS 2.10+)
ovs-vsctl set Open_vSwitch . other_config:smc-enable=true

# EMC 엔트리 수 조정
ovs-vsctl set Open_vSwitch . other_config:emc-max-entries=16384

Upcall 메커니즘

upcall 발생 조건과 흐름

upcall은 커널 데이터패스에서 매칭되는 플로우를 찾지 못했을 때 발생합니다. 커널은 Netlink 메시지를 통해 패킷(또는 패킷 일부)을 ovs-vswitchd에 전달합니다. 데몬은 OpenFlow 테이블을 참조하여 적절한 액션을 결정하고, 두 가지 동작을 수행합니다: (1) 현재 패킷에 대한 즉시 액션 실행, (2) 향후 동일 패턴 패킷을 위한 커널 플로우 캐시 설치.

커널 (openvswitch.ko) 유저스페이스 (ovs-vswitchd) 패킷 수신 (vport) 캐시 미스 OVS_PACKET_CMD_MISS Netlink (패킷 + 키) OpenFlow 테이블 룩업 테이블 0 -> 1 -> ... -> N OVS_PACKET_CMD_EXECUTE OVS_FLOW_CMD_NEW 패킷 실행 플로우 설치 패킷 출력 플로우 캐시 삽입 첫 패킷 지연: 수십 us ~ 수 ms

upcall 핸들러 스레드

ovs-vswitchd는 다수의 upcall 핸들러 스레드를 실행하여 병렬로 upcall을 처리합니다. 각 핸들러 스레드는 전용 Netlink 소켓을 가지며, 커널은 패킷 해시를 기반으로 라운드 로빈 방식으로 핸들러를 선택합니다.

# upcall 핸들러 스레드 수 조정 (기본: 1)
ovs-vsctl set Open_vSwitch . other_config:n-handler-threads=4

# revalidator 스레드 수 조정
ovs-vsctl set Open_vSwitch . other_config:n-revalidator-threads=4

# upcall 통계 확인
ovs-appctl upcall/show

# upcall 속도 제한
ovs-vsctl set Open_vSwitch . other_config:upcall-rate-limit=1000
upcall 폭풍(Upcall Storm) 주의: 플로우 테이블이 비어있거나, 매우 다양한 패킷 패턴이 동시에 유입되면 모든 패킷이 upcall 경로를 거치게 됩니다. 이는 ovs-vswitchd CPU 사용률 급증, 패킷 드롭(Netlink 버퍼 오버플로), 극심한 지연을 유발합니다. ovs-appctl coverage/show에서 upcall 카운터가 비정상적으로 높다면 플로우 설치 로직을 점검해야 합니다.

OVS 액션 처리

액션 타입 전체 목록

OVS 액션은 Netlink 속성(OVS_ACTION_ATTR_*)으로 인코딩됩니다. 커널의 do_execute_actions() 함수가 액션 리스트를 순회하며 각 액션을 실행합니다.

액션 (Netlink Attr)설명사용 예시
OVS_ACTION_ATTR_OUTPUT 지정된 포트로 패킷 출력 브리지 포워딩, 포트 미러링
OVS_ACTION_ATTR_USERSPACE 유저스페이스로 패킷 전달 sFlow/IPFIX 샘플링, 컨트롤러 전달
OVS_ACTION_ATTR_SET 패킷 헤더 필드 설정(Set-Field) MAC/IP/포트 재작성, DSCP 변경
OVS_ACTION_ATTR_SET_MASKED 마스크 기반 부분 필드 설정 특정 비트만 변경 (예: TCP 플래그)
OVS_ACTION_ATTR_PUSH_VLAN VLAN 태그 푸시 VLAN 트렁킹
OVS_ACTION_ATTR_POP_VLAN VLAN 태그 팝 액세스 포트 전달
OVS_ACTION_ATTR_PUSH_MPLS MPLS 레이블 푸시 MPLS 터널링
OVS_ACTION_ATTR_POP_MPLS MPLS 레이블 팝 MPLS 종단
OVS_ACTION_ATTR_CT Conntrack 처리 (상태 추적) 상태 기반 방화벽, NAT
OVS_ACTION_ATTR_CT_CLEAR Conntrack 상태 초기화 서비스 체이닝 시 CT 리셋
OVS_ACTION_ATTR_RECIRC 데이터패스 재순환 CT 후 재매칭, 터널 디캡슐화 후 처리
OVS_ACTION_ATTR_HASH 해시 계산 (ECMP/본딩) 다중 경로 분산
OVS_ACTION_ATTR_SAMPLE 확률적 패킷 샘플링 sFlow, 네트워크 모니터링
OVS_ACTION_ATTR_CLONE 패킷 복제 후 별도 액션 실행 미러링, 모니터링
OVS_ACTION_ATTR_TRUNC 패킷 잘라내기 미러링 시 헤더만 캡처
OVS_ACTION_ATTR_PUSH_ETH 이더넷 헤더 푸시 L3 패킷에 L2 헤더 추가
OVS_ACTION_ATTR_POP_ETH 이더넷 헤더 팝 L2 -> L3 변환
OVS_ACTION_ATTR_METER 미터링 (속도 제한) QoS 대역폭 제어
OVS_ACTION_ATTR_CHECK_PKT_LEN 패킷 길이 검사 후 분기 MTU 기반 경로 선택
OVS_ACTION_ATTR_DROP 패킷 드롭 ACL 차단, 속도 제한 초과

재순환(Recirculation) 메커니즘

재순환은 패킷을 데이터패스 파이프라인 시작으로 되돌리는 강력한 메커니즘입니다. 주로 CT(conntrack) 처리 후 상태 기반 매칭을 수행하거나, 터널 디캡슐화 후 내부 패킷에 대한 새로운 매칭을 수행할 때 사용됩니다. 재순환 시 recirc_id가 증가하여 순환 단계를 구분합니다.

/* net/openvswitch/actions.c - 재순환 구현 */
static int execute_recirc(struct datapath *dp,
                          struct sk_buff *skb,
                          struct sw_flow_key *key,
                          const struct nlattr *a)
{
    struct sw_flow_key recirc_key;
    int err;

    /* 키 복사 및 재순환 ID 설정 */
    memcpy(&recirc_key, key, sizeof(recirc_key));
    recirc_key.recirc_id = nla_get_u32(a);

    /* 새 키로 플로우 키 재추출 (L2-L4 헤더가 변경되었을 수 있음) */
    err = ovs_flow_key_update(skb, &recirc_key);
    if (err)
        return err;

    /* 데이터패스 재진입 */
    ovs_dp_process_packet(skb, &recirc_key);
    return 0;
}

Conntrack 통합

OVS CT 액션 개요

OVS는 리눅스 커널의 nf_conntrack 프레임워크를 직접 활용하여 상태 기반 패킷 처리(Stateful Packet Processing)를 지원합니다. OVS_ACTION_ATTR_CT 액션은 패킷을 conntrack 서브시스템에 통과시키고, 연결 상태(NEW, ESTABLISHED, RELATED, INVALID)를 sw_flow_key.ct 필드에 기록합니다. 이후 재순환을 통해 상태 기반 매칭이 가능합니다.

패킷 수신 플로우 매칭 (recirc_id=0) ct_state=untracked CT 액션 실행 nf_conntrack 통과 ct(zone=1,nat,commit) 재순환 플로우 매칭 (recirc_id=1) ct_state=+new / +est / +rel / +inv +est / +rel 허용 -> 출력 +new 정책 검사 -> 허용/차단 +inv 차단 -> 드롭 +trk-new-est 기본 동작 NAT 처리: ct(nat) 옵션 시 nf_nat 프레임워크가 SNAT/DNAT 수행. commit 옵션으로 연결 상태 확정. Zone 격리: zone=N 옵션으로 테넌트별 독립된 conntrack 테이블 사용.

CT 액션 구현

/* net/openvswitch/conntrack.c */
int ovs_ct_execute(struct net *net,
                   struct sk_buff *skb,
                   struct sw_flow_key *key,
                   const struct ovs_conntrack_info *info)
{
    int err;

    /* 1. conntrack 존(zone) 설정 */
    nf_ct_zone_init(&zone, info->zone.id, NF_CT_DEFAULT_ZONE_DIR, 0);

    /* 2. NAT 처리 (요청 시) */
    if (info->nat) {
        err = ovs_ct_nat(net, key, info, skb, &ct, ctinfo);
    }

    /* 3. nf_conntrack 경로 통과 */
    err = nf_conntrack_in(skb, &state);

    /* 4. commit (연결 확정) */
    if (info->commit) {
        err = ovs_ct_commit(net, key, info, skb);
    }

    /* 5. CT 상태를 sw_flow_key에 기록 */
    ovs_ct_update_key(skb, info, key, true);

    return 0;
}

OpenFlow CT 규칙 예시

# 상태 기반 방화벽: ESTABLISHED/RELATED 허용, NEW는 정책 검사

# 테이블 0: CT 처리
ovs-ofctl add-flow br0 \
  "table=0, priority=100, ip, action=ct(zone=1,table=1)"

# 테이블 1: ESTABLISHED/RELATED 허용
ovs-ofctl add-flow br0 \
  "table=1, priority=100, ct_state=+est+trk, action=normal"
ovs-ofctl add-flow br0 \
  "table=1, priority=100, ct_state=+rel+trk, action=normal"

# 테이블 1: NEW 연결 - 특정 포트만 허용
ovs-ofctl add-flow br0 \
  "table=1, priority=90, ct_state=+new+trk, tcp, tp_dst=80, action=ct(commit,zone=1),normal"
ovs-ofctl add-flow br0 \
  "table=1, priority=90, ct_state=+new+trk, tcp, tp_dst=443, action=ct(commit,zone=1),normal"

# 테이블 1: INVALID 차단
ovs-ofctl add-flow br0 \
  "table=1, priority=80, ct_state=+inv+trk, action=drop"

# NAT 규칙 (SNAT)
ovs-ofctl add-flow br0 \
  "table=0, priority=100, in_port=vm1, ip, action=ct(zone=1,nat(src=10.0.0.1),commit,table=1)"

터널링 (VXLAN/Geneve/GRE)

OVS 터널 아키텍처

OVS는 VXLAN, Geneve, GRE, STT 등 다양한 오버레이 터널 프로토콜을 네이티브로 지원합니다. 터널 포트는 vport 추상화를 통해 일반 포트와 동일한 방식으로 처리됩니다. 특히 key=flow 옵션을 사용하면 OpenFlow 규칙에서 터널 키(VNI)를 동적으로 설정할 수 있어, 단일 터널 포트로 수천 개의 가상 네트워크를 다중화할 수 있습니다.

호스트 A 호스트 B VM-A (VNI 100) VM-C (VNI 200) VM-B (VNI 100) VM-D (VNI 200) OVS br-int (데이터패스) OVS br-int (데이터패스) vxlan0 (key=flow) vxlan0 (key=flow) eth0 (10.0.0.1) eth0 (10.0.0.2) VXLAN 터널 [Outer Eth][Outer IP][UDP 4789][VXLAN Hdr (VNI)][Inner Eth][Inner IP][Payload]

터널 프로토콜 비교

프로토콜캡슐화헤더 크기확장성HW 오프로드OVS 지원
VXLAN UDP (4789) 50 바이트 24-bit VNI (16M) 광범위 지원 완전 지원
Geneve UDP (6081) 50+ 바이트 (가변 TLV) 24-bit VNI + TLV 옵션 증가 추세 완전 지원 (권장)
GRE IP 프로토콜 47 24-42 바이트 32-bit 키 광범위 지원 완전 지원
STT TCP-like (사실상 비표준) 54 바이트 64-bit 컨텍스트 ID 매우 제한적 out-of-tree 모듈

터널 설정 예시

# VXLAN 터널 포트 (flow 기반 VNI)
ovs-vsctl add-port br-int vxlan0 \
  -- set interface vxlan0 type=vxlan \
     options:remote_ip=flow \
     options:key=flow \
     options:dst_port=4789

# Geneve 터널 포트 (TLV 옵션 지원)
ovs-vsctl add-port br-int geneve0 \
  -- set interface geneve0 type=geneve \
     options:remote_ip=flow \
     options:key=flow

# GRE 터널 포트
ovs-vsctl add-port br-int gre0 \
  -- set interface gre0 type=gre \
     options:remote_ip=10.0.0.2 \
     options:key=flow

# OpenFlow 규칙: VNI 기반 트래픽 격리
ovs-ofctl add-flow br-int \
  "table=0, in_port=vm1, action=set_field:100->tun_id, output:vxlan0"
ovs-ofctl add-flow br-int \
  "table=0, in_port=vxlan0, tun_id=100, action=output:vm1"

TC Offload와 하드웨어 가속

OVS TC Flower Offload 개요

OVS는 리눅스 TC(Traffic Control) flower 분류기를 통해 SmartNIC 하드웨어에 플로우 규칙을 오프로드할 수 있습니다. 이를 통해 호스트 CPU 부하 없이 라인 레이트에 가까운 패킷 포워딩이 가능합니다. Mellanox(NVIDIA) ConnectX, Intel E810, Broadcom Stingray 등의 SmartNIC이 이 기능을 지원합니다.

Slow Path (소프트웨어 처리) Fast Path (하드웨어 오프로드) 패킷 수신 Representor 포트 OVS 커널 데이터패스 패킷 출력 TC flower 오프로드 패킷 수신 eSwitch HW (SmartNIC) TC flower 매칭 + 액션 (라인 레이트) 패킷 출력 Slow Path: ~5 Mpps (CPU 의존) Fast Path: 100+ Mpps (HW 라인 레이트, CPU 사용 0%) 첫 패킷: Slow Path 통과 -> ovs-vswitchd가 TC flower 규칙 설치 후속 패킷: eSwitch HW에서 직접 처리 (호스트 CPU 미사용)

TC offload 설정

# 1. eSwitch를 switchdev 모드로 전환 (Mellanox 예시)
devlink dev eswitch set pci/0000:03:00.0 mode switchdev

# 2. TC offload 활성화
ethtool -K enp3s0f0 hw-tc-offload on

# 3. OVS HW offload 설정
ovs-vsctl set Open_vSwitch . other_config:hw-offload=true
ovs-vsctl set Open_vSwitch . other_config:tc-policy=skip_sw

# 4. OVS 서비스 재시작
systemctl restart openvswitch-switch

# 5. offload 상태 확인
ovs-appctl dpctl/dump-flows type=offloaded
tc -s filter show dev enp3s0f0_0 ingress
TC offload 제약 사항: 모든 OVS 액션이 HW 오프로드 가능한 것은 아닙니다. 일반적으로 Output, Set-Field, Push/Pop VLAN, Encap/Decap(터널), CT(일부 NIC)가 지원됩니다. Sample, Clone, Check-pkt-len 등 복잡한 액션은 대부분 SW 폴백(slow path)으로 처리됩니다. tc-policy=skip_sw 설정 시 오프로드 불가한 플로우는 설치 자체가 실패하므로 tc-policy=none(기본값)으로 SW/HW 혼합 사용을 권장합니다.

DPDK 유저스페이스 데이터패스

OVS-DPDK 아키텍처

OVS-DPDK는 커널 데이터패스 대신 DPDK(Data Plane Development Kit)의 PMD(Poll Mode Driver)를 사용하여 유저스페이스에서 패킷을 처리합니다. 커널 인터럽트와 시스템 콜 오버헤드를 완전히 제거하여 수십 Mpps 이상의 처리량을 달성합니다.

특성커널 데이터패스OVS-DPDK
64B 패킷 처리량 (1코어) ~3-5 Mpps ~15-20 Mpps
지연 시간 (평균) ~5-10 us ~0.5-2 us
CPU 활용 트래픽 비례 (효율적) 항상 100% 폴링 (전용 코어)
메모리 요구사항 일반 커널 메모리 hugepage (1GB/2MB) 필수
포트 유형 모든 커널 netdev DPDK 지원 NIC (dpdk, dpdkvhostuser)
VM 연동 TAP / virtio-net vhost-user (공유 메모리)
컨테이너 연동 veth 직접 지원 AF_XDP 또는 vhost-user
운영 복잡도 낮음 높음 (NUMA, CPU 격리, hugepage)

OVS-DPDK 구성 예시

# 1. hugepage 설정
echo 1024 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
mount -t hugetlbfs none /dev/hugepages

# 2. OVS-DPDK 초기화
ovs-vsctl -- --no-wait set Open_vSwitch . other_config:dpdk-init=true
ovs-vsctl set Open_vSwitch . other_config:dpdk-socket-mem="1024,1024"
ovs-vsctl set Open_vSwitch . other_config:dpdk-lcore-mask="0x1"

# 3. PMD 스레드 CPU 마스크 설정
ovs-vsctl set Open_vSwitch . other_config:pmd-cpu-mask="0x6"

# 4. DPDK 브리지 생성
ovs-vsctl add-br br0 -- set bridge br0 datapath_type=netdev

# 5. DPDK 포트 추가
ovs-vsctl add-port br0 dpdk0 \
  -- set Interface dpdk0 type=dpdk \
     options:dpdk-devargs=0000:03:00.0

# 6. vhost-user 포트 추가 (VM 연동)
ovs-vsctl add-port br0 vhost-user-1 \
  -- set Interface vhost-user-1 type=dpdkvhostuserclient \
     options:vhost-server-path="/tmp/vhost-user-1"

# 7. PMD 스레드 상태 확인
ovs-appctl dpif-netdev/pmd-stats-show
ovs-appctl dpif-netdev/pmd-rxq-show

PMD 스레드 구조

OVS-DPDK에서 PMD(Poll Mode Driver) 스레드는 전용 CPU 코어에서 끊임없이 NIC 수신 큐를 폴링합니다. 각 PMD 스레드는 하나 이상의 RX 큐를 담당하며, 배치 단위로 패킷을 수신하여 EMC -> SMC -> 플로우 테이블 순서로 매칭하고 액션을 실행합니다.

# PMD 스레드별 RX 큐 할당 확인
ovs-appctl dpif-netdev/pmd-rxq-show

# 출력 예시:
# pmd thread numa_id 0 core_id 1:
#   isolated : false
#   port: dpdk0            queue-id: 0  pmd usage: 78%
#   port: dpdk0            queue-id: 1  pmd usage: 65%

# PMD 스레드 통계
ovs-appctl dpif-netdev/pmd-stats-show

# 출력 예시:
# pmd thread numa_id 0 core_id 1:
#   packets received: 1234567890
#   emc hits: 1100000000 (89%)
#   smc hits: 100000000 (8%)
#   megaflow hits: 30000000 (2%)
#   upcalls: 4567890 (0.4%)
#   lost: 0

OpenFlow 프로토콜 연동

OpenFlow 테이블 구조

OVS는 OpenFlow 1.0~1.5 프로토콜을 구현합니다. OpenFlow 파이프라인은 다수의 테이블(table 0~254)로 구성되며, 패킷은 테이블 0에서 시작하여 순차적으로 상위 테이블로 진행합니다. 각 테이블의 플로우 엔트리는 매치(match), 우선순위(priority), 인스트럭션(instruction)으로 구성됩니다.

OpenFlow 컴포넌트설명OVS 매핑
Flow Table (0-254) 매칭 규칙과 인스트럭션 집합 ofproto->tables[]
Flow Entry match + priority + instruction + counters + timeout struct rule_dpif
Match Fields L2-L4 패킷 헤더, 메타데이터 OXM(OpenFlow Extensible Match)
Instructions Apply-Actions, Write-Actions, Goto-Table, Meter struct ofpact[]
Group Table 다중 출력, ECMP, Fast Failover ofproto->groups
Meter Table 속도 제한 (QoS) ofproto->meters

OpenFlow 규칙 설정 예시

# 다중 테이블 파이프라인 예시

# 테이블 0: 분류 (Classifier)
ovs-ofctl add-flow br0 \
  "table=0, priority=100, in_port=1, dl_type=0x0800, action=goto_table:10"
ovs-ofctl add-flow br0 \
  "table=0, priority=100, in_port=1, dl_type=0x0806, action=goto_table:20"
ovs-ofctl add-flow br0 \
  "table=0, priority=0, action=drop"

# 테이블 10: ACL (Access Control List)
ovs-ofctl add-flow br0 \
  "table=10, priority=100, ip, nw_dst=10.0.1.0/24, action=goto_table:30"
ovs-ofctl add-flow br0 \
  "table=10, priority=0, action=drop"

# 테이블 20: ARP 처리
ovs-ofctl add-flow br0 \
  "table=20, priority=100, arp, action=normal"

# 테이블 30: L3 라우팅
ovs-ofctl add-flow br0 \
  "table=30, priority=100, ip, nw_dst=10.0.1.1, action=mod_dl_dst:aa:bb:cc:dd:ee:01, output:2"
ovs-ofctl add-flow br0 \
  "table=30, priority=100, ip, nw_dst=10.0.1.2, action=mod_dl_dst:aa:bb:cc:dd:ee:02, output:3"

# Group 테이블 (ECMP)
ovs-ofctl add-group br0 \
  "group_id=1, type=select, bucket=output:2, bucket=output:3, bucket=output:4"
ovs-ofctl add-flow br0 \
  "table=30, priority=90, ip, nw_dst=10.0.2.0/24, action=group:1"

# Meter 테이블 (속도 제한: 1 Mbps)
ovs-ofctl add-meter br0 \
  "meter=1, kbps, band=type=drop,rate=1000"
ovs-ofctl add-flow br0 \
  "table=10, priority=50, ip, nw_src=10.0.3.0/24, action=meter:1, goto_table:30"

# 플로우 테이블 확인
ovs-ofctl dump-flows br0
ovs-ofctl dump-groups br0
ovs-ofctl dump-meters br0

OVS Generic Netlink 패밀리

OVS 커널 모듈은 4개의 Generic Netlink 패밀리를 등록합니다. 각 패밀리는 특정 리소스 타입에 대한 CRUD 연산을 제공합니다.

패밀리매크로관리 대상주요 명령
ovs_datapath OVS_DATAPATH_FAMILY 데이터패스 (브리지) NEW, DEL, GET, SET
ovs_vport OVS_VPORT_FAMILY 가상 포트 NEW, DEL, GET, SET
ovs_flow OVS_FLOW_FAMILY 플로우 엔트리 NEW, DEL, GET, SET
ovs_packet OVS_PACKET_FAMILY 패킷 upcall/execute MISS, ACTION, EXECUTE

Netlink 메시지 형식

/* include/uapi/linux/openvswitch.h */

/* 데이터패스 명령 */
enum ovs_datapath_cmd {
    OVS_DP_CMD_UNSPEC,
    OVS_DP_CMD_NEW,        /* 데이터패스 생성 */
    OVS_DP_CMD_DEL,        /* 데이터패스 삭제 */
    OVS_DP_CMD_GET,        /* 데이터패스 조회 */
    OVS_DP_CMD_SET,        /* 데이터패스 설정 */
};

/* 플로우 명령 */
enum ovs_flow_cmd {
    OVS_FLOW_CMD_UNSPEC,
    OVS_FLOW_CMD_NEW,      /* 플로우 생성 */
    OVS_FLOW_CMD_DEL,      /* 플로우 삭제 */
    OVS_FLOW_CMD_GET,      /* 플로우 조회 */
    OVS_FLOW_CMD_SET,      /* 플로우 갱신 (액션 변경) */
};

/* 패킷 명령 */
enum ovs_packet_cmd {
    OVS_PACKET_CMD_UNSPEC,
    OVS_PACKET_CMD_MISS,    /* 커널->유저: 캐시 미스 upcall */
    OVS_PACKET_CMD_ACTION,  /* 커널->유저: 유저스페이스 액션 */
    OVS_PACKET_CMD_EXECUTE, /* 유저->커널: 패킷 실행 명령 */
};

/* 플로우 키 속성 (매칭 필드) */
enum ovs_key_attr {
    OVS_KEY_ATTR_UNSPEC,
    OVS_KEY_ATTR_ENCAP,        /* 중첩 캡슐화 */
    OVS_KEY_ATTR_PRIORITY,     /* skb->priority */
    OVS_KEY_ATTR_IN_PORT,      /* 입력 포트 */
    OVS_KEY_ATTR_ETHERNET,     /* L2 헤더 */
    OVS_KEY_ATTR_VLAN,         /* VLAN TCI */
    OVS_KEY_ATTR_ETHERTYPE,    /* EtherType */
    OVS_KEY_ATTR_IPV4,         /* IPv4 헤더 */
    OVS_KEY_ATTR_IPV6,         /* IPv6 헤더 */
    OVS_KEY_ATTR_TCP,          /* TCP 헤더 */
    OVS_KEY_ATTR_UDP,          /* UDP 헤더 */
    OVS_KEY_ATTR_ICMP,         /* ICMP 헤더 */
    OVS_KEY_ATTR_ARP,          /* ARP 헤더 */
    OVS_KEY_ATTR_TUNNEL,       /* 터널 메타데이터 */
    OVS_KEY_ATTR_CT_STATE,     /* CT 상태 */
    OVS_KEY_ATTR_CT_ZONE,      /* CT 존 */
    OVS_KEY_ATTR_CT_MARK,      /* CT 마크 */
    OVS_KEY_ATTR_CT_LABELS,    /* CT 레이블 */
    OVS_KEY_ATTR_RECIRC_ID,    /* 재순환 ID */
    /* ... 추가 필드 ... */
};

Netlink 플로우 설치 과정

ovs-vswitchd가 커널에 플로우를 설치할 때의 Netlink 메시지 구조입니다.

/* ovs-vswitchd에서 커널로 전송되는 OVS_FLOW_CMD_NEW 메시지 */
/*
 * [Netlink Header]
 *   nlmsg_type = GENL_ID_OVS_FLOW
 *   nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL
 * [Generic Netlink Header]
 *   cmd = OVS_FLOW_CMD_NEW
 * [OVS Header]
 *   dp_ifindex = 데이터패스 인덱스
 * [Netlink Attributes]
 *   OVS_FLOW_ATTR_KEY:       [매칭 키 (중첩 속성)]
 *     OVS_KEY_ATTR_IN_PORT:  입력 포트
 *     OVS_KEY_ATTR_ETHERNET: src/dst MAC
 *     OVS_KEY_ATTR_IPV4:     src/dst IP, proto
 *     OVS_KEY_ATTR_TCP:      src/dst 포트
 *   OVS_FLOW_ATTR_MASK:      [마스크 (와일드카드)]
 *     (키와 동일 구조, 0xFF = exact, 0x00 = wild)
 *   OVS_FLOW_ATTR_ACTIONS:   [액션 리스트 (중첩)]
 *     OVS_ACTION_ATTR_OUTPUT: 출력 포트
 *   OVS_FLOW_ATTR_UFID:      [고유 플로우 ID (128비트)]
 */

성능 분석과 튜닝

성능 핵심 지표

지표정상 범위경고 임계값확인 방법
캐시 히트율 95% 이상 90% 미만 ovs-appctl dpctl/show -s
upcall 비율 총 패킷의 1% 미만 5% 초과 ovs-appctl coverage/show
Megaflow 마스크 수 100개 미만 500개 초과 ovs-appctl dpctl/dump-flows
upcall 지연 100us 미만 1ms 초과 ovs-appctl upcall/show
커널 플로우 수 플로우 다양성에 비례 200,000개 초과 ovs-dpctl show
revalidator 지연 1초 미만 5초 초과 ovs-appctl upcall/show

성능 벤치마크 데이터

환경데이터패스64B pps1518B pps지연 (P99)
1코어 Xeon Platinum 8380 커널 (EMC 히트) ~5 Mpps ~3 Mpps ~5 us
1코어 Xeon Platinum 8380 OVS-DPDK (EMC 히트) ~18 Mpps ~14 Mpps ~1 us
ConnectX-6 Dx (25G) TC Offload (HW) ~37 Mpps (라인 레이트) ~2.4 Mpps (라인 레이트) ~0.5 us
1코어 (upcall 경로) 커널 ~50 Kpps ~50 Kpps ~100-500 us
성능 수치 해석 주의: 위 벤치마크는 단순 포워딩(L2 스위칭) 기준입니다. CT, NAT, 터널, 미러링 등 복잡한 액션이 추가될수록 처리량은 감소합니다. 특히 CT+NAT 조합은 커널 데이터패스에서 20-40% 성능 감소를 유발할 수 있습니다. 실제 환경에서는 반드시 실측 벤치마크를 수행하세요.

주요 튜닝 포인트

# 1. 플로우 캐시 타임아웃 조정
ovs-vsctl set Open_vSwitch . other_config:max-idle=30000  # 기본 10초 -> 30초

# 2. Netlink 수신 버퍼 크기 증가 (upcall 드롭 방지)
sysctl -w net.core.rmem_max=8388608

# 3. NUMA 인식 설정 (OVS-DPDK)
ovs-vsctl set Interface dpdk0 options:n_rxq=4
ovs-vsctl set Interface dpdk0 other_config:pmd-rxq-affinity="0:2,1:4,2:6,3:8"

# 4. Megaflow 마스크 최적화: 불필요한 매칭 필드 제거
# 나쁜 예: 모든 필드 매칭 -> 마스크 수 폭발
# 좋은 예: 필요한 필드만 매칭 -> 와일드카드 최대화

# 5. EMC 확률 조정
ovs-vsctl set Open_vSwitch . other_config:emc-insert-inv-prob=100  # 1/100 확률로 EMC 삽입

# 6. handler/revalidator 스레드 수 최적화
ovs-vsctl set Open_vSwitch . other_config:n-handler-threads=4
ovs-vsctl set Open_vSwitch . other_config:n-revalidator-threads=4

디버깅과 모니터링

OVS 디버깅 도구 총정리

도구용도핵심 명령어
ovs-vsctl 브리지/포트/인터페이스 구성 show, list interface
ovs-ofctl OpenFlow 테이블 조회/설정 dump-flows, dump-ports-desc
ovs-dpctl 커널 데이터패스 직접 조회 dump-flows, show -s
ovs-appctl 데몬 런타임 명령 bridge/dump-flows, dpif/show
ovsdb-client OVSDB 데이터베이스 직접 조회 dump, monitor
ovs-tcpdump OVS 포트에서 패킷 캡처 ovs-tcpdump -i port_name
ovs-pcap pcap 파일 텍스트 변환 ovs-pcap file.pcap

실전 디버깅 시나리오

# === 시나리오 1: 패킷이 왜 드롭되는가? ===

# 1-1. OpenFlow 플로우 확인 (패킷 카운터 포함)
ovs-ofctl dump-flows br0 --names --no-stats=false

# 1-2. 특정 패킷의 매칭 결과 추적
ovs-appctl ofproto/trace br0 in_port=1,tcp,nw_src=10.0.0.1,nw_dst=10.0.0.2,tp_dst=80

# 1-3. 커널 데이터패스 플로우 덤프
ovs-dpctl dump-flows -m

# 1-4. 포트별 패킷/에러 통계
ovs-ofctl dump-ports br0


# === 시나리오 2: 성능 저하 원인 분석 ===

# 2-1. 캐시 히트율 확인
ovs-appctl dpctl/show -s

# 2-2. coverage 카운터 (upcall 빈도 등)
ovs-appctl coverage/show

# 2-3. 마스크 수와 Megaflow 효율
ovs-appctl dpctl/dump-flows | wc -l  # 커널 플로우 수
ovs-appctl dpctl/dump-flows | grep -oP 'masks:\K\d+' | sort -un  # 마스크 수

# 2-4. 로그 레벨 동적 변경
ovs-appctl vlog/set dpif:dbg
ovs-appctl vlog/set ofproto:dbg

# 2-5. PMD 스레드 통계 (OVS-DPDK)
ovs-appctl dpif-netdev/pmd-stats-show
ovs-appctl dpif-netdev/pmd-stats-clear


# === 시나리오 3: CT 상태 디버깅 ===

# 3-1. conntrack 테이블 덤프
ovs-appctl dpctl/ct-stats-show
conntrack -L --zone=1

# 3-2. CT 시뮬레이션
ovs-appctl ofproto/trace br0 \
  "in_port=1,tcp,nw_src=10.0.0.1,nw_dst=10.0.0.2,tp_src=12345,tp_dst=80,tcp_flags=syn"


# === 시나리오 4: ftrace로 커널 경로 추적 ===

# 4-1. OVS 커널 함수 추적
echo ovs_dp_process_packet > /sys/kernel/debug/tracing/set_ftrace_filter
echo function > /sys/kernel/debug/tracing/current_tracer
cat /sys/kernel/debug/tracing/trace

# 4-2. perf로 CPU 프로파일링
perf top -g -p $(pgrep ovs-vswitchd)
perf record -g -a -F 99 -- sleep 10
perf report

ofproto/trace 출력 예시 해석

ovs-appctl ofproto/trace br0 \
  in_port=1,tcp,nw_src=10.0.0.1,nw_dst=10.0.0.2,tp_dst=80

# 출력 해석:
# Flow: tcp,in_port=1,vlan_tci=0x0000,dl_src=...,dl_dst=...,
#       nw_src=10.0.0.1,nw_dst=10.0.0.2,nw_tos=0,nw_ecn=0,
#       nw_ttl=64,tp_src=0,tp_dst=80,tcp_flags=0
#
# bridge("br0")
# -------------
# 0. priority 100, tcp,in_port=1, ct_state=-trk
#    -> ct(zone=1,table=1)    <- CT 액션 실행
# 1. priority 100, tcp,ct_state=+new+trk,tp_dst=80
#    -> ct(commit,zone=1),output:2    <- 커밋 후 포트 2로 출력
#
# Final flow: ... ct_state=new|trk ...
# Megaflow: recirc_id=0,eth,ip,in_port=1,nw_proto=6,tp_dst=80
# Datapath actions: ct(zone=1),recirc(0x1)

커널 설정

필수 및 권장 Kconfig 옵션

옵션필수/권장설명
CONFIG_OPENVSWITCH 필수 OVS 커널 데이터패스 모듈 (openvswitch.ko)
CONFIG_OPENVSWITCH_VXLAN 권장 VXLAN 터널 포트 지원
CONFIG_OPENVSWITCH_GRE 권장 GRE 터널 포트 지원
CONFIG_OPENVSWITCH_GENEVE 권장 Geneve 터널 포트 지원
CONFIG_NF_CONNTRACK CT 액션 사용 시 필수 conntrack 프레임워크
CONFIG_NF_NAT NAT 사용 시 필수 NAT 프레임워크
CONFIG_NET_CLS_FLOWER TC offload 시 필수 TC flower 분류기
CONFIG_NET_ACT_CT TC CT offload 시 필수 TC conntrack 액션
CONFIG_NET_SWITCHDEV HW offload 시 필수 switchdev 프레임워크
CONFIG_VXLAN VXLAN 사용 시 필수 VXLAN 커널 모듈
CONFIG_GENEVE Geneve 사용 시 필수 Geneve 커널 모듈
CONFIG_GRE GRE 사용 시 필수 GRE 커널 모듈

커널 모듈 파라미터

# 모듈 정보 확인
modinfo openvswitch

# 로드된 OVS 관련 모듈 확인
lsmod | grep openvswitch

# 출력 예시:
# openvswitch           131072  1
# nf_conntrack          172032  3 openvswitch,nf_nat,nf_conntrack_netlink
# nf_nat                 49152  1 openvswitch
# libcrc32c              16384  3 openvswitch,nf_conntrack,nf_nat

# OVS 커널 모듈 버전 확인
dmesg | grep -i openvswitch
# openvswitch: Open vSwitch switching datapath

커널 컴파일 설정 예시

# .config 파일에서 OVS 관련 설정 확인
grep -E "OPENVSWITCH|NF_CONNTRACK|NET_CLS_FLOWER|SWITCHDEV|VXLAN|GENEVE|GRE" /boot/config-$(uname -r)

# 또는 menuconfig에서:
# Networking support --->
#   Networking options --->
#     [*] Open vSwitch
#     [*]   Open vSwitch VXLAN tunneling support
#     [*]   Open vSwitch GRE tunneling support
#     [*]   Open vSwitch Geneve tunneling support
#   Network packet filtering framework (Netfilter) --->
#     [*] Netfilter connection tracking support
#     [*]   Connection tracking NAT support

운영 장애 대응 플레이북

OVS 운영 장애는 보통 upcall 폭증, 마스크 폭발(mask explosion), PMD 불균형, CT 테이블 포화로 수렴합니다. 아래 플레이북은 "10분 내 상태 파악 -> 30분 내 원인 축소 -> 1시간 내 완화 적용" 흐름을 목표로 합니다.

OVS 장애 대응 타임라인 (10분/30분/1시간) 0~10분: 증상 고정 - ovs-appctl dpctl/show -s - ovs-appctl coverage/show - ovs-ofctl dump-flows 카운터 10~30분: 원인 축소 - ofproto/trace 재현 - dump-flows -m 마스크 개수 확인 - PMD/core 편향 분석 30~60분: 완화 적용 - handler/revalidator 조정 - max-idle, emc 정책 조정 - 문제 플로우 우회/분리 핵심 분기 조건 1) upcall/sec 급증 + cache hit 저하 -> Megaflow 마스크/룰 구조 점검 2) PMD 한 코어 100% 고정 -> RSS/큐/PMD affinity 재배치 3) CT drop 증가 -> zone 설계, timeout, conntrack 용량 재검토 4) 커널만 문제면 TC offload/DPDK 경로와 분리 비교 "재현 가능한 단일 패킷"을 먼저 만들고 ofproto/trace로 정책 경로를 고정하는 것이 핵심
장애 대응의 핵심은 빠른 로그 수집보다 원인 분기(캐시/PMD/CT)를 명확히 나누는 것입니다.
증상우선 점검즉시 완화
처리량 급락, CPU 급등 coverage/show의 upcall 카운터, dpctl/show -s 캐시 히트율 룰 집합 단순화, n-handler-threads 임시 상향
특정 코어만 과부하 PMD stats의 큐 불균형 RXQ 분산, pmd-rxq-affinity 재설정
신규 연결 지연 증가 CT zone별 엔트리/드롭, NAT 충돌 zone 분리, timeout 완화, 신규 플로우 burst 제한
터널 트래픽만 손실 MTU, UDP checksum, DF 설정 경로 MTU 재조정, 터널 옵션 정합성 통일
# === OVS 장애 1차 수집 템플릿 ===
TS=$(date +%Y%m%d-%H%M%S)
OUT=/var/tmp/ovs-incident-$TS
mkdir -p "$OUT"

ovs-vsctl show > "$OUT/ovs-vsctl-show.txt"
ovs-appctl dpctl/show -s > "$OUT/dp-show-s.txt"
ovs-appctl coverage/show > "$OUT/coverage.txt"
ovs-ofctl dump-flows br0 --names > "$OUT/ofctl-flows.txt"
ovs-dpctl dump-flows -m > "$OUT/dp-flows-masked.txt"
ovs-appctl dpif/show > "$OUT/dpif-show.txt"

# PMD/DPDK 사용 시
ovs-appctl dpif-netdev/pmd-stats-show > "$OUT/pmd-stats.txt"

# 커널/인터럽트 관찰
grep -E "NAPI|softirq|NET_RX|openvswitch" /proc/softirqs > "$OUT/softirqs.txt"
cat /proc/interrupts > "$OUT/interrupts.txt"

tar czf "$OUT.tar.gz" -C /var/tmp "$(basename "$OUT")"

용량 계획과 SLO 설계

OVS 성능 문제는 단순 pps 최대치보다 워크로드 특성(플로우 수, 신규 연결 비율, 터널 비중, CT/NAT 사용량)에서 먼저 발생합니다. 운영 SLO는 다음 세 지표를 분리해서 정의하는 것이 안전합니다.

OVS 용량 계획: 트래픽 특성 -> 병목 지점 -> 확장 전략 입력 특성 flow churn, packet size, tunnel ratio 병목 후보 upcall/PMD/CT/IRQ imbalance 확장 전략 scale-up, scale-out, offload, DPDK 권장 임계값 예시 - upcall miss 비율 > 3% 지속: 플로우/마스크 재설계 신호 - PMD 코어 편차 > 35%: RXQ/pinning 불균형 신호 - CT usage > 80%: timeout/zone 분할 또는 노드 분산 필요 - p99 포워딩 지연 2배 증가: 커널 path vs DPDK path 분리 진단 단일 절대값보다 "증가 기울기" 알람이 실제 장애 조기 감지에 더 유효
용량 계획은 한계치 측정이 아니라 병목 발생 기울기를 모니터링하는 방식이 효과적입니다.

권장 SLO 템플릿

카테고리지표권장 목표
포워딩p99 패킷 지연< 250us (커널 path 기준)
포워딩드롭률< 0.1%
제어면upcall 처리 지연p99 < 5ms
캐시Megaflow hit 비율> 95%
자원PMD core 편차< 25%
상태CT 테이블 사용률< 70%

보안 하드닝과 멀티테넌시 운영

OVS는 L2~L4까지 강력한 정책을 적용할 수 있지만, 멀티테넌트 환경에서는 테넌트 분리 경계운영 권한 경계를 동시에 설계해야 합니다. 특히 CT zone, 터널 키, OpenFlow 우선순위 충돌은 보안 사고의 빈번한 원인입니다.

멀티테넌시 보안 경계: Port/VLAN/VNI/CT Zone 계층 분리 Tenant A in_port=10, VLAN 110, VNI 50110, CT zone 101 ACL: allow 10.10.0.0/16, deny east-west except policy Tenant B in_port=20, VLAN 120, VNI 50120, CT zone 201 ACL: allow 10.20.0.0/16, deny cross-zone 정책 검증 레이어 - OpenFlow priority 충돌 검사 - CT zone 격리 및 NAT 범위 검증 차단 테넌트 분리는 VLAN/VNI만으로 끝나지 않으며 CT zone과 ACL 우선순위를 함께 고정해야 안전
멀티테넌시 OVS는 포트 분리 + 오버레이 키 + CT zone + 정책 우선순위를 동시에 관리해야 합니다.

보안 하드닝 체크리스트

영역점검 항목권장 상태
제어 채널OpenFlow/OVSDB TLS 사용 여부mTLS 강제, 평문 TCP 금지
정책기본 정책(default) 허용 여부default deny + 명시 허용
CT테넌트 간 zone 공유zone 분리 필수
터널VNI 키 충돌 가능성테넌트별 키 공간 예약
운영ofctl 수동 변경 추적변경 감사 로그와 롤백 절차 확보
오프로드HW offload 정책 일관성SW/HW 결과 정합성 검증 자동화
# OpenFlow/OVSDB TLS 확인 (예시)
ovs-vsctl get Open_vSwitch . ssl
ovs-vsctl get-controller br0

# CT zone/정책 검증 보조 (예시)
ovs-ofctl dump-flows br0 | grep -E "ct\\(zone=|priority="

# 구성 변경 이력 확인
ovsdb-client dump Open_vSwitch
ovs-appctl vlog/list

# 하드웨어 오프로드 사용 시 정책 불일치 점검
tc -s filter show dev eth0 ingress
ovs-appctl dpctl/dump-flows -m
실무 주의: 보안 정책을 OpenFlow와 TC offload에 동시에 배치하는 환경에서는 "한쪽만 업데이트"되는 순간이 가장 위험합니다. 배포 파이프라인에서 정책 버전 일치 검증(OVS rule hash == TC rule hash)을 자동화하세요.

OVS vs Linux Bridge vs eBPF/XDP 선택 기준

실무에서는 "어떤 기술이 더 빠른가"보다 "현재 요구사항에 어떤 데이터 경로가 맞는가"가 더 중요합니다. 아래 매트릭스는 운영 복잡도, 기능 폭, 성능 특성, 장애 대응 난이도를 함께 비교해 OVS/Bridge/eBPF-XDP/DPDK 중 우선 선택지를 빠르게 좁히기 위한 기준입니다.

항목Linux BridgeOVS (Kernel)eBPF/XDP + TCOVS-DPDK
주요 강점 단순 L2 브리징, 낮은 운영 복잡도 플로우 기반 정책, 터널, OpenFlow/OVN 연계 초저지연 필터/리다이렉트, 커스텀 로직 최고 pps 처리량, 사용자 공간 고속 경로
정책 표현력 낮음 높음 (L2~L4 + CT + 미터) 매우 높음 (프로그램 가능) 높음 (OVS 정책 재사용 가능)
터널 오버레이 제한적 강함 (VXLAN/Geneve/GRE) 구현 가능하나 운영 난이도 높음 강함 (DPDK 포트/터널 경로)
최소 지연 낮음 낮음~중간 (룰/캐시 구조 의존) 매우 낮음 매우 낮음 (polling 기반)
최대 처리량 중간 중간~높음 높음 (기능 범위에 따라 변동) 매우 높음
운영 복잡도 낮음 중간 높음 (프로그램/검증 체계 필요) 매우 높음 (NUMA/PMD/hugepage)
장애 분석 난이도 낮음 중간 (flow/upcall/CT 추적) 높음 (BPF verifier + runtime 추적) 높음 (PMD/queue/pinning 포함)
추천 시나리오 단순 VM/컨테이너 L2 연결 멀티테넌시, SDN, 오버레이 네트워크 DDoS 완화, 고성능 트래픽 조작 NFV, 고정 기능 고처리량 데이터플레인
네트워크 데이터 경로 선택 플로우 요구사항 정의 오버레이/정책/지연/운영 인력 수준 정책 단순 + L2 중심 Bridge 우선 SDN/오버레이 필요 OVS Kernel 우선 커스텀 패킷 로직 eBPF/XDP 우선 극한 처리량 OVS-DPDK 우선 혼합 전략 권장 사례 - 기본: OVS Kernel, 엣지 DDoS 방어: XDP - 테넌트 경계/오버레이: OVS, 단순 브리지 구간: Linux Bridge - 초고속 데이터면: OVS-DPDK, 관리면/제어면: OVS Kernel 단일 기술 일괄 적용보다 트래픽 구간별 분할 적용이 안정성과 성능을 함께 확보
OVS 도입 여부는 기능 요구, 운영 난이도, 장애 대응 체계를 함께 평가해 결정해야 합니다.
결정 원칙: 운영 팀이 즉시 디버깅 가능한 경로를 1순위로 선택하세요. 최고 성능 경로라도 장애 시 관측/복구가 어려우면 전체 서비스 가용성은 오히려 낮아질 수 있습니다.

실전 랩 시나리오 (재현 + 검증)

OVS 학습은 개념만 읽는 것보다 "재현 가능한 장애/성능 이벤트"를 직접 만들어 보는 것이 훨씬 빠릅니다. 아래 시나리오는 단일 호스트에서도 재현 가능한 형태로 구성했으며, 각 단계마다 기대 결과검증 명령을 함께 제공합니다.

OVS 실습 루프: 구성 -> 부하 -> 관측 -> 개선 1) 토폴로지 구성 브리지/포트/룰 생성 2) 트래픽 주입 iperf/ping/tcp replay 3) 상태 관측 flows/coverage/PMD 4) 튜닝 적용 thread/cache/policy 실습 산출물 - 전/후 비교: pps, p99 지연, upcall 비율, CT drop, PMD 편차 - 정책 정합성: ofproto/trace 결과, 테넌트 격리 검증, 터널 경로 확인 - 운영 문서화: 재현 스크립트 + 롤백 절차 + 알람 임계값 실습 결과를 숫자로 남겨야 운영 튜닝이 "감"이 아닌 "근거"가 됩니다.
동일 시나리오를 반복 실행해 튜닝 전/후 지표를 비교하면 운영 정책을 안정적으로 고정할 수 있습니다.
목표핵심 확인 항목
랩 A 캐시 효율 Megaflow/EMC 히트율 개선 upcall 감소, hit 비율 증가, CPU 사용률 안정화
랩 B CT 경로 stateful 정책과 zone 분리 검증 CT state 전이, 신규/재전송 처리, zone 충돌 여부
랩 C PMD 밸런싱 큐/코어 편향 완화 코어별 처리량 편차 감소, tail latency 개선
랩 D 장애 대응 upcall 폭증 이벤트 대응 자동화 수집 번들 생성, 임시 완화, 롤백 절차 유효성

랩 A: 캐시 효율 실험

# 1) 기준 상태 수집
ovs-appctl dpctl/show -s
ovs-appctl coverage/show

# 2) 트래픽 주입 (예: iperf 또는 tcpreplay)
iperf3 -c 10.0.0.2 -t 30 -P 8

# 3) 룰 단순화 후 재측정
ovs-ofctl dump-flows br0
ovs-appctl dpctl/show -s

# 기대 결과: upcall 비율 감소, megaflow hit 증가

랩 B: CT zone 분리 검증

# 1) zone별 CT 룰 적용 예시
ovs-ofctl add-flow br0 "priority=200,in_port=10,ip,actions=ct(zone=101,table=1)"
ovs-ofctl add-flow br0 "priority=200,in_port=20,ip,actions=ct(zone=201,table=1)"

# 2) trace로 상태 전이 확인
ovs-appctl ofproto/trace br0 "in_port=10,tcp,nw_src=10.10.0.2,nw_dst=10.10.0.3,tp_dst=443"
ovs-appctl ofproto/trace br0 "in_port=20,tcp,nw_src=10.20.0.2,nw_dst=10.20.0.3,tp_dst=443"

# 3) conntrack 엔트리 점검
ovs-appctl dpctl/ct-stats-show
conntrack -L | head

# 기대 결과: 테넌트 간 CT state/entry가 섞이지 않음

랩 C: PMD 밸런싱 실험 (DPDK 환경)

# 1) 현재 PMD 편차 확인
ovs-appctl dpif-netdev/pmd-stats-show

# 2) RXQ affinity 조정
ovs-vsctl set Interface dpdk0 other_config:pmd-rxq-affinity="0:2,1:4,2:6,3:8"

# 3) 재부하 후 비교
ovs-appctl dpif-netdev/pmd-stats-clear
iperf3 -c 10.0.0.2 -t 60 -P 16
ovs-appctl dpif-netdev/pmd-stats-show

# 기대 결과: 특정 코어 쏠림 완화, p99 지연 감소

랩 D: 장애 대응 리허설

# 1) 이벤트 발생 전 수집 스크립트 준비
cat >/usr/local/bin/ovs-incident-capture.sh <<'EOF'
#!/bin/bash
TS=$(date +%Y%m%d-%H%M%S)
OUT=/var/tmp/ovs-incident-$TS
mkdir -p "$OUT"
ovs-appctl dpctl/show -s > "$OUT/dp.txt"
ovs-appctl coverage/show > "$OUT/coverage.txt"
ovs-ofctl dump-flows br0 > "$OUT/flows.txt"
tar czf "$OUT.tar.gz" -C /var/tmp "$(basename "$OUT")"
EOF
chmod +x /usr/local/bin/ovs-incident-capture.sh

# 2) 리허설 실행
/usr/local/bin/ovs-incident-capture.sh
ls -lh /var/tmp/ovs-incident-*.tar.gz

# 기대 결과: 1분 내 분석 번들 생성 완료
랩 운영 팁: 각 랩마다 "기준값(Baseline) -> 변경값(Change) -> 결과(Result)" 세 줄을 남기면, 추후 커널/OVS 버전 업그레이드 후 회귀 검증에도 동일 스크립트를 재사용할 수 있습니다.

커널/OVS/DPDK 버전 호환 매트릭스

OVS 운영에서 가장 많은 장애 원인은 "기능 미지원" 자체보다 버전 조합 불일치입니다. 특히 커널 CT/NAT 동작, TC offload, DPDK PMD 옵션은 OVS 릴리즈와 커널 기능 수준이 함께 맞아야 안정적으로 동작합니다.

기능커널 의존성OVS 의존성운영 체크 포인트
CT/Stateful ACL NF_CONNTRACK, NF_NAT 2.x 전반 지원 zone 분리, timeout 정책, conntrack 용량 한계 확인
TC flower offload NET_CLS_FLOWER, NIC 드라이버 지원 중반 이후 안정화 SW/HW rule 정합성 검증 자동화 필수
OVS-DPDK PMD hugepage, NUMA, vfio/uio DPDK ABI 호환 범위 필요 PMD pinning, RXQ 분배, 코어 편차 점검
Geneve 옵션 처리 Geneve 커널 모듈 수준 OVN/OVS 정책 연동 MTU/option 길이/파싱 오버헤드 검증
Recirculation 최적화 데이터패스 경로 안정성 Megaflow/SMC 개선 릴리즈 recirc depth 과도 증가 여부 모니터링

권장 조합 가이드 (실무 기준)

운영 목표권장 커널 계열권장 OVS 계열DPDK비고
일반 가상화 + 오버레이 LTS 커널 (배포판 벤더 지원) 배포판 기본 OVS 또는 LTS 브랜치 선택 운영 안정성 우선, 업그레이드 주기 길게
멀티테넌시 + 고급 정책 LTS + 최신 네트워크 백포트 최근 OVS 안정 릴리즈 선택 CT/터널/OVN 기능 검증 후 배포
초고성능 NFV DPDK 친화 커널 설정 OVS-DPDK 검증 릴리즈 필수 PMD/NUMA 설계가 성능 좌우
HW offload 중심 NIC 벤더 권장 커널 TC offload 검증 버전 선택 드라이버/펌웨어와 3자 호환성 확인
# 현재 커널/OVS/DPDK 버전과 빌드 옵션 확인
uname -r
ovs-vswitchd --version
ovsdb-server --version
ovs-vsctl get Open_vSwitch . ovs_version

# datapath 타입(system/netdev)과 기능 플래그 확인
ovs-vsctl get Open_vSwitch . datapath_types
ovs-vsctl get Open_vSwitch . iface_types
ovs-appctl dpif/show

# DPDK 연동 시
ovs-vsctl get Open_vSwitch . dpdk_initialized
ovs-vsctl get Open_vSwitch . dpdk_version

# 커널 OVS 모듈 및 의존 모듈 확인
modinfo openvswitch
lsmod | grep -E "openvswitch|nf_conntrack|nf_nat"
업그레이드 원칙: 커널/OVS/DPDK를 한 번에 모두 올리지 말고, 1) 테스트 환경에서 기능 호환성 검증 2) 단일 축(예: OVS만) 업그레이드 3) 성능/오류 지표 비교 순서로 진행해야 롤백 경로를 유지할 수 있습니다.

참고자료

공식 문서

커널 소스 코드

설계 문서 및 논문

관련 프로젝트

다음 학습:
  • Netlink -- OVS 커널/유저스페이스 제어 채널 이해를 위한 선행 문서
  • Netfilter -- CT/NAT 동작과 상태 기반 정책 해석에 필수
  • TC (Traffic Control) -- TC flower offload와 OVS 하드웨어 가속 연계
  • eSwitch (Embedded Switch) -- switchdev/오프로드 파이프라인 심화
  • DPDK -- OVS-DPDK PMD 경로와 성능 최적화 심화
  • SmartNIC/DPU -- 인프라 수준의 오프로드 아키텍처 확장
  • Bridge/VLAN/Bonding -- 리눅스 브리지와 운영 선택 기준 비교
  • GRE -- OVS 터널 경로 디버깅을 위한 GRE 세부 이해
  • VPP (FD.io) -- OVS 대비 유저스페이스 대안 데이터패스 비교