Skip to content

Commit f4411a6

Browse files
authored
Merge pull request snabbco#1013 from Igalia/fix-packetblaster-lwaftr
Fix packetblaster lwaftr
2 parents 6321d36 + 87c4263 commit f4411a6

File tree

6 files changed

+96
-67
lines changed

6 files changed

+96
-67
lines changed

src/program/packetblaster/lwaftr/README

Lines changed: 47 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -16,54 +16,69 @@ Usage: packetblaster lwaftr [OPTIONS]
1616

1717
--vlan VLANID VLAN tag traffic with VLANID if set
1818

19-
--src_mac SOURCE
20-
Source MAC-Address
19+
--src_mac SOURCE Source MAC-Address
2120
Default: 00:00:00:00:00:00
22-
--dst_mac DESTINATION
23-
Destination MAC-Address
21+
22+
--dst_mac DESTINATION Destination MAC-Address
2423
Default: 00:00:00:00:00:00
25-
--size SIZES
26-
A comma separated list of numbers. Send packets of
27-
SIZES bytes. The size specifies the lenght of the IPv4
28-
packet. The actual packet size on the wire is 14 Bytes
29-
longer (Ethernet header). Smallest allowed IPv4 packet
30-
size is 28 (20 Bytes for IPv4 header, 8 Bytes payload
31-
for packet loss detection)
32-
Default: 64,64,64,64,64,64,64,594,594,594,1500 (IMIX)
33-
--b4 IPV6,IPV4,PORT
34-
First B4 Client IPv6 mapped to IPv4 and UDP Port.
24+
25+
--size SIZES A comma separated list of numbers. Send packets whose
26+
frames are SIZES bytes long. The frame size includes
27+
the size of the packet, including its ethernet
28+
headers, and additionally a 4-byte CRC that is written
29+
and read by the NIC.
30+
31+
Note that the minimum ethernet frame size is 64 bytes.
32+
While it's technically possible to make smaller frames
33+
and we do allow it, the NIC will pad it up to the
34+
minimum before sending, so it's a bit pointless.
35+
Since Snabb does not see the CRC in the packet, that
36+
means that from Snabb's perspective the minimum useful
37+
packet size is 60 bytes.
38+
39+
The smallest allowed frame size is 46 bytes,
40+
comprising 14 bytes for the ethernet header, 20 for
41+
the IPv4 header, 8 for the UDP header, and 4
42+
additional bytes for the ethernet checksum. If the
43+
packet has at least 8 bytes of payload, the generated
44+
packets will include a unique identifier in the
45+
payload as well.
46+
47+
Default: 64,64,64,64,64,64,64,594,594,594,1500
48+
49+
--b4 IPV6,IPV4,PORT First B4 Client IPv6 mapped to IPv4 and UDP Port.
3550
B4 IPv6,IPv4 and Port are incremented for every count,
3651
then rolled over. Port is incremented by the port number:
3752
e.g. 1024 -> 1024, 2048, 3096 .. 64512 (63 in total)
3853
Default: 2001:db8::,10.0.0.0,1024
39-
--aftr IPV6
40-
IPv6 address of lwaftr server (softwire tunnel endpoint)
54+
55+
--aftr IPV6 IPv6 address of lwaftr server (softwire tunnel endpoint)
4156
Default: 2001:db8:ffff::100
42-
--ipv4 IPV4
43-
Public IPv4. Used as source for IPv4 traffic and
57+
58+
--ipv4 IPV4 Public IPv4. Used as source for IPv4 traffic and
4459
as destination in IPv6 packets from B4
4560
Default: 8.8.8.8
46-
--count COUNT
47-
Number of B4 clients to simulate.
61+
62+
--count COUNT Number of B4 clients to simulate.
4863
Default: 1
49-
--rate RATE
50-
Rate in MPPS for the generated traffic. Fractions are
64+
65+
--rate RATE Rate in MPPS for the generated traffic. Fractions are
5166
allowed (e.g. 3.148 for IMIX line rate). If set too high,
5267
the actual transmitted rate depends on the interfaces capacity.
5368
Setting rate to 0 turns it to listening only mode while
5469
reporting on incoming packets
5570
Default: 1 MPPS
56-
--v4only, -4
57-
Generate only IPv4 packets from the Internet towards lwaftr
58-
--v6only, -6
59-
Generate only IPv6 packets from B4 to lwaftr
60-
--duration DURATION
61-
Run for DURATION seconds.
71+
72+
--v4only, -4 Generate only IPv4 packets from the Internet towards lwaftr
73+
74+
--v6only, -6 Generate only IPv6 packets from B4 to lwaftr
75+
76+
--duration DURATION Run for DURATION seconds.
6277
Default: unlimited
63-
-V, --verbose
64-
Display verbose link information every second
65-
-h, --help
66-
Print usage information.
78+
79+
-V, --verbose Display verbose link information every second
80+
81+
-h, --help Print usage information.
6782

6883

6984
This tool generates two types of traffic according to RFC7596:

src/program/packetblaster/lwaftr/lib.lua

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ local ether_header_ptr_type = ffi.typeof("$*", ether_header_t)
3333
local ethernet_header_size = ffi.sizeof(ether_header_t)
3434
local OFFSET_ETHERTYPE = 12
3535

36+
-- The ethernet CRC field is not included in the packet as seen by
37+
-- Snabb, but it is part of the frame and therefore a contributor to the
38+
-- frame size.
39+
local ethernet_crc_size = 4
40+
3641
local ether_vlan_header_type = ffi.typeof([[
3742
struct {
3843
uint16_t tag;
@@ -56,6 +61,7 @@ struct {
5661
uint8_t dst_ip[4];
5762
} __attribute__((packed))
5863
]]
64+
local ipv4_header_size = ffi.sizeof(ipv4hdr_t)
5965
local ipv4_header_ptr_type = ffi.typeof("$*", ipv4hdr_t)
6066

6167
local ipv6_ptr_type = ffi.typeof([[
@@ -367,37 +373,44 @@ function Lwaftrgen:pull ()
367373
ipv4_udp_hdr.dst_port = C.htons(self.current_port)
368374
ipv6_ipv4_udp_hdr.src_port = C.htons(self.current_port)
369375

370-
for _,size in ipairs(self.sizes) do
376+
-- The sizes are frame sizes, including the 4-byte ethernet CRC
377+
-- that we don't see in Snabb.
378+
379+
local vlan_size = self.vlan and ether_vlan_header_size or 0
380+
local ethernet_total_size = ethernet_header_size + vlan_size
381+
local minimum_size = ethernet_total_size + ipv4_header_size +
382+
udp_header_size + ethernet_crc_size
371383

384+
for _,size in ipairs(self.sizes) do
385+
assert(size >= minimum_size)
386+
local packet_len = size - ethernet_crc_size
387+
local ipv4_len = packet_len - ethernet_total_size
388+
local udp_len = ipv4_len - ipv4_header_size
372389
if not self.ipv6_only then
373-
ipv4_hdr.total_length = C.htons(size)
374-
if self.vlan then
375-
ipv4_udp_hdr.len = C.htons(size - 28 + 4)
376-
self.ipv4_pkt.length = size + ethernet_header_size + 4
377-
else
378-
ipv4_udp_hdr.len = C.htons(size - 28)
379-
self.ipv4_pkt.length = size + ethernet_header_size
380-
end
390+
ipv4_hdr.total_length = C.htons(ipv4_len)
391+
ipv4_udp_hdr.len = C.htons(udp_len)
392+
self.ipv4_pkt.length = packet_len
381393
ipv4_hdr.checksum = 0
382-
ipv4_hdr.checksum = C.htons(ipsum(self.ipv4_pkt.data + ethernet_header_size, 20, 0))
383-
self.ipv4_payload.number = self.ipv4_packet_number;
384-
self.ipv4_packet_number = self.ipv4_packet_number + 1
394+
ipv4_hdr.checksum = C.htons(ipsum(self.ipv4_pkt.data + ethernet_total_size, 20, 0))
395+
if size >= minimum_size + payload_size then
396+
self.ipv4_payload.number = self.ipv4_packet_number;
397+
self.ipv4_packet_number = self.ipv4_packet_number + 1
398+
end
385399
local ipv4_pkt = packet.clone(self.ipv4_pkt)
386400
transmit(output, ipv4_pkt)
387401
end
388402

389403
if not self.ipv4_only then
390-
ipv6_hdr.payload_length = C.htons(size)
391-
ipv6_ipv4_hdr.total_length = C.htons(size)
392-
if self.vlan then
393-
ipv6_ipv4_udp_hdr.len = C.htons(size - 28 + 4)
394-
self.ipv6_pkt.length = size + 54 + 4
395-
else
396-
ipv6_ipv4_udp_hdr.len = C.htons(size - 28)
397-
self.ipv6_pkt.length = size + 54
404+
-- Expectation from callers is to make packets that are SIZE
405+
-- bytes big, *plus* the IPv6 header.
406+
ipv6_hdr.payload_length = C.htons(ipv4_len)
407+
ipv6_ipv4_hdr.total_length = C.htons(ipv4_len)
408+
ipv6_ipv4_udp_hdr.len = C.htons(udp_len)
409+
self.ipv6_pkt.length = packet_len + ipv6_header_size
410+
if size >= minimum_size + payload_size then
411+
self.ipv6_payload.number = self.ipv6_packet_number;
412+
self.ipv6_packet_number = self.ipv6_packet_number + 1
398413
end
399-
self.ipv6_payload.number = self.ipv6_packet_number;
400-
self.ipv6_packet_number = self.ipv6_packet_number + 1
401414
local ipv6_pkt = packet.clone(self.ipv6_pkt)
402415
transmit(output, ipv6_pkt)
403416
end

src/program/packetblaster/lwaftr/lwaftr.lua

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ local long_opts = {
2525
duration = "D", -- terminate after n seconds
2626
verbose = "V", -- verbose, display stats
2727
help = "h", -- display help text
28-
size = "S", -- packet size list (defaults to IMIX)
28+
size = "S", -- frame size list (defaults to IMIX)
2929
src_mac = "s", -- source ethernet address
3030
dst_mac = "d", -- destination ethernet address
3131
vlan = "v", -- VLAN id
@@ -64,18 +64,10 @@ function run (args)
6464
end
6565

6666
local sizes = { 64, 64, 64, 64, 64, 64, 64, 594, 594, 594, 1500 }
67-
local sizes_ipv6 = { 104, 104, 104, 104, 104, 104, 104, 634, 634, 634, 1540 }
6867
function opt.S (arg)
6968
sizes = {}
70-
sizes_ipv6 = {}
7169
for size in string.gmatch(arg, "%d+") do
72-
local s = tonumber(size)
73-
if s < 28 then
74-
s = 28
75-
print("Warning: Increasing IPv4 packet size to 28")
76-
end
77-
sizes[#sizes+1] = s
78-
sizes_ipv6[#sizes_ipv6+1] = s + 40
70+
sizes[#sizes + 1] = assert(tonumber(size), "size not a number: "..size)
7971
end
8072
end
8173

@@ -161,6 +153,12 @@ function run (args)
161153

162154
args = lib.dogetopt(args, opt, "VD:hS:s:a:d:b:iI:c:r:46p:v:o:t:i:k:", long_opts)
163155

156+
for _,s in ipairs(sizes) do
157+
if s < 18 + (vlan and 4 or 0) + 20 + 8 then
158+
error("Minimum frame size is 46 bytes (18 ethernet+CRC, 20 IPv4, and 8 UDP)")
159+
end
160+
end
161+
164162
if not target then
165163
print("either --pci, --tap, --sock, --int or --pcap are required parameters")
166164
main.exit(1)
@@ -172,14 +170,16 @@ function run (args)
172170
if not ipv4_only then
173171
print(string.format("IPv6: %s > %s: %s:%d > %s:12345", b4_ipv6, aftr_ipv6, b4_ipv4, b4_port, public_ipv4))
174172
print(" source IPv6 and source IPv4/Port adjusted per client")
175-
print("IPv6 packet sizes: " .. table.concat(sizes_ipv6,","))
173+
local sizes_ipv6 = {}
174+
for i,size in ipairs(sizes) do sizes_ipv6[i] = size + 40 end
175+
print("IPv6 frame sizes: " .. table.concat(sizes_ipv6,","))
176176
end
177177

178178
if not ipv6_only then
179179
print()
180180
print(string.format("IPv4: %s:12345 > %s:%d", public_ipv4, b4_ipv4, b4_port))
181181
print(" destination IPv4 and Port adjusted per client")
182-
print("IPv4 packet sizes: " .. table.concat(sizes,","))
182+
print("IPv4 frame sizes: " .. table.concat(sizes,","))
183183
end
184184

185185
if ipv4_only and ipv6_only then
Binary file not shown.
Binary file not shown.

src/program/packetblaster/selftest.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ function test_lwaftr_pcap {
1717
exit 1
1818
fi
1919
cmp $TEMP_PCAP $PCAP
20+
status=$?
2021
rm $TEMP_PCAP
2122
if [ $status != 0 ]; then
2223
echo "Error: lwaftr generated pcap differs from ${PCAP}"
@@ -25,7 +26,7 @@ function test_lwaftr_pcap {
2526
}
2627

2728
test_lwaftr_pcap program/packetblaster/lwaftr/test_lwaftr_1.pcap --count 1
28-
test_lwaftr_pcap program/packetblaster/lwaftr/test_lwaftr_2.pcap --count 2 --vlan 100 --size 0
29+
test_lwaftr_pcap program/packetblaster/lwaftr/test_lwaftr_2.pcap --count 2 --vlan 100 --size 50
2930

3031
# lwaftr tap test
3132
sudo ip netns add snabbtest || exit $TEST_SKIPPED

0 commit comments

Comments
 (0)