1 // SPDX-License-Identifier: GPL-2.0
12 #include <linux/if_tun.h>
13 #include <linux/netlink.h>
14 #include <linux/rtnetlink.h>
15 #include <sys/ioctl.h>
16 #include <sys/socket.h>
17 #include <linux/virtio_net.h>
18 #include <netinet/ip.h>
19 #include <netinet/udp.h>
20 #include "../kselftest_harness.h"
22 static const char param_dev_tap_name
[] = "xmacvtap0";
23 static const char param_dev_dummy_name
[] = "xdummy0";
24 static unsigned char param_hwaddr_src
[] = { 0x00, 0xfe, 0x98, 0x14, 0x22, 0x42 };
25 static unsigned char param_hwaddr_dest
[] = {
26 0x00, 0xfe, 0x98, 0x94, 0xd2, 0x43
29 #define MAX_RTNL_PAYLOAD (2048)
31 #define TEST_PACKET_SZ (sizeof(struct virtio_net_hdr) + ETH_HLEN + ETH_MAX_MTU)
33 static struct rtattr
*rtattr_add(struct nlmsghdr
*nh
, unsigned short type
,
37 (struct rtattr
*)((uint8_t *)nh
+ RTA_ALIGN(nh
->nlmsg_len
));
39 rta
->rta_len
= RTA_LENGTH(len
);
40 nh
->nlmsg_len
= RTA_ALIGN(nh
->nlmsg_len
) + RTA_ALIGN(rta
->rta_len
);
44 static struct rtattr
*rtattr_begin(struct nlmsghdr
*nh
, unsigned short type
)
46 return rtattr_add(nh
, type
, 0);
49 static void rtattr_end(struct nlmsghdr
*nh
, struct rtattr
*attr
)
51 uint8_t *end
= (uint8_t *)nh
+ nh
->nlmsg_len
;
53 attr
->rta_len
= end
- (uint8_t *)attr
;
56 static struct rtattr
*rtattr_add_str(struct nlmsghdr
*nh
, unsigned short type
,
59 struct rtattr
*rta
= rtattr_add(nh
, type
, strlen(s
));
61 memcpy(RTA_DATA(rta
), s
, strlen(s
));
65 static struct rtattr
*rtattr_add_strsz(struct nlmsghdr
*nh
, unsigned short type
,
68 struct rtattr
*rta
= rtattr_add(nh
, type
, strlen(s
) + 1);
70 strcpy(RTA_DATA(rta
), s
);
74 static struct rtattr
*rtattr_add_any(struct nlmsghdr
*nh
, unsigned short type
,
75 const void *arr
, size_t len
)
77 struct rtattr
*rta
= rtattr_add(nh
, type
, len
);
79 memcpy(RTA_DATA(rta
), arr
, len
);
83 static int dev_create(const char *dev
, const char *link_type
,
84 int (*fill_rtattr
)(struct nlmsghdr
*nh
),
85 int (*fill_info_data
)(struct nlmsghdr
*nh
))
89 struct ifinfomsg info
;
90 unsigned char data
[MAX_RTNL_PAYLOAD
];
92 struct rtattr
*link_info
, *info_data
;
95 rtnl
= socket(AF_NETLINK
, SOCK_DGRAM
, NETLINK_ROUTE
);
97 fprintf(stderr
, "%s: socket %s\n", __func__
, strerror(errno
));
101 memset(&req
, 0, sizeof(req
));
102 req
.nh
.nlmsg_len
= NLMSG_LENGTH(sizeof(req
.info
));
103 req
.nh
.nlmsg_flags
= NLM_F_REQUEST
| NLM_F_CREATE
;
104 req
.nh
.nlmsg_type
= RTM_NEWLINK
;
106 req
.info
.ifi_family
= AF_UNSPEC
;
107 req
.info
.ifi_type
= 1;
108 req
.info
.ifi_index
= 0;
109 req
.info
.ifi_flags
= IFF_BROADCAST
| IFF_UP
;
110 req
.info
.ifi_change
= 0xffffffff;
112 rtattr_add_str(&req
.nh
, IFLA_IFNAME
, dev
);
115 ret
= fill_rtattr(&req
.nh
);
120 link_info
= rtattr_begin(&req
.nh
, IFLA_LINKINFO
);
122 rtattr_add_strsz(&req
.nh
, IFLA_INFO_KIND
, link_type
);
124 if (fill_info_data
) {
125 info_data
= rtattr_begin(&req
.nh
, IFLA_INFO_DATA
);
126 ret
= fill_info_data(&req
.nh
);
129 rtattr_end(&req
.nh
, info_data
);
132 rtattr_end(&req
.nh
, link_info
);
134 ret
= send(rtnl
, &req
, req
.nh
.nlmsg_len
, 0);
136 fprintf(stderr
, "%s: send %s\n", __func__
, strerror(errno
));
137 ret
= (unsigned int)ret
!= req
.nh
.nlmsg_len
;
143 static int dev_delete(const char *dev
)
147 struct ifinfomsg info
;
148 unsigned char data
[MAX_RTNL_PAYLOAD
];
152 rtnl
= socket(AF_NETLINK
, SOCK_DGRAM
, NETLINK_ROUTE
);
154 fprintf(stderr
, "%s: socket %s\n", __func__
, strerror(errno
));
158 memset(&req
, 0, sizeof(req
));
159 req
.nh
.nlmsg_len
= NLMSG_LENGTH(sizeof(req
.info
));
160 req
.nh
.nlmsg_flags
= NLM_F_REQUEST
;
161 req
.nh
.nlmsg_type
= RTM_DELLINK
;
163 req
.info
.ifi_family
= AF_UNSPEC
;
165 rtattr_add_str(&req
.nh
, IFLA_IFNAME
, dev
);
167 ret
= send(rtnl
, &req
, req
.nh
.nlmsg_len
, 0);
169 fprintf(stderr
, "%s: send %s\n", __func__
, strerror(errno
));
171 ret
= (unsigned int)ret
!= req
.nh
.nlmsg_len
;
177 static int macvtap_fill_rtattr(struct nlmsghdr
*nh
)
181 ifindex
= if_nametoindex(param_dev_dummy_name
);
183 fprintf(stderr
, "%s: ifindex %s\n", __func__
, strerror(errno
));
187 rtattr_add_any(nh
, IFLA_LINK
, &ifindex
, sizeof(ifindex
));
188 rtattr_add_any(nh
, IFLA_ADDRESS
, param_hwaddr_src
, ETH_ALEN
);
193 static int opentap(const char *devname
)
200 ifindex
= if_nametoindex(devname
);
202 fprintf(stderr
, "%s: ifindex %s\n", __func__
, strerror(errno
));
206 sprintf(buf
, "/dev/tap%d", ifindex
);
207 fd
= open(buf
, O_RDWR
| O_NONBLOCK
);
209 fprintf(stderr
, "%s: open %s\n", __func__
, strerror(errno
));
213 memset(&ifr
, 0, sizeof(ifr
));
214 strcpy(ifr
.ifr_name
, devname
);
215 ifr
.ifr_flags
= IFF_TAP
| IFF_NO_PI
| IFF_VNET_HDR
| IFF_MULTI_QUEUE
;
216 if (ioctl(fd
, TUNSETIFF
, &ifr
, sizeof(ifr
)) < 0)
221 size_t build_eth(uint8_t *buf
, uint16_t proto
)
223 struct ethhdr
*eth
= (struct ethhdr
*)buf
;
225 eth
->h_proto
= htons(proto
);
226 memcpy(eth
->h_source
, param_hwaddr_src
, ETH_ALEN
);
227 memcpy(eth
->h_dest
, param_hwaddr_dest
, ETH_ALEN
);
232 static uint32_t add_csum(const uint8_t *buf
, int len
)
235 uint16_t *sbuf
= (uint16_t *)buf
;
243 sum
+= *(uint8_t *)sbuf
;
248 static uint16_t finish_ip_csum(uint32_t sum
)
250 uint16_t lo
= sum
& 0xffff;
251 uint16_t hi
= sum
>> 16;
257 static uint16_t build_ip_csum(const uint8_t *buf
, int len
,
260 sum
+= add_csum(buf
, len
);
261 return finish_ip_csum(sum
);
264 static int build_ipv4_header(uint8_t *buf
, int payload_len
)
266 struct iphdr
*iph
= (struct iphdr
*)buf
;
272 htons(sizeof(*iph
) + sizeof(struct udphdr
) + payload_len
);
273 iph
->id
= htons(1337);
274 iph
->protocol
= IPPROTO_UDP
;
275 iph
->saddr
= htonl((172 << 24) | (17 << 16) | 2);
276 iph
->daddr
= htonl((172 << 24) | (17 << 16) | 1);
277 iph
->check
= build_ip_csum(buf
, iph
->ihl
<< 2, 0);
279 return iph
->ihl
<< 2;
282 static int build_udp_packet(uint8_t *buf
, int payload_len
, bool csum_off
)
284 const int ip4alen
= sizeof(uint32_t);
285 struct udphdr
*udph
= (struct udphdr
*)buf
;
286 int len
= sizeof(*udph
) + payload_len
;
289 udph
->source
= htons(22);
290 udph
->dest
= htons(58822);
291 udph
->len
= htons(len
);
293 memset(buf
+ sizeof(struct udphdr
), PKT_DATA
, payload_len
);
295 sum
= add_csum(buf
- 2 * ip4alen
, 2 * ip4alen
);
296 sum
+= htons(IPPROTO_UDP
) + udph
->len
;
299 sum
+= add_csum(buf
, len
);
301 udph
->check
= finish_ip_csum(sum
);
303 return sizeof(*udph
) + payload_len
;
306 size_t build_test_packet_valid_udp_gso(uint8_t *buf
, size_t payload_len
)
309 struct virtio_net_hdr
*vh
= (struct virtio_net_hdr
*)buf
;
311 vh
->hdr_len
= ETH_HLEN
+ sizeof(struct iphdr
) + sizeof(struct udphdr
);
312 vh
->flags
= VIRTIO_NET_HDR_F_NEEDS_CSUM
;
313 vh
->csum_start
= ETH_HLEN
+ sizeof(struct iphdr
);
314 vh
->csum_offset
= __builtin_offsetof(struct udphdr
, check
);
315 vh
->gso_type
= VIRTIO_NET_HDR_GSO_UDP
;
316 vh
->gso_size
= ETH_DATA_LEN
- sizeof(struct iphdr
);
319 cur
+= build_eth(cur
, ETH_P_IP
);
320 cur
+= build_ipv4_header(cur
, payload_len
);
321 cur
+= build_udp_packet(cur
, payload_len
, true);
326 size_t build_test_packet_valid_udp_csum(uint8_t *buf
, size_t payload_len
)
329 struct virtio_net_hdr
*vh
= (struct virtio_net_hdr
*)buf
;
331 vh
->flags
= VIRTIO_NET_HDR_F_DATA_VALID
;
332 vh
->gso_type
= VIRTIO_NET_HDR_GSO_NONE
;
335 cur
+= build_eth(cur
, ETH_P_IP
);
336 cur
+= build_ipv4_header(cur
, payload_len
);
337 cur
+= build_udp_packet(cur
, payload_len
, false);
342 size_t build_test_packet_crash_tap_invalid_eth_proto(uint8_t *buf
,
346 struct virtio_net_hdr
*vh
= (struct virtio_net_hdr
*)buf
;
348 vh
->hdr_len
= ETH_HLEN
+ sizeof(struct iphdr
) + sizeof(struct udphdr
);
350 vh
->gso_type
= VIRTIO_NET_HDR_GSO_UDP
;
351 vh
->gso_size
= ETH_DATA_LEN
- sizeof(struct iphdr
);
354 cur
+= build_eth(cur
, 0);
355 cur
+= sizeof(struct iphdr
) + sizeof(struct udphdr
);
356 cur
+= build_ipv4_header(cur
, payload_len
);
357 cur
+= build_udp_packet(cur
, payload_len
, true);
372 ret
= dev_create(param_dev_dummy_name
, "dummy", NULL
, NULL
);
375 ret
= dev_create(param_dev_tap_name
, "macvtap", macvtap_fill_rtattr
,
379 self
->fd
= opentap(param_dev_tap_name
);
380 ASSERT_GE(self
->fd
, 0);
383 FIXTURE_TEARDOWN(tap
)
390 ret
= dev_delete(param_dev_tap_name
);
393 ret
= dev_delete(param_dev_dummy_name
);
397 TEST_F(tap
, test_packet_valid_udp_gso
)
399 uint8_t pkt
[TEST_PACKET_SZ
];
403 memset(pkt
, 0, sizeof(pkt
));
404 off
= build_test_packet_valid_udp_gso(pkt
, 1021);
405 ret
= write(self
->fd
, pkt
, off
);
409 TEST_F(tap
, test_packet_valid_udp_csum
)
411 uint8_t pkt
[TEST_PACKET_SZ
];
415 memset(pkt
, 0, sizeof(pkt
));
416 off
= build_test_packet_valid_udp_csum(pkt
, 1024);
417 ret
= write(self
->fd
, pkt
, off
);
421 TEST_F(tap
, test_packet_crash_tap_invalid_eth_proto
)
423 uint8_t pkt
[TEST_PACKET_SZ
];
427 memset(pkt
, 0, sizeof(pkt
));
428 off
= build_test_packet_crash_tap_invalid_eth_proto(pkt
, 1024);
429 ret
= write(self
->fd
, pkt
, off
);
431 ASSERT_EQ(errno
, EINVAL
);