Skip to content

Commit

Permalink
nsh: Add support to compose-packet and use it in system tests.
Browse files Browse the repository at this point in the history
OVS can parse NSH, but can't compose.  Fix that and get rid of plain
hex NSH packets in system tests as they are hard to read or modify.

Tcpdump calls modified to write actual pcaps instead of text output,
so ovs-pcap can be used while checking the results.

While at it, replacing sleeps with more robust waiting for tcpdump
to start listening.

M4 macros are better than shell variables, because we can see the
substitution result in the test log.  So, using m4_define and m4_join
extensively.

Acked-by: Simon Horman <[email protected]>
Acked-by: Eelco Chaudron <[email protected]>
Signed-off-by: Ilya Maximets <[email protected]>
  • Loading branch information
igsilya committed Jun 5, 2024
1 parent cd4ea33 commit ac4df0c
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 61 deletions.
18 changes: 18 additions & 0 deletions lib/flow.c
Original file line number Diff line number Diff line change
Expand Up @@ -3420,6 +3420,24 @@ flow_compose(struct dp_packet *p, const struct flow *flow,
arp->ar_sha = flow->arp_sha;
arp->ar_tha = flow->arp_tha;
}
} else if (flow->dl_type == htons(ETH_TYPE_NSH)) {
struct nsh_hdr *nsh;

nsh = dp_packet_put_zeros(p, sizeof *nsh);
dp_packet_set_l3(p, nsh);

nsh_set_flags_ttl_len(nsh, flow->nsh.flags, flow->nsh.ttl,
flow->nsh.mdtype == NSH_M_TYPE1
? NSH_M_TYPE1_LEN : NSH_BASE_HDR_LEN);
nsh->next_proto = flow->nsh.np;
nsh->md_type = flow->nsh.mdtype;
put_16aligned_be32(&nsh->path_hdr, flow->nsh.path_hdr);

if (flow->nsh.mdtype == NSH_M_TYPE1) {
for (size_t i = 0; i < 4; i++) {
put_16aligned_be32(&nsh->md1.context[i], flow->nsh.context[i]);
}
}
}

if (eth_type_mpls(flow->dl_type)) {
Expand Down
177 changes: 116 additions & 61 deletions tests/system-traffic.at
Original file line number Diff line number Diff line change
Expand Up @@ -8920,21 +8920,29 @@ dnl The flow will encap a nsh header to the TCP syn packet
dnl eth/ip/tcp --> OVS --> eth/nsh/eth/ip/tcp
AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 "table=0,priority=100,in_port=ovs-p0,ip,actions=encap(nsh(md_type=1)),set_field:0x1234->nsh_spi,set_field:0x11223344->nsh_c1,encap(ethernet),set_field:f2:ff:00:00:00:02->dl_dst,set_field:f2:ff:00:00:00:01->dl_src,ovs-p1"])

NETNS_DAEMONIZE([at_ns1], [tcpdump -l -n -xx -U -i p1 > p1.pcap], [tcpdump.pid])
sleep 1
NETNS_DAEMONIZE([at_ns1],
[tcpdump -l -n -xx -U -i p1 -w p1.pcap 2>tcpdump_err], [tcpdump.pid])
OVS_WAIT_UNTIL([grep "listening" tcpdump_err])

dnl The hex dump is a TCP syn packet. pkt=eth/ip/tcp
dnl The packet is sent from p0(at_ns0) interface directed to
dnl p1(at_ns1) interface
NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 f2 00 00 00 00 02 f2 00 00 00 00 01 08 00 45 00 00 28 00 01 00 00 40 06 b0 13 c0 a8 00 0a 0a 00 00 0a 04 00 08 00 00 00 00 c8 00 00 00 00 50 02 20 00 b8 5e 00 00 > /dev/null])
m4_define([TCP_SYN_PKT], [m4_join([,],
[eth_src=f2:00:00:00:00:01,eth_dst=f2:00:00:00:00:02,eth_type=0x0800],
[nw_src=192.168.0.10,nw_dst=10.0.0.10],
[nw_proto=6,nw_ttl=64,nw_frag=no],
[tcp_src=1024,tcp_dst=2048,tcp_flags=syn])])

dnl Check the expected nsh encapsulated packet on the egress interface
OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0000: *f2ff *0000 *0002 *f2ff *0000 *0001 *894f *0fc6" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0010: *0103 *0012 *34ff *1122 *3344 *0000 *0000 *0000" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0020: *0000 *0000 *0000 *f200 *0000 *0002 *f200 *0000" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0030: *0001 *0800 *4500 *0028 *0001 *0000 *4006 *b013" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0040: *c0a8 *000a *0a00 *000a *0400 *0800 *0000 *00c8" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0050: *0000 *0000 *5002 *2000 *b85e *0000" 2>&1 1>/dev/null])
dnl Send the TCP SYN packet from p0(at_ns0) interface directed to
dnl p1(at_ns1) interface.
NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
$(ovs-ofctl compose-packet --bare 'TCP_SYN_PKT')], [0], [ignore])

m4_define([NSH_HEADER], [m4_join([,],
[eth_src=f2:ff:00:00:00:01,eth_dst=f2:ff:00:00:00:02,eth_type=0x894f],
[nsh_ttl=63,nsh_np=3,nsh_spi=0x1234,nsh_si=255],
[nsh_mdtype=1,nsh_c1=0x11223344])])

OVS_WAIT_UNTIL([ovs-pcap p1.pcap | grep -q "m4_join([], [^],
$(ovs-ofctl compose-packet --bare 'NSH_HEADER'),
$(ovs-ofctl compose-packet --bare 'TCP_SYN_PKT'), [\$])"])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP
Expand All @@ -8952,19 +8960,31 @@ dnl The flow will decap a nsh header which in turn carries a TCP syn packet
dnl eth/nsh/eth/ip/tcp --> OVS --> eth/ip/tcp
AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 "table=0,priority=100,in_port=ovs-p0,dl_type=0x894f, actions=decap(),decap(), ovs-p1"])

NETNS_DAEMONIZE([at_ns1], [tcpdump -l -n -xx -U -i p1 > p1.pcap], [tcpdump.pid])
sleep 1
NETNS_DAEMONIZE([at_ns1],
[tcpdump -l -n -xx -U -i p1 -w p1.pcap 2>tcpdump_err], [tcpdump.pid])
OVS_WAIT_UNTIL([grep "listening" tcpdump_err])

dnl The hex dump is NSH packet with TCP syn payload. pkt=eth/nsh/eth/ip/tcp
dnl The packet is sent from p0(at_ns0) interface directed to
dnl p1(at_ns1) interface
NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 f2 ff 00 00 00 02 f2 ff 00 00 00 01 89 4f 02 06 01 03 00 00 64 03 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 f2 00 00 00 00 02 f2 00 00 00 00 01 08 00 45 00 00 28 00 01 00 00 40 06 b0 13 c0 a8 00 0a 0a 00 00 0a 04 00 08 00 00 00 00 c8 00 00 00 00 50 02 20 00 b8 5e 00 00 > /dev/null])
m4_define([TCP_SYN_PKT], [m4_join([,],
[eth_src=f2:00:00:00:00:01,eth_dst=f2:00:00:00:00:02,eth_type=0x0800],
[nw_src=192.168.0.10,nw_dst=10.0.0.10],
[nw_proto=6,nw_ttl=64,nw_frag=no],
[tcp_src=1024,tcp_dst=2048,tcp_flags=syn])])

m4_define([NSH_HEADER], [m4_join([,],
[eth_src=f2:ff:00:00:00:01,eth_dst=f2:ff:00:00:00:02,eth_type=0x894f],
[nsh_ttl=63,nsh_np=3,nsh_spi=0x1234,nsh_si=255],
[nsh_mdtype=1,nsh_c1=0x11223344])])

dnl Send the NSH packet with TCP SYN payload from p0(at_ns0) interface directed
dnl to p1(at_ns1) interface.
NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
"$(ovs-ofctl compose-packet --bare 'NSH_HEADER')" \
"$(ovs-ofctl compose-packet --bare 'TCP_SYN_PKT')"],
[0], [ignore])

dnl Check the expected de-capsulated TCP packet on the egress interface
OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0000: *f200 *0000 *0002 *f200 *0000 *0001 *0800 *4500" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0010: *0028 *0001 *0000 *4006 *b013 *c0a8 *000a *0a00" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0020: *000a *0400 *0800 *0000 *00c8 *0000 *0000 *5002" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0030: *2000 *b85e *0000" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([ovs-pcap p1.pcap | grep -q \
"^$(ovs-ofctl compose-packet --bare 'TCP_SYN_PKT')\$"])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP
Expand All @@ -8984,22 +9004,38 @@ dnl The flow will add another NSH header with nsh_spi=0x101, nsh_si=4,
dnl nsh_ttl=7 and change the md1 context
AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 "table=0,priority=100,in_port=ovs-p0,dl_type=0x894f,nsh_spi=0x100,nsh_si=0x03,actions=decap(),decap(),encap(nsh(md_type=1)),set_field:0x07->nsh_ttl,set_field:0x0101->nsh_spi,set_field:0x04->nsh_si,set_field:0x100f0e0d->nsh_c1,set_field:0x0c0b0a09->nsh_c2,set_field:0x08070605->nsh_c3,set_field:0x04030201->nsh_c4,encap(ethernet),set_field:f2:ff:00:00:00:02->dl_dst,set_field:f2:ff:00:00:00:01->dl_src,ovs-p1"])

NETNS_DAEMONIZE([at_ns1], [tcpdump -l -n -xx -U -i p1 > p1.pcap], [tcpdump.pid])
sleep 1
NETNS_DAEMONIZE([at_ns1],
[tcpdump -l -n -xx -U -i p1 -w p1.pcap 2>tcpdump_err], [tcpdump.pid])
OVS_WAIT_UNTIL([grep "listening" tcpdump_err])

dnl The hex dump is NSH packet with TCP syn payload. pkt=eth/nsh/eth/ip/tcp
dnl The nsh_ttl is 8, nsh_spi is 0x100 and nsh_si is 3
dnl The packet is sent from p0(at_ns0) interface directed to
dnl p1(at_ns1) interface
NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 f2 ff 00 00 00 02 f2 ff 00 00 00 01 89 4f 02 06 01 03 00 01 00 03 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 f2 00 00 00 00 02 f2 00 00 00 00 01 08 00 45 00 00 28 00 01 00 00 40 06 b0 13 c0 a8 00 0a 0a 00 00 0a 04 00 08 00 00 00 00 c8 00 00 00 00 50 02 20 00 b8 5e 00 00 > /dev/null])
m4_define([TCP_SYN_PKT], [m4_join([,],
[eth_src=f2:00:00:00:00:01,eth_dst=f2:00:00:00:00:02,eth_type=0x0800],
[nw_src=192.168.0.10,nw_dst=10.0.0.10],
[nw_proto=6,nw_ttl=64,nw_frag=no],
[tcp_src=1024,tcp_dst=2048,tcp_flags=syn])])

m4_define([NSH_HEADER_1], [m4_join([,],
[eth_src=f2:ff:00:00:00:01,eth_dst=f2:ff:00:00:00:02,eth_type=0x894f],
[nsh_ttl=8,nsh_np=3,nsh_spi=0x100,nsh_si=3,nsh_mdtype=1],
[nsh_c1=0x01020304,nsh_c2=0x05060708,nsh_c3=0x090a0b0c,nsh_c4=0x0d0e0f10])])

dnl Check the expected NSH packet with new fields in the header
OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0000: *f2ff *0000 *0002 *f2ff *0000* 0001 *894f *01c6" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0010: *0103 *0001 *0104 *100f *0e0d *0c0b *0a09 *0807" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0020: *0605 *0403 *0201 *f200 *0000 *0002 *f200 *0000" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0030: *0001 *0800 *4500 *0028 *0001 *0000 *4006 *b013" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0040: *c0a8 *000a *0a00 *000a *0400 *0800 *0000 *00c8" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0050: *0000 *0000 *5002 *2000 *b85e *0000" 2>&1 1>/dev/null])
dnl Send the NSH packet with TCP SYN payload from p0(at_ns0) interface directed
dnl to p1(at_ns1) interface.
dnl The nsh_ttl is 8, nsh_spi is 0x100 and nsh_si is 3.
NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
"$(ovs-ofctl compose-packet --bare 'NSH_HEADER_1')" \
"$(ovs-ofctl compose-packet --bare 'TCP_SYN_PKT')"],
[0], [ignore])

m4_define([NSH_HEADER_2], [m4_join([,],
[eth_src=f2:ff:00:00:00:01,eth_dst=f2:ff:00:00:00:02,eth_type=0x894f],
[nsh_ttl=7,nsh_np=3,nsh_spi=0x101,nsh_si=4,nsh_mdtype=1],
[nsh_c1=0x100f0e0d,nsh_c2=0x0c0b0a09,nsh_c3=0x08070605,nsh_c4=0x04030201])])

dnl Check the expected NSH packet with new fields in the header.
OVS_WAIT_UNTIL([ovs-pcap p1.pcap | grep -q "m4_join([], [^],
$(ovs-ofctl compose-packet --bare 'NSH_HEADER_2'),
$(ovs-ofctl compose-packet --bare 'TCP_SYN_PKT'), [\$])"])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP
Expand All @@ -9020,31 +9056,50 @@ dnl packet to to at_ns2.
AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 "table=0,priority=100,dl_type=0x894f,nsh_spi=0x100,nsh_si=0x02,actions=ovs-p1"])
AT_CHECK([ovs-ofctl -Oopenflow13 add-flow br0 "table=0,priority=100,dl_type=0x894f,nsh_spi=0x100,nsh_si=0x01,actions=ovs-p2"])

NETNS_DAEMONIZE([at_ns1], [tcpdump -l -n -xx -U -i p1 > p1.pcap], [tcpdump.pid])
NETNS_DAEMONIZE([at_ns2], [tcpdump -l -n -xx -U -i p2 > p2.pcap], [tcpdump2.pid])
sleep 1
NETNS_DAEMONIZE([at_ns1],
[tcpdump -l -n -xx -U -i p1 -w p1.pcap 2>tcpdump_err], [tcpdump.pid])
OVS_WAIT_UNTIL([grep "listening" tcpdump_err])
NETNS_DAEMONIZE([at_ns2],
[tcpdump -l -n -xx -U -i p2 -w p2.pcap 2>tcpdump2_err], [tcpdump2.pid])
OVS_WAIT_UNTIL([grep "listening" tcpdump2_err])

m4_define([TCP_SYN_PKT], [m4_join([,],
[eth_src=f2:00:00:00:00:01,eth_dst=f2:00:00:00:00:02,eth_type=0x0800],
[nw_src=192.168.0.10,nw_dst=10.0.0.10],
[nw_proto=6,nw_ttl=64,nw_frag=no],
[tcp_src=1024,tcp_dst=2048,tcp_flags=syn])])

dnl First send packet from at_ns0 --> OVS with SPI=0x100 and SI=2.
m4_define([NSH_HEADER_1], [m4_join([,],
[eth_src=f2:ff:00:00:00:01,eth_dst=f2:ff:00:00:00:02,eth_type=0x894f],
[nsh_ttl=8,nsh_np=3,nsh_spi=0x100,nsh_si=2,nsh_mdtype=1],
[nsh_c1=0x01020304,nsh_c2=0x05060708,nsh_c3=0x090a0b0c,nsh_c4=0x0d0e0f10])])

NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 \
"$(ovs-ofctl compose-packet --bare 'NSH_HEADER_1')" \
"$(ovs-ofctl compose-packet --bare 'TCP_SYN_PKT')"],
[0], [ignore])

dnl Check for the above packet on p1 interface.
OVS_WAIT_UNTIL([ovs-pcap p1.pcap | grep -q "m4_join([], [^],
$(ovs-ofctl compose-packet --bare 'NSH_HEADER_1'),
$(ovs-ofctl compose-packet --bare 'TCP_SYN_PKT'), [\$])"])

dnl Send the second packet from at_ns1 --> OVS with SPI=0x100 and SI=1.
m4_define([NSH_HEADER_2], [m4_join([,],
[eth_src=f2:ff:00:00:00:01,eth_dst=f2:ff:00:00:00:02,eth_type=0x894f],
[nsh_ttl=8,nsh_np=3,nsh_spi=0x100,nsh_si=1,nsh_mdtype=1],
[nsh_c1=0x01020304,nsh_c2=0x05060708,nsh_c3=0x090a0b0c,nsh_c4=0x0d0e0f10])])

NS_CHECK_EXEC([at_ns1], [$PYTHON3 $srcdir/sendpkt.py p1 \
"$(ovs-ofctl compose-packet --bare 'NSH_HEADER_2')" \
"$(ovs-ofctl compose-packet --bare 'TCP_SYN_PKT')"],
[0], [ignore])

dnl First send packet from at_ns0 --> OVS with SPI=0x100 and SI=2
NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 f2 ff 00 00 00 02 f2 ff 00 00 00 01 89 4f 02 06 01 03 00 01 00 02 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 f2 00 00 00 00 02 f2 00 00 00 00 01 08 00 45 00 00 28 00 01 00 00 40 06 b0 13 c0 a8 00 0a 0a 00 00 0a 04 00 08 00 00 00 00 c8 00 00 00 00 50 02 20 00 b8 5e 00 00 > /dev/null])

dnl Check for the above packet on p1 interface
OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0000: *f2ff *0000 *0002 *f2ff *0000 *0001 *894f *0206" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0010: *0103 *0001 *0002 *0102 *0304 *0506 *0708 *090a" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0020: *0b0c *0d0e *0f10 *f200 *0000 *0002 *f200 *0000" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0030: *0001 *0800 *4500 *0028 *0001 *0000 *4006 *b013" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0040: *c0a8 *000a *0a00 *000a *0400 *0800 *0000 *00c8" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([cat p1.pcap | grep -E "0x0050: *0000 *0000 *5002 *2000 *b85e *0000" 2>&1 1>/dev/null])

dnl Send the second packet from at_ns1 --> OVS with SPI=0x100 and SI=1
NS_CHECK_EXEC([at_ns1], [$PYTHON3 $srcdir/sendpkt.py p1 f2 ff 00 00 00 02 f2 ff 00 00 00 01 89 4f 01 c6 01 03 00 01 00 01 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 f2 00 00 00 00 02 f2 00 00 00 00 01 08 00 45 00 00 28 00 01 00 00 40 06 b0 13 c0 a8 00 0a 0a 00 00 0a 04 00 08 00 00 00 00 c8 00 00 00 00 50 02 20 00 b8 5e 00 00 > /dev/null])

dnl Check for the above packet on p2 interface
OVS_WAIT_UNTIL([cat p2.pcap | grep -E "0x0000: *f2ff *0000 *0002 *f2ff *0000 *0001 *894f *01c6" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([cat p2.pcap | grep -E "0x0010: *0103 *0001 *0001 *0102 *0304 *0506 *0708 *090a" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([cat p2.pcap | grep -E "0x0020: *0b0c *0d0e *0f10 *f200 *0000 *0002 *f200 *0000" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([cat p2.pcap | grep -E "0x0030: *0001 *0800 *4500 *0028 *0001 *0000 *4006 *b013" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([cat p2.pcap | grep -E "0x0040: *c0a8 *000a *0a00 *000a *0400 *0800 *0000 *00c8" 2>&1 1>/dev/null])
OVS_WAIT_UNTIL([cat p2.pcap | grep -E "0x0050: *0000 *0000 *5002 *2000 *b85e *0000" 2>&1 1>/dev/null])
dnl Check for the above packet on p2 interface.
OVS_WAIT_UNTIL([ovs-pcap p2.pcap | grep -q "m4_join([], [^],
$(ovs-ofctl compose-packet --bare 'NSH_HEADER_2'),
$(ovs-ofctl compose-packet --bare 'TCP_SYN_PKT'), [\$])"])

OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP

0 comments on commit ac4df0c

Please sign in to comment.