26A21a

Young-Kyoo Kim·2026년 4월 20일

제공해주신 pwru 트레이스 분석 결과와 상황을 종합해 볼 때, 이전 모델의 분석은 커널 내부의 흐름(Function Call Path) 관점에서는 정확하지만, 인프라 운영 측면에서는 '왜' 이런 일이 발생하는지에 대한 근본 원인(Root Cause)을 더 좁힐 필요가 있습니다.

플랫폼 엔지니어링 리드로서 대규모 클러스터를 운영하시는 상황임을 고려하여, 실무적인 관점에서 다음과 같이 판단하고 추가 조언을 드립니다.


1. 분석 결과에 대한 제 판단

이전 모델의 분석 중 tcp_check_req에서 드랍된다는 점이 핵심입니다. 이 단계는 TCP Handshake 과정에서 SYN을 받고 SYN-ACK을 보낸 후, 클라이언트로부터 오는 마지막 ACK를 검증하는 단계입니다. 여기서 드랍된다는 것은 서버가 "나는 이 ACK를 받을 준비가 안 됐거나, 기대하던 ACK가 아니다"라고 판단한 것입니다.

tcpdump에는 안 찍힐까? (중요)

pwru에는 찍히는데 tcpdump에 안 찍히는 이유는 크게 두 가지입니다.

  • Capture Point의 차이: tcpdump(libpcap)는 보통 NIC 드라이버 레벨에서 패킷을 가로챕니다. 반면 pwru는 커널 함수에 직접 훅을 겁니다. 패킷이 물리 NIC로 들어왔더라도 Bonding, VLAN, 혹은 Cilium의 eBPF 프로그램이 패킷을 처리하는 방식에 따라 tcpdump가 바라보는 인터페이스에는 패킷이 통과하지 않을 수 있습니다.
  • Cilium의 BPF Host Routing: Cilium이 bpf-host-routing을 사용 중이라면 일반적인 네트워킹 스택을 우회(Bypass)하여 스택의 더 깊은 곳으로 바로 패킷을 주입할 수 있습니다.

2. 예상되는 근본 원인 (Best Guess)

단순히 "상태 불일치"를 넘어, 실제 환경에서 흔히 발생하는 시나리오는 다음과 같습니다.

① MTU 및 패킷 파편화 (Fragmentation) 문제

SSH 연결 시 SYN, SYN-ACK까지는 크기가 작아 잘 넘어가다가, 세션 수립 직후나 특정 데이터가 실린 ACK 패킷이 MTU 제한으로 인해 조각나거나 드랍될 때 tcp_check_req에서 문제가 발생할 수 있습니다.

  • Cilium 환경 특이점: VXLAN이나 Geneve 터널링을 사용 중이라면 오버헤드(50 bytes+) 때문에 실제 MTU가 1450 이하로 설정되어야 합니다.

② 클러스터 외부 Load Balancer / Proxy의 Idle Timeout

간헐적으로 발생한다면, 서버(수신측)의 request_sock(SYN을 받고 기다리는 소켓)이 타임아웃되어 삭제된 후에 클라이언트의 ACK가 도착했을 가능성이 큽니다.

  • 네트워크 지연(Latency)이 순간적으로 튀거나, 중간 경로(L4, Firewall)에서 세션을 먼저 끊어버린 경우입니다.

③ Cilium의 Conntrack Table Full 또는 충돌

Cilium은 자체적인 eBPF 기반 conntrack 테이블을 관리합니다. 커널의 tcp_check_req와 Cilium의 상태 관리가 어긋날 때(예: 비대칭 라우팅) 드랍이 발생할 수 있습니다.


3. 정확한 진단을 위해 더 필요한 정보

더 명확한 답을 드리기 위해 다음 정보가 필요합니다.

  1. 통신 경로: 클라이언트와 서버가 같은 K8s 노드에 있나요? 아니면 외부에서 노드로 들어오는 상황인가요? (LB 통과 여부)
  2. Cilium 설정: native-routing인가요, 아니면 tunnel(VXLAN/Geneve) 모드인가요?
  3. 드랍된 패킷의 상세 정보: pwru 실행 시 -sh (show help) 옵션 등을 활용해 드랍된 패킷의 TCP Flags(ACK인지 RST인지)Sequence Number를 확인할 수 있나요?
  4. 수신측 노드의 자원 상황: 드랍 발생 시점에 해당 노드의 CPU 사용량(특히 SoftIRQ)이 급증하지는 않았나요?

4. 추천하는 후속 조치 (Action Items)

이전 답변에서 제안한 cat /proc/net/bonding/bond1 확인 외에 다음을 먼저 시도해 보세요.

  1. 인터페이스 전체 캡처:
    tcpdump -i any port 22 -nnvv로 캡처해 보시고, 그래도 안 나온다면 eth0, eth1 등 물리 슬레이브 인터페이스 각각을 지정해서 다시 확인해 보세요.
  2. Cilium 상태 확인:
    cilium monitor --type drop
    # 혹은 특정 IP에 대해
    cilium monitor --related-to <클라이언트_IP>
    Cilium 레벨에서 policy deniedct_trunc 등의 드랍 사유가 찍히는지 확인해야 합니다.
  3. 커널 메트릭 확인:
    netstat -s | grep -i drop 혹은 nstat -az | grep -i TcpExtListenDrops 명령어를 통해 커널 스택 수준의 드랍 카운트가 올라가는지 보십시오.

제 판단은 이렇습니다: "이것은 단순한 설정 오류라기보다, 네트워크 경로상의 MTU 불일치비대칭 라우팅(Asymmetric Routing)으로 인해 커널이 유효하지 않은 ACK를 받았다고 판단했을 확률이 90% 이상입니다."

추가 정보를 주시면 더 구체적으로 디버깅해 드릴 수 있습니다. 어떻게 진행해 볼까요?

===

추가 정보 감사합니다. Native Routing을 사용 중이고 Cilium monitor drop에 아무것도 찍히지 않는다면, 이는 Cilium의 BPF Datapath(보안 정책, 라우팅 로직 등) 문제가 아니라 리눅스 커널의 표준 TCP 스택 수준에서 패킷이 거부되고 있음을 강력하게 시사합니다.

pwru 트레이스에서 tcp_check_req 단계에서 드랍이 발생한다는 것은, 커널이 TCP Handshake의 마지막 단계인 ACK 패킷을 받았으나 이를 유효한 연결 요청으로 인정하지 않았다는 뜻입니다. L3 스위치만 있는 환경에서 발생할 수 있는 구체적인 원인과 점검 포인트를 정리해 드립니다.

1. Cilium monitor에 왜 안 찍힐까?

Cilium Monitor는 eBPF 프로그램이 명시적으로 drop 결정을 내릴 때(예: Policy Denied, LB 관련 오류 등) 이벤트를 발생시킵니다. 하지만 현재 상황은 패킷이 Cilium의 BPF 로직을 무사히 통과하여 커널의 TCP 서브시스템(tcp_v4_rcv)으로 전달된 후, 커널 함수 내부 검증 로직에서 드랍된 것이기 때문에 Cilium 레벨의 로그에는 남지 않는 것이 정상입니다.


2. tcp_check_req 드랍의 핵심 원인 분석

이 단계에서 패킷이 버려지는 가장 흔한 이유는 다음과 같습니다.

수신측 노드에 순간적으로 많은 연결 요청이 들어와 SYN Queue가 가득 찼을 때, 커널은 SYN Cookie를 발행합니다. 클라이언트가 보낸 ACK 패킷에 포함된 쿠키 값이 서버의 계산 결과와 일치하지 않으면 tcp_check_req에서 드랍됩니다.

  • 확인 방법: sysctl net.ipv4.tcp_syncookies 값이 1인지 확인하고, nstat -az | grep -i SyncookiesFailed 카운트가 올라가는지 보십시오.

② Request Sock 타임아웃 (ListenDrops)

서버가 SYN을 받고 SYN-ACK를 보낸 뒤 클라이언트의 ACK를 기다리는 동안 사용하는 것이 request_sock입니다. 네트워크 지연(L3 스위치 구간의 일시적 혼잡 등)으로 인해 클라이언트의 ACK가 너무 늦게 도착하여 서버 쪽의 대기 시간이 만료되면, 커널은 이 패킷을 "알 수 없는 연결의 ACK"로 취급하여 버립니다.

  • 확인 방법: nstat -az | grep -i TcpExtListenDrops 또는 TcpExtTCPMinisocksDrop 카운트를 확인하십시오.

③ 비대칭 라우팅 (Asymmetric Routing) 및 rp_filter

Native Routing 환경에서 L3 스위치가 ECMP 등으로 인해 나가는 경로와 들어오는 경로를 다르게 잡을 수 있습니다. 만약 패킷이 서버에 들어올 때 예상치 못한 인터페이스(예: bond1이 아닌 다른 인터페이스)로 들어오면 커널의 rp_filter가 작동하여 드랍될 수 있습니다.

  • 확인 방법: sysctl -a | grep rp_filter 값이 1(Strict)인지 확인해 보십시오. 테스트를 위해 임시로 0으로 설정하고 현상이 재발하는지 확인해 볼 수 있습니다.

3. 추가 진단을 위한 가이드

현재 상황에서 문제를 확정 짓기 위해 다음을 실행해 보시길 권장합니다.

  1. 커널 정밀 통계 확인 (가장 추천)
    문제가 발생한 직후 다음 명령어를 실행하여 어떤 카운터가 올라가는지 확인하십시오.

    nstat -az | grep -E 'TcpExtListenDrops|TcpExtTCPMinisocksDrop|Syncookies|TcpExtTCPACKSkipped'
  2. 물리 인터페이스 직접 캡처
    tcpdump -i any 보다는 물리 NIC(예: ens...)를 각각 지정해서 캡처해 보십시오. L3 스위치에서 오는 패킷이 본딩된 슬레이브 중 어느 쪽으로 들어오는지, 그리고 그 패킷의 Sequence NumberACK Number가 서버가 보낸 SYN-ACK와 일치하는지 대조해야 합니다.

  3. MTU 확인
    Native Routing이라도 하단 물리 망의 MTU가 1500 미만으로 설정된 구간이 있다면, SSH 인증 과정에서 큰 패킷이 오갈 때 tcp_check_req 이후 단계에서 문제가 될 수 있습니다. (다만, 현재 pwru상 드랍 지점은 Handshake 단계에 더 가깝습니다.)

결론적으로 제 판단은:
방화벽이 없는 Native Routing 환경이므로, "L3 스위치 구간의 일시적 지연으로 인한 SYN 대기 소켓(request_sock) 타임아웃" 또는 "커널의 SYN Cookie 오작동"일 가능성이 가장 높습니다.

위의 nstat 결과값 중 카운트가 유독 높은 항목이 있다면 알려주세요. 바로 다음 단계를 짚어드리겠습니다.

===


1 텍스트

이번 트레이스는 같은 플로우(10.111.43.21:11180 -> 10.111.43.38:22)에 대해 “PREROUTING/LOCAL_IN(넷필터) -> 라우팅/소스검증 -> 로컬 딜리버리 -> RAW 소켓 검사 -> TCP 수신 -> 요청 검증(tcp_check_req) -> 드롭”까지의 세부 경로를 보여줍니다. 핵심은 마지막에 TCP 계층에서 해당 패킷이 처리 중 “요청 검증 단계에서 드롭”되었다는 점입니다.

핵심 흐름 해석

  • nf_hook_slow -> nf_checksum/nf_ip_checksum
    • 넷필터 훅(주로 PREROUTING/LOCAL_IN)에서 체크섬 검사를 포함한 기본 검증을 수행. 여기서 DROP된 흔적은 보이지 않습니다.
  • tcpv4_early_demux -> ip_route_input{noref,slow} -> fib_validate_source/_fib_validate_source
    • 라우팅 결정 및 소스 유효성 검증(RP 필터 경로). 통과했기 때문에 이후 로컬 딜리버리로 진행됩니다.
  • ip_local_deliver -> ip_local_deliver_finish -> ip_protocol_deliver_rcu
    • 로컬 호스트(10.111.43.38) 대상 패킷으로 확정되어 상위(TCP)로 전달.
  • raw_local_deliver/raw_v4_input
    • RAW 소켓이 붙어 있다면 먼저 전달. 이어서 TCP로 진입.
  • sk_filter_trim_cap -> security_sock_rcv_skb -> selinux_socket_sock_rcv_skb -> bpf_lsm_socket_sock_rcv_skb
    • 소켓 레벨의 BPF/LSM/SELinux 훅 및 소켓 필터가 실행. 여기서 거부 흔적은 보이지 않습니다.
  • tcp_v4_rcv -> tcp_v4_fill_cb -> tcp_check_req
    • TCP 제어블록 설정 후, “요청 검증” 경로로 진입. 이는 보통 다음 두 경우에 해당:
    • LISTEN 중인 소켓이 받은 SYN에 대해 생성된 request_sock에 대해 후속 패킷(주로 ACK)을 검증할 때
    • SYN cookies/백로그/상태 일치 여부 등 조건을 확인
  • skskb_reason_drop(SKB_DROP_REASON_NOT_SPECIFIED) -> skb_release* -> kfree_skbmem
    • 검증 단계에서 조건 불일치 혹은 처리 불가로 판단되어 TCP가 skb를 드롭하고 메모리를 해제함을 의미합니다.

2 텍스트

무엇이 드롭을 유발했을 가능성이 큰가?

  • tcp_check_req 단계에서의 드롭 원인 후보:
    • 예상치 못한 ACK/RST: 기존 요청(request_sock)과 매칭되지 않는 ACK(예: 초과 지연, 틀린 ISN/윈도우, 이미 타임아웃 등)
    • SYN cookie 검증 실패: SYN cookies 사용 시, 이후 ACK가 쿠키 조건과 맞지 않으면 드롭
    • 백로그/큐 상태 문제로 요청이 소멸된 뒤 도착한 후속 패킷(ACK) -> 매칭 실패로 드롭
    • 중복/재전송 상황에서 윈도우/상태 불일치
  • 킬러 단서:
    • 이전에 60바이트(SYN+옵션) 패킷이 보였고, 여기서는 20바이트(옵션 없는) 패킷이 관찰됩니다. 20바이트는 “순수 ACK” 혹은 “RST”일 확률이 큽니다. 이 순수 ACK가 기존 요청과 맞지 않으면 tcp_check_req에서 드롭되는 전형적인 패턴과 부합합니다.

중요한 점

  • 넷필터(nf_hook_slow)나 SELinux/BPF 훅에서 DROP된 흔적은 없고, 최종적으로 TCP 레이어에서 드롭되었습니다.
  • 즉, 방화벽/SELinux 차단이 아니라 “TCP 상태/요청 매칭 불일치” 계열의 이유로 커널 TCP가 폐기한 것으로 해석하는 것이 타당합니다.
  • cpuidle_enter/do_idle 계열 콜스택 항목들은 인터럽트/소프트IRQ 진입 전/후의 CPU 아이들 경로로, 패킷 처리 자체의 성공/실패와 직접적인 상관은 없습니다.

진단을 확정하려면 필요한 것

  • 패킷 플래그/시퀀스 확인
    • tcpdump/pcap으로 해당 시간대 플래그와 시퀀스/ACK 번호를 확인하면 원인 판별이 빨라집니다.
    • 예: tcpdump -i bond1 -nnvv 'host 10.111.43.21 and port 22'
    • 확인 포인트: SYN -> SYN-ACK -> ACK의 3차 핸드셰이크가 완결되는지, ACK 번호가 합당한지, RST가 오는지.
  • SYN cookies/백로그 상태
    • sysctl net.ipv4.tcp_syncookies 값 확인(1이면 활성).
    • 백로그: ss -lnt sport = :22로 큐 상태, somaxconn, tcp_max_syn_backlog 설정 확인.

3 텍스트

  • conntrack/상태 관찰
    • conntrack -L | grep '10.111.43.21.*22'로 세션 상태를 살펴보고, SYN-RECV/SYN-SENT/ESTABLISHED로 전이되는지 확인.
  • 서버/클라이언트 재전송/지연
    • RTT가 큰 환경이나 패킷 손실이 있을 경우, request_sock 타임아웃 이후 ACK 도착 -> 드롭 시나리오가 발생할 수 있습니다. 인터페이스/링크 오류 카운터(ethtool -S)도 점검.

정리

  • 이 트레이스 상의 패킷은 넷필터·SELinux를 통과해 TCP까지 왔지만, tcp_check_req 단계에서 조건 불일치로 드롭되었습니다.
  • 가장 가능성 높은 원인은 “예상과 맞지 않는 ACK(또는 상태 불일치)”이고, SYN cookie/백로그/타이밍 문제와 연관될 수 있습니다.
  • 패킷 캡처로 플래그/시퀀스, 시스템의 syncookies/백로그 설정, 그리고 네트워크 품질을 함께 확인하면 원인을 특정할 수 있습니다. 필요하시면 tcpdump 결과 일부(특히 SYN/SYN-ACK/ACK 시퀀스)와 sysctl -a | egrep 'tcp_syncookies|somaxconn|tcp_max_syn_backlog' 출력, ss -lnt sport = :22 결과를 공유해 주세요.

4 텍스트

상황 정리

  • 커널 트레이스상으로는 해당 패킷이 NIC -> 본딩 -> Netfilter(PREROUTING/LOCAL_IN) -> 라우팅/소스검증 -> TCP로 올라온 뒤, tcp_check_req 단계에서 드롭되었습니다.
  • 그런데 수신측에서 tcpdump가 “아무 것도 안 찍힌다”면, 보통은 캡처 인터페이스/네임스페이스/필터/오프로드 등의 이유로 캡처 지점에서 패킷을 못 보고 있을 가능성이 큽니다(실제로 패킷이 없는 상황이 아니라면).

왜 tcpdump가 안 보일 수 있나(가능성)
1) 본딩 인터페이스에서 캡처함

  • 리눅스 본딩(특히 active-backup 등) 환경에서는 RX 패킷이 물리 슬레이브에서 처리되고, 가상 인터페이스(bond1)에서 tcpdump가 잘 안 보이는 경우가 흔합니다.
  • 트레이스에 ens5f1np1:7와 bond1:2가 교차로 등장하므로, 실제 수신은 ens5f1np1(슬레이브)에서 이루어졌을 가능성이 큽니다.

2) 잘못된 캡처 인터페이스/네임스페이스

  • 컨테이너/네트워크 네임스페이스에서 tcpdump를 실행하면 호스트 NIC 트래픽이 안 보입니다.
  • VLAN이 사용되는데 bond1.\이 아닌 bond1에서 캡처하면 놓칠 수 있습니다.

3) 필터/오프로드 영향

  • VLAN 태그가 있는 경우 BPF 필터가 매칭을 놓칠 수 있습니다.
  • GRO/LRO 등으로 인해 세그먼트가 합쳐져 보이거나 체크섬 오프로딩이 표시를 왜곡할 수 있지만, SYN 자체가 “아예 안 보이는” 현상을 설명하진 못합니다. 다만 진단 시 혼동 요소이므로 필요시 비활성화 권고.

먼저 확인할 것

  • 현재 활성 슬레이브 확인:
cat /proc/net/bonding/bond1
  • 네임스페이스 확인(호스트에서 실행 중인지):
ip netns identify $$
  • VLAN 사용 여부:
ip -d link show bond1

권장 캡처 방법(하나씩 시도)
1) 슬레이브 NIC에서 캡처

sudo tcpdump -i ens5f1np1 -nnvv -Q in 'host 10.111.43.21 and port 22'
  • active-backup이면 활성 슬레이브에서만 보입니다. balance-xor/rr 등 LACP 모드에서도 RX는 특정 슬레이브로만 들어옵니다.

2) 모든 인터페이스에서 캡처(네임스페이스/인터페이스 문제 회피)

sudo tcpdump -i any -nnvv 'host 10.111.43.21 and port 22'

3) VLAN 가능성 고려(캡처 출력에 VLAN 헤더 표시)

sudo tcpdump -i ens5f1np1 -nnvv -e -Q in 'vlan and host 10.111.43.21 and port 22'

4) 패킷 손실/오프로드 혼선 최소화(임시)

# 필요 시 일시적으로만 비활성화(테스트 후 원복)
sudo ethtool -K ens5f1np1 gro off lro off gso off tso off rxhash off

5) 캡처를 파일로 저장해 사후 분석

sudo tcpdump -i ens5f1np1 -nn -s 0 -U -w /tmp/ssh_rx.pcap 'host 10.111.43.21 and port 22'

보조 진단

  • NIC 카운터 증가 여부(수신이 실제 들어오는지):
ethtool -S ens5f1np1 | egrep 'rx_.*pack|rx_.*err|rx_.*drop'
  • 커널 드롭 위치 추적(드롭워치):
sudo dropwatch -l kas
  • conntrack/핸드세이크 상태:
sudo conntrack -L | grep '10.111.43.21.*dport=22'

해석 가이드

  • 위 캡처 중 하나라도 SYN 또는 ACK가 보이면, 커널 트레이스와 일치합니다. 이후 SYN -> SYN-ACK -> ACK 흐름이 정상인지 확인하세요.
  • 여전히 아무 것도 안 보인다면:
    캡처를 실행하는 위치(호스트 vs 컨테이너/네임스페이스), 인터페이스 선택(특히 슬레이브 NIC), VLAN 인터페이스 여부가 가장 유력합니다.
    본딩 모드/슬레이브 상태와 일치하는 곳에서 캡처하는지 재확인해 주세요.
    필요하시면 현재 본딩 설정(cat /proc/net/bonding/bond1)과 실행 중인 tcpdump 명령 줄을 알려주세요. 환경에 맞춰 캡처 지점을 정확히 짚어 드리겠습니다.

0개의 댓글