Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'selftest-extend-tun-virtio-coverage-for-gso-over-udp-tunnel'

Xu Du says:

====================
selftest: Extend tun/virtio coverage for GSO over UDP tunnel

The design strategy is to extend the existing tun testing infrastructure
to support this new use-case, rather than introducing a new or parallel framework.
This allows for better integration and re-use of existing test logic.
====================

Link: https://patch.msgid.link/cover.1768979440.git.xudu@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+1265 -39
+13 -3
tools/testing/selftests/net/Makefile
··· 183 183 tap \ 184 184 tcp_port_share \ 185 185 tls \ 186 - tun \ 187 186 # end of TEST_GEN_PROGS 188 187 189 188 TEST_FILES := \ ··· 194 195 195 196 # YNL files, must be before "include ..lib.mk" 196 197 YNL_GEN_FILES := busy_poller 197 - YNL_GEN_PROGS := netlink-dumps 198 + YNL_GEN_PROGS := \ 199 + netlink-dumps \ 200 + tun \ 201 + # end of YNL_GEN_PROGS 202 + 198 203 TEST_GEN_FILES += $(YNL_GEN_FILES) 199 204 TEST_GEN_PROGS += $(YNL_GEN_PROGS) 200 205 ··· 209 206 include ../lib.mk 210 207 211 208 # YNL build 212 - YNL_GENS := netdev 209 + YNL_GENS := \ 210 + netdev \ 211 + rt-addr \ 212 + rt-link \ 213 + rt-neigh \ 214 + rt-route \ 215 + # end of YNL_GENS 216 + 213 217 include ynl.mk 214 218 215 219 $(OUTPUT)/epoll_busy_poll: LDLIBS += -lcap
+862 -36
tools/testing/selftests/net/tun.c
··· 8 8 #include <stdlib.h> 9 9 #include <string.h> 10 10 #include <unistd.h> 11 - #include <linux/if.h> 12 11 #include <linux/if_tun.h> 13 - #include <linux/netlink.h> 14 - #include <linux/rtnetlink.h> 15 12 #include <sys/ioctl.h> 16 13 #include <sys/socket.h> 17 14 18 15 #include "kselftest_harness.h" 16 + #include "tuntap_helpers.h" 17 + 18 + static const char param_dev_geneve_name[] = "geneve1"; 19 + static unsigned char param_hwaddr_outer_dst[] = { 0x00, 0xfe, 0x98, 20 + 0x14, 0x22, 0x42 }; 21 + static unsigned char param_hwaddr_outer_src[] = { 0x00, 0xfe, 0x98, 22 + 0x94, 0xd2, 0x43 }; 23 + static unsigned char param_hwaddr_inner_dst[] = { 0x00, 0xfe, 0x98, 24 + 0x94, 0x22, 0xcc }; 25 + static unsigned char param_hwaddr_inner_src[] = { 0x00, 0xfe, 0x98, 26 + 0x94, 0xd2, 0xdd }; 27 + 28 + static struct in_addr param_ipaddr4_outer_dst = { 29 + __constant_htonl(0xac100001), 30 + }; 31 + 32 + static struct in_addr param_ipaddr4_outer_src = { 33 + __constant_htonl(0xac100002), 34 + }; 35 + 36 + static struct in_addr param_ipaddr4_inner_dst = { 37 + __constant_htonl(0xac100101), 38 + }; 39 + 40 + static struct in_addr param_ipaddr4_inner_src = { 41 + __constant_htonl(0xac100102), 42 + }; 43 + 44 + static struct in6_addr param_ipaddr6_outer_dst = { 45 + { { 0x20, 0x02, 0x0d, 0xb8, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } }, 46 + }; 47 + 48 + static struct in6_addr param_ipaddr6_outer_src = { 49 + { { 0x20, 0x02, 0x0d, 0xb8, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 } }, 50 + }; 51 + 52 + static struct in6_addr param_ipaddr6_inner_dst = { 53 + { { 0x20, 0x02, 0x0d, 0xb8, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } }, 54 + }; 55 + 56 + static struct in6_addr param_ipaddr6_inner_src = { 57 + { { 0x20, 0x02, 0x0d, 0xb8, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 } }, 58 + }; 59 + 60 + #ifndef BIT 61 + #define BIT(nr) (1UL << (nr)) 62 + #endif 63 + 64 + #define VN_ID 1 65 + #define VN_PORT 4789 66 + #define UDP_SRC_PORT 22 67 + #define UDP_DST_PORT 48878 68 + #define IPPREFIX_LEN 24 69 + #define IP6PREFIX_LEN 64 70 + #define TIMEOUT_SEC 10 71 + #define TIMEOUT_USEC 100000 72 + #define MAX_RETRIES 20 73 + 74 + #define UDP_TUNNEL_GENEVE_4IN4 0x01 75 + #define UDP_TUNNEL_GENEVE_6IN4 0x02 76 + #define UDP_TUNNEL_GENEVE_4IN6 0x04 77 + #define UDP_TUNNEL_GENEVE_6IN6 0x08 78 + 79 + #define UDP_TUNNEL_MAX_SEGMENTS BIT(7) 80 + 81 + #define UDP_TUNNEL_OUTER_IPV4 (UDP_TUNNEL_GENEVE_4IN4 | UDP_TUNNEL_GENEVE_6IN4) 82 + #define UDP_TUNNEL_INNER_IPV4 (UDP_TUNNEL_GENEVE_4IN4 | UDP_TUNNEL_GENEVE_4IN6) 83 + 84 + #define UDP_TUNNEL_GENEVE_4IN4_HDRLEN \ 85 + (ETH_HLEN + 2 * sizeof(struct iphdr) + GENEVE_HLEN + \ 86 + 2 * sizeof(struct udphdr)) 87 + #define UDP_TUNNEL_GENEVE_6IN6_HDRLEN \ 88 + (ETH_HLEN + 2 * sizeof(struct ipv6hdr) + GENEVE_HLEN + \ 89 + 2 * sizeof(struct udphdr)) 90 + #define UDP_TUNNEL_GENEVE_4IN6_HDRLEN \ 91 + (ETH_HLEN + sizeof(struct iphdr) + sizeof(struct ipv6hdr) + \ 92 + GENEVE_HLEN + 2 * sizeof(struct udphdr)) 93 + #define UDP_TUNNEL_GENEVE_6IN4_HDRLEN \ 94 + (ETH_HLEN + sizeof(struct ipv6hdr) + sizeof(struct iphdr) + \ 95 + GENEVE_HLEN + 2 * sizeof(struct udphdr)) 96 + 97 + #define UDP_TUNNEL_HDRLEN(type) \ 98 + ((type) == UDP_TUNNEL_GENEVE_4IN4 ? UDP_TUNNEL_GENEVE_4IN4_HDRLEN : \ 99 + (type) == UDP_TUNNEL_GENEVE_6IN6 ? UDP_TUNNEL_GENEVE_6IN6_HDRLEN : \ 100 + (type) == UDP_TUNNEL_GENEVE_4IN6 ? UDP_TUNNEL_GENEVE_4IN6_HDRLEN : \ 101 + (type) == UDP_TUNNEL_GENEVE_6IN4 ? UDP_TUNNEL_GENEVE_6IN4_HDRLEN : \ 102 + 0) 103 + 104 + #define UDP_TUNNEL_MSS(type) (ETH_DATA_LEN - UDP_TUNNEL_HDRLEN(type)) 105 + #define UDP_TUNNEL_MAX(type, is_tap) \ 106 + (ETH_MAX_MTU - UDP_TUNNEL_HDRLEN(type) - ((is_tap) ? ETH_HLEN : 0)) 107 + 108 + #define TUN_VNET_TNL_SIZE sizeof(struct virtio_net_hdr_v1_hash_tunnel) 109 + #define MAX_VNET_TUNNEL_PACKET_SZ \ 110 + (TUN_VNET_TNL_SIZE + ETH_HLEN + UDP_TUNNEL_GENEVE_6IN6_HDRLEN + \ 111 + ETH_MAX_MTU) 112 + 113 + struct geneve_setup_config { 114 + int family; 115 + union { 116 + struct in_addr r4; 117 + struct in6_addr r6; 118 + } remote; 119 + __be32 vnid; 120 + __be16 vnport; 121 + unsigned char hwaddr[6]; 122 + uint8_t csum; 123 + }; 19 124 20 125 static int tun_attach(int fd, char *dev) 21 126 { ··· 130 25 strcpy(ifr.ifr_name, dev); 131 26 ifr.ifr_flags = IFF_ATTACH_QUEUE; 132 27 133 - return ioctl(fd, TUNSETQUEUE, (void *) &ifr); 28 + return ioctl(fd, TUNSETQUEUE, (void *)&ifr); 134 29 } 135 30 136 31 static int tun_detach(int fd, char *dev) ··· 141 36 strcpy(ifr.ifr_name, dev); 142 37 ifr.ifr_flags = IFF_DETACH_QUEUE; 143 38 144 - return ioctl(fd, TUNSETQUEUE, (void *) &ifr); 39 + return ioctl(fd, TUNSETQUEUE, (void *)&ifr); 145 40 } 146 41 147 42 static int tun_alloc(char *dev) ··· 159 54 strcpy(ifr.ifr_name, dev); 160 55 ifr.ifr_flags = IFF_TAP | IFF_NAPI | IFF_MULTI_QUEUE; 161 56 162 - err = ioctl(fd, TUNSETIFF, (void *) &ifr); 57 + err = ioctl(fd, TUNSETIFF, (void *)&ifr); 163 58 if (err < 0) { 164 59 fprintf(stderr, "can't TUNSETIFF: %s\n", strerror(errno)); 165 60 close(fd); ··· 171 66 172 67 static int tun_delete(char *dev) 173 68 { 174 - struct { 175 - struct nlmsghdr nh; 176 - struct ifinfomsg ifm; 177 - unsigned char data[64]; 178 - } req; 179 - struct rtattr *rta; 180 - int ret, rtnl; 69 + return ip_link_del(dev); 70 + } 181 71 182 - rtnl = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); 183 - if (rtnl < 0) { 184 - fprintf(stderr, "can't open rtnl: %s\n", strerror(errno)); 185 - return 1; 72 + static int tun_open(char *dev, const int flags, const int hdrlen, 73 + const int features, const unsigned char *mac_addr) 74 + { 75 + struct ifreq ifr = { 0 }; 76 + int fd, sk = -1; 77 + 78 + fd = open("/dev/net/tun", O_RDWR); 79 + if (fd < 0) { 80 + perror("open"); 81 + return -1; 186 82 } 187 83 188 - memset(&req, 0, sizeof(req)); 189 - req.nh.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.ifm))); 190 - req.nh.nlmsg_flags = NLM_F_REQUEST; 191 - req.nh.nlmsg_type = RTM_DELLINK; 84 + ifr.ifr_flags = flags; 85 + if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0) { 86 + perror("ioctl(TUNSETIFF)"); 87 + goto err; 88 + } 89 + strcpy(dev, ifr.ifr_name); 192 90 193 - req.ifm.ifi_family = AF_UNSPEC; 91 + if (hdrlen > 0) { 92 + if (ioctl(fd, TUNSETVNETHDRSZ, &hdrlen) < 0) { 93 + perror("ioctl(TUNSETVNETHDRSZ)"); 94 + goto err; 95 + } 96 + } 194 97 195 - rta = (struct rtattr *)(((char *)&req) + NLMSG_ALIGN(req.nh.nlmsg_len)); 196 - rta->rta_type = IFLA_IFNAME; 197 - rta->rta_len = RTA_LENGTH(IFNAMSIZ); 198 - req.nh.nlmsg_len += rta->rta_len; 199 - memcpy(RTA_DATA(rta), dev, IFNAMSIZ); 98 + if (features) { 99 + if (ioctl(fd, TUNSETOFFLOAD, features) < 0) { 100 + perror("ioctl(TUNSETOFFLOAD)"); 101 + goto err; 102 + } 103 + } 200 104 201 - ret = send(rtnl, &req, req.nh.nlmsg_len, 0); 105 + sk = socket(PF_INET, SOCK_DGRAM, 0); 106 + if (sk < 0) { 107 + perror("socket"); 108 + goto err; 109 + } 110 + 111 + if (ioctl(sk, SIOCGIFFLAGS, &ifr) < 0) { 112 + perror("ioctl(SIOCGIFFLAGS)"); 113 + goto err; 114 + } 115 + 116 + ifr.ifr_flags |= (IFF_UP | IFF_RUNNING); 117 + if (ioctl(sk, SIOCSIFFLAGS, &ifr) < 0) { 118 + perror("ioctl(SIOCSIFFLAGS)"); 119 + goto err; 120 + } 121 + 122 + if (mac_addr && flags & IFF_TAP) { 123 + ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; 124 + memcpy(ifr.ifr_hwaddr.sa_data, mac_addr, ETH_ALEN); 125 + 126 + if (ioctl(sk, SIOCSIFHWADDR, &ifr) < 0) { 127 + perror("ioctl(SIOCSIFHWADDR)"); 128 + goto err; 129 + } 130 + } 131 + 132 + out: 133 + if (sk >= 0) 134 + close(sk); 135 + return fd; 136 + 137 + err: 138 + close(fd); 139 + fd = -1; 140 + goto out; 141 + } 142 + 143 + static size_t sockaddr_len(int family) 144 + { 145 + return (family == AF_INET) ? sizeof(struct sockaddr_in) : 146 + sizeof(struct sockaddr_in6); 147 + } 148 + 149 + static int geneve_fill_newlink(struct rt_link_newlink_req *req, void *data) 150 + { 151 + struct geneve_setup_config *cfg = data; 152 + 153 + #define SET_GENEVE_REMOTE rt_link_newlink_req_set_linkinfo_data_geneve_remote 154 + #define SET_GENEVE_REMOTE6 rt_link_newlink_req_set_linkinfo_data_geneve_remote6 155 + 156 + rt_link_newlink_req_set_address(req, cfg->hwaddr, ETH_ALEN); 157 + rt_link_newlink_req_set_linkinfo_data_geneve_id(req, cfg->vnid); 158 + rt_link_newlink_req_set_linkinfo_data_geneve_port(req, cfg->vnport); 159 + rt_link_newlink_req_set_linkinfo_data_geneve_udp_csum(req, cfg->csum); 160 + 161 + if (cfg->family == AF_INET) 162 + SET_GENEVE_REMOTE(req, cfg->remote.r4.s_addr); 163 + else 164 + SET_GENEVE_REMOTE6(req, &cfg->remote.r6, 165 + sizeof(cfg->remote.r6)); 166 + 167 + return 0; 168 + } 169 + 170 + static int geneve_create(const char *dev, int family, void *remote, 171 + void *hwaddr) 172 + { 173 + struct geneve_setup_config geneve; 174 + 175 + memset(&geneve, 0, sizeof(geneve)); 176 + geneve.vnid = VN_ID; 177 + geneve.vnport = htons(VN_PORT); 178 + geneve.csum = 1; 179 + geneve.family = family; 180 + if (family == AF_INET) 181 + memcpy(&geneve.remote.r4, remote, sizeof(struct in_addr)); 182 + else 183 + memcpy(&geneve.remote.r6, remote, sizeof(struct in6_addr)); 184 + memcpy(geneve.hwaddr, hwaddr, ETH_ALEN); 185 + 186 + return ip_link_add(dev, "geneve", geneve_fill_newlink, (void *)&geneve); 187 + } 188 + 189 + static int set_pmtu_discover(int fd, bool is_ipv4) 190 + { 191 + int level, name, val; 192 + 193 + if (is_ipv4) { 194 + level = SOL_IP; 195 + name = IP_MTU_DISCOVER; 196 + val = IP_PMTUDISC_DO; 197 + } else { 198 + level = SOL_IPV6; 199 + name = IPV6_MTU_DISCOVER; 200 + val = IPV6_PMTUDISC_DO; 201 + } 202 + 203 + return setsockopt(fd, level, name, &val, sizeof(val)); 204 + } 205 + 206 + static int udp_socket_open(struct sockaddr_storage *ssa, bool do_frag, 207 + bool do_connect, struct sockaddr_storage *dsa) 208 + { 209 + struct timeval to = { .tv_sec = TIMEOUT_SEC }; 210 + int fd, family = ssa->ss_family; 211 + int salen = sockaddr_len(family); 212 + 213 + fd = socket(family, SOCK_DGRAM, 0); 214 + if (fd < 0) 215 + return -1; 216 + 217 + if (bind(fd, (struct sockaddr *)ssa, salen) < 0) { 218 + perror("bind"); 219 + goto err; 220 + } 221 + 222 + if (do_connect && connect(fd, (struct sockaddr *)dsa, salen) < 0) { 223 + perror("connect"); 224 + goto err; 225 + } 226 + 227 + if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &to, sizeof(to)) < 0) { 228 + perror("setsockopt(SO_RCVTIMEO)"); 229 + goto err; 230 + } 231 + 232 + if (!do_frag && set_pmtu_discover(fd, family == AF_INET) < 0) { 233 + perror("set_pmtu_discover"); 234 + goto err; 235 + } 236 + return fd; 237 + 238 + err: 239 + close(fd); 240 + return -1; 241 + } 242 + 243 + static void parse_route_rsp(struct rt_route_getroute_rsp *rsp, void *rtm_type) 244 + { 245 + *(uint8_t *)rtm_type = rsp->_hdr.rtm_type; 246 + } 247 + 248 + static int ip_route_check(const char *intf, int family, void *addr) 249 + { 250 + uint8_t rtm_type, table = RT_TABLE_LOCAL; 251 + int retries = MAX_RETRIES; 252 + 253 + while (retries-- > 0) { 254 + if (ip_route_get(intf, family, table, addr, parse_route_rsp, 255 + &rtm_type) == 0 && 256 + rtm_type == RTN_LOCAL) 257 + break; 258 + 259 + usleep(TIMEOUT_USEC); 260 + } 261 + 262 + if (retries < 0) 263 + return -1; 264 + 265 + return 0; 266 + } 267 + 268 + static int send_gso_udp_msg(int socket, struct sockaddr_storage *addr, 269 + uint8_t *send_buf, int send_len, int gso_size) 270 + { 271 + char control[CMSG_SPACE(sizeof(uint16_t))] = { 0 }; 272 + int alen = sockaddr_len(addr->ss_family); 273 + struct msghdr msg = { 0 }; 274 + struct iovec iov = { 0 }; 275 + int ret; 276 + 277 + iov.iov_base = send_buf; 278 + iov.iov_len = send_len; 279 + 280 + msg.msg_iov = &iov; 281 + msg.msg_iovlen = 1; 282 + msg.msg_name = addr; 283 + msg.msg_namelen = alen; 284 + 285 + if (gso_size > 0) { 286 + struct cmsghdr *cmsg; 287 + 288 + msg.msg_control = control; 289 + msg.msg_controllen = sizeof(control); 290 + 291 + cmsg = CMSG_FIRSTHDR(&msg); 292 + cmsg->cmsg_level = SOL_UDP; 293 + cmsg->cmsg_type = UDP_SEGMENT; 294 + cmsg->cmsg_len = CMSG_LEN(sizeof(uint16_t)); 295 + *(uint16_t *)CMSG_DATA(cmsg) = gso_size; 296 + } 297 + 298 + ret = sendmsg(socket, &msg, 0); 202 299 if (ret < 0) 203 - fprintf(stderr, "can't send: %s\n", strerror(errno)); 204 - ret = (unsigned int)ret != req.nh.nlmsg_len; 300 + perror("sendmsg"); 205 301 206 - close(rtnl); 207 302 return ret; 303 + } 304 + 305 + static int validate_hdrlen(uint8_t **cur, int *len, int x) 306 + { 307 + if (*len < x) 308 + return -1; 309 + *cur += x; 310 + *len -= x; 311 + return 0; 312 + } 313 + 314 + static int parse_udp_tunnel_vnet_packet(uint8_t *buf, int len, int tunnel_type, 315 + bool is_tap) 316 + { 317 + struct ipv6hdr *iph6; 318 + struct udphdr *udph; 319 + struct iphdr *iph4; 320 + uint8_t *cur = buf; 321 + 322 + if (validate_hdrlen(&cur, &len, TUN_VNET_TNL_SIZE)) 323 + return -1; 324 + 325 + if (is_tap) { 326 + if (validate_hdrlen(&cur, &len, ETH_HLEN)) 327 + return -1; 328 + } 329 + 330 + if (tunnel_type & UDP_TUNNEL_OUTER_IPV4) { 331 + iph4 = (struct iphdr *)cur; 332 + if (validate_hdrlen(&cur, &len, sizeof(struct iphdr))) 333 + return -1; 334 + if (iph4->version != 4 || iph4->protocol != IPPROTO_UDP) 335 + return -1; 336 + } else { 337 + iph6 = (struct ipv6hdr *)cur; 338 + if (validate_hdrlen(&cur, &len, sizeof(struct ipv6hdr))) 339 + return -1; 340 + if (iph6->version != 6 || iph6->nexthdr != IPPROTO_UDP) 341 + return -1; 342 + } 343 + 344 + udph = (struct udphdr *)cur; 345 + if (validate_hdrlen(&cur, &len, sizeof(struct udphdr))) 346 + return -1; 347 + if (ntohs(udph->dest) != VN_PORT) 348 + return -1; 349 + 350 + if (validate_hdrlen(&cur, &len, GENEVE_HLEN)) 351 + return -1; 352 + if (validate_hdrlen(&cur, &len, ETH_HLEN)) 353 + return -1; 354 + 355 + if (tunnel_type & UDP_TUNNEL_INNER_IPV4) { 356 + iph4 = (struct iphdr *)cur; 357 + if (validate_hdrlen(&cur, &len, sizeof(struct iphdr))) 358 + return -1; 359 + if (iph4->version != 4 || iph4->protocol != IPPROTO_UDP) 360 + return -1; 361 + } else { 362 + iph6 = (struct ipv6hdr *)cur; 363 + if (validate_hdrlen(&cur, &len, sizeof(struct ipv6hdr))) 364 + return -1; 365 + if (iph6->version != 6 || iph6->nexthdr != IPPROTO_UDP) 366 + return -1; 367 + } 368 + 369 + udph = (struct udphdr *)cur; 370 + if (validate_hdrlen(&cur, &len, sizeof(struct udphdr))) 371 + return -1; 372 + if (ntohs(udph->dest) != UDP_DST_PORT) 373 + return -1; 374 + 375 + return len; 208 376 } 209 377 210 378 FIXTURE(tun) ··· 505 127 close(self->fd2); 506 128 } 507 129 508 - TEST_F(tun, delete_detach_close) { 130 + TEST_F(tun, delete_detach_close) 131 + { 509 132 EXPECT_EQ(tun_delete(self->ifname), 0); 510 133 EXPECT_EQ(tun_detach(self->fd, self->ifname), -1); 511 134 EXPECT_EQ(errno, 22); 512 135 } 513 136 514 - TEST_F(tun, detach_delete_close) { 137 + TEST_F(tun, detach_delete_close) 138 + { 515 139 EXPECT_EQ(tun_detach(self->fd, self->ifname), 0); 516 140 EXPECT_EQ(tun_delete(self->ifname), 0); 517 141 } 518 142 519 - TEST_F(tun, detach_close_delete) { 143 + TEST_F(tun, detach_close_delete) 144 + { 520 145 EXPECT_EQ(tun_detach(self->fd, self->ifname), 0); 521 146 close(self->fd); 522 147 self->fd = -1; 523 148 EXPECT_EQ(tun_delete(self->ifname), 0); 524 149 } 525 150 526 - TEST_F(tun, reattach_delete_close) { 151 + TEST_F(tun, reattach_delete_close) 152 + { 527 153 EXPECT_EQ(tun_detach(self->fd, self->ifname), 0); 528 154 EXPECT_EQ(tun_attach(self->fd, self->ifname), 0); 529 155 EXPECT_EQ(tun_delete(self->ifname), 0); 530 156 } 531 157 532 - TEST_F(tun, reattach_close_delete) { 158 + TEST_F(tun, reattach_close_delete) 159 + { 533 160 EXPECT_EQ(tun_detach(self->fd, self->ifname), 0); 534 161 EXPECT_EQ(tun_attach(self->fd, self->ifname), 0); 535 162 close(self->fd); 536 163 self->fd = -1; 537 164 EXPECT_EQ(tun_delete(self->ifname), 0); 538 165 } 166 + 167 + FIXTURE(tun_vnet_udptnl) 168 + { 169 + char ifname[IFNAMSIZ]; 170 + int fd, sock; 171 + }; 172 + 173 + FIXTURE_VARIANT(tun_vnet_udptnl) 174 + { 175 + int tunnel_type; 176 + int gso_size; 177 + int data_size; 178 + int r_num_mss; 179 + bool is_tap, no_gso; 180 + }; 181 + 182 + /* clang-format off */ 183 + #define TUN_VNET_UDPTNL_VARIANT_ADD(type, desc) \ 184 + FIXTURE_VARIANT_ADD(tun_vnet_udptnl, desc##_nogsosz_1byte) { \ 185 + /* no GSO: send a single byte */ \ 186 + .tunnel_type = type, \ 187 + .data_size = 1, \ 188 + .r_num_mss = 1, \ 189 + .is_tap = true, \ 190 + .no_gso = true, \ 191 + }; \ 192 + FIXTURE_VARIANT_ADD(tun_vnet_udptnl, desc##_nogsosz_1mss) { \ 193 + /* no GSO: send a single MSS, fall back to no GSO */ \ 194 + .tunnel_type = type, \ 195 + .data_size = UDP_TUNNEL_MSS(type), \ 196 + .r_num_mss = 1, \ 197 + .is_tap = true, \ 198 + .no_gso = true, \ 199 + }; \ 200 + FIXTURE_VARIANT_ADD(tun_vnet_udptnl, desc##_nogsosz_gtmss) { \ 201 + /* no GSO: send a single MSS + 1B: fail */ \ 202 + .tunnel_type = type, \ 203 + .data_size = UDP_TUNNEL_MSS(type) + 1, \ 204 + .r_num_mss = 1, \ 205 + .is_tap = true, \ 206 + .no_gso = true, \ 207 + }; \ 208 + FIXTURE_VARIANT_ADD(tun_vnet_udptnl, desc##_1byte) { \ 209 + /* GSO: send 1 byte, gso 1 byte, fall back to no GSO */ \ 210 + .tunnel_type = type, \ 211 + .gso_size = 1, \ 212 + .data_size = 1, \ 213 + .r_num_mss = 1, \ 214 + .is_tap = true, \ 215 + .no_gso = true, \ 216 + }; \ 217 + FIXTURE_VARIANT_ADD(tun_vnet_udptnl, desc##_1mss) { \ 218 + /* send a single MSS: fall back to no GSO */ \ 219 + .tunnel_type = type, \ 220 + .gso_size = UDP_TUNNEL_MSS(type), \ 221 + .data_size = UDP_TUNNEL_MSS(type), \ 222 + .r_num_mss = 1, \ 223 + .is_tap = true, \ 224 + .no_gso = true, \ 225 + }; \ 226 + FIXTURE_VARIANT_ADD(tun_vnet_udptnl, desc##_ltgso) { \ 227 + /* data <= MSS < gso: will fall back to no GSO */ \ 228 + .tunnel_type = type, \ 229 + .gso_size = UDP_TUNNEL_MSS(type) + 1, \ 230 + .data_size = UDP_TUNNEL_MSS(type), \ 231 + .r_num_mss = 1, \ 232 + .is_tap = true, \ 233 + .no_gso = true, \ 234 + }; \ 235 + FIXTURE_VARIANT_ADD(tun_vnet_udptnl, desc##_gtgso) { \ 236 + /* GSO: a single MSS + 1B */ \ 237 + .tunnel_type = type, \ 238 + .gso_size = UDP_TUNNEL_MSS(type), \ 239 + .data_size = UDP_TUNNEL_MSS(type) + 1, \ 240 + .r_num_mss = 2, \ 241 + .is_tap = true, \ 242 + }; \ 243 + FIXTURE_VARIANT_ADD(tun_vnet_udptnl, desc##_2mss) { \ 244 + /* no GSO: send exactly 2 MSS */ \ 245 + .tunnel_type = type, \ 246 + .gso_size = UDP_TUNNEL_MSS(type), \ 247 + .data_size = UDP_TUNNEL_MSS(type) * 2, \ 248 + .r_num_mss = 2, \ 249 + .is_tap = true, \ 250 + }; \ 251 + FIXTURE_VARIANT_ADD(tun_vnet_udptnl, desc##_maxbytes) { \ 252 + /* GSO: send max bytes */ \ 253 + .tunnel_type = type, \ 254 + .gso_size = UDP_TUNNEL_MSS(type), \ 255 + .data_size = UDP_TUNNEL_MAX(type, true), \ 256 + .r_num_mss = UDP_TUNNEL_MAX(type, true) / \ 257 + UDP_TUNNEL_MSS(type) + 1, \ 258 + .is_tap = true, \ 259 + }; \ 260 + FIXTURE_VARIANT_ADD(tun_vnet_udptnl, desc##_over_maxbytes) { \ 261 + /* GSO: send oversize max bytes: fail */ \ 262 + .tunnel_type = type, \ 263 + .gso_size = UDP_TUNNEL_MSS(type), \ 264 + .data_size = ETH_MAX_MTU, \ 265 + .r_num_mss = ETH_MAX_MTU / UDP_TUNNEL_MSS(type) + 1, \ 266 + .is_tap = true, \ 267 + }; \ 268 + FIXTURE_VARIANT_ADD(tun_vnet_udptnl, desc##_maxsegs) { \ 269 + /* GSO: send max number of min sized segments */ \ 270 + .tunnel_type = type, \ 271 + .gso_size = 1, \ 272 + .data_size = UDP_TUNNEL_MAX_SEGMENTS, \ 273 + .r_num_mss = UDP_TUNNEL_MAX_SEGMENTS, \ 274 + .is_tap = true, \ 275 + }; \ 276 + FIXTURE_VARIANT_ADD(tun_vnet_udptnl, desc##_5byte) { \ 277 + /* GSO: send 5 bytes, gso 2 bytes */ \ 278 + .tunnel_type = type, \ 279 + .gso_size = 2, \ 280 + .data_size = 5, \ 281 + .r_num_mss = 3, \ 282 + .is_tap = true, \ 283 + } /* clang-format on */ 284 + 285 + TUN_VNET_UDPTNL_VARIANT_ADD(UDP_TUNNEL_GENEVE_4IN4, 4in4); 286 + TUN_VNET_UDPTNL_VARIANT_ADD(UDP_TUNNEL_GENEVE_6IN4, 6in4); 287 + TUN_VNET_UDPTNL_VARIANT_ADD(UDP_TUNNEL_GENEVE_4IN6, 4in6); 288 + TUN_VNET_UDPTNL_VARIANT_ADD(UDP_TUNNEL_GENEVE_6IN6, 6in6); 289 + 290 + static void assign_ifaddr_vars(int family, int is_outer, void **srcip, 291 + void **dstip, void **srcmac, void **dstmac) 292 + { 293 + if (is_outer) { 294 + if (family == AF_INET) { 295 + *srcip = (void *)&param_ipaddr4_outer_src; 296 + *dstip = (void *)&param_ipaddr4_outer_dst; 297 + } else { 298 + *srcip = (void *)&param_ipaddr6_outer_src; 299 + *dstip = (void *)&param_ipaddr6_outer_dst; 300 + } 301 + *srcmac = param_hwaddr_outer_src; 302 + *dstmac = param_hwaddr_outer_dst; 303 + } else { 304 + if (family == AF_INET) { 305 + *srcip = (void *)&param_ipaddr4_inner_src; 306 + *dstip = (void *)&param_ipaddr4_inner_dst; 307 + } else { 308 + *srcip = (void *)&param_ipaddr6_inner_src; 309 + *dstip = (void *)&param_ipaddr6_inner_dst; 310 + } 311 + *srcmac = param_hwaddr_inner_src; 312 + *dstmac = param_hwaddr_inner_dst; 313 + } 314 + } 315 + 316 + static void assign_sockaddr_vars(int family, int is_outer, 317 + struct sockaddr_storage *src, 318 + struct sockaddr_storage *dst) 319 + { 320 + src->ss_family = family; 321 + dst->ss_family = family; 322 + 323 + if (family == AF_INET) { 324 + struct sockaddr_in *s4 = (struct sockaddr_in *)src; 325 + struct sockaddr_in *d4 = (struct sockaddr_in *)dst; 326 + 327 + s4->sin_addr = is_outer ? param_ipaddr4_outer_src : 328 + param_ipaddr4_inner_src; 329 + d4->sin_addr = is_outer ? param_ipaddr4_outer_dst : 330 + param_ipaddr4_inner_dst; 331 + if (!is_outer) { 332 + s4->sin_port = htons(UDP_SRC_PORT); 333 + d4->sin_port = htons(UDP_DST_PORT); 334 + } 335 + } else { 336 + struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)src; 337 + struct sockaddr_in6 *d6 = (struct sockaddr_in6 *)dst; 338 + 339 + s6->sin6_addr = is_outer ? param_ipaddr6_outer_src : 340 + param_ipaddr6_inner_src; 341 + d6->sin6_addr = is_outer ? param_ipaddr6_outer_dst : 342 + param_ipaddr6_inner_dst; 343 + if (!is_outer) { 344 + s6->sin6_port = htons(UDP_SRC_PORT); 345 + d6->sin6_port = htons(UDP_DST_PORT); 346 + } 347 + } 348 + } 349 + 350 + FIXTURE_SETUP(tun_vnet_udptnl) 351 + { 352 + int ret, family, prefix, flags, features; 353 + int tunnel_type = variant->tunnel_type; 354 + struct sockaddr_storage ssa, dsa; 355 + void *sip, *dip, *smac, *dmac; 356 + 357 + flags = (variant->is_tap ? IFF_TAP : IFF_TUN) | IFF_VNET_HDR | 358 + IFF_MULTI_QUEUE | IFF_NO_PI; 359 + features = TUN_F_CSUM | TUN_F_UDP_TUNNEL_GSO | 360 + TUN_F_UDP_TUNNEL_GSO_CSUM | TUN_F_USO4 | TUN_F_USO6; 361 + self->fd = tun_open(self->ifname, flags, TUN_VNET_TNL_SIZE, features, 362 + param_hwaddr_outer_src); 363 + ASSERT_GE(self->fd, 0); 364 + 365 + family = (tunnel_type & UDP_TUNNEL_OUTER_IPV4) ? AF_INET : AF_INET6; 366 + prefix = (family == AF_INET) ? IPPREFIX_LEN : IP6PREFIX_LEN; 367 + assign_ifaddr_vars(family, 1, &sip, &dip, &smac, &dmac); 368 + 369 + ret = ip_addr_add(self->ifname, family, sip, prefix); 370 + ASSERT_EQ(ret, 0); 371 + ret = ip_neigh_add(self->ifname, family, dip, dmac); 372 + ASSERT_EQ(ret, 0); 373 + ret = ip_route_check(self->ifname, family, sip); 374 + ASSERT_EQ(ret, 0); 375 + 376 + ret = geneve_create(param_dev_geneve_name, family, dip, 377 + param_hwaddr_inner_src); 378 + ASSERT_EQ(ret, 0); 379 + 380 + family = (tunnel_type & UDP_TUNNEL_INNER_IPV4) ? AF_INET : AF_INET6; 381 + prefix = (family == AF_INET) ? IPPREFIX_LEN : IP6PREFIX_LEN; 382 + assign_ifaddr_vars(family, 0, &sip, &dip, &smac, &dmac); 383 + 384 + ret = ip_addr_add(param_dev_geneve_name, family, sip, prefix); 385 + ASSERT_EQ(ret, 0); 386 + ret = ip_neigh_add(param_dev_geneve_name, family, dip, dmac); 387 + ASSERT_EQ(ret, 0); 388 + ret = ip_route_check(param_dev_geneve_name, family, sip); 389 + ASSERT_EQ(ret, 0); 390 + 391 + assign_sockaddr_vars(family, 0, &ssa, &dsa); 392 + self->sock = udp_socket_open(&ssa, false, true, &dsa); 393 + ASSERT_GE(self->sock, 0); 394 + } 395 + 396 + FIXTURE_TEARDOWN(tun_vnet_udptnl) 397 + { 398 + int ret; 399 + 400 + if (self->sock != -1) 401 + close(self->sock); 402 + 403 + ret = ip_link_del(param_dev_geneve_name); 404 + EXPECT_EQ(ret, 0); 405 + 406 + ret = tun_delete(self->ifname); 407 + EXPECT_EQ(ret, 0); 408 + } 409 + 410 + static int build_gso_packet_into_tun(const FIXTURE_VARIANT(tun_vnet_udptnl) * 411 + variant, 412 + uint8_t *buf) 413 + { 414 + int pktlen, hlen, proto, inner_family, outer_family; 415 + int tunnel_type = variant->tunnel_type; 416 + int payload_len = variant->data_size; 417 + int gso_size = variant->gso_size; 418 + uint8_t *outer_udph, *cur = buf; 419 + void *sip, *dip, *smac, *dmac; 420 + bool is_tap = variant->is_tap; 421 + 422 + hlen = (is_tap ? ETH_HLEN : 0) + UDP_TUNNEL_HDRLEN(tunnel_type); 423 + inner_family = (tunnel_type & UDP_TUNNEL_INNER_IPV4) ? AF_INET : 424 + AF_INET6; 425 + outer_family = (tunnel_type & UDP_TUNNEL_OUTER_IPV4) ? AF_INET : 426 + AF_INET6; 427 + 428 + cur += build_virtio_net_hdr_v1_hash_tunnel(cur, is_tap, hlen, gso_size, 429 + outer_family, inner_family); 430 + 431 + pktlen = hlen + payload_len; 432 + assign_ifaddr_vars(outer_family, 1, &sip, &dip, &smac, &dmac); 433 + 434 + if (is_tap) { 435 + proto = outer_family == AF_INET ? ETH_P_IP : ETH_P_IPV6; 436 + pktlen -= ETH_HLEN; 437 + cur += build_eth(cur, proto, dmac, smac); 438 + } 439 + 440 + if (outer_family == AF_INET) { 441 + pktlen = pktlen - sizeof(struct iphdr); 442 + cur += build_ipv4_header(cur, IPPROTO_UDP, pktlen, dip, sip); 443 + } else { 444 + pktlen = pktlen - sizeof(struct ipv6hdr); 445 + cur += build_ipv6_header(cur, IPPROTO_UDP, 0, pktlen, dip, sip); 446 + } 447 + 448 + outer_udph = cur; 449 + assign_ifaddr_vars(inner_family, 0, &sip, &dip, &smac, &dmac); 450 + 451 + pktlen -= sizeof(struct udphdr); 452 + proto = inner_family == AF_INET ? ETH_P_IP : ETH_P_IPV6; 453 + cur += build_udp_header(cur, UDP_SRC_PORT, VN_PORT, pktlen); 454 + cur += build_geneve_header(cur, VN_ID); 455 + cur += build_eth(cur, proto, dmac, smac); 456 + 457 + pktlen = sizeof(struct udphdr) + payload_len; 458 + if (inner_family == AF_INET) 459 + cur += build_ipv4_header(cur, IPPROTO_UDP, pktlen, dip, sip); 460 + else 461 + cur += build_ipv6_header(cur, IPPROTO_UDP, 0, pktlen, dip, sip); 462 + 463 + cur += build_udp_packet(cur, UDP_DST_PORT, UDP_SRC_PORT, payload_len, 464 + inner_family, false); 465 + 466 + build_udp_packet_csum(outer_udph, outer_family, false); 467 + 468 + return cur - buf; 469 + } 470 + 471 + static int 472 + receive_gso_packet_from_tunnel(FIXTURE_DATA(tun_vnet_udptnl) * self, 473 + const FIXTURE_VARIANT(tun_vnet_udptnl) * variant, 474 + int *r_num_mss) 475 + { 476 + uint8_t packet_buf[MAX_VNET_TUNNEL_PACKET_SZ]; 477 + int len, total_len = 0, socket = self->sock; 478 + int payload_len = variant->data_size; 479 + 480 + while (total_len < payload_len) { 481 + len = recv(socket, packet_buf, sizeof(packet_buf), 0); 482 + if (len <= 0) { 483 + if (len < 0 && errno != EAGAIN && errno != EWOULDBLOCK) 484 + perror("recv"); 485 + break; 486 + } 487 + 488 + (*r_num_mss)++; 489 + total_len += len; 490 + } 491 + 492 + return total_len; 493 + } 494 + 495 + static int send_gso_packet_into_tunnel(FIXTURE_DATA(tun_vnet_udptnl) * self, 496 + const FIXTURE_VARIANT(tun_vnet_udptnl) * 497 + variant) 498 + { 499 + int family = (variant->tunnel_type & UDP_TUNNEL_INNER_IPV4) ? AF_INET : 500 + AF_INET6; 501 + uint8_t buf[MAX_VNET_TUNNEL_PACKET_SZ] = { 0 }; 502 + int payload_len = variant->data_size; 503 + int gso_size = variant->gso_size; 504 + struct sockaddr_storage ssa, dsa; 505 + 506 + assign_sockaddr_vars(family, 0, &ssa, &dsa); 507 + return send_gso_udp_msg(self->sock, &dsa, buf, payload_len, gso_size); 508 + } 509 + 510 + static int 511 + receive_gso_packet_from_tun(FIXTURE_DATA(tun_vnet_udptnl) * self, 512 + const FIXTURE_VARIANT(tun_vnet_udptnl) * variant, 513 + struct virtio_net_hdr_v1_hash_tunnel *vnet_hdr) 514 + { 515 + struct timeval timeout = { .tv_sec = TIMEOUT_SEC }; 516 + uint8_t buf[MAX_VNET_TUNNEL_PACKET_SZ]; 517 + int tunnel_type = variant->tunnel_type; 518 + int payload_len = variant->data_size; 519 + bool is_tap = variant->is_tap; 520 + int ret, len, total_len = 0; 521 + int tun_fd = self->fd; 522 + fd_set fdset; 523 + 524 + while (total_len < payload_len) { 525 + FD_ZERO(&fdset); 526 + FD_SET(tun_fd, &fdset); 527 + 528 + ret = select(tun_fd + 1, &fdset, NULL, NULL, &timeout); 529 + if (ret <= 0) { 530 + perror("select"); 531 + break; 532 + } 533 + if (!FD_ISSET(tun_fd, &fdset)) 534 + continue; 535 + 536 + len = read(tun_fd, buf, sizeof(buf)); 537 + if (len <= 0) { 538 + if (len < 0 && errno != EAGAIN && errno != EWOULDBLOCK) 539 + perror("read"); 540 + break; 541 + } 542 + 543 + len = parse_udp_tunnel_vnet_packet(buf, len, tunnel_type, 544 + is_tap); 545 + if (len < 0) 546 + continue; 547 + 548 + if (total_len == 0) 549 + memcpy(vnet_hdr, buf, TUN_VNET_TNL_SIZE); 550 + 551 + total_len += len; 552 + } 553 + 554 + return total_len; 555 + } 556 + 557 + TEST_F(tun_vnet_udptnl, send_gso_packet) 558 + { 559 + uint8_t pkt[MAX_VNET_TUNNEL_PACKET_SZ]; 560 + int r_num_mss = 0; 561 + int ret, off; 562 + 563 + memset(pkt, 0, sizeof(pkt)); 564 + off = build_gso_packet_into_tun(variant, pkt); 565 + ret = write(self->fd, pkt, off); 566 + ASSERT_EQ(ret, off); 567 + 568 + ret = receive_gso_packet_from_tunnel(self, variant, &r_num_mss); 569 + ASSERT_EQ(ret, variant->data_size); 570 + ASSERT_EQ(r_num_mss, variant->r_num_mss); 571 + } 572 + 573 + TEST_F(tun_vnet_udptnl, recv_gso_packet) 574 + { 575 + struct virtio_net_hdr_v1_hash_tunnel vnet_hdr = { 0 }; 576 + struct virtio_net_hdr_v1 *vh = &vnet_hdr.hash_hdr.hdr; 577 + int ret, gso_type = VIRTIO_NET_HDR_GSO_UDP_L4; 578 + 579 + ret = send_gso_packet_into_tunnel(self, variant); 580 + ASSERT_EQ(ret, variant->data_size); 581 + 582 + memset(&vnet_hdr, 0, sizeof(vnet_hdr)); 583 + ret = receive_gso_packet_from_tun(self, variant, &vnet_hdr); 584 + ASSERT_EQ(ret, variant->data_size); 585 + 586 + if (!variant->no_gso) { 587 + ASSERT_EQ(vh->gso_size, variant->gso_size); 588 + gso_type |= (variant->tunnel_type & UDP_TUNNEL_OUTER_IPV4) ? 589 + (VIRTIO_NET_HDR_GSO_UDP_TUNNEL_IPV4) : 590 + (VIRTIO_NET_HDR_GSO_UDP_TUNNEL_IPV6); 591 + ASSERT_EQ(vh->gso_type, gso_type); 592 + } 593 + } 594 + 595 + XFAIL_ADD(tun_vnet_udptnl, 4in4_nogsosz_gtmss, recv_gso_packet); 596 + XFAIL_ADD(tun_vnet_udptnl, 6in4_nogsosz_gtmss, recv_gso_packet); 597 + XFAIL_ADD(tun_vnet_udptnl, 4in6_nogsosz_gtmss, recv_gso_packet); 598 + XFAIL_ADD(tun_vnet_udptnl, 6in6_nogsosz_gtmss, recv_gso_packet); 599 + 600 + XFAIL_ADD(tun_vnet_udptnl, 4in4_over_maxbytes, send_gso_packet); 601 + XFAIL_ADD(tun_vnet_udptnl, 6in4_over_maxbytes, send_gso_packet); 602 + XFAIL_ADD(tun_vnet_udptnl, 4in6_over_maxbytes, send_gso_packet); 603 + XFAIL_ADD(tun_vnet_udptnl, 6in6_over_maxbytes, send_gso_packet); 604 + 605 + XFAIL_ADD(tun_vnet_udptnl, 4in4_over_maxbytes, recv_gso_packet); 606 + XFAIL_ADD(tun_vnet_udptnl, 6in4_over_maxbytes, recv_gso_packet); 607 + XFAIL_ADD(tun_vnet_udptnl, 4in6_over_maxbytes, recv_gso_packet); 608 + XFAIL_ADD(tun_vnet_udptnl, 6in6_over_maxbytes, recv_gso_packet); 539 609 540 610 TEST_HARNESS_MAIN
+390
tools/testing/selftests/net/tuntap_helpers.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + 3 + #ifndef _TUNTAP_HELPERS_H 4 + #define _TUNTAP_HELPERS_H 5 + 6 + #include <errno.h> 7 + #include <linux/if_packet.h> 8 + #include <linux/ipv6.h> 9 + #include <linux/virtio_net.h> 10 + #include <netinet/in.h> 11 + #include <netinet/if_ether.h> 12 + #include <netinet/udp.h> 13 + #include <stdio.h> 14 + #include <stdlib.h> 15 + #include <string.h> 16 + #include <unistd.h> 17 + #include <ynl.h> 18 + 19 + #include "rt-route-user.h" 20 + #include "rt-addr-user.h" 21 + #include "rt-neigh-user.h" 22 + #include "rt-link-user.h" 23 + 24 + #define GENEVE_HLEN 8 25 + #define PKT_DATA 0xCB 26 + #define TUNTAP_DEFAULT_TTL 8 27 + #define TUNTAP_DEFAULT_IPID 1337 28 + 29 + unsigned int if_nametoindex(const char *ifname); 30 + 31 + static inline int ip_addr_len(int family) 32 + { 33 + return (family == AF_INET) ? sizeof(struct in_addr) : 34 + sizeof(struct in6_addr); 35 + } 36 + 37 + static inline void fill_ifaddr_msg(struct ifaddrmsg *ifam, int family, 38 + int prefix, int flags, const char *dev) 39 + { 40 + ifam->ifa_family = family; 41 + ifam->ifa_prefixlen = prefix; 42 + ifam->ifa_index = if_nametoindex(dev); 43 + ifam->ifa_flags = flags; 44 + ifam->ifa_scope = RT_SCOPE_UNIVERSE; 45 + } 46 + 47 + static inline int ip_addr_add(const char *dev, int family, void *addr, 48 + uint8_t prefix) 49 + { 50 + int nl_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; 51 + int ifa_flags = IFA_F_PERMANENT | IFA_F_NODAD; 52 + int ret = -1, ipalen = ip_addr_len(family); 53 + struct rt_addr_newaddr_req *req; 54 + struct ynl_sock *ys; 55 + 56 + ys = ynl_sock_create(&ynl_rt_addr_family, NULL); 57 + if (!ys) 58 + return -1; 59 + 60 + req = rt_addr_newaddr_req_alloc(); 61 + if (!req) 62 + goto err_req_alloc; 63 + 64 + fill_ifaddr_msg(&req->_hdr, family, prefix, ifa_flags, dev); 65 + rt_addr_newaddr_req_set_nlflags(req, nl_flags); 66 + rt_addr_newaddr_req_set_local(req, addr, ipalen); 67 + 68 + ret = rt_addr_newaddr(ys, req); 69 + rt_addr_newaddr_req_free(req); 70 + err_req_alloc: 71 + ynl_sock_destroy(ys); 72 + return ret; 73 + } 74 + 75 + static inline void fill_neigh_req_header(struct ndmsg *ndm, int family, 76 + int state, const char *dev) 77 + { 78 + ndm->ndm_family = family; 79 + ndm->ndm_ifindex = if_nametoindex(dev); 80 + ndm->ndm_state = state; 81 + ndm->ndm_flags = 0; 82 + ndm->ndm_type = RTN_UNICAST; 83 + } 84 + 85 + static inline int ip_neigh_add(const char *dev, int family, void *addr, 86 + unsigned char *lladdr) 87 + { 88 + int nl_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; 89 + int ret = -1, ipalen = ip_addr_len(family); 90 + struct rt_neigh_newneigh_req *req; 91 + struct ynl_sock *ys; 92 + 93 + ys = ynl_sock_create(&ynl_rt_neigh_family, NULL); 94 + if (!ys) 95 + return -1; 96 + 97 + req = rt_neigh_newneigh_req_alloc(); 98 + if (!req) 99 + goto err_req_alloc; 100 + 101 + fill_neigh_req_header(&req->_hdr, family, NUD_PERMANENT, dev); 102 + rt_neigh_newneigh_req_set_nlflags(req, nl_flags); 103 + rt_neigh_newneigh_req_set_dst(req, addr, ipalen); 104 + rt_neigh_newneigh_req_set_lladdr(req, lladdr, ETH_ALEN); 105 + rt_neigh_newneigh_req_set_ifindex(req, if_nametoindex(dev)); 106 + 107 + ret = rt_neigh_newneigh(ys, req); 108 + rt_neigh_newneigh_req_free(req); 109 + err_req_alloc: 110 + ynl_sock_destroy(ys); 111 + return ret; 112 + } 113 + 114 + static inline void fill_route_req_header(struct rtmsg *rtm, int family, 115 + int table) 116 + { 117 + rtm->rtm_family = family; 118 + rtm->rtm_table = table; 119 + } 120 + 121 + static inline int 122 + ip_route_get(const char *dev, int family, int table, void *dst, 123 + void (*parse_rsp)(struct rt_route_getroute_rsp *rsp, void *out), 124 + void *out) 125 + { 126 + int ret = -1, ipalen = ip_addr_len(family); 127 + struct rt_route_getroute_req *req; 128 + struct rt_route_getroute_rsp *rsp; 129 + struct ynl_sock *ys; 130 + 131 + ys = ynl_sock_create(&ynl_rt_route_family, NULL); 132 + if (!ys) 133 + return -1; 134 + 135 + req = rt_route_getroute_req_alloc(); 136 + if (!req) 137 + goto err_req_alloc; 138 + 139 + fill_route_req_header(&req->_hdr, family, table); 140 + rt_route_getroute_req_set_nlflags(req, NLM_F_REQUEST); 141 + rt_route_getroute_req_set_dst(req, dst, ipalen); 142 + rt_route_getroute_req_set_oif(req, if_nametoindex(dev)); 143 + 144 + rsp = rt_route_getroute(ys, req); 145 + if (!rsp) 146 + goto err_rsp_get; 147 + 148 + ret = 0; 149 + if (parse_rsp) 150 + parse_rsp(rsp, out); 151 + 152 + rt_route_getroute_rsp_free(rsp); 153 + err_rsp_get: 154 + rt_route_getroute_req_free(req); 155 + err_req_alloc: 156 + ynl_sock_destroy(ys); 157 + return ret; 158 + } 159 + 160 + static inline int 161 + ip_link_add(const char *dev, char *link_type, 162 + int (*fill_link_attr)(struct rt_link_newlink_req *req, void *data), 163 + void *data) 164 + { 165 + int nl_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; 166 + struct rt_link_newlink_req *req; 167 + struct ynl_sock *ys; 168 + int ret = -1; 169 + 170 + ys = ynl_sock_create(&ynl_rt_link_family, NULL); 171 + if (!ys) 172 + return -1; 173 + 174 + req = rt_link_newlink_req_alloc(); 175 + if (!req) 176 + goto err_req_alloc; 177 + 178 + req->_hdr.ifi_flags = IFF_UP; 179 + rt_link_newlink_req_set_nlflags(req, nl_flags); 180 + rt_link_newlink_req_set_ifname(req, dev); 181 + rt_link_newlink_req_set_linkinfo_kind(req, link_type); 182 + 183 + if (fill_link_attr && fill_link_attr(req, data) < 0) 184 + goto err_attr_fill; 185 + 186 + ret = rt_link_newlink(ys, req); 187 + err_attr_fill: 188 + rt_link_newlink_req_free(req); 189 + err_req_alloc: 190 + ynl_sock_destroy(ys); 191 + return ret; 192 + } 193 + 194 + static inline int ip_link_del(const char *dev) 195 + { 196 + struct rt_link_dellink_req *req; 197 + struct ynl_sock *ys; 198 + int ret = -1; 199 + 200 + ys = ynl_sock_create(&ynl_rt_link_family, NULL); 201 + if (!ys) 202 + return -1; 203 + 204 + req = rt_link_dellink_req_alloc(); 205 + if (!req) 206 + goto err_req_alloc; 207 + 208 + rt_link_dellink_req_set_nlflags(req, NLM_F_REQUEST); 209 + rt_link_dellink_req_set_ifname(req, dev); 210 + 211 + ret = rt_link_dellink(ys, req); 212 + rt_link_dellink_req_free(req); 213 + err_req_alloc: 214 + ynl_sock_destroy(ys); 215 + return ret; 216 + } 217 + 218 + static inline size_t build_eth(uint8_t *buf, uint16_t proto, unsigned char *src, 219 + unsigned char *dest) 220 + { 221 + struct ethhdr *eth = (struct ethhdr *)buf; 222 + 223 + eth->h_proto = htons(proto); 224 + memcpy(eth->h_source, src, ETH_ALEN); 225 + memcpy(eth->h_dest, dest, ETH_ALEN); 226 + 227 + return ETH_HLEN; 228 + } 229 + 230 + static inline uint32_t add_csum(const uint8_t *buf, int len) 231 + { 232 + uint16_t *sbuf = (uint16_t *)buf; 233 + uint32_t sum = 0; 234 + 235 + while (len > 1) { 236 + sum += *sbuf++; 237 + len -= 2; 238 + } 239 + 240 + if (len) 241 + sum += *(uint8_t *)sbuf; 242 + 243 + return sum; 244 + } 245 + 246 + static inline uint16_t finish_ip_csum(uint32_t sum) 247 + { 248 + while (sum >> 16) 249 + sum = (sum & 0xffff) + (sum >> 16); 250 + return ~((uint16_t)sum); 251 + } 252 + 253 + static inline uint16_t build_ip_csum(const uint8_t *buf, int len, uint32_t sum) 254 + { 255 + sum += add_csum(buf, len); 256 + return finish_ip_csum(sum); 257 + } 258 + 259 + static inline int build_ipv4_header(uint8_t *buf, uint8_t proto, 260 + int payload_len, struct in_addr *src, 261 + struct in_addr *dst) 262 + { 263 + struct iphdr *iph = (struct iphdr *)buf; 264 + 265 + iph->ihl = 5; 266 + iph->version = 4; 267 + iph->ttl = TUNTAP_DEFAULT_TTL; 268 + iph->tot_len = htons(sizeof(*iph) + payload_len); 269 + iph->id = htons(TUNTAP_DEFAULT_IPID); 270 + iph->protocol = proto; 271 + iph->saddr = src->s_addr; 272 + iph->daddr = dst->s_addr; 273 + iph->check = build_ip_csum(buf, iph->ihl << 2, 0); 274 + 275 + return iph->ihl << 2; 276 + } 277 + 278 + static inline void ipv6_set_dsfield(struct ipv6hdr *ip6h, uint8_t dsfield) 279 + { 280 + uint16_t val, *ptr = (uint16_t *)ip6h; 281 + 282 + val = ntohs(*ptr); 283 + val &= 0xF00F; 284 + val |= ((uint16_t)dsfield) << 4; 285 + *ptr = htons(val); 286 + } 287 + 288 + static inline int build_ipv6_header(uint8_t *buf, uint8_t proto, 289 + uint8_t dsfield, int payload_len, 290 + struct in6_addr *src, struct in6_addr *dst) 291 + { 292 + struct ipv6hdr *ip6h = (struct ipv6hdr *)buf; 293 + 294 + ip6h->version = 6; 295 + ip6h->payload_len = htons(payload_len); 296 + ip6h->nexthdr = proto; 297 + ip6h->hop_limit = TUNTAP_DEFAULT_TTL; 298 + ipv6_set_dsfield(ip6h, dsfield); 299 + memcpy(&ip6h->saddr, src, sizeof(ip6h->saddr)); 300 + memcpy(&ip6h->daddr, dst, sizeof(ip6h->daddr)); 301 + 302 + return sizeof(struct ipv6hdr); 303 + } 304 + 305 + static inline int build_geneve_header(uint8_t *buf, uint32_t vni) 306 + { 307 + uint16_t protocol = htons(ETH_P_TEB); 308 + uint32_t geneve_vni = htonl((vni << 8) & 0xffffff00); 309 + 310 + memcpy(buf + 2, &protocol, 2); 311 + memcpy(buf + 4, &geneve_vni, 4); 312 + return GENEVE_HLEN; 313 + } 314 + 315 + static inline int build_udp_header(uint8_t *buf, uint16_t sport, uint16_t dport, 316 + int payload_len) 317 + { 318 + struct udphdr *udph = (struct udphdr *)buf; 319 + 320 + udph->source = htons(sport); 321 + udph->dest = htons(dport); 322 + udph->len = htons(sizeof(*udph) + payload_len); 323 + return sizeof(*udph); 324 + } 325 + 326 + static inline void build_udp_packet_csum(uint8_t *buf, int family, 327 + bool csum_off) 328 + { 329 + struct udphdr *udph = (struct udphdr *)buf; 330 + size_t ipalen = ip_addr_len(family); 331 + uint32_t sum; 332 + 333 + /* No extension IPv4 and IPv6 headers addresses are the last fields */ 334 + sum = add_csum(buf - 2 * ipalen, 2 * ipalen); 335 + sum += htons(IPPROTO_UDP) + udph->len; 336 + 337 + if (!csum_off) 338 + sum += add_csum(buf, udph->len); 339 + 340 + udph->check = finish_ip_csum(sum); 341 + } 342 + 343 + static inline int build_udp_packet(uint8_t *buf, uint16_t sport, uint16_t dport, 344 + int payload_len, int family, bool csum_off) 345 + { 346 + struct udphdr *udph = (struct udphdr *)buf; 347 + 348 + build_udp_header(buf, sport, dport, payload_len); 349 + memset(buf + sizeof(*udph), PKT_DATA, payload_len); 350 + build_udp_packet_csum(buf, family, csum_off); 351 + 352 + return sizeof(*udph) + payload_len; 353 + } 354 + 355 + static inline int build_virtio_net_hdr_v1_hash_tunnel(uint8_t *buf, bool is_tap, 356 + int hdr_len, int gso_size, 357 + int outer_family, 358 + int inner_family) 359 + { 360 + struct virtio_net_hdr_v1_hash_tunnel *vh_tunnel = (void *)buf; 361 + struct virtio_net_hdr_v1 *vh = &vh_tunnel->hash_hdr.hdr; 362 + int outer_iphlen, inner_iphlen, eth_hlen, gso_type; 363 + 364 + eth_hlen = is_tap ? ETH_HLEN : 0; 365 + outer_iphlen = (outer_family == AF_INET) ? sizeof(struct iphdr) : 366 + sizeof(struct ipv6hdr); 367 + inner_iphlen = (inner_family == AF_INET) ? sizeof(struct iphdr) : 368 + sizeof(struct ipv6hdr); 369 + 370 + vh_tunnel->outer_th_offset = eth_hlen + outer_iphlen; 371 + vh_tunnel->inner_nh_offset = vh_tunnel->outer_th_offset + ETH_HLEN + 372 + GENEVE_HLEN + sizeof(struct udphdr); 373 + 374 + vh->csum_start = vh_tunnel->inner_nh_offset + inner_iphlen; 375 + vh->csum_offset = __builtin_offsetof(struct udphdr, check); 376 + vh->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; 377 + vh->hdr_len = hdr_len; 378 + vh->gso_size = gso_size; 379 + 380 + if (gso_size) { 381 + gso_type = outer_family == AF_INET ? 382 + VIRTIO_NET_HDR_GSO_UDP_TUNNEL_IPV4 : 383 + VIRTIO_NET_HDR_GSO_UDP_TUNNEL_IPV6; 384 + vh->gso_type = VIRTIO_NET_HDR_GSO_UDP_L4 | gso_type; 385 + } 386 + 387 + return sizeof(struct virtio_net_hdr_v1_hash_tunnel); 388 + } 389 + 390 + #endif /* _TUNTAP_HELPERS_H */