NGFW 하드웨어 오프로드
차세대 방화벽(NGFW) 하드웨어 오프로드 아키텍처 3대 유형(CPU중심 Lookaside·SoC중심 Lookaside·Inline SmartNIC/DPU), Fast/Slow/Exception 경로, Stateful 방화벽·NAT·ACL·QoS·터널(Tunnel)·IPSec 오프로드, 상용 NGFW 비교, Linux 커널 기반 NGFW 파이프라인(Pipeline), 세션 오프로드 결정 트리 종합 가이드
핵심 요약
- 한 줄 정의: NGFW 하드웨어 오프로드란 차세대 방화벽의 패킷 처리 파이프라인 중 검증 완료된 세션을 SmartNIC/DPU 하드웨어에서 직접 전달하여 CPU 부하를 극적으로 줄이는 기술입니다.
- 핵심 역할: 새 세션의 첫 패킷만 커널(Slow Path)에서 전체 보안 검사(ACL, conntrack, DPI, IPS)를 수행하고, 이후 패킷은 하드웨어 Fast Path로 우회시켜 라인 레이트(Line Rate) 처리를 달성합니다.
- 사용 이유: DPI·IPS·App-ID·SSL 검사가 추가된 NGFW는 전통 방화벽 대비 패킷당 처리 비용이 수십 배 높으므로, 확립된 세션을 오프로드하지 않으면 처리량(Throughput)이 급감합니다.
- Linux 구현:
nf_flowtable(SW 오프로드) →TC flower+eSwitch FDB(HW 오프로드) →NFQUEUE(DPI 연동)를 조합하여 오픈소스 NGFW 파이프라인을 구성합니다. - 3계층 경로: Fast Path(HW/SW 고속 전달), Slow Path(전체 보안 파이프라인), Exception Path(이상 탐지 시 CPU 복귀)로 트래픽을 분류합니다.
단계별 이해
- 패킷 수신과 분류
NIC가 패킷을 수신하면 eSwitch FDB 또는 TC flower 규칙으로 기존 오프로드 세션인지 확인합니다. 매칭되면 Fast Path로 즉시 전달하고, 매칭되지 않으면 커널 네트워크 스택으로 올립니다. - Slow Path 보안 검사
새 세션의 첫 패킷은 Netfilter 훅 체인을 통과하며 ACL 필터링, conntrack 상태 생성, NAT 변환, NFQUEUE를 통한 DPI/IPS 검사를 순서대로 받습니다. - 오프로드 결정
conntrack 상태가 ESTABLISHED로 전환되고 보안 정책이 허용(ACCEPT)이면,nf_flowtable이 해당 세션을 오프로드 후보로 등록합니다. ALG, 프래그먼트, 특수 프로토콜 세션은 제외됩니다. - HW 오프로드 설치
flowtable이 TC flower 규칙을 생성하고, 이를 eSwitch FDB에 설치합니다. 이후 해당 세션의 패킷은 커널을 거치지 않고 NIC 하드웨어에서 직접 NAT 변환과 포워딩을 수행합니다. - Exception 처리와 세션 종료
오프로드 중 TCP RST/FIN, 프로토콜 변경, 정책 업데이트가 감지되면 HW 규칙을 제거하고 패킷을 다시 Slow Path로 복귀시킵니다. conntrack 타임아웃(Timeout) 시에도 오프로드 엔트리를 정리합니다.
단계별 학습 로드맵
| 단계 | 학습 내용 | 관련 섹션 | 난이도 |
|---|---|---|---|
| 1 | NGFW가 전통 FW와 어떻게 다른지 이해 | 개요 | 입문 |
| 1.5 | CPU중심 Lookaside / SoC중심 Lookaside / Inline 3대 아키텍처 | 오프로드 아키텍처 3대 유형 | 입문 |
| 2 | Fast/Slow/Exception 3계층 경로 구분 | 데이터 플레인 아키텍처 | 입문 |
| 3 | 세션이 오프로드되는 조건과 결정 트리 | 세션 오프로드 생명주기 | 중급 |
| 4 | Stateful FW/NAT/ACL 오프로드 메커니즘 | Stateful 방화벽 오프로드 | 중급 |
| 5 | QoS/터널/IPSec 오프로드 파이프라인 | QoS/터널/IPSec 오프로드 | 중급 |
| 5.5 | 암·복호화 트래픽 HW 오프로드 | 암/복호화 HW 오프로드 | 고급 |
| 6 | 상용 NGFW 칩 아키텍처 비교 (암호화 관점) | 상용 NGFW HW 아키텍처 | 참고 |
| 7 | 커널 서브시스템 매핑(Mapping) | 커널 빌딩 블록 | 중급 |
| 8 | 실전 nftables + TC flower 규칙 | 구현 패턴 | 고급 |
| 9 | 보안 vs 성능 트레이드오프 분석 | 보안 vs 오프로드 트레이드오프 | 고급 |
| 10 | 성능 튜닝과 운영 | 성능 튜닝, 운영 가이드 | 고급 |
| 11 | QUIC/TLS 1.3/ECH의 NGFW 도전과제 | QUIC/ECH와 NGFW 오프로드 | 고급 |
| 12 | 멀티 테넌트 격리(Isolation)와 zone 분리 | 멀티 테넌트 NGFW | 고급 |
| 13 | eBPF 기반 차세대 NGFW 파이프라인 | eBPF 기반 차세대 NGFW | 고급 |
| 14 | 흔한 실수와 안티패턴 회피 | 흔한 실수 | 중급 |
| 15 | 실습 (flowtable, DPI, XDP) | 실습 가이드 | 중급 |
| 16 | TC action 오프로드 전체 레퍼런스 (12종) | TC action 오프로드 | 고급 |
| 17 | Bridge/switchdev/FIB HW 오프로드 상세 | Bridge/switchdev, FIB 오프로드 | 고급 |
| 18 | Tunnel/LAG/Bond HW 오프로드 상세 | Tunnel 오프로드, LAG/Bond | 고급 |
| 19 | TC chain 멀티스테이지/qdisc HW 오프로드 | TC chain/goto, qdisc 오프로드 | 고급 |
| 20 | ethtool/Header Rewrite/Meter/devlink 상세 | ethtool, Header Rewrite, devlink | 고급 |
선수 지식 수준 가이드
| 지식 영역 | 필수/권장 | 수준 | 학습 자료 |
|---|---|---|---|
| iptables/nftables 기초 | 필수 | 체인, 테이블, 규칙 작성 | Netfilter 프레임워크 |
| conntrack 이해 | 필수 | NEW/EST/REL 상태, conntrack -L 사용 | conntrack 헬퍼 |
| TC (Traffic Control) | 권장 | qdisc, filter, flower classifier 기초 | TC |
| NIC 드라이버 기초 | 권장 | ethtool, ring buffer, offload 개념 | Network Device 드라이버 |
| Linux 네트워킹 전반 | 권장 | sk_buff, Netfilter 훅, 포워딩 경로 | sk_buff 구조 |
핵심 용어 정리
| 용어 | 설명 |
|---|---|
| Fast Path | 이미 검사가 완료된 세션의 후속 패킷을 최소 비용(HW 또는 SW)으로 전달하는 경로 |
| Slow Path | 새 세션의 패킷이 전체 보안 파이프라인(ACL → conntrack → DPI → IPS)을 통과하는 경로 |
| Exception Path | 오프로드된 세션이 비정상 상황(FIN/RST, ALG, 정책변경)으로 CPU로 복귀하는 경로 |
| conntrack | 커널의 연결 추적(Connection Tracking) 시스템. TCP/UDP 세션 상태(NEW, ESTABLISHED, RELATED)를 관리 |
| flowtable | nf_flowtable. ESTABLISHED 세션을 Netfilter 훅을 건너뛰고 직접 전달하는 SW 오프로드 |
| eSwitch FDB | NIC 내장 하드웨어 스위치의 Forwarding Database. TC flower 규칙을 하드웨어에서 실행 |
| TC flower | Traffic Control의 flower 분류기. L2~L4 필드 매칭으로 패킷을 분류하고 HW offload 가능 |
| ct_state | conntrack 상태 플래그. +est(established), +new(new), +trk(tracked), +inv(invalid) 등 |
| NFQUEUE | Netfilter Queue. 커널 패킷을 유저스페이스 프로그램(DPI 엔진)에 전달하는 메커니즘 |
| CPS | Connections Per Second. 초당 새 연결 수립 수. NGFW Slow Path의 핵심 성능 지표 |
| App-ID | Application Identification. 포트번호가 아닌 실제 L7 프로토콜/애플리케이션을 식별하는 기술 |
| DPI | Deep Packet Inspection. 패킷 페이로드(Payload)를 분석하여 프로토콜, 시그니처, 악성 패턴을 탐지 |
| ALG | Application Level Gateway. FTP/SIP 등 동적 포트를 사용하는 프로토콜의 NAT traversal 지원 |
| SmartNIC/DPU | 프로그래머블 NIC. eSwitch, TC flower offload, IPSec crypto offload 등을 하드웨어에서 실행 |
NGFW HW 오프로드 개요
NGFW의 정의
차세대 방화벽(Next-Generation Firewall, NGFW)은 전통적인 L3/L4 패킷 필터링 방화벽에 다음 기능을 통합한 보안 장비입니다:
- Deep Packet Inspection (DPI) — L7 애플리케이션 프로토콜 분석
- Application Identification (App-ID) — 포트 번호가 아닌 실제 애플리케이션 식별
- Intrusion Prevention System (IPS) — 시그니처 기반 공격 탐지/차단
- SSL/TLS Inspection — 암호화(Encryption)된 트래픽 복호화(Decryption) 후 검사
- Stateful Session Tracking — conntrack 기반 연결 상태 추적
- URL Filtering / Threat Intelligence — 평판 기반 차단
이러한 기능은 패킷당 처리 비용을 크게 증가시키므로, 하드웨어 오프로드를 통해 검증이 완료된 세션의 후속 패킷을 CPU를 거치지 않고 직접 전달하는 것이 성능의 핵심입니다.
NGFW 세대별 진화
| 세대 | 시기 | 핵심 기술 | 오프로드 방식 | 처리량(Throughput) |
|---|---|---|---|---|
| 1세대 (패킷 필터) | 1990s | L3/L4 ACL (stateless) | ASIC 전체 오프로드 | 1~10 Gbps |
| 2세대 (Stateful FW) | 2000s | conntrack + 상태 기반 ACL | 세션 테이블 ASIC | 10~40 Gbps |
| 3세대 (UTM) | 2005~ | FW + IPS + AV + VPN 통합 | 보안 프로세서(SP) 보조 | 1~10 Gbps |
| 4세대 (NGFW) | 2010~ | App-ID + DPI + SSL 검사 | 검증 세션 선택적 오프로드 | 10~100 Gbps |
| 5세대 (SmartNIC NGFW) | 2020~ | eBPF/XDP + eSwitch + flowtable | 프로그래머블 HW offload | 100~400 Gbps |
5세대의 핵심 차이점은 프로그래머블 오프로드입니다. 기존 ASIC은 벤더가 설계한 고정 파이프라인만 지원했지만, SmartNIC/DPU는 TC flower, eBPF, P4 등으로 오프로드 로직을 사용자가 정의할 수 있습니다.
NGFW 배치 모델
NGFW는 네트워크 내 위치와 동작 방식에 따라 여러 배치 모델이 있으며, 각 모델에서 HW offload의 적용 범위가 달라집니다:
| 배치 모델 | 동작 방식 | HW 오프로드 적용 | 장점 | 단점 |
|---|---|---|---|---|
| Inline (L3 Routed) | 라우터처럼 L3 포워딩 경로에 위치. 패킷이 NGFW를 반드시 통과 | flowtable + eSwitch FDB 전체 활용 가능 | 차단/허용 즉시 적용, NAT 연동 | 단일 장애점, 지연(Latency) 추가 |
| Inline (L2 Transparent) | 브리지(Bridge) 모드로 L2에서 투명하게 검사. IP 주소 불필요 | eSwitch bridge offload + TC flower 활용 | 네트워크 구조 변경 불필요 | NAT 불가, 라우팅(Routing) 정책 제한 |
| TAP/SPAN (Passive) | 트래픽 사본을 수신하여 탐지만 수행 (IDS 모드) | HW offload 불필요 (패킷 전달 없음) | 무중단, 성능 영향 없음 | 차단 불가, 실시간(Real-time) 대응 지연 |
| Proxy (Explicit/Transparent) | TCP 연결을 중간에서 종료/재수립 (SSL Proxy) | 프록시 세션 간 TCP splice offload 가능 | 완전한 L7 검사, SSL 복호화 | 높은 CPU 부하, 세션 오프로드 제한 |
| DPU 기반 (Bump-in-the-Wire) | SmartNIC/DPU가 호스트 앞에서 독립적으로 NGFW 실행 | DPU 내 eSwitch + flowtable 전용 활용 | 호스트 CPU 부하 제로, 독립 보안 | DPU 비용, 관리 복잡성 |
전통 FW vs NGFW 비교
| 특성 | 전통 방화벽 | NGFW |
|---|---|---|
| 검사 계층 | L3/L4 (IP, Port) | L3~L7 (App-ID, DPI) |
| 정책 기준 | 5-tuple (src/dst IP, port, proto) | 5-tuple + App + User + Content |
| 상태 추적 | conntrack (선택적) | conntrack 필수 + DPI 세션 상태 |
| IPS/IDS | 별도 장비 | 통합 (inline IPS) |
| SSL 검사 | 미지원 | SSL/TLS Proxy 또는 인라인 복호화 |
| 처리량 병목(Bottleneck) | PPS (초당 패킷) | CPS (초당 새 연결) + DPI 처리량 |
| HW 오프로드 대상 | 전체 ACL | 검증 완료 세션만 (selective offload) |
| 오프로드 비율 | 90%+ (대부분 정적 규칙) | 40~80% (DPI 결과에 따라 가변) |
오프로드 필요성
NGFW에서 모든 패킷을 CPU에서 처리하면 다음과 같은 병목이 발생합니다:
- DPI 처리량: Suricata/Snort 단일 코어 처리량은 약 1~5 Gbps
- CPS (Connections Per Second): conntrack NEW + DPI 첫 분류까지 코어당 수만~수십만 CPS
- 메모리 대역폭(Bandwidth): 패킷 데이터 + conntrack 테이블 + DPI 시그니처 DB 접근
100Gbps 이상 인터페이스에서 NGFW를 운영하려면, ESTABLISHED 세션의 후속 패킷을 하드웨어에서 처리하고 CPU는 NEW 세션과 예외 상황에만 집중해야 합니다.
트래픽 프로파일과 오프로드 효과
실제 네트워크 트래픽에서 세션의 특성을 분석하면 오프로드의 효과를 정량적으로 이해할 수 있습니다:
| 트래픽 특성 | 일반적 비율 | 패킷 비율 | 바이트 비율 | 오프로드 영향 |
|---|---|---|---|---|
| 장수명 대용량 세션 (영상, 다운로드) | 세션 5% | 60% | 80% | 오프로드 시 가장 큰 효과 |
| 중간 세션 (웹 브라우징) | 세션 20% | 25% | 15% | DPI 분류 후 오프로드 |
| 단수명 세션 (DNS, API) | 세션 75% | 15% | 5% | CPS에 영향, 오프로드 효과 적음 |
핵심 인사이트: 세션 수로는 단수명 세션이 압도적이지만, 실제 트래픽 볼륨(바이트)의 80%는 소수의 장수명 세션이 차지합니다. 이 장수명 세션을 HW offload하면 전체 CPU 부하의 대부분을 해소할 수 있습니다.
- Elephant Flow: 100KB+ 세션. 비디오 스트리밍, 파일 다운로드, 백업. 오프로드 1순위 대상
- Mouse Flow: 10KB 미만 세션. DNS 쿼리, API 호출, 헬스체크. 오프로드 효과 미미하지만 CPS에 영향
- NGFW 오프로드의 목표: Elephant Flow를 모두 Fast Path로 → CPU는 Mouse Flow의 DPI에만 집중
NGFW 핵심 성능 지표
NGFW 성능을 평가할 때 반드시 구분해야 하는 핵심 메트릭입니다. 벤더 데이터시트는 대부분 "방화벽 처리량"만 강조하지만, 실제 NGFW 성능은 모든 보안 기능을 활성화한 상태에서 측정해야 합니다:
| 메트릭 | 의미 | 측정 단위 | 병목 원인 | HW 오프로드 효과 |
|---|---|---|---|---|
| FW 처리량 | L3/L4 ACL + NAT + conntrack만 적용한 최대 처리량 | Gbps | 패킷 처리 오버헤드(Overhead), PPS | flowtable/eSwitch로 100Gbps+ 가능 |
| NGFW 처리량 | App-ID + IPS + DPI를 모두 활성화한 처리량 | Gbps | DPI 엔진 CPU, 시그니처 DB 크기 | EST 세션 오프로드로 DPI 부하 분산(Load Balancing) |
| Threat Prevention 처리량 | IPS + AV + 안티봇 + URL 필터 전체 적용 처리량 | Gbps | 시그니처 매칭, 파일 검사 | 제한적 (첫 패킷/새 세션은 항상 검사) |
| SSL Inspection 처리량 | SSL/TLS 복호화 후 전체 검사 처리량 | Gbps | PKI 연산 (RSA/ECDHE) | Crypto offload (QAT, NIC inline crypto) |
| CPS | 초당 새 연결 수립 수 | connections/s | conntrack NEW + DPI 첫 분류 | 간접적 (CPU 여유분이 CPS에 할당) |
| CC | 동시 연결 수 (Concurrent Connections) | sessions | conntrack 테이블 + DPI 세션 메모리 | HW flow 테이블 활용으로 메모리 절감 |
| 지연 (Latency) | 패킷이 NGFW를 통과하는 데 걸리는 시간 | μs | 파이프라인 단계 수, 큐잉 | HW Fast Path: <5μs, SW: 50~200μs |
오프로드 아키텍처 3대 유형
NGFW 하드웨어 오프로드는 패킷이 처리되는 주체와 경로에 따라 크게 세 가지 아키텍처로 분류됩니다. 이 분류는 앞서 소개한 Fast/Slow/Exception 3계층 경로가 어떤 하드웨어에서, 어떤 방식으로 구현되는지를 결정하는 근본적인 설계 선택입니다.
- CPU중심 룩어사이드(CPU-Centric Lookaside) — CPU가 전체 패킷 처리 파이프라인을 주도하고, 특정 기능(암호화, 패턴 매칭 등)만 외장 가속기에 위임
- SoC중심 룩어사이드(SoC-Centric Lookaside) — 전용 네트워크 프로세서(NP) 또는 ASIC이 Fast Path를 전담하고, 예외 패킷만 CPU로 전달
- 인라인(Inline) — SmartNIC/DPU가 데이터 경로 자체에서 패킷을 처리하여 호스트 CPU를 완전히 우회
세 아키텍처는 상호 배타적이 아니며, 상용 NGFW는 기능별로 이를 혼합(Hybrid)하여 사용합니다. 예를 들어 Fortinet은 세션 오프로드에 SoC중심(NP7), SSL 복호화에 SoC중심(SP5), DPI에 CPU중심(CP9+CPU)을 동시에 적용합니다. 아래에서는 각 아키텍처의 전체 패킷 처리 관점에서의 동작 원리, 장단점, 적용 사례를 상세히 살펴봅니다.
CPU중심 룩어사이드 아키텍처
CPU중심 룩어사이드(CPU-Centric Lookaside) 아키텍처에서 범용 CPU(x86, ARM 서버)가 NGFW 파이프라인의 모든 단계를 직접 실행합니다. Netfilter 훅 체인, conntrack 상태 머신, nftables 규칙 평가, DPI 엔진(Suricata/nDPI) 호출이 모두 CPU에서 수행됩니다. 특정 연산이 CPU에 과도한 부하를 주는 경우에만 해당 작업을 PCIe 버스를 통해 외장 가속기(Lookaside 엔진)에 위임하고, 결과를 돌려받습니다.
동작 원리
- 패킷 수신: NIC이 패킷을 수신하여 DMA로 호스트 메모리에 적재 → NAPI/인터럽트로 CPU에 통보
- 전체 파이프라인 CPU 실행: Netfilter PREROUTING → conntrack → FORWARD(nftables ACL) → NFQUEUE(DPI) → POSTROUTING(NAT) 전 과정을 CPU가 순차 처리
- Lookaside 위임(선택적): 암호화(QAT), 정규식 매칭(HyperScan FPGA), 압축(IAA) 등 CPU 집약적 연산만 가속기에 전송 → 비동기 완료 대기
- 오프로드 판정 후 SW Fast Path: ESTABLISHED + ACCEPT 세션은
nf_flowtable에 등록하여 이후 패킷의 Netfilter 훅 체인을 건너뜀 (여전히 CPU에서 실행, 단 경로 단축) - 패킷 송신: CPU가
ip_output()을 호출하여 NIC TX 큐에 패킷 전달
핵심 특성
| 항목 | 설명 |
|---|---|
| Fast Path 구현 | nf_flowtable SW 오프로드 (conntrack bypass만, CPU에서 실행) |
| Slow Path 구현 | 전체 Netfilter 훅 + NFQUEUE + DPI (모두 CPU) |
| Lookaside 대상 | 암호화(QAT/NITROX), 정규식(FPGA), 압축(IAA/QAT), AV 패턴 매칭 |
| 처리량 한계 | CPU 코어 수 × 코어당 처리량 (DPI 포함 시 코어당 1~5 Gbps) |
| CPS 한계 | CPU 기반 conntrack + DPI 초기 분류 (코어당 10K~100K CPS) |
| 대표 구현 | 리눅스 서버 + nftables + Suricata + QAT 카드, Check Point(CoreXL + SecureXL) |
CPU중심 Lookaside의 패킷 흐름
아래 다이어그램은 CPU중심 아키텍처에서 새 세션(Slow Path)과 확립된 세션(SW Fast Path)의 처리 흐름을 보여줍니다. Lookaside 가속기는 파이프라인의 특정 단계에서만 호출됩니다.
CPU중심 아키텍처의 성능 프로파일
| 시나리오 | 코어당 처리량 | 16코어 서버 예상 | 병목 원인 |
|---|---|---|---|
| L3/L4 ACL만 (FW 모드) | 10~20 Gbps | 100~200 Gbps | PPS, conntrack 해시 |
| flowtable SW Fast Path | 10~40 Gbps | 100~200 Gbps | 메모리 대역폭, 캐시 미스 |
| DPI + IPS 활성화 | 1~5 Gbps | 16~80 Gbps | DPI 시그니처 매칭 |
| SSL Inspection (CPU AES-NI) | 2~8 Gbps | 30~120 Gbps | RSA/ECDHE 핸드셰이크 |
| SSL Inspection (QAT 가속) | 5~15 Gbps | 80~200 Gbps | QAT PCIe 대역폭 |
CPU중심 아키텍처에서의 Crypto Offload
CPU중심 아키텍처의 가장 일반적인 Lookaside 대상은 암호화 연산입니다. SSL Inspection이 활성화된 NGFW에서 CPU의 60~80%가 TLS 핸드셰이크(RSA/ECDHE)와 레코드 암·복호화(AES-GCM)에 소비되므로, 이를 PCIe 가속기(QAT, NITROX)에 위임하면 CPU 코어를 DPI에 집중할 수 있습니다.
| Lookaside 대상 | 가속기 예시 | CPU 절감 효과 | 커널 API |
|---|---|---|---|
| TLS 핸드셰이크 (RSA/ECDHE) | Intel QAT 4xxx/8970, NITROX V | CPS 10x 향상 (5K→100K ops/s) | crypto_akcipher, crypto_kpp |
| 대칭키 벌크 암호화 (AES-GCM) | Intel QAT 4xxx/8970 | 코어당 2~8→100+ Gbps | crypto_aead |
| IPSec ESP (Crypto offload) | NIC (ConnectX, E810) | AES 연산만 NIC 위임 | xfrm_offload |
| 정규식 패턴 매칭 | Intel HyperScan FPGA, Marvell REE | DPI 시그니처 매칭 가속 | 벤더 API |
| 데이터 압축 | Intel IAA, QAT 압축 | 로그 압축, 패킷 캡처 압축 | crypto_comp |
CPU중심 아키텍처에서 QAT 가속기를 활용한 대표적인 NGFW crypto 파이프라인은 다음과 같습니다:
/* CPU중심 Lookaside NGFW crypto 파이프라인 */
[새 TLS 세션 - Slow Path]
패킷 수신 → conntrack NEW → nftables ACL ACCEPT
→ SSL MITM Proxy (nginx/haproxy)
→ TLS ClientHello 수신
→ QAT Lookaside: RSA-2048 서명 / ECDHE P-256 키 교환
→ CPU: -EINPROGRESS → 다른 패킷 처리 → QAT IRQ → 콜백
→ TLS 핸드셰이크 완료 → 대칭키 확보
→ setsockopt(SOL_TLS) → kTLS 활성화 (NIC inline 가능)
→ NFQUEUE → Suricata DPI (평문 검사)
→ Verdict ACCEPT → flowtable 등록
[확립된 TLS 세션 - Fast Path]
패킷 수신 → NIC Inline: kTLS 복호화 (AES-GCM)
→ flowtable bypass → NAT rewrite → NIC Inline: kTLS 재암호화 → TX
→ CPU 부하: 0%
SoC중심 룩어사이드 아키텍처
SoC중심 룩어사이드(SoC-Centric Lookaside) 아키텍처에서는 전용 네트워크 프로세서(NP) 또는 ASIC이 데이터 플레인의 Fast Path를 전담합니다. NP는 패킷 파싱, 세션 테이블 룩업, NAT rewrite, ACL 매칭, QoS 스케줄링을 하드웨어 파이프라인으로 와이어 속도에 가깝게 처리합니다. CPU는 컨트롤 플레인(정책 배포, 로깅, 관리)과 예외 패킷 처리(새 세션의 DPI, ALG, 정책 미매칭 패킷)만 담당합니다.
핵심 설계 원리는 "NP가 처리할 수 있는 패킷은 CPU에 전달하지 않습니다"입니다. 새 세션의 첫 패킷만 CPU로 올라가고(Slow Path), CPU가 보안 검사를 완료하면 세션 정보를 NP의 하드웨어 세션 테이블에 프로그래밍합니다. 이후 해당 세션의 모든 패킷은 NP에서 직접 처리됩니다.
동작 원리
- 패킷 수신: 물리 포트에서 패킷이 NP ASIC에 직접 도달 (호스트 메모리 DMA 없음)
- NP 파이프라인 실행: 패킷 파서 → 세션 테이블 TCAM/Hash 룩업 → 매칭 시 NAT rewrite + ACL + QoS + 포워딩을 하드웨어에서 처리 → 즉시 TX
- 세션 미스 → CPU 전달(Lookaside): 세션 테이블에 매칭되지 않는 패킷(새 세션, 예외)은 내부 버스를 통해 CPU로 전달
- CPU에서 Slow Path 처리: conntrack NEW, nftables ACL, DPI/IPS 검사 수행
- 세션 프로그래밍: CPU가 검사 결과(ACCEPT + 세션 정보)를 NP의 세션 테이블에 기록 → 이후 패킷은 NP에서 직접 처리
핵심 특성
| 항목 | 설명 |
|---|---|
| Fast Path 구현 | NP ASIC 하드웨어 세션 테이블 (TCAM/Hash 기반 와이어 속도 처리) |
| Slow Path 구현 | CPU에서 Netfilter + DPI (NP→CPU 내부 버스 전달) |
| Lookaside 방향 | NP→CPU (예외 패킷), CPU→NP (세션 프로그래밍) — CPU중심과 반대 방향 |
| 처리량 한계 | NP ASIC 설계에 의존 (100~800 Gbps), CPU는 CPS만 제한 |
| 세션 테이블 용량 | NP TCAM/SRAM 크기에 의존 (수백만~수천만 세션) |
| 대표 구현 | Fortinet(NP7 ASIC + CP9 + CPU), Juniper(Express Path NP + SPC3 + RE), Cisco(QFP) |
SoC중심 Lookaside의 패킷 흐름
상용 NGFW의 SoC중심 구현 사례
| 벤더 | NP/ASIC | Fast Path 처리량 | 세션 테이블 용량 | CPU 역할 | 특이사항 |
|---|---|---|---|---|---|
| Fortinet | NP7 (자체 ASIC) | 800 Gbps | 12M 세션 | DPI(CP9 보조), 관리 | SP5(암호화), CP9(콘텐츠 검사) 별도 ASIC 추가 — 기능별 전용 칩 |
| Juniper SRX | Express Path NP + SPC3 | 400 Gbps | 80M 세션 | flowd(DPI), RE(관리) | SPC3는 Lookaside 암호화 겸용, Express Path는 세션 오프로드 전용 |
| Cisco Firepower | QFP (QuantumFlow) | 200 Gbps | 30M 세션 | Snort DPI, 관리 | QFP는 프로그래머블 NP, microcode 업데이트로 제한적 기능 추가 가능 |
| Huawei USG | Hi1822 NP | 200 Gbps | 40M 세션 | DPI, SSL, 관리 | 서버용 SmartNIC으로도 판매, NP + ARM 코어 통합 SoC |
SoC중심 아키텍처에서의 Crypto Offload
SoC중심 아키텍처에서 암호화 처리는 두 가지 경로로 나뉩니다. NP ASIC 내장 크립토 엔진이 Fast Path에서 IPSec을 인라인 처리하고, SoC 내부의 별도 크립토 코프로세서(CAAM, OCTEON CPT, SP5 등)가 SSL/TLS 복호화를 Lookaside로 처리합니다.
| 벤더 | NP 인라인 크립토 | 별도 크립토 코프로세서 | CPU 크립토 역할 |
|---|---|---|---|
| Fortinet | NP7: IPSec AES-GCM 인라인 (800 Gbps) | SP5: SSL/TLS 핸드셰이크 + 레코드 가속 | CP9 보조: DPI 시 복호화된 평문 처리 |
| Marvell OCTEON | CN10K NP: IPSec 인라인 (100 Gbps) | CPT 코어: TLS/SSL 룩어사이드 (100 Gbps 대칭키) | ARM 코어: DPI, 관리, 예외 |
| NXP Layerscape | DPAA2 SEC: IPSec 인라인 (10~40 Gbps) | CAAM: Job Ring 기반 비동기 (10~20 Gbps) | Cortex-A72: DPI, SSL 프록시 |
| Juniper | Express Path NP: 세션 오프로드 | SPC3: SSL/IPSec Lookaside 카드 | RE/flowd: DPI, 관리 |
SoC중심 아키텍처의 핵심 장점은 NP와 크립토 엔진이 동일 SoC 다이 내에 있어 내부 버스(AXI/AMBA)로 직접 통신하는 점입니다. PCIe를 거치지 않으므로 Lookaside 지연이 1~5μs로, CPU중심 아키텍처의 QAT(10~50μs) 대비 5~10배 빠릅니다. 이에 대한 상세 분석은 SoC중심 룩어사이드(암호화) 절을 참조하세요.
인라인(Inline) 오프로드 아키텍처
인라인(Inline) 아키텍처에서는 SmartNIC/DPU가 네트워크 데이터 경로 자체에 위치하여 패킷이 호스트 CPU를 거치지 않고 NIC 하드웨어에서 직접 처리됩니다. SoC중심 아키텍처의 NP와 유사하지만, 핵심 차이점은 표준 Linux 커널 인터페이스(TC flower, eSwitch, flowtable HW offload)를 통해 오프로드 규칙을 프로그래밍하는 점입니다. 벤더 전용 API가 아닌 오픈 표준을 사용하므로 리눅스 기반 NGFW에서 가장 주목받는 아키텍처입니다.
인라인 아키텍처의 근본적인 설계 원리는 "확립된 세션의 패킷이 호스트 메모리를 전혀 건드리지 않습니다"입니다. NIC의 eSwitch FDB에 설치된 TC flower 규칙이 5-tuple + conntrack 상태로 매칭하여, NAT rewrite, 터널 encap/decap, VLAN 처리를 NIC ASIC에서 직접 수행한 뒤 대상 포트로 전달합니다.
동작 원리
- 패킷 수신: 이더넷 프레임이 NIC의 물리 포트에 도착
- eSwitch FDB 룩업: NIC 내장 eSwitch가 FDB 테이블에서 5-tuple + ct_state 매칭 → HW 규칙 히트(Hit) 시 즉시 처리
- HW Fast Path 처리: NAT rewrite, TTL 감소, 터널 encap/decap, VLAN push/pop을 NIC ASIC에서 실행 → 대상 포트 TX 큐로 직접 전달 (DMA-to-DMA, CPU 인터럽트 없음)
- FDB 미스 → 호스트 CPU: 매칭되지 않는 패킷은 일반 NIC RX 큐를 통해 호스트 CPU로 DMA 전달 → Slow Path(Netfilter + DPI) 처리
- 오프로드 설치: CPU에서 세션이 ESTABLISHED + ACCEPT로 확인되면
nf_flowtable이 TC flower 규칙을 생성하고ndo_setup_tc()를 통해 NIC 드라이버에 전달 → eSwitch FDB에 HW 규칙 설치
핵심 특성
| 항목 | 설명 |
|---|---|
| Fast Path 구현 | eSwitch FDB + TC flower HW offload (NIC ASIC에서 와이어 속도 처리) |
| Slow Path 구현 | 호스트 CPU에서 Netfilter + DPI (FDB 미스 시에만 진입) |
| 프로그래밍 인터페이스 | 표준 Linux: TC flower, ndo_setup_tc(), nf_flowtable HW offload |
| 처리량 한계 | NIC 라인레이트 (25/50/100/200/400 Gbps) |
| FDB 규칙 용량 | NIC TCAM/EM 크기에 의존 (수만~수백만 엔트리) |
| 대표 구현 | NVIDIA ConnectX + BlueField DPU, Intel E810, AMD Pensando DSC, nftables + flowtable HW offload |
인라인 오프로드의 패킷 흐름
인라인 아키텍처의 Linux 커널 연동
인라인 아키텍처의 핵심 장점은 표준 Linux 커널 API를 통한 HW 오프로드입니다. NGFW 관리자는 일반적인 nftables/TC 명령으로 정책을 설정하면, 커널이 자동으로 NIC 하드웨어에 규칙을 설치합니다.
# 1. nftables에서 flowtable HW offload 정의
nft add table inet filter
nft add flowtable inet filter ft {
hook ingress priority 0 \;
devices = { enp1s0f0np0, enp1s0f1np0 } \;
flags offload \; # ← HW offload 핵심 플래그
}
# 2. ESTABLISHED 세션을 flowtable으로 전달
nft add chain inet filter forward { type filter hook forward priority 0 \; }
nft add rule inet filter forward ct state established,related flow add @ft
# 3. 커널이 자동으로 TC flower 규칙 생성 → NIC eSwitch FDB에 설치
# 확인: HW offload 규칙 조회
tc -s filter show dev enp1s0f0np0 ingress
# filter protocol ip pref 1 flower chain 0
# ct_state +est+trk ← HW에서 conntrack 상태 매칭
# action mirred (Egress Redirect to device enp1s0f1np0)
# in_hw in_hw_count 1 ← HW offload 확인
인라인 아키텍처에서의 Crypto Offload
인라인 아키텍처에서 SmartNIC/DPU는 세션 오프로드(flowtable)뿐 아니라 암호화도 인라인으로 처리합니다. 패킷이 NIC ASIC을 통과하는 과정에서 암·복호화가 와이어 속도로 수행되므로, 호스트 메모리에 암호화된 데이터가 전혀 도달하지 않습니다.
| 인라인 Crypto 기술 | NIC 요구 | 프로토콜 | 처리량 | 커널 설정 |
|---|---|---|---|---|
| IPSec Packet offload | ConnectX-6 Dx+, E810 | ESP (AES-128/256-GCM) | NIC 라인레이트 | ip xfrm state ... offload dev eth0 dir out |
| IPSec Full offload | ConnectX-7 + eSwitch | ESP (AES-GCM) + 포워딩 | NIC 라인레이트 | eSwitch switchdev + TC flower + xfrm offload |
| kTLS TX/RX offload | ConnectX-6 Dx+, E810 | TLS 1.2/1.3 (AES-GCM) | NIC 라인레이트 | ethtool -K eth0 tls-hw-tx-offload on |
| MACsec offload | ConnectX-6 Dx+, Microchip VSC | 802.1AE (AES-128/256-GCM) | NIC 라인레이트 | ip link add ... type macsec offload mac |
인라인 crypto의 핵심 제약은 AES-GCM 외 알고리즘 미지원과 SA/TLS context 수 제한(NIC 메모리 의존)입니다. 이 제약을 초과하는 세션은 자동으로 SW 폴백됩니다. 상세 알고리즘 매트릭스는 아키텍처별 알고리즘 지원 매트릭스를, NIC 벤더별 지원 현황은 전용 크립토 가속기 절을 참조하세요.
3대 아키텍처 종합 비교
아래 표는 세 아키텍처를 전체 NGFW 파이프라인 관점에서 비교합니다. 암호화에 특화된 비교는 암호화 오프로드 3종 비교를 참조하세요.
| 항목 | CPU중심 룩어사이드 | SoC중심 룩어사이드 | 인라인 (SmartNIC/DPU) |
|---|---|---|---|
| Fast Path 주체 | CPU (nf_flowtable SW) | NP ASIC (HW 세션 테이블) | SmartNIC eSwitch (TC flower HW) |
| Slow Path 주체 | CPU (Netfilter + DPI) | CPU (NP→CPU 전달 후 처리) | 호스트 CPU (NIC→DMA 후 처리) |
| Fast Path 처리량 | 코어 수 × 10~40 Gbps | 100~800 Gbps (ASIC 설계) | NIC 라인레이트 (100~400 Gbps) |
| Fast Path 지연 | 50~200μs (SW 경로) | <5μs (NP 파이프라인) | <5μs (eSwitch 파이프라인) |
| Slow Path 처리량 | 코어 수 × 1~5 Gbps (DPI) | CPU 코어 수 의존 | 호스트 CPU 코어 수 의존 |
| CPS (새 연결/초) | 코어 수 × 10K~100K | CPU 코어 수 의존 | 호스트 CPU 코어 수 의존 |
| 동시 세션 (CC) | 호스트 메모리 의존 | NP TCAM/SRAM (수천만) | NIC EM/TCAM (수만~수백만) |
| 프로그래밍 인터페이스 | nftables, Netfilter API | 벤더 전용 API/CLI | TC flower, nf_flowtable, switchdev |
| 새 프로토콜 지원 | SW 업데이트 즉시 가능 | NP FW/ASIC 세대 교체 필요 | NIC FW 업데이트 (제한적) |
| 벤더 종속성 | 낮음 (범용 서버) | 높음 (자체 ASIC 어플라이언스) | 중간 (표준 API, NIC 선택 가능) |
| 초기 비용 | 낮음 (서버 + SW) | 높음 (전용 어플라이언스) | 중간 (서버 + SmartNIC) |
| 대표 구현 | 리눅스 서버 + Suricata + QAT Check Point (CoreXL) | Fortinet (NP7 + SP5) Juniper SRX (SPC3) Cisco (QFP) | NVIDIA BlueField DPU Intel E810 AMD Pensando DSC |
아키텍처 선택 가이드
| 요구사항 | 추천 아키텍처 | 이유 |
|---|---|---|
| DPI/IPS 시그니처를 주 1회 이상 업데이트 | CPU중심 | SW 업데이트만으로 즉시 적용, HW 제약 없음 |
| Fast Path 100Gbps+ 필수, DPI는 선택적 | SoC중심 | NP ASIC이 와이어 속도 보장 |
| 리눅스 오픈소스 NGFW + HW 가속 | 인라인 | TC flower/nf_flowtable으로 표준 오프로드 |
| 클라우드/VM 기반 가상 NGFW | CPU중심 | 범용 서버에서 SW만으로 구동 |
| 데이터센터 마이크로세그멘테이션 | 인라인 | SmartNIC이 각 서버 앞단에서 NGFW 실행 |
| ISP/통신사 엣지(Edge) 보안 | SoC중심 | 수천만 세션 + 라인레이트 필수 |
| SSL Inspection이 전체 트래픽의 80%+ | CPU중심 + QAT | Lookaside 암호화 가속기로 핸드셰이크 처리 |
| 호스트 CPU를 NGFW에 0% 할당 | 인라인 (DPU) | BlueField DPU가 독립적으로 NGFW 실행 |
데이터 플레인 아키텍처
Fast Path (HW + SW)
Fast Path는 이미 보안 검사가 완료된 세션의 후속 패킷을 최소 비용으로 전달하는 경로입니다. 두 가지 수준이 있습니다:
HW Fast Path (eSwitch FDB)
eSwitch의 switchdev 모드에서 TC flower 규칙으로 ct_state +est +trk 매칭 후 FDB(Forwarding Database) 룰을 NIC 하드웨어에 설치합니다. 패킷이 NIC에 도착하면 CPU를 거치지 않고 직접 전달됩니다.
HW Fast Path의 동작을 단계별로 보면:
- 패킷 도착: 이더넷 프레임이 NIC의 RX 큐에 도달
- eSwitch FDB lookup: NIC 내장 하드웨어가 5-tuple + ct_state로 FDB 테이블을 검색
- 매칭 시 HW 처리: NAT rewrite (IP/Port/Checksum), TTL 감소, 터널 encap/decap, VLAN push/pop
- 직접 TX: 처리된 패킷이 대상 포트의 TX 큐로 직접 전달 (DMA to DMA, CPU interrupt 없음)
- 수행: L2/L3/L4 헤더 매칭, NAT rewrite (SNAT/DNAT), VLAN push/pop, 터널 encap/decap (VXLAN/GRE/Geneve), conntrack 상태 확인
- 미수행: DPI 재검사, TCP window 검증, 시퀀스 번호 추적, ALG 프로토콜 파싱, IP 단편화(Fragmentation) 처리
- 처리량: NIC 라인레이트 (25/50/100/200Gbps)
SW Fast Path (nf_flowtable)
nf_flowtable은 커널 소프트웨어에서 conntrack을 bypass하고 직접 L3 forwarding을 수행합니다. HW offload가 불가능한 경우(예: NIC 미지원, 복잡한 NAT, 특정 터널)의 폴백 경로입니다.
SW Fast Path는 커널의 Netfilter ingress 훅(priority -10)에서 동작하여, 일반 Netfilter 체인(PREROUTING → FORWARD → POSTROUTING)을 완전히 건너뜁니다. 이를 통해 nftables 규칙 평가, conntrack 상세 추적, NFQUEUE 전달 등의 오버헤드를 제거합니다.
- 수행: conntrack bypass, L3 forwarding, NAT rewrite, TTL 감소, 통계 카운터
- 미수행: Netfilter 훅 체인, DPI, TCP 상태 머신 상세 추적
- 처리량: 코어당 약 10~40Gbps (패킷 크기 의존)
Fast Path 전환의 커널 내부 흐름
패킷이 Fast Path로 처리되는 과정을 커널 코드 수준에서 살펴보면:
/* net/netfilter/nf_flow_table_ip.c */
/* flowtable ingress 훅에서 호출되는 핵심 함수 */
static unsigned int
nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
struct flow_offload_tuple_rhash *tuplehash;
struct nf_flowtable *flow_table = priv;
struct flow_offload_tuple tuple = {};
enum flow_offload_tuple_dir dir;
struct flow_offload *flow;
/* 1. skb에서 5-tuple 추출 */
if (nf_flow_tuple_ip(skb, state->in, &tuple) < 0)
return NF_ACCEPT; /* 추출 실패 → Slow Path */
/* 2. flowtable에서 lookup */
tuplehash = flow_offload_lookup(flow_table, &tuple);
if (!tuplehash)
return NF_ACCEPT; /* 미등록 플로우 → Slow Path */
flow = container_of(tuplehash, struct flow_offload,
tuplehash[dir]);
/* 3. TEARDOWN 상태면 Slow Path로 복귀 */
if (flow_offload_stale_flow(flow))
return NF_ACCEPT;
/* 4. NAT rewrite 적용 */
if (flow->flags & FLOW_OFFLOAD_SNAT)
nf_flow_snat_ip(skb, thoff, ...);
if (flow->flags & FLOW_OFFLOAD_DNAT)
nf_flow_dnat_ip(skb, thoff, ...);
/* 5. TTL 감소 + routing 적용 */
ip_decrease_ttl(iph);
skb_dst_set_noref(skb, &rt->dst);
/* 6. 직접 전달 (Netfilter 훅 체인 건너뜀) */
ip_output(state->net, state->sk, skb);
return NF_STOLEN; /* skb 소유권 가져감 → 훅 종료 */
}
코드 설명
-
8-10행
flow_offload_tuple은 5-tuple(src IP, dst IP, src port, dst port, protocol)을 담는 구조체(Struct)입니다. flowtable의 해시(Hash) 키로 사용됩니다. - 13-14행 skb에서 IP/TCP/UDP 헤더를 파싱하여 5-tuple을 추출합니다. 실패하면 일반 Netfilter 경로로 진행합니다.
-
17-18행
flow_offload_lookup()은 rhashtable 기반 해시 테이블(Hash Table)에서 O(1) 조회합니다. 미스 시 NF_ACCEPT로 Slow Path 진입합니다. - 24-25행 TEARDOWN 플래그가 설정된 플로우(TCP FIN/RST 수신)는 GC 대기 중이므로 Slow Path로 보내 정상 종료를 처리합니다.
- 28-31행 NAT 오프로드: SNAT/DNAT 플래그에 따라 IP/포트를 직접 rewrite합니다. conntrack을 거치지 않으므로 매우 빠릅니다.
- 34행 라우터 기능: TTL을 1 감소시킵니다. TTL=0이면 ICMP Time Exceeded를 생성하고 패킷을 DROP합니다.
-
37-38행
NF_STOLEN을 반환하면 Netfilter가 이 패킷의 소유권을 flowtable에 넘깁니다. 이후 FORWARD/POSTROUTING 훅이 호출되지 않습니다.
flow_offload 구조체
/* include/net/netfilter/nf_flow_table.h */
struct flow_offload_tuple {
union {
struct in_addr src_v4; /* IPv4 소스 주소 */
struct in6_addr src_v6; /* IPv6 소스 주소 */
};
union {
struct in_addr dst_v4;
struct in6_addr dst_v6;
};
struct {
__be16 src; /* 소스 포트 */
__be16 dst; /* 목적지 포트 */
} port;
u8 l3proto; /* AF_INET / AF_INET6 */
u8 l4proto; /* IPPROTO_TCP / IPPROTO_UDP */
struct dst_entry *dst_cache; /* 라우팅 캐시 */
int iifidx; /* ingress 인터페이스 인덱스 */
int oifidx; /* egress 인터페이스 인덱스 */
};
struct flow_offload {
struct flow_offload_tuple_rhash tuplehash[2]; /* [ORIGINAL] + [REPLY] */
struct nf_conn *ct; /* 대응하는 conntrack 엔트리 */
unsigned long flags; /* SNAT, DNAT, TEARDOWN 등 */
u32 timeout; /* GC 타임아웃 (jiffies) */
};
하나의 flow_offload는 양방향 플로우를 나타냅니다. tuplehash[0]은 ORIGINAL 방향, tuplehash[1]은 REPLY 방향의 5-tuple을 저장합니다. NAT가 적용된 경우 두 방향의 IP/포트가 다릅니다.
Slow Path (전체 검사)
새로운 연결의 첫 패킷(또는 아직 DPI 분류가 완료되지 않은 초기 패킷)은 전체 보안 파이프라인을 통과합니다. Slow Path는 NGFW의 보안 정밀도를 담당하며, 여기서의 결정이 세션의 나머지 수명 동안의 처리 방식을 결정합니다.
Slow Path에서의 패킷 처리 시간은 일반적으로 100us~5ms 범위입니다. DPI 엔진의 시그니처 수, 패킷 페이로드 크기, CPU 캐시(Cache) 히트율에 따라 달라집니다.
처리 순서:
- Ingress ACL — nftables/TC filter 기반 정적 규칙 (IP/Port/Protocol 매칭)
- conntrack — 연결 추적 테이블에 NEW 엔트리 생성 또는 기존 상태 갱신
- NAT — SNAT/DNAT/MASQUERADE 주소 변환(Address Translation)
- NFQUEUE — DPI 엔진으로 패킷 전달 (NFQUEUE & DPI 엔진 통합)
- DPI / App-ID — 프로토콜 분류, 시그니처 매칭, 애플리케이션 식별
- IPS — 시그니처 기반 공격 탐지
- Verdict — ACCEPT/DROP/QUEUE 최종 판정
CPS 병목: Slow Path의 처리량은 주로 초당 새 연결(CPS)으로 측정됩니다. DPI 엔진에 따라 코어당 10K~100K CPS 범위이며, 이는 NGFW의 실질적 성능 한계를 결정합니다.
Slow Path 커널 호출 체인
/* Slow Path에서 새 패킷이 거치는 커널 함수 호출 순서 */
/* 1. PREROUTING: conntrack 입구 */
nf_conntrack_in()
→ resolve_normal_ct()
→ nf_conntrack_find_get() /* 해시 테이블에서 기존 ct 검색 */
→ init_conntrack() /* 미발견 시 NEW ct 생성 */
→ __nf_conntrack_alloc() /* slab에서 nf_conn 할당 */
→ nf_ct_helper_find() /* ALG 헬퍼 자동 할당 (SIP/FTP 등) */
/* 2. FORWARD: nftables 체인 평가 */
nft_do_chain()
→ nft_lookup_eval() /* set/map 기반 ACL 매칭 */
→ nft_ct_eval() /* ct state 조건 평가 */
→ nft_queue_eval() /* NFQUEUE verdict → DPI 전달 */
/* 3. NFQUEUE: 유저스페이스 DPI 전달 */
nf_queue()
→ nf_queue_entry_get_refs() /* 참조 카운터 증가 */
→ nfnetlink_queue_enqueue() /* netlink 소켓으로 전달 */
/* ... Suricata/nDPI가 패킷을 분석 ... */
→ nf_reinject() /* verdict 반환 후 재주입 */
/* 4. POSTROUTING: NAT 적용 */
nf_nat_ipv4_out()
→ nf_nat_packet()
→ nf_nat_manip_pkt() /* SNAT/DNAT 주소 변환 */
/* 5. 전송 */
ip_output()
→ ip_finish_output()
→ neigh_output() /* L2 헤더 추가 후 NIC TX */
CPS 병목 분석
NGFW에서 Slow Path의 CPS가 전체 성능을 제한하는 원인을 세분화하면:
| 단계 | CPU 비용 (cycles/pkt) | 병목 원인 | 최적화 방법 |
|---|---|---|---|
| conntrack alloc | ~500 | slab 할당 + 해시 삽입 | conntrack_buckets 증가, NUMA 로컬 할당 |
| nftables 평가 | ~200 | 규칙 수에 비례 | set/map 기반 매칭 (O(1) lookup) |
| NFQUEUE 전달 | ~1000 | netlink 소켓(Socket), 컨텍스트 스위치 | NFQUEUE batch mode, fanout 분산 |
| DPI 분석 | ~5000~50000 | 패턴 매칭, SSL 파싱 | 멀티코어 분산, 시그니처 최적화 |
| verdict 반환 | ~500 | 재주입 + 훅 체인 재개 | BPF verdict 캐시 |
| NAT | ~300 | conntrack NAT tuple 확인 | 1:1 NAT 단순화 |
DPI가 전체 Slow Path 비용의 70~90%를 차지합니다. 따라서 DPI 완료 후 세션을 즉시 Fast Path로 전환하는 것이 핵심 최적화입니다.
Exception Path
이미 오프로드된 세션이라도 다음 경우에는 Fast Path에서 CPU로 복귀합니다:
- ALG 프로토콜 — FTP DATA, SIP RTP, H.323 등 동적 포트 할당이 필요한 프로토콜 (conntrack 헬퍼 & ALG)
- IP Fragment — 단편화된 패킷은 재조립 후 검사 필요
- ICMP Error — Destination Unreachable, TTL Exceeded 등 원래 세션의 상태 갱신 필요
- 정책 변경 재분류 — 관리자가 정책을 변경하면 기존 오프로드 플로우를 삭제하고 재평가
- TCP RST/FIN — 연결 종료 → flowtable GC → HW rule 삭제
- 바이트/패킷 임계치 — 보안 정책에 따라 주기적 샘플링을 위해 복귀
Exception Path 처리의 커널 내부
Exception Path의 핵심은 flow_offload_stale_flow() 검사와 HW trap 메커니즘입니다:
/* net/netfilter/nf_flow_table_core.c */
static bool flow_offload_stale_flow(struct flow_offload *flow)
{
/* TEARDOWN 플래그: TCP FIN/RST 수신 시 설정 */
if (flow->flags & FLOW_OFFLOAD_TEARDOWN)
return true;
/* DYING 플래그: GC에 의해 만료 대기 중 */
if (flow->flags & FLOW_OFFLOAD_DYING)
return true;
/* conntrack이 삭제된 경우 */
if (!nf_ct_is_confirmed(flow->ct))
return true;
return false;
}
/* GC 워커: 주기적으로 만료된 플로우 정리 */
static void nf_flow_offload_gc_step(struct nf_flowtable *flow_table)
{
struct flow_offload_tuple_rhash *tuplehash;
struct rhashtable_iter hti;
rhashtable_walk_enter(&flow_table->rhashtable, &hti);
rhashtable_walk_start(&hti);
while ((tuplehash = rhashtable_walk_next(&hti))) {
struct flow_offload *flow = ...;
if (nf_flow_has_expired(flow) ||
nf_ct_is_dying(flow->ct)) {
/* HW rule 삭제 → 카운터 동기화 → ct 삭제 */
flow_offload_teardown(flow);
nf_flow_offload_del(flow_table, flow);
}
}
}
ALG 프로토콜의 Exception 처리
FTP, SIP, H.323 등 ALG(Application Level Gateway) 프로토콜은 제어 채널에서 동적으로 데이터 채널 포트를 협상합니다. 이 과정에서 conntrack helper가 페이로드를 파싱해야 하므로 오프로드가 불가능합니다.
| ALG 프로토콜 | Helper 모듈 | 동적 포트 | 오프로드 불가 이유 |
|---|---|---|---|
| FTP | nf_conntrack_ftp | PORT/PASV 명령으로 데이터 포트 협상 | 제어 채널 파싱 + RELATED 세션 생성 |
| SIP | nf_conntrack_sip | SDP에서 RTP 포트 협상 | SDP 메시지 파싱 + NAT 주소 치환 |
| H.323 | nf_conntrack_h323 | H.245에서 미디어 포트 협상 | ASN.1 디코딩 + NAT traversal |
| TFTP | nf_conntrack_tftp | 서버가 임의 포트에서 응답 | RELATED expectation 추적 |
| PPTP | nf_conntrack_pptp | GRE 터널 세션 생성 | GRE call ID 추적 + NAT |
| 기능 | HW Fast Path | SW Fast Path | Slow Path | Exception Path |
|---|---|---|---|---|
| L3/L4 ACL | HW 매칭 | bypass | nftables chain | nftables chain |
| conntrack 상태 | HW ct_state | bypass (aging) | 전체 추적 | 전체 추적 |
| NAT rewrite | HW rewrite | SW rewrite | nf_nat | nf_nat |
| DPI / App-ID | 미수행 | 미수행 | NFQUEUE → DPI | 재분류 가능 |
| IPS 시그니처 | 미수행 | 미수행 | 인라인 검사 | 재검사 |
| TCP 윈도우 검증 | 미수행 | 미수행 | conntrack 수행 | conntrack 수행 |
| 터널 encap/decap | VXLAN/GRE/Geneve | 제한적 | 전체 지원 | 전체 지원 |
| TTL/Hop Limit | HW 감소 | SW 감소 | SW 감소 | SW 감소 |
| 통계/카운터 | HW counter | SW counter | per-chain counter | per-chain counter |
| 처리량 (100G NIC) | 100Gbps | 10~40Gbps | 1~10Gbps | 개별 처리 |
NIC-Level 오프로드와 NGFW 파이프라인 상호작용
NIC 하드웨어에는 RSS, GRO, TSO, checksum offload 등 다양한 NIC-Level 오프로드 기능이 내장되어 있습니다. 이 기능들은 일반 네트워크 스택에서는 성능을 극대화하지만, NGFW 파이프라인과 결합하면 세션 친화성 깨짐, DPI 시그니처 미탐지, 바이트 카운터 불일치 등의 부작용을 일으킬 수 있습니다. 이 섹션에서는 각 NIC 오프로드 기능이 NGFW 파이프라인의 어느 단계와 상호작용하는지 분석하고, 최적 설정 방법을 제시합니다.
NIC 오프로드 기능과 NGFW 파이프라인 매핑
아래 표는 주요 NIC 오프로드 기능이 NGFW 파이프라인의 어떤 단계에 영향을 미치는지 정리한 것입니다. 영향의 성격은 긍정적(+), 부정적(-), 조건부(±)로 구분합니다.
| NIC 오프로드 | 동작 위치 | 영향받는 NGFW 단계 | 영향 | 설명 |
|---|---|---|---|---|
| RSS (Receive Side Scaling) | RX 큐 분배 | conntrack, DPI | ± | 해시 불일치 시 동일 세션이 다른 CPU로 분산되어 conntrack race 발생 가능 |
| aRFS (Accelerated RFS) | RX 큐 스티어링 | DPI 워커, conntrack | + | 소켓/스레드가 실행 중인 CPU로 패킷을 유도하여 캐시 히트율 향상 |
| Flow Director | RX 큐 스티어링 | Exception Path | + | 특정 플로우를 지정 큐로 고정하여 예외 경로 패킷의 처리 지연 감소 |
| GRO (Generic Receive Offload) | RX 병합 | DPI 시그니처 매칭 | ± | 병합된 슈퍼 세그먼트에서 패킷 경계가 사라져 per-packet 시그니처 오탐 가능 |
| LRO (Large Receive Offload) | RX 병합 (HW) | flowtable, conntrack | - | nf_flowtable과 호환되지 않으며, conntrack 시퀀스(Sequence) 추적 정확도 저하 |
| GSO (Generic Segmentation Offload) | TX 분할 | TC flower actions | ± | TC flower 액션 후 재분할이 필요하여 eSwitch 오프로드 복잡도 증가 |
| TSO (TCP Segmentation Offload) | TX 분할 (HW) | TC flower 카운터 | - | 슈퍼 세그먼트(Super Segment)가 단일 패킷으로 카운트되어 바이트 통계 왜곡 |
| TX/RX Checksum | 체크섬 계산 | NAT rewrite | + | NAT 변환 후 체크섬 재계산을 HW에 위임하여 CPU 부하 절감 |
RSS/aRFS/Flow Director와 NGFW 세션 친화성
NGFW에서 세션 친화성(Session Affinity)은 동일 세션의 모든 패킷이 동일 CPU 코어에서 처리되는 것을 의미합니다. 이것이 깨지면 conntrack 엔트리의 lock contention이 증가하고, DPI 엔진이 세션 상태를 공유해야 하므로 성능이 급격히 저하됩니다.
RSS 해시와 conntrack zone 정렬
RSS는 NIC 하드웨어가 수신 패킷의 L3/L4 헤더를 해시(Hash)하여 여러 RX 큐에 분배하는 기능입니다. 문제는 RSS 해시 함수가 conntrack의 양방향 세션 매핑을 인식하지 못합니다는 점입니다.
예시: TCP 연결 (10.1.1.1:5000 → 192.168.1.1:80)
순방향 RSS 해시: hash(10.1.1.1, 192.168.1.1, 5000, 80) = 큐 3 → CPU 3
역방향 RSS 해시: hash(192.168.1.1, 10.1.1.1, 80, 5000) = 큐 7 → CPU 7
결과: 동일 세션의 양방향 패킷이 서로 다른 CPU에서 처리됨
→ conntrack spinlock contention 발생
→ DPI 워커가 세션 상태를 cross-CPU로 참조해야 함
이 문제를 해결하려면 RSS 해시 키를 대칭 해시(Symmetric Hash)로 설정하여 양방향 패킷이 같은 큐로 분배되도록 해야 합니다.
# RSS 해시 키 확인
ethtool -x eth0
# 대칭(Symmetric) RSS 해시 설정 (Toeplitz 키를 대칭으로 변경)
# 드라이버에 따라 지원 여부가 다름 (mlx5, i40e 등 지원)
ethtool -X eth0 hfunc toeplitz
# RSS 해시 필드 설정: L3+L4 (src/dst IP + src/dst port)
ethtool -N eth0 rx-flow-hash tcp4 sdfn
ethtool -N eth0 rx-flow-hash udp4 sdfn
# 대칭 해시 지원 확인 (mlx5 드라이버)
ethtool --show-priv-flags eth0 | grep symmetric
# symmetric_rss가 있으면:
ethtool --set-priv-flags eth0 symmetric_rss on
aRFS: DPI 워커 CPU로 패킷 유도
aRFS(Accelerated Receive Flow Steering)는 커널이 소켓이 처리되는 CPU를 NIC에 알려주어, 해당 소켓의 패킷을 그 CPU의 RX 큐로 직접 유도하는 기능입니다. NGFW에서 NFQUEUE를 통해 DPI 엔진(Suricata, nDPI 등)이 특정 CPU에서 워커 스레드를 실행하고 있을 때, aRFS를 활용하면 해당 패킷이 DPI 워커가 실행 중인 CPU로 직접 전달됩니다.
# aRFS 활성화
echo 32768 > /proc/sys/net/core/rps_sock_flow_entries
# 각 RX 큐의 flow table 크기 설정
for rxq in /sys/class/net/eth0/queues/rx-*/rps_flow_cnt; do
echo 4096 > "$rxq"
done
# ntuple 필터 활성화 (aRFS가 NIC에 룰을 설치하기 위해 필요)
ethtool -K eth0 ntuple on
# aRFS 동작 확인
cat /proc/net/softnet_stat
# 열 9: flow_limit_count, 열 10: rps_count
aRFS는 NFQUEUE 기반 DPI 파이프라인에서 특히 효과적입니다. DPI 워커가 nfq_set_queue_maxlen()으로 큐를 바인딩한 CPU와 패킷이 도착하는 CPU가 일치하면, cross-CPU IPI(Inter-Processor Interrupt) 없이 패킷이 DPI 워커로 전달됩니다.
Flow Director: Exception Path 전용 큐
Flow Director는 NIC 하드웨어가 특정 플로우 패턴(Flow Pattern)을 매칭하여 지정된 RX 큐로 스티어링(Steering)하는 기능입니다. NGFW에서는 Exception Path 트래픽(TCP RST, ICMP error, ALG 프로토콜)을 전용 큐로 분리하여 Fast Path 트래픽과의 간섭을 방지하는 데 활용합니다.
# Flow Director: TCP RST 패킷을 큐 0(Exception 전용)으로 스티어링
ethtool -N eth0 flow-type tcp4 action 0 loc 100
# ICMP error를 Exception 큐로
ethtool -N eth0 flow-type ip4 proto 1 action 0 loc 101
# FTP 제어 채널(포트 21)을 ALG 전용 큐로
ethtool -N eth0 flow-type tcp4 dst-port 21 action 1 loc 102
# SIP 시그널링(포트 5060)을 ALG 전용 큐로
ethtool -N eth0 flow-type udp4 dst-port 5060 action 1 loc 103
# 설치된 Flow Director 규칙 확인
ethtool -n eth0
GRO/GSO/LRO와 DPI 검사
패킷 병합(Coalescing) 오프로드는 인터럽트(Interrupt) 빈도를 줄이고 처리량을 높이는 데 효과적이지만, DPI 엔진의 패킷 경계 인식에 중대한 영향을 미칩니다.
GRO와 DPI 시그니처 매칭
GRO(Generic Receive Offload)는 연속된 TCP 세그먼트(Segment)를 하나의 큰 sk_buff로 병합하는 소프트웨어 오프로드입니다. GRO가 활성화되면 하나의 sk_buff에 최대 64KB의 페이로드가 담기며, 이는 DPI 엔진에 다음과 같은 영향을 줍니다:
- Suricata MPM(Multi-Pattern Matcher) — GRO 병합된 버퍼에서 시그니처 매칭 시 패턴이 두 원래 패킷의 경계에 걸쳐 있으면 정상적으로 탐지됩니다(오히려 유리). 그러나 per-packet 카운터 기반 시그니처(예: "3번째 패킷의 offset 0에서 매칭")는 오동작합니다.
- nDPI 프로토콜 탐지 — 프로토콜 핸드셰이크(Handshake)의 첫 몇 패킷을 개별적으로 분석해야 하는 경우, GRO로 병합되면 핸드셰이크 패턴 인식이 실패할 수 있습니다.
- IPS bypass 공격 — 공격자가 의도적으로 작은 세그먼트(Segment)를 전송하여 시그니처를 분산시키는 evasion 기법에 대해, GRO는 세그먼트를 재조합하므로 오히려 방어에 유리합니다.
/* net/core/dev.c - GRO 수신 경로 */
static int napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
{
/* GRO 레이어가 동일 플로우의 skb를 병합 시도 */
skb_gro_reset_offset(skb);
/* ...
* 병합 성공 시: skb->len이 원래 MSS의 배수로 증가
* → NFQUEUE로 전달 시 단일 대형 skb로 전달됨
* → DPI 엔진은 이를 단일 "논리 패킷"으로 처리
*/
return napi_gro_complete(napi, skb);
}
LRO와 flowtable 비호환성
LRO(Large Receive Offload)는 GRO와 유사하지만 NIC 하드웨어에서 TCP 세그먼트를 병합합니다. LRO의 핵심 문제는 TCP 헤더를 재작성하는 것입니다. LRO는 병합된 슈퍼 세그먼트에 대해 새로운 시퀀스 번호와 ACK 번호를 생성하는데, 이는 다음 문제를 일으킵니다:
- nf_flowtable 시퀀스 추적 실패 — flowtable은 conntrack의 TCP 시퀀스 윈도우 추적에 의존합니다. LRO가 시퀀스 번호를 변조하면 윈도우 검증이 실패하여 세션이 오프로드에서 제외됩니다.
- conntrack TCP strict 모드 충돌 —
nf_conntrack_tcp_be_liberal=0(기본값)에서 LRO의 시퀀스 변조는 INVALID 상태를 유발합니다. - 포워딩(Forwarding) 경로 문제 — LRO는 로컬 수신(Local Receive) 전용으로 설계되었으며, 포워딩 경로에서 사용하면 원래 패킷 구조를 복원할 수 없습니다.
# flowtable 사용 시 LRO 반드시 비활성화
ethtool -K eth0 lro off
# 확인
ethtool -k eth0 | grep large-receive-offload
# large-receive-offload: off
/* net/netfilter/nf_flow_table_core.c */
static bool nf_flow_offload_check(struct nf_flowtable *flowtable,
struct flow_offload *flow)
{
/*
* LRO가 활성화된 인터페이스에서는 TCP 시퀀스 추적이
* 불안정하므로 flowtable 오프로드가 실패할 수 있음.
* 커널은 dev->features에서 NETIF_F_LRO 플래그를 확인하고
* 포워딩 경로에서 자동으로 LRO를 비활성화함.
* (dev_disable_lro() in net/core/dev.c)
*/
...
}
nf_flowtable HW offload를 사용할 때는 반드시 ethtool -K eth0 lro off를 설정해야 합니다. 커널은 포워딩 경로에서 자동으로 LRO를 비활성화하지만(dev_disable_lro()), 명시적으로 설정하는 것이 안전합니다.
GSO와 TC flower 액션 재분할
GSO(Generic Segmentation Offload)는 TX 경로에서 커널이 큰 세그먼트를 MSS 단위로 분할하는 소프트웨어 오프로드입니다. TC flower 액션이 적용된 후 GSO 재분할이 필요한 경우, 다음과 같은 상호작용이 발생합니다:
TX 경로에서 TC flower + GSO 상호작용:
1. 커널이 64KB GSO 세그먼트 생성
2. TC egress에서 flower 규칙 매칭 → NAT rewrite 액션 실행
3. NAT rewrite 후 체크섬 무효화
4. GSO가 MSS 단위로 분할 (예: 1460B × 44 세그먼트)
5. 각 분할 세그먼트에 대해 체크섬 재계산 필요
→ HW TSO가 활성화되면 단계 4~5를 NIC가 처리
→ HW TSO가 비활성화되면 CPU가 44회 분할 + 체크섬 계산
eSwitch HW offload에서는 TC flower 매칭, NAT rewrite, GSO 분할이 단일 하드웨어 파이프라인으로 처리되므로 이 문제가 발생하지 않습니다. 그러나 SW 경로에서는 TC flower 액션과 GSO의 순서가 성능에 영향을 줍니다.
TSO/Checksum 오프로드와 TC flower 카운터
TX 경로의 오프로드 기능은 NGFW의 트래픽 통계와 과금(Accounting)에 직접적인 영향을 미칩니다.
TSO와 바이트 카운터 불일치
TSO(TCP Segmentation Offload)가 활성화되면 커널은 최대 64KB의 슈퍼 세그먼트를 NIC로 전달하고, NIC 하드웨어가 이를 MSS 단위로 분할합니다. 문제는 TC flower의 패킷/바이트 카운터가 분할 전의 슈퍼 세그먼트를 기준으로 계산되는 것입니다.
TSO가 TC flower 카운터에 미치는 영향:
실제 전송: 44 × 1460B = 64,240 바이트 (44 패킷)
TC flower 카운터: 1 패킷, 64,240 바이트
→ 패킷 카운터가 실제보다 1/44로 축소
→ PPS(Packets Per Second) 기반 QoS 정책이 부정확해짐
→ conntrack byte accounting과 TC flower 카운터가 불일치
# TC flower 규칙의 카운터 확인
tc -s filter show dev eth0 ingress
# conntrack 바이트 카운터 비교
conntrack -L -o extended | grep "10.1.1.1"
# 불일치 확인 예시:
# TC flower: packets 1523, bytes 98,234,880
# conntrack: packets 67,012, bytes 98,234,880
# → 바이트는 일치하지만 패킷 수가 44배 차이
conntrack의 바이트 카운터를 참조하거나, ethtool -K eth0 tso off로 TSO를 비활성화합니다. 다만 TSO 비활성화는 TX 성능을 크게 저하시키므로 트레이드오프(Trade-off) 분석이 필요합니다.
Checksum 오프로드와 NAT 재계산
NAT 변환 후에는 IP 헤더와 TCP/UDP 체크섬을 재계산해야 합니다. 체크섬 오프로드의 SW/HW 처리 방식에 따라 NGFW 파이프라인의 동작이 달라집니다:
| 시나리오 | 체크섬 처리 | CPU 비용 | 호환성 |
|---|---|---|---|
| HW checksum + HW NAT (eSwitch) | NIC가 NAT rewrite와 체크섬을 한 번에 처리 | 없음 | 최적 |
| SW NAT + HW checksum | 커널이 NAT rewrite 후 partial checksum을 NIC에 위임 | NAT만 CPU | 좋음 |
| SW NAT + SW checksum | 커널이 NAT rewrite와 전체 체크섬을 모두 계산 | 높음 | 범용 |
| HW NAT + SW checksum | 불가 (논리적 모순) | - | - |
/* net/netfilter/nf_nat_core.c - NAT 후 체크섬 처리 */
static void nf_nat_csum_recalc(struct sk_buff *skb,
u8 proto, __be32 oldip, __be32 newip)
{
/*
* skb->ip_summed == CHECKSUM_PARTIAL이면
* 체크섬의 pseudo-header 부분만 업데이트하고
* 나머지는 NIC HW가 최종 계산 (TX checksum offload)
*
* skb->ip_summed == CHECKSUM_NONE이면
* 전체 체크섬을 SW에서 재계산
*/
inet_proto_csum_replace4(&tcp_hdr(skb)->check, skb,
oldip, newip, true);
}
conntrack의 바이트 어카운팅(Byte Accounting)과 관련하여, NAT 변환 전후의 패킷 크기가 변하지 않으므로(IP/포트 필드만 변경) 바이트 카운터에는 영향이 없습니다. 다만 NAT helper(ALG)가 페이로드를 수정하는 경우(FTP PORT 명령의 IP 주소 변경 등)에는 페이로드 크기가 변할 수 있으며, 이때 체크섬과 시퀀스 번호 조정이 모두 필요합니다.
NGFW 최적 NIC 오프로드 설정
NGFW의 동작 모드에 따라 NIC 오프로드 설정이 달라져야 합니다. 아래는 두 가지 대표적인 모드별 권장 설정입니다.
DPI 모드 vs 순수 포워딩 모드 비교
| NIC 오프로드 | DPI 모드 (Suricata/IPS 연동) | 순수 포워딩 모드 (ACL + NAT만) | 이유 |
|---|---|---|---|
| RSS | ON (대칭 해시) | ON (대칭 해시) | 양방향 세션 친화성 필수 |
| aRFS | ON | OFF | DPI 워커 CPU 캐시 최적화. 순수 포워딩은 불필요 |
| Flow Director | ON (Exception 큐 분리) | OFF | DPI 모드에서 ALG/RST 패킷 격리. 순수 포워딩은 RSS로 충분 |
| GRO | OFF 또는 조건부 | ON | DPI 시그니처 정확도 vs 처리량 트레이드오프 |
| LRO | OFF | OFF | flowtable 비호환. 포워딩 경로에서 항상 비활성화 |
| GSO | ON | ON | TX 성능 최적화. 두 모드 모두 유익 |
| TSO | ON | ON | TX 성능 핵심. 카운터 불일치는 conntrack으로 보정 |
| TX Checksum | ON | ON | NAT 후 체크섬 재계산 HW 가속. 항상 유익 |
| RX Checksum | ON | ON | 수신 체크섬 검증 HW 가속. 항상 유익 |
자동화 설정 스크립트
#!/bin/bash
# NGFW NIC 오프로드 최적 설정 스크립트
# 사용법: ./ngfw-nic-offload.sh <인터페이스> <dpi|forward>
IFACE="${1:?Usage: $0 }"
MODE="${2:?Usage: $0 }"
echo "=== NGFW NIC Offload 설정: ${IFACE} (${MODE} 모드) ==="
# 공통 설정 (두 모드 공유)
ethtool -K "$IFACE" lro off # flowtable 호환을 위해 항상 OFF
ethtool -K "$IFACE" tx on # TX checksum offload ON
ethtool -K "$IFACE" rx on # RX checksum offload ON
ethtool -K "$IFACE" tso on # TCP Segmentation Offload ON
ethtool -K "$IFACE" gso on # Generic Segmentation Offload ON
# 대칭 RSS 해시 (드라이버 지원 시)
ethtool --set-priv-flags "$IFACE" symmetric_rss on 2>/dev/null \
&& echo "[OK] symmetric RSS 활성화" \
|| echo "[SKIP] symmetric RSS 미지원"
# RSS 해시 필드: L3+L4 (양방향 세션 친화성)
ethtool -N "$IFACE" rx-flow-hash tcp4 sdfn 2>/dev/null
ethtool -N "$IFACE" rx-flow-hash udp4 sdfn 2>/dev/null
ethtool -N "$IFACE" rx-flow-hash tcp6 sdfn 2>/dev/null
ethtool -N "$IFACE" rx-flow-hash udp6 sdfn 2>/dev/null
case "$MODE" in
dpi)
echo "--- DPI 모드 (Suricata/IPS 연동) ---"
ethtool -K "$IFACE" gro off # DPI 시그니처 정확도 우선
ethtool -K "$IFACE" ntuple on # aRFS/Flow Director 필요
# aRFS 활성화
echo 32768 > /proc/sys/net/core/rps_sock_flow_entries
for rxq in /sys/class/net/"$IFACE"/queues/rx-*/rps_flow_cnt; do
echo 4096 > "$rxq"
done
# Flow Director: Exception 패킷을 큐 0으로 분리
ethtool -N "$IFACE" flow-type tcp4 action 0 loc 100 2>/dev/null
ethtool -N "$IFACE" flow-type ip4 proto 1 action 0 loc 101 2>/dev/null
echo "[DPI] GRO=off, aRFS=on, FlowDir=on"
;;
forward)
echo "--- 순수 포워딩 모드 (ACL + NAT) ---"
ethtool -K "$IFACE" gro on # 처리량 최적화
echo "[FORWARD] GRO=on, aRFS=off, FlowDir=off"
;;
*)
echo "ERROR: 모드는 'dpi' 또는 'forward'만 지원합니다."
exit 1
;;
esac
echo "=== 최종 오프로드 상태 ==="
ethtool -k "$IFACE" | grep -E "rx-checksumming|tx-checksumming|tcp-segmentation|generic-segmentation|generic-receive|large-receive|ntuple"
gro on을 유지하여 처리량을 확보할 수 있습니다. suricata --build-info | grep GRO로 지원 여부를 확인하세요.
세션 오프로드 생명주기
첫 패킷 처리
TCP SYN 또는 첫 UDP 패킷이 도착하면 다음 과정을 거칩니다:
- conntrack NEW —
nf_conntrack_in()에서 새 conntrack 엔트리 생성 - 전체 Netfilter 훅 — PREROUTING → FORWARD → POSTROUTING 체인의 모든 규칙 평가
- NFQUEUE 전달 — DPI 엔진(Suricata, nDPI 등)이 패킷을 수신하여 프로토콜 분석 시작
- App-ID 분류 — 첫 패킷만으로 부족하면 DPI 엔진이 추가 패킷 요청 (보통 3~10패킷)
- Verdict 반환 — DPI 엔진이 ACCEPT 또는 DROP verdict를 반환
이 단계에서 오프로드는 발생하지 않습니다. 모든 검사가 완료될 때까지 Slow Path에 머뭅니다.
첫 패킷 conntrack 처리 상세
/* net/netfilter/nf_conntrack_core.c - 새 연결 생성 */
static struct nf_conntrack_tuple_hash *
init_conntrack(struct net *net, struct nf_conn *tmpl,
const struct nf_conntrack_tuple *tuple,
struct sk_buff *skb)
{
struct nf_conn *ct;
/* conntrack_max 초과 시 early drop (LRU) */
if (nf_conntrack_max &&
atomic_read(&net->ct.count) >= nf_conntrack_max) {
if (!early_drop(net, hash))
return ERR_PTR(-ENOMEM); /* DROP: 테이블 가득 참 */
}
/* nf_conn 구조체 할당 (slab 캐시) */
ct = __nf_conntrack_alloc(net, zone, tuple, ...);
/* L4 프로토콜별 초기 상태 설정 */
/* TCP: SYN_SENT, UDP: UNREPLIED */
l4proto->new(ct, skb, dataoff);
/* ALG helper 자동 할당 (포트 기반) */
if (net->ct.sysctl_auto_assign_helper)
nf_ct_helper_find(ct, tuple);
/* unconfirmed list에 추가 (아직 해시에 삽입하지 않음) */
/* POSTROUTING에서 confirm되면 해시 테이블에 삽입 */
nf_ct_add_to_unconfirmed_list(ct);
return &ct->tuplehash[IP_CT_DIR_ORIGINAL];
}
코드 설명
-
10-13행
nf_conntrack_max한계에 도달하면early_drop()이 가장 오래된 UNREPLIED 연결을 삭제하여 공간을 확보합니다. 이 한계는 NGFW에서 매우 중요합니다. - 16행 nf_conn 구조체는 conntrack 엔트리 하나를 나타냅니다. slab 캐시에서 할당되어 메모리 단편화를 줄입니다.
- 19-20행 TCP는 SYN_SENT 상태로 시작하여 3-way handshake 완료 시 ESTABLISHED로 전환됩니다. UDP는 첫 응답 수신 시 ASSURED 상태가 됩니다.
-
27-28행
conntrack 엔트리는 처음에 unconfirmed list에 들어갑니다. 패킷이 성공적으로 POSTROUTING까지 도달하면
nf_conntrack_confirm()에서 해시 테이블에 삽입됩니다. 이 2단계 삽입은 DROP된 패킷의 conntrack 엔트리가 테이블을 오염시키는 것을 방지합니다.
DPI 엔진의 패킷 분류 과정
NFQUEUE를 통해 유저스페이스 DPI 엔진(Suricata/nDPI)에 전달된 패킷의 분류 과정입니다:
| 패킷 번호 | DPI 동작 | App-ID 상태 | Verdict |
|---|---|---|---|
| 1 (SYN) | TCP 핸드셰이크 감지 | UNKNOWN | ACCEPT (통과) |
| 2 (SYN-ACK) | 서버 응답 확인 | UNKNOWN | ACCEPT |
| 3 (ACK) | 연결 수립 확인 | UNKNOWN | ACCEPT |
| 4 (Client Hello) | TLS SNI 추출 | TLS (SNI 확인중) | ACCEPT |
| 5 (Server Hello) | 서버 인증서/프로토콜 분석 | HTTPS (example.com) | ACCEPT |
| 6~ (Application Data) | 분류 완료, IPS 시그니처 검사 | CLASSIFIED | ACCEPT → 오프로드 가능 |
일반적으로 3~10개 패킷이면 App-ID 분류가 완료됩니다. TLS 1.3에서 Encrypted Client Hello(ECH)가 사용되면 SNI가 암호화되어 더 많은 패킷이 필요하거나, SSL 복호화 없이는 분류가 불가능합니다.
ESTABLISHED 전환
TCP 3-way handshake가 완료되면 conntrack 상태가 ESTABLISHED로 전환됩니다. 이 시점에서 오프로드 여부를 결정합니다.
오프로드 결정 기준 4가지:
- DPI 분류 완료 — App-ID가 결정되고 ALLOW verdict가 나왔는가?
- ALG 프로토콜 아닌가 — FTP/SIP/H.323 등 동적 포트 할당이 필요한 프로토콜은 오프로드 불가
- IP 단편화 아닌가 — 단편화된 패킷 스트림은 오프로드 불가
- HW 지원 여부 — NIC/SmartNIC이 해당 플로우의 오프로드를 지원하는가? (터널 타입, NAT 유형 등)
오프로드 등록 커널 코드
nftables에서 flow add @ft가 실행되면 내부적으로 다음이 호출됩니다:
/* net/netfilter/nft_flow_offload.c */
static void nft_flow_offload_eval(const struct nft_expr *expr,
struct nft_regs *regs,
const struct nft_pktinfo *pkt)
{
struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
ct = nf_ct_get(pkt->skb, &ctinfo);
/* 오프로드 가능 조건 확인 */
if (nf_ct_is_dying(ct))
goto err;
if (nf_ct_helper(ct)) /* ALG helper 있으면 불가 */
goto err;
/* flow_offload 구조체 생성 */
struct flow_offload *flow = flow_offload_alloc(ct);
/* 라우팅 캐시 설정 */
flow_offload_route_init(flow, &route);
/* flowtable 해시에 등록 */
flow_offload_add(&ft->ft, flow);
/* HW offload 플래그가 있으면 NIC에도 등록 */
if (ft->ft.flags & NF_FLOWTABLE_HW_OFFLOAD)
nf_flow_offload_hw_add(net, flow, ct);
/* → TC flower ct 규칙 → NIC eSwitch FDB 삽입 */
}
nf_flow_offload_hw_add()는 내부적으로 TC flower API를 호출하여 eSwitch에 FDB 규칙을 삽입합니다. 이 과정은 워크큐에서 비동기적으로 수행되므로, HW 규칙 설치까지 수 밀리초의 지연이 발생할 수 있습니다. 이 사이에 도착하는 패킷은 SW flowtable에서 처리됩니다.
오프로드 결정 트리
| conntrack 상태 | DPI 결과 | ALG | NIC HW 지원 | 오프로드 결과 |
|---|---|---|---|---|
| NEW | 미분류 | - | - | Slow Path (전체 검사) |
| ESTABLISHED | ALLOW | No | Yes | HW Offload (eSwitch FDB) |
| ESTABLISHED | ALLOW | No | No | SW Offload (flowtable) |
| ESTABLISHED | ALLOW | Yes (FTP/SIP) | - | Slow Path 유지 (ALG 필요) |
| ESTABLISHED | DROP | - | - | 즉시 DROP |
| ESTABLISHED | 미완료 | - | - | Slow Path (DPI 계속) |
| RELATED | - | Yes | - | Slow Path (헬퍼 추적) |
| INVALID | - | - | - | DROP (기본 정책) |
오프로드 해제
오프로드된 세션은 다음 상황에서 해제됩니다:
- TCP FIN/RST — 연결 종료 신호가 감지되면 flowtable에서 DYING 상태로 전환
- GC 타이머(Timer) —
nf_flow_offload_gc_step()이 주기적으로 만료된 엔트리 정리 - HW rule 삭제 —
nf_flow_offload_hw_del()이 eSwitch FDB 규칙을 제거 - conntrack 삭제 — 관련 conntrack 엔트리도 정리하여 리소스 해제
/* flowtable 오프로드 해제 흐름 */
TCP FIN/RST 수신
→ flow_offload_teardown() /* FLOW_OFFLOAD_TEARDOWN 플래그 설정 */
→ nf_flow_offload_gc_step() /* GC 워크큐가 DYING 플로우 정리 */
→ nf_flow_table_offload_del() /* HW rule 삭제 (TC flower del) */
→ nf_ct_delete() /* conntrack 엔트리 삭제 */
GC 메커니즘 상세
flowtable의 Garbage Collection은 두 가지 메커니즘으로 동작합니다:
| GC 유형 | 트리거 | 동작 | 지연 |
|---|---|---|---|
| Passive GC | 패킷 도착 시 flow_offload_stale_flow() 확인 | stale 플로우 감지 → Slow Path 복귀 | 즉시 (패킷 기반) |
| Active GC | 워크큐가 주기적 실행 (nf_flow_offload_work) | 만료된 플로우 정리 + HW rule 삭제 | 1초 주기 |
| Forced GC | conntrack destroy 이벤트 | conntrack 삭제 시 연관 플로우 즉시 정리 | 즉시 |
HW 카운터 동기화: HW offload된 플로우가 삭제될 때, NIC에서 처리된 패킷/바이트 카운터를 SW 카운터에 동기화합니다. 이를 통해 conntrack -L이나 nft list counter에서 정확한 통계를 확인할 수 있습니다.
/* HW 카운터 동기화 (net/netfilter/nf_flow_table_offload.c) */
static void nf_flow_offload_stats(struct flow_offload *flow,
struct flow_stats *stats)
{
struct nf_conn_acct *acct = nf_conn_acct_find(flow->ct);
/* HW에서 읽어온 패킷/바이트 카운터를 conntrack에 반영 */
atomic64_add(stats[0].pkts, &acct->counter[IP_CT_DIR_ORIGINAL].packets);
atomic64_add(stats[0].bytes, &acct->counter[IP_CT_DIR_ORIGINAL].bytes);
atomic64_add(stats[1].pkts, &acct->counter[IP_CT_DIR_REPLY].packets);
atomic64_add(stats[1].bytes, &acct->counter[IP_CT_DIR_REPLY].bytes);
/* 타임스탬프 갱신 → GC 타임아웃 리셋 */
flow->timeout = nf_flowtable_time_stamp + flow_offload_get_timeout(flow);
}
nf_flowtable_tcp_timeout은 최소 30초 이상으로 설정해야 합니다.
Stateful 방화벽 오프로드
ACL HW 오프로드
TC flower를 사용하여 ct_state 매칭과 함께 ACL 규칙을 eSwitch에 설치할 수 있습니다. 이를 통해 conntrack 상태 기반 방화벽 규칙이 하드웨어에서 직접 평가됩니다.
# eSwitch switchdev 모드에서 TC flower ct 규칙 예시
# 1. ct zone 설정 및 conntrack 추적 시작
tc filter add dev eth0_rep0 ingress prio 1 \
protocol ip flower \
ct_state -trk \
action ct zone 1
# 2. ESTABLISHED+TRACKED 세션 → HW offload forward
tc filter add dev eth0_rep0 ingress prio 2 \
protocol ip flower \
ct_state +trk+est \
action ct zone 1 \
action mirred egress redirect dev eth1_rep0
# 3. NEW+TRACKED 세션 → CPU (Slow Path)
tc filter add dev eth0_rep0 ingress prio 3 \
protocol ip flower \
ct_state +trk+new \
action pass # CPU로 전달하여 전체 검사
# 4. INVALID → DROP
tc filter add dev eth0_rep0 ingress prio 4 \
protocol ip flower \
ct_state +trk+inv \
action drop
코드 설명
-
3-5행
아직 conntrack에 의해 추적되지 않은(
-trk) 패킷에 대해ct zone 1에서 conntrack 추적을 시작합니다. -
8-12행
이미 추적되고 ESTABLISHED 상태인 패킷(
+trk+est)을 하드웨어에서 직접 다른 representor 포트로 리다이렉트합니다. 이것이 HW Fast Path의 핵심입니다. -
15-18행
새로운 연결(
+trk+new)은pass로 CPU에 전달하여 nftables → NFQUEUE → DPI 전체 검사를 수행합니다. -
21-24행
INVALID 상태(
+trk+inv) 패킷은 하드웨어에서 즉시 DROP합니다.
conntrack HW 오프로드
NF_FLOWTABLE_HW_OFFLOAD 플래그가 활성화되면, flowtable에 등록된 플로우가 NIC 하드웨어의 conntrack 테이블에도 설치됩니다.
# flowtable HW offload 활성화
nft add flowtable inet filter ft \
{ hook ingress priority 0\; devices = { eth0, eth1 }\; \
flags offload\; }
# forward chain에서 established 세션을 flowtable으로 등록
nft add rule inet filter forward \
ct state established \
flow add @ft
# 오프로드 상태 실시간 확인
conntrack -L --status OFFLOAD
# 출력 예:
# tcp 6 300 ESTABLISHED src=10.0.0.1 dst=192.168.1.1
# sport=45678 dport=443 [OFFLOAD] mark=0 use=2
HW offload 내부 메커니즘
flowtable HW offload는 다음 과정으로 NIC에 규칙을 설치합니다:
/* HW offload 규칙 설치 흐름 */
nf_flow_offload_hw_add()
→ nf_flow_offload_tuple()
→ flow_offload_mangle() /* NAT rewrite 액션 구성 */
→ flow_action_entry_set() /* TC flow_action 구조체 채움 */
→ nf_flow_table_offload_add()
→ flow_block_cb() /* NIC 드라이버 콜백 호출 */
→ mlx5e_tc_offload_fdb_rules() /* mlx5: FDB rule 삽입 */
→ ice_tc_flower_action() /* ice: TC flower 규칙 */
NIC 드라이버는 FLOW_BLOCK_BIND/FLOW_BLOCK_UNBIND 이벤트를 통해 flowtable과 연결됩니다. 드라이버가 지원하지 않는 플로우 타입(예: 특수 NAT, 미지원 터널)에 대해서는 -EOPNOTSUPP를 반환하고, 이 경우 SW flowtable에서만 처리됩니다.
HW conntrack의 한계:
- TCP window 검증 — HW에서는 TCP 윈도우/시퀀스 번호의 유효성을 검증하지 않습니다. 이를 악용한 공격(out-of-window injection)에 대해서는 주기적 샘플링으로 대응합니다.
- conntrack 테이블 크기 — NIC HW의 flow table 크기가 제한적 (수만~수십만 엔트리). 초과 시 SW flowtable로 폴백합니다.
- NAT 변환 복잡도 — CGNAT(Many-to-one NAT)이나 복잡한 NAT 매핑은 HW에서 지원하지 않을 수 있습니다.
- 프로토콜 제한 — TCP와 UDP만 HW offload 가능. ICMP, GRE, SCTP 등은 SW 처리
- IPv6 지원 — NIC에 따라 IPv6 CT offload 미지원 가능. 지원 여부는
ethtool -k에서 확인
conntrack HW offload 호환성 매트릭스
| 기능 | NVIDIA CX-6 Dx | NVIDIA CX-7 | Intel E810 | Broadcom P2100 |
|---|---|---|---|---|
| CT offload (TCP) | 지원 | 지원 | 지원 | 지원 |
| CT offload (UDP) | 지원 | 지원 | 지원 | 지원 |
| CT offload (IPv6) | 지원 | 지원 | 제한적 | 미지원 |
| CT zone 지원 | 지원 | 지원 | 제한적 | 미지원 |
| CT NAT action | SNAT/DNAT | SNAT/DNAT | SNAT/DNAT | DNAT만 |
| CT mark action | 지원 | 지원 | 미지원 | 미지원 |
| 최대 HW flow 엔트리 | ~1M | ~4M | ~64K | ~128K |
| flowtable HW offload | 지원 | 지원 | 지원 (5.15+) | 미지원 |
NAT 오프로드
SNAT/DNAT 주소 변환은 flowtable과 eSwitch 모두에서 오프로드할 수 있습니다. (NAT 아키텍처 참고)
| 기능 | eSwitch HW | flowtable SW | 비고 |
|---|---|---|---|
| SNAT (Source NAT) | 지원 | 지원 | NF_FLOW_SNAT 플래그 |
| DNAT (Destination NAT) | 지원 | 지원 | NF_FLOW_DNAT 플래그 |
| MASQUERADE | 제한적 | 지원 | 인터페이스 주소 변경 시 flush 필요 |
| CGNAT (Large-scale NAT) | NIC 의존 | 지원 | 포트 범위 제한 시 SW 폴백 |
| 1:1 NAT | 지원 | 지원 | 가장 효율적인 HW offload 대상 |
| Port Forwarding (REDIRECT) | 지원 | 지원 | 단일 목적지 DNAT |
| NAT64/NAT46 | 미지원 | 제한적 | IPv6↔IPv4 변환은 주로 SW |
| conntrack 기반 NAT | 지원 | 지원 | CT action에서 NAT 정보 전달 |
NAT 오프로드의 커널 구현
flowtable NAT offload는 conntrack의 NAT 정보를 flow_offload 구조체에 복사하여, 이후 패킷을 conntrack 없이 직접 변환합니다:
/* net/netfilter/nf_flow_table_ip.c - NAT 오프로드 적용 */
static int nf_flow_nat_ip(const struct flow_offload *flow,
struct sk_buff *skb,
unsigned int thoff,
enum flow_offload_tuple_dir dir)
{
struct iphdr *iph = ip_hdr(skb);
/* SNAT: 소스 IP/포트 교체 */
if (flow->flags & FLOW_OFFLOAD_SNAT) {
/* ORIGINAL 방향: src → NAT 주소로 변경 */
/* REPLY 방향: dst → 원래 주소로 복원 */
nf_flow_snat_port(skb, thoff,
flow->tuplehash[!dir].tuple.src_v4.s_addr,
flow->tuplehash[!dir].tuple.port.src);
/* IP 체크섬 + L4 체크섬 재계산 */
csum_replace4(&iph->check, iph->saddr, new_addr);
}
/* DNAT: 목적지 IP/포트 교체 (위와 유사) */
if (flow->flags & FLOW_OFFLOAD_DNAT)
nf_flow_dnat_port(skb, thoff, ...);
return 0;
}
CGNAT 대규모 NAT 시나리오
통신사(ISP) 환경의 CGNAT(Carrier-Grade NAT)에서는 수만 개의 내부 IP를 소수의 공인 IP로 변환합니다. 이 경우:
- 포트 풀 관리: 각 공인 IP당 ~64K 포트를 내부 IP에 분배. 포트 소진 시 새 연결 불가
- HW NAT의 한계: 일부 NIC은 한정된 NAT 매핑 테이블만 지원 (수만 엔트리). 초과 시 SW 폴백
- Deterministic NAT: 포트 범위를 사전 할당하여 로깅 부하 감소.
nft add map으로 구현 가능
# CGNAT nftables 설정 예시
table ip cgnat {
chain postrouting {
type nat hook postrouting priority 100; policy accept;
# 내부 대역별 공인 IP 분배 (Deterministic NAT)
ip saddr 100.64.0.0/24 snat to 203.0.113.1:1024-32767
ip saddr 100.64.1.0/24 snat to 203.0.113.1:32768-65535
ip saddr 100.64.2.0/24 snat to 203.0.113.2:1024-32767
# 폴백: 나머지 → 공인 IP 풀에서 동적 할당
ip saddr 100.64.0.0/10 snat to 203.0.113.1-203.0.113.10
}
}
# CGNAT 세션도 flowtable 오프로드 적용
nft add rule ip cgnat forward \
ct state established flow add @ft
QoS/터널/IPSec 오프로드
DSCP/QoS 오프로드
TC flower로 DSCP 필드를 매칭하고 QoS 큐에 매핑하는 규칙을 eSwitch에 설치할 수 있습니다.
# DSCP EF (46) → TC 큐 0 (높은 우선순위)
tc filter add dev eth0_rep0 ingress prio 1 \
protocol ip flower \
ip_tos 0xb8/0xfc \
action skbedit priority 0
# DSCP AF11 (10) → TC 큐 2 (낮은 우선순위)
tc filter add dev eth0_rep0 ingress prio 2 \
protocol ip flower \
ip_tos 0x28/0xfc \
action skbedit priority 2
DSCP/QoS 매핑 상세
NGFW에서 QoS는 보안 정책과 연계됩니다. DPI 결과(App-ID)에 따라 DSCP 값을 재마킹하고, HW QoS 큐에 매핑하는 패턴입니다:
| DSCP 클래스 | 값 | IP ToS 바이트 | 용도 | HW 큐 매핑 |
|---|---|---|---|---|
| EF (Expedited Forwarding) | 46 | 0xB8 | VoIP, 실시간 미디어 | TC 0 (strict priority) |
| AF41 | 34 | 0x88 | 화상회의, 인터랙티브 | TC 1 |
| AF31 | 26 | 0x68 | 스트리밍 비디오 | TC 2 |
| AF21 | 18 | 0x48 | 주요 비즈니스 앱 | TC 3 |
| AF11 | 10 | 0x28 | 일반 트래픽 | TC 4 (WRR) |
| BE (Best Effort) | 0 | 0x00 | 기본 트래픽 | TC 5 (WRR) |
| CS1 (Scavenger) | 8 | 0x20 | 백업, 대용량 전송 | TC 6 (lowest) |
# NGFW에서 DPI 결과 기반 DSCP 재마킹
# nftables에서 App-ID → DSCP 매핑 (DPI 엔진이 ct mark에 App-ID 기록)
table inet qos_mark {
map app_dscp {
type mark : verdict
elements = {
0x0001 : accept, # VoIP → DSCP EF (DPI에서 이미 마킹)
0x0002 : accept, # Video → DSCP AF41
0x0003 : accept, # Web → DSCP AF11
}
}
chain forward {
type filter hook forward priority 50; policy accept;
# DPI 엔진이 ct mark에 기록한 App-ID → DSCP 재마킹
ct mark 0x0001 ip dscp set ef
ct mark 0x0002 ip dscp set af41
ct mark 0x0003 ip dscp set af11
}
}
# HW QoS 큐 설정 (TC MQPRIO)
tc qdisc add dev eth0 root mqprio \
num_tc 4 map 3 3 2 2 1 1 0 0 0 0 0 0 0 0 0 0 \
queues 1@0 1@1 2@2 4@4 hw 1
터널 오프로드
NGFW에서 터널은 두 가지 역할을 합니다: 사이트 간 VPN과 오버레이(Overlay) 네트워크. eSwitch는 다음 터널 타입의 encap/decap을 하드웨어에서 수행합니다:
- VXLAN — L2 over UDP 캡슐화(Encapsulation), 가장 널리 지원
- GRE — IP over IP 캡슐화 (GRE 프로토콜)
- Geneve — 유연한 TLV 옵션을 지원하는 현대적 터널
터널 + NGFW 오프로드 결합
터널 decap → 내부 패킷 DPI → 오프로드의 전체 흐름을 TC flower로 구성합니다:
# VXLAN 터널 디바이스 생성
ip link add vxlan0 type vxlan id 100 \
local 10.0.0.1 dport 4789 nolearning external
# eSwitch에서 VXLAN decap + conntrack + forward 규칙
# chain 0: 외부 헤더로 VXLAN 매칭 → decap
tc filter add dev eth0_rep0 ingress chain 0 prio 1 \
protocol ip flower \
enc_dst_ip 10.0.0.1 enc_dst_port 4789 enc_key_id 100 \
action tunnel_key unset pipe \
action goto chain 1
# chain 1: decap된 내부 패킷에 conntrack 적용
tc filter add dev eth0_rep0 ingress chain 1 prio 1 \
protocol ip flower ct_state -trk \
action ct zone 1 pipe \
action goto chain 2
# chain 2: EST → HW forward, NEW → CPU
tc filter add dev eth0_rep0 ingress chain 2 prio 1 \
protocol ip flower ct_state +trk+est \
action ct zone 1 nat pipe \
action mirred egress redirect dev eth1_rep0
tc filter add dev eth0_rep0 ingress chain 2 prio 2 \
protocol ip flower ct_state +trk+new \
action pass # CPU → nftables → NFQUEUE → DPI
IPSec 인라인 크립토 오프로드
IPSec & xfrm의 HW 오프로드를 NGFW 파이프라인에 통합하면, 암호화/복호화를 NIC에서 수행하고 평문 패킷만 DPI 엔진에 전달할 수 있습니다.
# IPSec crypto offload 활성화 (xfrm)
ip xfrm state add src 10.0.0.1 dst 10.0.0.2 \
proto esp spi 0x1001 reqid 1 mode tunnel \
enc 'aes' 0x$(head -c 16 /dev/urandom | xxd -p) \
offload dev eth0 dir out
IPSec 오프로드 모드 비교
| 모드 | 암호화 | ESP 헤더 | 라우팅 | 성능 | NIC 요구사항 |
|---|---|---|---|---|---|
| Full SW | CPU | CPU | CPU | 1~5 Gbps/core | 없음 |
| Crypto offload | NIC | CPU | CPU | 10~25 Gbps | inline crypto 지원 |
| Packet offload | NIC | NIC | CPU | 25~50 Gbps | packet offload 지원 |
| Full offload | NIC | NIC | NIC | 50~100 Gbps | eSwitch + xfrm full offload |
NGFW와의 통합 포인트: IPSec 수신 시 NIC이 복호화를 수행하고, 평문(decrypted) 패킷이 커널에 전달됩니다. 이 평문 패킷에 대해 conntrack → flowtable → DPI 파이프라인이 정상 작동합니다. 송신 시에는 flowtable이 평문 패킷을 NIC에 전달하고, NIC이 ESP 캡슐화와 암호화를 인라인으로 수행합니다.
# IPSec + flowtable NGFW 조합 설정
# 1. xfrm SA에 crypto offload 설정
ip xfrm state add src 10.0.0.1 dst 10.0.0.2 \
proto esp spi 0x1001 reqid 1 mode tunnel \
aead 'rfc4106(gcm(aes))' 0x$(head -c 20 /dev/urandom | xxd -p) 128 \
offload crypto dev eth0 dir out
ip xfrm state add src 10.0.0.2 dst 10.0.0.1 \
proto esp spi 0x1002 reqid 1 mode tunnel \
aead 'rfc4106(gcm(aes))' 0x$(head -c 20 /dev/urandom | xxd -p) 128 \
offload crypto dev eth0 dir in
# 2. xfrm 정책
ip xfrm policy add src 10.1.0.0/24 dst 10.2.0.0/24 \
dir out tmpl src 10.0.0.1 dst 10.0.0.2 \
proto esp reqid 1 mode tunnel
# 3. flowtable에서 decrypted 패킷 오프로드
nft add flowtable inet ngfw ft_ipsec \
{ hook ingress priority 0\; devices = { eth0 }\; flags offload\; }
nft add rule inet ngfw forward \
ct state established \
ipsec in reqid 1 \
flow add @ft_ipsec accept
# 확인: IPSec HW 오프로드 상태
ip xfrm state show | grep -A1 offload
ethtool -S eth0 | grep ipsec
NGFW에서 VXLAN 오버레이 + 보안 통합
데이터센터 NGFW에서 VXLAN 오버레이 네트워크와 보안 검사를 통합하는 아키텍처입니다. eSwitch가 VXLAN 터널의 encap/decap을 하드웨어에서 수행하고, 내부 패킷에 대해 conntrack + DPI를 적용합니다.
# VXLAN + NGFW 통합 구성 (eSwitch offload)
# 1. VXLAN 터널 엔드포인트 생성
ip link add vxlan100 type vxlan id 100 \
local 10.0.0.1 dport 4789 nolearning external
# 2. nftables에서 decap된 내부 트래픽에 NGFW 정책 적용
table inet vxlan_ngfw {
flowtable ft_vxlan {
hook ingress priority 0
devices = { vxlan100, eth1 }
flags offload
}
chain forward {
type filter hook forward priority 0; policy drop;
ct state invalid drop
# VXLAN 내부 트래픽: EST → offload
iifname "vxlan100" ct state established,related \
flow add @ft_vxlan accept
# VXLAN 내부 트래픽: NEW → DPI
iifname "vxlan100" ct state new \
queue num 0-3 fanout
# 내부 → VXLAN: EST → offload
oifname "vxlan100" ct state established,related \
flow add @ft_vxlan accept
}
}
# 3. eSwitch에서 VXLAN + conntrack 통합 규칙
# 외부 헤더로 VXLAN 패킷 식별 → decap → conntrack → forward
tc filter add dev eth0_rep0 ingress chain 0 prio 1 \
protocol ip flower \
enc_dst_ip 10.0.0.1 enc_dst_port 4789 enc_key_id 100 \
action tunnel_key unset pipe \
action ct zone 2 pipe \
action goto chain 1
# chain 1에서 EST/NEW 분기 (위 §8 패턴과 동일)
tc filter add dev eth0_rep0 ingress chain 1 prio 1 \
protocol ip flower ct_state +trk+est \
action ct zone 2 nat pipe \
action mirred egress redirect dev eth1_rep0
tc filter add dev eth0_rep0 ingress chain 1 prio 2 \
protocol ip flower ct_state +trk+new \
action pass
| 터널 타입 | NVIDIA ConnectX-6+ | Intel E810 | Fortinet NP7 | Linux SW |
|---|---|---|---|---|
| VXLAN | HW encap/decap | HW encap/decap | HW encap/decap | 지원 |
| GRE | HW encap/decap | SW | HW encap/decap | 지원 |
| Geneve | HW encap/decap | HW encap/decap | 제한적 | 지원 |
| IPSec ESP | inline crypto | inline crypto | NP7 내장 | xfrm SW |
| WireGuard | 미지원 | 미지원 | 미지원 | 커널 SW |
| L2TP | 미지원 | 미지원 | HW | 지원 |
| MPLS | HW push/pop | 미지원 | HW | 지원 |
GTP-U 오프로드와 5G NGFW
5G 모바일 네트워크에서 사용자 트래픽은 GTP-U(GPRS Tunnelling Protocol User Plane)로 캡슐화되어 전송됩니다. NGFW가 5G 환경에 배치되면 GTP-U 터널 내부의 실제 사용자 트래픽을 검사해야 하며, 이때 GTP-U 디캡슐레이션(Decapsulation)과 내부 패킷 검사를 SmartNIC 하드웨어에서 오프로드하면 처리량을 극대화할 수 있습니다. 이 섹션에서는 GTP-U 프로토콜 구조, 커널 GTP 모듈, TC flower 연동, HW 오프로드 구현을 다룹니다.
GTP-U 프로토콜 구조
GTP-U(GPRS Tunnelling Protocol - User Plane)는 3GPP 표준(TS 29.281)에 정의된 터널링 프로토콜로, 모바일 네트워크에서 사용자 데이터 패킷을 캡슐화하여 네트워크 노드 간에 전달합니다. GTP-U는 UDP 포트 2152 위에서 동작하며, 핵심 식별자는 TEID(Tunnel Endpoint Identifier)입니다.
GTP-U 헤더 형식
| 비트 | 필드 | 크기 | 설명 |
|---|---|---|---|
| 0~2 | Version | 3비트 | 프로토콜 버전 (GTP-U = 1) |
| 3 | PT (Protocol Type) | 1비트 | 1 = GTP, 0 = GTP' (과금) |
| 4 | Reserved | 1비트 | 예약 (0) |
| 5 | E (Extension Header) | 1비트 | 확장 헤더 존재 여부 |
| 6 | S (Sequence Number) | 1비트 | 시퀀스 번호 존재 여부 |
| 7 | PN (N-PDU Number) | 1비트 | N-PDU 번호 존재 여부 |
| 8~15 | Message Type | 8비트 | 0xFF = T-PDU (사용자 데이터) |
| 16~31 | Length | 16비트 | TEID 이후 페이로드 길이 |
| 32~63 | TEID | 32비트 | 터널 엔드포인트 식별자 (세션 ID) |
| 64~79 | Sequence Number | 16비트 | 옵션 (S=1일 때) |
| 80~87 | N-PDU Number | 8비트 | 옵션 (PN=1일 때) |
| 88~95 | Next Extension Header | 8비트 | 옵션 (E=1일 때) |
GTP-U 캡슐화 스택
GTP-U로 캡슐화된 패킷의 전체 프로토콜 스택은 다음과 같습니다:
┌─────────────────────────────────────────────────────────────────────┐
│ Outer Ethernet │ Outer IP │ UDP(2152) │ GTP-U │ Inner IP │ Payload │
├────────────────┼──────────┼───────────┼───────┼──────────┼─────────┤
│ 14 bytes │ 20 bytes │ 8 bytes │ 8~12B │ 20 bytes │ ... │
└────────────────┴──────────┴───────────┴───────┴──────────┴─────────┘
총 오버헤드: 14 + 20 + 8 + 8(~12) = 50~54 bytes (Inner Ethernet 없음)
1500B MTU 기준 실효 페이로드: 1446~1450 bytes
| 레이어 | 프로토콜 | 크기 | 역할 |
|---|---|---|---|
| L2 Outer | Ethernet | 14B | 물리 네트워크 전달 |
| L3 Outer | IPv4/IPv6 | 20/40B | gNB ↔ UPF 간 라우팅 |
| L4 Outer | UDP (dst 2152) | 8B | GTP-U 전송 계층 |
| Tunnel | GTP-U Header | 8~12B | TEID로 사용자 세션 식별 |
| L3 Inner | IPv4/IPv6 | 20/40B | 사용자 원본 IP (UE의 실제 IP) |
| L4 Inner | TCP/UDP | 20/8B | 사용자 원본 전송 계층 |
| Payload | Application Data | 가변 | 사용자 실제 데이터 (DPI 검사 대상) |
모바일 네트워크에서 NGFW 배치 위치
5G 네트워크 아키텍처(3GPP TS 23.501)에서 NGFW는 주로 N3 인터페이스(gNB ↔ UPF)와 N6 인터페이스(UPF ↔ Data Network) 두 위치에 배치됩니다.
5G 아키텍처 개요
5G 데이터 플레인 경로:
UE ──[무선]──→ gNB ──[N3: GTP-U]──→ UPF ──[N6: IP]──→ DN (Internet)
│ │
│ ┌──[N9: GTP-U]──┐ │
│ │ (UPF 간 중계) │ │
│ └───────────────┘ │
│ │
┌───┴───────────────┐ ┌─┴──────────┐
│ NGFW 위치 A │ │ NGFW 위치 B │
│ (N3 인라인) │ │ (N6 이그레스)│
│ GTP-U 내부 검사 │ │ 일반 IP 검사 │
└───────────────────┘ └────────────┘
| 배치 위치 | 인터페이스 | 트래픽 형태 | NGFW 요구사항 | 오프로드 방식 |
|---|---|---|---|---|
| 위치 A: N3 인라인 | gNB ↔ UPF 사이 | GTP-U 캡슐화 | GTP-U decap 후 inner 패킷 DPI | GTP-U HW decap + CT + ACL |
| 위치 B: N6 이그레스 | UPF ↔ DN 사이 | 일반 IP (디캡슐 후) | 일반 L3/L4 검사 + DPI | 표준 flowtable + TC flower |
| 위치 C: N9 중계 | UPF ↔ UPF 사이 | GTP-U (재캡슐화) | inter-UPF 트래픽 검사 | 이중 GTP-U decap/encap |
N3 인라인 배치 시 트래픽 패턴
N3 인터페이스에 NGFW를 배치하면 모든 사용자 트래픽이 GTP-U로 캡슐화된 상태로 통과합니다. NGFW는 다음과 같은 처리를 수행해야 합니다:
- GTP-U 디캡슐레이션 — 외부 Ethernet/IP/UDP/GTP-U 헤더를 제거하여 내부(Inner) IP 패킷을 추출합니다.
- TEID 기반 세션 매핑 — TEID를 사용자(가입자) 세션에 매핑합니다. 단일 UPF에 10만~100만 개의 동시 TEID가 존재할 수 있습니다.
- Inner 패킷 검사 — 추출된 내부 IP 패킷에 대해 ACL, conntrack, DPI, IPS를 수행합니다.
- GTP-U 재캡슐레이션 — 검사 완료 후 원래의 GTP-U 헤더를 재부착하여 전달합니다.
N6 이그레스 배치 시 장단점
N6 인터페이스에서는 UPF가 이미 GTP-U 디캡슐레이션을 완료했으므로, NGFW는 일반 IP 패킷을 처리합니다. 이 경우 GTP-U 처리 오버헤드가 없어 기존 NGFW 파이프라인을 그대로 사용할 수 있지만, TEID 기반 가입자 식별이 불가능하다는 단점이 있습니다. 가입자별 정책(Per-Subscriber Policy)을 적용하려면 UPF가 내부 IP에 DSCP 마킹이나 VLAN 태그로 가입자 정보를 전달해야 합니다.
커널 GTP 모듈과 TC flower 연동
Linux 커널은 gtp.ko 모듈을 통해 GTP-U 터널 인터페이스를 제공합니다. 이 모듈은 커널 4.7부터 포함되어 있으며, Open5GS, free5GC 등 오픈소스 5G 코어에서 UPF 구현에 사용됩니다.
gtp.ko 모듈 아키텍처
# GTP 커널 모듈 로드
modprobe gtp
# GTP 터널 인터페이스 생성 (libgtpnl 사용)
# gtp-link 명령은 genl(generic netlink) 기반
ip link add gtp0 type gtp role sgsn hashsize 131072
# 또는 gtp_newlink netlink API로 직접 생성
# (Open5GS UPF가 내부적으로 사용하는 방식)
# GTP 인터페이스 상태 확인
ip link show gtp0
ip addr add 10.45.0.1/16 dev gtp0
ip link set gtp0 up
# GTP 터널 세션(PDP context) 추가
# TEID 0x12345678, peer 192.168.1.100 (gNB IP)
gtp-tunnel add gtp0 v1 12345678 192.168.1.100 10.45.0.2
/* drivers/net/gtp.c - GTP-U 수신 처리 */
static int gtp1u_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
{
struct gtphdr *gtp1;
struct pdp_ctx *pctx;
/* GTP-U 헤더 파싱 */
gtp1 = (struct gtphdr *)(skb->data + sizeof(struct udphdr));
if ((gtp1->flags >> 5) != GTP_V1)
return 1; /* not GTPv1 */
if (gtp1->type != GTP_TPDU)
return 1; /* not T-PDU (user data) */
/* TEID로 PDP context (세션) 조회 */
pctx = gtp1_pdp_find(gtp, ntohl(gtp1->tid));
if (!pctx)
return -1; /* unknown TEID */
/* outer 헤더 제거, inner IP 패킷 노출 */
skb_pull(skb, hdrlen);
/* inner 패킷을 GTP 인터페이스(gtp0)로 수신 처리 */
skb->dev = gtp->dev;
netif_rx(skb);
return 0;
}
TC flower로 GTP-U 매칭
커널 5.7부터 TC flower는 enc_key_id 필드로 GTP-U의 TEID를 매칭할 수 있습니다. 이를 통해 특정 TEID(가입자 세션)에 대한 정책을 TC flower 규칙으로 설정할 수 있습니다.
# TC flower로 GTP-U TEID 매칭
# enc_key_id = TEID (tunnel key)
# 1. GTP-U 터널의 특정 TEID에 대한 트래픽 미러링
tc filter add dev eth0 ingress protocol ip \
flower \
enc_key_id 0x12345678 \
enc_dst_port 2152 \
action mirred egress mirror dev mon0
# 2. 특정 TEID의 inner IP 기반 ACL
tc filter add dev eth0 ingress protocol ip \
flower \
enc_key_id 0x12345678 \
enc_dst_port 2152 \
enc_src_ip 192.168.1.100 \
ip_proto tcp \
dst_port 443 \
action pass
# 3. tunnel_key 액션으로 GTP-U decap
tc filter add dev eth0 ingress protocol ip \
flower \
enc_dst_port 2152 \
action tunnel_key unset \
action mirred egress redirect dev gtp_decap0
# 4. 결합: GTP decap + conntrack + NAT
tc filter add dev eth0 ingress protocol ip \
flower \
enc_dst_port 2152 \
enc_key_id 0x12345678 \
action tunnel_key unset \
action ct zone 100 \
action ct commit zone 100 nat src addr 203.0.113.1 \
action mirred egress redirect dev eth1
enc_* 접두사로 외부(Outer) 헤더 필드를, 접두사 없는 필드로 내부(Inner) 헤더를 매칭합니다. 예를 들어 enc_key_id 0x12345678 dst_ip 10.0.0.1은 "TEID가 0x12345678이고 내부 목적지 IP가 10.0.0.1인 패킷"을 의미합니다. 이를 통해 TEID(가입자) + 내부 서비스(목적지) 조합으로 세밀한 정책을 설정할 수 있습니다.
GTP-U HW 오프로드 구현
NVIDIA ConnectX-7(BlueField-3)은 GTP-U 하드웨어 디캡슐레이션을 지원하는 대표적인 SmartNIC입니다. GTP-U decap을 TC flower와 결합하면 디캡슐레이션, conntrack, NAT, ACL을 단일 HW 파이프라인에서 처리할 수 있습니다.
NVIDIA ConnectX-7 GTP-U 오프로드
# ConnectX-7 eSwitch 모드 설정
devlink dev eswitch set pci/0000:03:00.0 mode switchdev
# GTP-U decap offload 활성화
# representor 인터페이스에서 GTP-U 터널 매칭
# 1단계: GTP-U decap + inner 패킷 추출
tc filter add dev eth0_rep ingress protocol ip \
flower \
enc_dst_port 2152 \
enc_key_id 0x12345678 \
action tunnel_key unset pipe \
action goto chain 1
# 2단계: chain 1에서 inner 패킷에 대해 conntrack
tc filter add dev eth0_rep ingress chain 1 protocol ip \
flower \
ct_state -trk \
action ct zone 100 pipe \
action goto chain 2
# 3단계: chain 2에서 ESTABLISHED 세션 offload
tc filter add dev eth0_rep ingress chain 2 protocol ip \
flower \
ct_state +trk+est \
action ct commit zone 100 nat pipe \
action tunnel_key set \
id 0x87654321 \
dst_ip 10.100.1.1 \
dst_port 2152 \
action mirred egress redirect dev eth1_rep
# NEW 세션은 SW로 (Slow Path)
tc filter add dev eth0_rep ingress chain 2 protocol ip \
flower \
ct_state +trk+new \
action trap
위 규칙이 eSwitch FDB에 설치되면, 확립된 GTP-U 세션의 패킷은 다음 HW 파이프라인을 거칩니다:
ConnectX-7 HW 파이프라인 (GTP-U offload):
NIC RX → TEID 매칭 → GTP-U decap → inner IP 추출
→ CT lookup (zone 100) → EST 매칭 → NAT rewrite
→ GTP-U encap (new TEID) → TX → Wire
전체 과정이 NIC 하드웨어에서 완료 (CPU 개입 없음)
지연(Latency): ~5μs (SW 경로 대비 1/100)
Stateful GTP 검사 파이프라인
완전한 5G NGFW HW 오프로드 파이프라인은 다음 요소를 결합합니다:
| 파이프라인 단계 | HW 처리 | SW 처리 (Slow Path만) | TC flower 액션 |
|---|---|---|---|
| GTP-U 디캡슐레이션 | tunnel_key unset | gtp.ko decap | action tunnel_key unset |
| TEID → 가입자 매핑 | enc_key_id 매칭 | PDP context 조회 | flower enc_key_id |
| Inner ACL | eSwitch FDB 규칙 | nftables 규칙 | flower ip_proto dst_port |
| conntrack | CT HW offload | nf_conntrack | action ct zone |
| NAT | HW NAT rewrite | nf_nat | action ct commit nat |
| DPI/IPS | 불가 (SW only) | NFQUEUE → Suricata | action trap (첫 패킷) |
| GTP-U 재캡슐레이션 | tunnel_key set | gtp.ko encap | action tunnel_key set |
| QoS 마킹 | DSCP rewrite | tc-skbedit | action skbedit priority |
action trap으로 CPU에 전달되어 DPI 분류를 받은 후, ESTABLISHED + ALLOW 판정이 나면 HW offload로 전환됩니다. DPI가 지속적으로 필요한 트래픽(예: 스트리밍 DRM 검증)은 오프로드에서 제외해야 합니다.
5G NGFW 오프로드 성능 특성
5G NGFW 오프로드의 성능은 가입자 세션 밀도, GTP-U 오버헤드, 오프로드 비율에 따라 크게 달라집니다.
가입자 세션 밀도
5G UPF의 가입자 세션 규모는 다음과 같습니다:
| 배치 규모 | 동시 가입자 세션 | 동시 TEID 수 | CPS 요구량 | NGFW 요구 사양 |
|---|---|---|---|---|
| 소규모 (Edge) | 1만~5만 | 2만~10만 | 5K~20K | 10GbE SmartNIC 1개 |
| 중규모 (Regional) | 5만~50만 | 10만~100만 | 20K~100K | 25GbE SmartNIC 2개 |
| 대규모 (Central) | 50만~200만 | 100만~400만 | 100K~500K | 100GbE DPU 또는 전용 ASIC |
GTP-U 오버헤드 분석
| 항목 | 바이트 | 비율 (1500B 기준) | 비고 |
|---|---|---|---|
| Outer Ethernet | 14B | 0.9% | L2 프레임 헤더 |
| Outer IP (IPv4) | 20B | 1.3% | IPv6이면 40B (2.7%) |
| Outer UDP | 8B | 0.5% | dst port 2152 |
| GTP-U 헤더 (최소) | 8B | 0.5% | E=S=PN=0 |
| GTP-U 헤더 (5G 확장) | 12~16B | 0.8~1.1% | QFI 확장 헤더 포함 |
| 총 오버헤드 (IPv4, 최소) | 50B | 3.3% | |
| 총 오버헤드 (IPv6, 5G 확장) | 76B | 5.1% | 최악의 경우 |
SW 전용 vs HW 오프로드 성능 비교
| 측정 항목 | SW 전용 (gtp.ko + nftables) | HW 오프로드 (ConnectX-7 TC flower) | 개선 비율 |
|---|---|---|---|
| GTP-U decap 처리량 | 12~18 Gbps | 100+ Gbps (라인 레이트) | 6~8× |
| GTP-U decap + conntrack | 8~14 Gbps | 100+ Gbps | 7~12× |
| GTP-U decap + CT + NAT | 6~10 Gbps | 100+ Gbps | 10~16× |
| GTP-U decap + DPI (Suricata) | 2~5 Gbps | N/A (DPI는 SW only) | - |
| 패킷당 지연 (Latency) | 50~200 μs | 3~10 μs | 10~50× |
| CPU 사용률 (100Gbps) | 16+ 코어 (100%) | 0~2 코어 (EST 세션) | 8~16× |
| CPS (Slow Path) | 50K~200K | 50K~200K (변동 없음) | 1× (동일) |
| 동시 오프로드 세션 | SW flowtable 한계 | 1M~4M (eSwitch FDB) | HW 테이블 크기 |
| 전력 소비 | 200~400W (서버) | 15~25W (SmartNIC) | 10~20× |
오프로드 효과 분석
HW 오프로드의 효과는 트래픽 프로파일(Profile)에 따라 달라집니다:
처리량 모델 (100Gbps 환경):
총 트래픽: 100 Gbps
시나리오 1: 오프로드 비율 0% (SW 전용)
CPU 필요: 100Gbps ÷ 10Gbps/코어 = 10코어 (GTP decap + CT + NAT)
DPI 추가 시: 100Gbps ÷ 3Gbps/코어 = 33코어
→ 총 33+ CPU 코어 필요 (불가능에 가까움)
시나리오 2: 오프로드 비율 80%
HW 처리: 80 Gbps (CPU 부하 없음)
SW 처리: 20 Gbps → 20 ÷ 10 = 2코어 (EST)
DPI (새 세션만): ~5 Gbps → 5 ÷ 3 = 2코어
→ 총 4 CPU 코어로 100Gbps 처리 가능
시나리오 3: 오프로드 비율 90%
HW 처리: 90 Gbps
SW 처리: 10 Gbps → 1코어 (EST) + 1코어 (DPI)
→ 총 2 CPU 코어로 100Gbps 처리 가능
암/복호화 트래픽 HW 오프로드
이 주제는 별도 페이지로 분리되었습니다: NGFW 암/복호화 HW 오프로드 — kTLS, IPSec, MACsec, Intel QAT, SSL Inspection 파이프라인 심층 가이드
Regex/DPI 하드웨어 가속 엔진
NGFW의 핵심 기능인 심층 패킷 검사(DPI, Deep Packet Inspection)는 네트워크 트래픽의 페이로드(Payload)를 정규식(Regular Expression) 패턴으로 분석하여 악성 코드, 침입 시도, 애플리케이션 프로토콜을 식별합니다. 이 과정은 CPU 집약적이며, 10Gbps 이상의 환경에서 소프트웨어만으로는 라인 레이트 처리가 불가능합니다. 이 절에서는 정규식 매칭의 비용 구조와 하드웨어 가속 엔진 3종(NVIDIA RXP, Marvell REE, Intel Hyperscan+QAT)의 아키텍처 및 통합 방법을 다룹니다.
NGFW에서 정규식 매칭의 비용
IDS/IPS 엔진(Suricata, Snort)의 CPU 프로파일링(Profiling) 데이터를 보면, 멀티 패턴 매칭(Multi-Pattern Matching, MPM)이 전체 CPU 사이클의 40~60%를 소비합니다. 이는 수천 개의 시그니처(Signature)를 동시에 매칭해야 하기 때문입니다.
| 오토마톤 유형 | 시간 복잡도 | 메모리 사용 | 특성 | 대표 구현 |
|---|---|---|---|---|
| DFA (Deterministic Finite Automaton) | O(n) — 입력 길이에 비례 | O(2^m) — 상태 폭발 가능 | 예측 가능한 처리 시간, 메모리 집약적 | 하드웨어 엔진 (RXP, REE) |
| NFA (Non-deterministic Finite Automaton) | O(n×m) — 최악 시 패턴 수에 비례 | O(m) — 패턴 크기에 비례 | 메모리 효율적, 처리 시간 가변적 | PCRE, RE2 |
| Hybrid DFA/NFA | O(n) 평균, 일부 NFA 폴백 | 중간 | DFA 이점 + NFA 폴백으로 상태 폭발 회피 | Hyperscan, Suricata MPM |
다음 명령으로 Suricata 프로세스의 CPU 프로파일을 수집할 수 있습니다.
# perf를 이용한 Suricata CPU 프로파일링 (30초 샘플링)
sudo perf record -g -p $(pidof suricata) -- sleep 30
sudo perf report --sort=dso,symbol --stdio | head -60
# 특정 함수별 CPU 비중 확인
sudo perf report --stdio --sort=symbol | grep -E "(SCACSearch|MpmSearch|DetectMatch)"
# bpftrace로 MPM 함수 레이턴시 분포 확인
sudo bpftrace -e '
uprobe:/usr/bin/suricata:SCACSearch {
@start[tid] = nsecs;
}
uretprobe:/usr/bin/suricata:SCACSearch /@start[tid]/ {
@latency_ns = hist(nsecs - @start[tid]);
delete(@start[tid]);
}
interval:s:10 { exit(); }
'
# flamegraph 생성 (CPU 핫스팟 시각화)
sudo perf script | stackcollapse-perf.pl | flamegraph.pl > suricata-flame.svg
perf report 결과에서 SCACSearch(Aho-Corasick), hs_scan(Hyperscan), pcre2_match(PCRE2) 함수가 상위에 나타나면 정규식 매칭이 병목입니다. 이러한 워크로드가 전체의 30%를 초과하면 하드웨어 가속 도입을 검토해야 합니다.
10Gbps 이상 환경에서 하드웨어 가속이 중요한 이유를 정리하면 다음과 같습니다.
- 결정론적 레이턴시: DFA 기반 하드웨어 엔진은 O(n) 처리 시간을 보장하므로, NFA 폴백으로 인한 지연 스파이크(Latency Spike)가 발생하지 않습니다.
- CPU 오프로드: 정규식 매칭을 전용 하드웨어에 위임하면 CPU 코어를 세션 관리, 정책 판단, 로깅 등 다른 작업에 할당할 수 있습니다.
- 확장성: 트래픽 증가 시 CPU 코어를 추가하는 것보다 하드웨어 엔진의 병렬 처리 유닛을 활용하는 것이 전력 효율과 비용 면에서 유리합니다.
- 일관된 처리량: 소프트웨어 MPM은 패턴 집합 크기에 따라 성능이 변동하지만, 하드웨어 엔진은 수만 개 패턴에서도 안정적인 처리량을 유지합니다.
NVIDIA BlueField-3 RXP 엔진
NVIDIA BlueField-3 DPU에 내장된 RXP(RegEx Processing Unit)는 하드웨어 DFA 기반 정규식 가속 엔진입니다. 최대 400Gbps의 정규식 매칭 처리량을 제공하며, DOCA(Data Center Infrastructure on a Chip Architecture) SDK를 통해 프로그래밍합니다.
| 항목 | 사양 |
|---|---|
| 엔진 아키텍처 | 하드웨어 DFA + NFA 폴백 하이브리드 |
| 최대 처리량 | 최대 400Gbps (BlueField-3 기준) |
| 최대 규칙 수 | 수만 개 PCRE 호환 패턴 |
| 레이턴시 | 결정론적 — 패턴 수에 무관 |
| 컴파일러 | rxpc — PCRE 패턴 → RXP 바이너리 규칙 |
| API | DOCA RegEx API (doca_regex) |
| 배치 처리 | 복수 버퍼를 단일 요청으로 일괄 제출 |
RXP 엔진의 워크플로는 다음과 같습니다.
- 규칙 컴파일:
rxpc컴파일러가 PCRE 형식의 정규식 패턴 파일(.rules)을 RXP 하드웨어가 이해하는 바이너리 규칙 파일(.rxp)로 변환합니다. - 엔진 초기화: DOCA RegEx 컨텍스트를 생성하고, 컴파일된 규칙을 RXP 엔진에 로드합니다.
- 배치 제출: 검사할 패킷 버퍼들을 배치(Batch)로 묶어 RXP 엔진에 비동기 제출합니다.
- 결과 수집: 폴링(Polling) 또는 이벤트 기반으로 매칭 결과를 수집하고, 매칭된 규칙 ID와 오프셋 정보를 확인합니다.
# rxpc를 이용한 규칙 컴파일
# 입력: PCRE 패턴 파일, 출력: RXP 바이너리 규칙
rxpc -f suricata_patterns.rules -o compiled_rules.rxp \
--max-rules 10000 \
--optimize-level 3
# 컴파일 결과 통계 확인
rxpc -f suricata_patterns.rules --stats-only
# 출력 예: Total rules: 8432, DFA states: 124567, Memory: 48MB
다음은 DOCA RegEx API를 사용한 정규식 하드웨어 가속 코드 예제입니다.
#include <doca_regex.h>
#include <doca_buf.h>
#include <doca_ctx.h>
#include <doca_dev.h>
#include <doca_error.h>
#include <doca_log.h>
DOCA_LOG_REGISTER(REGEX_DPI);
#define MAX_BATCH_SIZE 256
#define MAX_MATCHES 16
struct regex_dpi_ctx {
struct doca_dev *dev;
struct doca_regex *regex;
struct doca_ctx *ctx;
struct doca_pe *pe; /* Progress engine */
struct doca_buf_arr *buf_arr;
struct doca_mmap *mmap;
uint32_t total_matches;
uint32_t total_scanned;
};
/* 매칭 완료 콜백 — 비동기 결과 처리 */
static void regex_task_completion_cb(struct doca_regex_task_search *task,
union doca_data task_user_data,
union doca_data ctx_user_data)
{
struct regex_dpi_ctx *dpi = (struct regex_dpi_ctx *)ctx_user_data.ptr;
struct doca_regex_search_result *result;
uint32_t num_matches = 0;
doca_error_t err;
err = doca_regex_task_search_get_result(task, &result);
if (err != DOCA_SUCCESS) {
DOCA_LOG_WARN("regex result retrieval failed: %s",
doca_error_get_descr(err));
goto cleanup;
}
num_matches = doca_regex_search_result_get_num_matches(result);
if (num_matches > 0) {
dpi->total_matches += num_matches;
/* 매칭된 각 규칙 ID와 오프셋 순회 */
for (uint32_t i = 0; i < num_matches && i < MAX_MATCHES; i++) {
struct doca_regex_match *match;
doca_regex_search_result_get_match(result, i, &match);
uint32_t rule_id = doca_regex_match_get_rule_id(match);
uint32_t offset = doca_regex_match_get_offset(match);
uint32_t length = doca_regex_match_get_length(match);
DOCA_LOG_DBG("Match: rule=%u offset=%u len=%u",
rule_id, offset, length);
}
}
dpi->total_scanned++;
cleanup:
doca_task_free(doca_regex_task_search_as_task(task));
}
/* RXP 엔진 초기화: 디바이스 탐색, 규칙 로드, 컨텍스트 생성 */
static doca_error_t init_regex_engine(struct regex_dpi_ctx *dpi,
const char *rules_path)
{
doca_error_t err;
/* BlueField DPU의 RegEx 디바이스 열기 */
err = doca_dev_open_by_capability(DOCA_DEV_CAP_REGEX, &dpi->dev);
if (err != DOCA_SUCCESS) {
DOCA_LOG_ERR("RegEx device not found: %s",
doca_error_get_descr(err));
return err;
}
/* DOCA RegEx 인스턴스 생성 */
err = doca_regex_create(dpi->dev, &dpi->regex);
if (err != DOCA_SUCCESS)
return err;
/* 컴파일된 규칙 파일 로드 */
err = doca_regex_set_hardware_compiled_rules(dpi->regex, rules_path);
if (err != DOCA_SUCCESS) {
DOCA_LOG_ERR("Failed to load rules from %s", rules_path);
return err;
}
/* Progress Engine 생성 (비동기 태스크 관리) */
err = doca_pe_create(&dpi->pe);
if (err != DOCA_SUCCESS)
return err;
/* 컨텍스트 연결 및 시작 */
dpi->ctx = doca_regex_as_ctx(dpi->regex);
err = doca_pe_connect_ctx(dpi->pe, dpi->ctx);
if (err != DOCA_SUCCESS)
return err;
/* 완료 콜백 설정 */
union doca_data user_data = { .ptr = dpi };
err = doca_regex_task_search_set_conf(
dpi->regex,
regex_task_completion_cb, /* 성공 콜백 */
regex_task_completion_cb, /* 에러 콜백 */
MAX_BATCH_SIZE);
if (err != DOCA_SUCCESS)
return err;
err = doca_ctx_set_user_data(dpi->ctx, user_data);
if (err != DOCA_SUCCESS)
return err;
return doca_ctx_start(dpi->ctx);
}
/* 패킷 버퍼 배치를 RXP 엔진에 제출 */
static doca_error_t submit_packet_batch(struct regex_dpi_ctx *dpi,
void **pkt_bufs,
uint32_t *pkt_lens,
int count)
{
doca_error_t err;
for (int i = 0; i < count; i++) {
struct doca_regex_task_search *task;
struct doca_buf *buf;
/* 패킷 데이터를 DOCA 버퍼에 매핑 */
err = doca_buf_arr_get_buf(dpi->buf_arr, i, &buf);
if (err != DOCA_SUCCESS)
continue;
doca_buf_set_data(buf, pkt_bufs[i], pkt_lens[i]);
/* 검색 태스크 생성 및 제출 */
union doca_data task_data = { .u64 = i };
err = doca_regex_task_search_alloc_init(
dpi->regex, buf, task_data, &task);
if (err != DOCA_SUCCESS)
continue;
err = doca_task_submit(
doca_regex_task_search_as_task(task));
if (err != DOCA_SUCCESS) {
doca_task_free(doca_regex_task_search_as_task(task));
continue;
}
}
/* Progress Engine 폴링 — 완료된 태스크의 콜백 호출 */
while (dpi->total_scanned < (uint32_t)count) {
(void)doca_pe_progress(dpi->pe);
}
return DOCA_SUCCESS;
}
rxpc)는 대부분의 PCRE 구문을 지원하지만, 역참조(Back-reference), 재귀 패턴(Recursive Pattern), 무제한 반복(Unbounded Repetition) 등 일부 고급 기능은 지원하지 않습니다. Suricata 시그니처를 변환할 때 rxpc --check-only 옵션으로 호환성을 사전 검증해야 합니다.
Marvell REE (RegEx Engine)
Marvell OCTEON CN10K SoC에 내장된 REE(RegEx Engine)는 하드웨어 DFA/NFA 하이브리드 정규식 코프로세서(Coprocessor)입니다. DPDK의 rte_regexdev API를 통해 접근하며, 이벤트 기반 비동기 처리 모델을 지원합니다.
| 항목 | NVIDIA RXP (BlueField-3) | Marvell REE (CN10K) |
|---|---|---|
| 기반 하드웨어 | DPU (SmartNIC) | 네트워크 SoC (OCTEON) |
| 오토마톤 | 하드웨어 DFA + NFA 폴백 | DFA/NFA 하이브리드 |
| 프로그래밍 인터페이스 | DOCA RegEx API | DPDK rte_regexdev API |
| 규칙 컴파일 | rxpc CLI 도구 | roc-re 컴파일러 / REE SDK |
| 배치 처리 | DOCA Progress Engine | DPDK eventdev 연동 |
| 최대 규칙 수 | 수만 개 | 수만 개 |
| 통합 대상 | DOCA DPI 프레임워크 | DPDK 인라인 파이프라인 |
DPDK rte_regexdev API의 핵심 구성 요소는 다음과 같습니다.
rte_regexdev_configure(): REE 디바이스를 초기화하고 큐 수, 규칙 DB 크기 등을 설정합니다.rte_regexdev_rule_db_update(): 컴파일된 규칙을 하드웨어에 로드합니다.rte_regexdev_enqueue_burst(): 검사 대상 버퍼를 배치로 제출합니다.rte_regexdev_dequeue_burst(): 완료된 매칭 결과를 배치로 수집합니다.- eventdev 연동:
rte_event_regex_adapter를 통해 이벤트 기반 비동기 파이프라인에 통합합니다.
#include <rte_regexdev.h>
#include <rte_mbuf.h>
#include <rte_log.h>
#define REGEX_DEV_ID 0
#define REGEX_QP_ID 0
#define BATCH_SIZE 64
#define MAX_MATCHES 8
/* REE 디바이스 초기화 및 규칙 로드 */
static int init_ree_device(const char *rules_file)
{
struct rte_regexdev_config cfg = {
.nb_queue_pairs = 4,
.nb_max_matches = MAX_MATCHES,
.nb_rules = 10000,
.rule_db_len = 0, /* 자동 감지 */
.dev_cfg_flags = 0,
};
struct rte_regexdev_info dev_info;
int ret;
/* 디바이스 정보 조회 */
ret = rte_regexdev_info_get(REGEX_DEV_ID, &dev_info);
if (ret < 0) {
RTE_LOG(ERR, USER1, "REE device info failed: %d\n", ret);
return ret;
}
RTE_LOG(INFO, USER1, "REE device: %s, max_rules=%u\n",
dev_info.driver_name, dev_info.max_rules);
/* 디바이스 설정 */
ret = rte_regexdev_configure(REGEX_DEV_ID, &cfg);
if (ret < 0)
return ret;
/* 규칙 DB 업데이트 — 컴파일된 바이너리 규칙 로드 */
struct rte_regexdev_rule *rules;
uint32_t nb_rules;
/* 규칙 파일 파싱 (실제 구현에서는 파일 I/O) */
ret = load_compiled_rules(rules_file, &rules, &nb_rules);
if (ret < 0)
return ret;
ret = rte_regexdev_rule_db_update(REGEX_DEV_ID,
rules, nb_rules);
if (ret < 0)
return ret;
ret = rte_regexdev_rule_db_compile_activate(REGEX_DEV_ID);
if (ret < 0)
return ret;
/* 큐 페어 설정 */
struct rte_regexdev_qp_conf qp_conf = {
.nb_desc = 1024,
.qp_conf_flags = RTE_REGEX_QUEUE_PAIR_CFG_OOS_F,
};
ret = rte_regexdev_queue_pair_setup(REGEX_DEV_ID,
REGEX_QP_ID, &qp_conf);
if (ret < 0)
return ret;
return rte_regexdev_start(REGEX_DEV_ID);
}
/* 패킷 배치를 REE 엔진에 제출하고 결과 수집 */
static int process_packet_batch(struct rte_mbuf **pkts,
uint16_t nb_pkts,
uint32_t *match_flags)
{
struct rte_regex_ops *ops[BATCH_SIZE];
struct rte_regex_ops *results[BATCH_SIZE];
uint16_t enqueued, dequeued;
int i;
/* 검색 오퍼레이션 생성 */
for (i = 0; i < nb_pkts && i < BATCH_SIZE; i++) {
ops[i] = rte_malloc(NULL, sizeof(struct rte_regex_ops), 0);
if (!ops[i])
return -ENOMEM;
ops[i]->mbuf = pkts[i];
ops[i]->group_id0 = 0; /* 규칙 그룹 ID */
ops[i]->user_id = i; /* 패킷 식별자 */
ops[i]->req_flags = 0;
}
/* 배치 제출 (enqueue) */
enqueued = rte_regexdev_enqueue_burst(REGEX_DEV_ID,
REGEX_QP_ID,
ops, nb_pkts);
/* 결과 수집 (dequeue) — 폴링 루프 */
dequeued = 0;
while (dequeued < enqueued) {
uint16_t n = rte_regexdev_dequeue_burst(
REGEX_DEV_ID, REGEX_QP_ID,
results + dequeued,
enqueued - dequeued);
dequeued += n;
}
/* 매칭 결과 처리 */
for (i = 0; i < dequeued; i++) {
uint16_t nb_matches = results[i]->nb_matches;
uint32_t pkt_idx = results[i]->user_id;
if (nb_matches > 0) {
match_flags[pkt_idx] = 1;
for (uint16_t m = 0; m < nb_matches; m++) {
struct rte_regexdev_match *match;
match = &results[i]->matches[m];
RTE_LOG(DEBUG, USER1,
"pkt[%u] match: rule=%u off=%u len=%u\n",
pkt_idx, match->rule_id,
match->start_offset, match->len);
}
} else {
match_flags[pkt_idx] = 0;
}
rte_free(results[i]);
}
return dequeued;
}
rte_event_regex_adapter를 사용하면 REE 엔진의 완료 이벤트를 eventdev 큐에 자동으로 전달할 수 있습니다. 이 방식은 폴링 루프 대신 이벤트 기반으로 CPU 효율을 높이며, 암호화(crypto)·압축(compress) 등 다른 하드웨어 가속기와 동일한 이벤트 파이프라인에서 조합할 수 있습니다.
Hyperscan + Intel QAT 가속
Hyperscan은 Intel이 개발한 고성능 정규식 매칭 라이브러리로, SIMD(SSE4.2/AVX2/AVX-512) 명령어를 활용한 멀티 패턴 매칭을 제공합니다. 전용 하드웨어가 아닌 CPU 기반이지만, 하드웨어 수준에 근접하는 성능을 달성합니다. Intel QAT(QuickAssist Technology)와 조합하면 암호 해제 + 정규식 매칭 파이프라인을 구성할 수 있습니다.
| 모드 | 설명 | 사용 사례 |
|---|---|---|
| Block 모드 | 단일 버퍼를 한 번에 스캔 | 개별 패킷 페이로드 검사 |
| Streaming 모드 | 여러 버퍼에 걸친 연속 스캔 (상태 유지) | TCP 스트림 재조립 후 검사 |
| Vectored 모드 | 비연속 버퍼 세트를 논리적으로 연결하여 스캔 | scatter-gather 버퍼 검사 |
Hyperscan의 핵심 장점은 다음과 같습니다.
- 멀티 패턴 동시 매칭: 수만 개 패턴을 단일 패스(Single Pass)로 매칭합니다.
- SIMD 최적화: AVX-512 기반 DFA 시뮬레이션으로 코어당 수 Gbps 처리를 달성합니다.
- Chimera 모드: Hyperscan + PCRE 폴백을 결합하여 호환성과 성능을 모두 확보합니다.
- 사전 컴파일: 패턴 DB를 바이트코드로 사전 컴파일하여 런타임 오버헤드를 제거합니다.
Suricata에서 Hyperscan MPM을 활성화하는 설정 예제입니다.
# /etc/suricata/suricata.yaml — Hyperscan MPM 설정
# Multi-Pattern Matching 엔진 선택
mpm-algo: hs # 'ac' (Aho-Corasick) 대신 'hs' (Hyperscan)
# 패턴 매칭 상세 설정
detect:
profile: high # high = 더 많은 메모리, 더 빠른 매칭
sgh-mpm-context: full # 시그니처 그룹별 독립 MPM 컨텍스트
inspection-recursion-limit: 3000
# Hyperscan 관련 상세 설정
# Suricata 빌드 시 --enable-hyperscan 필요
# 의존성: libhs-dev (Intel Hyperscan 라이브러리)
# Intel QAT 암호 해제 가속 (AF_ALG 또는 OpenSSL QAT engine)
# TLS 복호화 → Hyperscan 매칭 파이프라인
app-layer:
protocols:
tls:
enabled: yes
detection-ports:
dp: 443
# QAT 가속 OpenSSL 엔진 사용 시 별도 설정 필요
# Suricata 빌드 시 Hyperscan 활성화
./configure --enable-hyperscan \
--with-libhs-includes=/usr/include/hs \
--with-libhs-libraries=/usr/lib/x86_64-linux-gnu
# Hyperscan 성능 벤치마크
# hsbench: Hyperscan 공식 벤치마크 도구
hsbench -e /path/to/patterns.db \
-c /path/to/corpus/ \
-T 8 # 8 스레드
# Intel QAT 디바이스 확인
lspci | grep "QuickAssist"
# 출력 예: 0000:6b:00.0 Co-processor: Intel Corporation
# C62x Chipset QuickAssist Technology
# QAT 상태 확인
adf_ctl status
# 출력 예: qat_dev0 - type: c6xx, state: up
# QAT OpenSSL 엔진 설정 확인
openssl engine -t qatengine
# 출력 예: (qatengine) Reference implementation of QAT engine
# [ available ]
Regex HW와 NGFW 파이프라인 통합 패턴
정규식 하드웨어 가속 엔진을 NGFW 파이프라인에 효율적으로 통합하려면 2단계 필터링 모델을 사용합니다. 모든 패킷을 하드웨어 정규식 엔진에 보내는 것은 비효율적이므로, 저비용 사전 필터(Pre-filter)로 후보를 먼저 선별하고, 후보 패킷만 정밀 매칭 엔진에 전달합니다.
| 단계 | 처리 위치 | 알고리즘 | 비용 | 정확도 | 목적 |
|---|---|---|---|---|---|
| 1단계 — Pre-filter | CPU (SIMD) 또는 NIC HW | 블룸 필터(Bloom Filter), 해시 매칭 | 매우 낮음 (ns/pkt) | 위양성 있음 (false positive) | 빠른 거부 (fast reject) |
| 2단계 — Exact Match | Regex HW 엔진 | DFA/NFA 정규식 매칭 | 높음 (μs/pkt) | 정확 | 정밀 시그니처 판정 |
이 2단계 모델의 핵심은 1단계에서 대부분의 정상 트래픽을 빠르게 통과시키고(95~99%), 의심 트래픽(1~5%)만 2단계 하드웨어 엔진으로 전달하는 것입니다.
- 블룸 필터 사전 필터: 시그니처에서 추출한 고정 문자열(Literal)로 블룸 필터를 구성합니다. 블룸 필터에 히트되지 않으면 해당 패킷은 어떤 시그니처와도 매칭되지 않으므로 즉시 통과(PASS)합니다.
- 위양성 처리: 블룸 필터는 위양성(False Positive)이 존재하므로, 1단계를 통과한 패킷이 2단계에서 실제로 매칭되지 않을 수 있습니다. 이는 정상적인 동작이며, 블룸 필터 크기와 해시 함수 수를 조정하여 위양성 비율을 0.1~1% 수준으로 관리합니다.
- XDP/TC 기반 인라인 통합: 1단계 사전 필터를 XDP 또는 TC BPF 프로그램에 구현하면, 커널 네트워크 스택에 진입하기 전에 필터링할 수 있습니다.
- NFQUEUE 기반 통합: Netfilter의
NFQUEUE를 통해 패킷을 사용자 공간으로 전달하고, regex HW 엔진으로 검사한 후NF_ACCEPT또는NF_DROP판정을 반환합니다.
| 통합 방식 | 장점 | 단점 | 적합 환경 |
|---|---|---|---|
| XDP/TC + Regex HW | 최소 레이턴시, 커널 바이패스 가능 | 구현 복잡, BPF 제약 | SmartNIC/DPU 기반 인라인 DPI |
| NFQUEUE + Regex HW | 기존 Netfilter 파이프라인 재활용 | 사용자 공간 복사 오버헤드 | 기존 IDS/IPS에 HW 가속 추가 |
| DPDK 인라인 | 최고 처리량, zero-copy | 커널 바이패스로 모니터링 제한 | 전용 DPI 어플라이언스 |
HS_FLAG_PREFILTER 플래그는 이 목적에 최적화되어 있으며, 사전 필터용 경량 DFA를 별도로 생성합니다. 사전 필터 히트율(Hit Rate)이 5%를 초과하면 블룸 필터 크기를 늘리거나 리터럴 추출 전략을 재검토해야 합니다.
위 다이어그램은 2단계 DPI 파이프라인의 전체 흐름을 보여줍니다. 1단계 사전 필터에서 95~99%의 정상 트래픽을 즉시 통과시키고, 나머지 1~5%의 의심 트래픽만 2단계 Regex HW 엔진으로 전달합니다. 2단계에서도 위양성 패킷은 PASS로 처리되며, 실제 시그니처 매칭이 확인된 패킷만 DROP/LOG/ALERT 정책을 적용합니다.
상용 NGFW HW 아키텍처
이 주제는 별도 페이지로 분리되었습니다: 상용 NGFW HW 아키텍처 — Fortinet NP7, Palo Alto SP3, Check Point SecureXL, Juniper Express Path, Linux NGFW 비교
커널 NGFW 빌딩 블록
Linux 커널에서 NGFW를 구축할 때 사용하는 주요 서브시스템과 NGFW 기능 간의 매핑입니다. 각 서브시스템은 독립적으로 발전해 왔지만, NGFW에서는 이들을 하나의 통합 파이프라인으로 결합해야 합니다. 이 절에서는 각 서브시스템의 역할과 연동 포인트를 정리합니다.
- XDP: 가장 빠른 경로 (NIC 드라이버 직후). DDoS pre-filter, 명백한 악성 패킷 DROP
- TC flower + eSwitch: HW Fast Path. ESTABLISHED 세션의 라인레이트 전달
- nf_flowtable: SW Fast Path. HW 미지원 세션의 커널 내 가속
- nftables + conntrack: Slow Path. 새 세션의 정책 평가, 상태 추적
- NFQUEUE: 유저스페이스 DPI 연동. Suricata/nDPI로 패킷 전달
- xfrm: IPSec 처리. HW crypto offload 가능
- TC qdisc: QoS. 대역폭 제어, 우선순위 큐잉
| NGFW 기능 | 커널 서브시스템 | HW 오프로드 | 관련 페이지(Page) |
|---|---|---|---|
| Stateful ACL (L3/L4) | nftables + nf_conntrack | TC flower ct_state → eSwitch | Netfilter |
| NAT (SNAT/DNAT) | nf_nat | flowtable NAT offload / eSwitch NAT action | NAT |
| 세션 오프로드 (Fast Path) | nf_flowtable | NF_FLOWTABLE_HW_OFFLOAD → NIC flow table | Flowtable |
| DPI / IPS | NFQUEUE + 유저스페이스 DPI | 미오프로드 (CPU 처리) | NFQUEUE & DPI |
| DDoS Pre-filter | XDP BPF 프로그램 | XDP HW offload (지원 NIC) | BPF/XDP |
| HW Fast Path | TC flower + mlx5/ice eSwitch | eSwitch FDB rule 삽입 | eSwitch |
| IPSec VPN | xfrm | NIC inline crypto offload | IPSec & xfrm |
| QoS / Traffic Shaping | TC qdisc (HTB, TBF, fq_codel) | TC flower + skbedit → HW QoS queue | TC |
| ALG 프로토콜 | nf_conntrack_helper | 미오프로드 (CPU 필수) | conntrack 헬퍼 |
| 네트워크 격리 | network namespace / VRF | eSwitch VF representor | 네트워크 네임스페이스 |
HW 오프로드 인터페이스 전체 지도
Linux에서 "HW 오프로드 인터페이스"는 하나의 API가 아닙니다. 사용자 공간에서 보이는 명령은 ethtool, tc, nft, ip xfrm, ip macsec, ip link xdpoffload, devlink처럼 제각각이지만, 커널 내부에서는 결국 feature bit 토글, 객체 생성/삭제, 드라이버 콜백, 펌웨어/ASIC 프로그래밍으로 수렴합니다. NGFW 관점에서는 다음 표를 하나의 지도처럼 기억하는 것이 가장 중요합니다.
| 범주 | 사용자 공간 인터페이스 | 커널 핵심 오브젝트/콜백 | 오프로드 대상 | 대표 명령 | 실패 시 동작 |
|---|---|---|---|---|---|
| Feature 토글 | ethtool -k/-K | NETIF_F_*, ndo_fix_features, ndo_set_features, ndo_features_check | checksum, TSO/GSO, hw-tc-offload, tls-hw-*, esp-hw-offload | ethtool -K eth0 hw-tc-offload on | feature bit가 꺼지거나 per-skb 기준으로 SW 경로로 폴백합니다. |
| TC 분류/액션 | tc qdisc/filter/action | cls_flower, act_ct, act_mirred, act_police, TC_SETUP_CLSFLOWER, TC_SETUP_BLOCK, flow_block_cb, ndo_setup_tc | parser, ACL TCAM, FDB, queue steering, CT offload | tc filter add ... flower ... skip_sw | skip_sw가 없으면 소프트웨어 TC가 계속 처리합니다. |
| qdisc 스케줄러 | tc qdisc add mqprio/taprio/cbs/etf | TC_SETUP_QDISC_MQPRIO, 드라이버 qdisc offload 콜백 | HW 큐 매핑, TSN gate control, rate shaper | tc qdisc replace dev eth0 root mqprio ... hw 1 | HW 미지원이면 소프트웨어 qdisc가 유지됩니다. |
| Netfilter flowtable | nft add flowtable ... offload | nf_flowtable, nf_flow_offload_hw_add(), TC_SETUP_FT | ESTABLISHED 세션 전달, NAT rewrite | nft add flowtable inet fw ft { hook ingress priority 0; devices = { eth0 }; flags offload; } | HW 실패 시 nf_flowtable 소프트웨어 fast path로 남습니다. |
| Bridge / switchdev | bridge, ip link | switchdev_port_obj_add/del, switchdev_port_attr_set, ndo_fdb_add/del/dump, ndo_bridge_setlink/getlink | FDB, VLAN, MDB, learning, STP 상태 | bridge fdb add ... | 브리지 소프트웨어 경로가 그대로 동작하고 offloaded 플래그만 사라집니다. |
| Representor / SR-IOV | ip link set vf, devlink port | ndo_set_vf_*, ndo_get_phys_port_id, ndo_get_phys_port_name, ndo_get_port_parent_id | VF/SF 트래픽 가시화, 정책 연결점 | devlink port show pci/0000:03:00.0 | representor가 없으면 호스트가 VF 트래픽을 세밀하게 제어하기 어렵습니다. |
| XDP / BPF | ip link set xdpoffload, bpftool net | ndo_bpf, ndo_xdp_xmit, bpf_prog_offload | NIC 내장 코어 또는 드라이버 레벨 drop/redirect | ip link set dev eth0 xdpoffload obj xdp.o sec xdp | 미지원이면 xdpdrv 또는 xdpgeneric로 떨어집니다. |
| IPsec | ip xfrm state/policy ... offload | xfrm_state, xfrm_policy, xfrmdev_ops | ESP crypto offload, packet offload | ip xfrm state add ... offload packet dev eth0 dir out | 대부분 crypto offload 또는 SW xfrm로 폴백합니다. |
| kTLS | setsockopt(TCP_ULP,"tls"), ethtool -K tls-hw-* | tls_context, tlsdev_ops | TLS 레코드 계층 TX/RX 암·복호화 | ethtool -K eth0 tls-hw-tx-offload on | 자동으로 소프트웨어 kTLS(TLS_SW)로 전환합니다. |
| MACsec | ip macsec offload mac|phy | macsec_ops, SecY/SC/SA 오브젝트 | L2 프레임 암호화, SA/PN/XPN 테이블 | ip macsec offload macsec0 mac | 지원하지 않으면 에러를 반환하거나 소프트웨어 MACsec을 유지합니다. |
| devlink 제어면 | devlink dev/port/trap/health/resource | eSwitch 모드, trap, reporter, resource allocator | ASIC 포트 토폴로지, trap policer, health dump | devlink dev eswitch set ... mode switchdev | 데이터면 폴백이 아니라 "관리 불가" 상태가 됩니다. |
| 관찰/예외 경로 | ethtool -S, tc -s, nft list flowtable, conntrack -L, devlink trap show, devlink health show | HW 카운터, trap 그룹, health reporter, flow stats | 예외 패킷, HW 용량, 펌웨어 오류, offload hit ratio | devlink trap show pci/0000:03:00.0 | 폴백 원인을 추적하는 주 경로입니다. |
사용자 공간 UAPI 계열 전수 분류
NGFW에서 "커널이 제공하는 HW offload 인터페이스"를 빠짐없이 이해하려면, 먼저 사용자 공간에서 보이는 인터페이스를 능력 협상, 데이터 경로 프로그래밍, 프로토콜 상태 오프로드, 예외/관측 네 계열로 나눠 보는 것이 좋습니다. 이름은 제각각이지만, 실제로는 모두 netlink, socket option, feature bit, 드라이버 콜백으로 수렴합니다.
| 계열 | 대표 사용자 공간 진입점 | 커널이 만드는 공통 오브젝트 | HW에 내려가는 실체 | NGFW에서의 의미 | 비고 |
|---|---|---|---|---|---|
| 능력 협상 | ethtool -k/-K, ethtool --show-priv-flags | net_device feature bit, 채널 수, ring, coalesce, RSS | parser 모드, checksum/TLS/ESP enable bit, IRQ/RX 큐 문맥 | 오프로드를 "쓸 수 있는 상태"로 장비를 준비합니다. | 기능을 켜도 규칙이 자동 생성되지는 않습니다. |
| 분류/정책 프로그래밍 | tc filter, tc chain, tc action, tc qdisc | flow_rule, flow_action, qdisc offload 요청 | ACL TCAM, FDB 엔트리, meter/policer, queue map, trap rule | L2~L4 방화벽, NAT, Hairpin, QoS를 직접 HW에 설치합니다. | NGFW의 핵심 HW fast path 계약입니다. |
| 세션 경로 단축 | nft add flowtable ... flags offload | nf_flowtable, flow_offload, flow_block | ESTABLISHED 세션 캐시, NAT rewrite 문맥 | Slow Path에서 검증된 세션만 선택적으로 HW로 내립니다. | 정책 작성은 nftables, 실제 HW 설치는 TC/switchdev 계약을 재사용합니다. |
| 브리지/스위치 객체 | bridge fdb, bridge vlan, ip link set master | FDB, VLAN, MDB, bridge port attr, neigh | L2 forwarding table, VLAN admission, multicast replication | 투명 방화벽(L2 inline), VF 간 격리, East-West 보안에 필요합니다. | switchdev 지원 장비에서만 완전한 HW 동기화가 가능합니다. |
| 포트 토폴로지 | devlink port, ip link set vf | PF/VF/SF port object, representor 관계 | embedded switch 포트, 서브 함수(Sub Function), queue ownership | 테넌트별 정책을 어느 representor에 거는지 결정합니다. | OVS, SR-IOV, Kubernetes SR-IOV CNI가 이 계층에 의존합니다. |
| XDP / BPF | ip link set xdpoffload, bpftool prog load | bpf_prog, map, offload verifier 문맥 | NIC 내장 파이프라인의 drop/redirect/parser 프로그램 | DDoS pre-filter, 초반 드롭, 간단한 5-tuple 분류를 가장 앞단에서 처리합니다. | 모든 NIC가 XDP HW offload를 지원하지는 않습니다. |
| 암호화 프로토콜 | ip xfrm, setsockopt(TCP_ULP, "tls"), ip macsec | xfrm_state, tls_context, SecY/SA | SA table, TLS record context, MACsec PN/XPN 상태 | VPN, SSL 프록시 재암호화, uplink 보호를 HW로 내립니다. | 프로토콜별 계약이 다르므로 하나의 공통 API로 묶이지 않습니다. |
| 예외/관측 | devlink trap, devlink health, ethtool -S, tc -s, conntrack -L | trap group, reporter, HW counter, CT 상태 | miss 이유, drop 이유, 리소스 사용량, 예외 패킷 샘플 | 오프로드 실패 원인과 폴백 비율을 추적합니다. | 운영 안정성은 이 계층이 좌우합니다. |
| 사용자 공간 예외 경로 | NFQUEUE, psample, AF_XDP | queue verdict, sampled skb, XSK ring | 패킷 자체가 아니라 "예외 패킷 전달 경로"를 구성합니다. | DPI, IDS 샘플링, 초고속 사용자 공간 검사기를 결합할 때 사용합니다. | 직접적인 HW policy offload 계약은 아니지만 NGFW 전체 파이프라인에는 필수입니다. |
OVS, Suricata, DPDK, AF_XDP는 NGFW를 구성하는 데 매우 중요하지만, 그 자체가 NIC에 규칙을 내려 주는 표준 HW offload 계약은 아닙니다. OVS는 주로 TC/switchdev 계약 위에서 동작하고, Suricata와 NFQUEUE는 예외 경로를 담당하며, AF_XDP는 제로카피 예외 경로를 제공합니다.
패킷 경로별 부착 지점 지도
각 인터페이스는 패킷의 서로 다른 시점에 개입합니다. 이 위치를 잘못 이해하면 "XDP에서 이미 드롭된 패킷이 왜 NFQUEUE로 안 오느냐", "TLS offload를 켰는데 왜 TC 카운터와 상관이 없느냐" 같은 혼란이 생깁니다. 다음 그림은 NGFW에서 실제로 중요한 부착 지점을 시간 순서대로 보여 줍니다.
| 부착 지점 | 대표 인터페이스 | 생성되는 핵심 오브젝트 | HW가 맡기 좋은 일 | NGFW에서 흔한 한계 |
|---|---|---|---|---|
| skb 생성 이전 | ndo_bpf, xdpoffload | XDP 프로그램, map, redirect target | 조기 DROP, 간단한 rate limit, CPU 우회 redirect | conntrack, NAT, TCP 재조립, DPI는 불가능합니다. |
| ingress skb 직후 | tc flower, matchall, act_ct, act_mirred | flow_rule, flow_action | ACL, NAT, Hairpin, redirect, meter, sample | 드라이버별 지원 field/action 조합이 다릅니다. |
| Netfilter ingress hook | nft flowtable | flow_offload, flow_block | ESTABLISHED 세션의 빠른 전달과 NAT rewrite | ALG, fragment, 복잡한 tunnel, 일부 프로토콜은 제외됩니다. |
| Slow Path 중간 | nft, conntrack, NFQUEUE | nf_conn, chain, verdict queue | 정책 판정, 상태 생성, DPI verdict | 기본적으로 CPU 처리이며 HW offload의 "결정권"만 가집니다. |
| egress / scheduler | mqprio, taprio, police, skbedit | queue map, gate entry, meter profile | queue steer, shaping, TSN, 색상 기반 우선순위 | qdisc와 flower action의 조합은 장비별 차이가 큽니다. |
| 프로토콜/소켓 계층 | ip xfrm, TCP_ULP=tls | SA, policy, TLS offload context | ESP 암·복호화, TLS record 암·복호화 | 세션 수, 알고리즘, resync 능력이 HW 메모리에 제한됩니다. |
| 링크 계층 | ip macsec | SecY, RXSC, TXSA, PN/XPN 카운터 | L2 프레임 보호 | MACsec은 L3/L4 방화벽 정책의 대체가 아닙니다. |
| 예외/관측 | devlink trap, psample, ethtool -S | trap rule, trap policer, sample group, HW counter | miss 원인 전달, 샘플 export, 리소스 감시 | 이 경로가 많아질수록 사실상 SW 처리 비율이 높아집니다. |
flow_rule와 flow_action 공통 계약
TC, nf_flowtable, 일부 switchdev 오브젝트가 결국 드라이버에게 전달될 때는 각자 별개의 형식으로 가지 않습니다. 커널은 대체로 flow dissector가 만든 match key와 flow_action 배열로 정규화합니다. 즉, 사용자 공간에서 tc filter ... flower action ct nat mirred라고 쓰든, nftables에서 flowtable offload를 요청하든, 드라이버 입장에서는 "어떤 field를 비교하고 어떤 action을 어떤 순서로 실행할지"라는 동일한 문제로 환원됩니다.
/* HW offload 요청이 드라이버로 내려가기 전 정규화되는 공통 형태(개념도) */
struct flow_cls_offload {
enum flow_cls_command command;
unsigned long cookie;
u32 chain_index;
u32 prio;
struct flow_rule *rule;
struct netlink_ext_ack *extack;
};
struct flow_rule {
struct flow_match_basic basic;
struct flow_match_control control;
struct flow_match_meta meta;
struct flow_match_ipv4_addrs ipv4;
struct flow_match_ports ports;
struct flow_match_vlan vlan;
struct flow_match_enc_keyid enc_keyid;
struct flow_action action;
};
struct flow_action_entry {
enum flow_action_id id;
union {
struct net_device *dev; /* REDIRECT, MIRRED */
u32 chain_index; /* GOTO */
u32 mark; /* CT metadata */
};
};
코드 설명
-
2-8행
flow_cls_offload는 TC가 드라이버에 전달하는 규칙 단위입니다. cookie, chain, priority, 그리고 실패 이유를 되돌려 줄netlink_ext_ack가 함께 전달됩니다. -
10-18행
flow_rule는 "무엇을 비교할 것인가"를 정규화한 오브젝트입니다. 사용자 명령이 무엇이었는지보다, 결국 어느 헤더 필드와 메타데이터를 비교하는지가 중요합니다. -
20-26행
flow_action_entry는 실행 순서를 가진 액션 배열의 한 칸입니다. NAT, redirect, sample, trap 같은 동작이 순서대로 적재되며, 드라이버는 이를 HW action pipeline으로 번역합니다.
| match 계열 | 대표 필드 | 주로 누가 생성하는가 | NGFW 활용 | 자주 막히는 이유 |
|---|---|---|---|---|
| basic / control | ethertype, ip_proto, ingress/egress 방향 | TC flower, matchall | ACL 기본 분기, IPv4/IPv6 체인 분리 | parser stage 수가 부족하면 일부 조합이 실패합니다. |
| meta | ingress ifindex, skb mark, priority | TC, OVS, 일부 BPF 연동 | zone 분리, VRF 구분, pre-classification | 모든 장비가 skb 메타데이터를 HW에서 이해하지는 않습니다. |
| L2 / VLAN | src/dst MAC, VLAN ID, PCP | bridge, TC, switchdev | 투명 방화벽, tenant VLAN, QinQ 분기 | stacked VLAN이나 provider bridge는 제한이 많습니다. |
| L3 / L4 | src/dst IP, port, TCP flag, ICMP type | TC flower, nftables flow offload | 전형적인 5-tuple 방화벽과 NAT | fragment, IPv6 확장 헤더, option packet은 예외가 많습니다. |
| tunnel / encap | VXLAN VNI, Geneve option, tunnel dst, key id | TC tunnel_key, switchdev, flowtable tunnel offload | overlay 보안, service chaining, East-West 보안 | inner header까지 동시에 매칭하는 기능은 장비 편차가 큽니다. |
| conntrack metadata | ct_state, ct_mark, zone, label | act_ct, flowtable, OVS CT | stateful 방화벽, NAT 후속 처리, asymmetric flow 제어 | CT zone 수, timeout profile, NAT action 결합이 HW 자원에 민감합니다. |
| action 계열 | 대표 예 | HW로 내릴 때 기대 효과 | NGFW 활용 | 운영 시 확인 포인트 |
|---|---|---|---|---|
| 종결 동작 | drop, trap, accept | 명백한 차단/예외를 즉시 결정합니다. | DDoS 차단, ACL deny, 예외 CPU 전달 | trap가 많으면 Slow Path가 다시 병목이 됩니다. |
| 전달 동작 | mirred redirect, mirror, Hairpin | 호스트 메모리 왕복 없이 포트 간 전달합니다. | WAN↔LAN 포워딩, IDS TAP, 서비스 체인 | representor/egress 포트 매핑이 정확해야 합니다. |
| 헤더 수정 | pedit, csum, VLAN push/pop | rewrite를 ASIC에서 끝냅니다. | NAT 보조 수정, DSCP/TTL 정리, tenant 태깅 | 수정 가능한 필드 폭과 개수가 장비마다 다릅니다. |
| stateful action | ct commit, nat, CT metadata | 세션 상태와 NAT 문맥을 HW에 유지합니다. | stateful ACL, SNAT/DNAT, zone 기반 멀티 테넌시 | timeout, zone 수, reply direction 동기화가 중요합니다. |
| 터널 action | tunnel_key set/unset, encap/decap | overlay 헤더 추가/제거를 HW에서 처리합니다. | VXLAN 보안 경로, GTP-U, service mesh 우회 | 옵션 헤더와 inner match 동시 사용은 제약이 큽니다. |
| QoS / 계측 | police, meter, sample, skbedit, goto | 속도 제한과 샘플 추출을 ASIC에서 수행합니다. | per-flow rate limit, IDS 샘플링, chain 분기 | meter profile 수와 sample group이 HW 용량을 소모합니다. |
리소스, extack, 폴백 계약
규칙이 HW에 "들어가지 않는" 대부분의 이유는 기능 미지원보다 자원 고갈과 조합 제한입니다. 커널은 이 문제를 netlink_ext_ack, devlink resource, devlink trap, 드라이버 통계로 노출합니다. 즉, offload 인터페이스는 규칙을 설치하는 기능만이 아니라, 실패 이유를 구조화해 되돌려 주는 오류 계약까지 포함합니다.
| 계약 | 사용자 공간에서 보이는 형태 | 무엇을 알려 주는가 | NGFW 운영에서의 의미 |
|---|---|---|---|
netlink_ext_ack | tc, ip, devlink 에러 메시지 | 지원하지 않는 match/action, 조합 제한, 잘못된 port 관계 | "왜 안 되는지"를 가장 먼저 알려 주는 표준 오류 통로입니다. |
devlink resource | devlink resource show | FDB, ACL, flow counter, encap object, meter profile 용량 | TCAM 또는 flow table이 꽉 찼는지 즉시 확인할 수 있습니다. |
devlink trap | devlink trap show, devlink trap group show | miss, TTL error, source MAC 이상, ACL drop, exception packet | SW 경로로 복귀한 이유를 추적하는 핵심 인터페이스입니다. |
devlink health | devlink health show, recover | 펌웨어 reset, recover 횟수, dump 수집 상태 | 오프로드가 갑자기 꺼졌을 때 드라이버/펌웨어 문제를 구분합니다. |
| 드라이버 통계 | ethtool -S | CT offload hit, rule fail, FDB miss, TLS resync fail | 실제 hit ratio와 예외율을 시간대별로 볼 수 있습니다. |
# 리소스와 실패 이유를 한 번에 확인하는 기본 점검 순서
ethtool -k eth0 | grep -E 'hw-tc-offload|tls-hw|esp-hw-offload'
devlink dev eswitch show pci/0000:03:00.0
devlink resource show pci/0000:03:00.0
tc -s filter show dev eth0 ingress
devlink -s trap show pci/0000:03:00.0
ethtool -S eth0 | grep -E 'offload|flow|ct_|tls|macsec'
예외 경로와 제로카피 연동 인터페이스
NGFW는 모든 트래픽을 HW만으로 처리하지 않습니다. DPI, 포렌식, 이상 행위 탐지, 사용자 공간 보안 엔진 연동을 위해 예외 경로가 반드시 필요합니다. 중요한 점은 이 예외 경로도 커널이 제공하는 별도의 인터페이스 집합으로 정의돼 있는 점입니다.
| 인터페이스 | 성격 | 패킷을 어떻게 전달하는가 | NGFW에서 적합한 용도 | 한계 |
|---|---|---|---|---|
| NFQUEUE | verdict 기반 예외 경로 | skb를 nfnetlink queue로 내리고, 사용자 공간이 ACCEPT/DROP verdict를 반환합니다. | 정밀 DPI, IPS, App-ID, URL 분류 | 대역폭보다 CPS와 queue 지연에 민감합니다. |
| devlink trap | ASIC 예외 경로 | HW가 처리할 수 없거나 일부러 CPU 검사가 필요한 패킷을 trap rule로 보냅니다. | ACL miss, control plane packet, suspicious flow 검증 | trap policer를 넘으면 패킷 손실이 생길 수 있습니다. |
| psample | 샘플 기반 관측 경로 | HW 또는 커널이 일부 패킷만 추출하여 netlink sample 그룹으로 보냅니다. | sFlow, NetFlow, 행위 분석, IDS 미러 대체 | 전수 검사는 불가능하므로 차단 판단에는 부적합합니다. |
| AF_XDP | 제로카피 사용자 공간 경로 | XSK RX/TX ring으로 패킷 버퍼를 직접 공유합니다. | 고속 L7 검사기, 커스텀 프록시, 특수 exception worker | conntrack/nftables와 자동 통합되지 않으므로 설계가 복잡합니다. |
UAPI에서 ASIC까지 내려가는 제어 스택
모든 오프로드는 결국 같은 4단계를 거칩니다. 1) 사용자 공간 UAPI가 요청을 만들고, 2) 커널 서브시스템이 이를 일반화된 오브젝트로 정리한 뒤, 3) 드라이버 계약으로 변환하고, 4) NIC 펌웨어/ASIC 테이블에 실제 엔트리를 설치합니다. NGFW를 운영할 때 장애 지점을 찾으려면 이 4단계를 역순으로 확인해야 합니다.
tc filter ... skip_sw가 실패하면 먼저 ethtool -k에서 hw-tc-offload가 켜져 있는지 확인하고, 그다음 devlink dev eswitch show로 switchdev 모드인지 확인하며, 마지막으로 devlink trap과 tc -s로 실제 HW hit 여부를 봐야 합니다.
ethtool과 netdev feature 계약
ethtool -K는 단순한 토글처럼 보이지만 실제로는 드라이버가 선언한 hw_features, 커널이 허용한 feature 조합, 개별 skb가 충족한 제약이 동시에 맞아야 비로소 HW 경로에 들어갑니다. 따라서 NGFW 장비에서 feature bit를 켜는 일은 "속도를 높이는 옵션"이 아니라 드라이버와 데이터 경로의 계약을 활성화하는 행위입니다.
| Feature bit / 토글 | 의미 | NGFW에서 중요한 이유 | 대표 확인 명령 |
|---|---|---|---|
NETIF_F_HW_TC / hw-tc-offload | TC 규칙을 NIC 하드웨어로 내릴 수 있음을 의미합니다. | stateful ACL, NAT, ct offload, tunnel steering의 출발점입니다. | ethtool -k eth0 | grep hw-tc-offload |
NETIF_F_HW_TLS_TX / tls-hw-tx-offload | TX 방향 TLS 레코드 암호화를 NIC이 처리합니다. | SSL 프록시의 재암호화 비용을 크게 줄입니다. | ethtool -k eth0 | grep tls-hw |
NETIF_F_HW_TLS_RX / tls-hw-rx-offload | RX 방향 TLS 레코드 복호화를 NIC이 처리합니다. | 대용량 HTTPS 인입 시 CPU decrypt 부하를 줄입니다. | ethtool -k eth0 | grep tls-hw |
NETIF_F_HW_ESP / esp-hw-offload | ESP/IPsec crypto 또는 packet offload를 허용합니다. | 사이트 간 VPN과 원격 접속 VPN의 inline offload 핵심입니다. | ethtool -k eth0 | grep esp-hw-offload |
NETIF_F_HW_CSUM, NETIF_F_RXCSUM | 체크섬 생성/검사를 NIC에 맡깁니다. | TLS/IPsec/overlay와 결합될 때 CPU 오버헤드를 줄입니다. | ethtool -k eth0 | grep checksum |
NETIF_F_GSO, TSO, GRO | 패킷 분할/병합을 HW 또는 커널이 협력 처리합니다. | DPI 전 단계에서는 유리하지만, 일부 offload와 조합 제약이 있습니다. | ethtool -k eth0 | grep -E 'tso|gso|gro' |
NETIF_F_RXHASH | NIC이 RSS 해시를 채워 넣습니다. | CoreXL/Suricata worker affinity, XDP 분산, flow pinning에 중요합니다. | ethtool -k eth0 | grep rxhash |
/* feature 토글이 실제 HW 계약으로 번역되는 방식 */
static netdev_features_t ngfw_fix_features(struct net_device *dev,
netdev_features_t features)
{
/* SG가 없으면 대형 세그먼트와 TLS TX offload를 함께 쓸 수 없습니다. */
if (!(features & NETIF_F_SG))
features &= ~(NETIF_F_GSO_MASK | NETIF_F_HW_TLS_TX);
/* HW checksum이 없으면 ESP offload도 사실상 성립하기 어렵습니다. */
if (!(features & NETIF_F_HW_CSUM))
features &= ~NETIF_F_HW_ESP;
return features;
}
static int ngfw_set_features(struct net_device *dev,
netdev_features_t features)
{
if (features & NETIF_F_HW_TC)
program_acl_parser(dev);
if (features & NETIF_F_HW_TLS_TX)
program_tls_tx_context(dev);
if (features & NETIF_F_HW_ESP)
enable_ipsec_context(dev);
return 0;
}
# NGFW 장비에서 feature 계약 확인
ethtool -k eth0 | grep -E 'hw-tc-offload|tls-hw|esp-hw-offload|checksum'
# HW TC / TLS / ESP 지원을 켜기
ethtool -K eth0 hw-tc-offload on
ethtool -K eth0 tls-hw-tx-offload on tls-hw-rx-offload on
ethtool -K eth0 tx-checksum-ip-generic on
# per-skb 제약 때문에 실제 offload가 빠졌는지 확인
ip -details link show dev eth0
ethtool -S eth0
TC, switchdev, representor, devlink 계약
NGFW의 HW fast path는 보통 TC flower, nf_flowtable, switchdev, representor, devlink가 묶여 동작합니다. 즉, 매칭 규칙은 TC가 만들고, 세션/브리지 객체는 switchdev가 동기화하며, 포트 토폴로지와 trap/health 관리는 devlink가 담당합니다. 어느 하나라도 빠지면 "규칙은 들어갔는데 실제 와이어에서 안 돈다"는 현상이 생깁니다.
| 커널 계약 | 역할 | NGFW 활용 예 | 핵심 확인 포인트 |
|---|---|---|---|
TC_SETUP_CLSFLOWER + ndo_setup_tc | L2~L4 매칭 규칙과 action을 드라이버에 전달합니다. | 5-tuple ACL, NAT, mirred redirect, ct_state 기반 fast path | tc -s filter show ...에서 in_hw와 카운터를 봅니다. |
TC_SETUP_BLOCK + flow_block_cb | shared block을 여러 포트/representor에 공유합니다. | WAN/LAN 다수 포트에 공통 정책 적용 | block/chain 설계가 틀리면 일부 포트만 HW offload됩니다. |
TC_SETUP_FT | nf_flowtable의 EST 세션 오브젝트를 드라이버에 전달합니다. | conntrack 완료 세션을 NIC FDB/flow cache에 설치 | nft list flowtable와 conntrack -L를 함께 봅니다. |
switchdev_port_obj_add/del | FDB/VLAN/MDB/neighbor 객체를 ASIC에 동기화합니다. | 브리지 포트 learning, VLAN 태깅, VXLAN neigh offload | bridge fdb show의 offloaded 표기를 확인합니다. |
ndo_fdb_add/del/dump | 실제 HW FDB 테이블을 읽고 씁니다. | 브리지형 NGFW, transparent firewall, VRF/eSwitch 경로 | FDB가 차면 trap 비율이 올라갑니다. |
ndo_get_phys_port_id/name, ndo_get_port_parent_id | representor와 실제 포트/스위치 상관관계를 사용자 공간에 노출합니다. | VF/SF별 정책 분리, OVS/TC offload | 잘못 구현되면 OVS가 representor 매핑을 실패합니다. |
devlink dev eswitch set | legacy ↔ switchdev 모드 전환 | TC/OVS 기반 HW fast path의 전제 조건 | 운영 중 전환 시 VF 연결이 끊길 수 있습니다. |
devlink trap, devlink health | 예외 패킷과 펌웨어 오류를 구조화해 노출합니다. | ACL miss, TTL error, MACsec/IPsec 예외, FW reset 추적 | trap이 많으면 사실상 SW path로 새고 있는 뜻입니다. |
# 1. eSwitch를 switchdev 모드로 전환
devlink dev eswitch set pci/0000:03:00.0 mode switchdev
# 2. representor와 포트 토폴로지 확인
devlink port show pci/0000:03:00.0
ip -details link show | grep -E 'repr|phys_port'
# 3. TC flower + conntrack offload 규칙 설치
tc filter add dev eth0 ingress protocol ip flower \
ct_state +trk+est ip_proto tcp dst_port 443 \
skip_sw action mirred egress redirect dev eth1
# 4. 오프로드 결과와 예외 패킷 확인
tc -s filter show dev eth0 ingress
bridge fdb show dev eth0
devlink trap show pci/0000:03:00.0
devlink health show pci/0000:03:00.0
IPsec, kTLS, MACsec 오프로드 계약
암호화 offload는 "암호화 장치 하나"로 통합돼 있지 않습니다. Linux는 프로토콜별로 별도의 계약을 둡니다. IPsec은 xfrmdev_ops, kTLS는 tlsdev_ops, MACsec은 macsec_ops를 사용합니다. 따라서 상용 NGFW처럼 SSL inspection ASIC 하나로 모든 암호화 경로를 덮는 구조가 아니라, 프로토콜마다 다른 offload 계약을 조합하는 방식입니다.
| 서브시스템 | 드라이버 계약 | 사용자 공간 진입점 | 하드웨어가 맡는 범위 | NGFW 관점의 의미 |
|---|---|---|---|---|
| IPsec / xfrm | xfrmdev_ops | ip xfrm state/policy ... offload | crypto offload 또는 packet offload | 사이트 간 VPN과 서비스 체인용 tunnel offload의 표준 계약입니다. |
| kTLS | tlsdev_ops | setsockopt(TCP_ULP,"tls"), ethtool -K tls-hw-* | TLS 레코드 암·복호화, resync | SSL 프록시의 record path를 NIC으로 내리는 유일한 표준 계약입니다. |
| MACsec | macsec_ops | ip link add macsec0, ip macsec offload | SecY, RXSC/TXSA, PN/XPN 카운터 | 데이터센터 L2 보안이나 appliance uplink 보호에 적합합니다. |
| PCIe crypto 가속기 | crypto API / 라이브러리 엔진 | OpenSSL engine/provider, strongSwan, QAT 엔진 | AES, RSA, ECDHE 등 연산 가속 | 커널 네트워크 offload라기보다 CPU중심 lookaside 계열입니다. |
/* IPsec / TLS / MACsec은 서로 다른 드라이버 계약을 사용합니다. */
struct xfrmdev_ops {
int (*xdo_dev_state_add)(struct net_device *dev,
struct xfrm_state *x,
struct netlink_ext_ack *extack);
bool (*xdo_dev_offload_ok)(struct sk_buff *skb,
struct xfrm_state *x);
int (*xdo_dev_policy_add)(struct xfrm_policy *p,
struct netlink_ext_ack *extack);
};
struct tlsdev_ops {
int (*tls_dev_add)(struct net_device *netdev, struct sock *sk,
enum tls_offload_ctx_dir direction,
struct tls_crypto_info *crypto_info,
u32 start_offload_tcp_sn);
void (*tls_dev_del)(struct net_device *netdev,
struct tls_context *ctx,
enum tls_offload_ctx_dir direction);
int (*tls_dev_resync)(struct net_device *netdev,
struct sock *sk, u32 seq,
u8 *rcd_sn, enum tls_offload_ctx_dir direction);
};
struct macsec_ops {
int (*mdo_add_secy)(struct macsec_context *ctx);
int (*mdo_add_txsa)(struct macsec_context *ctx);
int (*mdo_add_rxsc)(struct macsec_context *ctx);
int (*mdo_add_rxsa)(struct macsec_context *ctx);
};
# IPsec offload
ip xfrm state add src 203.0.113.1 dst 198.51.100.1 \
proto esp spi 0x1000 mode transport \
aead 'rfc4106(gcm(aes))' 0x00112233445566778899aabbccddeeff00112233 128 \
offload dev eth0 dir out
# kTLS offload
ethtool -K eth0 tls-hw-tx-offload on tls-hw-rx-offload on
cat /proc/net/tls_stat
# MACsec offload
ip link add link eth0 macsec0 type macsec port 1 encrypt on
ip macsec offload macsec0 mac
# 실제 feature 노출 확인
ethtool -k eth0 | grep -E 'esp-hw-offload|tls-hw'
예외 경로, 통계, 폴백 인터페이스
오프로드 운영에서 중요한 것은 "켜졌는지"보다 "왜 빠졌는지"입니다. HW 용량 초과, 지원하지 않는 match field, MTU 제약, TLS resync 실패, XFRM 정책 불일치 같은 이유로 언제든 SW 경로로 되돌아갈 수 있습니다. 아래 인터페이스는 그 순간을 잡아내는 데 사용합니다.
| 인터페이스 | 무엇을 보여주는가 | NGFW에서 보는 값 |
|---|---|---|
tc -s filter show | 각 flower 규칙의 패킷/바이트, in_hw 여부 | ACL/NAT/redirect가 실제 ASIC에서 hit 하는지 확인합니다. |
nft list flowtable | flowtable 오브젝트와 offload 플래그 | EST 세션 fast path가 커널/하드웨어 어느 쪽에 남아 있는지 봅니다. |
conntrack -L -o extended | conntrack 엔트리와 [OFFLOAD] 상태 | 세션이 CT offload까지 갔는지 확인합니다. |
ethtool -S | 드라이버별 HW 카운터 | FDB miss, TLS context fail, RX drop, MACsec stats 같은 벤더 카운터를 봅니다. |
devlink trap show | 예외 패킷이 왜 CPU로 왔는지 | ACL miss, TTL error, source MAC 문제, tunnel exception 등을 확인합니다. |
devlink health show | 펌웨어 오류와 자동 복구 이력 | 오프로드가 갑자기 꺼진 원인이 FW reset인지 판별합니다. |
bpftool net, ip link show | XDP 부착 위치와 모드 | xdpoffload, xdpdrv, xdpgeneric 중 어디인지 확인합니다. |
/proc/net/tls_stat | kTLS SW/HW 사용량 | TLS offload가 resync/fallback로 SW로 내려왔는지 봅니다. |
드라이버 오프로드 계약 (ndo_setup_tc)
NIC 드라이버가 TC flower offload를 지원하기 위해 구현해야 하는 인터페이스입니다. NGFW 파이프라인의 HW offload는 이 계약에 의존합니다. (Network Device 드라이버 참고)
/* include/linux/netdevice.h */
struct net_device_ops {
/* TC flower offload 진입점 */
int (*ndo_setup_tc)(struct net_device *dev,
enum tc_setup_type type,
void *type_data);
};
/* 드라이버가 처리해야 하는 TC 타입 */
enum tc_setup_type {
TC_SETUP_QDISC_MQPRIO, /* MQPRIO QoS 큐 설정 */
TC_SETUP_CLSFLOWER, /* TC flower 분류기 규칙 */
TC_SETUP_FT, /* flowtable offload */
TC_SETUP_BLOCK, /* 블록 바인딩 (CT offload) */
};
/* CLSFLOWER 콜백에서 처리하는 명령 */
enum tc_fl_command {
TC_CLSFLOWER_REPLACE, /* 규칙 추가/교체 */
TC_CLSFLOWER_DESTROY, /* 규칙 삭제 */
TC_CLSFLOWER_STATS, /* HW 카운터 읽기 */
};
코드 설명
-
4-6행
ndo_setup_tc는 TC 서브시스템이 NIC 드라이버에 오프로드 규칙을 전달하는 단일 진입점(Entry Point)입니다. type 파라미터로 어떤 종류의 오프로드인지 구분합니다. -
10-14행
TC_SETUP_FT는 flowtable offload 전용 타입으로,nf_flow_offload_hw_add()가 이 타입으로 드라이버를 호출합니다.TC_SETUP_BLOCK은 conntrack action offload에 사용됩니다. -
18행
TC_CLSFLOWER_STATS는 HW에서 처리된 패킷/바이트 카운터를 읽어옵니다. GC가 주기적으로 이 명령을 호출하여 타임아웃을 갱신합니다.
nf_flowtable 내부 구조
/* include/net/netfilter/nf_flow_table.h */
struct nf_flowtable {
struct list_head list; /* flowtable 전역 리스트 */
struct rhashtable rhashtable; /* 5-tuple 해시 테이블 */
int priority; /* Netfilter 훅 우선순위 */
unsigned int flags; /* NF_FLOWTABLE_HW_OFFLOAD 등 */
struct nf_flowtable_type *type;
struct delayed_work gc_work; /* GC 워크큐 */
struct flow_block flow_block; /* HW offload 블록 */
struct mutex flow_block_lock;
possible_net_t net;
};
/* rhashtable 파라미터: 자동 크기 조절 */
static const struct rhashtable_params nf_flow_offload_rhash_params = {
.head_offset = offsetof(struct flow_offload_tuple_rhash, node),
.key_offset = offsetof(struct flow_offload_tuple_rhash, tuple),
.key_len = sizeof(struct flow_offload_tuple),
.automatic_shrinking = true, /* 엔트리 감소 시 자동 축소 */
};
flowtable은 rhashtable(Resizable Hash Table)을 사용합니다. 엔트리 수에 따라 버킷이 자동으로 확장/축소되며, RCU 기반 읽기로 lock-free lookup을 보장합니다. 이는 NGFW에서 높은 CPS 환경에서도 Fast Path lookup의 일관된 성능을 유지하는 핵심입니다.
핵심 커널 API 흐름
/* NGFW 파이프라인의 커널 API 호출 흐름 (개념도) */
/* 1. 패킷 수신 → Netfilter PREROUTING 훅 */
nf_hook(NFPROTO_IPV4, NF_INET_PRE_ROUTING, skb);
/* 2. conntrack: 세션 추적 */
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
if (ctinfo == IP_CT_NEW) {
/* 새 세션 → Slow Path: 전체 규칙 평가 */
nft_do_chain(chain, skb); /* nftables 규칙 평가 */
nf_queue(skb, queue_num); /* NFQUEUE → DPI 엔진 */
}
/* 3. flowtable: ESTABLISHED 세션 Fast Path */
if (ctinfo == IP_CT_ESTABLISHED) {
struct flow_offload *flow = flow_offload_lookup(ft, skb);
if (flow) {
/* Fast Path: conntrack bypass → 직접 전달 */
nf_flow_offload_ip_hook(skb); /* NAT rewrite + forward */
return NF_STOLEN; /* Netfilter 훅 체인 종료 */
}
}
/* 4. HW offload 등록 */
flow_offload_add(ft, flow);
if (ft->flags & NF_FLOWTABLE_HW_OFFLOAD)
nf_flow_offload_hw_add(net, flow, ct); /* eSwitch FDB rule 설치 */
코드 설명
- 3행 (nf_hook PREROUTING) 패킷이 처음 도착하면 PREROUTING 훅에서 모든 등록된 콜백(Callback)이 실행됩니다. conntrack, nftables, flowtable이 이 훅에 등록되어 있습니다.
-
6행 (nf_ct_get)
skb에 연결된 conntrack 엔트리를 가져옵니다.
ctinfo는 현재 패킷의 방향(ORIGINAL/REPLY)과 상태(NEW/ESTABLISHED)를 나타냅니다. - 7-10행 (IP_CT_NEW) 새로운 세션의 첫 패킷입니다. nftables 체인 전체를 평가하고, NFQUEUE로 DPI 엔진에 전달합니다.
-
13-19행 (IP_CT_ESTABLISHED)
이미 수립된 세션의 패킷입니다. flowtable에서 플로우를 찾으면 NAT rewrite + forward를 직접 수행하고
NF_STOLEN으로 Netfilter 체인을 종료합니다. - 22-24행 (HW offload) flowtable에 등록하고, HW offload 플래그가 있으면 NIC eSwitch에도 FDB 규칙을 설치합니다. 이후 동일 플로우의 패킷은 NIC에서 직접 처리됩니다.
NFQUEUE 연동 API
DPI 엔진이 NFQUEUE에서 패킷을 수신하고 verdict를 반환하는 과정의 유저스페이스 API입니다:
/* libnetfilter_queue를 사용한 DPI 엔진 기본 구조 */
#include <libnetfilter_queue/libnetfilter_queue.h>
static int nfq_callback(struct nfq_q_handle *qh,
struct nfgenmsg *nfmsg,
struct nfq_data *nfa,
void *data)
{
struct nfqnl_msg_packet_hdr *ph;
unsigned char *payload;
int payload_len;
uint32_t id;
ph = nfq_get_msg_packet_hdr(nfa);
id = ntohl(ph->packet_id);
payload_len = nfq_get_payload(nfa, &payload);
/* DPI 분석 수행 */
int verdict = analyze_packet(payload, payload_len);
/* verdict 반환: NF_ACCEPT 또는 NF_DROP */
if (verdict == DPI_ALLOW)
return nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL);
else
return nfq_set_verdict(qh, id, NF_DROP, 0, NULL);
}
/* 메인 루프: NFQUEUE 수신 + DPI 콜백 */
int main(void)
{
struct nfq_handle *h = nfq_open();
struct nfq_q_handle *qh = nfq_create_queue(h, 0,
&nfq_callback, NULL);
/* 배치 verdict 활성화 (성능 향상) */
nfq_set_queue_flags(qh, NFQA_CFG_F_GSO, NFQA_CFG_F_GSO);
/* 소켓에서 패킷 수신 루프 */
int fd = nfq_fd(h);
char buf[65536];
int rv;
while ((rv = recv(fd, buf, sizeof(buf), 0)) > 0)
nfq_handle_packet(h, buf, rv);
return 0;
}
오프로드 구현 패턴
Suricata NFQUEUE 통합 설정
Suricata를 NGFW의 DPI/IPS 엔진으로 사용할 때의 최적화된 설정입니다:
# /etc/suricata/suricata.yaml (NGFW 최적화)
# NFQUEUE 모드 설정
nfq:
mode: repeat # verdict 후 재주입 (NFQUEUE → nftables 계속)
repeat-mark: 1 # 재주입된 패킷 마킹 (중복 큐잉 방지)
repeat-mask: 1
bypass: yes # Suricata 과부하 시 패킷 bypass (가용성 우선)
fail-open: yes # Suricata 장애 시 패킷 통과 (HA 환경)
batchcount: 20 # 배치 verdict (성능 향상)
# 멀티 스레드 설정 (CPU 코어 4~16개 환경)
threading:
set-cpu-affinity: yes
cpu-affinity:
- management-cpu-set:
cpu: [ 0 ]
- receive-cpu-set:
cpu: [ 1, 2, 3, 4 ] # NFQUEUE 수신 스레드
- worker-cpu-set:
cpu: [ 5, 6, 7, 8, 9, 10, 11, 12 ] # 분석 워커
# App-Layer 프로토콜 분석 (NGFW App-ID)
app-layer:
protocols:
tls:
enabled: yes
detection-ports:
dp: 443, 8443
ja3-fingerprints: yes # JA3/JA3S 핑거프린트 (TLS 분류)
http:
enabled: yes
server-body-limit: 1mb # DLP를 위한 바디 검사 한계
dns:
enabled: yes
smb:
enabled: yes
ssh:
enabled: yes
hassh: yes # HASSH 핑거프린트
# 플로우 타임아웃 (flowtable과 동기화)
flow-timeouts:
default:
new: 30
established: 300 # nf_flowtable_tcp_timeout과 일치
closed: 10
bypassed: 300 # bypass된 세션 (오프로드됨)
tcp:
new: 60
established: 600
closed: 60
# bypass 설정 (오프로드 연동)
stream:
bypass: yes # 분류 완료 후 스트림 바이패스
max-sessions: 1000000 # 최대 동시 세션
코드 설명
- 5행 (mode: repeat) repeat 모드에서 Suricata는 verdict(ACCEPT/DROP) 후 패킷을 Netfilter에 재주입합니다. 이를 통해 nftables의 나머지 규칙(flowtable 등록 등)이 계속 실행됩니다.
- 9행 (fail-open: yes) Suricata 프로세스가 크래시하거나 응답하지 않을 때 패킷을 자동으로 통과시킵니다. NGFW에서 가용성이 보안보다 중요한 경우 필수입니다.
- 10행 (batchcount: 20) NFQUEUE에서 20개 패킷을 모아서 한 번에 verdict를 전송합니다. syscall 횟수를 줄여 ~30% 성능 향상이 가능합니다.
- 34행 (ja3-fingerprints) JA3 핑거프린트는 TLS Client Hello의 특성으로 클라이언트 애플리케이션을 식별합니다. SNI 없이도 App-ID가 가능합니다.
- 55행 (stream: bypass) Suricata가 세션 분류를 완료하면 이후 패킷의 스트림 재조립을 건너뜁니다. nftables의 flowtable 오프로드와 함께 사용하면 DPI 완료 세션이 Fast Path로 전환됩니다.
nftables NGFW 설정
완전한 nftables 규칙셋으로 NGFW 데이터 플레인을 구성하는 예시입니다. flowtable으로 ESTABLISHED 세션을 오프로드하고, NEW 세션은 NFQUEUE로 DPI 검사를 수행합니다.
#!/usr/sbin/nft -f
# NGFW nftables 규칙셋 (flowtable + NFQUEUE DPI)
table inet ngfw {
# flowtable 정의 (HW offload 활성화)
flowtable ft {
hook ingress priority 0
devices = { eth0, eth1 }
flags offload # NF_FLOWTABLE_HW_OFFLOAD
}
# forward chain: NGFW 핵심 파이프라인
chain forward {
type filter hook forward priority 0; policy drop;
# 1. INVALID 패킷 즉시 DROP
ct state invalid drop
# 2. ESTABLISHED/RELATED → flowtable offload
ct state established,related flow add @ft accept
# 3. NEW 세션 → 기본 ACL 통과 후 NFQUEUE로 DPI
ct state new ip protocol tcp \
tcp dport { 80, 443, 8080, 8443 } \
queue num 0-3 fanout # 4개 DPI 워커로 분산
ct state new ip protocol udp \
udp dport { 53, 443 } \
queue num 0-3 fanout
# 4. 허용된 ICMP
ct state new icmp type { echo-request, echo-reply } accept
# 5. 나머지 NEW → DROP (기본 정책)
}
# input chain: 관리 인터페이스 보호
chain input {
type filter hook input priority 0; policy drop;
ct state established,related accept
iifname "lo" accept
tcp dport 22 accept # SSH 관리
}
}
코드 설명
-
6-10행
flowtable
ft를 정의합니다.flags offload로 HW offload를 활성화하면, SmartNIC이 지원하는 경우 eSwitch FDB 규칙이 자동 설치됩니다. - 17행 INVALID 상태 패킷은 즉시 DROP합니다. conntrack이 유효하지 않다고 판단한 패킷(시퀀스 번호 불일치 등)입니다.
- 20행 핵심 오프로드 규칙: ESTABLISHED/RELATED 세션을 flowtable에 등록하고 accept합니다. 이후 패킷은 Fast Path로 처리됩니다.
-
23-25행
새로운 TCP 연결(특정 포트)을 NFQUEUE 0~3번 큐로
fanout분산합니다. 각 큐에 Suricata 워커가 연결되어 DPI를 수행합니다. - 27-29행 DNS(53)와 QUIC(443/UDP) 트래픽도 DPI로 전달합니다.
TC flower ACL 오프로드
eSwitch switchdev 모드에서 TC flower를 사용하여 ACL 규칙을 하드웨어에 직접 설치합니다. 이 방식은 nftables의 SW 경로와 병행하여, NEW 패킷은 CPU(nftables → NFQUEUE → DPI)에서 처리하고 ESTABLISHED 패킷은 eSwitch HW에서 직접 전달합니다.
- TC flower 직접 규칙: 관리자가 명시적으로 CT 매칭 규칙을 설치. 세밀한 제어 가능하지만 관리 복잡도 증가
- nftables flowtable + HW offload:
flow add @ft로 자동 등록. 간편하지만 커널이 자동 결정 - 권장 조합: nftables flowtable으로 기본 오프로드 + TC flower로 특수 규칙(IP 차단, QoS 등) 추가
# 1. eSwitch switchdev 모드 전환
devlink dev eswitch set pci/0000:03:00.0 mode switchdev
# 2. VF representor에서 hw-tc-offload 활성화
ethtool -K eth0_rep0 hw-tc-offload on
# 3. conntrack zone 설정 + 추적 시작
tc filter add dev eth0_rep0 ingress prio 1 \
protocol ip flower \
ct_state -trk \
action ct zone 1
# 4. EST+TRK → NAT + forward (HW offload)
tc filter add dev eth0_rep0 ingress prio 2 \
protocol ip flower \
ct_state +trk+est \
action ct zone 1 nat \
action mirred egress redirect dev eth1_rep0
# 5. NEW+TRK → pass to CPU (Slow Path)
tc filter add dev eth0_rep0 ingress prio 3 \
protocol ip flower \
ct_state +trk+new \
action pass
# 6. 특정 IP 대역 차단 (HW에서 DROP)
tc filter add dev eth0_rep0 ingress prio 0 \
protocol ip flower \
src_ip 192.168.100.0/24 \
action drop
DPI 오프로드 바이패스 패턴
DPI 엔진이 세션을 분류하면 이후 패킷은 NFQUEUE를 bypass해야 합니다. eBPF map을 활용한 캐시 패턴입니다:
eBPF DPI 결과 캐시 (완전한 구현)
/* dpi_cache.bpf.c — eBPF DPI 결과 캐시 프로그램 */
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
/* 5-tuple 플로우 키 */
struct flow_key {
__be32 src_ip;
__be32 dst_ip;
__be16 src_port;
__be16 dst_port;
__u8 protocol;
__u8 pad[3];
};
/* DPI 결과 값 */
struct dpi_result {
__u32 verdict; /* 0=ACCEPT, 1=DROP, 2=CONTINUE */
__u32 app_id; /* 애플리케이션 ID (DPI 엔진이 설정) */
__u64 timestamp; /* 마지막 갱신 (nsec) */
__u64 bytes; /* 바이트 카운터 (샘플링용) */
};
/* LRU 해시 맵: 자동으로 가장 오래된 엔트리 퇴출 */
struct {
__uint(type, BPF_MAP_TYPE_LRU_HASH);
__uint(max_entries, 500000);
__type(key, struct flow_key);
__type(value, struct dpi_result);
} dpi_cache SEC(".maps");
/* 통계 맵 */
struct {
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
__uint(max_entries, 4);
__type(key, __u32);
__type(value, __u64);
} stats SEC(".maps");
/* stats[0]=cache_hit, stats[1]=cache_miss,
stats[2]=bypass_accept, stats[3]=bypass_drop */
static __always_inline int
extract_flow_key(struct __sk_buff *skb, struct flow_key *key)
{
void *data = (void *)(long)skb->data;
void *data_end = (void *)(long)skb->data_end;
struct iphdr *iph = data + sizeof(struct ethhdr);
if ((void *)(iph + 1) > data_end)
return -1;
key->src_ip = iph->saddr;
key->dst_ip = iph->daddr;
key->protocol = iph->protocol;
if (iph->protocol == IPPROTO_TCP) {
struct tcphdr *tcph = (void *)iph + (iph->ihl * 4);
if ((void *)(tcph + 1) > data_end) return -1;
key->src_port = tcph->source;
key->dst_port = tcph->dest;
} else if (iph->protocol == IPPROTO_UDP) {
struct udphdr *udph = (void *)iph + (iph->ihl * 4);
if ((void *)(udph + 1) > data_end) return -1;
key->src_port = udph->source;
key->dst_port = udph->dest;
}
return 0;
}
SEC("netfilter")
int dpi_bypass(struct bpf_nf_ctx *ctx)
{
struct flow_key key = {};
__u32 idx;
__u64 *counter;
if (extract_flow_key(ctx->skb, &key) < 0)
return NF_ACCEPT;
struct dpi_result *result = bpf_map_lookup_elem(&dpi_cache, &key);
if (result) {
/* 캐시 히트 */
idx = 0; counter = bpf_map_lookup_elem(&stats, &idx);
if (counter) (*counter)++;
/* 바이트 카운터 갱신 (샘플링 판단용) */
__sync_fetch_and_add(&result->bytes, ctx->skb->len);
/* 10MB 초과 시 캐시 무효화 → 재검사 */
if (result->bytes > 10485760) {
bpf_map_delete_elem(&dpi_cache, &key);
return NF_ACCEPT; /* NFQUEUE로 전달 */
}
if (result->verdict == 0) {
idx = 2; counter = bpf_map_lookup_elem(&stats, &idx);
if (counter) (*counter)++;
return NF_ACCEPT; /* DPI ALLOW → bypass */
} else if (result->verdict == 1) {
idx = 3; counter = bpf_map_lookup_elem(&stats, &idx);
if (counter) (*counter)++;
return NF_DROP; /* DPI DROP → 즉시 차단 */
}
}
/* 캐시 미스 → NFQUEUE로 전달 (DPI 검사) */
idx = 1; counter = bpf_map_lookup_elem(&stats, &idx);
if (counter) (*counter)++;
return NF_ACCEPT;
}
char _license[] SEC("license") = "GPL";
코드 설명
-
11-18행 (flow_key)
5-tuple 플로우 키 구조체.
pad[3]은 구조체를 8바이트 정렬하여 해시 성능을 최적화합니다. -
21-26행 (dpi_result)
DPI 결과에 바이트 카운터를 추가하여 주기적 샘플링 임계치를 판단합니다.
app_id는 모니터링/로깅에 활용됩니다. - 29-33행 (LRU_HASH) LRU 해시 맵은 max_entries에 도달하면 가장 오래된 엔트리를 자동 퇴출합니다. 50만 엔트리로 대부분의 활성 세션을 커버합니다.
-
36-41행 (PERCPU_ARRAY)
per-CPU 카운터로 캐시 히트/미스 통계를 lock-free로 수집합니다.
bpftool map dump으로 확인 가능합니다. - 85-89행 (바이트 임계치) 10MB 초과 시 캐시 엔트리를 삭제하여 DPI 재검사를 강제합니다. 이는 §9의 주기적 샘플링을 eBPF 수준에서 구현한 것입니다.
DPI 엔진에서 eBPF 맵 업데이트
Suricata의 output 플러그인에서 verdict를 eBPF 맵에 기록합니다:
/* Suricata output 플러그인 (유저스페이스): verdict를 eBPF 맵에 기록 */
#include <bpf/libbpf.h>
#include <bpf/bpf.h>
int map_fd; /* bpf_obj_get()으로 pinned map 열기 */
void update_dpi_cache(struct Packet *p, int verdict)
{
struct flow_key key = {
.src_ip = p->src.addr_data32[0],
.dst_ip = p->dst.addr_data32[0],
.src_port = p->sp,
.dst_port = p->dp,
.protocol = p->proto,
};
struct dpi_result result = {
.verdict = (verdict == VERDICT_PASS) ? 0 : 1,
.app_id = p->flow->alproto,
.timestamp = get_timestamp_ns(),
.bytes = 0,
};
bpf_map_update_elem(map_fd, &key, &result, BPF_ANY);
/* 역방향 플로우도 등록 (양방향 캐시) */
struct flow_key rev_key = {
.src_ip = key.dst_ip, .dst_ip = key.src_ip,
.src_port = key.dst_port, .dst_port = key.src_port,
.protocol = key.protocol,
};
bpf_map_update_elem(map_fd, &rev_key, &result, BPF_ANY);
}
# eBPF 프로그램 로드 및 nftables 연동
# 1. 컴파일
clang -O2 -target bpf -c dpi_cache.bpf.c -o dpi_cache.bpf.o
# 2. 로드 및 맵 핀닝
bpftool prog load dpi_cache.bpf.o /sys/fs/bpf/dpi_bypass \
type netfilter
# 3. nftables에서 eBPF 프로그램 연결
# (nftables 커널 5.18+에서 BPF verdict 지원)
nft add rule inet ngfw forward \
ct state new \
meta mark != 0xff \
queue num 0-3 fanout # BPF 캐시 미스만 NFQUEUE로 전달
# 4. 캐시 통계 확인
bpftool map dump pinned /sys/fs/bpf/dpi_bypass/stats
# key: 0 value (per-cpu): [12345, 12340, ...] ← cache_hit
# key: 1 value (per-cpu): [567, 570, ...] ← cache_miss
NGFW 시스템 서비스 구성
Linux NGFW를 프로덕션에 배포하기 위한 systemd 서비스 구성입니다:
# /etc/systemd/system/ngfw-nftables.service
[Unit]
Description=NGFW nftables Rules
Before=suricata.service
After=network-pre.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/sbin/nft -f /etc/nftables-ngfw.conf
ExecReload=/usr/sbin/nft -f /etc/nftables-ngfw.conf
ExecStop=/usr/sbin/nft flush ruleset
[Install]
WantedBy=multi-user.target
# /etc/systemd/system/ngfw-eswitch.service
[Unit]
Description=NGFW eSwitch TC flower Rules
After=ngfw-nftables.service
Requires=ngfw-nftables.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStartPre=/usr/bin/devlink dev eswitch set pci/0000:03:00.0 mode switchdev
ExecStartPre=/usr/bin/sleep 2
ExecStartPre=/usr/sbin/ethtool -K eth0_rep0 hw-tc-offload on
ExecStart=/usr/local/bin/ngfw-tc-rules.sh
ExecStop=/usr/sbin/tc filter del dev eth0_rep0 ingress
[Install]
WantedBy=multi-user.target
# /etc/systemd/system/ngfw-tuning.service
[Unit]
Description=NGFW Kernel Tuning
Before=ngfw-nftables.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/sh -c '\
sysctl -w net.netfilter.nf_conntrack_max=2000000; \
sysctl -w net.netfilter.nf_conntrack_buckets=500000; \
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=300; \
sysctl -w net.netfilter.nf_flowtable_tcp_timeout=300; \
sysctl -w net.core.optmem_max=81920; \
sysctl -w net.core.netdev_budget=600; \
sysctl -w net.core.netdev_max_backlog=10000; \
sysctl -w net.ipv4.ip_forward=1; \
ethtool -C eth0 rx-usecs 50 rx-frames 64 adaptive-rx on; \
ethtool -G eth0 rx 4096 tx 4096; \
/usr/local/bin/set_irq_affinity.sh 0-3 eth0 \
'
[Install]
WantedBy=multi-user.target
# 서비스 활성화 및 시작 순서
systemctl enable ngfw-tuning ngfw-nftables ngfw-eswitch
systemctl enable suricata conntrackd
# 시작 순서: tuning → nftables → eswitch → suricata → conntrackd
systemctl start ngfw-tuning
systemctl start ngfw-nftables
systemctl start ngfw-eswitch
systemctl start suricata
systemctl start conntrackd
# 상태 확인
systemctl status ngfw-nftables ngfw-eswitch suricata conntrackd
멀티 테이블 파이프라인
TC chain을 사용하여 다단계 매칭 파이프라인을 구성합니다:
# chain 0: conntrack 추적 및 분기
tc filter add dev eth0_rep0 ingress chain 0 prio 1 \
protocol ip flower ct_state -trk \
action ct zone 1 pipe \
action goto chain 1
# chain 1: 상태 기반 분기
tc filter add dev eth0_rep0 ingress chain 1 prio 1 \
protocol ip flower ct_state +trk+est \
action goto chain 2 # ESTABLISHED → Fast Path chain
tc filter add dev eth0_rep0 ingress chain 1 prio 2 \
protocol ip flower ct_state +trk+new \
action pass # NEW → CPU (Slow Path)
# chain 2: Fast Path (NAT + forward)
tc filter add dev eth0_rep0 ingress chain 2 prio 1 \
protocol ip flower \
action ct zone 1 nat \
action mirred egress redirect dev eth1_rep0
XDP DDoS Pre-filter 패턴
NGFW의 가장 앞단에서 XDP를 사용하여 DDoS/스캔 트래픽을 CPU 부하 없이 처리합니다. 이 패턴은 conntrack 테이블 포화를 방지하는 핵심 방어선입니다.
/* xdp_ddos_filter.c — NGFW XDP DDoS Pre-filter */
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/tcp.h>
/* 차단 IP 세트 (관리 도구에서 동적 업데이트) */
struct {
__uint(type, BPF_MAP_TYPE_LPM_TRIE);
__uint(max_entries, 100000);
__uint(map_flags, BPF_F_NO_PREALLOC);
__type(key, struct lpm_key);
__type(value, __u32);
} blocklist SEC(".maps");
/* SYN flood 속도 제한 (per-source IP) */
struct {
__uint(type, BPF_MAP_TYPE_LRU_HASH);
__uint(max_entries, 1000000);
__type(key, __be32); /* source IP */
__type(value, __u64); /* timestamp + count */
} syn_rate SEC(".maps");
SEC("xdp")
int xdp_ddos_filter(struct xdp_md *ctx)
{
void *data = (void *)(long)ctx->data;
void *data_end = (void *)(long)ctx->data_end;
struct ethhdr *eth = data;
if ((void *)(eth + 1) > data_end) return XDP_DROP;
if (eth->h_proto != __constant_htons(ETH_P_IP)) return XDP_PASS;
struct iphdr *iph = (void *)(eth + 1);
if ((void *)(iph + 1) > data_end) return XDP_DROP;
/* 1. IP 차단 리스트 확인 (LPM Trie: CIDR 매칭) */
struct lpm_key key = { .prefixlen = 32, .addr = iph->saddr };
if (bpf_map_lookup_elem(&blocklist, &key))
return XDP_DROP; /* 차단 IP → 즉시 DROP (최소 지연) */
/* 2. SYN flood 감지 (TCP SYN 패킷만) */
if (iph->protocol == IPPROTO_TCP) {
struct tcphdr *tcph = (void *)iph + (iph->ihl * 4);
if ((void *)(tcph + 1) > data_end) return XDP_DROP;
if (tcph->syn && !tcph->ack) {
/* SYN 속도 제한: 소스 IP당 초당 100 SYN */
__u64 *rate = bpf_map_lookup_elem(&syn_rate, &iph->saddr);
__u64 now = bpf_ktime_get_ns();
if (rate) {
__u64 last = *rate & 0xFFFFFFFF00000000ULL;
__u32 count = *rate & 0xFFFFFFFF;
if (now - last < 1000000000ULL) { /* 1초 이내 */
if (count > 100)
return XDP_DROP; /* 속도 초과 → DROP */
*rate = last | (count + 1);
} else {
*rate = (now & 0xFFFFFFFF00000000ULL) | 1;
}
} else {
__u64 val = (now & 0xFFFFFFFF00000000ULL) | 1;
bpf_map_update_elem(&syn_rate, &iph->saddr, &val, BPF_ANY);
}
}
}
return XDP_PASS; /* 정상 → 커널 네트워크 스택으로 전달 */
}
char _license[] SEC("license") = "GPL";
코드 설명
- 9-14행 (LPM_TRIE) LPM(Longest Prefix Match) Trie는 CIDR 블록(예: 192.168.0.0/16)을 효율적으로 매칭합니다. IP 차단 리스트를 bpftool map으로 동적 업데이트할 수 있습니다.
-
40-42행
차단 IP가 발견되면
XDP_DROP을 반환하여 NIC 드라이버 수준에서 즉시 패킷을 폐기합니다. skb 할당도 발생하지 않으므로 최소한의 CPU 비용만 소모합니다. - 47-66행 (SYN 속도 제한) 소스 IP당 초당 SYN 패킷 수를 추적합니다. 100 SYN/초를 초과하면 DROP합니다. 이를 통해 SYN flood가 conntrack 테이블에 도달하기 전에 차단합니다.
# XDP DDoS 필터 운영 명령
# 프로그램 로드
ip link set dev eth0 xdp obj xdp_ddos_filter.o sec xdp
# IP 차단 리스트 관리 (bpftool)
bpftool map update pinned /sys/fs/bpf/xdp_ddos/blocklist \
key hex 20 00 00 00 c0 a8 64 00 \
value hex 01 00 00 00 # 192.168.100.0/32 차단
# SYN flood 상위 공격자 확인
bpftool map dump pinned /sys/fs/bpf/xdp_ddos/syn_rate | \
sort -t: -k2 -rn | head -20
# XDP 통계 확인
ip -s link show dev eth0 | grep -A5 xdp
conntrackd HA (세션 동기화)
Active-Standby NGFW 클러스터에서 failover 시 기존 세션을 유지하려면 conntrack 테이블을 실시간 동기화해야 합니다:
# /etc/conntrackd/conntrackd.conf (NGFW HA)
Sync {
Mode FTFW { # Fault Tolerant (ack 기반 신뢰성)
DisableExternalCache Off
CommitTimeout 1800
PurgeTimeout 5
}
# 동기화 프로토콜
Multicast {
IPv4_address 225.0.0.50
Group 3780
IPv4_interface 192.168.100.1 # HA 전용 인터페이스
Interface eth2
SndSocketBuffer 1249280
RcvSocketBuffer 1249280
Checksum on
}
}
General {
Nice -20 # 높은 우선순위
HashSize 32768
HashLimit 131072 # 최대 동기화 엔트리
# 동기화 대상 필터 (flowtable 오프로드 세션 포함)
Filter From Kernelspace {
Protocol Accept {
TCP
UDP
}
Address Ignore {
IPv4_address 127.0.0.1 # 로컬 제외
IPv4_address 224.0.0.0/4 # 멀티캐스트 제외
}
}
}
# HA failover 스크립트 (Keepalived notify 스크립트)
#!/bin/bash
# /usr/local/bin/ngfw-failover.sh
case "$1" in
"MASTER")
# Active 전환: flowtable HW offload 재등록
conntrackd -c # 외부 캐시 → 커널 동기화
conntrackd -k # 커널 conntrack 동기화 요청
# eSwitch FDB 규칙 재설치 (기존 EST 세션)
nft flush flowtable inet ngfw ft
nft add flowtable inet ngfw ft \
{ hook ingress priority 0\; devices = { eth0, eth1 }\; flags offload\; }
# 기존 conntrack의 EST 세션을 flowtable에 재등록
# (자동으로 다음 패킷이 도착하면 flow add @ft에 의해 등록됨)
;;
"BACKUP")
# Standby 전환: HW offload 정리
conntrackd -f # 외부 캐시 플러시
nft flush flowtable inet ngfw ft
;;
esac
XDP HW 오프로드와 라인레이트 DDoS 방어
XDP(eXpress Data Path)는 리눅스 커널의 네트워크 스택 최하단에서 BPF 프로그램을 실행하여 패킷을 초기 단계에 처리하는 프레임워크입니다. 특히 HW 오프로드 모드에서는 BPF 프로그램이 NIC의 ASIC/FPGA에서 직접 실행되어, CPU를 전혀 사용하지 않고 라인 레이트(Line Rate)로 패킷을 필터링합니다. 이 절에서는 XDP의 3가지 동작 모드, HW 오프로드의 제약사항, 라인레이트 DDoS 필터 구현, 그리고 XDP offload + TC flower + flowtable 3계층 방어 아키텍처를 다룹니다.
XDP 오프로드 모드 비교
XDP는 BPF 프로그램이 실행되는 위치에 따라 세 가지 모드로 동작합니다. 각 모드는 성능, 호환성, 기능 제약 사이의 트레이드오프(Trade-off)가 다릅니다.
| 모드 | 실행 위치 | SKB 생성 | 100G NIC 기준 pps | CPU 사용 | NIC 요구사항 | 커널 API 플래그 |
|---|---|---|---|---|---|---|
| Generic (SKB) | 네트워크 스택 내부 (tc ingress 이후) | O (SKB 할당) | ~1~3 Mpps | 높음 | 없음 (모든 NIC) | XDP_FLAGS_SKB_MODE |
| Native (Driver) | NIC 드라이버 NAPI poll 내부 (SKB 전) | X (xdp_buff 직접) | ~24~40 Mpps | 중간 (코어당) | XDP 지원 드라이버 | XDP_FLAGS_DRV_MODE |
| Offload (HW) | NIC ASIC/FPGA 내부 | X | ~148 Mpps (라인 레이트) | 없음 (zero CPU) | XDP HW offload 지원 NIC | XDP_FLAGS_HW_MODE |
XDP 프로그램의 모드별 로딩 방법은 다음과 같습니다.
# Generic 모드 — 모든 NIC에서 동작 (테스트 용도)
ip link set dev eth0 xdpgeneric obj xdp_filter.o sec xdp
# Native 모드 — 드라이버 레벨 (고성능, 대부분의 최신 NIC)
ip link set dev eth0 xdp obj xdp_filter.o sec xdp
# HW Offload 모드 — NIC ASIC에서 직접 실행 (라인 레이트)
ip link set dev eth0 xdpoffload obj xdp_filter.o sec xdp
# 현재 XDP 프로그램 확인
ip link show dev eth0
# 출력 예: ... xdpoffload prog/id 42 tag abc123...
# XDP 프로그램 제거
ip link set dev eth0 xdpoffload off
# 커널에서 XDP HW offload 지원 여부 확인
ethtool -i eth0 | grep driver
# Netronome: nfp
# NVIDIA: mlx5_core
bpftool feature probe dev eth0 | grep xdp
XDP HW 오프로드 제약사항과 지원 NIC
XDP HW 오프로드는 BPF 프로그램을 NIC 내부의 프로세서(마이크로엔진, FPGA 등)에서 실행하므로, CPU 기반 실행과는 다른 엄격한 제약이 있습니다.
| NIC | 칩셋 | HW Offload 지원 | 명령어 제한 | 지원 맵 타입 | 특이사항 |
|---|---|---|---|---|---|
| Netronome Agilio CX | NFP-4000/6000 | 완전 지원 | 최대 4,000+ BPF 명령어 | HASH, ARRAY, LPM_TRIE | 가장 성숙한 XDP HW offload 지원 |
| NVIDIA ConnectX-6+ | mlx5 | 부분 지원 | 제한적 (단순 필터) | 제한적 | XDP_DROP/XDP_PASS 중심, 복잡한 로직 미지원 |
| Intel E810 | ice | 미지원 | N/A | N/A | Native XDP만 지원, HW offload 계획 없음 |
| Broadcom BCM5760x | bnxt | 미지원 | N/A | N/A | Native XDP 지원 |
HW 오프로드 모드에서의 주요 제약사항은 다음과 같습니다.
- 루프(Loop) 금지: BPF 검증기(Verifier)의 bounded loop도 HW에서는 지원되지 않습니다. 모든 반복 작업은 언롤링(Unrolling)해야 합니다.
- 꼬리 호출(Tail Call) 미지원:
bpf_tail_call()은 HW 오프로드에서 사용할 수 없습니다. - 헬퍼 함수 제한:
bpf_map_lookup_elem(),bpf_map_update_elem()등 기본 맵 연산만 지원되며,bpf_ktime_get_ns(),bpf_trace_printk()등 커널 의존 헬퍼는 사용할 수 없습니다. - 맵 타입 제한:
BPF_MAP_TYPE_HASH,BPF_MAP_TYPE_ARRAY,BPF_MAP_TYPE_LPM_TRIE정도만 지원됩니다. - 명령어 수 제한: NIC의 마이크로엔진 메모리 크기에 따라 BPF 명령어 수가 제한됩니다. Netronome NFP는 4,000개 이상을 지원하지만, 복잡한 프로그램은 최적화가 필요합니다.
- 패킷 수정 제한: 일부 NIC에서는
XDP_TX(수정 후 재전송)가 HW 오프로드에서 동작하지 않습니다.
bpftool prog load xdp_filter.o /sys/fs/bpf/xdp_filter dev eth0 type xdp offload_dev eth0 명령으로 로드를 시도하면, 검증기가 HW 미지원 기능을 즉시 알려줍니다.
라인레이트 DDoS 필터 구현
HW 오프로드 가능한 XDP 프로그램으로 라인 레이트 DDoS 방어 필터를 구현합니다. 핵심 전략은 세 가지입니다: (1) LPM Trie 기반 IP 블랙리스트, (2) SYN 검증, (3) 소스별 패킷 레이트 제한입니다.
/* xdp_ddos_filter.c — HW offload 가능 DDoS 필터 */
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_endian.h>
/* LPM Trie 키: prefix + IPv4 주소 */
struct lpm_key {
__u32 prefixlen;
__u32 addr;
};
/* 소스 IP별 카운터 */
struct rate_info {
__u64 packets;
__u64 bytes;
__u64 last_reset; /* HW 모드에서는 userspace에서 리셋 */
};
/* IP 블랙리스트 — LPM Trie (CIDR 매칭) */
struct {
__uint(type, BPF_MAP_TYPE_LPM_TRIE);
__uint(max_entries, 100000);
__type(key, struct lpm_key);
__type(value, __u64); /* drop counter */
__uint(map_flags, BPF_F_NO_PREALLOC);
} ip_blocklist SEC(".maps");
/* 소스 IP별 레이트 카운터 */
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 1000000);
__type(key, __u32); /* src IP */
__type(value, struct rate_info);
} rate_counters SEC(".maps");
/* 글로벌 설정 (userspace에서 업데이트) */
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(max_entries, 4);
__type(key, __u32);
__type(value, __u64);
} config SEC(".maps");
/* 설정 인덱스 */
#define CFG_RATE_LIMIT_PPS 0 /* 소스당 최대 pps */
#define CFG_RATE_LIMIT_BPS 1 /* 소스당 최대 bps */
#define CFG_SYN_VALIDATE 2 /* SYN 검증 활성화 여부 */
#define CFG_DROP_COUNTER 3 /* 전체 드롭 카운터 */
static __always_inline __u64 get_config(__u32 idx)
{
__u32 key = idx;
__u64 *val = bpf_map_lookup_elem(&config, &key);
return val ? *val : 0;
}
SEC("xdp")
int xdp_ddos_filter(struct xdp_md *ctx)
{
void *data = (void *)(long)ctx->data;
void *data_end = (void *)(long)ctx->data_end;
/* 이더넷 헤더 파싱 */
struct ethhdr *eth = data;
if ((void *)(eth + 1) > data_end)
return XDP_PASS;
/* IPv4만 처리 */
if (eth->h_proto != bpf_htons(ETH_P_IP))
return XDP_PASS;
struct iphdr *ip = (void *)(eth + 1);
if ((void *)(ip + 1) > data_end)
return XDP_PASS;
__u32 src_ip = ip->saddr;
/* === 1단계: LPM Trie IP 블랙리스트 === */
struct lpm_key lpm = {
.prefixlen = 32,
.addr = src_ip,
};
__u64 *blocked = bpf_map_lookup_elem(&ip_blocklist, &lpm);
if (blocked) {
__sync_fetch_and_add(blocked, 1);
return XDP_DROP;
}
/* === 2단계: 소스별 레이트 제한 === */
__u64 max_pps = get_config(CFG_RATE_LIMIT_PPS);
if (max_pps > 0) {
struct rate_info *info;
info = bpf_map_lookup_elem(&rate_counters, &src_ip);
if (info) {
__u64 cur = __sync_fetch_and_add(&info->packets, 1);
__sync_fetch_and_add(&info->bytes,
data_end - data);
if (cur > max_pps)
return XDP_DROP;
} else {
struct rate_info new_info = {
.packets = 1,
.bytes = data_end - data,
.last_reset = 0,
};
bpf_map_update_elem(&rate_counters, &src_ip,
&new_info, BPF_NOEXIST);
}
}
/* === 3단계: TCP SYN 검증 === */
if (ip->protocol == IPPROTO_TCP) {
struct tcphdr *tcp = (void *)ip + (ip->ihl * 4);
if ((void *)(tcp + 1) > data_end)
return XDP_DROP;
__u64 syn_check = get_config(CFG_SYN_VALIDATE);
if (syn_check && tcp->syn && !tcp->ack) {
/*
* SYN 패킷 레이트 제한:
* HW 모드에서는 SYN cookie 계산이 불가능하므로,
* 단순 레이트 기반 SYN flood 완화를 적용합니다.
* 소스 IP당 SYN 레이트가 임계치 초과 시 DROP.
*/
struct rate_info *info;
info = bpf_map_lookup_elem(&rate_counters, &src_ip);
if (info && info->packets > (max_pps / 10))
return XDP_DROP;
}
}
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";
# BPF 프로그램 컴파일 (HW offload 호환)
clang -O2 -g -target bpf \
-D__TARGET_ARCH_x86 \
-c xdp_ddos_filter.c \
-o xdp_ddos_filter.o
# HW offload 모드로 로드 (Netronome Agilio CX 예시)
ip link set dev eth0 xdpoffload obj xdp_ddos_filter.o sec xdp
# 로드 확인
bpftool prog show dev eth0
# 출력 예:
# 42: xdp tag abc123def456 dev eth0 offloaded
# loaded_at 2026-03-26T10:00:00+0900 uid 0
# xlated 384B jited 0B memlock 4096B
# map_ids 10,11,12
# IP 블랙리스트에 CIDR 추가 (userspace에서 맵 업데이트)
bpftool map update id 10 \
key hex 20 00 00 00 c0 a8 01 00 \
value hex 00 00 00 00 00 00 00 00
# → 192.168.1.0/32 차단
# 대역 차단 (/24)
bpftool map update id 10 \
key hex 18 00 00 00 0a 00 01 00 \
value hex 00 00 00 00 00 00 00 00
# → 10.0.1.0/24 차단
# 레이트 제한 설정 (소스당 10000 pps)
bpftool map update id 12 \
key hex 00 00 00 00 \
value hex 10 27 00 00 00 00 00 00
# SYN 검증 활성화
bpftool map update id 12 \
key hex 02 00 00 00 \
value hex 01 00 00 00 00 00 00 00
# 레이트 카운터 주기적 리셋 (cron 또는 userspace 데몬)
# HW 모드에서는 bpf_ktime_get_ns()를 사용할 수 없으므로
# userspace에서 주기적으로 카운터를 리셋해야 합니다
while true; do
bpftool map dump id 11 | \
awk '/key:/{k=$2} /packets:/{if($2>0) print k}' | \
while read key; do
bpftool map delete id 11 key hex $key
done
sleep 1
done
# 드롭 통계 확인
bpftool map dump id 10 # IP별 드롭 카운터
bpftool map dump id 12 # 글로벌 설정 및 통계
__sync_fetch_and_add()(원자적 카운터 증가)는 Netronome NFP에서 지원되지만, 모든 HW 오프로드 NIC에서 보장되지는 않습니다. 또한 BPF_F_NO_PREALLOC 플래그가 붙은 LPM Trie는 HW 맵으로 변환될 때 사전 할당(Pre-allocation)될 수 있어, max_entries를 실제 사용량에 맞게 설정해야 NIC 메모리를 초과하지 않습니다.
XDP offload + TC flower + flowtable 3계층 아키텍처
NGFW에서 최적의 DDoS 방어와 세션 오프로드를 달성하려면, XDP HW offload, TC flower eSwitch, nf_flowtable 세 가지 메커니즘을 계층적으로 조합해야 합니다. 각 계층은 서로 다른 유형의 트래픽을 담당하며, 상위 계층이 처리하지 못한 패킷만 하위 계층으로 전달됩니다.
| 계층 | 처리 위치 | 담당 역할 | 처리량 (100G 기준) | 패킷 판단 기준 |
|---|---|---|---|---|
| Layer 1: XDP HW Offload | NIC ASIC/FPGA | 볼류메트릭 DDoS 사전 필터 | 100Gbps (라인 레이트) | IP 블랙리스트, 레이트 제한, 프로토콜 이상 |
| Layer 2: TC flower eSwitch | NIC eSwitch FDB | 세션 레벨 ACL / NAT 오프로드 | 40~80Gbps | 5-tuple 매칭, conntrack 상태, NAT 변환 |
| Layer 3: nf_flowtable | 커널 소프트웨어 | 확립된 세션 고속 포워딩 | 10~20Gbps | conntrack ESTABLISHED, flowtable 등록 |
| Slow Path | 커널 전체 스택 | 전체 DPI/IPS/App-ID 검사 | 1~5Gbps | 새 세션, 분류 미완료 패킷 |
3계층 아키텍처의 패킷 처리 흐름은 다음과 같습니다.
- Layer 1 — XDP HW Offload (라인 레이트 필터): NIC가 패킷을 수신하면, ASIC에 로드된 XDP BPF 프로그램이 먼저 실행됩니다. IP 블랙리스트 매칭(
LPM_TRIE)과 소스별 레이트 제한을 수행하여, DDoS 공격 트래픽을 CPU에 도달하기 전에 차단합니다. 이 단계에서 볼류메트릭 공격의 대부분(90%+)이 제거됩니다. - Layer 2 — TC flower eSwitch (세션 레벨 오프로드): XDP를 통과한 패킷은 eSwitch FDB(Forwarding Database)의 TC flower 규칙을 확인합니다. flowtable에 의해 설치된 HW 오프로드 규칙이 매칭되면, NIC 내부에서 NAT 변환과 MAC/VLAN 재작성을 수행하여 즉시 포워딩합니다.
- Layer 3 — nf_flowtable (SW 고속 경로): HW 오프로드가 불가능한 세션(예: GRE 터널, 소프트웨어 브릿지)이지만 conntrack ESTABLISHED 상태인 경우, 커널의 flowtable 소프트웨어 경로에서 Netfilter 훅을 우회하여 고속 포워딩합니다.
- Slow Path — 전체 검사: 위 세 계층 어디에도 해당하지 않는 패킷(새 세션, 미분류 트래픽)은 전체 Netfilter 훅 체인, conntrack, NFQUEUE DPI/IPS 검사를 거칩니다.
# === 3계층 구성 예시 ===
# --- Layer 1: XDP HW Offload (DDoS 사전 필터) ---
ip link set dev eth0 xdpoffload obj xdp_ddos_filter.o sec xdp
# --- Layer 2: TC flower + CT offload (세션 레벨) ---
# eSwitch 모드 활성화
devlink dev eswitch set pci/0000:03:00.0 mode switchdev
# CT offload 지원 TC flower 규칙 (nftables flowtable이 자동 생성)
# 수동 예시: 특정 서브넷 간 트래픽 HW 오프로드
tc filter add dev eth0 ingress protocol ip \
flower ct_state +trk+est \
ip_proto tcp \
action ct zone 1 pipe \
action mirred egress redirect dev eth1
# --- Layer 3: nf_flowtable (SW 고속 경로) ---
nft add table inet filter
nft add flowtable inet filter ft \
'{ hook ingress priority 0; devices = { eth0, eth1 }; flags offload; }'
nft add chain inet filter forward \
'{ type filter hook forward priority 0; }'
nft add rule inet filter forward \
ct state established,related flow add @ft accept
nft add rule inet filter forward \
ct state new accept
# flowtable offload 상태 확인
nft list flowtable inet filter ft
conntrack -L | grep OFFLOAD
# HW 오프로드 규칙 확인
tc filter show dev eth0 ingress | grep -A5 "ct_state"
위 다이어그램은 3계층 방어 아키텍처의 패킷 흐름을 보여줍니다. 패킷이 수신되면 Layer 1(XDP HW Offload)에서 볼류메트릭 DDoS를 라인 레이트로 차단하고, 통과한 패킷은 Layer 2(TC flower eSwitch)에서 확립된 세션을 하드웨어 포워딩하며, HW 오프로드가 불가능한 세션은 Layer 3(nf_flowtable)에서 소프트웨어 고속 경로로 처리합니다. 어느 계층에도 해당하지 않는 새 세션만 Slow Path의 전체 DPI/IPS 검사를 거칩니다. Slow Path에서 ESTABLISHED로 전환된 세션은 flowtable을 통해 Layer 2로 승격(오프로드)됩니다.
보안 vs 오프로드 트레이드오프
트레이드오프 모델
NGFW에서 가장 중요한 설계 결정은 어느 수준의 보안 검사를 활성화하고, 어느 지점에서 오프로드할 것인가입니다. 이 결정이 전체 시스템의 처리량을 결정합니다.
보안 기능을 추가할수록 오프로드 가능한 트래픽 비율이 줄어듭니다. 대략적인 모델:
- L4 ACL만 — 오프로드 비율 ~95%. 거의 모든 ESTABLISHED 세션이 Fast Path
- +IPS — 오프로드 비율 ~80%. 첫 패킷 IPS 검사 후 ALLOW된 세션만 오프로드
- +SSL Inspection — 오프로드 비율 ~40%. SSL 복호화가 필요한 세션은 CPU에서 처리
- +Full DPI + 주기적 재검사 — 오프로드 비율 ~20%. 지속적 모니터링이 필요한 세션
오프로드 비율 측정
# conntrack 전체 세션 수
conntrack -C
# flowtable 오프로드된 세션 수
conntrack -L -p tcp --state ESTABLISHED | wc -l
# flowtable 통계 (nftables)
nft list flowtable inet ngfw ft
# ethtool HW offload 카운터
ethtool -S eth0 | grep offload
# 오프로드 비율 계산
# ratio = (flowtable_sessions / total_established) * 100
| 보안 기능 | 오프로드 영향 | 오프로드 비율 | 비고 |
|---|---|---|---|
| L3/L4 Stateful ACL | 영향 없음 | ~95% | HW ct_state 매칭 |
| IPS (시그니처 검사) | 첫 패킷만 영향 | ~80% | ALLOW 후 오프로드 |
| App-ID (L7 분류) | 초기 3~10 패킷 | ~75% | 분류 완료 후 오프로드 |
| SSL Inspection | 전체 세션 영향 | ~40% | 복호화 세션은 CPU |
| URL Filtering | HTTP/DNS만 영향 | ~70% | 첫 요청 검사 후 오프로드 |
| DLP (Data Loss Prevention) | 전체 페이로드 검사 | ~30% | 대부분 CPU 처리 |
| 주기적 재검사 (Sampling) | 오프로드 해제 주기 | ~60% | 바이트 임계치 기반 |
위협 회피 대응
공격자가 오프로드 메커니즘을 악용하여 검사를 회피할 수 있는 시나리오와 대응:
| 회피 기법 | 설명 | 대응 |
|---|---|---|
| 첫 패킷 위장 | 정상 프로토콜로 시작 후 ESTABLISHED에서 악성 페이로드 전송 | 주기적 샘플링 (N번째 패킷마다 DPI 재검사) |
| 프로토콜 변경 | HTTP로 시작 후 터널링으로 프로토콜 변경 | 바이트 카운터 감시, 임계치 초과 시 재분류 |
| 저속 공격 (Low & Slow) | 오프로드 유지하며 느린 속도로 데이터 유출 | 세션 지속 시간 제한, 바이트 감사 |
| 단편화 공격 | IP fragment로 DPI 우회 시도 | 단편화 패킷은 Exception Path에서 재조립 후 검사 |
| 세션 하이재킹 | 오프로드된 세션의 5-tuple을 스푸핑하여 주입 | TCP 시퀀스 번호 검증 (SW 샘플링) |
| 암호화 터널링 | 정상 HTTPS 내부에 VPN 터널 생성 | 바이트 패턴 분석, JA3 핑거프린트 |
주기적 샘플링 구현
오프로드된 세션에 대한 주기적 재검사(sampling)는 위협 회피를 방지하는 핵심 메커니즘입니다:
# nftables에서 바이트 기반 샘플링 구현
table inet ngfw_sampling {
chain forward {
type filter hook forward priority -50; policy accept;
# 오프로드된 세션의 패킷이 N번째마다 CPU로 복귀
# (flowtable timeout이 만료되면 자동으로 이 체인을 거침)
# 10MB 이상 전송된 세션 → DPI 재검사
ct state established \
ct bytes gt 10485760 \
ct mark != 0xfe \
queue num 4 bypass # 재검사용 별도 큐
# 1시간 이상 지속된 세션 → 재분류
ct state established \
ct original packets gt 100000 \
ct mark != 0xfe \
queue num 4 bypass
# 재검사 완료 마킹 (중복 방지)
ct state established ct mark 0xfe accept
}
}
정책 설계 가이드
Zone-based 오프로드 정책 매트릭스
네트워크 Zone 간 트래픽 특성에 따라 오프로드 수준을 차별화합니다:
| 소스 Zone | 목적지 Zone | 검사 수준 | 오프로드 정책 | 예상 오프로드율 |
|---|---|---|---|---|
| Trust (내부) | Trust (내부) | L4 ACL만 | 즉시 HW offload | 95%+ |
| Trust | DMZ | L4 ACL + App-ID | 분류 후 SW offload | 80% |
| Trust | Untrust (인터넷) | Full DPI + IPS | DPI 완료 후 offload | 60~70% |
| Untrust | DMZ (서버) | Full DPI + IPS + WAF | DPI 완료 후 offload | 50~60% |
| Untrust | Trust | Full DPI + IPS + DLP | DPI 완료 후 offload (제한적) | 40~50% |
| Guest | Untrust | URL Filter + IPS | URL 검사 후 offload | 65% |
| IoT | Cloud | App-ID + 주기적 재검사 | 조건부 offload (샘플링) | 70% |
nftables Zone 구현 예시
# Zone-based NGFW nftables 설정
table inet ngfw_zones {
# Zone별 flowtable (오프로드 수준 차별화)
flowtable ft_trust {
hook ingress priority 0
devices = { eth0 } # 내부 네트워크
flags offload # HW offload 활성화
}
flowtable ft_untrust {
hook ingress priority 0
devices = { eth1 } # 인터넷 연결
# flags offload 미설정 → SW offload만
}
chain forward {
type filter hook forward priority 0; policy drop;
ct state invalid drop
# Trust → Trust: 즉시 HW offload (DPI 건너뜀)
iifname "eth0" oifname "eth0" \
ct state established,related \
flow add @ft_trust accept
# Trust → Untrust: DPI 검사 후 SW offload
iifname "eth0" oifname "eth1" \
ct state established,related \
flow add @ft_untrust accept
# Untrust → DMZ: 반드시 DPI 검사
iifname "eth1" oifname "eth2" \
ct state new \
queue num 0-3 fanout
# Untrust → DMZ: DPI 완료 후에만 offload
iifname "eth1" oifname "eth2" \
ct state established ct mark 0xff \
flow add @ft_untrust accept
}
}
오프로드 비율 정량 모델
NGFW의 전체 처리량은 Fast Path와 Slow Path의 가중 합으로 모델링됩니다:
Total_Throughput = (Offload_Ratio × Fast_Path_BW) + ((1 - Offload_Ratio) × Slow_Path_BW)
예시: 오프로드 70%, Fast Path 100Gbps, Slow Path 5Gbps인 경우:
Total = (0.70 × 100) + (0.30 × 5) = 70 + 1.5 = 71.5 Gbps
오프로드 비율이 10% 증가하면(70% → 80%):
Total = (0.80 × 100) + (0.20 × 5) = 80 + 1.0 = 81.0 Gbps (+13%)
이 모델에서 Slow Path 처리량(DPI 성능)보다 오프로드 비율을 높이는 것이 전체 성능에 훨씬 큰 영향을 미칩니다. 오프로드 비율 1% 향상은 Slow Path 성능 20% 향상과 동등한 효과를 가집니다.
보안 수준별 성능 영향 시뮬레이션
| 보안 프로파일 | 활성 기능 | 오프로드율 | 100G NIC 실효 처리량 | CPS 영향 |
|---|---|---|---|---|
| Minimal | L4 Stateful ACL | 95% | ~95 Gbps | 200K+ CPS |
| Standard | + IPS + App-ID | 75% | ~76 Gbps | 100K CPS |
| Enhanced | + SSL Inspection | 45% | ~47 Gbps | 30K CPS |
| Maximum | + DLP + AV + 주기적 재검사 | 20% | ~24 Gbps | 10K CPS |
- 오프로드 우선 정책: 내부 트래픽, 신뢰된 애플리케이션은 빠른 오프로드
- 보안 우선 정책: 인터넷 트래픽, 알 수 없는 프로토콜은 DPI 유지
- 하이브리드 접근: 세션 시작 시 DPI 검사 → 분류 완료 후 오프로드 → 주기적 샘플링
성능 튜닝과 벤치마크
RFC 9411 메트릭
NGFW 성능 측정에 사용되는 주요 메트릭 (RFC 9411 — Benchmarking Methodology for Network Security Device Performance):
- CPS (Connections Per Second) — 초당 새 TCP/UDP 연결 수립 수. Slow Path 성능의 핵심 지표
- CC (Concurrent Connections) — 동시 유지 가능한 세션 수. conntrack 테이블 + flowtable 크기
- Throughput — 총 데이터 처리량 (bps). Fast Path + Slow Path 합산
- Latency — 패킷 지연. Fast Path <10us, Slow Path >100us (DPI 포함)
- Offload Ratio — Fast Path로 처리되는 트래픽 비율
IRQ Affinity / NUMA 최적화
NGFW에서 CPU 코어 할당은 성능에 결정적입니다. NIC IRQ, Netfilter, DPI 엔진을 올바른 NUMA 노드와 코어에 배치해야 합니다:
# NUMA 토폴로지 확인
lscpu | grep -E "NUMA|Socket|Core"
# NUMA node0 CPU(s): 0-7 (NIC PCI 슬롯과 같은 노드)
# NUMA node1 CPU(s): 8-15
# NIC의 NUMA 노드 확인
cat /sys/class/net/eth0/device/numa_node
# 0 ← NIC이 NUMA 노드 0에 연결
# IRQ Affinity: NIC IRQ를 같은 NUMA 노드 코어에 바인딩
# eth0의 IRQ 번호 확인
grep eth0 /proc/interrupts | awk '{print $1}' | tr -d ':'
# IRQ 42, 43, 44, 45 (4개 큐)
# 각 IRQ를 NUMA node0 코어에 1:1 바인딩
echo 1 > /proc/irq/42/smp_affinity # CPU 0
echo 2 > /proc/irq/43/smp_affinity # CPU 1
echo 4 > /proc/irq/44/smp_affinity # CPU 2
echo 8 > /proc/irq/45/smp_affinity # CPU 3
# 또는: mlx5/ice 드라이버의 set_irq_affinity 스크립트
/usr/sbin/set_irq_affinity_cpulist.sh 0-3 eth0
NGFW 코어 배치 가이드
| 역할 | 코어 할당 | NUMA 요구 | 이유 |
|---|---|---|---|
| NIC IRQ (NAPI poll) | 0~3 | NIC과 같은 노드 | DMA 버퍼가 로컬 메모리에 위치 |
| XDP pre-filter | 0~3 (IRQ와 동일) | NIC과 같은 노드 | XDP는 NAPI 컨텍스트에서 실행 |
| conntrack / nftables | 0~3 (softirq) | NIC과 같은 노드 | skb가 생성된 코어에서 처리 |
| Suricata DPI 워커 | 4~11 | NIC과 같은 노드 우선 | NFQUEUE 패킷 접근 locality |
| conntrackd (HA) | 12 | 어느 노드든 | netlink 이벤트 수신 |
| 관리 (SSH, 모니터링) | 13~15 | 어느 노드든 | 데이터 플레인과 분리 |
CPS/처리량/지연 최적화
# ===== 1. conntrack 최적화 =====
sysctl -w net.netfilter.nf_conntrack_max=2000000
sysctl -w net.netfilter.nf_conntrack_buckets=500000
# 해시 충돌 최소화: buckets ≥ max/4
# conntrack 타임아웃 단축 (빠른 리소스 회수)
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=300
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=30
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_close_wait=30
# ===== 2. flowtable 최적화 =====
sysctl -w net.netfilter.nf_flowtable_tcp_timeout=300
sysctl -w net.netfilter.nf_flowtable_udp_timeout=30
# ===== 3. NFQUEUE 최적화 =====
sysctl -w net.core.optmem_max=81920
# NFQUEUE 소켓 버퍼 증가 → 버스트 트래픽 대응
sysctl -w net.core.rmem_max=16777216
sysctl -w net.core.wmem_max=16777216
# ===== 4. NIC RSS/ethtool 최적화 =====
# RSS 큐를 IRQ affinity 코어 수에 맞춤
ethtool -L eth0 combined 4
# Interrupt Coalescing (배치 처리로 IRQ 빈도 감소)
ethtool -C eth0 rx-usecs 50 rx-frames 64 \
tx-usecs 50 tx-frames 64 adaptive-rx on
# Ring Buffer 크기 증가 (버스트 흡수)
ethtool -G eth0 rx 4096 tx 4096
# HW offload 기능 활성화
ethtool -K eth0 hw-tc-offload on
ethtool -K eth0 ntuple on
# ===== 5. XDP DDoS pre-filter =====
ip link set dev eth0 xdp obj xdp_ddos_filter.o sec xdp
# ===== 6. eSwitch 최적화 =====
devlink dev eswitch set pci/0000:03:00.0 mode switchdev
devlink dev eswitch set pci/0000:03:00.0 inline-mode transport
# ===== 7. 커널 파라미터 =====
sysctl -w net.core.netdev_budget=600
sysctl -w net.core.netdev_max_backlog=10000
sysctl -w net.ipv4.ip_forward=1
# NAPI busy_poll (지연 최소화)
sysctl -w net.core.busy_read=50
sysctl -w net.core.busy_poll=50
ethtool Interrupt Coalescing 상세
NGFW에서 Interrupt Coalescing은 처리량과 지연 사이의 균형을 결정합니다:
| 설정 | rx-usecs | rx-frames | 적합 시나리오 | 영향 |
|---|---|---|---|---|
| Low Latency | 10 | 8 | VoIP, 금융 트래픽 | IRQ 빈도 높음, CPU 사용률 증가 |
| Balanced | 50 | 64 | 일반 NGFW | 적절한 지연/처리량 균형 |
| High Throughput | 100 | 128 | 대용량 파일 전송 위주 | 지연 증가, 처리량 최대화 |
| Adaptive | adaptive-rx on | - | 트래픽 변동이 큰 환경 | NIC이 트래픽에 따라 자동 조절 |
벤치마크 방법론 (RFC 9411)
NGFW 성능을 올바르게 측정하기 위한 RFC 9411 기반 방법론입니다:
| 테스트 유형 | 측정 대상 | 트래픽 프로파일 | 도구 |
|---|---|---|---|
| CPS 측정 | 초당 새 TCP 연결 | 1-packet HTTP 요청 (MSS 크기) | TRex, iperf3 --parallel |
| 처리량 (Throughput) | Mbps/Gbps | ESTABLISHED 대량 UDP/TCP 스트림 | TRex, DPDK pktgen |
| Latency 측정 | 패킷 지연 | 고정 크기 패킷 스트림 | moongen, TRex |
| NGFW 처리량 | DPI 활성 시 처리량 | HTTP/HTTPS 혼합 실제 트래픽 | TRex ASTF (app-layer) |
| SSL 처리량 | SSL 인스펙션 시 처리량 | TLS 1.2/1.3 혼합 | TRex + nginx SSL 백엔드 |
| 혼합 부하 | CPS + 처리량 동시 | 실제 트래픽 PCAP 재생 | TRex 리플레이 모드 |
# TRex를 사용한 NGFW 벤치마크 예시
# 1. CPS 측정 (TCP SYN flood → 세션 수립률 측정)
./t-rex-64 -f cap2/http_simple.yaml \
--duration 60 --multiplier 100000 \
--latency 1000
# 2. 처리량 측정 (기존 세션에 대량 트래픽)
./t-rex-64 -f cap2/imix_64_594_1518.yaml \
--duration 120 --multiplier 1 \
--astf # Application-layer TRex
# 3. 결과에서 Fast Path / Slow Path 분리 확인
# TRex 실행 중 DUT에서:
conntrack -C # 전체 세션 수
conntrack -L --status OFFLOAD | wc -l # 오프로드 세션
ethtool -S eth0 | grep tx_packets_phy # HW 처리 패킷
| 메트릭 | HW Fast Path | SW Fast Path | Slow Path (DPI) |
|---|---|---|---|
| 처리량 (64B 패킷) | 148.8 Mpps (100GbE) | 10~20 Mpps | 1~3 Mpps |
| 처리량 (1518B 패킷) | 8.1 Mpps (100GbE) | 3~5 Mpps | 0.5~1 Mpps |
| 지연 (Latency) | <5 us | 10~50 us | 100~500 us |
| CPS (초당 새 연결) | N/A (오프로드만) | N/A | 50K~200K/core |
| 동시 세션 | NIC 의존 (1M~) | conntrack_max | conntrack_max |
| CPU 코어 사용 | 0 | 1~2 코어 | 4~16 코어 |
패킷 크기별 성능 특성
NGFW 성능은 패킷 크기에 크게 의존합니다. 작은 패킷은 PPS(초당 패킷)에 의해, 큰 패킷은 BPS(초당 비트)에 의해 제한됩니다:
| 패킷 크기 | HW offload PPS | HW offload BPS | SW flowtable PPS | DPI (Slow Path) PPS | 주요 트래픽 |
|---|---|---|---|---|---|
| 64B | 148.8 Mpps | 76.2 Gbps | 15 Mpps | 2 Mpps | TCP ACK, SYN |
| 128B | 84.5 Mpps | 86.5 Gbps | 12 Mpps | 1.5 Mpps | VoIP (G.711) |
| 256B | 45.3 Mpps | 92.8 Gbps | 8 Mpps | 1 Mpps | DNS 응답 |
| 512B | 23.5 Mpps | 96.3 Gbps | 5 Mpps | 0.8 Mpps | 웹 요청 |
| 1024B | 12.0 Mpps | 98.3 Gbps | 3.5 Mpps | 0.6 Mpps | 파일 전송 |
| 1518B (MTU) | 8.1 Mpps | 98.4 Gbps | 3 Mpps | 0.5 Mpps | 대용량 전송 |
| IMIX (혼합) | ~30 Mpps | ~80 Gbps | ~8 Mpps | ~1 Mpps | 실제 트래픽 |
IMIX(Internet Mix)는 실제 인터넷 트래픽을 모사한 혼합 패킷 크기 분포입니다 (7:4:1 비율로 64B:594B:1518B). NGFW 벤치마크에서는 IMIX 또는 HTTP 애플리케이션 트래픽을 사용하는 것이 실제 환경에 가장 가깝습니다.
성능 최적화 체크리스트
- 오프로드 비율 극대화 — flowtable + HW offload로 EST 세션 비율 70%+ 달성 (가장 큰 효과)
- NFQUEUE 최적화 — fanout 분산 + batchcount + fail-open으로 DPI 병목 해소
- IRQ/NUMA 최적화 — NIC IRQ를 같은 NUMA 노드 코어에 바인딩
- conntrack 튜닝 — 해시 버킷 최적화 + 타임아웃 단축으로 테이블 효율 향상
- Interrupt Coalescing — ethtool -C로 IRQ 빈도 최적화
- XDP pre-filter — DDoS/스캔 트래픽을 가장 빠른 경로에서 DROP
- DPI 시그니처 최적화 — 불필요한 시그니처 비활성화로 Suricata 부하 감소
진단과 모니터링
모니터링 아키텍처
NGFW의 각 구성 요소에서 메트릭을 수집하여 중앙 모니터링 시스템으로 전달하는 아키텍처입니다:
핵심 알림 규칙
| 알림 | 조건 | 심각도 | 대응 |
|---|---|---|---|
| conntrack 포화 | entries/max > 0.8 | Warning | nf_conntrack_max 증가 또는 타임아웃 단축 |
| conntrack 가득 참 | entries/max > 0.95 | Critical | 즉시 타임아웃 단축 + early_drop 활성화 |
| NFQUEUE 드롭 | drops/s > 0 | Warning | Suricata 워커 증가 또는 batchcount 조정 |
| 오프로드 비율 저하 | ratio < 0.5 | Warning | flowtable 설정 확인, ALG 세션 분석 |
| HW offload 실패 | devlink trap 증가 | Info | NIC 펌웨어(Firmware)/드라이버 업데이트 확인 |
| DPI 엔진 과부하 | Suricata kernel_drops > 0 | Critical | 워커 스레드(Thread) 추가, 규칙 최적화 |
flowtable 진단
# flowtable 오프로드 상태 확인
nft list flowtable inet ngfw ft
# conntrack 테이블에서 offloaded 세션 확인
conntrack -L --status OFFLOAD
# conntrack 이벤트 실시간 모니터
conntrack -E -e NEW,DESTROY
# TC flower 오프로드 규칙 통계
tc -s filter show dev eth0_rep0 ingress
# eSwitch FDB 규칙 확인
tc -s filter show dev eth0_rep0 ingress chain 0
# ethtool 오프로드 카운터
ethtool -S eth0 | grep -E '(offload|flower|ct)'
# devlink 트랩 (오프로드 실패 원인)
devlink trap show pci/0000:03:00.0
bpftrace / perf 진단
# flowtable offload 이벤트 추적
bpftrace -e 'kprobe:nf_flow_offload_add { printf("flow offload add: %s\n", comm); }'
# conntrack NEW 이벤트 빈도 측정 (CPS 추정)
bpftrace -e 'kprobe:__nf_conntrack_alloc { @cps = count(); }
interval:s:1 { printf("CPS: %d\n", @cps); clear(@cps); }'
# NFQUEUE 지연 측정
perf probe -a 'nf_queue_entry_get_refs'
perf stat -e probe:nf_queue_entry_get_refs -a sleep 10
# Netfilter 훅 처리 시간 분포
bpftrace -e 'kprobe:nf_hook_slow { @start[tid] = nsecs; }
kretprobe:nf_hook_slow /@start[tid]/ {
@latency_us = hist((nsecs - @start[tid]) / 1000);
delete(@start[tid]);
}'
Prometheus 메트릭 수집
NGFW의 성능을 지속적으로 모니터링하기 위한 주요 메트릭과 수집 방법입니다:
#!/bin/bash
# /usr/local/bin/ngfw-metrics.sh
# node_exporter textfile collector용 메트릭 생성
METRICS_DIR="/var/lib/node_exporter/textfile_collector"
{
# conntrack 메트릭
ct_count=$(conntrack -C 2>/dev/null || echo 0)
ct_max=$(sysctl -n net.netfilter.nf_conntrack_max)
echo "ngfw_conntrack_entries $ct_count"
echo "ngfw_conntrack_max $ct_max"
echo "ngfw_conntrack_utilization $(echo "scale=4; $ct_count/$ct_max" | bc)"
# flowtable 오프로드 세션 수
offloaded=$(conntrack -L --status OFFLOAD 2>/dev/null | wc -l)
echo "ngfw_flowtable_offloaded_sessions $offloaded"
# 오프로드 비율
established=$(conntrack -L -p tcp --state ESTABLISHED 2>/dev/null | wc -l)
if [ "$established" -gt 0 ]; then
ratio=$(echo "scale=4; $offloaded/$established" | bc)
echo "ngfw_offload_ratio $ratio"
fi
# NIC HW offload 카운터 (mlx5)
for stat in tx_packets_phy rx_packets_phy \
rx_vport_rdma_unicast_packets \
tx_vport_rdma_unicast_packets; do
val=$(ethtool -S eth0 2>/dev/null | grep "$stat" | awk '{print $2}')
[ -n "$val" ] && echo "ngfw_nic_${stat} $val"
done
# TC flower 규칙 수
tc_rules=$(tc -s filter show dev eth0_rep0 ingress 2>/dev/null | grep -c "filter")
echo "ngfw_tc_flower_rules $tc_rules"
# NFQUEUE 드롭 (과부하 지표)
nfq_drops=$(cat /proc/net/netfilter/nfnetlink_queue 2>/dev/null | \
awk '{sum+=$5} END {print sum+0}')
echo "ngfw_nfqueue_drops $nfq_drops"
} > "$METRICS_DIR/ngfw.prom.$$"
mv "$METRICS_DIR/ngfw.prom.$$" "$METRICS_DIR/ngfw.prom"
실시간 성능 대시보드 스크립트
#!/bin/bash
# /usr/local/bin/ngfw-dashboard.sh — 실시간 NGFW 상태
watch -n 1 '
echo "===== NGFW Status ====="
echo ""
echo "--- Conntrack ---"
printf " Entries: %s / %s\n" $(conntrack -C) $(sysctl -n net.netfilter.nf_conntrack_max)
printf " Offloaded: %s\n" $(conntrack -L --status OFFLOAD 2>/dev/null | wc -l)
echo ""
echo "--- Flowtable ---"
nft list flowtable inet ngfw ft 2>/dev/null | tail -5
echo ""
echo "--- TC flower (HW rules) ---"
tc -s filter show dev eth0_rep0 ingress 2>/dev/null | \
grep -E "(filter|action|Sent)" | head -20
echo ""
echo "--- NIC Offload Stats ---"
ethtool -S eth0 2>/dev/null | grep -E "(offload|flower|ct)" | head -10
echo ""
echo "--- NFQUEUE ---"
cat /proc/net/netfilter/nfnetlink_queue 2>/dev/null
'
트러블슈팅 체크리스트
- eSwitch 모드 확인:
devlink dev eswitch show→mode switchdev인가? - hw-tc-offload 활성화:
ethtool -k eth0 | grep hw-tc-offload→on인가? - flowtable flags offload: nftables flowtable에
flags offload가 설정되었는가? - NIC 드라이버 지원: mlx5/ice 등 TC flower ct offload를 지원하는 드라이버인가?
- conntrack 상태:
conntrack -L --status OFFLOAD에 엔트리가 있는가? - devlink trap 확인: HW offload 실패 이유가 trap으로 보고되는가?
- 커널 버전: flowtable HW offload는 커널 5.13+, CT offload는 5.7+ 필요
- 펌웨어 버전: NIC 펌웨어가 CT offload를 지원하는 버전인가?
자주 발생하는 문제와 해결
| 증상 | 원인 | 해결 방법 |
|---|---|---|
| 오프로드 비율이 0% | flowtable에 flags offload 미설정 |
nft list flowtable에서 flags 확인 → offload 추가 |
| HW offload는 되지만 NAT가 안 됨 | TC flower에서 ct nat action 누락 |
TC 규칙에 action ct zone 1 nat 추가 |
| conntrack 테이블이 빠르게 가득 참 | DDoS/스캔으로 인한 NEW 세션 폭주 | XDP pre-filter 활성화 + conntrack 타임아웃 단축 |
| NFQUEUE에서 패킷 드롭 | Suricata 처리 속도 부족 | 워커 스레드 증가, batchcount 최적화, bypass 활성화 |
| flowtable 세션이 빠르게 만료 | nf_flowtable_tcp_timeout이 너무 짧음 |
300초 이상으로 증가 (conntrack EST 타임아웃과 동기화) |
| 특정 세션이 오프로드되지 않음 | ALG helper가 할당된 세션 | conntrack -L | grep helper로 확인 → 정상 동작 (ALG는 오프로드 불가) |
| eSwitch 전환 후 네트워크 끊김 | switchdev 모드 전환 시 VF 재설정 필요 | VF representor 재생성 + IP 재설정 |
| TC flower 규칙이 HW에 설치되지 않음 | NIC가 해당 매칭 조건 미지원 | dmesg | grep tc로 에러 확인 → SW 폴백 또는 규칙 단순화 |
디버깅용 커널 트레이싱
# flowtable 이벤트 전체 추적 (디버깅 시에만 사용)
# 주의: 프로덕션에서는 성능 영향 있음
# 1. ftrace로 flowtable 함수 추적
echo 'nf_flow_offload*' > /sys/kernel/debug/tracing/set_ftrace_filter
echo function > /sys/kernel/debug/tracing/current_tracer
echo 1 > /sys/kernel/debug/tracing/tracing_on
cat /sys/kernel/debug/tracing/trace_pipe | head -100
echo 0 > /sys/kernel/debug/tracing/tracing_on
# 2. perf로 Netfilter 훅 프로파일링
perf top -g -e cycles:k --filter='nf_*'
# 3. bpftrace: flowtable HW offload 성공/실패 추적
bpftrace -e '
kprobe:nf_flow_offload_hw_add {
printf("HW add: ct=%p\n", arg2);
}
kretprobe:nf_flow_offload_hw_add /retval != 0/ {
printf("HW add FAILED: err=%d\n", retval);
}
kprobe:nf_flow_offload_hw_del {
printf("HW del: flow=%p\n", arg1);
}'
# 4. conntrack 이벤트와 flowtable 이벤트 상관관계 추적
bpftrace -e '
kprobe:nf_conntrack_in {
@ct_in = count();
}
kprobe:nf_flow_offload_ip_hook {
@flow_hit = count();
}
interval:s:5 {
printf("conntrack_in: %d, flow_hit: %d, ratio: ",
@ct_in, @flow_hit);
printf("%d%%\n",
@flow_hit * 100 / (@ct_in + @flow_hit + 1));
clear(@ct_in); clear(@flow_hit);
}'
커널 설정
커널 버전 요구사항
NGFW HW offload의 각 기능에 필요한 최소 커널 버전입니다:
| 기능 | 최소 커널 | 권장 커널 | 관련 커밋/패치(Patch) |
|---|---|---|---|
| nf_flowtable 기본 | 4.16 | 5.13+ | nf_flow_table 모듈 도입 |
| flowtable HW offload | 5.13 | 6.1+ | NF_FLOWTABLE_HW_OFFLOAD 플래그 |
| TC flower ct action | 5.7 | 5.13+ | NET_ACT_CT 모듈 |
| mlx5 CT offload | 5.7 | 5.15+ | MLX5_TC_CT 설정 |
| ice eSwitch switchdev | 5.15 | 6.1+ | ICE_SWITCHDEV 설정 |
| nftables BPF verdict | 5.18 | 6.1+ | BPF netfilter 프로그램 타입 |
| xfrm packet offload | 6.1 | 6.6+ | XFRM_OFFLOAD 확장 |
| flowtable VLAN offload | 5.17 | 6.1+ | VLAN push/pop 지원 |
| conntrack zone offload | 5.10 | 5.15+ | CT zone HW 지원 |
필수 CONFIG_* 옵션
# Netfilter / conntrack
CONFIG_NF_CONNTRACK=y
CONFIG_NF_TABLES=y
CONFIG_NF_TABLES_INET=y
CONFIG_NFT_FLOW_OFFLOAD=y # flowtable offload 지원
CONFIG_NF_FLOW_TABLE=y # nf_flowtable 코어
CONFIG_NF_FLOW_TABLE_INET=y
CONFIG_NETFILTER_NETLINK_QUEUE=y # NFQUEUE
# HW offload (eSwitch/TC)
CONFIG_NET_SWITCHDEV=y # switchdev 프레임워크
CONFIG_NET_CLS_FLOWER=y # TC flower classifier
CONFIG_NET_ACT_CT=y # TC conntrack action
CONFIG_NET_ACT_MIRRED=y # TC mirred (redirect)
CONFIG_NET_ACT_PEDIT=y # TC packet edit
CONFIG_NET_ACT_TUNNEL_KEY=y # TC tunnel encap/decap
# NIC 드라이버 (예: NVIDIA ConnectX)
CONFIG_MLX5_CORE=y
CONFIG_MLX5_ESWITCH=y
CONFIG_MLX5_TC_CT=y # mlx5 CT offload
# XDP
CONFIG_XDP_SOCKETS=y
CONFIG_BPF_SYSCALL=y
CONFIG_BPF_JIT=y
# IPSec HW offload
CONFIG_XFRM=y
CONFIG_XFRM_OFFLOAD=y
CONFIG_INET_ESP_OFFLOAD=y
# conntrack 헬퍼 (ALG 프로토콜)
CONFIG_NF_CONNTRACK_FTP=m # FTP ALG
CONFIG_NF_CONNTRACK_SIP=m # SIP ALG
CONFIG_NF_CONNTRACK_H323=m # H.323 ALG
CONFIG_NF_CONNTRACK_TFTP=m # TFTP ALG
CONFIG_NF_CONNTRACK_PPTP=m # PPTP ALG
CONFIG_NF_CT_NETLINK=y # conntrackd 통신
# NAT 관련
CONFIG_NF_NAT=y
CONFIG_NF_NAT_MASQUERADE=y
CONFIG_NFT_NAT=y
CONFIG_NFT_MASQ=y
# NFQUEUE 관련
CONFIG_NETFILTER_NETLINK_QUEUE=y
CONFIG_NFT_QUEUE=y # nft queue 표현식
# Intel E810 드라이버 (대안 NIC)
CONFIG_ICE=y
CONFIG_ICE_SWITCHDEV=y # ice eSwitch 지원
# QoS 관련
CONFIG_NET_SCH_HTB=y # HTB qdisc
CONFIG_NET_SCH_FQ_CODEL=y # fq_codel (AQM)
CONFIG_NET_SCH_MQPRIO=y # HW QoS 큐 매핑
CONFIG_NET_SCH_INGRESS=y # TC ingress qdisc
모듈 로딩 순서와 검증
NGFW 관련 커널 모듈(Kernel Module)은 의존성 순서대로 로드해야 합니다. 다음은 systemd 서비스 이전에 실행할 모듈 로딩 스크립트입니다:
#!/bin/bash
# /usr/local/sbin/ngfw-modules-load.sh
# NGFW 커널 모듈 로딩 (의존성 순서)
set -e
# 1단계: 기본 Netfilter 프레임워크
modprobe nf_conntrack
modprobe nf_tables
modprobe nft_chain_nat
modprobe nft_ct # nft ct 표현식
# 2단계: flowtable 오프로드
modprobe nf_flow_table
modprobe nf_flow_table_inet
modprobe nft_flow_offload # nft flow offload 표현식
# 3단계: NFQUEUE (DPI 엔진 연동)
modprobe nfnetlink_queue
modprobe nft_queue # nft queue 표현식
# 4단계: TC offload 프레임워크
modprobe act_ct # TC conntrack action
modprobe act_mirred # TC redirect action
modprobe act_pedit # TC packet edit
modprobe cls_flower # TC flower classifier
# 5단계: conntrack 헬퍼 (필요한 ALG만 선택 로드)
# modprobe nf_conntrack_ftp
# modprobe nf_conntrack_sip
# 6단계: IPSec offload (필요시)
# modprobe esp4_offload
# modprobe esp6_offload
echo "NGFW modules loaded successfully"
코드 설명
-
7-10행
nf_conntrack과nf_tables가 모든 NGFW 기능의 기반입니다.nft_ct는 nftables에서 conntrack 상태를 매칭하는 표현식을 제공합니다. -
13-15행
nf_flow_table은 flowtable 코어 모듈이고,nft_flow_offload은 nftables에서flow offload @ft구문을 사용할 수 있게 합니다. 반드시 nf_conntrack 다음에 로드. -
18-19행
NFQUEUE는 Suricata 등 유저스페이스 DPI 엔진과의 통신을 담당합니다.
nfnetlink_queue가 커널 측, libnetfilter_queue가 유저 측입니다. -
22-25행
TC flower는 eSwitch HW offload의 핵심입니다.
act_ct가 TC에서 conntrack 조회를 가능하게 하고,act_mirred가 패킷 리다이렉트를 수행합니다.
모듈 로딩 후 다음 명령으로 검증합니다:
# 모듈 로딩 확인
lsmod | grep -E "nf_flow|nft_flow|nf_conntrack|cls_flower|act_ct"
# 기대 출력 예시:
# nft_flow_offload 20480 1
# nf_flow_table_inet 16384 1 nft_flow_offload
# nf_flow_table 36864 1 nf_flow_table_inet
# nf_conntrack 172032 5 nf_flow_table,nft_ct,...
# cls_flower 40960 0
# act_ct 20480 0
# dmesg에서 초기화 로그 확인
dmesg | grep -iE "flow.table|conntrack|switchdev"
# NIC eSwitch 상태 확인
devlink dev eswitch show pci/0000:03:00.0 2>/dev/null || echo "eSwitch not available"
# NIC hw-tc-offload 기능 확인
ethtool -k eth0 | grep hw-tc-offload
커널 부트 파라미터
# /etc/default/grub의 GRUB_CMDLINE_LINUX에 추가
# NGFW 최적화 커널 부트 파라미터
# IOMMU (SmartNIC SR-IOV/eSwitch 필수)
intel_iommu=on iommu=pt
# CPU 격리: 데이터 플레인 코어를 커널 스케줄러에서 분리
isolcpus=4-11 # Suricata 전용 코어 격리
nohz_full=4-11 # 격리 코어의 타이머 틱 제거
rcu_nocbs=4-11 # RCU 콜백을 다른 코어에서 실행
# Hugepages (VPP/DPDK 사용 시)
default_hugepagesz=1G hugepagesz=1G hugepages=4
# NIC MMIO 매핑 최적화
pci=assign-busses # PCI 버스 재할당
# 네트워크 스택 최적화
net.ifnames=0 # 예측 가능한 인터페이스 이름 비활성화 (선택)
sysctl 튜닝 파라미터
| 파라미터 | 기본값 | NGFW 권장값 | 설명 |
|---|---|---|---|
nf_conntrack_max | 262144 | 2000000 | 최대 conntrack 엔트리 수 |
nf_conntrack_buckets | 65536 | 500000 | conntrack 해시 테이블 버킷 수 |
nf_conntrack_tcp_timeout_established | 432000 | 300 | TCP ESTABLISHED 타임아웃 (초) |
nf_flowtable_tcp_timeout | 30 | 300 | flowtable TCP 타임아웃 |
nf_flowtable_udp_timeout | 30 | 30 | flowtable UDP 타임아웃 |
net.core.optmem_max | 20480 | 81920 | NFQUEUE 소켓 옵션 메모리 |
net.core.netdev_budget | 300 | 600 | NAPI poll 버짓 |
net.core.netdev_max_backlog | 1000 | 10000 | 입력 큐 크기 |
net.ipv4.ip_forward | 0 | 1 | IP 포워딩 활성화 |
net.netfilter.nf_conntrack_helper | 0 | 0 | 자동 헬퍼 비활성화 (보안) |
운영 가이드
NGFW 초기 배포 절차
Linux 기반 NGFW를 처음부터 배포하는 단계별 가이드입니다:
| 단계 | 작업 | 명령/설정 | 검증 |
|---|---|---|---|
| 1 | 커널 설정 확인 | CONFIG_NF_FLOW_TABLE, CONFIG_MLX5_ESWITCH 등 확인 | zcat /proc/config.gz | grep NF_FLOW |
| 2 | NIC 드라이버/펌웨어 | mlx5/ice 드라이버 로드, 펌웨어 업데이트 | ethtool -i eth0, devlink dev info |
| 3 | eSwitch switchdev 모드 | devlink dev eswitch set pci/... mode switchdev |
devlink dev eswitch show |
| 4 | 커널 파라미터 튜닝 | sysctl 설정 (conntrack_max, flowtable timeout 등) | sysctl net.netfilter.nf_conntrack_max |
| 5 | IRQ/NUMA 바인딩 | NIC IRQ를 로컬 NUMA 코어에 바인딩 | cat /proc/interrupts | grep eth0 |
| 6 | nftables 규칙 설치 | flowtable + forward chain + NFQUEUE 규칙 | nft list ruleset |
| 7 | TC flower 규칙 | ct_state 매칭 + HW forward 규칙 | tc -s filter show dev eth0_rep0 ingress |
| 8 | Suricata DPI 설정 | NFQUEUE 모드, 멀티스레드, App-Layer 설정 | suricatasc -c uptime |
| 9 | conntrackd HA (선택) | FTFW 모드, 멀티캐스트 동기화 | conntrackd -s |
| 10 | 모니터링 설정 | Prometheus + Grafana + 알림 규칙 | 대시보드 접근 확인 |
일상 운영 명령 요약
# ===== 상태 확인 =====
# 전체 NGFW 상태 요약
echo "=== conntrack ===" && conntrack -C && \
echo "=== offloaded ===" && conntrack -L --status OFFLOAD 2>/dev/null | wc -l && \
echo "=== nft flowtable ===" && nft list flowtable inet ngfw ft 2>/dev/null && \
echo "=== suricata ===" && systemctl is-active suricata
# ===== 긴급 대응 =====
# DDoS 감지 시 XDP 긴급 필터 적용
ip link set dev eth0 xdp obj /usr/local/lib/xdp/emergency_block.o sec xdp
# conntrack 테이블 긴급 정리 (가득 참 상황)
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=60
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=5
conntrack -F # 전체 플러시 (주의: 모든 세션 끊김)
# 특정 IP 긴급 차단
nft add element inet ngfw blocklist { 203.0.113.50 }
# ===== 정책 변경 =====
# 규칙 변경 시 기존 오프로드 세션 재평가
nft flush flowtable inet ngfw ft # flowtable 초기화
# 이후 패킷이 도착하면 자동으로 새 규칙에 따라 재등록
# nftables 규칙 리로드 (서비스 무중단)
systemctl reload ngfw-nftables
# ===== 유지보수 =====
# Suricata 시그니처 업데이트
suricata-update
systemctl reload suricata
# NIC 펌웨어 업데이트 (다운타임 필요)
mlxfwmanager --online-activate
장애 복구 시나리오
| 장애 시나리오 | 증상 | 복구 절차 |
|---|---|---|
| Suricata 크래시 | NFQUEUE에 패킷 쌓임 → 지연 증가 | fail-open: yes로 자동 bypass. systemctl restart suricata |
| conntrack 테이블 가득 | 새 연결 불가 (dmesg에 "nf_conntrack: table full") | 타임아웃 단축 + nf_conntrack_max 증가. XDP DDoS 필터 확인 |
| eSwitch HW 오류 | HW offload 중단, SW 폴백으로 성능 저하 | devlink trap show로 원인 확인. NIC 재설정 또는 펌웨어 업데이트 |
| HA failover | Active 노드 장애 → Standby 승격 | conntrackd가 자동 동기화. flowtable은 다음 패킷부터 자동 재등록 |
| 메모리 부족 | slab 할당 실패, conntrack alloc 실패 | conntrack_max 감소, flowtable 타임아웃 단축, 불필요 규칙 정리 |
업그레이드/롤백(Rollback) 절차
NGFW 커널이나 NIC 펌웨어 업그레이드 시 무중단 또는 최소 중단을 위한 절차입니다:
| 구성요소 | 업그레이드 방법 | 중단 시간 | 롤백 방법 |
|---|---|---|---|
| Suricata 시그니처 | suricata-update && systemctl reload suricata |
0초 (graceful reload) | suricata-update --force로 이전 버전 재적용 |
| nftables 규칙 | nft -f /etc/ngfw/ruleset-v2.nft (atomic replace) |
0초 (원자적(Atomic) 교체) | nft -f /etc/ngfw/ruleset-v1.nft 이전 규칙셋 복원 |
| TC flower 규칙 | 새 규칙 추가 후 구 규칙 삭제 (순서 중요) | 개별 규칙 <1ms | 삭제한 규칙 재추가. HW 규칙은 NIC이 캐시 유지 |
| NIC 펌웨어 | mlxfwmanager --online-activate |
10~30초 (NIC 리셋) | 이전 펌웨어 이미지로 재플래시. HA 구성 시 failover 후 수행 |
| 커널 업그레이드 | 새 커널 설치 → GRUB 업데이트 → 재부팅 | 2~5분 (재부팅) | GRUB에서 이전 커널 선택. grubby --set-default |
| eBPF/XDP 프로그램 | ip link set dev eth0 xdp obj new_prog.o (atomic) |
0초 (원자적 교체) | ip link set dev eth0 xdp off로 제거 또는 이전 프로그램 로드 |
# ===== 안전한 커널 업그레이드 절차 (HA 구성) =====
# 1단계: Standby 노드에서 먼저 업그레이드
conntrackd -n # Standby 역할 확인
# 2단계: 새 커널 설치
dnf install kernel-6.6.x # 또는 dpkg -i linux-image-6.6.x
# 3단계: Standby 재부팅 (Active가 트래픽 처리 중)
reboot
# 4단계: 재부팅 후 검증
uname -r # 새 커널 버전 확인
lsmod | grep nf_flow_table # 모듈 로딩 확인
conntrackd -s # HA 동기화 상태 확인
suricatasc -c uptime # Suricata 정상 기동 확인
# 5단계: Failover → 이 노드를 Active로 승격
conntrackd -c commit # 캐시된 세션 커밋
conntrackd -k # Active 역할 요청
# 6단계: 구 Active 노드도 동일 절차로 업그레이드
로그 관리와 감사
NGFW는 보안 장비이므로 로그 관리가 법적 요구사항일 수 있습니다. 주요 로그 소스와 관리 방안입니다:
| 로그 소스 | 경로/방법 | 포함 정보 | 보존 기간 (권장) |
|---|---|---|---|
| nftables 로그 | nft log → syslog 또는 nflog → ulogd2 |
차단/허용 verdict, 5-tuple, 카운터 | 90일+ |
| conntrack 이벤트 | conntrack -E 또는 conntrackd의 stats 로그 |
NEW/DESTROY 이벤트, 세션 지속 시간, 바이트 | 30일 |
| Suricata EVE JSON | /var/log/suricata/eve.json |
IPS alert, App-ID, DNS 쿼리, TLS 핸드셰이크, HTTP 메타데이터 | 90일+ (SIEM 전송) |
| flowtable 통계 | nft list flowtable, ethtool -S |
오프로드된 플로우 수, 바이트, 패킷 | Prometheus에 시계열 저장 |
| 커널 메시지 | dmesg, /var/log/kern.log |
conntrack table full, NIC 오류, OOM | 30일 |
# /etc/rsyslog.d/ngfw.conf — NGFW 로그 분리 저장
# nftables LOG 타겟 로그
:msg, contains, "NGFW_" /var/log/ngfw/firewall.log
& stop
# conntrackd 로그
:programname, isequal, "conntrackd" /var/log/ngfw/conntrackd.log
& stop
# logrotate 설정
# /etc/logrotate.d/ngfw
# /var/log/ngfw/*.log {
# daily
# rotate 90
# compress
# delaycompress
# missingok
# notifempty
# sharedscripts
# postrotate
# systemctl reload rsyslog
# endscript
# }
용량 계획
NGFW 장비의 리소스 소요를 사전에 계획하기 위한 가이드입니다:
| 리소스 | 계산 공식 | 예시 (100K 동시 세션) |
|---|---|---|
| conntrack 메모리 | 세션 수 × ~320 bytes/entry | 100K × 320B = ~32 MB |
| flowtable 메모리 | 오프로드 세션 × ~256 bytes/entry | 70K × 256B = ~18 MB |
| conntrack 해시 버킷 | max_entries / 4 (권장) | 100K / 4 = 25K 버킷 |
| NIC HW flow 엔트리 | NIC 의존 (CX-6: ~1M, E810: ~64K) | 70K (HW 한계 내) |
| Suricata 메모리 | 기본 ~2GB + 시그니처 ~1GB + 세션 캐시 | ~4 GB |
| DPI CPU 코어 | DPI 처리량 / 코어당 1~3 Gbps | 10 Gbps DPI → 4~10 코어 |
QUIC/TLS 1.3과 NGFW 오프로드
이 주제는 별도 페이지로 분리되었습니다: NGFW 고급 오프로드 구성 — QUIC/ECH와 NGFW 오프로드
멀티 테넌트 NGFW 아키텍처
이 주제는 별도 페이지로 분리되었습니다: NGFW 고급 오프로드 구성 — 멀티 테넌트 NGFW
Hairpin/Loopback 오프로드와 East-West 트래픽 보안
이 주제는 별도 페이지로 분리되었습니다: NGFW 고급 오프로드 구성 — Hairpin/East-West 보안
eBPF 기반 차세대 NGFW
이 주제는 별도 페이지로 분리되었습니다: eBPF + P4 프로그래머블 NGFW 파이프라인 — BPF netfilter, Cilium, P4 match-action, Tofino/FPGA 심층 가이드
P4 프로그래머블 파이프라인 NGFW 오프로드
이 주제는 별도 페이지로 분리되었습니다: eBPF + P4 프로그래머블 NGFW 파이프라인
흔한 실수와 안티패턴
NGFW 오프로드를 구현할 때 자주 발생하는 실수와 안티패턴 10가지를 정리합니다. 각 실수에 대한 증상, 원인, 올바른 해결 방법을 포함합니다.
| # | 실수 | 증상 | 올바른 방법 |
|---|---|---|---|
| 1 | flowtable에 flags offload 없이 HW offload 기대 | 모든 세션이 SW fast path에서만 처리 | flags offload 명시 + NIC 지원 확인 |
| 2 | nf_conntrack_max 부족 | 새 연결 불가, nf_conntrack: table full 로그 | 예상 동시 세션의 1.5배로 설정 |
| 3 | NFQUEUE fail-open 미설정 | Suricata 장애 시 전체 트래픽 차단 | queue ... bypass 옵션 사용 |
| 4 | flowtable timeout > conntrack timeout | 유령 플로우 (이미 종료된 세션의 HW 규칙 잔존) | flowtable timeout < conntrack timeout |
| 5 | ALG 프로토콜(FTP/SIP)을 무조건 오프로드 | 데이터 채널 생성 실패, 통화 끊김 | ALG 제어 채널은 오프로드 제외 |
| 6 | eSwitch switchdev 전환 시 VF 미재설정 | VF가 legacy 모드에서 멈춤, offload 불가 | VF unbind → switchdev 전환 → VF rebind |
| 7 | IRQ affinity 미설정 | 단일 코어 과부하, 다른 코어 유휴 | RX 큐별 IRQ를 별도 코어에 바인딩 |
| 8 | XDP + NFQUEUE 조합 시 순서 실수 | XDP에서 DROP한 패킷이 DPI에 미도달 | XDP는 pre-filter만, DPI 대상은 반드시 PASS |
| 9 | conntrackd 동기화 없이 HA failover | failover 시 모든 세션 손실 | conntrackd + VRRP/keepalived 동기화 |
| 10 | HW flow table 크기 초과 무시 | SW 폴백으로 성능 급락 (HW→SW 전환 시 지연) | HW 테이블 사용률 모니터링 + 알림 |
실수 1: flowtable에 flags offload 누락
# ❌ 잘못된 설정: flags offload 누락
nft add flowtable inet filter ft \
{ hook ingress priority 0; devices = { eth0, eth1 }; }
# → SW fast path만 동작, HW offload 없음
# ✅ 올바른 설정
nft add flowtable inet filter ft \
{ hook ingress priority 0; devices = { eth0, eth1 }; \
flags offload; }
# 검증: HW offload 확인
conntrack -L --status OFFLOAD 2>/dev/null | wc -l
# 0이면 HW offload 동작하지 않음
# NIC 지원 여부 확인
ethtool -k eth0 | grep hw-tc-offload
# hw-tc-offload: on → HW offload 가능
실수 2: nf_conntrack_max 부족
# 현재 conntrack 사용량 확인
cat /proc/sys/net/netfilter/nf_conntrack_count
cat /proc/sys/net/netfilter/nf_conntrack_max
# ❌ 기본값(65536)은 NGFW에 부족
# 증상: dmesg에 "nf_conntrack: table full, dropping packet" 출력
dmesg | grep "table full"
# ✅ 예상 동시 세션의 1.5배로 설정
# 예: 동시 세션 200K 예상 → 300K으로 설정
sysctl -w net.netfilter.nf_conntrack_max=300000
# 해시 테이블 크기도 함께 조정 (max / 4 권장)
# 부팅 시 모듈 파라미터로 설정 (런타임 변경 불가)
echo "options nf_conntrack hashsize=75000" > \
/etc/modprobe.d/nf_conntrack.conf
# 메모리 계산: 300K × ~320 bytes = ~96 MB
# 영구 설정
echo "net.netfilter.nf_conntrack_max = 300000" >> /etc/sysctl.d/99-ngfw.conf
실수 3: NFQUEUE fail-open 미설정
# ❌ 잘못된 설정: bypass 없음
# Suricata가 죽으면 모든 트래픽이 DROP됨
nft add rule inet filter forward \
ct state new queue num 0
# ✅ 올바른 설정: bypass 옵션으로 fail-open
nft add rule inet filter forward \
ct state new queue num 0-3 fanout,bypass
# fanout: 여러 NFQUEUE에 분산 (Suricata 멀티스레드)
# bypass: NFQUEUE가 비어있으면 자동으로 ACCEPT
# 검증: Suricata 프로세스 상태 확인
ss -nlp | grep suricata
# Suricata가 NFQUEUE를 바인딩하고 있는지 확인
# Suricata 설정 (suricata.yaml)
# nfqueue:
# mode: accept ← fail-open (NFQUEUE 바인딩 해제 시 accept)
# fail-open: yes
실수 4: flowtable timeout > conntrack timeout
# ❌ 위험: conntrack timeout이 먼저 만료되면
# conntrack 엔트리 삭제 → flowtable 엔트리 고아화
# → HW에 유령 규칙 잔존 → 보안 위험
# conntrack timeout 확인
sysctl net.netfilter.nf_conntrack_tcp_timeout_established
# 기본: 432000 (5일)
# ✅ flowtable timeout은 conntrack timeout보다 짧게
# flowtable 기본 timeout: 30초 (자동 갱신)
# 문제가 되는 경우: conntrack timeout을 짧게 줄인 경우
# 예: UDP conntrack timeout을 30초로 줄이면
sysctl -w net.netfilter.nf_conntrack_udp_timeout_stream=60
# flowtable aging은 이보다 짧은 주기로 동작해야 함
# HW flow 엔트리 상태 확인 (mlx5)
tc -s filter show dev eth0 ingress
# → 각 규칙의 packets/bytes 카운터 확인
# 카운터가 오래 정지된 규칙 = 유령 플로우 의심
실수 5: ALG 프로토콜 무조건 오프로드
# ❌ 잘못된 설정: 모든 EST 세션을 무조건 오프로드
nft add rule inet filter forward \
ct state established flow add @ft
# ✅ 올바른 설정: ALG helper가 있는 세션은 제외
nft add rule inet filter forward \
ct state established \
ct helper "" \
flow add @ft
# ct helper ""는 helper가 없는 세션만 매칭
# FTP, SIP, H.323 등 ALG 세션은 항상 Slow Path 유지
# 현재 ALG helper가 할당된 세션 확인
conntrack -L | grep helper
# 예: tcp 6 300 ESTABLISHED ... helper=ftp
실수 6: eSwitch switchdev 전환 시 VF 미재설정
# ❌ 잘못된 순서: VF가 바인딩된 상태에서 switchdev 전환
# 결과: 전환 실패 또는 VF가 legacy 모드에 잔류
# ✅ 올바른 순서
# 1. VF unbind (모든 VF)
for vf in /sys/bus/pci/devices/0000:04:00.0/virtfn*; do
pci_addr=$(basename $(readlink $vf))
echo $pci_addr > /sys/bus/pci/drivers/mlx5_core/unbind 2>/dev/null
done
# 2. switchdev 모드 전환
devlink dev eswitch set pci/0000:04:00.0 mode switchdev
# 3. VF rebind
for vf in /sys/bus/pci/devices/0000:04:00.0/virtfn*; do
pci_addr=$(basename $(readlink $vf))
echo $pci_addr > /sys/bus/pci/drivers/mlx5_core/bind 2>/dev/null
done
# 4. 검증
devlink dev eswitch show pci/0000:04:00.0
# mode switchdev inline-mode transport encap-mode basic
# VF representor 확인
ip link show | grep "enp4s0f0v"
실수 7: IRQ affinity 미설정
# 증상: mpstat으로 확인하면 CPU0만 100%, 나머지 idle
mpstat -P ALL 1
# 현재 IRQ 분포 확인
cat /proc/interrupts | grep eth0
# ✅ IRQ affinity 자동 설정 스크립트
# Mellanox NIC의 경우
if [ -x /usr/sbin/mlnx_affinity ]; then
/usr/sbin/mlnx_affinity
fi
# 수동 설정: RX 큐별 IRQ를 별도 코어에 바인딩
# 예: 8개 RX 큐를 CPU 0-7에 각각 바인딩
for i in $(seq 0 7); do
irq=$(grep "eth0-$i" /proc/interrupts | awk '{print $1}' | tr -d ':')
echo $((1 << $i)) > /proc/irq/$irq/smp_affinity
done
# irqbalance 서비스 비활성화 (NGFW에서는 수동 제어 권장)
systemctl stop irqbalance
systemctl disable irqbalance
# RPS (Receive Packet Steering) 설정 (SW fallback)
echo "ff" > /sys/class/net/eth0/queues/rx-0/rps_cpus
실수 8: XDP + NFQUEUE 순서 실수
# ❌ 문제: XDP에서 DPI 대상까지 DROP
# XDP는 Netfilter 이전에 실행되므로
# XDP에서 DROP한 패킷은 NFQUEUE(DPI)에 도달 불가
# ✅ 올바른 설계:
# XDP: 명백한 공격만 차단 (rate limit, blocklist)
# Netfilter/NFQUEUE: DPI 대상 패킷 처리
# XDP에서 DPI 대상 트래픽은 반드시 XDP_PASS
# XDP 프로그램 내 분류 로직:
# blocklist match → XDP_DROP
# rate limit 초과 → XDP_DROP
# 그 외 모두 → XDP_PASS (Netfilter로 진행)
# XDP 프로그램 로드
ip link set dev eth0 xdpgeneric obj xdp_prefilter.o sec xdp
# XDP 통계 확인 (DROP된 패킷이 의도한 것인지 검증)
bpftool prog show
bpftool map dump name xdp_stats_map
실수 9: conntrackd 동기화 없이 HA failover
# ❌ conntrackd 없이 VRRP failover 시:
# 모든 기존 세션이 새 마스터에서 NEW로 처리
# → DPI 재검사, flowtable 재등록 → 수초간 성능 저하
# ✅ conntrackd 설정 (/etc/conntrackd/conntrackd.conf)
# Sync {
# Mode FTFW { ← Fault Tolerant, Full Write
# ResendQueueSize 131072
# PurgeTimeout 60
# }
# UDP {
# IPv4_address 10.0.0.1
# IPv4_Destination_Address 10.0.0.2
# Port 3780
# Interface eth2 ← 동기화 전용 인터페이스
# }
# }
# conntrackd 시작
systemctl start conntrackd
# VRRP failover 스크립트에 추가
# /etc/keepalived/notify_master.sh:
conntrackd -C /etc/conntrackd/conntrackd.conf -c # 커밋
conntrackd -C /etc/conntrackd/conntrackd.conf -f # 플러시
conntrackd -C /etc/conntrackd/conntrackd.conf -R # 수신 테이블 복원
# 동기화 상태 확인
conntrackd -s
# cache-internal: 150000 entries
# cache-external: 148500 entries ← 피어와 거의 동기
실수 10: HW flow table 크기 초과 무시
# NIC별 HW flow table 최대 엔트리
# Mellanox CX-6 Dx: ~1M flows
# Intel E810: ~64K flows
# Broadcom P2100: ~500K flows
# ❌ HW 테이블 초과 시 증상:
# - dmesg: "mlx5_core: Failed to add TC flower rule (-ENOSPC)"
# - 새 오프로드 실패 → SW flowtable 폴백 → 성능 급락
# - 기존 HW 규칙은 유지되지만 새 세션은 모두 SW 처리
# ✅ 모니터링 설정
# Prometheus exporter를 위한 HW flow 사용률 체크 스크립트
# 현재 HW offload 세션 수
hw_flows=$(conntrack -L --status OFFLOAD 2>/dev/null | wc -l)
echo "ngfw_hw_flows_current $hw_flows"
# TC filter 통계
tc -s filter show dev eth0 ingress | grep -c "in_hw"
# in_hw = HW에 설치된 규칙 수
# 알림 임계값: HW 한계의 80%에서 경고
hw_max=1000000 # CX-6 Dx
threshold=$(( hw_max * 80 / 100 ))
if [ $hw_flows -gt $threshold ]; then
logger -p daemon.warning "NGFW: HW flow table usage $hw_flows/$hw_max (${threshold} threshold)"
fi
실습 가이드
이 섹션에서는 실제 Linux 환경에서 NGFW 오프로드를 단계별로 구현하는 실습을 제공합니다. 네트워크 네임스페이스를 활용하여 물리 장비 없이도 핵심 개념을 실험할 수 있습니다.
실습 환경 구성
| 요구사항 | 최소 사양 | 권장 사양 | 비고 |
|---|---|---|---|
| 커널 버전 | 5.13+ (flowtable) | 6.1+ (full CT offload) | uname -r로 확인 |
| nftables | 0.9.8+ | 1.0.6+ | nft --version |
| Suricata | 6.0+ | 7.0+ | suricata --build-info |
| iproute2 | 5.10+ | 6.1+ | ip -V |
| NIC (Lab 3용) | - | Mellanox CX-5+ / Intel E810 | HW offload 실습 시 필요 |
| 메모리 | 2 GB | 8 GB+ | Suricata + conntrack 테이블 |
| CPU | 2 코어 | 4+ 코어 | NFQUEUE 병렬 처리 |
| 도구 | iperf3, curl | + hping3, bpftool, tcpdump | 테스트 및 디버깅 |
Lab 1 — 기본 flowtable 오프로드
네트워크 네임스페이스로 라우터를 구성하고, nftables flowtable을 설정한 후 성능을 측정합니다.
#!/bin/bash
# Lab 1: 기본 flowtable 오프로드 실습
# 토폴로지: [client] ---veth--- [router] ---veth--- [server]
set -e
# ============ 1. 네임스페이스 생성 ============
ip netns add client
ip netns add router
ip netns add server
# ============ 2. veth 쌍 생성 ============
# client ↔ router
ip link add c-eth0 type veth peer name r-eth0
ip link set c-eth0 netns client
ip link set r-eth0 netns router
# router ↔ server
ip link add r-eth1 type veth peer name s-eth0
ip link set r-eth1 netns router
ip link set s-eth0 netns server
# ============ 3. IP 설정 ============
# client: 10.0.1.0/24
ip netns exec client ip addr add 10.0.1.10/24 dev c-eth0
ip netns exec client ip link set c-eth0 up
ip netns exec client ip link set lo up
ip netns exec client ip route add default via 10.0.1.1
# router: 게이트웨이
ip netns exec router ip addr add 10.0.1.1/24 dev r-eth0
ip netns exec router ip addr add 10.0.2.1/24 dev r-eth1
ip netns exec router ip link set r-eth0 up
ip netns exec router ip link set r-eth1 up
ip netns exec router ip link set lo up
ip netns exec router sysctl -w net.ipv4.ip_forward=1
# server: 10.0.2.0/24
ip netns exec server ip addr add 10.0.2.20/24 dev s-eth0
ip netns exec server ip link set s-eth0 up
ip netns exec server ip link set lo up
ip netns exec server ip route add default via 10.0.2.1
# ============ 4. 연결 테스트 ============
ip netns exec client ping -c 2 10.0.2.20
echo "=== 네트워크 설정 완료 ==="
# ============ 5. nftables flowtable 설정 (router) ============
ip netns exec router nft -f - <<'EOF'
flush ruleset
table inet ngfw_lab {
flowtable ft {
hook ingress priority 0;
devices = { r-eth0, r-eth1 };
}
chain forward {
type filter hook forward priority 0; policy drop;
# ESTABLISHED 세션 → flowtable (SW offload)
ct state established,related flow add @ft counter accept
# 새 세션 허용 (테스트용 전체 허용)
ct state new counter accept
# INVALID 차단
ct state invalid counter drop
}
# NAT (옵션: SNAT 테스트)
chain postrouting {
type nat hook postrouting priority 100; policy accept;
oifname "r-eth1" masquerade
}
}
EOF
echo "=== nftables 설정 완료 ==="
# ============ 6. 성능 측정 ============
# server에서 iperf3 서버 시작
ip netns exec server iperf3 -s -D
# client에서 iperf3 테스트 (10초, TCP)
echo "=== flowtable 활성 상태 성능 ==="
ip netns exec client iperf3 -c 10.0.2.20 -t 10
# ============ 7. 오프로드 확인 ============
# conntrack 상태 확인 (router)
ip netns exec router conntrack -L
# 예상 출력:
# tcp 6 300 ESTABLISHED src=10.0.1.10 dst=10.0.2.20
# sport=45678 dport=5201 [OFFLOAD] ...
# flowtable 엔트리 확인
ip netns exec router conntrack -L --status ASSURED
# OFFLOAD 상태가 표시되면 SW flowtable에서 처리 중
# nftables 카운터 확인
ip netns exec router nft list ruleset
# forward chain의 counter: 첫 몇 패킷만 카운트
# (나머지는 flowtable에서 바이패스)
# ============ 8. flowtable 비활성 비교 ============
# flowtable 규칙 제거
ip netns exec router nft delete rule inet ngfw_lab forward handle $(
ip netns exec router nft -a list chain inet ngfw_lab forward | \
grep "flow add" | awk '{print $NF}'
)
echo "=== flowtable 비활성 상태 성능 ==="
ip netns exec client iperf3 -c 10.0.2.20 -t 10
# 두 결과 비교: flowtable 활성 시 처리량 향상 확인
# ============ 정리 스크립트 ============
ip netns exec server pkill iperf3 2>/dev/null
ip netns del client
ip netns del router
ip netns del server
echo "=== Lab 1 정리 완료 ==="
Lab 2 — NFQUEUE + Suricata DPI 통합
Lab 1의 환경에 Suricata DPI 엔진을 추가하여, 새 세션은 DPI 검사를 거치고 분류 완료된 세션만 오프로드되도록 구성합니다.
# Lab 2: NFQUEUE + Suricata DPI 통합
# 사전 조건: Lab 1의 네트워크 환경 구성 완료
# Suricata 설치: apt install suricata (또는 dnf install suricata)
# ============ 1. Suricata 설정 ============
# /etc/suricata/suricata.yaml 수정 (주요 항목)
cat > /tmp/suricata-nfqueue.yaml <<'EOF'
# NFQUEUE 모드 설정
nfq:
mode: accept # 기본 verdict: accept (fail-open)
repeat-mark: 1
repeat-mask: 1
bypass-mark: 8 # DPI 분류 완료 시 이 mark 설정
bypass-mask: 8
fail-open: yes # Suricata 장애 시 트래픽 허용
# NFQUEUE 수신 설정
nfqueue:
- queue-num: 0
threads: 2
- queue-num: 1
threads: 2
# 출력: eve.json 로깅
outputs:
- eve-log:
enabled: yes
filename: /var/log/suricata/eve.json
types:
- alert
- http
- dns
- tls
EOF
# ============ 2. nftables 규칙 (DPI 통합) ============
ip netns exec router nft -f - <<'EOF'
flush ruleset
table inet ngfw_lab2 {
flowtable ft {
hook ingress priority 0;
devices = { r-eth0, r-eth1 };
}
chain forward {
type filter hook forward priority 0; policy drop;
# 1. DPI 완료 + bypass mark가 있는 EST 세션 → flowtable
ct state established meta mark & 0x08 == 0x08 \
flow add @ft counter accept
# 2. EST/RELATED (아직 DPI 진행 중) → 통과
ct state established,related counter accept
# 3. 새 세션 → NFQUEUE (Suricata DPI)
ct state new queue num 0-1 fanout,bypass
# 4. INVALID 차단
ct state invalid counter drop
}
chain postrouting {
type nat hook postrouting priority 100; policy accept;
oifname "r-eth1" masquerade
}
}
EOF
echo "=== DPI 통합 nftables 설정 완료 ==="
# ============ 3. Suricata 시작 및 테스트 ============
# Suricata를 router 네임스페이스에서 NFQUEUE 모드로 시작
ip netns exec router suricata -c /tmp/suricata-nfqueue.yaml \
-q 0 -q 1 -D
# 잠시 대기 (초기화)
sleep 3
# ============ 4. DPI 탐지 테스트 ============
# HTTP 요청 (DPI가 HTTP로 분류해야 함)
ip netns exec server python3 -m http.server 80 &
sleep 1
ip netns exec client curl -s http://10.0.2.20/
# Suricata 로그 확인
ip netns exec router cat /var/log/suricata/eve.json | \
python3 -m json.tool | grep -A5 "\"http\""
# conntrack 확인: bypass mark(8)가 설정되었는지 확인
ip netns exec router conntrack -L | grep mark
# mark=8 → DPI 완료, 오프로드 대상
# iperf3 성능 테스트 (DPI 후 오프로드 확인)
ip netns exec server iperf3 -s -D
ip netns exec client iperf3 -c 10.0.2.20 -t 10
# 결과: 첫 몇 패킷은 NFQUEUE 경유, 이후 flowtable 오프로드
echo "=== Lab 2 완료 ==="
Lab 3 — TC flower eSwitch HW offload (SmartNIC 필요)
#!/bin/bash
# Lab 3: TC flower eSwitch HW offload
# 사전 조건: SmartNIC (CX-5+/E810), SR-IOV VF 생성됨
NIC="enp4s0f0" # PF 이름 (환경에 맞게 변경)
PCI="0000:04:00.0" # PCI 주소
# ============ 1. eSwitch switchdev 전환 ============
# 현재 모드 확인
devlink dev eswitch show pci/$PCI
# VF unbind
for vf in /sys/bus/pci/devices/$PCI/virtfn*; do
pci_addr=$(basename $(readlink $vf))
echo $pci_addr > /sys/bus/pci/drivers/mlx5_core/unbind 2>/dev/null || true
done
# switchdev 모드 전환
devlink dev eswitch set pci/$PCI mode switchdev
# VF rebind
for vf in /sys/bus/pci/devices/$PCI/virtfn*; do
pci_addr=$(basename $(readlink $vf))
echo $pci_addr > /sys/bus/pci/drivers/mlx5_core/bind 2>/dev/null || true
done
# TC HW offload 활성화
ethtool -K $NIC hw-tc-offload on
echo "=== eSwitch switchdev 전환 완료 ==="
# VF representor 확인
ip link show | grep "${NIC}v"
# ============ 2. TC flower ct 규칙 설치 ============
VF_REP="${NIC}v0" # VF0 representor
# 기존 규칙 초기화
tc qdisc del dev $VF_REP ingress 2>/dev/null || true
tc qdisc add dev $VF_REP ingress
tc qdisc del dev $NIC ingress 2>/dev/null || true
tc qdisc add dev $NIC ingress
# VF → Uplink 방향: conntrack 추적 시작
tc filter add dev $VF_REP ingress prio 1 \
protocol ip flower \
ct_state -trk \
action ct zone 1
# VF → Uplink: EST 세션 → HW forward
tc filter add dev $VF_REP ingress prio 2 \
protocol ip flower \
ct_state +trk+est \
action ct zone 1 \
action mirred egress redirect dev $NIC
# VF → Uplink: NEW 세션 → CPU
tc filter add dev $VF_REP ingress prio 3 \
protocol ip flower \
ct_state +trk+new \
action pass
# Uplink → VF 방향 (동일 패턴)
tc filter add dev $NIC ingress prio 1 \
protocol ip flower \
ct_state -trk \
action ct zone 1
tc filter add dev $NIC ingress prio 2 \
protocol ip flower \
ct_state +trk+est \
action ct zone 1 \
action mirred egress redirect dev $VF_REP
tc filter add dev $NIC ingress prio 3 \
protocol ip flower \
ct_state +trk+new \
action pass
echo "=== TC flower ct 규칙 설치 완료 ==="
# ============ 3. HW offload 확인 ============
# TC 규칙이 HW에 설치되었는지 확인
tc -s filter show dev $VF_REP ingress
# 출력에서 "in_hw" 플래그 확인
# in_hw in_hw_count 1 → HW에 성공적으로 설치됨
# conntrack 오프로드 확인
conntrack -L --status OFFLOAD
# [OFFLOAD] 상태의 세션 확인
# HW 카운터 확인
tc -s filter show dev $VF_REP ingress
# packets/bytes 카운터가 증가하면 HW에서 처리 중
# ethtool 통계
ethtool -S $NIC | grep -E "tx_packets|rx_packets|offload"
echo "=== Lab 3 HW offload 확인 완료 ==="
Lab 4 — XDP DDoS Pre-filter
XDP 프로그램을 작성하여 NIC 드라이버 수준에서 SYN flood 공격을 차단합니다. 이 프로그램은 nftables NGFW 파이프라인 앞에 배치됩니다.
/* xdp_synflood_filter.c — XDP SYN flood 방어 프로그램 */
/* 컴파일: clang -O2 -target bpf -c xdp_synflood_filter.c -o xdp_synflood_filter.o */
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_endian.h>
#define MAX_ENTRIES 100000
#define SYN_RATE_LIMIT 100 /* 소스 IP당 초당 SYN 최대 100개 */
#define WINDOW_NS (1000000000ULL) /* 1초 (나노초) */
/* 소스 IP별 SYN 카운터 */
struct syn_count {
__u64 count; /* 윈도우 내 SYN 수 */
__u64 window_start; /* 현재 윈도우 시작 시간 */
};
struct {
__uint(type, BPF_MAP_TYPE_LRU_HASH);
__uint(max_entries, MAX_ENTRIES);
__type(key, __be32); /* 소스 IP */
__type(value, struct syn_count);
} syn_rate_map SEC(".maps");
/* IP 차단 리스트 (관리자가 bpftool로 추가) */
struct {
__uint(type, BPF_MAP_TYPE_LPM_TRIE);
__uint(max_entries, 10000);
__uint(map_flags, BPF_F_NO_PREALLOC);
__type(key, struct lpm_key);
__type(value, __u32); /* 1=block */
} blocklist SEC(".maps");
/* 통계 */
struct {
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
__uint(max_entries, 3); /* 0:pass, 1:drop_rate, 2:drop_block */
__type(key, __u32);
__type(value, __u64);
} xdp_stats SEC(".maps");
struct lpm_key {
__u32 prefixlen;
__be32 addr;
};
SEC("xdp")
int xdp_syn_filter(struct xdp_md *ctx)
{
void *data = (void *)(long)ctx->data;
void *data_end = (void *)(long)ctx->data_end;
struct ethhdr *eth = data;
struct iphdr *iph;
struct tcphdr *tcph;
__u32 stat_key;
__u64 *stat_val;
/* 경계 검사 */
if ((void *)(eth + 1) > data_end)
return XDP_PASS;
if (eth->h_proto != bpf_htons(ETH_P_IP))
return XDP_PASS;
iph = (struct iphdr *)(eth + 1);
if ((void *)(iph + 1) > data_end)
return XDP_PASS;
/* 1. IP 차단 리스트 확인 */
struct lpm_key lpm = {
.prefixlen = 32,
.addr = iph->saddr,
};
if (bpf_map_lookup_elem(&blocklist, &lpm)) {
stat_key = 2;
stat_val = bpf_map_lookup_elem(&xdp_stats, &stat_key);
if (stat_val) (*stat_val)++;
return XDP_DROP;
}
/* TCP SYN만 rate limit */
if (iph->protocol != IPPROTO_TCP)
goto pass;
tcph = (struct tcphdr *)((void *)iph + (iph->ihl * 4));
if ((void *)(tcph + 1) > data_end)
goto pass;
/* SYN 패킷만 필터링 (SYN=1, ACK=0) */
if (!(tcph->syn && !tcph->ack))
goto pass;
/* 2. SYN rate limiting */
__u64 now = bpf_ktime_get_ns();
struct syn_count *sc;
sc = bpf_map_lookup_elem(&syn_rate_map, &iph->saddr);
if (sc) {
if (now - sc->window_start > WINDOW_NS) {
/* 새 윈도우 시작 */
sc->count = 1;
sc->window_start = now;
} else {
sc->count++;
if (sc->count > SYN_RATE_LIMIT) {
/* rate limit 초과 → DROP */
stat_key = 1;
stat_val = bpf_map_lookup_elem(&xdp_stats, &stat_key);
if (stat_val) (*stat_val)++;
return XDP_DROP;
}
}
} else {
struct syn_count new_sc = {
.count = 1,
.window_start = now,
};
bpf_map_update_elem(&syn_rate_map, &iph->saddr, &new_sc, BPF_ANY);
}
pass:
stat_key = 0;
stat_val = bpf_map_lookup_elem(&xdp_stats, &stat_key);
if (stat_val) (*stat_val)++;
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";
# ============ XDP 프로그램 로드 및 테스트 ============
# 1. 컴파일
clang -O2 -g -target bpf \
-I /usr/include/$(uname -m)-linux-gnu \
-c xdp_synflood_filter.c -o xdp_synflood_filter.o
# 2. XDP 프로그램 로드 (generic 모드: 모든 NIC 지원)
ip netns exec router \
ip link set dev r-eth0 xdpgeneric obj xdp_synflood_filter.o sec xdp
# 확인
ip netns exec router ip link show r-eth0
# → "xdpgeneric ... prog/xdp" 표시
# 3. SYN flood 테스트 (hping3 사용)
# hping3 설치: apt install hping3
ip netns exec client hping3 -S -p 80 --flood 10.0.2.20 &
FLOOD_PID=$!
sleep 5
kill $FLOOD_PID
# 4. XDP 통계 확인
ip netns exec router bpftool map dump name xdp_stats
# key: 0 (pass), 1 (drop_rate), 2 (drop_block)
# drop_rate 카운터가 증가했으면 rate limiting 작동
# 5. IP 차단 리스트에 추가 (bpftool 사용)
# bpftool map update name blocklist \
# key hex 20 00 00 00 0a 00 01 0a \
# value hex 01 00 00 00
# → 10.0.1.10/32 차단
# 6. XDP 프로그램 제거
ip netns exec router ip link set dev r-eth0 xdpgeneric off
echo "=== Lab 4 완료 ==="
- Lab 5: conntrackd + keepalived로 HA failover 테스트 (네임스페이스 2개의 라우터)
- Lab 6: conntrack zone 기반 멀티 테넌트 격리 (Lab 1에 zone 추가)
- Lab 7: Prometheus + Grafana로 NGFW 메트릭 대시보드 구성
- Lab 8: nftables + Suricata + XDP 삼중 파이프라인 전체 통합
TC flower + CT offload 스테이트풀 방화벽 실전 예제
이 섹션에서는 TC flower + CT action을 사용하여 실제 스테이트풀 방화벽을 구성하는 완전한 예제를 제공합니다. eSwitch switchdev 모드에서 동작하며, 첫 패킷만 커널 conntrack을 거치고 이후 패킷은 하드웨어에서 직접 포워딩됩니다.
전체 아키텍처
eSwitch switchdev 모드 준비
# 1. eSwitch switchdev 모드 전환 (Mellanox CX-6 Dx 예시)
# VF 생성 후 switchdev 모드로 전환
echo 2 > /sys/class/net/enp3s0f0/device/sriov_numvfs
devlink dev eswitch set pci/0000:03:00.0 mode switchdev
# 2. VF representor 확인
ip link show | grep "enp3s0f0"
# enp3s0f0: PF (uplink representor)
# enp3s0f0_0: VF0 representor
# enp3s0f0_1: VF1 representor
# 3. TC offload 활성화
ethtool -K enp3s0f0 hw-tc-offload on
ethtool -K enp3s0f0_0 hw-tc-offload on
ethtool -K enp3s0f0_1 hw-tc-offload on
# 4. CT offload 커널 모듈 로드
modprobe act_ct
modprobe cls_flower
TC flower CT 스테이트풀 규칙 구성
#!/bin/bash
# TC flower + CT offload 스테이트풀 방화벽 구성 스크립트
# 대상: eSwitch switchdev 모드 NIC (CX-5+, CX-6, E810)
UPLINK_REP="enp3s0f0" # PF uplink representor
VF0_REP="enp3s0f0_0" # VF0 representor (내부 VM/컨테이너)
VF1_REP="enp3s0f0_1" # VF1 representor (외부 인터페이스)
CT_ZONE=1
# === Ingress 방향 (외부 → 내부) ===
# chain 0: 모든 ingress 패킷에 CT lookup 수행
tc qdisc add dev $VF1_REP ingress
tc filter add dev $VF1_REP ingress prio 1 chain 0 proto ip flower \
action ct zone $CT_ZONE pipe \
action goto chain 1
# chain 1: established 세션 → HW fast path로 redirect
tc filter add dev $VF1_REP ingress prio 1 chain 1 proto ip flower \
ct_state +est+trk \
action mirred egress redirect dev $VF0_REP
# chain 1: 새 연결 (허용 포트: 80, 443) → CT commit 후 redirect
tc filter add dev $VF1_REP ingress prio 2 chain 1 proto ip flower \
ct_state +new+trk \
ip_proto tcp dst_port 80 \
action ct zone $CT_ZONE commit pipe \
action mirred egress redirect dev $VF0_REP
tc filter add dev $VF1_REP ingress prio 3 chain 1 proto ip flower \
ct_state +new+trk \
ip_proto tcp dst_port 443 \
action ct zone $CT_ZONE commit pipe \
action mirred egress redirect dev $VF0_REP
# chain 1: invalid 패킷 → drop
tc filter add dev $VF1_REP ingress prio 10 chain 1 proto ip flower \
ct_state +inv+trk \
action drop
# chain 1: 그 외 새 연결 → drop (default deny)
tc filter add dev $VF1_REP ingress prio 100 chain 1 proto ip flower \
ct_state +new+trk \
action drop
# === Egress 방향 (내부 → 외부) ===
tc qdisc add dev $VF0_REP ingress
tc filter add dev $VF0_REP ingress prio 1 chain 0 proto ip flower \
action ct zone $CT_ZONE pipe \
action goto chain 1
# 내부에서 외부로 나가는 established 트래픽 → HW fast path
tc filter add dev $VF0_REP ingress prio 1 chain 1 proto ip flower \
ct_state +est+trk \
action mirred egress redirect dev $VF1_REP
# 내부에서 외부로 새 연결 시작 → 허용 후 commit
tc filter add dev $VF0_REP ingress prio 2 chain 1 proto ip flower \
ct_state +new+trk \
action ct zone $CT_ZONE commit pipe \
action mirred egress redirect dev $VF1_REP
NAT 오프로드 추가
# SNAT offload: 내부 사설 IP → 외부 공인 IP
# chain 0에서 CT + NAT 동시 수행
PUBLIC_IP="203.0.113.1"
tc filter add dev $VF0_REP ingress prio 1 chain 0 proto ip flower \
action ct zone $CT_ZONE nat src addr $PUBLIC_IP pipe \
action goto chain 1
# DNAT offload: 외부 → 내부 서비스 포트 매핑
INTERNAL_SERVER="10.0.1.100"
tc filter add dev $VF1_REP ingress prio 1 chain 0 proto ip flower \
ip_proto tcp dst_port 8080 \
action ct zone $CT_ZONE nat dst addr $INTERNAL_SERVER port 80 pipe \
action goto chain 1
오프로드 상태 확인 명령어
# HW offload된 규칙 확인
tc -s filter show dev $VF1_REP ingress
# 출력 예시:
# filter protocol ip pref 1 flower chain 1 handle 0x1
# ct_state +established+tracked
# in_hw in_hw_count 1 ← HW에 설치됨
# action order 1: mirred (Egress Redirect to device enp3s0f0_0)
# Sent 1523456 bytes 12345 pkt (hardware 1523456 bytes 12345 pkt)
# conntrack 테이블에서 offload된 엔트리 확인
conntrack -L | grep "\[OFFLOAD\]"
# tcp 6 src=10.0.1.100 dst=203.0.113.50 ... [OFFLOAD]
# HW flow 통계
cat /sys/kernel/debug/mlx5/0000:03:00.0/ct/stats
# offloaded: 4523 sw_only: 12 max: 1000000
tc -s filter show에서 in_hw 플래그와 hardware N bytes N pkt 카운터를 반드시 확인하세요. in_hw가 없으면 규칙이 SW fallback으로 동작 중이며, 성능이 수십 배 차이날 수 있습니다. HW offload 실패 원인은 대부분 dmesg에서 확인할 수 있습니다.
OVS + HW 오프로드 마이크로세그멘테이션
마이크로세그멘테이션은 VM/컨테이너(Container) 간 East-West 트래픽을 세밀하게 제어하는 보안 모델입니다. Open vSwitch(OVS)의 TC flower offload를 활용하면 eSwitch 하드웨어에서 직접 마이크로세그멘테이션 정책을 적용할 수 있어, CPU 오버헤드 없이 수십만 개의 흐름을 처리합니다.
OVS HW offload 활성화
# 1. OVS HW offload 활성화
ovs-vsctl set Open_vSwitch . other_config:hw-offload=true
ovs-vsctl set Open_vSwitch . other_config:tc-policy=skip_sw
# 2. OVS 재시작 (설정 적용)
systemctl restart openvswitch-switch
# 3. OVS 브리지 생성 + VF representor 추가
ovs-vsctl add-br br-ngfw
ovs-vsctl add-port br-ngfw enp3s0f0 # PF uplink rep
ovs-vsctl add-port br-ngfw enp3s0f0_0 # VF0 rep (Web VM1)
ovs-vsctl add-port br-ngfw enp3s0f0_1 # VF1 rep (Web VM2)
ovs-vsctl add-port br-ngfw enp3s0f0_2 # VF2 rep (App VM3)
ovs-vsctl add-port br-ngfw enp3s0f0_3 # VF3 rep (App VM4)
ovs-vsctl add-port br-ngfw enp3s0f0_4 # VF4 rep (DB VM5)
ovs-vsctl add-port br-ngfw enp3s0f0_5 # VF5 rep (DB VM6)
마이크로세그멘테이션 OpenFlow 규칙
# 포트 번호 확인
ovs-ofctl dump-ports-desc br-ngfw
# 1(enp3s0f0): addr:... (uplink)
# 2(enp3s0f0_0): addr:... (VM1-web)
# 3(enp3s0f0_1): addr:... (VM2-web)
# 4(enp3s0f0_2): addr:... (VM3-app)
# 5(enp3s0f0_3): addr:... (VM4-app)
# 6(enp3s0f0_4): addr:... (VM5-db)
# 7(enp3s0f0_5): addr:... (VM6-db)
# === Zone A (Web) → Zone B (App): 8080/tcp 허용 ===
ovs-ofctl add-flow br-ngfw "priority=100,ip,in_port=2,tcp,tp_dst=8080,\
actions=ct(zone=1,commit),output:4"
ovs-ofctl add-flow br-ngfw "priority=100,ip,in_port=3,tcp,tp_dst=8080,\
actions=ct(zone=1,commit),output:4,output:5"
# === Zone B (App) → Zone C (DB): 5432/tcp, 6379/tcp 허용 ===
ovs-ofctl add-flow br-ngfw "priority=100,ip,in_port=4,tcp,tp_dst=5432,\
actions=ct(zone=2,commit),output:6"
ovs-ofctl add-flow br-ngfw "priority=100,ip,in_port=4,tcp,tp_dst=6379,\
actions=ct(zone=2,commit),output:7"
ovs-ofctl add-flow br-ngfw "priority=100,ip,in_port=5,tcp,tp_dst=5432,\
actions=ct(zone=2,commit),output:6"
ovs-ofctl add-flow br-ngfw "priority=100,ip,in_port=5,tcp,tp_dst=6379,\
actions=ct(zone=2,commit),output:7"
# === Established 응답 트래픽 (양방향) ===
ovs-ofctl add-flow br-ngfw "priority=200,ct_state=+est+trk,actions=normal"
# === Zone A (Web) → Zone C (DB): 직접 접근 차단 ===
ovs-ofctl add-flow br-ngfw "priority=150,ip,in_port=2,\
nw_dst=10.0.3.0/24,actions=drop"
ovs-ofctl add-flow br-ngfw "priority=150,ip,in_port=3,\
nw_dst=10.0.3.0/24,actions=drop"
# === 외부 → Zone A (Web): 80, 443 허용 ===
ovs-ofctl add-flow br-ngfw "priority=100,ip,in_port=1,tcp,tp_dst=80,\
actions=ct(zone=0,commit),output:2,output:3"
ovs-ofctl add-flow br-ngfw "priority=100,ip,in_port=1,tcp,tp_dst=443,\
actions=ct(zone=0,commit),output:2,output:3"
# === Default deny ===
ovs-ofctl add-flow br-ngfw "priority=1,actions=drop"
오프로드 확인
# HW offload된 flow 확인
ovs-appctl dpctl/dump-flows type=offloaded
# 출력 예시:
# recirc_id(0),in_port(2),ct_state(est|trk),eth_type(0x0800),
# ipv4(src=10.0.1.10,dst=10.0.2.20,proto=6),
# tcp(src=45678,dst=8080), packets:152340, bytes:12345678,
# used:0.001s, offloaded:yes, dp:tc
# HW flow 수 확인
ovs-appctl dpctl/dump-flows type=offloaded | wc -l
# TC flower HW 규칙 확인 (OVS가 내부적으로 생성)
tc -s filter show dev enp3s0f0_0 ingress
- OVS 2.13+ 및 커널 5.7+에서 TC CT offload 지원
- ALG(FTP, SIP 등) 프로토콜은 HW offload 불가 → SW fallback
- CT zone은 NIC 하드웨어마다 최대 개수가 다름 (CX-6: 65535개)
- NAT + CT 동시 offload 시
tc-policy=skip_sw대신skip_hwfallback 확인 필요
nftables + flowtable HW offload 실전 구성
nftables flowtable은 커널 nf_flow_table 인프라를 사용하여 established 세션을 Netfilter 훅을 건너뛰고 직접 전달합니다. NF_FLOWTABLE_HW_OFFLOAD 플래그를 설정하면 이 경로가 NIC 하드웨어에 직접 설치되어 제로 CPU 오버헤드로 패킷을 처리합니다.
완전한 nftables 방화벽 + flowtable offload 구성
#!/usr/sbin/nft -f
# nftables + flowtable HW offload 완전 구성 예제
# 요구사항: 커널 5.13+, NIC driver TC_SETUP_FT 지원
flush ruleset
table inet firewall {
# flowtable 정의: HW offload 활성화
flowtable ft {
hook ingress priority 0
devices = { eth0, eth1 }
flags offload # ← HW offload 핵심 플래그
}
# NAT용 flowtable (별도 정의 가능)
flowtable ft-nat {
hook ingress priority 0
devices = { eth0, eth1 }
flags offload
}
# === Forward 체인: 방화벽 정책 ===
chain forward {
type filter hook forward priority filter; policy drop;
# 1. established/related 세션 → flowtable offload
ct state established,related flow add @ft accept
# 2. 허용 정책: 내부→외부 (새 연결)
iifname "eth1" oifname "eth0" ct state new accept
# 3. 허용 정책: 외부→내부 특정 포트
iifname "eth0" oifname "eth1" tcp dport { 80, 443, 22 } ct state new accept
iifname "eth0" oifname "eth1" udp dport { 53, 123 } ct state new accept
# 4. ICMP 허용 (offload 불가, SW 처리)
ip protocol icmp accept
ip6 nexthdr icmpv6 accept
# 5. invalid 패킷 차단
ct state invalid drop
# 6. 로깅 후 drop (default deny)
log prefix "NFT-DROP: " limit rate 10/second drop
}
# === NAT 체인 ===
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
# SNAT: 내부 → 외부 (flowtable에서 NAT도 offload)
oifname "eth0" masquerade
}
chain prerouting {
type nat hook prerouting priority dstnat; policy accept;
# DNAT: 외부 포트 8080 → 내부 서버 80
iifname "eth0" tcp dport 8080 dnat to 10.0.1.100:80
}
# === Input 체인 (호스트 보호) ===
chain input {
type filter hook input priority filter; policy drop;
ct state established,related accept
iif lo accept
tcp dport 22 ct state new accept
ip protocol icmp accept
drop
}
}
flowtable offload 상태 확인 및 디버깅
# 1. flowtable offload 상태 확인
nft list flowtable inet firewall ft
# flowtable ft {
# hook ingress priority 0
# devices = { eth0, eth1 }
# flags offload
# 2. offload된 flow 목록
cat /proc/net/nf_conntrack | grep "\[OFFLOAD\]"
# ipv4 2 tcp 6 src=10.0.1.10 dst=8.8.8.8 ... [OFFLOAD] ...
# 3. flowtable 통계
cat /proc/sys/net/netfilter/nf_flowtable_tcp_timeout
# 30 (초 단위, 기본값)
# 4. HW offload 활성 확인 (ethtool)
ethtool -k eth0 | grep "hw-tc-offload"
# hw-tc-offload: on
# 5. 커널 로그에서 offload 성공/실패 확인
dmesg | grep -i "flowtable\|flow_offload"
# mlx5_core: flow offload added, cookie=0x12345678
# mlx5_core: flow offload stats: pkts=152340 bytes=12345678
# 6. nftables 카운터로 실시간 모니터링
nft add rule inet firewall forward ct state established counter
nft list chain inet firewall forward
# counter packets 0 bytes 0 ← offload 중이면 0에 가까움
# (HW에서 처리되므로 nftables 카운터 증가하지 않음)
conntrack -L의 [OFFLOAD] 엔트리 또는 ethtool -S eth0 | grep offload를 사용하세요.
Connection Tracking HW 오프로드
Connection Tracking(CT) 하드웨어 오프로드는 NGFW 성능의 핵심입니다. 이 섹션에서는 CT zone, NAT 오프로드, 타임아웃 관리, HW/SW 동기화 메커니즘을 상세히 다룹니다.
CT Zone 아키텍처
CT zone은 독립적인 conntrack 네임스페이스를 제공합니다. 동일한 5-tuple(src IP, dst IP, src port, dst port, protocol)이라도 서로 다른 zone에서는 별개의 연결로 추적됩니다. 멀티 테넌트 환경에서 필수입니다.
| 속성 | CT Zone 0 (기본) | CT Zone N (사용자 정의) | 비고 |
|---|---|---|---|
| 용도 | 일반 conntrack | 테넌트/VRF 격리 | zone ID: 0-65535 |
| HW offload | 기본 지원 | CX-6+, E810 지원 | 커널 5.13+ |
| NAT 독립성 | 글로벌 NAT | zone별 독립 NAT | 동일 내부 IP 가능 |
| 최대 엔트리 | nf_conntrack_max 공유 | zone별 제한 불가 | 전체 합산 제한 |
| HW 최대 zone | - | NIC 종속 (CX-6: 64K) | HW 테이블 크기 |
# CT Zone 활용 예시: 테넌트별 격리
# 테넌트 A (zone 100): 192.168.1.0/24
tc filter add dev vf0_rep ingress prio 1 chain 0 proto ip flower \
src_net 192.168.1.0/24 \
action ct zone 100 pipe \
action goto chain 1
# 테넌트 B (zone 200): 192.168.1.0/24 (동일 서브넷이지만 별도 추적)
tc filter add dev vf2_rep ingress prio 1 chain 0 proto ip flower \
src_net 192.168.1.0/24 \
action ct zone 200 pipe \
action goto chain 1
# Zone별 conntrack 엔트리 확인
conntrack -L -z 100 # 테넌트 A 연결 목록
conntrack -L -z 200 # 테넌트 B 연결 목록
# Zone별 NAT: 동일 내부 IP가 다른 공인 IP로 NAT
# zone 100: 192.168.1.10 → 203.0.113.1
tc filter add dev vf0_rep ingress prio 1 chain 0 proto ip flower \
action ct zone 100 nat src addr 203.0.113.1 pipe \
action goto chain 1
# zone 200: 192.168.1.10 → 203.0.113.2
tc filter add dev vf2_rep ingress prio 1 chain 0 proto ip flower \
action ct zone 200 nat src addr 203.0.113.2 pipe \
action goto chain 1
HW/SW conntrack 타임아웃 동기화
HW와 SW conntrack은 독립적인 타임아웃 타이머를 가집니다. 이 둘의 불일치는 stale flow(유령 세션)나 premature expiry(조기 만료)를 유발하며, NGFW 안정성의 가장 큰 위험 요소입니다.
# SW conntrack 타임아웃 (기본값)
sysctl net.netfilter.nf_conntrack_tcp_timeout_established
# 432000 (5일)
sysctl net.netfilter.nf_conntrack_udp_timeout_stream
# 120 (2분)
# HW 타임아웃 (NIC 드라이버별 상이)
# Mellanox CX-6: 기본 30초 aging, SW와 주기적 동기화
cat /sys/kernel/debug/mlx5/0000:03:00.0/ct/aging_timeout
# 30
# HW aging 동작 방식:
# 1. HW entry에 30초간 패킷 없음 → HW aging event 발생
# 2. 드라이버가 SW conntrack에 통보 (nf_flow_offload_stats_update)
# 3. SW conntrack이 아직 활성이면 → HW entry 재설치
# 4. SW conntrack도 만료됐으면 → HW entry 삭제 확정
# 타임아웃 튜닝: flowtable TCP 타임아웃
sysctl -w net.netfilter.nf_flowtable_tcp_timeout=30
sysctl -w net.netfilter.nf_flowtable_udp_timeout=30
# 장기 세션 보호: TCP keepalive가 HW aging을 리셋
# → keepalive 간격을 HW aging보다 짧게 설정
sysctl -w net.ipv4.tcp_keepalive_time=20
sysctl -w net.ipv4.tcp_keepalive_intvl=5
conntrack -L로 보이는 카운터는 최대 1초 지연될 수 있습니다. 실시간 정밀 모니터링이 필요하면 NIC 하드웨어 카운터를 직접 조회하세요.
CT offload 예외 처리
| 상황 | 동작 | 원인 | 대응 |
|---|---|---|---|
| TCP RST/FIN | HW → SW 복귀 | 연결 종료 시그널(Signal) | 자동 처리 (HW trap) |
| TCP 윈도우 밖 패킷 | HW → SW 복귀 | 잠재적 공격 탐지 | SW에서 검증 후 재오프로드 |
| ALG 프로토콜 (FTP) | 오프로드 불가 | 페이로드 수정 필요 | SW 전용 처리 (flowtable 제외) |
| IP fragment | 오프로드 불가 | 완전한 5-tuple 불가 | SW에서 재조립 후 처리 |
| IPsec ESP/AH | crypto offload만 | 전체 flow offload 불가 | xfrm device offload 별도 사용 |
| GRE/VXLAN 내부 flow | 터널 offload 필요 | outer header만 HW 처리 | 커널 6.1+ tunnel offload |
| SCTP | 오프로드 불가 | 드라이버 미지원 | SW flowtable만 가능 |
| conntrack helper (ALG) | 오프로드 불가 | payload inspection 필요 | 해당 flow만 SW 유지 |
TC police/meter + mirred/sample HW 오프로드
TC flower 오프로드는 매치(match)뿐 아니라 다양한 액션(action)도 하드웨어에서 실행할 수 있습니다. 이 절에서는 act_police(속도 제한), act_sample(패킷 샘플링), act_mirred(미러링/리다이렉트), act_ct(커넥션 트래킹)를 조합하여 NGFW QoS + 모니터링 + 포워딩 파이프라인을 하드웨어에서 구현하는 방법을 살펴봅니다.
tc police action HW 오프로드
act_police는 토큰 버킷(Token Bucket) 알고리즘을 사용하여 트래픽 속도를 제한합니다. 커널 6.3 이상에서 skip_sw 플래그와 함께 사용하면, NIC ASIC의 하드웨어 미터(Meter)에서 속도 제한을 수행합니다.
토큰 버킷 알고리즘
| 파라미터 | 설명 | tc 옵션 |
|---|---|---|
| rate | 허용 속도 (CIR: Committed Information Rate) | rate 1gbit |
| burst | 버스트 허용량 (CBS: Committed Burst Size) | burst 64k |
| peakrate | 피크 속도 (PIR: Peak Information Rate, 선택) | peakrate 2gbit |
| conform-exceed | 초과 시 액션 (drop, pipe, ok, reclassify) | conform-exceed drop/pipe |
per-flow 속도 제한
# === per-flow police 오프로드 ===
# 인그레스 qdisc 생성
tc qdisc add dev enp1s0f0 ingress
# 특정 플로우(10.0.0.0/24 → any, TCP/443)에 1 Gbps 제한
tc filter add dev enp1s0f0 ingress protocol ip \
flower skip_sw \
src_ip 10.0.0.0/24 \
ip_proto tcp dst_port 443 \
action police rate 1gbit burst 64k \
conform-exceed drop/pipe \
hw_stats immediate
# 전체 포트에 10 Gbps 제한 (per-port policing)
tc filter add dev enp1s0f0 ingress protocol all \
prio 1000 flower skip_sw \
action police rate 10gbit burst 256k \
conform-exceed drop/pipe
드라이버 구현: mlx5e_tc_act_police
mlx5 드라이버에서 act_police HW 오프로드는 다음과 같은 경로로 처리됩니다.
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c에서 TC 액션 파싱 시 police를 감지하는 호출 흐름입니다:
tc_act_police_offload()mlx5e_tc_act_police.offload()mlx5_create_flow_meter()— HW 미터 객체 생성MLX5_CMD_OP_CREATE_FLOW_METER— 펌웨어 명령
- FDB 규칙에 미터 연결
주요 구조체 mlx5_flow_meter_params의 필드:
u64 cir- Committed Information Rate (bytes/sec)
u32 cbs- Committed Burst Size (bytes)
u64 eir- Excess Information Rate (optional)
u32 ebs- Excess Burst Size (optional)
tc 명령에 skip_sw를 지정하면 하드웨어만으로 처리하라는 의미입니다. HW 오프로드가 실패하면 규칙 설치 자체가 에러를 반환합니다. skip_hw는 반대로 소프트웨어만 사용합니다. skip_sw도 skip_hw도 지정하지 않으면 HW를 시도하고 실패 시 SW로 폴백(Fallback)합니다.
tc sample action HW 오프로드
act_sample은 패킷 샘플링을 수행하여 sFlow/IPFIX 수집기에 트래픽 가시성을 제공합니다. 하드웨어 오프로드 시 CPU 개입 없이 NIC이 직접 샘플 패킷을 추출합니다.
psample 커널 모듈
psample(net/psample/)은 커널의 패킷 샘플링 인프라입니다. NIC 드라이버가 샘플링한 패킷을 netlink 채널을 통해 사용자 공간의 수집기(hsflowd, softflowd 등)에 전달합니다.
| 파라미터 | 설명 | tc 옵션 |
|---|---|---|
| rate | 샘플 비율 (1:N, N개 패킷 중 1개 샘플) | rate 1000 |
| group | psample 그룹 ID (수집기 식별) | group 1 |
| trunc | 샘플 패킷 절단 크기 (헤더만 수집 시) | trunc 128 |
# === tc sample HW 오프로드 설정 ===
# 1:1000 비율로 샘플링, psample 그룹 1, 헤더 128바이트만
tc filter add dev enp1s0f0 ingress protocol ip \
flower skip_sw \
action sample rate 1000 group 1 trunc 128
# 모든 트래픽 샘플링 (matchall 사용)
tc filter add dev enp1s0f0 ingress protocol all \
matchall skip_sw \
action sample rate 500 group 1 trunc 256
# psample 그룹 확인
cat /proc/net/psample/groups
# 출력 예시:
# group 1: refcnt 1, packets 523456, bytes 67002368
sFlow 수집기 연동 (hsflowd)
# hsflowd 설치 및 설정
# /etc/hsflowd.conf
# sflow {
# sampling = 1000
# polling = 30
# collector { ip = 10.0.0.200 udpport = 6343 }
# }
# hsflowd는 psample netlink에서 샘플을 수신하여 sFlow 패킷으로 변환
systemctl start hsflowd
systemctl status hsflowd
# 실시간 sFlow 데이터 확인 (sflowtool)
sflowtool -p 6343 | head -20
tc mirred + pedit HW 오프로드
act_mirred는 패킷을 다른 인터페이스로 리다이렉트(redirect)하거나 미러(mirror, 복제)합니다. IDS/IPS TAP 포트 구성에 핵심적이며, act_pedit을 결합하면 미러링 전에 헤더를 수정할 수 있습니다.
mirred redirect vs mirror
| 모드 | 동작 | 용도 |
|---|---|---|
| egress redirect | 패킷을 대상 인터페이스로 전달 (원래 경로 대체) | 포워딩, Hairpin, NAT 후 전달 |
| egress mirror | 패킷 복제본을 대상 인터페이스로 전송 (원본은 원래 경로 유지) | IDS TAP, 트래픽 분석, 감사 로깅 |
# === mirred 오프로드: IDS TAP 포트 구성 ===
# 특정 플로우를 IDS 모니터링 포트(enp1s0f1)로 미러링
tc filter add dev enp1s0f0 ingress protocol ip \
flower skip_sw \
src_ip 10.0.0.0/24 \
ip_proto tcp dst_port 443 \
action mirred egress mirror dev enp1s0f1 pipe \
action mirred egress redirect dev enp1s0f0_1
# 전체 포트 미러링 (matchall)
tc filter add dev enp1s0f0 ingress protocol all \
matchall skip_sw \
action mirred egress mirror dev enp1s0f1
# 이그레스 방향도 미러링 (양방향 TAP)
tc qdisc add dev enp1s0f0 clsact
tc filter add dev enp1s0f0 egress protocol all \
matchall skip_sw \
action mirred egress mirror dev enp1s0f1
pedit을 이용한 헤더 수정 후 미러링
# ERSPAN-like: 미러링 전에 GRE 헤더 정보를 DSCP에 기록
# (실제 ERSPAN 캡슐화는 HW 지원 필요)
tc filter add dev enp1s0f0 ingress protocol ip \
flower skip_sw \
ip_proto tcp \
action pedit ex munge ip dscp set 46 pipe \
action mirred egress mirror dev enp1s0f1
# VLAN 태그 추가 후 미러링 (TAP 포트에서 VLAN으로 소스 구분)
tc filter add dev enp1s0f0 ingress protocol ip \
flower skip_sw \
src_ip 10.0.1.0/24 \
action vlan push id 100 pipe \
action mirred egress mirror dev enp1s0f1
tc meter (committed/peak) HW 오프로드
Two-Rate Three-Color Marker(trTCM, RFC 2698)는 트래픽을 CIR(Committed Information Rate)과 PIR(Peak Information Rate)를 기준으로 Green/Yellow/Red 세 가지 색상으로 분류합니다. 이 분류 결과를 skb->priority에 반영하여 후속 QoS 스케줄링에 활용합니다.
trTCM 색상 분류
| 색상 | 조건 | 처리 |
|---|---|---|
| Green | CIR 이내 | 정상 전달, 최고 우선순위 |
| Yellow | CIR 초과, PIR 이내 | 혼잡 시 우선 드롭 대상 |
| Red | PIR 초과 | 즉시 드롭 또는 재분류 |
# === Two-Rate Three-Color Marker HW 오프로드 ===
# CIR=1Gbps, CBS=64KB, PIR=2Gbps, PBS=128KB
tc filter add dev enp1s0f0 ingress protocol ip \
flower skip_sw \
src_ip 10.0.0.0/24 \
action police rate 1gbit burst 64k \
peakrate 2gbit mtu 128k \
conform-exceed pipe/pipe pipe \
action skbedit priority 1 # Green → 높은 우선순위
# Yellow 트래픽 재분류 (체인으로 분기)
# police exceed → pipe → 다음 action에서 priority 낮춤
tc filter add dev enp1s0f0 ingress protocol ip \
flower skip_sw \
src_ip 10.0.0.0/24 \
action police rate 1gbit burst 64k \
conform-exceed ok/pipe pipe \
action skbedit priority 7 # Yellow → 낮은 우선순위
HTB/PRIO qdisc와 통합
# police 색상 분류 → PRIO qdisc로 계층적 QoS
# 이그레스에 PRIO qdisc 설정 (3개 밴드)
tc qdisc add dev enp1s0f0 root handle 1: prio bands 3
# 밴드별 rate 제한 (HTB)
tc qdisc add dev enp1s0f0 parent 1:1 handle 10: htb
tc class add dev enp1s0f0 parent 10: classid 10:1 htb rate 5gbit
tc qdisc add dev enp1s0f0 parent 1:2 handle 20: htb
tc class add dev enp1s0f0 parent 20: classid 20:1 htb rate 3gbit
tc qdisc add dev enp1s0f0 parent 1:3 handle 30: htb
tc class add dev enp1s0f0 parent 30: classid 30:1 htb rate 1gbit
# police에서 설정한 priority에 따라 밴드 매핑
# priority 1(Green) → 밴드 0(최고), 4(Yellow) → 밴드 1, 7(Red) → 밴드 2
act_police의 peakrate HW 오프로드는 커널 6.5 이상에서 안정적으로 지원됩니다. trTCM의 세 가지 색상을 모두 구분하려면 NIC 하드웨어가 dual-rate meter를 지원해야 합니다. 지원 여부는 ethtool -i로 드라이버 버전을 확인하고, 벤더 릴리스 노트를 참조합니다.
통합 예제: NGFW QoS + 모니터링 + 포워딩 파이프라인
앞서 소개한 모든 TC 액션을 결합하여, 하나의 TC flower 체인에서 NGFW의 QoS, 모니터링, 스테이트풀 방화벽, NAT, 포워딩을 모두 하드웨어에서 처리하는 완전한 파이프라인을 구성합니다.
파이프라인 구성: 인그레스 → 매치 → police → sample → ct → nat → mirred
# =============================================================
# 통합 NGFW HW 오프로드 파이프라인 (전체 skip_sw)
# =============================================================
# 0. 사전 설정
tc qdisc add dev enp1s0f0 ingress
tc qdisc add dev enp1s0f0_1 ingress # VF1 representor
# =============================================================
# 1단계: chain 0 — 매치 + police(속도 제한) + sample(IDS) + CT 진입
# =============================================================
tc filter add dev enp1s0f0 ingress protocol ip \
chain 0 prio 1 flower skip_sw \
ip_proto tcp \
src_ip 10.0.0.0/24 dst_ip 192.168.1.0/24 \
dst_port 443 \
action police rate 1gbit burst 64k \
conform-exceed drop/pipe pipe \
action sample rate 1000 group 1 trunc 128 pipe \
action ct zone 1 nat pipe \
action goto chain 1
# =============================================================
# 2단계: chain 1 — CT 상태 확인 + NAT + 포워딩
# =============================================================
# ESTABLISHED 세션: NAT 적용 후 VF1으로 리다이렉트
tc filter add dev enp1s0f0 ingress protocol ip \
chain 1 prio 1 flower skip_sw \
ct_state +trk+est \
action mirred egress redirect dev enp1s0f0_1
# 새 연결(NEW): CT 커밋 + DNAT + 포워딩
tc filter add dev enp1s0f0 ingress protocol ip \
chain 1 prio 10 flower skip_sw \
ct_state +trk+new \
ip_proto tcp dst_port 443 \
action ct commit zone 1 \
nat dst addr 192.168.1.10 port 8443 pipe \
action mirred egress redirect dev enp1s0f0_1
# 허용되지 않은 트래픽: 차단
tc filter add dev enp1s0f0 ingress protocol ip \
chain 1 prio 99 flower skip_sw \
action drop
# =============================================================
# 3단계: 역방향 (VF1 → 외부)
# =============================================================
tc filter add dev enp1s0f0_1 ingress protocol ip \
chain 0 flower skip_sw \
ip_proto tcp ct_state -trk \
action ct zone 1 nat pipe \
action goto chain 1
tc filter add dev enp1s0f0_1 ingress protocol ip \
chain 1 flower skip_sw \
ct_state +trk+est \
action mirred egress redirect dev enp1s0f0
오프로드 상태 검증
# === 규칙 설치 및 HW 통계 확인 ===
# 모든 규칙이 HW에 설치되었는지 확인 (in_hw 플래그)
tc -s filter show dev enp1s0f0 ingress
# 출력 예시:
# filter protocol ip pref 1 flower chain 0
# in_hw in_hw_count 1
# action order 1: police 0x1 rate 1Gbit burst 64Kb ...
# Sent 892345678 bytes 5234567 pkt (hw: 892345678 bytes 5234567 pkt)
# action order 2: sample rate 1/1000 group 1 trunc 128 ...
# Sent 892345 bytes 5234 pkt (sampled)
# action order 3: ct zone 1 nat pipe ...
# Sent 892345678 bytes 5234567 pkt
# action order 4: goto chain 1
# conntrack 오프로드 엔트리 확인
conntrack -L | grep zone=1 | head -5
# police 드롭 통계
tc -s actions ls action police
# 출력: police 0x1 ... drop 12345 overlimits 12345
# sample 통계
cat /proc/net/psample/groups
# 실시간 모니터링 (1초 간격)
watch -n 1 'tc -s filter show dev enp1s0f0 ingress chain 0'
police가 sample보다 먼저 와야 rate limit을 초과한 패킷이 샘플링되지 않습니다. ct는 mirred보다 먼저 와야 커넥션 트래킹이 완료된 후 포워딩됩니다. 순서를 잘못 지정하면 보안 정책이 우회될 수 있습니다.
TC 액션 오프로드 파이프라인 다이어그램
아래 다이어그램은 TC 액션들이 하드웨어에서 처리되는 순서와 각 액션의 역할, 그리고 샘플 복제본이 별도의 모니터링 포트로 전달되는 경로를 보여줍니다.
skip_hw로 소프트웨어에서 정상 동작을 확인한 뒤, skip_sw로 변경하여 하드웨어 오프로드를 활성화합니다. tc -s filter show의 hw_stats를 실시간 모니터링하여 예상치 못한 동작을 빠르게 감지합니다.
대규모 규칙 관리
이 주제는 별도 페이지로 분리되었습니다: NGFW 고급 오프로드 구성 — 대규모 규칙 관리
NGFW offload 모니터링 및 통계 수집
NGFW offload 환경에서는 HW에서 처리되는 패킷이 기존 SW 카운터에 반영되지 않으므로, 전용 모니터링 체계가 필요합니다. ethtool, devlink trap, conntrack 이벤트, NIC 하드웨어 카운터를 조합하여 종합적인 가시성을 확보합니다.
ethtool HW 카운터 수집
# Mellanox CX-6 HW offload 관련 카운터
ethtool -S enp3s0f0 | grep -E "offload|ct_|flow_"
# tx_vport_rdma_ucast_bytes: 0
# rx_steer_missed_packets: 0
# ct_offload_rx_packets: 15234567
# ct_offload_rx_bytes: 12345678901
# ct_offload_tx_packets: 14567890
# ct_offload_tx_bytes: 11234567890
# flow_table_hw_count: 45230
# flow_table_hw_max: 4000000
# flow_table_sw_count: 120
# tc_offload_rx_packets: 2345678
# tc_offload_tx_packets: 2234567
# Intel E810 HW 카운터
ethtool -S eth0 | grep -E "fdir|offload"
# fdir_match: 1234567
# fdir_miss: 456
# fdir_sb_match: 234567
# rx_hw_offload_packets: 9876543
# 주기적 수집 스크립트 (Prometheus 텍스트 형식)
cat << 'SCRIPT' > /usr/local/bin/ngfw-metrics.sh
#!/bin/bash
IFACE="${1:-enp3s0f0}"
PREFIX="ngfw_offload"
ct_rx_pkts=$(ethtool -S $IFACE 2>/dev/null | awk '/ct_offload_rx_packets/ {print $2}')
ct_tx_pkts=$(ethtool -S $IFACE 2>/dev/null | awk '/ct_offload_tx_packets/ {print $2}')
hw_flows=$(ethtool -S $IFACE 2>/dev/null | awk '/flow_table_hw_count/ {print $2}')
hw_max=$(ethtool -S $IFACE 2>/dev/null | awk '/flow_table_hw_max/ {print $2}')
sw_flows=$(ethtool -S $IFACE 2>/dev/null | awk '/flow_table_sw_count/ {print $2}')
# conntrack 통계
ct_total=$(conntrack -C 2>/dev/null || echo 0)
ct_max=$(sysctl -n net.netfilter.nf_conntrack_max 2>/dev/null || echo 0)
ct_offloaded=$(conntrack -L 2>/dev/null | grep -c "\[OFFLOAD\]" || echo 0)
echo "# HELP ${PREFIX}_ct_rx_packets CT offloaded RX packets"
echo "# TYPE ${PREFIX}_ct_rx_packets counter"
echo "${PREFIX}_ct_rx_packets{iface=\"$IFACE\"} ${ct_rx_pkts:-0}"
echo "# HELP ${PREFIX}_ct_tx_packets CT offloaded TX packets"
echo "# TYPE ${PREFIX}_ct_tx_packets counter"
echo "${PREFIX}_ct_tx_packets{iface=\"$IFACE\"} ${ct_tx_pkts:-0}"
echo "# HELP ${PREFIX}_hw_flows Current HW flow entries"
echo "# TYPE ${PREFIX}_hw_flows gauge"
echo "${PREFIX}_hw_flows{iface=\"$IFACE\"} ${hw_flows:-0}"
echo "# HELP ${PREFIX}_hw_flows_max Maximum HW flow entries"
echo "# TYPE ${PREFIX}_hw_flows_max gauge"
echo "${PREFIX}_hw_flows_max{iface=\"$IFACE\"} ${hw_max:-0}"
echo "# HELP ${PREFIX}_conntrack_total Total conntrack entries"
echo "# TYPE ${PREFIX}_conntrack_total gauge"
echo "${PREFIX}_conntrack_total ${ct_total}"
echo "# HELP ${PREFIX}_conntrack_offloaded Offloaded conntrack entries"
echo "# TYPE ${PREFIX}_conntrack_offloaded gauge"
echo "${PREFIX}_conntrack_offloaded ${ct_offloaded}"
# Offload 비율 계산
if [ "$ct_total" -gt 0 ]; then
offload_ratio=$(echo "scale=4; $ct_offloaded / $ct_total" | bc)
else
offload_ratio=0
fi
echo "# HELP ${PREFIX}_offload_ratio Ratio of offloaded connections"
echo "# TYPE ${PREFIX}_offload_ratio gauge"
echo "${PREFIX}_offload_ratio $offload_ratio"
SCRIPT
chmod +x /usr/local/bin/ngfw-metrics.sh
devlink trap 모니터링
# devlink trap: HW에서 SW로 전달된 예외 패킷 모니터링
devlink trap show pci/0000:03:00.0
# 특정 trap 그룹 통계
devlink trap group show pci/0000:03:00.0 group l2_drops
devlink trap group show pci/0000:03:00.0 group l3_drops
devlink trap group show pci/0000:03:00.0 group acl_drops
# trap 카운터 (패킷 수)
devlink trap show pci/0000:03:00.0 trap source_mac_is_multicast
# pci/0000:03:00.0:
# name source_mac_is_multicast type drop
# generic true action drop group l2_drops
# stats:
# rx:
# bytes 0 packets 0
# 실시간 trap 모니터링 (tcpdump처럼)
devlink trap set pci/0000:03:00.0 trap ingress_flow_action_drop action trap
# → 캡처된 패킷이 devlink trap policer를 통해 CPU로 전달
# trap policer 설정 (CPU 보호)
devlink trap policer set pci/0000:03:00.0 policer 1 rate 1000 burst 128
# 주기적 trap 통계 수집
watch -n 5 'devlink -s trap show pci/0000:03:00.0 | grep -E "packets [1-9]"'
핵심 경보 규칙
| 메트릭 | 임계값 | 심각도 | 설명 |
|---|---|---|---|
| HW flow 사용률 | > 80% | Warning | TCAM/hash 테이블 용량 부족 예고 |
| HW flow 사용률 | > 95% | Critical | SW fallback 발생, 성능 급감 |
| CT offload 비율 | < 70% | Warning | 대부분 세션이 SW 처리 중 |
| devlink trap 패킷율 | > 10K/s | Warning | exception 경로 과부하 |
| conntrack 테이블 | > 90% | Critical | 새 연결 거부 위험 |
| TC 규칙 삽입 실패 | > 0 | Warning | HW offload 실패 (용량/미지원) |
| flow aging 급증 | 전일 대비 2x | Info | 트래픽 패턴 변화 감지 |
벤더별 offload 지원 현황 비교
NGFW 하드웨어 오프로드 지원 수준은 NIC 벤더와 모델에 따라 크게 다릅니다. 이 섹션에서는 주요 벤더별 오프로드 기능 매트릭스, 드라이버 성숙도, 커널 버전 요구사항을 비교합니다.
NVIDIA/Mellanox 상세
NVIDIA/Mellanox ConnectX 시리즈는 Linux 커널 NGFW offload에서 가장 성숙한 에코시스템을 제공합니다. mlx5 드라이버가 upstream 커널에 포함되어 있으며, TC flower, CT offload, NAT offload, OVS offload를 모두 지원합니다.
| 모델 | 대역폭 | CT 엔트리 | TCAM 규칙 | 최소 커널 | 주요 기능 |
|---|---|---|---|---|---|
| CX-5 | 25/100G | 1M | 16K | 4.19 | TC flower, switchdev, flowtable |
| CX-6 Dx | 25/100G | 4M | 64K | 5.7 | + CT offload, NAT offload |
| CX-6 Lx | 25G | 1M | 16K | 5.7 | CX-6 Dx 기능 서브셋 |
| CX-7 | 400G | 16M | 128K | 6.2 | + enhanced steering, crypto |
| BlueField-2 | 100G | 4M | 64K | 5.11 | + ARM SoC, 전용 OS |
| BlueField-3 | 400G | 64M | 256K | 6.2 | + 16 ARM cores, crypto |
Intel 상세
| 모델 | 대역폭 | CT 엔트리 | TCAM 규칙 | 최소 커널 | 주요 기능 |
|---|---|---|---|---|---|
| E810 (ice) | 25/100G | 512K | 8K | 5.9 | TC flower, switchdev, ADQ |
| E810 + ACC100 | 100G | 512K | 8K | 5.14 | + FEC offload |
| E830 (예정) | 200G | 2M | 32K | 6.8+ | + enhanced CT, tunnel |
| IPU (Mt. Evans) | 200G | TBD | TBD | TBD | IDPF driver, P4 pipeline |
- NGFW 전용 (최대 기능): NVIDIA CX-6 Dx / CX-7 — CT, NAT, OVS offload 모두 지원
- DPU 기반 (최대 유연성): NVIDIA BlueField-3 — ARM에서 커스텀 파이프라인 실행
- 가성비 (기본 offload): Intel E810 — flowtable + 기본 TC flower
- Broadcom/Marvell: 스위치 ASIC 기반 offload에 강점, Linux 드라이버 성숙도는 상대적으로 낮음
커널 6.x NGFW offload 최신 변경사항
Linux 커널 6.x 시리즈에서는 NGFW offload 관련 기능이 대폭 확장되었습니다. CT offload 성능 개선, 새로운 offload 경로, eBPF 기반 확장 등 주요 변경사항을 정리합니다.
| 커널 버전 | 변경사항 | 영향 | 관련 서브시스템 |
|---|---|---|---|
| 6.0 | nf_conntrack 성능 개선: per-CPU hash resize | conntrack 삽입 성능 40% 향상 | nf_conntrack |
| 6.1 | flowtable tunnel offload (VXLAN, Geneve) | 터널 트래픽 HW offload 가능 | nf_flow_table, mlx5 |
| 6.1 | TC flower ct action NAT 포트 범위 | NAPT 오프로드 범위 확대 | act_ct |
| 6.2 | mlx5 CX-7 steering 아키텍처 (HWS) | 규칙 삽입 속도 5배 향상 | mlx5_core |
| 6.2 | nftables flowtable counter offload | HW 패킷 카운터를 flowtable에 반영 | nf_flow_table |
| 6.3 | TC flower police action HW offload | QoS rate limiting을 HW에서 처리 | act_police, mlx5 |
| 6.4 | CT timeout policy offload | 프로토콜별 HW 타임아웃 설정 | act_ct, nf_conntrack |
| 6.5 | flowtable priority 지원 | 멀티 flowtable 우선순위 제어 | nf_flow_table |
| 6.5 | mlx5 connection tracking 스케일 개선 | CT offload 엔트리 16M+ 지원 | mlx5_core |
| 6.6 LTS | ice driver switchdev CT offload | Intel E810 CT 오프로드 지원 | ice |
| 6.7 | nftables inner header match offload | 터널 내부 패킷 매칭 HW offload | nf_tables, mlx5 |
| 6.8 | TC flower sample action offload | HW에서 패킷 샘플링 (sFlow/NetFlow) | act_sample, mlx5 |
| 6.9 | WQ_BH workqueue (softirq 대체) | 네트워크 스택 지연 감소 | workqueue, net |
| 6.10 | nf_flow_table GRO 연동 개선 | offload 경로에서 GRO 활용 | nf_flow_table |
| 6.11 | TC flower ct action mark offload | CT mark를 HW에서 설정/매칭 | act_ct, mlx5 |
| 6.12 | mlx5 enhanced connection tracking v2 | CT miss 시 SW fallback 성능 개선 | mlx5_core |
주요 변경사항 상세
커널 6.1: flowtable tunnel offload
# 커널 6.1+에서 VXLAN 터널 트래픽을 flowtable HW offload 가능
table inet firewall {
flowtable ft {
hook ingress priority 0
devices = { eth0, vxlan0 } # ← VXLAN 인터페이스 포함
flags offload
}
chain forward {
type filter hook forward priority filter; policy drop;
# VXLAN 터널을 통한 세션도 HW offload됨
ct state established,related flow add @ft accept
# ... (나머지 규칙)
}
}
커널 6.2: mlx5 HWS (Hardware Steering)
# mlx5 CX-7 HWS 모드 활성화 (기본값은 FWS)
# HWS: 규칙 삽입 50K/s 이상 (FWS 대비 5배)
devlink dev param set pci/0000:03:00.0 name flow_steering_mode \
value "hmfs" cmode runtime
# HWS 모드 확인
devlink dev param show pci/0000:03:00.0 name flow_steering_mode
# pci/0000:03:00.0:
# name flow_steering_mode type generic
# values:
# cmode runtime value hmfs
커널 6.5: CT 스케일 개선
# CT offload 엔트리 수 확인 (CX-7)
cat /sys/kernel/debug/mlx5/0000:03:00.0/ct/stats
# max_ct_entries: 16777216 ← 16M
# active_ct_entries: 4523120 ← 현재 활성
# ct_insert_rate: 45230/s
# ct_delete_rate: 42100/s
# ct_miss_to_sw: 12/s
# 성능 비교 (커널 6.4 vs 6.5, CX-7)
# 6.4: CT insert ~10K/s, max 4M entries
# 6.5: CT insert ~50K/s, max 16M entries
# (connection rate 5x 향상)
커널 6.8: TC sample action offload
# HW에서 직접 패킷 샘플링 (sFlow 용도)
# CPU를 거치지 않고 NIC에서 1/1000 비율로 샘플링
tc filter add dev enp3s0f0 ingress prio 1 proto ip flower \
skip_sw \
action sample rate 1000 group 1 trunc 128 \
action mirred egress redirect dev enp3s0f0_0
# psample 수신 (sFlow collector에서 활용)
# psample: group=1, seq=12345, iif=3, orig_size=1500, data=...
# 기존 방법 (SW): CPU에서 모든 패킷을 보고 1/N을 추출
# 새 방법 (HW): NIC가 직접 샘플링 → CPU 부하 0
- 프로덕션 (보수적): 커널 6.6 LTS — CT offload + flowtable tunnel + 충분한 안정성
- 고성능 NGFW: 커널 6.8+ — sample offload + police offload + CT mark offload
- CX-7 / BlueField-3: 커널 6.2+ 필수 — HWS steering 지원
- Intel E810: 커널 6.6+ 권장 — ice switchdev CT offload 안정화
멀티 클러스터 NGFW offload 연동
이 주제는 별도 페이지로 분리되었습니다: NGFW 고급 오프로드 구성 — 멀티 클러스터 연동
고가용성(HA) NGFW offload
이 주제는 별도 페이지로 분리되었습니다: NGFW 고급 오프로드 구성 — HA NGFW offload
NGFW offload 트러블슈팅
이 주제는 별도 페이지로 분리되었습니다: NGFW 고급 오프로드 구성 — 고급 트러블슈팅
커널 HW 오프로드 인터페이스 심층 레퍼런스
이 주제는 별도 페이지로 분리되었습니다: 커널 HW 오프로드 인터페이스 레퍼런스 — TC action 12종, Bridge/switchdev, FIB/Routing, Tunnel, qdisc, devlink 심층 레퍼런스
참고자료
커널 공식 문서
- Linux Kernel: nf_flowtable 공식 문서 — flowtable 아키텍처, SW/HW 오프로드 메커니즘
- Linux Kernel: switchdev 프레임워크 — eSwitch 모드, FDB 오프로드 API
- Linux Kernel: TC conntrack action 사용법 — TC flower ct action으로 HW CT offload
- Linux Kernel: XFRM Device Offload — IPSec HW offload API (crypto/packet/full mode)
- Linux Kernel: BPF/XDP 문서 — XDP 프로그램 작성, 맵 타입, HW offload
- Linux Kernel: conntrack sysctl 파라미터 — 세션 테이블 크기, 타임아웃, 해시 설정
- Port Representors — VF/SF representor 기반 트래픽 스티어링
- Devlink — eSwitch 모드, 리소스 관리, 파라미터 설정
벤더 기술 문서
- NVIDIA MLNX_OFED: Connection Tracking Offload — ConnectX-6/7 CT offload 설정 가이드
- NVIDIA BlueField: TC Flower Offload — BlueField DPU TC flower 규칙 HW offload
- Intel ICE Driver (E810) — E810 eSwitch switchdev 모드 지원 드라이버
- NVIDIA Crypto Offload — ConnectX-6 Dx/7 IPSec, TLS 하드웨어 암호화 오프로드
- Broadcom SmartNIC — Stingray PS1100R, 하드웨어 방화벽 오프로드
DPI/IPS 엔진
- Suricata: NFQUEUE IPS 모드 설정 — Suricata + NFQUEUE inline IPS 구성
- Suricata: 성능 튜닝 가이드 — 멀티스레드, 워커 모드, 메모리 최적화
- nDPI: 오픈소스 DPI 라이브러리 — L7 프로토콜 식별, eBPF 연동
- Snort 3 — Cisco 오픈소스 IDS/IPS, 멀티스레드, DAQ AF_PACKET/NFQ
- Zeek (구 Bro) — 네트워크 트래픽 분석 프레임워크, 프로토콜 로깅
- Suricata 소스 (GitHub) — Suricata IDS/IPS 소스 코드
- Suricata Rule Format — 탐지 규칙 작성법, 키워드 레퍼런스
표준/벤치마크
- RFC 9411: Benchmarking Methodology for Network Security Device Performance — NGFW 벤치마크 표준 방법론
- RFC 3511: Benchmarking Methodology for Firewall Performance — 전통 방화벽 벤치마크 (RFC 9411의 기반)
- TRex Traffic Generator — CPS/CC/처리량 측정용 오픈소스 트래픽 생성기
- RFC 2544: Benchmarking Methodology for Network Interconnect Devices — 기본 네트워크 벤치마크 방법론
- TRex 소스 (GitHub) — Stateful/Stateless 트래픽 생성기 소스
- Spirent CyberFlood — 상용 NGFW 벤치마크 솔루션 (참고)
고가용성/운영
- conntrack-tools (conntrackd) 공식 사이트 — HA 세션 동기화, FTFW/NOTRACK 모드
- nftables Wiki — nftables 규칙 작성, flowtable 설정, 예제
- Keepalived — VRRP 기반 HA, Health Check, 방화벽 이중화
- HAProxy — L4/L7 로드 밸런서, 세션 지속, 방화벽 앞단 배치
- Prometheus — 방화벽 메트릭 수집, 세션 수/처리량/지연 모니터링
커널 소스 경로
net/netfilter/nf_flow_table_core.c— flowtable 코어 구현 (SW/HW offload)net/netfilter/nf_conntrack_core.c— conntrack 세션 관리net/sched/cls_flower.c— TC flower 분류기 (HW offload 진입점)net/sched/act_ct.c— TC conntrack action (CT offload)net/netfilter/nft_flow_offload.c— nftables flowtable 오프로드net/xfrm/xfrm_device.c— IPSec HW offload 디바이스 APInet/netfilter/nfnetlink_queue.c— NFQUEUE 커널 모듈 (DPI 연동)include/net/netfilter/nf_flow_table.h— flowtable API 헤더
- NGFW 암/복호화 오프로드 — kTLS, IPSec, MACsec, Intel QAT, SSL Inspection
- 상용 NGFW HW 아키텍처 — Fortinet NP7, Palo Alto SP3, Check Point, Juniper
- HW 오프로드 인터페이스 레퍼런스 — TC action 12종, switchdev, FIB, Tunnel, devlink
- NGFW 고급 오프로드 구성 — QUIC/ECH, 멀티 테넌트, Hairpin, 대규모 규칙, HA, 트러블슈팅
- eBPF + P4 NGFW 파이프라인 — BPF netfilter, Cilium, P4 match-action
- Netfilter Flowtable — SW/HW 오프로드 상세 메커니즘
- eSwitch (Embedded Switch) — TC flower offload 실전
- SmartNIC/DPU — DPU 아키텍처와 제품군
- NFQUEUE & DPI 엔진 통합 — Suricata/nDPI 연동
- TC (Traffic Control) — qdisc, TC flower 규칙
- Network Device 드라이버 — ndo_setup_tc 오프로드 계약
- 네트워크 공격 방어 — XDP DDoS pre-filter
- Open vSwitch — OVS TC flower offload
- VPP (FD.io) — VPP 기반 NGFW 데이터 플레인