커널 HW 오프로드 인터페이스 레퍼런스
Linux 커널 HW 오프로드 인터페이스 심층 레퍼런스: TC action 12종(mirred·pedit·csum·vlan·tunnel_key·ct·sample·police·gate·skbedit·connmark·mpls), Bridge/switchdev FDB·VLAN·MDB·STP 오프로드, FIB/Routing, Tunnel encap/decap, LAG/Bond, TC chain 멀티스테이지, qdisc(mqprio·taprio·CBS), ethtool, Header Rewrite, Meter/Policer, devlink
TC action 오프로드 전체 레퍼런스
TC(Traffic Control) action은 cls_flower 분류기가 패킷을 매칭한 뒤 수행하는 처리 단위입니다.
커널 include/net/flow_offload.h에 정의된 flow_action_entry 구조체 배열로 드라이버에 전달되며,
드라이버는 ndo_setup_tc 콜백에서 이를 받아 ASIC 파이프라인(Pipeline)에 프로그래밍합니다.
각 action은 독립적인 flow_action_id 열거값을 가지며, 여러 action이 연결되어 복합 파이프라인을 구성합니다.
act_mirred — 리디렉트(Redirect) 및 미러(Mirror)
act_mirred는 패킷을 다른 네트워크 인터페이스로 리디렉트(전송)하거나 미러링(복제 전달)하는 TC action입니다.
커널 소스는 net/sched/act_mirred.c에 위치합니다.
드라이버 계약 — flow_action_entry 매핑:
리디렉트 동작은 FLOW_ACTION_REDIRECT, 미러 동작은 FLOW_ACTION_MIRROR로 매핑됩니다.
flow_action_entry.dev 필드에 목적지 net_device 포인터가 설정됩니다.
eSwitch(Embedded Switch) 환경에서는 소스와 목적지가 동일 물리 NIC의 VF(Virtual Function)일 경우,
드라이버가 내부 포트 매핑 테이블(Port Mapping Table)에 직접 프로그래밍하여 패킷이 CPU 없이 포트-대-포트로 이동합니다.
HW 오프로드 지원 수준: mlx5, ice, bnxt_en, nfp, hns3 모두 REDIRECT를 지원합니다. MIRROR는 mlx5와 nfp가 지원하며, 미러링 패킷을 별도 인터페이스로 복사합니다. 헤어핀(Hairpin) 모드는 수신된 포트로 다시 전송하는 자기 루프(Self-Loop)로, mlx5 eSwitch에서 NAT 후 원래 포트로 반환 시 활용합니다.
NGFW 활용 시나리오:
- 포트-대-포트 L2 포워딩: NGFW가 브리지(Bridge) 없이 두 포트 사이의 패킷을 ASIC에서 직접 전달합니다. 연결 추적이 완료된 세션에서 mirred redirect로 와이어 속도 전달을 구현합니다.
- IDS TAP 미러링: act_mirred mirror로 패킷 복사본을 Suricata/Snort 인터페이스로 전달합니다. ASIC이 복제를 처리하므로 CPU 부하가 없습니다.
- 헤어핀 NAT: VF에서 수신한 패킷을 NAT 처리 후 동일 VF로 반환할 때 hairpin 모드를 활용합니다.
# act_mirred: 리디렉트 오프로드 설정
# eth0(uplink) → eth1(downlink) 방향 세션 리디렉트
tc qdisc add dev eth0 ingress
tc filter add dev eth0 ingress \
protocol ip prio 1 flower \
ct_state +est+trk \
dst_ip 192.168.1.0/24 \
action mirred egress redirect dev eth1
# act_mirred: IDS 미러링 (복사본을 tap0으로 전달)
tc filter add dev eth0 ingress \
protocol ip prio 2 flower \
action mirred egress mirror dev tap0 \
action mirred egress redirect dev eth1
/* net/sched/act_mirred.c — HW 오프로드 flow_action_entry 구성 */
int tcf_mirred_offload_act_setup(struct tc_action *act,
void *entry_data,
u32 *index_inc, bool bind,
struct netlink_ext_ack *extack)
{
struct flow_action_entry *entry = entry_data;
struct tcf_mirred *m = to_mirred(act);
if (tcf_mirred_is_redirect(m->tcfm_eaction)) {
entry->id = FLOW_ACTION_REDIRECT; /* 리디렉트 */
} else {
entry->id = FLOW_ACTION_MIRROR; /* 미러 */
}
/* 목적지 net_device 설정 — 드라이버가 포트 테이블에 프로그래밍 */
entry->dev = tcf_mirred_dev(act);
return 0;
}
act_pedit — 패킷 헤더 수정 (Header Modification)
act_pedit는 패킷의 임의 필드를 바이트 단위로 수정하는 TC action입니다.
커널 소스는 net/sched/act_pedit.c, HW 오프로드 변환 로직은 net/sched/cls_flower.c의 fl_dump_key_pedit와
드라이버 측 parse_tc_pedit_action()에 있습니다.
드라이버 계약 — flow_action_entry 매핑:
pedit action은 FLOW_ACTION_MANGLE로 매핑됩니다.
flow_action_entry.mangle 구조체에 수정 대상 헤더 타입(htype), 오프셋(offset), 마스크(mask), 값(val)이 설정됩니다.
지원 필드: IP 소스/목적지 주소, TCP/UDP 포트, MAC 주소, TTL(Time To Live), DSCP(Differentiated Services Code Point),
VLAN PCP, IPv6 주소 등입니다. 드라이버별 지원 필드 제한이 있으므로, 지원하지 않는 필드를 오프로드하려 하면
FLOW_ACTION_MANGLE 처리 시 -EOPNOTSUPP를 반환하고 소프트웨어 경로로 폴백(Fallback)합니다.
드라이버별 지원 필드 제한:
- mlx5e: IPv4/v6 주소, TCP/UDP 포트, TTL, DSCP, MAC 주소 전부 지원.
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c - ice: IPv4/v6 주소, TCP/UDP 포트, TTL 지원. DSCP 수정은 펌웨어 버전 의존.
drivers/net/ethernet/intel/ice/ice_tc_lib.c - bnxt_en: 제한적 지원 — IPv4 주소, 포트 수정 가능.
drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
# act_pedit: NAT용 목적지 IP 수정 오프로드
tc filter add dev eth0 ingress \
protocol ip prio 1 flower \
ct_state +est+trk \
ct_mark 0x1/0x1 \
action pedit ex munge ip dst set 10.0.0.1 \
action csum ip tcp \
action mirred egress redirect dev eth1
# DSCP 마킹 (QoS 정책): DSCP를 EF(0x2E)로 설정
tc filter add dev eth0 ingress \
protocol ip prio 3 flower \
ip_tos 0x00/0xfc \
action pedit ex munge ip tos set 0xb8 retain 0xfc \
action mirred egress redirect dev eth1
/* include/net/flow_offload.h — FLOW_ACTION_MANGLE 구조 */
struct flow_action_entry {
enum flow_action_id id;
union {
struct { /* FLOW_ACTION_MANGLE */
enum flow_action_mangle_base htype; /* FLOW_ACT_MANGLE_HDR_TYPE_ETH 등 */
u32 offset; /* 헤더 내 오프셋 (바이트) */
u32 mask; /* 변경할 비트 마스크 */
u32 val; /* 설정할 값 */
} mangle;
/* ... 다른 action 공용체 필드 ... */
};
};
act_csum — 체크섬(Checksum) 재계산
act_csum은 act_pedit로 헤더를 수정한 뒤 IP(L3), TCP/UDP(L4), SCTP 체크섬을 재계산하는 TC action입니다.
커널 소스는 net/sched/act_csum.c에 있습니다.
드라이버 계약 — flow_action_entry 매핑:
FLOW_ACTION_CSUM으로 매핑됩니다.
flow_action_entry.csum_flags에 재계산 대상 체크섬이 비트 플래그로 설정됩니다:
TCA_CSUM_UPDATE_FLAG_IPV4HDR(IPv4 헤더 체크섬),
TCA_CSUM_UPDATE_FLAG_TCP(TCP 체크섬),
TCA_CSUM_UPDATE_FLAG_UDP(UDP 체크섬),
TCA_CSUM_UPDATE_FLAG_SCTP(SCTP 체크섬).
NGFW 활용: NAT 오프로드에서 IP 주소나 포트를 변경한 뒤 반드시 체크섬 재계산이 필요합니다.
대부분의 ASIC이 헤더 수정 후 체크섬 재계산을 하드웨어에서 자동으로 수행하므로,
act_csum은 ASIC에 체크섬 재계산 플래그를 활성화하도록 지시하는 역할을 합니다.
mlx5는 modify_header 명령에 체크섬 업데이트 플래그를 내장하여 별도 단계 없이 처리합니다.
# act_csum: pedit 이후 L3/L4 체크섬 재계산
tc filter add dev eth0 ingress \
protocol ip prio 1 flower \
ct_state +est+trk \
action pedit ex munge ip dst set 10.0.0.1 \
munge tcp dport set 8080 \
action csum ip tcp \
action mirred egress redirect dev eth1
act_vlan — VLAN 푸시(Push)/팝(Pop)/수정(Mangle)
act_vlan은 VLAN(Virtual LAN) 태그를 추가(push), 제거(pop), 또는 수정(modify)하는 TC action입니다.
커널 소스는 net/sched/act_vlan.c에 있습니다.
드라이버 계약 — flow_action_entry 매핑:
TCA_VLAN_ACT_PUSH→FLOW_ACTION_VLAN_PUSH:entry->vlan.vid,entry->vlan.prio,entry->vlan.proto설정TCA_VLAN_ACT_POP→FLOW_ACTION_VLAN_POP: 외부 VLAN 태그 제거TCA_VLAN_ACT_MODIFY→FLOW_ACTION_VLAN_MANGLE: VID(VLAN ID) 또는 PCP(Priority Code Point) 변경
QinQ(IEEE 802.1ad) 지원: proto 필드에 ETH_P_8021AD(0x88a8)를 설정하면 외부 태그로 S-VLAN을 추가합니다.
mlx5와 nfp가 QinQ 이중 태깅을 HW에서 지원합니다.
NGFW 활용:
- 트렁크(Trunk) 포트: 업링크(Uplink)에서 VLAN 태그를 팝하고 내부 포트로 전달합니다.
- 액세스(Access) 포트: 내부 포트에서 수신한 언태그(Untagged) 패킷에 VLAN을 푸시합니다.
- VLAN 간 격리: NGFW가 VLAN 세그먼트 사이의 정책을 HW에서 적용합니다.
# act_vlan push: 트래픽에 VLAN 100 태그 추가
tc filter add dev eth0 ingress \
protocol ip prio 1 flower \
action vlan push id 100 protocol 802.1Q \
action mirred egress redirect dev eth1
# act_vlan pop: VLAN 태그 제거 후 내부 포트로 전달
tc filter add dev eth1 ingress \
protocol 802.1Q prio 1 flower \
vlan_id 100 \
action vlan pop \
action mirred egress redirect dev br0
# QinQ: 서비스 VLAN(S-VLAN 200) + 고객 VLAN(C-VLAN 100) 이중 태깅
tc filter add dev uplink ingress \
protocol 802.1Q prio 1 flower \
vlan_id 100 \
action vlan push id 200 protocol 802.1ad \
action mirred egress redirect dev core_port
act_tunnel_key — 터널(Tunnel) 캡슐화/역캡슐화
act_tunnel_key는 VXLAN(Virtual Extensible LAN), GRE(Generic Routing Encapsulation), Geneve 등의 터널 메타데이터(Metadata)를 설정하고
패킷을 캡슐화(Encapsulate) 또는 역캡슐화(Decapsulate)하는 TC action입니다.
커널 소스는 net/sched/act_tunnel_key.c에 있습니다.
드라이버 계약 — flow_action_entry 매핑:
TCA_TUNNEL_KEY_ACT_SET→FLOW_ACTION_TUNNEL_ENCAP:entry->tunnel포인터에ip_tunnel_info설정TCA_TUNNEL_KEY_ACT_RELEASE→FLOW_ACTION_TUNNEL_DECAP: 터널 헤더 제거, 이너 헤더(Inner Header) 노출
ip_tunnel_info 구조: 원격 IP(Remote IP), 로컬 IP(Local IP), VNI(VXLAN Network Identifier)/터널 키, ToS, TTL, VXLAN 플래그가 포함됩니다. 드라이버는 이 정보를 ASIC의 터널 엔드포인트 테이블에 프로그래밍합니다.
이너 헤더 매칭: DECAP action 후 flower 분류기가 이너 패킷의 IP/포트를 매칭할 수 있습니다. mlx5는 VXLAN 역캡슐화 후 이너 헤더 기준으로 CT와 pedit action을 연결하는 전체 파이프라인을 HW에서 처리합니다.
NGFW 활용:
- VXLAN 오버레이(Overlay) NGFW: 서버 팜(Farm) 앞단에서 VXLAN 역캡슐화 → 정책 검사 → 재캡슐화를 HW에서 수행합니다.
- GRE 터널 인라인 검사: GRE 역캡슐화 후 이너 헤더 CT 추적을 ASIC에서 처리합니다.
# VXLAN 역캡슐화 후 이너 헤더 기준 리디렉트
tc filter add dev vxlan0 ingress \
protocol ip prio 1 flower \
enc_dst_ip 192.168.100.1 \
enc_src_ip 10.0.0.1 \
enc_key_id 1000 \
action tunnel_key unset \
action ct commit \
action mirred egress redirect dev eth_internal
# VXLAN 캡슐화 — 이너 패킷에 VXLAN 헤더 추가
tc filter add dev eth_internal ingress \
protocol ip prio 1 flower \
dst_ip 192.168.200.0/24 \
action tunnel_key set \
src_ip 10.0.0.1 \
dst_ip 10.0.0.2 \
id 1000 \
dst_port 4789 \
action mirred egress redirect dev vxlan0
act_ct — 연결 추적(Connection Tracking) 오프로드
act_ct는 TC 레이어에서 넷필터(Netfilter) conntrack을 연동하는 TC action으로,
NGFW의 스테이트풀(Stateful) 방화벽 오프로드의 핵심입니다.
커널 소스는 net/sched/act_ct.c에 있으며, 넷필터 conntrack API(net/netfilter/nf_conntrack_core.c)를 직접 호출합니다.
드라이버 계약 — flow_action_entry 매핑:
FLOW_ACTION_CT로 매핑됩니다. flow_action_entry.ct 구조체에 다음 필드가 설정됩니다:
action:TCA_CT_ACT_COMMIT(세션 확립),TCA_CT_ACT_CLEAR(세션 삭제),TCA_CT_ACT_FORCE(기존 세션 갱신),TCA_CT_ACT_NAT(NAT 수행)zone: conntrack 존(Zone) ID — 다중 VRF(Virtual Routing and Forwarding) 시나리오에서 구분mark,mark_mask: ct mark 설정 값labels,labels_mask: ct label 비트맵(Bitmap)
mlx5 CT 오프로드 구현:
mlx5e는 drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c에서 CT 오프로드를 구현합니다.
소프트웨어 conntrack에서 세션이 확립되면 nf_flow_offload_add() 경로를 통해 mlx5 ASIC의 CT 테이블에 항목이 추가됩니다.
ASIC은 이후 패킷에서 5-튜플(Tuple)을 매칭하여 CT 상태(state), 존, 마크를 자동으로 설정합니다.
CT action 시퀀스 — NGFW 스테이트풀 파이어월:
- 첫 번째 패킷: flower
ct_state=-trk매칭 →action ct(추적 시작) → 소프트웨어 conntrack 처리 - SYN/SYN-ACK/ACK: conntrack이 ESTABLISHED 상태 전환 →
ct commit으로 세션 확립 - 확립된 세션: flower
ct_state=+est+trk매칭 → HW 오프로드 엔트리 추가 → 이후 패킷 ASIC 처리
# 스테이트풀 방화벽: CT 오프로드 전체 설정
# 1단계: 추적되지 않은 패킷을 conntrack으로 안내
tc filter add dev eth0 ingress \
protocol ip prio 1 flower \
ct_state -trk \
action ct
# 2단계: 확립된 세션 → HW 오프로드 (커밋 + NAT)
tc filter add dev eth0 ingress \
protocol ip prio 2 flower \
ct_state +est+trk \
action ct commit nat src addr 203.0.113.1 \
action mirred egress redirect dev eth1
# 3단계: NEW 세션 허용 정책 (정책 기반 필터링 후 커밋)
tc filter add dev eth0 ingress \
protocol ip prio 3 flower \
ct_state +new+trk \
dst_port 80 \
action ct commit \
action mirred egress redirect dev eth1
# conntrack 존(zone)을 활용한 다중 VRF 분리
tc filter add dev eth0 ingress \
protocol ip prio 4 flower \
ct_zone 10 \
ct_state +est+trk \
action ct commit zone 10 \
action mirred egress redirect dev vrf10
act_sample — 패킷 샘플링(Packet Sampling)
act_sample은 패킷의 일부를 복사하여 psample 넷링크(Netlink) 그룹으로 전송하는 TC action입니다.
커널 소스는 net/sched/act_sample.c, psample 서브시스템은 net/psample/psample.c에 있습니다.
드라이버 계약 — flow_action_entry 매핑:
FLOW_ACTION_SAMPLE로 매핑됩니다. flow_action_entry.sample 구조체에 다음이 설정됩니다:
psample_group: 샘플 패킷을 수신할 psample 그룹 포인터rate: 샘플링 비율 (1/N). 예: 1000이면 1000개 중 1개 복사trunc_size: 복사할 패킷 바이트 수 (0이면 전체)truncate: 잘라내기 활성화 여부
NGFW 활용:
- sFlow: 고속 링크에서 1/1000 비율로 샘플링하여 트래픽 분석 도구로 전송합니다.
- IPFIX/NetFlow: psample 그룹에서 샘플 패킷을 수신하여 플로우 레코드를 생성합니다.
- HW 와이어 속도 샘플링: mlx5, nfp가 ASIC에서 확률적 샘플링을 수행하여 CPU 부하를 최소화합니다.
# act_sample: 1/1000 확률 샘플링, 첫 128바이트만 복사
# psample 그룹 1로 전달 (사용자 공간 hsflowd/pmacctd 수신)
tc filter add dev eth0 ingress \
protocol ip prio 1 flower \
action sample rate 1000 trunc_size 128 group 1 \
action mirred egress redirect dev eth1
act_police — 속도 제한 (Rate Limiting / Policing)
act_police는 트래픽 속도를 제한하는 TC action으로, 지정된 속도를 초과하는 패킷을 드롭(Drop)하거나
다른 action으로 우회시킵니다. 커널 소스는 net/sched/act_police.c에 있습니다.
드라이버 계약 — flow_action_entry 매핑:
FLOW_ACTION_POLICE로 매핑됩니다. flow_action_entry.police 구조체에 다음이 설정됩니다:
rate_bytes_ps: 허용 속도 (bytes/s) — CIR(Committed Information Rate)burst: 버스트 허용량 (bytes) — CBS(Committed Burst Size)rate_pkt_ps: 패킷 수 기준 속도 제한 (pps)burst_pkt: 패킷 단위 버스트conform_id,exceed_id: 준수/초과 시 다음 action ID
색상 인식(Color-Aware) 폴리싱: 커널 6.3부터 FLOW_ACTION_POLICE에 피크(Peak) 속도 파라미터가 추가되어
단일 속도/이중 속도 삼색 마킹(TCM, Three-Color Marking)을 HW에서 지원합니다.
mlx5는 미터(Meter) 테이블 기반으로 그린(Green)/옐로우(Yellow)/레드(Red) 색상 판정을 ASIC에서 수행합니다.
NGFW 활용: QoS 정책(Policy) 적용, DDoS 방어를 위한 소스 IP별 속도 제한, SLA(Service Level Agreement) 보장이 목적입니다.
# act_police: 10Mbps 속도 제한 (초과 시 드롭)
tc filter add dev eth0 ingress \
protocol ip prio 1 flower \
src_ip 192.168.1.100 \
action police rate 10mbit burst 100k drop \
action mirred egress redirect dev eth1
# 이중 속도 삼색 마킹 (CIR 10Mbps, PIR 20Mbps)
tc filter add dev eth0 ingress \
protocol ip prio 2 flower \
action police rate 10mbit burst 100k \
pkts_rate 0 pkts_burst 0 \
conform-exceed drop/continue \
action mirred egress redirect dev eth1
act_gate — TSN 시간 인식 게이트 (Time-Aware Shaper)
act_gate는 IEEE 802.1Qbv TSN(Time-Sensitive Networking) 규격의 시간 인식 게이트 제어 목록(GCL, Gate Control List)을 TC action으로 구현합니다.
커널 소스는 net/sched/act_gate.c에 있습니다.
드라이버 계약 — flow_action_entry 매핑:
FLOW_ACTION_GATE로 매핑됩니다. flow_action_entry.gate 구조체에 사이클 시간(Cycle Time),
게이트 제어 목록(GCL 엔트리 배열), 기준 시간(Base Time)이 설정됩니다.
NGFW 활용: 산업용 제어망(OT 네트워크)에서 실시간 트래픽과 일반 트래픽을 시간 슬롯으로 분리하여 산업용 NGFW가 실시간성을 보장하면서 보안 정책을 적용합니다. intel ice 드라이버가 802.1Qbv HW 오프로드를 지원합니다.
act_skbedit — SKB 메타데이터 수정
act_skbedit는 소켓 버퍼(SKB, Socket Buffer) 메타데이터 — 우선순위(Priority), 패킷 타입(Ptype), 큐 매핑(Queue Mapping) — 을 수정하는 TC action입니다.
커널 소스는 net/sched/act_skbedit.c에 있습니다.
드라이버 계약 — flow_action_entry 매핑:
- 우선순위 수정 →
FLOW_ACTION_PRIORITY:entry->priority에 skb→priority 값 설정 - 큐 매핑 →
FLOW_ACTION_QUEUE:entry->queue.index에 TX 큐 인덱스 설정,entry->queue.vf에 VF 번호 - 패킷 타입 →
FLOW_ACTION_PTYPE:entry->ptype에PACKET_HOST등 설정
NGFW 활용: 방화벽 정책에 따라 트래픽 클래스를 분류하고 QoS 큐로 조정합니다. 고우선순위 트래픽(VoIP, 제어 트래픽)을 낮은 지연의 TX 큐로 유도하는 데 사용합니다.
act_connmark — CT 마크(Mark) 전파
act_connmark는 넷필터 conntrack 마크(ct mark)를 SKB 마크(skb→mark)로 복사하거나,
SKB 마크를 ct mark로 저장하는 TC action입니다. 커널 소스는 net/sched/act_connmark.c에 있습니다.
동작 방식:
- RESTORE:
ct->mark→skb->mark복사. CT에 저장된 정책 마크를 패킷 마크로 전파하여 이후 qdisc나 라우팅이 참조합니다. - SAVE:
skb->mark→ct->mark저장. 사용자 공간 정책 결정 결과를 CT에 영속화합니다.
HW 오프로드: act_connmark 자체는 FLOW_ACTION_CT의 mark 필드를 통해 간접 오프로드됩니다.
mlx5 CT 오프로드는 ASIC에서 ct mark를 메타데이터 레지스터(REG_C)에 저장하여 이후 action에서 참조합니다.
NGFW 활용: 첫 패킷에서 NFQUEUE/DPI가 판단한 트래픽 분류 결과를 ct mark로 저장하고, 이후 패킷에서 ct mark를 읽어 QoS 큐, 로깅, VPN 터널 선택에 활용합니다.
act_mpls — MPLS 레이블 조작
act_mpls는 MPLS(Multi-Protocol Label Switching) 레이블을 추가(push), 제거(pop), 또는 수정(mangle)하는 TC action입니다.
커널 소스는 net/sched/act_mpls.c에 있습니다.
드라이버 계약 — flow_action_entry 매핑:
TCA_MPLS_ACT_PUSH→FLOW_ACTION_MPLS_PUSH:entry->mpls_push.label,tc,ttl,bos설정TCA_MPLS_ACT_POP→FLOW_ACTION_MPLS_POP: 외부 레이블 제거, 프로토콜 전환TCA_MPLS_ACT_MODIFY→FLOW_ACTION_MPLS_MANGLE: 레이블 값, TC 비트, TTL 수정
NGFW 활용: MPLS 서비스 프로바이더(Service Provider) 환경에서 레이블 스위칭을 HW에서 수행하면서 NGFW 정책을 적용합니다. 레이블 기반 VPN 분리와 방화벽 정책을 결합할 수 있습니다. mlx5와 일부 상용 ASIC이 MPLS push/pop 오프로드를 지원합니다.
TC action 오프로드 종합 비교표
| Action | flow_action_id | HW 오프로드 가능 | mlx5 | ice | bnxt_en | NGFW 용도 | 커널 소스 경로 |
|---|---|---|---|---|---|---|---|
act_mirred |
FLOW_ACTION_REDIRECTFLOW_ACTION_MIRROR |
예 (REDIRECT/MIRROR) | REDIRECT+MIRROR | REDIRECT | REDIRECT | 포트-대-포트 전달, IDS TAP, 헤어핀 NAT | net/sched/act_mirred.c |
act_pedit |
FLOW_ACTION_MANGLE |
예 (필드 제한) | IP/포트/MAC/TTL/DSCP | IP/포트/TTL | IP/포트 | NAT, 헤더 재작성, DSCP 마킹 | net/sched/act_pedit.c |
act_csum |
FLOW_ACTION_CSUM |
예 (ASIC 내장) | 자동 처리 | 자동 처리 | 자동 처리 | NAT/pedit 후 체크섬 재계산 | net/sched/act_csum.c |
act_vlan |
FLOW_ACTION_VLAN_PUSHFLOW_ACTION_VLAN_POPFLOW_ACTION_VLAN_MANGLE |
예 | PUSH+POP+QinQ | PUSH+POP | POP | 트렁크/액세스 포트, VLAN 간 격리, QinQ | net/sched/act_vlan.c |
act_tunnel_key |
FLOW_ACTION_TUNNEL_ENCAPFLOW_ACTION_TUNNEL_DECAP |
예 (VXLAN/GRE/Geneve) | VXLAN+GRE+Geneve | VXLAN | VXLAN | 오버레이 NGFW, 터널 인라인 검사 | net/sched/act_tunnel_key.c |
act_ct |
FLOW_ACTION_CT |
예 (CT 테이블 오프로드) | 완전 지원 | 부분 지원 | 미지원 | 스테이트풀 방화벽, NAT, CT 존 분리 | net/sched/act_ct.c |
act_sample |
FLOW_ACTION_SAMPLE |
예 (확률적 샘플링) | 지원 | 지원 | 미지원 | sFlow, IPFIX, 트래픽 분석 | net/sched/act_sample.c |
act_police |
FLOW_ACTION_POLICE |
예 (미터 테이블) | 완전 지원 | 지원 | 지원 | QoS 정책, DDoS 속도 제한, SLA 보장 | net/sched/act_police.c |
act_gate |
FLOW_ACTION_GATE |
예 (TSN 지원 HW) | 미지원 | 802.1Qbv 지원 | 미지원 | OT 네트워크 실시간 격리, 산업용 NGFW | net/sched/act_gate.c |
act_skbedit |
FLOW_ACTION_PRIORITYFLOW_ACTION_QUEUEFLOW_ACTION_PTYPE |
부분 (PRIORITY/QUEUE) | QUEUE 지원 | 부분 | 부분 | QoS 큐 조정, 트래픽 분류 | net/sched/act_skbedit.c |
act_connmark |
(FLOW_ACTION_CT 간접) |
CT mark 간접 오프로드 | REG_C 메타데이터 | 미지원 | 미지원 | 정책 마크 전파, DPI 결과 영속화 | net/sched/act_connmark.c |
act_mpls |
FLOW_ACTION_MPLS_PUSHFLOW_ACTION_MPLS_POPFLOW_ACTION_MPLS_MANGLE |
예 (MPLS 지원 HW) | PUSH+POP 지원 | 미지원 | 미지원 | MPLS VPN 레이블 스위칭, 서비스 프로바이더 NGFW | net/sched/act_mpls.c |
Bridge/switchdev HW 오프로드 상세
리눅스 브리지(Bridge)는 switchdev 프레임워크를 통해 스위칭(Switching) 기능을 ASIC에 오프로드합니다.
switchdev는 브리지 코어가 발생시키는 이벤트(FDB 학습, VLAN 설정, MDB, STP 상태)를 드라이버에 전달하는
알림(Notification) 기반 API입니다. 드라이버는 switchdev_ops 콜백을 등록하여 이 이벤트를 ASIC에 프로그래밍합니다.
FDB 학습(Learning) 오프로드
브리지 FDB(Forwarding Database) 학습은 패킷의 소스 MAC 주소를 수신 포트와 연결하는 과정입니다.
switchdev가 활성화된 환경에서 ASIC이 FDB 학습을 직접 수행하고 소프트웨어 FDB에 동기화합니다.
커널 내부 흐름:
- ASIC이 새로운 소스 MAC을 학습하면 드라이버가
switchdev_handle_fdb_event_to_device()를 호출합니다. SWITCHDEV_FDB_ADD_TO_BRIDGE이벤트가 브리지 코어에 전달됩니다.- 브리지 코어가 소프트웨어 FDB에 항목을 추가하고
bridge fdb show에서offload플래그가 표시됩니다. - 반대로 브리지가 FDB 항목을 추가/삭제할 때는
SWITCHDEV_FDB_ADD_TO_DEVICE/DEL_TO_DEVICE이벤트로 ASIC에 전파합니다.
에이징(Aging) 타이머: ASIC 자체 에이징 타이머로 오래된 FDB 항목을 삭제하고,
SWITCHDEV_FDB_DEL_TO_BRIDGE로 소프트웨어 FDB도 갱신합니다.
브리지 에이징 시간(bridge link set dev eth0 ageing_time 3000)과 ASIC 에이징 타이머를 일치시켜야 합니다.
# bridge fdb show: offloaded 항목 확인
bridge fdb show dev eth0
# 출력 예시:
# aa:bb:cc:dd:ee:01 dev eth0 master br0 offload <-- ASIC이 학습/처리
# ff:ff:ff:ff:ff:ff dev eth0 self permanent <-- 소프트웨어 전용
# 정적 FDB 항목 추가 (ASIC에 직접 프로그래밍)
bridge fdb add aa:bb:cc:dd:ee:01 dev eth1 master
# → SWITCHDEV_FDB_ADD_TO_DEVICE 이벤트로 드라이버 전달
# → ASIC FDB 테이블에 MAC+VID → 포트 매핑 추가
/* net/switchdev/switchdev.c — FDB 이벤트 드라이버 전달 */
int switchdev_handle_fdb_event_to_device(
struct net_device *dev, unsigned long event,
const struct switchdev_notifier_fdb_info *fdb_info,
bool (*check_cb)(const struct net_device *dev),
int (*add_cb)(struct net_device *dev,
const unsigned char *addr, u16 vid,
bool added_by_user, bool offloaded,
extack),
int (*del_cb)(struct net_device *dev,
const unsigned char *addr, u16 vid,
bool added_by_user, bool offloaded,
extack))
{
/* SWITCHDEV_FDB_ADD_TO_DEVICE: ASIC FDB 테이블에 추가 */
/* SWITCHDEV_FDB_DEL_TO_DEVICE: ASIC FDB 테이블에서 삭제 */
switch (event) {
case SWITCHDEV_FDB_ADD_TO_DEVICE:
return add_cb(dev, fdb_info->addr, fdb_info->vid,
fdb_info->added_by_user, fdb_info->offloaded,
fdb_info->info.extack);
case SWITCHDEV_FDB_DEL_TO_DEVICE:
return del_cb(dev, fdb_info->addr, fdb_info->vid,
fdb_info->added_by_user, fdb_info->offloaded,
fdb_info->info.extack);
}
return 0;
}
VLAN 필터링(Filtering) 오프로드
브리지 VLAN 필터링은 포트별로 허용할 VLAN ID 집합을 정의합니다.
switchdev를 통해 ASIC의 포트별 VLAN 테이블에 직접 프로그래밍됩니다.
switchdev 객체 — SWITCHDEV_OBJ_ID_PORT_VLAN:
switchdev_port_obj_add() 콜백에서 SWITCHDEV_OBJ_ID_PORT_VLAN 객체를 받습니다.
switchdev_obj_port_vlan 구조체에 VLAN ID, 플래그(PVID, 언태그드)가 포함됩니다.
- PVID(Port VLAN ID): 태그 없는 패킷에 할당할 기본 VLAN ID
- 언태그드(Untagged): 이 VLAN 출력 시 태그를 제거하여 전송
- 트렁크 모드: 여러 VLAN ID를 허용하는 포트 설정
# VLAN 필터링 오프로드 설정
ip link add name br0 type bridge vlan_filtering 1
# eth0을 액세스 포트로: VLAN 100이 PVID, 언태그드
bridge vlan add vid 100 dev eth0 pvid untagged
# → SWITCHDEV_OBJ_ID_PORT_VLAN 객체로 드라이버 전달
# → ASIC VLAN 테이블: eth0 포트에 VID=100, PVID=yes, untagged=yes
# eth1을 트렁크 포트로: VLAN 100, 200 허용
bridge vlan add vid 100 dev eth1
bridge vlan add vid 200 dev eth1
# QinQ: S-VLAN 프로토콜 설정
ip link set br0 type bridge vlan_protocol 802.1ad
/* drivers/net/ethernet/mellanox/mlx5/core/en/port.c
SWITCHDEV_OBJ_ID_PORT_VLAN 처리 예시 */
int mlx5_sw_sp_port_obj_add(struct net_device *dev,
const struct switchdev_obj *obj,
struct netlink_ext_ack *extack)
{
switch (obj->id) {
case SWITCHDEV_OBJ_ID_PORT_VLAN: {
const struct switchdev_obj_port_vlan *vlan =
SWITCHDEV_OBJ_PORT_VLAN(obj);
/* ASIC VLAN 테이블에 VID 추가 */
return mlx5_sw_sp_port_vlan_add(mlx5_sw_sp_port,
vlan->vid,
vlan->flags); /* PVID | UNTAGGED */
}
case SWITCHDEV_OBJ_ID_PORT_MDB: {
/* MDB 처리 → 아래 절 참조 */
break;
}
}
return 0;
}
MDB(Multicast Database) 오프로드
MDB(Multicast Database)는 멀티캐스트 그룹 주소와 해당 그룹을 구독하는 포트의 매핑 테이블입니다. IGMP(Internet Group Management Protocol) 스누핑(Snooping)으로 학습된 MDB 항목이 ASIC에 오프로드되면 멀티캐스트 복제를 CPU 없이 ASIC에서 수행합니다.
switchdev 객체 — SWITCHDEV_OBJ_ID_PORT_MDB:
switchdev_obj_port_mdb 구조체에 멀티캐스트 그룹 MAC 주소(addr)와 VLAN ID(vid)가 포함됩니다.
드라이버는 ASIC의 멀티캐스트 포워딩 테이블에 그룹 주소와 포트 집합(Port Set)을 프로그래밍합니다.
NGFW 활용: 멀티캐스트 방화벽 정책을 적용하면서 멀티캐스트 복제를 ASIC에서 수행합니다. IPTV, 미디어 스트리밍 트래픽을 NGFW가 제어하는 환경에서 중요합니다.
# IGMP 스누핑 활성화 — MDB 자동 학습 후 ASIC 오프로드
ip link set br0 type bridge mcast_snooping 1
ip link set br0 type bridge mcast_querier 1
# 정적 MDB 항목 추가
bridge mdb add dev br0 port eth1 grp 239.1.1.1 vid 100
# → SWITCHDEV_OBJ_ID_PORT_MDB로 드라이버 전달
# → ASIC MDB 테이블: 239.1.1.1+VID100 → eth1
# MDB 확인
bridge mdb show dev br0
STP 상태(State) 오프로드
STP(Spanning Tree Protocol) 상태 — BLOCKING, LEARNING, FORWARDING — 를 ASIC 포트에 직접 설정합니다.
소프트웨어 STP 상태 머신(State Machine)이 상태를 전환하면 switchdev_port_attr_set()을 통해 ASIC에 반영됩니다.
switchdev 속성 — SWITCHDEV_ATTR_ID_PORT_STP_STATE:
switchdev_attr.u.stp_state에 BR_STATE_BLOCKING, BR_STATE_LISTENING,
BR_STATE_LEARNING, BR_STATE_FORWARDING, BR_STATE_DISABLED 값이 설정됩니다.
NGFW 활용: RSTP(Rapid STP) 토폴로지 변경 시 ASIC 포트 상태를 즉시 변경하여 패킷 손실을 최소화합니다. MLAG(Multi-Chassis Link Aggregation) 환경에서 정확한 포트 상태 동기화가 필요합니다.
/* net/bridge/br_stp_if.c — STP 상태 변경 시 ASIC 동기화 */
void br_set_state(struct net_bridge_port *p, unsigned int state)
{
struct switchdev_attr attr = {
.orig_dev = p->dev,
.id = SWITCHDEV_ATTR_ID_PORT_STP_STATE,
.u.stp_state = state,
};
p->state = state;
/* ASIC 포트 STP 상태 레지스터 업데이트 */
switchdev_port_attr_set(p->dev, &attr, NULL);
br_log_state(p);
}
이웃(Neighbor) 오프로드
ARP(Address Resolution Protocol)/NDP(Neighbor Discovery Protocol) 해석 결과를 ASIC의 이웃 캐시(Neighbor Cache)에 오프로드합니다. 라우팅 오프로드와 함께 사용하여 ASIC이 L3 패킷을 포워딩할 때 MAC 재작성(MAC Rewrite)을 HW에서 수행합니다.
이웃 오프로드 경로:
넷 코어가 ARP 해석 완료 시 NETEVENT_NEIGH_UPDATE 이벤트를 발생시키고,
드라이버는 이를 수신하여 ASIC 이웃 테이블에 IP → MAC 매핑을 추가합니다.
FDB 관점에서는 ndo_fdb_add()로 라우터 인터페이스(Router Interface)의 이웃 MAC을 등록합니다.
Bridge VXLAN 오프로드
VXLAN FDB와 브리지 FDB를 동기화하여 오버레이(Overlay) 네트워크에서 L2 스위칭을 ASIC이 처리하게 합니다.
동작 원리:
- VXLAN VTEP(VXLAN Tunnel Endpoint) 장치가 브리지에 멤버로 참여합니다.
- 원격 VTEP IP와 MAC이 VXLAN FDB에 등록됩니다 (
bridge fdb add또는 컨트롤 플레인 자동 학습). - 브리지 코어가 VXLAN FDB 항목을
SWITCHDEV_FDB_ADD_TO_DEVICE로 드라이버에 전달합니다. - 드라이버가 ASIC의 L2 터널 테이블에 MAC → VTEP IP + VNI 매핑을 프로그래밍합니다.
- ASIC이 이후 패킷에서 FDB 히트 → VXLAN 캡슐화 → 원격 VTEP 전송을 CPU 없이 처리합니다.
# VXLAN + 브리지 오프로드 설정
ip link add vxlan100 type vxlan id 100 \
local 192.168.1.1 dstport 4789 nolearning
ip link set vxlan100 master br0
ip link set vxlan100 up
# 원격 VTEP FDB 항목 추가 (ASIC에 터널 매핑 오프로드)
bridge fdb add 00:00:00:00:00:00 dev vxlan100 \
dst 192.168.1.2 vni 100 port 4789 self permanent
# → ASIC: VNI=100, 목적지 MAC 미지정 → 플러딩 → VTEP 192.168.1.2
# 특정 MAC의 원격 위치 등록
bridge fdb add aa:bb:cc:dd:ee:02 dev vxlan100 \
dst 192.168.1.3 self permanent
# → ASIC FDB: aa:bb:cc:dd:ee:02 → VXLAN 캡슐화 → 192.168.1.3
switchdev 객체 유형 종합표
| switchdev 객체/속성 유형 | 커널 콜백 | HW 리소스 | NGFW 활용 |
|---|---|---|---|
SWITCHDEV_FDB_ADD_TO_DEVICE |
switchdev_handle_fdb_event_to_device() |
ASIC FDB 테이블 (MAC+VID→포트) | L2 세그먼트 간 정책 적용, 스테이션 격리 |
SWITCHDEV_OBJ_ID_PORT_VLAN |
switchdev_port_obj_add() |
포트별 VLAN 허용 테이블, PVID/언태그드 설정 | VLAN 기반 마이크로 세그멘테이션, DMZ 격리 |
SWITCHDEV_OBJ_ID_PORT_MDB |
switchdev_port_obj_add() |
ASIC 멀티캐스트 포워딩 테이블 | 멀티캐스트 방화벽 정책, IPTV 제어 |
SWITCHDEV_ATTR_ID_PORT_STP_STATE |
switchdev_port_attr_set() |
포트 STP 상태 레지스터 (BLOCK/FWD/LEARN) | 루프 방지, RSTP 토폴로지 변경 시 무중단 전환 |
SWITCHDEV_OBJ_ID_HOST_MDB |
switchdev_port_obj_add() |
ASIC 호스트 멀티캐스트 엔트리 | 로컬 멀티캐스트 구독 관리 |
NETEVENT_NEIGH_UPDATE |
register_netevent_notifier() |
ASIC 이웃 캐시 (IP→MAC) | L3 포워딩 시 MAC 재작성, ARP 프록시 |
SWITCHDEV_VLAN_TUNNEL_INFO |
switchdev_port_obj_add() |
VLAN-VNI 매핑 테이블 | VXLAN 오버레이 NGFW, 터널 엔드포인트 관리 |
SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME |
switchdev_port_attr_set() |
ASIC 에이징 타이머 레지스터 | 단기 세션 빠른 FDB 정리, 메모리 효율화 |
FIB/Routing HW 오프로드
FIB(Forwarding Information Base) 오프로드는 리눅스 라우팅 테이블의 항목을 ASIC의 LPM(Longest Prefix Match) 테이블에 동기화하여
L3 패킷 포워딩을 CPU 없이 ASIC에서 처리하게 합니다.
fib_notifier 프레임워크가 라우팅 테이블 변경을 드라이버에 알리고,
드라이버는 ASIC의 라우팅 테이블을 실시간으로 갱신합니다.
FIB 오프로드 개요
fib_notifier는 리눅스 라우팅 테이블 변경을 구독자(드라이버)에게 알리는 알림 체인(Notifier Chain)입니다.
net/core/fib_notifier.c에 구현되어 있으며, IPv4(net/ipv4/fib_trie.c)와
IPv6(net/ipv6/ip6_fib.c) 모두 동일한 인터페이스를 사용합니다.
FIB 이벤트 유형:
FIB_EVENT_ENTRY_REPLACE: 새 경로 추가 또는 기존 경로 교체. ASIC LPM 테이블에 새 항목 추가FIB_EVENT_ENTRY_DELETE: 경로 삭제. ASIC LPM 테이블에서 항목 제거FIB_EVENT_ENTRY_APPEND: ECMP 그룹에 경로 추가. ASIC ECMP 해시 테이블 멤버 추가FIB_EVENT_NH_ADD/FIB_EVENT_NH_DEL: 멀티경로 그룹 내 넥스트홉(Nexthop) 변경FIB_EVENT_RULE_ADD/FIB_EVENT_RULE_DEL: 정책 라우팅(Policy Routing) 규칙 변경
fib_notifier_info 구조: 이벤트 데이터에는 목적지 프리픽스(dst, dst_len),
넥스트홉 정보(nh), 라우팅 테이블 ID(tb_id), TOS 등이 포함됩니다.
/* net/ipv4/fib_trie.c — fib_notifier 등록 및 이벤트 발생 */
/* 드라이버가 fib_notifier를 등록하는 방법 */
static struct notifier_block mlx5_fib_nb = {
.notifier_call = mlx5_router_fib_event,
};
int mlx5_router_init(struct mlx5_core_dev *mdev)
{
/* FIB 변경 알림 구독 */
return register_fib_notifier(dev_net(mdev->pdev->dev),
&mlx5_fib_nb,
mlx5_fib_notifier_dump, /* 초기 덤프 콜백 */
NULL);
}
/* FIB 이벤트 처리 콜백 */
static int mlx5_router_fib_event(struct notifier_block *nb,
unsigned long event, void *ptr)
{
struct fib_notifier_info *info = ptr;
switch (event) {
case FIB_EVENT_ENTRY_REPLACE:
case FIB_EVENT_ENTRY_APPEND: {
struct fib_entry_notifier_info *fen_info =
container_of(info, struct fib_entry_notifier_info, info);
/* ASIC LPM 테이블에 경로 추가 */
mlx5_router_fib4_add(router, fen_info);
break;
}
case FIB_EVENT_ENTRY_DELETE: {
struct fib_entry_notifier_info *fen_info =
container_of(info, struct fib_entry_notifier_info, info);
/* ASIC LPM 테이블에서 경로 삭제 */
mlx5_router_fib4_del(router, fen_info);
break;
}
case FIB_EVENT_NH_ADD:
case FIB_EVENT_NH_DEL: {
/* 멀티경로 넥스트홉 그룹 갱신 */
mlx5_router_nexthop_update(router, event, info);
break;
}
}
return NOTIFY_DONE;
}
넥스트홉(Nexthop) 오프로드
리눅스 커널 5.1부터 독립적인 넥스트홉(Nexthop) 객체 시스템이 도입되었습니다(net/ipv4/nexthop.c).
여러 경로가 동일한 넥스트홉 그룹을 참조할 수 있어, ASIC 넥스트홉 테이블 항목 수를 효율적으로 관리합니다.
nexthop_notifier 이벤트:
NEXTHOP_EVENT_REPLACE: 넥스트홉 객체 생성 또는 교체. ASIC 넥스트홉 테이블에 IP + 이그레스 포트 + MAC 재작성 정보 추가NEXTHOP_EVENT_DEL: 넥스트홉 객체 삭제. ASIC에서 항목 제거
ECMP(Equal-Cost Multi-Path) 해시: 넥스트홉 그룹에 여러 멤버가 있으면 ASIC은 ECMP 해시 테이블을 구성합니다. 해시 키는 소스 IP, 목적지 IP, 포트, 프로토콜로 구성되며, 해시 결과로 출력 포트가 결정됩니다. mlx5는 해시 알고리즘(CRC32, XOR)과 해시 필드를 드라이버에서 선택할 수 있습니다.
# 독립적인 넥스트홉 객체 생성
ip nexthop add id 1 via 192.168.1.1 dev eth0
ip nexthop add id 2 via 192.168.1.2 dev eth0
# → NEXTHOP_EVENT_REPLACE × 2 → ASIC 넥스트홉 테이블 항목 추가
# ECMP 넥스트홉 그룹 (2개 경로 동일 비용)
ip nexthop add id 100 group 1/2
# → ASIC ECMP 해시 테이블: 그룹 ID 100 → [NH1, NH2]
# ECMP 그룹으로 경로 등록
ip route add 10.0.0.0/8 nhid 100
# → FIB_EVENT_ENTRY_REPLACE → ASIC LPM: 10.0.0.0/8 → ECMP 그룹 100
# 비율 기반 ECMP (weighted)
ip nexthop add id 200 group 1,weight=3/2,weight=1
# → ASIC 해시 테이블 버킷 배분: NH1 = 75%, NH2 = 25%
/* net/ipv4/nexthop.c — nexthop_notifier 이벤트 발생 경로 */
static int nexthop_add(struct net *net, struct nlattr *tb[],
struct nexthop *nh,
struct netlink_ext_ack *extack)
{
int err;
err = nh_fill_node(net, nh, tb, extack);
if (err)
return err;
/* 넥스트홉 생성 후 알림 체인에 이벤트 발생 */
err = call_nexthop_notifiers(net, NEXTHOP_EVENT_REPLACE, nh, extack);
if (err) {
nexthop_put(nh);
return err;
}
return 0;
}
FIB 오프로드와 NGFW
라우팅 NGFW(Routed NGFW) 환경에서 FIB 오프로드는 L3 포워딩 성능을 결정하는 핵심 요소입니다.
L3 포워딩 오프로드 전체 파이프라인:
- ASIC 수신 포트에서 패킷 도착
- ASIC LPM 테이블에서 목적지 IP 매칭 → 넥스트홉 ID 확인
- 넥스트홉 테이블에서 출력 포트 + 재작성할 목적지/소스 MAC 주소 조회
- ECMP 그룹이면 해시 계산으로 넥스트홉 선택
- 패킷 헤더 수정: 목적지 MAC 교체, 소스 MAC 교체, TTL 감소, IP 체크섬 재계산
- 출력 포트로 패킷 전송 — CPU 개입 없음
정책 라우팅(Policy Routing) 제한:
ip rule로 설정하는 정책 라우팅(VRF 기반 라우팅, DSCP 기반 테이블 선택)은
일부 ASIC에서만 오프로드를 지원합니다. mlx5는 VRF 기반 정책 라우팅 오프로드를 지원하며,
각 VRF가 별도의 ASIC 라우팅 인스턴스(Virtual Router)로 매핑됩니다.
DSCP 기반 멀티 테이블 선택은 대부분의 ASIC에서 오프로드가 어렵고 소프트웨어 폴백이 발생합니다.
NAT와 FIB 오프로드 결합:
TC flower + act_ct(NAT) + FIB 오프로드를 결합하면 NAT 후 라우팅 결정까지 ASIC에서 처리합니다.
mlx5 eSwitch 환경에서 TC_REDIRECT_NEIGH 플래그를 사용하면 TC action이 이웃 테이블을 참조하여
MAC 재작성과 포워딩을 한 번에 처리합니다.
이웃(Neighbor)/ARP 오프로드
L3 FIB 오프로드의 마지막 퍼즐은 목적지 IP에 대한 MAC 주소 해석입니다.
ARP/NDP 해석이 완료되면 이웃 테이블이 갱신되고, 드라이버는 NETEVENT_NEIGH_UPDATE를 수신하여
ASIC의 이웃 캐시를 갱신합니다.
이웃 오프로드 시나리오:
- ARP 해석 완료:
NETEVENT_NEIGH_UPDATE→ 드라이버 → ASIC 이웃 캐시에 IP → MAC 추가 → FIB 포워딩 활성화 - ARP 만료:
NETEVENT_NEIGH_UPDATE(NUD_FAILED) → ASIC 이웃 캐시에서 항목 무효화 → 해당 넥스트홉 ASIC 오프로드 비활성화 → CPU 처리로 폴백 - ARP 프로브(Probe): 만료 직전 ARP 재확인 중에도 ASIC이 기존 항목으로 계속 포워딩 → 재확인 완료 후 갱신
/* drivers/net/ethernet/mellanox/mlx5/core/lib/roce.c
이웃 갱신 이벤트 처리 — ASIC 이웃 캐시 갱신 */
static int mlx5_netdev_notifier_handler(struct notifier_block *nb,
unsigned long event, void *ptr)
{
struct netevent_notify *n;
switch (event) {
case NETEVENT_NEIGH_UPDATE: {
struct neighbour *neigh = ptr;
if (neigh->nud_state & NUD_VALID) {
/* 유효한 이웃: ASIC 이웃 캐시에 IP→MAC 추가 */
mlx5_add_neigh(dev, neigh->primary_key, neigh->ha);
} else {
/* 무효화: ASIC 이웃 캐시에서 제거 */
mlx5_del_neigh(dev, neigh->primary_key);
}
break;
}
}
return NOTIFY_DONE;
}
# FIB/넥스트홉/이웃 오프로드 상태 확인
# 오프로드된 경로 확인 (rt_offload 플래그)
ip route show | grep offload
# 10.0.0.0/8 via 192.168.1.1 dev eth0 offload ← ASIC에서 처리
# 이웃 테이블 확인 (오프로드 상태)
ip neigh show
# 192.168.1.1 dev eth0 lladdr aa:bb:cc:dd:ee:01 offload REACHABLE
# 넥스트홉 오프로드 상태
ip nexthop show
# id 1 via 192.168.1.1 dev eth0 scope link offload
# IPv6 FIB 오프로드 (동일 메커니즘, net/ipv6/ip6_fib.c)
ip -6 route show | grep offload
FIB 이벤트 유형 종합표
| FIB 이벤트 유형 | 트리거 조건 | HW 동작 | NGFW 영향 |
|---|---|---|---|
FIB_EVENT_ENTRY_REPLACE |
ip route add/replace, BGP 경로 수신, 정적 경로 설정 |
ASIC LPM 테이블에 Prefix → NexthopID 항목 추가/교체 | 새 목적지 네트워크로의 L3 포워딩 활성화. 경로 플랩(Flap) 시 일시적 오프로드 해제 |
FIB_EVENT_ENTRY_DELETE |
ip route del, BGP Withdraw, 인터페이스 다운 |
ASIC LPM 테이블에서 항목 제거. 관련 ECMP 멤버 정리 | 삭제된 경로의 트래픽이 CPU로 폴백 또는 드롭. NGFW 정책 재평가 필요 |
FIB_EVENT_ENTRY_APPEND |
동일 Prefix에 ECMP 경로 추가 (ip route append) |
ASIC ECMP 해시 테이블에 멤버 추가. 버킷 재배분 | 부하 분산(Load Balancing) 개선. NGFW가 다중 경로 모니터링 필요 |
NEXTHOP_EVENT_REPLACE |
ip nexthop add/replace, 독립 넥스트홉 객체 생성 |
ASIC 넥스트홉 테이블에 ID → 포트+MAC 항목 추가 | 공유 넥스트홉 효율 — 여러 경로가 단일 ASIC 넥스트홉 항목 공유 |
NEXTHOP_EVENT_DEL |
ip nexthop del, 참조 경로 삭제 |
ASIC 넥스트홉 테이블에서 항목 제거. 참조 LPM 항목도 무효화 | 넥스트홉 삭제 시 연관된 모든 경로 오프로드 해제. NGFW 가용성 영향 |
NETEVENT_NEIGH_UPDATE (유효) |
ARP/NDP 해석 완료, NUD_REACHABLE/STALE → 갱신 | ASIC 이웃 캐시에 IP → MAC 추가. 넥스트홉 포워딩 활성화 | 게이트웨이 MAC 변경 시 ASIC 즉시 갱신 — MAC 스푸핑 방지 연동 필요 |
NETEVENT_NEIGH_UPDATE (무효) |
ARP 만료, NUD_FAILED, 인터페이스 다운 | ASIC 이웃 캐시 항목 무효화. 해당 넥스트홉 오프로드 비활성화 | 이웃 만료 시 일시적 CPU 처리. NGFW 처리량 감소. ARP 타이머 조정 필요 |
FIB_EVENT_RULE_ADD |
ip rule add, 정책 라우팅 규칙 추가 |
ASIC Virtual Router 인스턴스 추가 (지원 시). 미지원 시 소프트웨어 폴백 | VRF 기반 NGFW 구성 시 테이블별 오프로드 가능 여부 확인 필수 |
Tunnel encap/decap HW 오프로드 상세
터널(Tunnel) HW 오프로드는 VXLAN·GRE·Geneve 등의 오버레이(Overlay) 터널을 NIC ASIC에서 직접 캡슐화(Encapsulation)·역캡슐화(Decapsulation)하여 CPU 개입 없이 처리하는 기술입니다. NGFW 환경에서 East-West 마이크로 세그멘테이션(Micro-segmentation), 데이터센터 간 VPN 터널, 클라우드 오버레이 네트워크의 패킷을 HW에서 직접 검사하고 전달할 수 있어 처리량이 극적으로 향상됩니다.
VXLAN HW 오프로드
VXLAN(Virtual eXtensible LAN) HW 오프로드는 UDP 포트 4789를 통해 L2 프레임을 UDP로 캡슐화·역캡슐화하는 과정을 NIC에서 수행합니다. Linux 커널은 udp_tunnel_nic_info 구조체와 ndo_udp_tunnel_add()/ndo_udp_tunnel_del() 콜백을 통해 드라이버에 터널 포트를 등록합니다.
/* VXLAN UDP 터널 포트 등록 — net/ipv4/udp_tunnel_nic.c */
struct udp_tunnel_nic_info {
int (*set_port)(struct net_device *dev,
unsigned int table, unsigned int entry,
struct udp_tunnel_info *ti);
int (*unset_port)(struct net_device *dev,
unsigned int table, unsigned int entry,
struct udp_tunnel_info *ti);
int (*sync_table)(struct net_device *dev, unsigned int table);
unsigned int flags;
struct udp_tunnel_nic_table tables[UDP_TUNNEL_NIC_MAX_TABLES];
};
/* 드라이버 등록 예시 — mlx5 드라이버 */
static const struct udp_tunnel_nic_info mlx5e_udp_tunnels = {
.set_port = mlx5e_udp_tunnel_set_port,
.unset_port = mlx5e_udp_tunnel_unset_port,
.sync_table = mlx5e_udp_tunnel_sync_table,
.tables = {
{
.n_entries = 8, /* 최대 8개 UDP 터널 포트 */
.tunnel_types = UDP_TUNNEL_TYPE_VXLAN |
UDP_TUNNEL_TYPE_VXLAN_GPE,
},
{
.n_entries = 4,
.tunnel_types = UDP_TUNNEL_TYPE_GENEVE,
},
},
};
/* tunnel_key_act_to_flow_act() — TC action → flow_action 변환 */
int tunnel_key_act_to_flow_act(struct tc_action *act,
struct flow_action_entry *entry,
struct netlink_ext_ack *extack)
{
struct tcf_tunnel_key_params *params = rcu_dereference(act->params);
if (params->tcft_action == TCA_TUNNEL_KEY_ACT_SET) {
entry->id = FLOW_ACTION_TUNNEL_ENCAP;
entry->tunnel = params->tcft_enc_metadata;
/* ASIC에서 outer IP/UDP/VXLAN 헤더를 prepend */
} else { /* TCA_TUNNEL_KEY_ACT_RELEASE */
entry->id = FLOW_ACTION_TUNNEL_DECAP;
/* ASIC에서 outer 헤더를 strip하고 inner 패킷 노출 */
}
return 0;
}
VXLAN TX 오프로드를 위해 NIC는 NETIF_F_GSO_UDP_TUNNEL 및 NETIF_F_GSO_UDP_TUNNEL_CSUM 피처 플래그를 제공해야 합니다. 이 플래그는 TSO(TCP Segmentation Offload)의 터널 버전으로, 큰 inner TCP 세그먼트를 NIC에서 분할하면서 outer UDP/VXLAN 헤더를 각 세그먼트에 자동으로 추가합니다.
# VXLAN GSO 오프로드 기능 확인
ethtool -k eth0 | grep -E "tx-udp_tnl"
# tx-udp_tnl-segmentation: on
# tx-udp_tnl-csum-segmentation: on
# VXLAN FDB 오프로드 확인 — switchdev 드라이버
bridge fdb show dev vxlan0 | grep offload
# 00:11:22:33:44:55 dev vxlan0 dst 192.168.1.2 self offload
# VXLAN outer 헤더 매칭 + inner 5-tuple 동시 매칭
tc filter add dev eth0 ingress protocol ip flower \
enc_dst_ip 192.168.1.1 enc_src_ip 192.168.1.2 \
enc_key_id 100 enc_dst_port 4789 \
ip_proto tcp \
dst_ip 10.0.0.5 dst_port 443 \
action tunnel_key release \
action ct nat action goto chain 1
GRE HW 오프로드
GRE(Generic Routing Encapsulation) HW 오프로드는 IP-over-GRE, GRE-over-UDP, ERSPAN(Encapsulated Remote SPAN) 등 다양한 GRE 변형을 NIC에서 처리합니다. GRE는 VXLAN과 달리 UDP를 사용하지 않으므로 별도의 UDP 포트 등록 과정이 없으며, IP 프로토콜 번호 47로 식별됩니다.
/* GRE GSO 피처 플래그 — include/linux/netdev_features.h */
NETIF_F_GSO_GRE /* GRE 패킷의 GSO 오프로드 */
NETIF_F_GSO_GRE_CSUM /* GRE 헤더 체크섬 포함 GSO */
/* ERSPAN HW 오프로드 — mlx5 예시 */
static int mlx5e_rep_setup_tc_cls_flower(struct mlx5e_priv *priv,
struct flow_cls_offload *cls_flower,
int flags)
{
struct flow_rule *rule = flow_cls_offload_flow_rule(cls_flower);
struct flow_action_entry *act;
int i;
flow_action_for_each(i, act, &rule->action) {
switch (act->id) {
case FLOW_ACTION_TUNNEL_ENCAP:
/* ERSPAN Type II/III 헤더 생성 */
mlx5e_tc_tun_create_header_ipv4(priv, act->tunnel);
break;
case FLOW_ACTION_TUNNEL_DECAP:
/* GRE outer 헤더 제거 후 inner 패킷 처리 */
mlx5e_tc_tun_parse_gre(act, spec, attr);
break;
}
}
return mlx5e_tc_offload_flow(priv, rule, attr);
}
Geneve HW 오프로드
Geneve(Generic Network Virtualization Encapsulation)는 VXLAN과 동일한 UDP 기반이지만, 가변 길이 TLV(Type-Length-Value) 옵션 헤더를 지원하여 더 풍부한 메타데이터를 전달할 수 있습니다. NGFW 환경에서 Geneve 옵션은 보안 태그(Security Tag), 정책 ID, 테넌트(Tenant) 정보를 전달하는 데 사용됩니다.
/* Geneve TLV 옵션 매칭 — TC flower key */
/* tc filter add dev eth0 ingress protocol ip flower \
enc_dst_ip 192.168.1.1 enc_dst_port 6081 \
enc_opts.geneve type 0x0001 class 0x0102 data 0x12345678 \
action tunnel_key release action goto chain 2 */
struct flow_dissector_key_enc_opts {
u8 data[FLOW_DIS_TUN_OPTS_MAX]; /* 최대 255바이트 TLV 데이터 */
u8 len;
__be16 dst_opt_type; /* 옵션 클래스 */
};
/* Geneve vs VXLAN 오프로드 차이:
* VXLAN: 고정 8바이트 헤더, VNI 24비트, UDP 포트 4789
* Geneve: 가변 헤더, VNI 24비트, TLV 옵션, UDP 포트 6081
* Geneve TLV 매칭은 ASIC TCAM에서 추가 비용 발생
* mlx5는 Geneve TLV 최대 4개 동시 매칭 지원 */
/* Tunnel metadata mode — OVS와의 연동 */
struct metadata_dst {
union {
struct ip_tunnel_info tun_info; /* 터널 키/플래그 */
struct hw_port_info port_info;
} u;
enum metadata_type type;
};
Inner Header 매칭
Inner header 매칭은 터널로 캡슐화된 패킷의 outer 헤더와 inner 헤더를 동시에 매칭하는 기능입니다. NGFW에서 이를 통해 특정 테넌트(VXLAN VNI)에서 오는 특정 플로우(inner 5-tuple)만을 선택적으로 검사하거나 차단할 수 있습니다. TCAM 자원 측면에서 outer+inner 동시 매칭은 단일 매칭의 약 2배 엔트리를 소비합니다.
# outer + inner 동시 매칭 예시
tc filter add dev eth0 ingress protocol ip flower \
enc_src_ip 192.168.1.0/24 \ # outer src IP (VTEP)
enc_dst_ip 192.168.1.100 \ # outer dst IP (local VTEP)
enc_key_id 1000 \ # VNI 1000
enc_dst_port 4789 \ # VXLAN UDP 포트
ip_proto tcp \ # inner IP 프로토콜
src_ip 10.0.0.0/8 \ # inner src IP
dst_ip 172.16.0.5 \ # inner dst IP
dst_port 443 \ # inner dst 포트 (HTTPS)
action drop # 악성 트래픽 차단
Tunnel 오프로드와 NGFW 파이프라인
오버레이 보안 검사 시나리오에서 NGFW는 터널을 종단(Terminate)하고 inner 패킷을 검사한 후 다시 캡슐화하여 전송합니다. HW 오프로드가 적용되면 첫 패킷 검사 후 확립된 세션은 NIC에서 자동으로 decap → inner 헤더 매칭 → 정책 적용 → encap 과정을 수행합니다.
| 터널 유형 | Encap 오프로드 | Decap 오프로드 | Inner 매칭 | GSO 피처 플래그 | 대표 NIC |
|---|---|---|---|---|---|
| VXLAN | 지원 | 지원 | 5-tuple + VNI | NETIF_F_GSO_UDP_TUNNEL, _CSUM |
mlx5, ice, bnxt, i40e |
| GRE | 지원 | 지원 | 5-tuple + key | NETIF_F_GSO_GRE, _CSUM |
mlx5, i40e |
| ERSPAN v2 | 지원 (미러링) | 부분 지원 | 제한적 | NETIF_F_GSO_GRE |
mlx5 |
| Geneve | 지원 | 지원 | 5-tuple + VNI + TLV | NETIF_F_GSO_UDP_TUNNEL |
mlx5, ice |
| VXLAN-GPE | 지원 | 지원 | 5-tuple + VNI | NETIF_F_GSO_UDP_TUNNEL |
mlx5 |
| IP-in-IP | 지원 | 지원 | inner 5-tuple | NETIF_F_GSO_IPXIP4 |
mlx5, bnxt |
| STT | 부분 지원 | 미지원 | 미지원 | — | OVS 소프트웨어만 |
LAG/Bond HW 오프로드
LAG(Link Aggregation Group)/Bond HW 오프로드는 복수의 물리 포트를 하나의 논리 인터페이스로 묶어 대역폭 확장과 고가용성을 제공하는 기능을 NIC ASIC에서 직접 처리합니다. NGFW 환경에서 LAG는 방화벽 앞단의 업링크(Uplink) 이중화에 주로 사용되며, eSwitch(Embedded Switch)와 결합하면 TC flower 규칙을 LAG 멤버 포트 전체에 팬아웃(Fan-out)할 수 있습니다.
Bonding과 eSwitch
switchdev 모델에서 bond/team 디바이스는 상위(Upper) 인터페이스로 동작하며, 각 물리 포트의 representor가 하위(Lower) 인터페이스로 연결됩니다. 커널은 NETDEV_CHANGEUPPER 이벤트를 통해 드라이버에 LAG 구성 변경을 통보합니다.
/* LAG 상위 이벤트 처리 — drivers/net/bonding/bond_main.c */
static int bond_netdev_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
struct net_device *event_dev = netdev_notifier_info_to_dev(ptr);
switch (event) {
case NETDEV_CHANGEUPPER: {
struct netdev_notifier_changeupper_info *info = ptr;
struct net_device *upper = info->upper_dev;
if (netif_is_bond_master(upper)) {
/* LAG 멤버 추가/제거 시 eSwitch 통보 */
mlx5_lag_changeupper_notify(upper, event_dev,
info->linking);
}
break;
}
case NETDEV_BONDING_INFO: {
struct netdev_bonding_info *bonding_info = ptr;
/* LACP actor/partner 상태 업데이트 */
mlx5_lag_bonding_update(event_dev, bonding_info);
break;
}
}
return NOTIFY_DONE;
}
/* eSwitch LAG 설정 */
static int mlx5_lag_set_active_port_selection(struct mlx5_lag *ldev,
u8 *ports)
{
struct lag_upper_info lag_upper_info = {
.tx_type = NETDEV_LAG_TX_TYPE_HASH, /* LACP 또는 hash 모드 */
.hash_type = NETDEV_LAG_HASH_L34, /* L3+L4 해시 */
};
return mlx5_esw_modify_vport_tir(ldev->pf[0].dev, ports,
&lag_upper_info);
}
LACP HW 오프로드
LACP(Link Aggregation Control Protocol) PDU는 멀티캐스트 MAC 주소(01:80:C2:00:00:02)로 전송되며, NIC ASIC이 이를 직접 처리하면 CPU 개입 없이 포트 선택과 액터(Actor)/파트너(Partner) 상태 관리를 수행할 수 있습니다. 이는 LACP PDU 전송 주기(Fast: 1초, Slow: 30초)에 따른 CPU 인터럽트를 완전히 제거합니다.
# bond 디바이스 생성 및 LACP 설정
ip link add bond0 type bond
ip link set bond0 type bond mode 802.3ad # LACP 모드
ip link set bond0 type bond lacp_rate fast # Fast LACP (1초)
ip link set bond0 type bond xmit_hash_policy layer3+4
# representor를 bond에 추가 — eSwitch LAG 오프로드 트리거
ip link set eth0_repr master bond0
ip link set eth1_repr master bond0
# LACP 상태 확인
cat /proc/net/bonding/bond0 | head -20
# Bonding Mode: IEEE 802.3ad Dynamic link aggregation
# Transmit Hash Policy: layer3+4 (1)
# LACP rate: fast
LAG Hash 오프로드
xmit_hash_policy(전송 해시 정책)를 NIC ASIC에서 수행하면 소프트웨어 해시 계산 없이 패킷을 멤버 포트에 분산할 수 있습니다. NGFW 환경에서는 대칭 해시(Symmetric Hash)가 중요한데, 이는 forward 방향과 return 방향 패킷이 반드시 같은 멤버 포트로 전달되어야 세션 추적이 올바르게 동작하기 때문입니다.
/* LAG 해시 타입 — include/net/lag.h */
enum netdev_lag_hash {
NETDEV_LAG_HASH_NONE,
NETDEV_LAG_HASH_L2, /* MAC 주소 기반 */
NETDEV_LAG_HASH_L34, /* IP+포트 기반 */
NETDEV_LAG_HASH_L23, /* MAC+IP 기반 */
NETDEV_LAG_HASH_E23, /* Encap MAC+IP */
NETDEV_LAG_HASH_E34, /* Encap IP+포트 */
NETDEV_LAG_HASH_VLAN_SRCMAC, /* VLAN+src MAC */
NETDEV_LAG_HASH_UNKNOWN,
};
/* 대칭 해시:
* forward: 192.168.1.1:1234 → 10.0.0.1:80 → port0
* return: 10.0.0.1:80 → 192.168.1.1:1234 → port0 (동일 포트)
* XOR(srcIP, dstIP) 및 XOR(srcPort, dstPort) 사용 */
TC flower on bond 디바이스
bond 마스터 디바이스에 TC flower 규칙을 설치하면 드라이버가 이 규칙을 모든 멤버 포트의 eSwitch에 동시에 팬아웃합니다. 공유 블록(Shared Block) 메커니즘을 사용하면 하나의 TC qdisc block을 여러 인터페이스에서 공유할 수 있어 규칙 중복을 방지합니다.
# bond0에 shared block 기반 TC ingress 설정
tc qdisc add dev bond0 ingress_block 1 clsact
tc qdisc add dev eth0_repr ingress_block 1 clsact # 같은 블록 공유
tc qdisc add dev eth1_repr ingress_block 1 clsact
# bond0에 규칙 추가 → eth0_repr, eth1_repr 양쪽에 자동 설치
tc filter add block 1 ingress protocol ip flower \
dst_ip 10.0.0.0/8 \
action drop
# HW 오프로드 확인 — in_hw_count 2 = 2개 포트 모두 설치
tc filter show block 1 ingress | grep in_hw
# ... in_hw in_hw_count 2
Bond Failover와 Offload
멤버 포트 링크 장애 발생 시 bond 드라이버는 장애 포트를 제거하고 나머지 포트로 트래픽을 재분산합니다. eSwitch LAG 오프로드 규칙도 원자적(Atomic)으로 업데이트되어 패킷 손실을 최소화합니다.
/* 링크 장애 처리 — bond_main.c */
static void bond_handle_link_change(struct bonding *bond,
struct slave *slave,
char link)
{
if (link == BOND_LINK_DOWN) {
bond_set_slave_link_state(slave, BOND_LINK_DOWN,
BOND_SLAVE_NOTIFY_NOW);
/* eSwitch LAG 포트 제거 → 나머지 포트로 규칙 마이그레이션 */
mlx5_lag_remove_slave(slave->dev);
bond_select_active_slave(bond);
}
}
TC chain/goto 멀티스테이지 HW 파이프라인
TC(Traffic Control) chain은 단일 TC 인스턴스에서 여러 단계의 분류·처리 파이프라인을 구성하는 메커니즘입니다. 기본 chain 0에서 패킷이 매칭되면 goto chain N 액션을 통해 다음 단계로 이동할 수 있으며, 각 chain은 서로 다른 매칭 필드와 액션 집합을 정의할 수 있습니다. HW 오프로드가 지원되는 경우 전체 파이프라인이 NIC ASIC의 멀티 테이블 TCAM에서 처리됩니다.
Chain 개념
chain 0은 기본 체인으로 모든 패킷이 처음 처리됩니다. goto chain N 액션은 패킷을 chain N의 첫 번째 규칙으로 즉시 이동시키며, chain N에서 매칭 실패 시 패킷은 드롭됩니다. 각 chain은 독립적인 TCAM 테이블로 매핑되므로 서로 다른 매칭 필드를 효율적으로 사용할 수 있습니다.
# chain 0: 프리필터 — IP 프로토콜 식별 후 chain 1으로 이동
tc filter add dev eth0 ingress protocol ip chain 0 flower \
ip_proto tcp \
action goto chain 1
tc filter add dev eth0 ingress protocol ip chain 0 flower \
ip_proto udp \
action goto chain 1
# chain 0 기본: 매칭 안되면 드롭
tc filter add dev eth0 ingress chain 0 matchall \
action drop
# chain 1: conntrack 상태 검사
tc filter add dev eth0 ingress protocol ip chain 1 flower \
ct_state +est+trk \
action goto chain 3 # established → chain 3 (ACL)
tc filter add dev eth0 ingress protocol ip chain 1 flower \
ct_state +new+trk \
action ct commit \
action goto chain 2 # new → chain 2 (연결 허용 판단)
HW Chain 오프로드
TC_SETUP_CLSFLOWER와 함께 chain_index 필드를 통해 드라이버에 chain 번호가 전달됩니다. 드라이버는 각 chain을 NIC 하드웨어의 별도 플로우 테이블로 매핑하며, goto chain 액션은 플로우 테이블 간 포인터로 구현됩니다.
/* TC flower offload 구조체 — include/net/flow_offload.h */
struct flow_cls_offload {
enum flow_cls_command command; /* REPLACE/DESTROY/STATS */
u32 classid;
u32 chain_index; /* chain 번호 */
unsigned long cookie;
struct flow_stats stats;
u8 use_act_stats;
};
/* 드라이버 chain → 플로우 테이블 매핑 */
static int mlx5e_tc_get_flow_table(struct mlx5e_priv *priv,
u32 chain_index,
struct mlx5_flow_table **ft)
{
struct mlx5_chain_info *chain_info;
chain_info = rhashtable_lookup_fast(&priv->tc_chains,
&chain_index,
mlx5_tc_chain_params);
if (!chain_info) {
/* 새 chain → 새 ASIC 플로우 테이블 할당 */
chain_info = mlx5_create_chain_flow_table(priv, chain_index);
}
*ft = chain_info->ft;
return 0;
}
/* goto chain 액션 처리 */
case FLOW_ACTION_GOTO:
dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
dest.ft = chain_info->ft; /* 다음 테이블 포인터 */
break;
Chain Template
Chain template은 TC chain이 실제 규칙 설치 이전에 사용할 매칭 필드를 미리 선언하여 TCAM 자원 할당을 최적화하는 기능입니다. 동일한 필드를 사용하는 규칙들을 같은 TCAM 테이블에 배치하여 리소스 단편화를 방지합니다.
# chain template 선언 — chain 2의 매칭 필드를 미리 정의
tc chain add dev eth0 ingress chain 2 \
flower \
ip_proto tcp \
src_ip 0.0.0.0/0 \
dst_ip 0.0.0.0/0 \
src_port 0 \
dst_port 0
# 실제 규칙 설치 — template과 동일한 필드 사용
tc filter add dev eth0 ingress protocol ip chain 2 flower \
ip_proto tcp dst_port 22 \
action drop
tc filter add dev eth0 ingress protocol ip chain 2 flower \
ip_proto tcp dst_port 443 \
action goto chain 3
# chain template 확인
tc chain show dev eth0 ingress
# chain 0
# chain 1
# chain 2 flower template
NGFW 멀티스테이지 설계
실제 NGFW 파이프라인에서는 TC chain을 다음과 같이 단계별로 설계합니다. 각 chain은 특정 보안 기능에 집중하며, 이전 chain의 결정을 다음 chain이 상속합니다.
## NGFW 멀티스테이지 TC 파이프라인 전체 예시
# Chain 0: Pre-filter (L2/L3 필터링)
tc filter add dev eth0 ingress protocol arp chain 0 matchall \
action mirred egress redirect dev eth1 # ARP 통과
tc filter add dev eth0 ingress protocol 0x0800 chain 0 matchall \
action goto chain 1 # IPv4 → conntrack
tc filter add dev eth0 ingress chain 0 matchall \
action drop
# Chain 1: Conntrack 상태 추적
tc filter add dev eth0 ingress protocol ip chain 1 flower \
ct_state -trk \
action ct action goto chain 1 # 추적 후 재진입
tc filter add dev eth0 ingress protocol ip chain 1 flower \
ct_state +inv \
action drop
tc filter add dev eth0 ingress protocol ip chain 1 flower \
ct_state +est+trk \
action goto chain 3 # established → ACL
tc filter add dev eth0 ingress protocol ip chain 1 flower \
ct_state +new+trk \
action goto chain 2 # new → 정책 판단
# Chain 2: ACL (신규 연결 허용 정책)
tc filter add dev eth0 ingress protocol ip chain 2 flower \
src_ip 10.0.0.0/8 dst_port 443 ip_proto tcp \
action ct commit \
action goto chain 4 # 허용 후 NAT
tc filter add dev eth0 ingress chain 2 matchall \
action drop
# Chain 3: ACL (established 세션 Fast Path)
tc filter add dev eth0 ingress protocol ip chain 3 flower \
ct_state +est \
action goto chain 4
# Chain 4: NAT (주소 변환)
tc filter add dev eth0 ingress protocol ip chain 4 flower \
ct_zone 0 \
action ct nat src addr 10.0.0.1 \
action goto chain 5
# Chain 5: QoS (트래픽 쉐이핑)
tc filter add dev eth0 ingress protocol ip chain 5 flower \
dst_port 443 \
action police rate 100mbit burst 1mb \
action mirred egress redirect dev eth1
tc filter add dev eth0 ingress chain 5 matchall \
action mirred egress redirect dev eth1
qdisc HW 오프로드 상세
qdisc(queuing discipline) HW 오프로드는 리눅스 TC qdisc의 큐잉 정책을 NIC ASIC의 하드웨어 큐 스케줄러에서 직접 구현하는 기술입니다. NGFW 환경에서는 DPI 트래픽 분류 결과에 따른 우선순위 큐, TSN(Time-Sensitive Networking) 환경의 결정론적 레이턴시(Deterministic Latency), 멀티미디어 스트림의 대역폭 보장 등에 활용됩니다.
mqprio
mqprio(Multi-Queue Priority)는 트래픽 클래스(TC, Traffic Class)와 HW 큐를 매핑하는 가장 기본적인 qdisc HW 오프로드입니다. hw 1 모드에서는 NIC가 SW qdisc 없이 완전한 HW 스케줄링을 수행하며, channel 모드에서는 TC당 독립적인 인터럽트 큐를 할당합니다.
# mqprio HW 오프로드 설정 — 4개 TC, 8개 HW 큐
tc qdisc replace dev eth0 root mqprio \
num_tc 4 \
map 0 0 0 0 1 1 1 1 2 2 2 3 3 3 3 3 \ # DSCP → TC 매핑
queues 2@0 2@2 2@4 2@6 \ # TC0→Q0-1, TC1→Q2-3, ...
hw 1
# channel 모드 — TC당 IRQ 분리
tc qdisc replace dev eth0 root mqprio \
num_tc 4 \
map 0 0 0 0 1 1 2 2 \
queues 1@0 1@1 1@2 1@3 \
hw 1 mode channel
/* mqprio HW 오프로드 콜백 — TC_SETUP_QDISC_MQPRIO */
static int mlx5e_setup_tc_mqprio(struct mlx5e_priv *priv,
struct tc_mqprio_qopt_offload *mqprio)
{
struct tc_mqprio_qopt *qopt = &mqprio->qopt;
u8 num_tc = qopt->num_tc;
int i;
if (num_tc > MLX5E_MAX_NUM_TC)
return -EINVAL;
for (i = 0; i < num_tc; i++) {
mlx5e_set_sq_maxrate(priv, qopt->prio_tc_map[i],
qopt->count[i], qopt->offset[i]);
}
return mlx5e_qos_set_tc_config(priv, mqprio);
}
taprio (TSN)
taprio(Time-Aware Priority qdisc)는 IEEE 802.1Qbv 표준을 구현하며, 게이트 제어 목록(GCL, Gate Control List)에 따라 각 TC의 전송 창(Time Window)을 정밀하게 제어합니다. HW 전체 오프로드 모드에서는 NIC의 하드웨어 타이머가 PTP 시계와 동기화되어 나노초 정밀도로 게이트를 제어합니다.
# taprio HW 전체 오프로드 (IEEE 802.1Qbv)
tc qdisc replace dev eth0 parent root handle 100 taprio \
num_tc 4 \
map 0 0 0 0 1 1 2 2 \
queues 1@0 1@1 1@2 1@3 \
base-time 1000000000 \ # 기준 시간 (nanosec)
sched-entry S 0x08 125000 \ # TC3 열림, 125μs
sched-entry S 0x04 125000 \ # TC2 열림, 125μs
sched-entry S 0x02 125000 \ # TC1 열림, 125μs
sched-entry S 0x01 625000 \ # TC0 열림, 625μs
clockid CLOCK_TAI \ # PTP/TAI 시계
flags 0x2 # full-offload 모드
# cycle time = 125+125+125+625 = 1ms
CBS (Credit-Based Shaper)
CBS(Credit-Based Shaper)는 IEEE 802.1Qav 표준을 구현하며, AVB(Audio Video Bridging) 스트림의 대역폭을 크레딧(Credit) 기반으로 보장합니다. idleSlope는 허용 전송 속도, sendSlope는 전송 중 크레딧 감소율, hiCredit/loCredit은 크레딧 상·하한값을 정의합니다.
# CBS HW 오프로드 (Class A 스트림, TC1)
tc qdisc add dev eth0 parent 100:2 cbs \
idleslope 20000 \ # 20Mbps (kbit/s)
sendslope -980000 \ # -980Mbps
hicredit 153 \ # 최대 크레딧 (bytes)
locredit -1389 \ # 최소 크레딧 (bytes)
offload 1
# hicredit = maxFrameSize × (idleslope / linkspeed)
ETF (Earliest TxTime First)
ETF(Earliest TxTime First) qdisc는 SO_TXTIME 소켓 옵션으로 지정된 전송 시각에 패킷을 정밀하게 발송합니다. NIC 하드웨어가 패킷의 타임스탬프를 읽어 지정된 시각에 정확히 전송하므로, 마이크로초 수준의 정밀도를 요구하는 TSN 애플리케이션에 사용됩니다.
# ETF HW 오프로드 (TC2)
tc qdisc add dev eth0 parent 100:3 etf \
clockid CLOCK_TAI \ # TAI 시계
delta 500000 \ # 전송 여유: 500μs
offload \ # NIC HW 타임스탬프
skip_sock_check
ETS (Enhanced Transmission Selection)
ETS(Enhanced Transmission Selection)는 IEEE 802.1Qaz 표준을 구현하며, Strict Priority와 대역폭 공유(Bandwidth Sharing)를 조합한 스케줄링을 제공합니다. DCBX(Data Center Bridging Exchange)를 통해 스위치와 NIC 간 QoS 파라미터를 자동으로 협상합니다.
# ETS HW 오프로드
tc qdisc replace dev eth0 root ets \
bands 4 \
strict 2 \ # 상위 2개 Strict Priority
quanta 3000 3000 \ # 하위 2개 WRR
priomap 0 0 0 1 1 2 2 3
# DCBX 설정 확인
lldptool -t -n -i eth0 -V ETS-CFG
| qdisc 유형 | tc_setup_type 열거값 | IEEE 표준 | HW 오프로드 모드 | NGFW 활용 사례 |
|---|---|---|---|---|
| mqprio | TC_SETUP_QDISC_MQPRIO |
802.1p | hw 1 / channel | DPI 결과 기반 우선순위 큐 분리 |
| taprio | TC_SETUP_QDISC_TAPRIO |
802.1Qbv | full-offload / txtime-assist | OT/ICS 방화벽 결정론적 레이턴시 보장 |
| CBS | TC_SETUP_QDISC_CBS |
802.1Qav | offload 1 | 미디어 방화벽 AVB 스트림 보장 |
| ETF | TC_SETUP_QDISC_ETF |
802.1Qbv | NIC HW 타임스탬프 | TSN 게이트웨이 나노초 정밀 전송 |
| ETS | TC_SETUP_QDISC_ETS |
802.1Qaz | HW WRR 스케줄러 | 데이터센터 방화벽 DCBX QoS |
ethtool ntuple/queue/timestamping HW 오프로드
ethtool은 NIC의 다양한 HW 기능을 제어하는 핵심 인터페이스입니다. NGFW 환경에서 ethtool을 통해 N-tuple 필터링, 인터럽트 응집(Coalescing), 링 버퍼 크기, HW 타임스탬핑 등을 세밀하게 조정하여 처리량과 레이턴시를 최적화할 수 있습니다.
ntuple Filter (ethtool -N)
N-tuple 필터는 src/dst IP, src/dst 포트, 프로토콜, VLAN, TOS 등의 조합으로 패킷을 특정 HW 수신 큐로 스티어링(Steering)하거나 드롭하는 기능입니다. NGFW에서는 Exception Path 패킷(DPI가 필요한 특정 프로토콜)을 전용 큐로 스티어링하거나, 알려진 악성 IP를 HW에서 즉시 드롭하는 데 활용합니다.
# HTTPS(443)를 큐 4로 스티어링
ethtool -N eth0 flow-type tcp4 \
dst-port 443 \
action 4 # 큐 4로 스티어링
# 악성 IP 하드웨어 드롭
ethtool -N eth0 flow-type ip4 \
src-ip 198.51.100.0 m 255.255.255.0 \
action -1 # -1: 드롭
# 관리 트래픽(SSH)을 CPU 0 전용 큐로 격리
ethtool -N eth0 flow-type tcp4 \
dst-port 22 \
action 0
# N-tuple 목록 확인
ethtool -n eth0
/* N-tuple 필터 커널 콜백 */
static int mlx5e_set_rxnfc(struct net_device *dev,
struct ethtool_rxnfc *info)
{
struct mlx5e_priv *priv = netdev_priv(dev);
switch (info->cmd) {
case ETHTOOL_SRXCLSRLINS:
return mlx5e_ethtool_flow_replace(priv, &info->fs,
info->rss_context);
case ETHTOOL_SRXCLSRLDEL:
return mlx5e_ethtool_flow_remove(priv, info->fs.location);
}
return -EOPNOTSUPP;
}
Channel/Queue 관리 (ethtool -L)
ethtool -L은 NIC의 채널(channel) 수, 즉 수신/송신 큐 쌍의 수를 설정합니다. NGFW에서는 CPU 코어당 하나의 큐를 할당하고 IRQ 어피니티(Affinity)를 설정하여 캐시 적중률을 최대화합니다.
# 채널 설정 확인
ethtool -l eth0
# Channel parameters: Pre-set max Combined: 63 Current: 8
# 물리 CPU 코어 수에 맞게 설정
ethtool -L eth0 combined 16
# IRQ 어피니티 설정 — 큐 i → CPU i 고정
for i in $(seq 0 15); do
irq=$(grep "eth0-TxRx-$i" /proc/interrupts | awk -F: '{print $1}' | tr -d ' ')
echo $((1 << i)) > /proc/irq/$irq/smp_affinity
done
Ring Buffer (ethtool -G)
링 버퍼 크기는 NIC RX/TX 디스크립터 수를 결정합니다. NGFW에서 대량의 소패킷 처리 시 링 버퍼가 작으면 오버플로우(드롭)가 발생하므로, 처리 지연이 예상되는 시나리오에서는 큰 링 버퍼를 사용해야 합니다.
# 링 버퍼 크기 확인
ethtool -g eth0
# Pre-set maximums: RX: 8192 TX: 8192
# Current hardware settings: RX: 1024 TX: 1024
# 최대 링 크기로 설정
ethtool -G eth0 rx 8192 tx 8192
# 링 버퍼 드롭 모니터링
ethtool -S eth0 | grep -E "no_dma|ring_full|drop"
# rx_no_dma_resources: 0 ← 증가 시 링 버퍼 부족
Interrupt Coalescing (ethtool -C)
인터럽트 응집은 NIC가 패킷 수신 후 즉시 CPU에 인터럽트를 발생시키지 않고, 일정 시간(rx-usecs) 또는 일정 패킷 수(rx-frames) 후에 인터럽트를 발생시키는 기능입니다. NGFW 환경에서는 처리량과 레이턴시의 트레이드오프를 워크로드 특성에 맞게 조정해야 합니다.
# 현재 설정 확인
ethtool -c eth0
# Adaptive RX: on TX: on
# rx-usecs: 50 rx-frames: 25
# 고처리량 최적화
ethtool -C eth0 rx-usecs 500 rx-frames 64 tx-usecs 500 tx-frames 64
# 저레이턴시 최적화
ethtool -C eth0 rx-usecs 10 rx-frames 1 tx-usecs 10 tx-frames 1
# 적응형 모드 (워크로드 자동 감지)
ethtool -C eth0 adaptive-rx on adaptive-tx on \
rx-usecs-low 10 rx-frames-low 1 \
rx-usecs-high 200 rx-frames-high 64
Hardware Timestamping
HW 타임스탬핑은 NIC PHY 계층에서 패킷 수신/발신 시각을 나노초 정밀도로 기록하는 기능입니다. NGFW 포렌식(Forensic) 분석, 플로우 레이턴시 측정, PTP(Precision Time Protocol) 동기화에 필수적입니다. PHC(PTP Hardware Clock)를 통해 시스템 시계와 동기화됩니다.
# HW 타임스탬핑 지원 확인
ethtool -T eth0
# Capabilities:
# hardware-transmit (SOF_TIMESTAMPING_TX_HARDWARE)
# hardware-receive (SOF_TIMESTAMPING_RX_HARDWARE)
# hardware-raw-clock (SOF_TIMESTAMPING_RAW_HARDWARE)
# PTP Hardware Clock: 0 ← /dev/ptp0
# PTP 동기화
ptp4l -i eth0 -f /etc/ptp4l.conf &
phc2sys -s /dev/ptp0 -c CLOCK_REALTIME -w &
/* SO_TIMESTAMPING 소켓 옵션 */
int flags = SOF_TIMESTAMPING_RX_HARDWARE
| SOF_TIMESTAMPING_TX_HARDWARE
| SOF_TIMESTAMPING_RAW_HARDWARE
| SOF_TIMESTAMPING_OPT_CMSG;
setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, &flags, sizeof(flags));
/* CMSG로 HW 타임스탬프 수신 */
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
if (cmsg->cmsg_type == SO_TIMESTAMPING) {
struct timespec *ts = (struct timespec *)CMSG_DATA(cmsg);
/* ts[0]: SW, ts[2]: HW 타임스탬프 */
latency_ns = ts[2].tv_nsec - send_hw_ts;
}
}
Private Flags (ethtool --show-priv-flags)
드라이버별 Private Flag는 표준 ethtool 인터페이스에 포함되지 않는 NIC 고유 기능을 제어합니다. NGFW 환경에서 중요한 플래그로는 대칭 RSS(Symmetric RSS), 스트라이딩 RQ(Striding RQ), VF 격리(VF Isolation) 등이 있습니다.
# Private Flag 목록 확인
ethtool --show-priv-flags eth0
# rx-striding-rq : on
# rx-cqe-moder : on
# rx-cqe-compress : off
# sniffer : off
# vf_vlan_filter : on
# NGFW 관련 플래그 설정
ethtool --set-priv-flags eth0 rx-striding-rq on
ethtool --set-priv-flags eth0 rx-cqe-compress on
ethtool --set-priv-flags eth0 symmetric_rss on # 대칭 RSS 필수
| ethtool 기능 | 커널 콜백/ioctl | HW 자원 | NGFW 최적화 목적 |
|---|---|---|---|
ntuple filter (-N) |
set_rxnfc / ETHTOOL_SRXCLSRLINS |
플로우 스티어링 테이블 | Exception Path 큐 분리, 악성 IP 드롭 |
채널 설정 (-L) |
set_channels |
RX/TX 큐 쌍 + IRQ | CPU당 큐 1:1 매핑, 캐시 효율 |
링 버퍼 (-G) |
set_ringparam |
DMA 디스크립터 메모리 | 패킷 버스트 흡수, 드롭 방지 |
인터럽트 응집 (-C) |
set_coalesce |
NIC 타이머/카운터 | 처리량 vs 레이턴시 트레이드오프 |
HW 타임스탬핑 (-T) |
SIOCSHWTSTAMP |
PHC (PTP Hardware Clock) | 포렌식 타임스탬프, 플로우 레이턴시 |
RSS 설정 (-X) |
set_rxfh |
RSS 인다이렉션 테이블 | 대칭 해시 활성화, CPU 분산 |
| Private Flags | set_priv_flags |
드라이버별 HW 레지스터 | Striding RQ, 대칭 RSS, VF 격리 |
Header Rewrite 오프로드 상세
헤더 재작성(Header Rewrite) HW 오프로드는 TC pedit(Packet Edit) 액션을 NIC ASIC에서 직접 수행하는 기능입니다. NAT(Network Address Translation), DSCP 마킹(Marking), TTL 감소, VLAN 태그 조작 등 다양한 헤더 필드를 HW에서 수정함으로써 CPU 없이 패킷 변환을 처리할 수 있습니다.
modify_header 컨텍스트
드라이버는 TC pedit 액션을 파싱하여 modify_header 객체로 컴파일합니다. 이 객체는 ASIC별 헤더 수정 명령어 집합으로 변환되어 플로우 테이블에 연결됩니다. ASIC마다 지원하는 필드와 최대 동시 수정 횟수가 다릅니다.
/* pedit → modify_header 컴파일 */
static int alloc_modify_header_actions(struct mlx5_eswitch *esw,
struct mlx5e_tc_flow_parse_attr *parse_attr,
struct netlink_ext_ack *extack)
{
int max_actions, nactions;
max_actions = mlx5_eswitch_get_max_modify_header_actions(esw);
nactions = calc_header_actions(parse_attr->hdrs);
if (nactions > max_actions) {
NL_SET_ERR_MSG_MOD(extack,
"Requested modify header actions exceed HW limit");
return -EOPNOTSUPP;
}
return mlx5e_tc_pedit_to_modify_hdr(esw, parse_attr->hdrs,
&parse_attr->mod_hdr_acts);
}
/* pedit 필드 → MLX5 수정 명령어 */
if (hdrs[TCA_PEDIT_KEY_EX_HDR_TYPE_IP4].used_keys &
BIT(PEDIT_FIELD_IPV4_SRC)) {
MLX5_SET(set_action_in, action,
field, MLX5_ACTION_IN_FIELD_OUT_IP_SRC);
MLX5_SET(set_action_in, action, data, hdrs->vals.ipv4.saddr);
}
if (hdrs[TCA_PEDIT_KEY_EX_HDR_TYPE_TCP].used_keys &
BIT(PEDIT_FIELD_TCP_SPORT)) {
MLX5_SET(set_action_in, action,
field, MLX5_ACTION_IN_FIELD_OUT_TCP_SPORT);
}
지원 필드 매트릭스
| 필드 | IPv4/IPv6 | mlx5 지원 | ice 지원 | bnxt 지원 | 최대 동시 재작성 |
|---|---|---|---|---|---|
| src MAC | L2 공통 | 지원 | 지원 | 지원 | mlx5: 8 / ice: 4 / bnxt: 4 |
| dst MAC | L2 공통 | 지원 | 지원 | 지원 | 동일 |
| src IPv4 | IPv4 | 지원 | 지원 | 지원 | 동일 |
| dst IPv4 | IPv4 | 지원 | 지원 | 지원 | 동일 |
| src IPv6 | IPv6 | 지원 | 지원 | 부분 지원 | 동일 |
| dst IPv6 | IPv6 | 지원 | 지원 | 부분 지원 | 동일 |
| src Port (TCP/UDP) | L4 공통 | 지원 | 지원 | 지원 | 동일 |
| dst Port (TCP/UDP) | L4 공통 | 지원 | 지원 | 지원 | 동일 |
| TTL/Hop Limit | IPv4/IPv6 | 지원 | 지원 | 미지원 | 동일 |
| DSCP/TOS | IPv4/IPv6 | 지원 | 지원 | 지원 | 동일 |
| TCP 플래그 | TCP | 지원 | 미지원 | 미지원 | mlx5만 |
| VLAN PCP/DEI | 802.1Q | 지원 | 지원 | 지원 | 동일 |
| MPLS 레이블 | MPLS | 지원 (실험적) | 미지원 | 미지원 | mlx5 일부 |
다중 Rewrite 제한
ASIC 플로우 테이블 엔트리는 수정 액션 수에 제한이 있습니다. mlx5(ConnectX-6 Dx 기준)는 플로우당 최대 8개의 수정 액션을 지원합니다. pedit와 csum 액션을 체이닝하는 경우, IP/L4 헤더 수정 시 NIC가 자동으로 체크섬을 재계산합니다.
# 다중 pedit 액션 — SNAT + DSCP + TTL 감소
tc filter add dev eth0 ingress protocol ip flower \
src_ip 192.168.1.100 \
action pedit ex munge ip src set 203.0.113.1 \ # SNAT (1번)
ex munge ip ttl add 0xff \ # TTL-1 (2번)
ex munge ip dsfield set 0x28 \ # DSCP 10 (3번)
action csum ip tcp \
action mirred egress redirect dev eth1
# 제한 초과 시 오류
# Error: mlx5_core: Requested modify header actions exceed HW limit
NAT Rewrite와 modify_header
act_ct conntrack NAT는 내부적으로 modify_header와 동일한 ASIC 메커니즘을 사용하지만, 변환 주소가 conntrack 상태에서 동적으로 결정되는 점이 다릅니다. 명시적 pedit와 달리 ct nat은 드라이버가 conntrack 테이블을 조회하여 ASIC에 NAT 규칙을 설치합니다.
# act_ct NAT 오프로드 — conntrack 기반 동적 주소
tc filter add dev eth0 ingress protocol ip flower \
ct_state -trk \
action ct zone 1 nat src addr 10.0.0.0/24 \ # SNAT 풀
action goto chain 1
# 차이점:
# act_ct nat: 동적 주소 (conntrack에서 per-flow 결정)
# pedit: 정적 주소 (규칙 설치 시점에 고정)
# mlx5 ct 테이블 크기: 기본 4K, devlink param으로 최대 1M 확장 가능
Meter/Policer HW 오프로드 상세
미터(Meter)/폴리서(Policer) HW 오프로드는 TC act_police 액션을 NIC ASIC의 토큰 버킷(Token Bucket) 하드웨어 회로에서 구현하는 기능입니다. NGFW에서 플로우별 속도 제한(Per-flow Rate Limiting), 테넌트별 대역폭 보장, DDoS 완화(Mitigation)에 핵심적으로 활용됩니다.
act_police HW 오프로드
act_police는 rate(허용 속도), burst(버스트 허용량), conform_exceed(준수/초과 시 액션)를 정의합니다. HW 토큰 버킷에서 conform 패킷은 pipe 액션으로 다음 단계로 전달되고, exceed 패킷은 drop 또는 reclassify됩니다.
# act_police HW 오프로드 — 100Mbps 제한
tc filter add dev eth0 ingress protocol ip flower \
src_ip 10.0.0.100 \
action police rate 100mbit burst 2mb \
conform-exceed drop/pipe \
action mirred egress redirect dev eth1
# peakrate — 이중 토큰 버킷
tc filter add dev eth0 ingress protocol ip flower \
src_ip 10.0.0.0/24 \
action police rate 100mbit burst 2mb \
peakrate 120mbit latency 100ms \
conform-exceed drop/ok
/* act_police → HW meter 변환 */
static int mlx5e_tc_act_police_offload(struct mlx5e_priv *priv,
struct flow_action_entry *act,
struct mlx5e_tc_attr *attr)
{
struct mlx5e_flow_meter_params params = {
.mode = MLX5_RATE_LIMIT_BPS,
.rate = act->police.rate_bytes_ps,
.burst = act->police.burst,
};
attr->meter_id = mlx5e_alloc_flow_meter(priv, ¶ms);
if (act->police.exceed.act_id == FLOW_ACTION_DROP)
attr->meter_action = MLX5_METER_ACTION_DROP;
else
attr->meter_action = MLX5_METER_ACTION_PIPE;
return mlx5e_tc_set_meter(priv, attr);
}
Shared Meter
공유 미터(Shared Meter)는 여러 플로우 규칙이 동일한 미터 프로필을 공유하는 기능입니다. NGFW에서 특정 서브넷이나 사용자 그룹 전체에 대한 대역폭 제한을 하나의 미터로 구현할 수 있어 ASIC 미터 자원을 효율적으로 사용합니다.
# 공유 미터 생성 — 미터 인덱스 1
tc filter add dev eth0 ingress protocol ip flower \
src_ip 10.0.0.0/24 \
action police index 1 rate 500mbit burst 10mb \
conform-exceed drop/pipe \
action mirred egress redirect dev eth1
# 다른 규칙에서 동일 미터 재사용
tc filter add dev eth0 ingress protocol ip flower \
src_ip 10.0.1.0/24 \
action police index 1 # 두 서브넷이 합산 500Mbps 공유
Color-aware Policing
색상 인식(Color-aware) 폴리싱은 패킷을 Green(준수)/Yellow(경계)/Red(초과) 색상으로 표시하고, 색상에 따라 다른 처리를 적용합니다. DSCP 재분류(Reclassification) 기반의 차등 서비스(DiffServ)를 구현할 수 있습니다.
# 2단계 색상 인식 폴리싱
# Green: CIR 이하 → DSCP AF11
# Yellow: CIR~PIR → DSCP AF12
# Red: PIR 초과 → drop
tc filter add dev eth0 ingress protocol ip flower \
src_ip 10.0.0.0/8 \
action police rate 100mbit burst 2mb \
peakrate 200mbit latency 10ms \
conform-exceed \
action pedit ex munge ip dsfield set 0x28 pipe \ # Green
action pedit ex munge ip dsfield set 0x30 drop # Yellow/Red
HW Meter 자원 관리
ASIC의 미터 풀 크기는 NIC 모델에 따라 다릅니다. devlink resource 인터페이스를 통해 미터 풀 현황을 모니터링하고, 필요 시 자원을 재배분할 수 있습니다.
# devlink 미터 자원 확인
devlink resource show pci/0000:03:00.0
# name meters
# size 65536 occ 128 ← 64K 미터 중 128 사용
# 미터 자원 임계값 모니터링
ethtool -S eth0 | grep meter
# rx_meter_alloc: 128
# rx_meter_free: 65408
# 미터 풀 크기 조정 (재로드 필요)
devlink resource set pci/0000:03:00.0 \
path global/flow_meter_pool size 32768
devlink dev reload pci/0000:03:00.0
Per-flow vs Per-port Rate Limiting
NGFW QoS 설계에서 Per-flow 속도 제한과 Per-port 속도 제한은 서로 다른 목적과 구현 방식을 가집니다. Per-flow 제한은 개별 TCP/UDP 플로우에 적용되며 act_police로 구현합니다. Per-port 제한은 특정 포트 또는 인터페이스 전체에 적용되며 devlink rate 또는 mqprio CBS로 구현합니다.
| 항목 | Per-flow Rate Limiting | Per-port Rate Limiting |
|---|---|---|
| 적용 범위 | 개별 5-tuple 플로우 | 포트/VF/SF 전체 집합 |
| 구현 방식 | TC act_police (공유 미터 포함) | devlink rate / CBS / mqprio |
| ASIC 자원 | 미터 엔트리 (플로우당 1개) | 포트 스케줄러 자원 |
| NGFW 사용 사례 | 사용자별 대역폭 제한, P2P 차단 | VF별 대역폭 격리, 테넌트 SLA |
| 동적 변경 | 규칙 교체 필요 | devlink rate로 무중단 변경 |
devlink 파라미터/리소스/region 상세
devlink는 리눅스 커널이 제공하는 NIC/스위치 디바이스 관리 인터페이스로, 드라이버 파라미터 설정, ASIC 자원 모니터링, 펌웨어 메모리 스냅샷, 대역폭 계층 제어 등을 통합 제공합니다. NGFW 환경에서 devlink를 통해 NIC의 동작 모드, 자원 할당, 진단을 세밀하게 제어할 수 있습니다.
devlink param
devlink param은 드라이버가 노출하는 구성 파라미터로, runtime(즉시 적용), driverinit(드라이버 재로드 후 적용), permanent(펌웨어 플래시 필요) 세 가지 cmode를 가집니다.
# 모든 devlink 파라미터 확인
devlink dev param show pci/0000:03:00.0
# name enable_roce type generic
# values: cmode driverinit value true
# name flow_steering_mode type driver-specific
# values: cmode runtime value smfs
# name ct_action_on_nat_conns type driver-specific
# values: cmode driverinit value false
# 플로우 스티어링 모드 변경 (runtime)
# smfs: Software-Managed Flow Steering (대량 규칙 최적)
# dmfs: Device-Managed Flow Steering (소량 규칙, 저레이턴시)
devlink dev param set pci/0000:03:00.0 \
name flow_steering_mode value smfs cmode runtime
# RoCE 비활성화 — NGFW에서 불필요
devlink dev param set pci/0000:03:00.0 \
name enable_roce value false cmode driverinit
devlink dev reload pci/0000:03:00.0
# conntrack NAT 연결에 CT 액션 적용
devlink dev param set pci/0000:03:00.0 \
name ct_action_on_nat_conns value true cmode driverinit
/* devlink param 커널 API */
static const struct devlink_param mlx5_devlink_params[] = {
DEVLINK_PARAM_DRIVER(MLX5_DEVLINK_PARAM_ID_FLOW_STEERING_MODE,
"flow_steering_mode",
DEVLINK_PARAM_TYPE_STRING,
BIT(DEVLINK_PARAM_CMODE_RUNTIME),
mlx5_devlink_fs_mode_get,
mlx5_devlink_fs_mode_set,
mlx5_devlink_fs_mode_validate),
DEVLINK_PARAM_GENERIC(ENABLE_ROCE,
BIT(DEVLINK_PARAM_CMODE_DRIVERINIT),
NULL, NULL, NULL),
};
devlink resource
devlink resource는 ASIC 하드웨어 자원의 현재 사용량과 최대값을 계층적으로 표시합니다. NGFW 운영에서 플로우 테이블 고갈, 카운터 풀 소진, 미터 풀 부족은 성능 저하의 주요 원인이므로 지속적인 모니터링이 필요합니다.
# 전체 자원 계층 표시
devlink resource show pci/0000:03:00.0
# name global
# name fdb
# size 524288 occ 1024 ← FDB 52만 중 1024 사용
# name encap
# size 8192 occ 64
# name counters
# size 1048576 occ 2048 ← 카운터 1M 중 2K 사용
# name meters
# size 65536 occ 128
# name tc_filters
# size 65536 occ 8192 ← TC 필터 64K 중 8K 사용
# 80% 초과 자원 경고 스크립트
devlink resource show pci/0000:03:00.0 | awk '
/occ/ {
match($0, /size ([0-9]+)/, sz_arr);
match($0, /occ ([0-9]+)/, occ_arr);
sz = sz_arr[1]+0; occ = occ_arr[1]+0;
if (sz > 0 && occ/sz > 0.8)
print "WARNING:", $2, "usage:", occ "/" sz, "(" int(occ*100/sz) "%)"
}'
# 자원 재배분 — TC 필터 확장
devlink resource set pci/0000:03:00.0 \
path global/fdb size 262144
devlink resource set pci/0000:03:00.0 \
path global/tc_filters size 131072
devlink dev reload pci/0000:03:00.0
devlink region
devlink region은 ASIC 내부 메모리 영역의 스냅샷을 캡처하여 디버깅과 충돌 분석에 사용합니다. NIC 펌웨어 충돌, 플로우 테이블 불일치, 하드웨어 에러 발생 시 region 덤프로 상태를 보존할 수 있습니다.
# 사용 가능한 region 목록
devlink region show pci/0000:03:00.0
# region cr-space size 1048576 snapshot []
# region fw-health size 4096 snapshot []
# region lldp size 65536 snapshot []
# region pci-rw size 65536 snapshot []
# cr-space 스냅샷 생성 (ASIC 설정 레지스터)
devlink region new pci/0000:03:00.0/cr-space snapshot 1
# 스냅샷 덤프
devlink region dump pci/0000:03:00.0/cr-space snapshot 1 | head -20
# 특정 오프셋 읽기
devlink region read pci/0000:03:00.0/cr-space \
snapshot 1 address 0x1000 length 64
# 스냅샷 삭제
devlink region del pci/0000:03:00.0/cr-space snapshot 1
# fw-health: 펌웨어 충돌 덤프 분석
devlink region new pci/0000:03:00.0/fw-health snapshot 2
devlink region dump pci/0000:03:00.0/fw-health snapshot 2 > /tmp/fw_health.bin
strings /tmp/fw_health.bin | grep -E "assert|error|panic"
devlink rate
devlink rate는 VF(Virtual Function)와 SF(Scalable Function)별 송신 대역폭을 계층적으로 제어합니다. tx_max는 최대 대역폭, tx_share는 보장 대역폭(최소 보장)을 설정합니다. 이를 통해 NGFW에서 멀티테넌트 환경의 VF별 SLA를 하드웨어에서 보장할 수 있습니다.
# VF rate 설정 확인
devlink port function rate show
# pci/0000:03:00.0/1: type leaf ← VF 0
# tx_share 100Mbit tx_max 1Gbit
# pci/0000:03:00.0/2: type leaf ← VF 1
# tx_share 100Mbit tx_max 1Gbit
# VF 0 대역폭 설정
devlink port function rate set pci/0000:03:00.0/1 \
tx_share 500Mbit \ # 보장 대역폭 500Mbps
tx_max 2Gbit # 최대 대역폭 2Gbps
# 계층형 rate 노드 생성 — 그룹 제한
devlink port function rate add pci/0000:03:00.0/group1 \
tx_max 5Gbit # 그룹 전체 최대 5Gbps
# VF를 그룹에 연결
devlink port function rate set pci/0000:03:00.0/1 parent group1
devlink port function rate set pci/0000:03:00.0/2 parent group1
# 결과: VF0 + VF1 합산 최대 5Gbps, 각각 최소 100Mbps 보장
devlink port function (SF)
SF(Scalable Function)는 단일 물리 NIC에서 독립적인 커널 네트워크 스택을 가진 경량 가상 함수를 생성하는 기능입니다. VF보다 적은 오버헤드로 더 많은 격리된 함수를 만들 수 있으며, NGFW에서 테넌트별 독립 데이터 플레인 구성에 활용됩니다.
# SF 생성
devlink port add pci/0000:03:00.0 flavour pcisf \
pfnum 0 sfnum 100
# pci/0000:03:00.0/32768: type eth netdev eth6 flavour pcisf
# pfnum 0 sfnum 100 splittable false
# SF 함수 설정 — MAC 주소, 신뢰 모드
devlink port function set pci/0000:03:00.0/32768 \
hw_addr 00:11:22:33:44:55 \
trust on \
state active # 활성화
# SF 상태 확인
devlink port show pci/0000:03:00.0/32768
# function:
# hw_addr 00:11:22:33:44:55
# state active opstate attached
# SF rate 설정
devlink port function rate set pci/0000:03:00.0/32768 \
tx_share 1Gbit tx_max 10Gbit
# SF 제거
devlink port function set pci/0000:03:00.0/32768 state inactive
devlink port del pci/0000:03:00.0/32768
/* devlink SF 생명주기 — 커널 API */
static int mlx5_devlink_sf_port_new(struct devlink *devlink,
const struct devlink_port_new_attrs *attrs,
struct netlink_ext_ack *extack,
unsigned int *new_port_index)
{
struct mlx5_sf *sf;
/* SF 자원 할당 */
sf = mlx5_sf_alloc(dev, attrs->sfnum, extack);
if (IS_ERR(sf))
return PTR_ERR(sf);
/* devlink port 등록 */
mlx5_esw_offloads_sf_vport_enable(dev->priv.eswitch, sf->hw_fn_id);
*new_port_index = sf->port_index;
return 0;
}
/* SF 상태 전환: inactive → active */
static int mlx5_devlink_sf_port_fn_state_set(
struct devlink_port *dl_port,
enum devlink_port_fn_state state,
struct netlink_ext_ack *extack)
{
if (state == DEVLINK_PORT_FN_STATE_ACTIVE) {
/* SF 드라이버 바인딩 → 독립 네트워크 스택 생성 */
return mlx5_sf_activate(sf, extack);
}
return mlx5_sf_deactivate(sf, extack);
}
| devlink 서브시스템 | 주요 명령어 | cmode | NGFW 활용 |
|---|---|---|---|
| param | devlink dev param set/show |
runtime / driverinit / permanent | 플로우 스티어링 모드, RoCE 비활성화 |
| resource | devlink resource show/set |
driverinit (재로드 필요) | FDB/미터/TC 필터 자원 재배분 |
| region | devlink region new/dump/del |
즉시 스냅샷 | ASIC 메모리 덤프, 펌웨어 충돌 분석 |
| rate | devlink port function rate set |
runtime | VF/SF 대역폭 계층 제어, 테넌트 SLA |
| port function | devlink port add/del/set |
런타임 생명주기 | SF 생성/삭제, 멀티테넌트 데이터 플레인 |
| health | devlink health show/dump/recover |
즉시 | NIC 오류 복구, 자동 재설정 |
| flash | devlink dev flash |
permanent | 펌웨어 업그레이드, 설정 초기화 |
devlink resource show로 ASIC 자원 포화 여부 확인 (80% 이상 시 경고)devlink dev param show로 플로우 스티어링 모드 확인 (smfs vs dmfs)ethtool -S eth0로 HW 드롭 카운터 확인 (no_dma_resources, out_of_buffer)devlink region new .../cr-space로 ASIC 상태 스냅샷 후 지원팀 제출devlink health show로 자동 복구 기록 확인
HW 플로우 통계 및 카운터 오프로드
HW 플로우 통계(Flow Statistics) 오프로드는 TC flower 규칙에 매칭된 패킷/바이트 수를 NIC ASIC의 하드웨어 카운터에서 직접 수집하는 기능입니다. 소프트웨어 카운터는 패킷이 CPU를 거쳐야만 갱신되지만, HW 카운터는 오프로드된 플로우의 통계를 CPU 개입 없이 기록합니다. NGFW 환경에서 플로우별 트래픽량 모니터링, 정책 적중 확인, QoS 통계 수집에 필수적입니다.
플로우 통계 아키텍처
TC flower 규칙의 통계는 flow_stats 구조체로 관리됩니다. 드라이버는 TC_CLSFLOWER_STATS 명령을 받으면 ASIC 카운터를 읽어 커널에 반환합니다. 이 통계는 tc -s filter show 명령으로 확인할 수 있습니다.
/* include/net/flow_offload.h — 플로우 통계 구조체 */
struct flow_stats {
u64 pkts; /* 매칭 패킷 수 */
u64 bytes; /* 매칭 바이트 수 */
u64 drops; /* 드롭 패킷 수 */
u64 lastused; /* 마지막 매칭 시간 (jiffies) */
enum flow_action_hw_stats used_hw_stats;
};
/* flow_action_hw_stats 열거값 — 통계 소스 구분 */
enum flow_action_hw_stats {
FLOW_ACTION_HW_STATS_IMMEDIATE, /* 즉시 HW 카운터 읽기 */
FLOW_ACTION_HW_STATS_DELAYED, /* 주기적 폴링 (배치 업데이트) */
FLOW_ACTION_HW_STATS_DISABLED, /* 통계 비활성화 (자원 절약) */
};
/* 드라이버 통계 콜백 — TC_CLSFLOWER_STATS */
static int mlx5e_tc_stats_flower(struct mlx5e_priv *priv,
struct flow_cls_offload *f)
{
struct mlx5e_tc_flow *flow;
u64 packets, bytes, lastused;
flow = rhashtable_lookup_fast(&priv->tc_ht, &f->cookie,
mlx5e_tc_flow_ht_params);
if (!flow)
return -ENOENT;
/* ASIC HW 카운터 읽기 */
mlx5_fc_query_cached(flow->counter, &bytes, &packets, &lastused);
/* TC 코어에 통계 전달 */
flow_stats_update(&f->stats, bytes, packets, 0, lastused,
FLOW_ACTION_HW_STATS_DELAYED);
return 0;
}
HW 카운터 유형
NIC ASIC은 여러 계층의 카운터를 제공합니다. 플로우 카운터(Flow Counter)는 개별 TC 규칙에 연결되고, 포트 카운터(Port Counter)는 물리/가상 포트 전체 트래픽을 측정합니다. NGFW에서는 두 유형을 조합하여 정책 적중률과 인터페이스 처리량을 동시에 모니터링합니다.
# TC flower 규칙별 HW 통계 확인
tc -s filter show dev eth0 ingress
# filter protocol ip pref 49152 flower chain 0
# filter protocol ip pref 49152 flower chain 0 handle 0x1
# eth_type ipv4
# ip_proto tcp
# dst_port 443
# in_hw in_hw_count 1
# action order 1: mirred (Egress Redirect to device eth1) ... index 1
# Action statistics:
# Sent 1234567890 bytes 987654 pkt (dropped 0, overlimits 0 requeues 0)
# hw_stats delayed
# 포트 카운터 (ethtool -S)
ethtool -S eth0 | grep -E "^ (rx|tx)_"
# rx_packets: 12345678
# rx_bytes: 9876543210
# tx_packets: 11223344
# rx_out_of_buffer: 0 ← 버퍼 부족 드롭
# rx_if_down_packets: 0 ← 인터페이스 다운 시 드롭
# eSwitch 가상 포트 카운터
ethtool -S eth0_repr | grep "vport"
# vport_rx_packets: 5678
# vport_tx_packets: 4567
/* mlx5 HW 카운터 할당/해제 — drivers/net/ethernet/mellanox/mlx5 */
struct mlx5_fc *mlx5_fc_create(struct mlx5_core_dev *dev, bool aging)
{
struct mlx5_fc *counter;
counter = kzalloc(sizeof(*counter), GFP_KERNEL);
/* ASIC에서 카운터 ID 할당 */
mlx5_cmd_fc_alloc(dev, &counter->id);
if (aging) {
/* 에이징 카운터: 주기적 폴링으로 lastused 추적 */
list_add(&counter->list, &dev->priv.fc_stats.counters);
}
return counter;
}
/* 카운터 배치 쿼리 — 성능 최적화를 위해 여러 카운터를 한 번에 읽기 */
static void mlx5_fc_stats_work(struct work_struct *work)
{
struct mlx5_fc_stats *fc_stats =
container_of(work, struct mlx5_fc_stats, work.work);
struct mlx5_fc *counter;
u32 *bulk_query;
/* 벌크 쿼리: 최대 4096개 카운터를 단일 FW 명령으로 읽기 */
mlx5_cmd_fc_bulk_query(fc_stats->dev,
fc_stats->bulk_query_id,
fc_stats->bulk_query_len,
bulk_query);
/* 개별 카운터에 결과 배포 */
list_for_each_entry(counter, &fc_stats->counters, list) {
mlx5_fc_stats_update(counter, bulk_query);
counter->lastuse = jiffies;
}
/* 다음 폴링 예약 (기본 500ms) */
queue_delayed_work(fc_stats->wq, &fc_stats->work,
msecs_to_jiffies(500));
}
| 카운터 유형 | 연결 대상 | 폴링 주기 | ASIC 자원 비용 | NGFW 용도 |
|---|---|---|---|---|
| 플로우 카운터 | TC flower 규칙 (cookie) | 500ms (배치 쿼리) | 규칙당 1개 카운터 ID | 정책 적중 모니터링, 트래픽 통계 |
| 포트 카운터 | 물리/가상 포트 | ethtool 요청 시 | 포트당 고정 할당 | 인터페이스 처리량, 드롭 모니터링 |
| CT 카운터 | conntrack 오프로드 엔트리 | 1초 (CT 에이징 연동) | CT 엔트리당 1개 | 세션별 트래픽량, DPI 결정 참조 |
| 미터 카운터 | act_police 미터 | 미터 쿼리 시 | 미터당 conform/exceed 2개 | QoS 통계, SLA 준수 확인 |
| 드롭 카운터 | 드롭 이유별 (ACL/미터/버퍼) | ethtool 요청 시 | 이유당 1개 | 드롭 원인 분석, 용량 계획 |
플로우 에이징 및 타임아웃 관리
HW 오프로드된 플로우는 영구적으로 ASIC에 존재하지 않습니다. 플로우 에이징(Aging)은 일정 시간 동안 패킷이 매칭되지 않은 플로우를 자동으로 제거하는 메커니즘으로, ASIC 자원 고갈을 방지하고 동적 트래픽 패턴에 대응합니다. NGFW 환경에서는 conntrack 타임아웃과 HW 에이징을 동기화하여 세션 종료 후 ASIC 자원을 즉시 회수해야 합니다.
TC flower 플로우 에이징
TC flower 규칙 자체는 명시적으로 삭제하지 않는 한 영구적입니다. 그러나 nf_flow_table(flowtable) 기반 오프로드는 conntrack 타임아웃과 연동하여 HW 플로우를 자동으로 에이징합니다. 드라이버는 HW 카운터의 lastused 필드를 주기적으로 확인하여 소프트웨어 타임아웃과 동기화합니다.
/* net/netfilter/nf_flow_table_offload.c — HW 플로우 에이징 */
static void nf_flow_offload_work_gc(struct work_struct *work)
{
struct flow_offload *flow;
struct hlist_node *n;
hlist_for_each_entry_safe(flow, n, &flow_table->rhashtable) {
/* HW 카운터에서 lastused 읽기 */
nf_flow_offload_stats(flow_table, flow);
if (nf_flow_has_expired(flow)) {
/* 타임아웃 도달: HW 플로우 삭제 */
flow_offload_teardown(flow);
nf_flow_offload_del(flow_table, flow);
} else if (nf_flow_is_dying(flow)) {
/* conntrack 만료 또는 RST/FIN: 즉시 삭제 */
flow_offload_teardown(flow);
nf_flow_offload_del(flow_table, flow);
}
}
/* 다음 GC 주기 예약 (기본 1초) */
queue_delayed_work(system_power_efficient_wq,
&flow_table->gc_work,
msecs_to_jiffies(1000));
}
/* 타임아웃 판단: conntrack 타임아웃과 동기화 */
static bool nf_flow_has_expired(const struct flow_offload *flow)
{
u32 timeout = flow->timeout;
u64 lastused = flow->tuplehash[0].stats.lastused;
/* lastused + timeout < now → 만료 */
return time_is_before_jiffies(lastused +
timeout * HZ);
}
CT 오프로드 타임아웃 동기화
act_ct conntrack 오프로드에서 HW 플로우의 타임아웃은 conntrack 엔트리의 프로토콜별 타임아웃과 동기화됩니다. TCP established 세션은 기본 5일, UDP 스트림은 기본 2분입니다. HW 카운터의 lastused가 갱신되면 conntrack 타임아웃도 리셋됩니다.
# conntrack 타임아웃 확인
sysctl net.netfilter.nf_conntrack_tcp_timeout_established
# 432000 (5일 = 5×24×60×60)
sysctl net.netfilter.nf_conntrack_udp_timeout_stream
# 120 (2분)
# NGFW 최적화: UDP 타임아웃 단축 (ASIC 자원 회수 가속)
sysctl -w net.netfilter.nf_conntrack_udp_timeout_stream=30
sysctl -w net.netfilter.nf_conntrack_udp_timeout=10
# flowtable 기반 오프로드 설정
nft add table inet fw
nft add flowtable inet fw f1 \
{ hook ingress priority 0 \; devices = { eth0, eth1 } \; \
flags offload \; }
# flowtable 오프로드 현황 확인
nft list flowtable inet fw f1
conntrack -L | grep OFFLOAD
# tcp 6 431999 ESTABLISHED src=10.0.0.1 dst=10.0.0.2 ... [OFFLOAD]
# HW 오프로드 플로우 수 확인
cat /proc/net/nf_conntrack | grep -c OFFLOAD
에이징과 ASIC 자원 회수
ASIC 플로우 테이블 자원은 유한합니다. 에이징이 적절히 동작하지 않으면 플로우 테이블이 고갈되어 새로운 오프로드가 실패합니다. NGFW에서는 프로토콜별 타임아웃을 워크로드 특성에 맞게 조정하고, devlink resource로 자원 사용률을 모니터링해야 합니다.
# ASIC 플로우 테이블 사용률 모니터링
devlink resource show pci/0000:03:00.0 | grep -A1 "tc_filters\|fdb\|counters"
# name tc_filters
# size 65536 occ 58000 ← 88% 사용 (경고 임계값 초과)
# 자원 고갈 시 증상 — dmesg 로그
dmesg | grep -E "flow|offload|tc"
# mlx5_core: Failed to add TC flow, -ENOSPC
# mlx5_core: Flow counter pool exhausted
# conntrack 테이블 크기와 HW 자원 균형 조정
# conntrack max를 HW 용량에 맞추어 제한
sysctl -w net.netfilter.nf_conntrack_max=50000
# 에이징 주기 확인 (mlx5 기본 500ms)
ethtool -S eth0 | grep "cache_\|age"
| 프로토콜/상태 | 커널 기본 타임아웃 | NGFW 권장값 | ASIC 자원 영향 | sysctl 파라미터 |
|---|---|---|---|---|
| TCP established | 432000초 (5일) | 3600초 (1시간) | 장기 점유 → 고갈 위험 높음 | nf_conntrack_tcp_timeout_established |
| TCP time_wait | 120초 | 30초 | 빠른 회수 가능 | nf_conntrack_tcp_timeout_time_wait |
| UDP stream | 120초 | 30초 | DNS/QUIC 버스트 시 대량 생성 | nf_conntrack_udp_timeout_stream |
| UDP unreplied | 30초 | 10초 | 스캔 트래픽 시 급증 가능 | nf_conntrack_udp_timeout |
| ICMP | 30초 | 10초 | 낮음 (소량) | nf_conntrack_icmp_timeout |
| Generic | 600초 | 120초 | 비표준 프로토콜 점유 | nf_conntrack_generic_timeout |
오프로드 실패 처리 및 폴백 메커니즘
HW 오프로드는 항상 성공하지 않습니다. ASIC 자원 부족, 지원하지 않는 매칭 필드 조합, 드라이버 제한 등으로 오프로드가 거부될 수 있습니다. 리눅스 TC 프레임워크는 이러한 실패를 처리하는 폴백(Fallback) 메커니즘을 제공하며, NGFW 환경에서는 오프로드 실패 시 소프트웨어 경로로 자동 전환하여 연결이 끊기지 않도록 해야 합니다.
TC 오프로드 플래그
TC flower 규칙 설치 시 skip_sw, skip_hw 플래그로 오프로드 동작을 제어합니다. 기본 동작(플래그 없음)은 HW와 SW 양쪽 모두에 설치를 시도하며, HW 실패 시 SW만으로 동작합니다.
# 기본: HW + SW 모두 설치 (HW 실패 시 SW 폴백)
tc filter add dev eth0 ingress protocol ip flower \
dst_port 443 \
action mirred egress redirect dev eth1
# in_hw: 0/1 → HW 오프로드 성공 여부 확인
# skip_sw: HW 전용 (SW 미설치) — HW 실패 시 규칙 전체 실패
tc filter add dev eth0 ingress protocol ip flower \
skip_sw \
dst_port 443 \
action mirred egress redirect dev eth1
# HW 미지원 시: Error: filter offload failed - Loss of netlink message
# skip_hw: SW 전용 (HW 미설치) — 의도적 SW 처리
tc filter add dev eth0 ingress protocol ip flower \
skip_hw \
dst_port 22 \
action mirred egress redirect dev eth1
# 규칙 오프로드 상태 확인
tc -s filter show dev eth0 ingress
# in_hw ← HW에 설치됨
# in_hw_count 1 ← 1개 NIC에 설치
# not_in_hw ← HW 오프로드 실패 (SW만 동작)
오프로드 실패 원인과 진단
오프로드 실패 시 드라이버는 netlink extack(Extended ACK) 메시지로 구체적인 실패 이유를 커널에 반환합니다. tc 명령어에 -echo 옵션을 추가하면 이 메시지를 확인할 수 있습니다.
/* 드라이버 오프로드 실패 메시지 예시 — mlx5 */
static int mlx5e_tc_parse_action(struct mlx5e_priv *priv,
struct flow_action_entry *act,
struct netlink_ext_ack *extack)
{
switch (act->id) {
case FLOW_ACTION_MANGLE:
if (!mlx5e_tc_can_offload_pedit(priv, act)) {
NL_SET_ERR_MSG_MOD(extack,
"Unsupported pedit field for HW offload");
return -EOPNOTSUPP;
}
break;
case FLOW_ACTION_CT:
if (act->ct.action & TCA_CT_ACT_CLEAR) {
NL_SET_ERR_MSG_MOD(extack,
"CT clear action not supported in HW");
return -EOPNOTSUPP;
}
break;
default:
NL_SET_ERR_MSG_MOD(extack,
"Unsupported action for HW offload");
return -EOPNOTSUPP;
}
return 0;
}
# 오프로드 실패 원인 확인 — dmesg
dmesg | grep -E "mlx5.*offload|tc.*offload|flower.*err"
# 주요 실패 메시지:
# "Failed to add TC flow, -ENOSPC" → ASIC 자원 부족
# "Unsupported pedit field" → 미지원 헤더 수정
# "Requested modify header exceed" → pedit 횟수 초과
# "Can't offload re-write" → 동시 encap+pedit 제한
# "Matching on ct_state requires" → CT zone 미설정
# "Can't offload hairpin" → 헤어핀 미지원 구성
# netlink extack 메시지 직접 확인
tc -echo filter add dev eth0 ingress protocol ip flower \
skip_sw \
ip_flags nofrag \
action drop 2>&1
# Error: mlx5_core: matching on frag requires CT
| 실패 원인 | 오류 코드 | extack 메시지 예시 | 대응 방법 |
|---|---|---|---|
| ASIC 자원 부족 | -ENOSPC |
Failed to add TC flow | 에이징 타임아웃 단축, devlink resource 재배분 |
| 미지원 매칭 필드 | -EOPNOTSUPP |
Unsupported key/action | skip_sw 제거하여 SW 폴백 허용 |
| pedit 횟수 초과 | -EOPNOTSUPP |
Modify header actions exceed HW limit | pedit 수 줄이기 또는 chain 분리 |
| encap+pedit 동시 사용 | -EOPNOTSUPP |
Can't offload re-write and target encap | chain 분리: pedit → goto → encap |
| 카운터 풀 고갈 | -ENOSPC |
Flow counter pool exhausted | 불필요한 규칙 제거, 카운터 풀 확장 |
| CT 오프로드 제한 | -EOPNOTSUPP |
CT clear/force not supported | 해당 플로우를 SW 경로로 처리 |
| FW 버전 미지원 | -EOPNOTSUPP |
FW does not support feature | NIC 펌웨어 업그레이드 |
NGFW 그레이스풀 폴백 설계
NGFW에서 오프로드 실패 시 패킷이 드롭되지 않도록 그레이스풀 폴백(Graceful Fallback) 전략이 필요합니다. 핵심 원칙은 skip_sw를 가능한 사용하지 않고, HW 실패 시 SW 경로로 자동 전환하는 것입니다.
## NGFW 그레이스풀 폴백 설계 패턴
# 패턴 1: 기본 폴백 (skip_sw 미사용)
# HW 가능 시 HW, 불가 시 SW 경로 자동 전환
tc filter add dev eth0 ingress protocol ip flower \
dst_port 443 \
action ct nat \
action mirred egress redirect dev eth1
# in_hw → HW 처리, not_in_hw → SW 처리 (패킷 드롭 없음)
# 패턴 2: 선택적 skip_sw (성능 크리티컬 규칙만)
# 대량 트래픽 규칙은 HW 필수, 관리 트래픽은 SW 허용
tc filter add dev eth0 ingress protocol ip flower \
skip_sw \
ct_state +est+trk \
action mirred egress redirect dev eth1 # 성능 크리티컬
tc filter add dev eth0 ingress protocol ip flower \
dst_port 22 \
action mirred egress redirect dev mgmt0 # 관리 트래픽 (SW OK)
# 패턴 3: 오프로드 실패 모니터링 스크립트
#!/bin/bash
not_in_hw=$(tc -s filter show dev eth0 ingress | grep -c "not_in_hw")
total=$(tc -s filter show dev eth0 ingress | grep -c "filter protocol")
echo "오프로드 실패: $not_in_hw / $total"
if [ "$not_in_hw" -gt 0 ]; then
echo "WARNING: $not_in_hw 개 규칙이 SW 폴백 중"
dmesg | tail -20 | grep -i offload
fi
RSS/RPS HW 오프로드
RSS(Receive Side Scaling)는 수신 패킷을 NIC 하드웨어에서 여러 RX 큐에 해시 기반으로 분산하는 기능입니다. NGFW 환경에서 RSS는 멀티코어 CPU를 효과적으로 활용하는 핵심 메커니즘이며, 대칭 RSS(Symmetric RSS)는 forward/return 패킷을 동일 CPU에서 처리하여 conntrack 성능을 최대화합니다.
RSS 아키텍처
NIC ASIC은 패킷 헤더에서 해시 키(Hash Key)를 추출하고, Toeplitz 해시 함수를 적용하여 인다이렉션 테이블(Indirection Table)을 조회합니다. 인다이렉션 테이블의 엔트리가 가리키는 RX 큐로 패킷이 전달됩니다.
/* include/linux/netdevice.h — RSS 해시 입력 */
enum rss_hash_type {
RSS_HASH_TYPE_L3, /* src/dst IP만 사용 */
RSS_HASH_TYPE_L4, /* src/dst IP + src/dst 포트 */
};
/* Toeplitz 해시 함수 — NIC 하드웨어에서 실행
* input: {src_ip, dst_ip, src_port, dst_port}
* key: 40바이트 비밀 키 (ethtool -X로 설정)
* hash = Σ(input_bit[i] ? shift(key, i) : 0) → 하위 N비트로 큐 선택 */
/* 대칭 해시 원리:
* 일반 Toeplitz: hash(A→B) ≠ hash(B→A) → forward/return 다른 큐
* 대칭 Toeplitz: hash(A→B) = hash(B→A) → 동일 큐 보장
* 구현: XOR(src_ip, dst_ip) + XOR(src_port, dst_port)를 해시 입력으로 사용 */
/* 드라이버 RSS 설정 콜백 */
static int mlx5e_set_rxfh(struct net_device *dev,
const u32 *indir,
const u8 *hkey,
const u8 hfunc)
{
struct mlx5e_priv *priv = netdev_priv(dev);
if (hfunc == ETH_RSS_HASH_XOR) {
/* XOR 해시: 대칭 해시 자동 보장 */
priv->rss_params.hfunc = MLX5_RX_HASH_FN_INVERTED_XOR8;
} else {
/* Toeplitz 해시: 대칭 키 필요 */
priv->rss_params.hfunc = MLX5_RX_HASH_FN_TOEPLITZ;
}
if (indir)
memcpy(priv->rss_params.indirection_rqt, indir,
priv->rss_params.indir_rqt_size * sizeof(u32));
if (hkey)
memcpy(priv->rss_params.toeplitz_hash_key, hkey,
MLX5E_RSS_HASH_KEY_SIZE);
return mlx5e_modify_tirs_hash(priv);
}
# 현재 RSS 설정 확인
ethtool -x eth0
# RX flow hash indirection table for eth0 with 16 RX ring(s):
# 0: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
# RSS hash key: toeplitz
# 해시 함수 변경 — XOR (대칭 해시 보장)
ethtool -X eth0 hfunc xor
# Toeplitz 대칭 해시 키 설정
# 대칭 키: src/dst XOR 시 동일 해시가 나오도록 설계된 키
ethtool -X eth0 hfunc toeplitz \
hkey 6d:5a:56:da:25:5b:0e:c2:41:67:25:3d:43:a3:8f:b0:d0:ca:2b:cb:ae:7b:30:b4:77:cb:2d:a3:80:30:f2:0c:6a:42:b7:3b:be:ac:01:fa
# 인다이렉션 테이블 커스텀 설정 — 큐 0~7만 사용
ethtool -X eth0 equal 8
# 특정 큐 가중치 설정
ethtool -X eth0 weight 1 1 1 1 2 2 2 2 # 큐 4~7에 2배 가중
# RSS 해시 입력 필드 설정
ethtool -N eth0 rx-flow-hash tcp4 sdfn # src/dst IP + src/dst 포트
ethtool -N eth0 rx-flow-hash udp4 sdfn
NGFW 대칭 RSS 최적화
NGFW에서 대칭 RSS는 필수입니다. conntrack은 forward 방향과 return 방향 패킷이 동일 CPU에서 처리되어야 락 경합(Lock Contention) 없이 효율적으로 동작합니다. 대칭 RSS가 없으면 conntrack 해시 테이블 접근 시 다른 CPU의 캐시를 무효화하여 성능이 크게 저하됩니다.
# NGFW 대칭 RSS 최적화 스크립트
# 1. 대칭 RSS 활성화 (Private Flag)
ethtool --set-priv-flags eth0 symmetric_rss on 2>/dev/null || \
ethtool -X eth0 hfunc xor
# 2. 채널 수 = CPU 코어 수에 맞춤
NUM_CPUS=$(nproc --all)
ethtool -L eth0 combined $NUM_CPUS
# 3. IRQ 어피니티 설정 — 큐 N → CPU N
for q in $(seq 0 $((NUM_CPUS-1))); do
irq=$(grep "eth0-$q\|mlx5_comp${q}" /proc/interrupts \
| awk -F: '{print $1}' | tr -d ' ' | head -1)
[ -n "$irq" ] && echo $((1 << q)) > /proc/irq/$irq/smp_affinity
done
# 4. XPS (Transmit Packet Steering) 설정 — TX 큐 N → CPU N
for q in $(seq 0 $((NUM_CPUS-1))); do
echo $((1 << q)) > /sys/class/net/eth0/queues/tx-$q/xps_cpus
done
# 5. RPS 비활성화 (HW RSS 사용 시 SW RPS 불필요)
for q in /sys/class/net/eth0/queues/rx-*/rps_cpus; do
echo 0 > "$q"
done
# 6. 대칭 해시 검증
# 동일 5-tuple의 forward/return이 같은 큐로 수신되는지 확인
ethtool -S eth0 | grep "rx_queue_[0-9]*_packets"
| 설정 | ethtool 명령 | 대상 | NGFW 권장값 |
|---|---|---|---|
| 해시 함수 | ethtool -X eth0 hfunc xor |
HW (NIC ASIC) | XOR 또는 대칭 Toeplitz |
| 인다이렉션 테이블 | ethtool -X eth0 equal N |
HW | CPU 코어 수와 동일 |
| 해시 키 | ethtool -X eth0 hkey ... |
HW | 대칭 해시 키 (XOR 사용 시 불필요) |
| 해시 입력 필드 | ethtool -N eth0 rx-flow-hash tcp4 sdfn |
HW | L3+L4 (src/dst IP + src/dst 포트) |
| 채널 수 | ethtool -L eth0 combined N |
HW | nproc 결과와 동일 |
| 대칭 RSS Private Flag | ethtool --set-priv-flags eth0 symmetric_rss on |
HW | on (지원 드라이버) |
실전 디버깅 및 트러블슈팅
NGFW HW 오프로드 환경에서 성능 저하, 패킷 드롭, 규칙 미적용 등의 문제가 발생할 수 있습니다. 체계적인 디버깅 프로세스를 통해 문제를 빠르게 식별하고 해결하는 것이 중요합니다.
오프로드 상태 확인
가장 먼저 확인할 것은 TC flower 규칙이 실제로 HW에 설치되었는지 여부입니다. in_hw 플래그와 in_hw_count로 확인합니다.
## 1단계: TC 규칙 오프로드 상태 확인
tc -s filter show dev eth0 ingress
# 핵심 확인 항목:
# in_hw → HW에 설치됨 (정상)
# in_hw_count 2 → 2개 NIC에 설치 (bond 환경)
# not_in_hw → HW 미설치 (SW 폴백 중)
# HW 오프로드 규칙만 필터링
tc -s filter show dev eth0 ingress | grep -A5 "in_hw"
tc -s filter show dev eth0 ingress | grep -c "not_in_hw"
## 2단계: eSwitch 모드 확인
devlink dev eswitch show pci/0000:03:00.0
# mode switchdev ← TC 오프로드 필수 모드
# mode legacy ← 오프로드 불가
## 3단계: HW 오프로드 피처 플래그 확인
ethtool -k eth0 | grep -E "hw-tc-offload|switchdev"
# hw-tc-offload: on ← TC 오프로드 활성화 필수
# hw-tc-offload 활성화 (비활성 시)
ethtool -K eth0 hw-tc-offload on
패킷 드롭 원인 진단
패킷 드롭이 발생할 때 NIC HW 드롭과 SW 드롭을 구분하는 것이 중요합니다. HW 드롭은 ASIC 레벨에서 발생하며, SW 드롭은 커널 스택에서 발생합니다.
## HW 드롭 카운터 확인
ethtool -S eth0 | grep -iE "drop|discard|error|no_buf|overflow"
# rx_out_of_buffer: 0 ← NIC RX 링 버퍼 부족
# rx_if_down_packets: 0 ← 인터페이스 다운 시 수신
# tx_errors_phy: 0 ← PHY 계층 오류
# rx_discards_phy: 0 ← PHY 폐기
# rx_pci_signal_integrity: 0 ← PCIe 오류
# rx_steer_missed_packets: 0 ← 플로우 스티어링 미스
## SW 드롭 확인 — dropwatch
dropwatch -l kas
# Initalizing kallsyms db
# start
# 1 drops at nf_hook_slow+0xa4 (0xffffffff816ae5a4)
# 3 drops at __netif_receive_skb_core+0x123 (0xffffffff8169a123)
## perf trace 기반 드롭 추적
perf trace --no-syscalls -e 'skb:kfree_skb' --duration 5000
# kfree_skb: skbaddr=0xff... protocol=0x0800 location=nf_hook_slow
## nftables/iptables 드롭 카운터
nft list ruleset | grep -A1 "counter"
iptables -L -v -n | grep DROP
성능 병목 식별
NGFW 성능 병목은 HW 자원 포화, CPU 과부하, PCIe 대역폭 한계 중 하나에서 발생합니다. 체계적으로 확인하여 병목 지점을 식별합니다.
## CPU 병목 확인
mpstat -P ALL 1 5
# CPU %usr %sys %sirq %idle
# 0 2.0 5.0 45.0 48.0 ← softirq 높음 → RSS 불균형
# 1 2.0 5.0 10.0 83.0
# softirq(%sirq) > 30%인 CPU → 해당 큐 과부하
# 인터럽트 분포 확인
watch -n1 'cat /proc/interrupts | grep eth0'
## ASIC 자원 포화 확인
devlink resource show pci/0000:03:00.0
# 80% 이상 사용 자원이 있으면 병목 가능
## PCIe 대역폭 확인
lspci -s 03:00.0 -vvv | grep -E "LnkSta|Width|Speed"
# LnkSta: Speed 16GT/s, Width x16 ← PCIe Gen4 x16 = 32GB/s
# Gen3 x8 = 8GB/s → 100GbE 병목 가능
## conntrack 테이블 포화 확인
conntrack -C
sysctl net.netfilter.nf_conntrack_max
# count가 max의 80% 이상이면 확장 필요
## 종합 진단 스크립트
echo "=== TC 규칙 오프로드 현황 ==="
total=$(tc filter show dev eth0 ingress 2>/dev/null | grep -c "filter protocol")
in_hw=$(tc filter show dev eth0 ingress 2>/dev/null | grep -c "in_hw\b")
echo "전체: $total, HW: $in_hw, SW: $((total - in_hw))"
echo "=== ASIC 자원 사용률 ==="
devlink resource show pci/0000:03:00.0 2>/dev/null | awk '
/occ/ {
match($0, /name ([a-z_]+)/, nm);
match($0, /size ([0-9]+)/, sz);
match($0, /occ ([0-9]+)/, oc);
if (sz[1]+0 > 0) printf " %-20s %6d / %6d (%d%%)\n",
nm[1], oc[1]+0, sz[1]+0, (oc[1]+0)*100/(sz[1]+0)
}'
echo "=== HW 드롭 카운터 ==="
ethtool -S eth0 2>/dev/null | grep -iE "drop|discard|no_buf" | grep -v ": 0$"
echo "=== conntrack 사용률 ==="
ct_count=$(conntrack -C 2>/dev/null || echo 0)
ct_max=$(sysctl -n net.netfilter.nf_conntrack_max 2>/dev/null || echo 0)
echo " $ct_count / $ct_max ($((ct_count * 100 / (ct_max + 1)))%)"
자주 발생하는 문제 체크리스트
| 증상 | 확인 명령어 | 원인 | 해결 방법 |
|---|---|---|---|
TC 규칙이 not_in_hw |
tc -s filter show dev eth0 ingress |
hw-tc-offload 비활성화 | ethtool -K eth0 hw-tc-offload on |
TC 규칙이 not_in_hw |
devlink dev eswitch show |
eSwitch가 legacy 모드 | devlink dev eswitch set mode switchdev |
새 규칙 설치 실패 (-ENOSPC) |
devlink resource show |
ASIC 자원 포화 | 타임아웃 단축, 자원 재배분 |
| 특정 CPU softirq 100% | mpstat -P ALL 1 |
RSS 불균형 / 비대칭 해시 | 대칭 RSS 활성화, 채널 수 조정 |
| HW 오프로드 후 패킷 드롭 | ethtool -S eth0 | grep drop |
RX 링 버퍼 부족 | ethtool -G eth0 rx 8192 |
| conntrack OFFLOAD 표시 안됨 | conntrack -L | grep OFFLOAD |
flowtable 미설정 | nft flowtable + flags offload 설정 |
| bond 멤버에 규칙 미적용 | tc filter show block 1 ingress |
shared block 미설정 | tc qdisc add dev bond0 ingress_block 1 clsact |
| VXLAN 터널 오프로드 실패 | ethtool -k eth0 | grep udp_tnl |
UDP 터널 오프로드 비활성화 | ethtool -K eth0 tx-udp_tnl-segmentation on |
| HW 통계가 0으로 표시 | tc -s filter show | grep hw_stats |
카운터 풀 고갈 | 불필요한 카운터 해제, 카운터 풀 확장 |
| NIC 펌웨어 충돌 | devlink health show |
FW 버그 또는 자원 누수 | FW 업그레이드, devlink health recover |
커널 트레이싱으로 오프로드 경로 추적
ftrace와 bpftrace를 사용하여 TC flower 오프로드의 커널 내부 경로를 실시간으로 추적할 수 있습니다. 오프로드 실패의 정확한 원인 함수를 식별하는 데 유용합니다.
# ftrace: TC flower 오프로드 경로 추적
echo 'nop' > /sys/kernel/debug/tracing/current_tracer
echo 1 > /sys/kernel/debug/tracing/events/net/net_dev_xmit/enable
# TC flower 관련 함수 트레이싱
echo 'fl_hw_replace_filter' >> /sys/kernel/debug/tracing/set_ftrace_filter
echo 'mlx5e_configure_flower' >> /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
# bpftrace: 오프로드 성공/실패 실시간 모니터링
bpftrace -e '
kretprobe:fl_hw_replace_filter {
printf("TC offload %s: ret=%d\n",
comm, retval);
}'
# bpftrace: 플로우 카운터 폴링 주기 확인
bpftrace -e '
kprobe:mlx5_fc_stats_work {
printf("FC stats poll at %llu\n", nsecs);
}'
참고자료
- Linux Kernel Documentation: switchdev — Switch Device Abstraction
- Linux Kernel Documentation: TC Actions
- Linux Kernel Documentation: devlink
- Linux Kernel Documentation: Port Representors
- Linux Kernel Documentation: Netdev Features
- Linux Kernel: TC conntrack action
- NGFW 하드웨어 오프로드 — 오프로드 아키텍처 3대 유형, Fast/Slow/Exception 경로
- TC (Traffic Control) — 트래픽 제어 프레임워크 기초
- eSwitch — 임베디드 스위치 아키텍처
- BPF/XDP — eXpress Data Path 고성능 패킷 처리