소프트스위치(p4 bmv2)를 통해 veth 쌍으로 상호 연결된 두 개의 네임스페이스 srv1과 srv2가 있습니다. Softswitch는 단순 전달만 수행합니다. 네임스페이스 내의 veth 인터페이스에는 IP 주소(각각 192.168.1.1 및 192.168.1.2)가 할당됩니다. 다음 IP 주소를 사용하여 두 네임스페이스 간에 ping을 수행할 수 있습니다.
sudo ip netns exec srv1 ping 192.168.1.2
PING 192.168.1.2 (192.168.1.2) 56(84) bytes of data.
64 bytes from 192.168.1.2: icmp_seq=1 ttl=64 time=1.03 ms
64 bytes from 192.168.1.2: icmp_seq=2 ttl=64 time=1.04 ms
하지만 netcat을 시도하면 서버 측에서 메시지가 표시되지 않습니다.
고객:
sudo ip netns exec srv1 netcat 192.168.1.2 80 -u
hello!
섬기는 사람:
sudo ip netns exec srv2 netcat -l 80 -u
인터페이스는 올바른 형식의 패킷을 수신합니다. 두 네임스페이스 모두에서 tcpdump를 사용하여 확인하고 패킷이 올바르게 전송되고 수신되는 것을 확인했습니다.
고객:
sudo ip netns exec srv1 tcpdump -XXvv -i srv1p
tcpdump: listening on srv1p, link-type EN10MB (Ethernet), capture size 262144 bytes
^C06:09:41.088601 IP (tos 0x0, ttl 64, id 14169, offset 0, flags [DF], proto UDP (17), length 35)
192.168.1.1.55080 > 192.168.1.2.http: [bad udp cksum 0x8374 -> 0x5710!] UDP, length 7
0x0000: 00aa bbcc dd02 00aa bbcc dd01 0800 4500 ..............E.
0x0010: 0023 3759 4000 4011 801d c0a8 0101 c0a8 .#7Y@.@.........
0x0020: 0102 d728 0050 000f 8374 6865 6c6c 6f21 ...(.P...thello!
0x0030: 0a .
1 packet captured
1 packet received by filter
0 packets dropped by kernel
섬기는 사람:
sudo ip netns exec srv2 tcpdump -XXvv -i srv2p
tcpdump: listening on srv2p, link-type EN10MB (Ethernet), capture size 262144 bytes
^C06:09:41.089232 IP (tos 0x0, ttl 64, id 14169, offset 0, flags [DF], proto UDP (17), length 35)
192.168.1.1.55080 > 192.168.1.2.http: [bad udp cksum 0x8374 -> 0x5710!] UDP, length 7
0x0000: 00aa bbcc dd02 00aa bbcc dd01 0800 4500 ..............E.
0x0010: 0023 3759 4000 4011 801d c0a8 0101 c0a8 .#7Y@.@.........
0x0020: 0102 d728 0050 000f 8374 6865 6c6c 6f21 ...(.P...thello!
0x0030: 0a .
1 packet captured
1 packet received by filter
0 packets dropped by kernel
포트 80에서 UDP 패킷을 허용하도록 srv2 iptable 규칙을 추가하고 기록했습니다.
sudo ip netns exec srv2 iptables -t filter -A INPUT -p udp --dport 80 -j ACCEPT
sudo ip netns exec srv2 iptables -I INPUT -p udp --dport 80 -j LOG --log-prefix " IPTABLES " --log-level=debug
항목이 증가하고 패킷이 /var/log/kern.log에 기록되는 통계를 볼 수 있지만 메시지는 netcat의 청취 소켓에 도달하지 않습니다.
sudo ip netns exec srv2 iptables -L -n -v
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
1 33 LOG udp -- * * 0.0.0.0/0 0.0.0.0/0 udp dpt:80 LOG flags 0 level 7 prefix " IPTABLES "
4 133 ACCEPT udp -- * * 0.0.0.0/0 0.0.0.0/0 udp dpt:80
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
커널 로그:
kernel: [581970.306032] IPTABLES IN=srv2p OUT= MAC=00:aa:bb:cc:dd:02:00:aa:bb:cc:dd:01:08:00 SRC=192.168.1.1 DST=192.168.1.2 LEN=33 TOS=0x00 PREC=0x00 TTL=64 ID=51034 DF PROTO=UDP SPT=48784 DPT=80 LEN=13
소프트스위치를 브리지로 교체하자 netcat이 작동했습니다. 소프트스위치가 패킷을 손상시켰을 수도 있다고 생각했는데 tcpdump가 올바른 형식을 보여주었습니다. UDP 체크섬은 올바르지 않지만 Linux 브리지를 사용할 때와 동일하지만 이 경우에는 작동하는 원본 서버에서 생성됩니다. 이러한 패킷이 netcat 서버에 도달하지 못하는 이유를 알 수 있는 방법이 있습니까?
편집: 댓글에서 요청한 추가 정보는 다음과 같습니다.
$ sudo ip netns exec srv1 ip -br link
lo DOWN 00:00:00:00:00:00 <LOOPBACK>
srv1p@if2948 UP 00:aa:bb:cc:dd:01 <BROADCAST,MULTICAST,UP,LOWER_UP>
$ sudo ip netns exec srv2 ip -br link
lo DOWN 00:00:00:00:00:00 <LOOPBACK>
srv2p@if2944 UP 00:aa:bb:cc:dd:02 <BROADCAST,MULTICAST,UP,LOWER_UP>
$ sudo ip netns exec srv1 ip route
192.168.1.0/24 dev srv1p proto kernel scope link src 192.168.1.1
$ sudo ip netns exec srv2 ip route
192.168.1.0/24 dev srv2p proto kernel scope link src 192.168.1.2
$ sudo ip netns exec srv2 ip neighbour
192.168.1.7 dev srv2p lladdr 00:aa:bb:cc:dd:0d STALE
192.168.1.4 dev srv2p lladdr 00:aa:bb:cc:dd:06 STALE
192.168.1.8 dev srv2p lladdr 00:aa:bb:cc:dd:0e STALE
192.168.1.6 dev srv2p lladdr 00:aa:bb:cc:dd:0a STALE
192.168.1.1 dev srv2p lladdr 00:aa:bb:cc:dd:01 STALE
192.168.1.3 dev srv2p lladdr 00:aa:bb:cc:dd:05 STALE
192.168.1.5 dev srv2p lladdr 00:aa:bb:cc:dd:09 STALE
$ sudo ip netns exec srv1 ip neighbour
192.168.1.8 dev srv1p lladdr 00:aa:bb:cc:dd:0e STALE
192.168.1.4 dev srv1p lladdr 00:aa:bb:cc:dd:06 STALE
192.168.1.2 dev srv1p lladdr 00:aa:bb:cc:dd:02 STALE
192.168.1.7 dev srv1p lladdr 00:aa:bb:cc:dd:0d STALE
192.168.1.5 dev srv1p lladdr 00:aa:bb:cc:dd:09 STALE
192.168.1.3 dev srv1p lladdr 00:aa:bb:cc:dd:05 STALE
192.168.1.6 dev srv1p lladdr 00:aa:bb:cc:dd:0a STALE
$ /sbin/sysctl -ar '\.rp_filter'
net.ipv4.conf.all.rp_filter = 2
net.ipv4.conf.default.rp_filter = 2
net.ipv4.conf.docker0.rp_filter = 0
net.ipv4.conf.eth0.rp_filter = 0
net.ipv4.conf.lo.rp_filter = 0
net.ipv4.conf.veth0b5517e.rp_filter = 2
net.ipv4.conf.veth5c69974.rp_filter = 2
net.ipv4.conf.veth6c63fa9.rp_filter = 2
net.ipv4.conf.veth87b4442.rp_filter = 2
net.ipv4.conf.vethaecf041.rp_filter = 2
net.ipv4.conf.vethc9014e5.rp_filter = 2
net.ipv4.conf.vethf280de4.rp_filter = 2
net.ipv4.conf.vethf442944.rp_filter = 2
답변1
문제는 UDP 체크섬과 관련이 있습니다. 이러한 패킷은 UDP 체크섬이 잘못된 netcat에 의해 생성되며 이를 무시하도록 커널에 플래그가 설정되어 있습니다. 패킷이 커널 공간에 유지되기 때문에 Linux 브리지와 함께 작동하지만 소프트 스위치를 통과하면 패킷이 사용자 공간으로 이동하여 잘못된 체크섬의 초기 플래그를 무시하지 않고 커널에 다시 삽입되므로 삭제됩니다.
이는 인터페이스의 체크섬 오프로딩으로 해결됩니다.
/sbin/ethtool --offload $intf tx off
/sbin/ethtool --offload $intf rx off