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 tag 'bpf-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf

Pull bpf fixes from Alexei Starovoitov:

- Followup fixes for resilient spinlock (Kumar Kartikeya Dwivedi):
- Make res_spin_lock test less verbose, since it was spamming BPF
CI on failure, and make the check for AA deadlock stronger
- Fix rebasing mistake and use architecture provided
res_smp_cond_load_acquire
- Convert BPF maps (queue_stack and ringbuf) to resilient spinlock
to address long standing syzbot reports

- Make sure that classic BPF load instruction from SKF_[NET|LL]_OFF
offsets works when skb is fragmeneted (Willem de Bruijn)

* tag 'bpf-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf:
bpf: Convert ringbuf map to rqspinlock
bpf: Convert queue_stack map to rqspinlock
bpf: Use architecture provided res_smp_cond_load_acquire
selftests/bpf: Make res_spin_lock AA test condition stronger
selftests/net: test sk_filter support for SKF_NET_OFF on frags
bpf: support SKF_NET_OFF and SKF_LL_OFF on skb frags
selftests/bpf: Make res_spin_lock test less verbose

+354 -76
+1 -1
arch/arm64/include/asm/rqspinlock.h
··· 86 86 87 87 #endif 88 88 89 - #define res_smp_cond_load_acquire_timewait(v, c) smp_cond_load_acquire_timewait(v, c, 0, 1) 89 + #define res_smp_cond_load_acquire(v, c) smp_cond_load_acquire_timewait(v, c, 0, 1) 90 90 91 91 #include <asm-generic/rqspinlock.h> 92 92
+12 -23
kernel/bpf/queue_stack_maps.c
··· 9 9 #include <linux/slab.h> 10 10 #include <linux/btf_ids.h> 11 11 #include "percpu_freelist.h" 12 + #include <asm/rqspinlock.h> 12 13 13 14 #define QUEUE_STACK_CREATE_FLAG_MASK \ 14 15 (BPF_F_NUMA_NODE | BPF_F_ACCESS_MASK) 15 16 16 17 struct bpf_queue_stack { 17 18 struct bpf_map map; 18 - raw_spinlock_t lock; 19 + rqspinlock_t lock; 19 20 u32 head, tail; 20 21 u32 size; /* max_entries + 1 */ 21 22 ··· 79 78 80 79 qs->size = size; 81 80 82 - raw_spin_lock_init(&qs->lock); 81 + raw_res_spin_lock_init(&qs->lock); 83 82 84 83 return &qs->map; 85 84 } ··· 99 98 int err = 0; 100 99 void *ptr; 101 100 102 - if (in_nmi()) { 103 - if (!raw_spin_trylock_irqsave(&qs->lock, flags)) 104 - return -EBUSY; 105 - } else { 106 - raw_spin_lock_irqsave(&qs->lock, flags); 107 - } 101 + if (raw_res_spin_lock_irqsave(&qs->lock, flags)) 102 + return -EBUSY; 108 103 109 104 if (queue_stack_map_is_empty(qs)) { 110 105 memset(value, 0, qs->map.value_size); ··· 117 120 } 118 121 119 122 out: 120 - raw_spin_unlock_irqrestore(&qs->lock, flags); 123 + raw_res_spin_unlock_irqrestore(&qs->lock, flags); 121 124 return err; 122 125 } 123 126 ··· 130 133 void *ptr; 131 134 u32 index; 132 135 133 - if (in_nmi()) { 134 - if (!raw_spin_trylock_irqsave(&qs->lock, flags)) 135 - return -EBUSY; 136 - } else { 137 - raw_spin_lock_irqsave(&qs->lock, flags); 138 - } 136 + if (raw_res_spin_lock_irqsave(&qs->lock, flags)) 137 + return -EBUSY; 139 138 140 139 if (queue_stack_map_is_empty(qs)) { 141 140 memset(value, 0, qs->map.value_size); ··· 150 157 qs->head = index; 151 158 152 159 out: 153 - raw_spin_unlock_irqrestore(&qs->lock, flags); 160 + raw_res_spin_unlock_irqrestore(&qs->lock, flags); 154 161 return err; 155 162 } 156 163 ··· 196 203 if (flags & BPF_NOEXIST || flags > BPF_EXIST) 197 204 return -EINVAL; 198 205 199 - if (in_nmi()) { 200 - if (!raw_spin_trylock_irqsave(&qs->lock, irq_flags)) 201 - return -EBUSY; 202 - } else { 203 - raw_spin_lock_irqsave(&qs->lock, irq_flags); 204 - } 206 + if (raw_res_spin_lock_irqsave(&qs->lock, irq_flags)) 207 + return -EBUSY; 205 208 206 209 if (queue_stack_map_is_full(qs)) { 207 210 if (!replace) { ··· 216 227 qs->head = 0; 217 228 218 229 out: 219 - raw_spin_unlock_irqrestore(&qs->lock, irq_flags); 230 + raw_res_spin_unlock_irqrestore(&qs->lock, irq_flags); 220 231 return err; 221 232 } 222 233
+7 -10
kernel/bpf/ringbuf.c
··· 11 11 #include <linux/kmemleak.h> 12 12 #include <uapi/linux/btf.h> 13 13 #include <linux/btf_ids.h> 14 + #include <asm/rqspinlock.h> 14 15 15 16 #define RINGBUF_CREATE_FLAG_MASK (BPF_F_NUMA_NODE) 16 17 ··· 30 29 u64 mask; 31 30 struct page **pages; 32 31 int nr_pages; 33 - raw_spinlock_t spinlock ____cacheline_aligned_in_smp; 32 + rqspinlock_t spinlock ____cacheline_aligned_in_smp; 34 33 /* For user-space producer ring buffers, an atomic_t busy bit is used 35 34 * to synchronize access to the ring buffers in the kernel, rather than 36 35 * the spinlock that is used for kernel-producer ring buffers. This is ··· 174 173 if (!rb) 175 174 return NULL; 176 175 177 - raw_spin_lock_init(&rb->spinlock); 176 + raw_res_spin_lock_init(&rb->spinlock); 178 177 atomic_set(&rb->busy, 0); 179 178 init_waitqueue_head(&rb->waitq); 180 179 init_irq_work(&rb->work, bpf_ringbuf_notify); ··· 417 416 418 417 cons_pos = smp_load_acquire(&rb->consumer_pos); 419 418 420 - if (in_nmi()) { 421 - if (!raw_spin_trylock_irqsave(&rb->spinlock, flags)) 422 - return NULL; 423 - } else { 424 - raw_spin_lock_irqsave(&rb->spinlock, flags); 425 - } 419 + if (raw_res_spin_lock_irqsave(&rb->spinlock, flags)) 420 + return NULL; 426 421 427 422 pend_pos = rb->pending_pos; 428 423 prod_pos = rb->producer_pos; ··· 443 446 */ 444 447 if (new_prod_pos - cons_pos > rb->mask || 445 448 new_prod_pos - pend_pos > rb->mask) { 446 - raw_spin_unlock_irqrestore(&rb->spinlock, flags); 449 + raw_res_spin_unlock_irqrestore(&rb->spinlock, flags); 447 450 return NULL; 448 451 } 449 452 ··· 455 458 /* pairs with consumer's smp_load_acquire() */ 456 459 smp_store_release(&rb->producer_pos, new_prod_pos); 457 460 458 - raw_spin_unlock_irqrestore(&rb->spinlock, flags); 461 + raw_res_spin_unlock_irqrestore(&rb->spinlock, flags); 459 462 460 463 return (void *)hdr + BPF_RINGBUF_HDR_SZ; 461 464 }
+1 -1
kernel/bpf/rqspinlock.c
··· 253 253 }) 254 254 #else 255 255 #define RES_CHECK_TIMEOUT(ts, ret, mask) \ 256 - ({ (ret) = check_timeout(&(ts)); }) 256 + ({ (ret) = check_timeout((lock), (mask), &(ts)); }) 257 257 #endif 258 258 259 259 /*
+44 -36
net/core/filter.c
··· 218 218 return 0; 219 219 } 220 220 221 + static int bpf_skb_load_helper_convert_offset(const struct sk_buff *skb, int offset) 222 + { 223 + if (likely(offset >= 0)) 224 + return offset; 225 + 226 + if (offset >= SKF_NET_OFF) 227 + return offset - SKF_NET_OFF + skb_network_offset(skb); 228 + 229 + if (offset >= SKF_LL_OFF && skb_mac_header_was_set(skb)) 230 + return offset - SKF_LL_OFF + skb_mac_offset(skb); 231 + 232 + return INT_MIN; 233 + } 234 + 221 235 BPF_CALL_4(bpf_skb_load_helper_8, const struct sk_buff *, skb, const void *, 222 236 data, int, headlen, int, offset) 223 237 { 224 - u8 tmp, *ptr; 238 + u8 tmp; 225 239 const int len = sizeof(tmp); 226 240 227 - if (offset >= 0) { 228 - if (headlen - offset >= len) 229 - return *(u8 *)(data + offset); 230 - if (!skb_copy_bits(skb, offset, &tmp, sizeof(tmp))) 231 - return tmp; 232 - } else { 233 - ptr = bpf_internal_load_pointer_neg_helper(skb, offset, len); 234 - if (likely(ptr)) 235 - return *(u8 *)ptr; 236 - } 241 + offset = bpf_skb_load_helper_convert_offset(skb, offset); 242 + if (offset == INT_MIN) 243 + return -EFAULT; 237 244 238 - return -EFAULT; 245 + if (headlen - offset >= len) 246 + return *(u8 *)(data + offset); 247 + if (!skb_copy_bits(skb, offset, &tmp, sizeof(tmp))) 248 + return tmp; 249 + else 250 + return -EFAULT; 239 251 } 240 252 241 253 BPF_CALL_2(bpf_skb_load_helper_8_no_cache, const struct sk_buff *, skb, ··· 260 248 BPF_CALL_4(bpf_skb_load_helper_16, const struct sk_buff *, skb, const void *, 261 249 data, int, headlen, int, offset) 262 250 { 263 - __be16 tmp, *ptr; 251 + __be16 tmp; 264 252 const int len = sizeof(tmp); 265 253 266 - if (offset >= 0) { 267 - if (headlen - offset >= len) 268 - return get_unaligned_be16(data + offset); 269 - if (!skb_copy_bits(skb, offset, &tmp, sizeof(tmp))) 270 - return be16_to_cpu(tmp); 271 - } else { 272 - ptr = bpf_internal_load_pointer_neg_helper(skb, offset, len); 273 - if (likely(ptr)) 274 - return get_unaligned_be16(ptr); 275 - } 254 + offset = bpf_skb_load_helper_convert_offset(skb, offset); 255 + if (offset == INT_MIN) 256 + return -EFAULT; 276 257 277 - return -EFAULT; 258 + if (headlen - offset >= len) 259 + return get_unaligned_be16(data + offset); 260 + if (!skb_copy_bits(skb, offset, &tmp, sizeof(tmp))) 261 + return be16_to_cpu(tmp); 262 + else 263 + return -EFAULT; 278 264 } 279 265 280 266 BPF_CALL_2(bpf_skb_load_helper_16_no_cache, const struct sk_buff *, skb, ··· 285 275 BPF_CALL_4(bpf_skb_load_helper_32, const struct sk_buff *, skb, const void *, 286 276 data, int, headlen, int, offset) 287 277 { 288 - __be32 tmp, *ptr; 278 + __be32 tmp; 289 279 const int len = sizeof(tmp); 290 280 291 - if (likely(offset >= 0)) { 292 - if (headlen - offset >= len) 293 - return get_unaligned_be32(data + offset); 294 - if (!skb_copy_bits(skb, offset, &tmp, sizeof(tmp))) 295 - return be32_to_cpu(tmp); 296 - } else { 297 - ptr = bpf_internal_load_pointer_neg_helper(skb, offset, len); 298 - if (likely(ptr)) 299 - return get_unaligned_be32(ptr); 300 - } 281 + offset = bpf_skb_load_helper_convert_offset(skb, offset); 282 + if (offset == INT_MIN) 283 + return -EFAULT; 301 284 302 - return -EFAULT; 285 + if (headlen - offset >= len) 286 + return get_unaligned_be32(data + offset); 287 + if (!skb_copy_bits(skb, offset, &tmp, sizeof(tmp))) 288 + return be32_to_cpu(tmp); 289 + else 290 + return -EFAULT; 303 291 } 304 292 305 293 BPF_CALL_2(bpf_skb_load_helper_32_no_cache, const struct sk_buff *, skb,
+5 -2
tools/testing/selftests/bpf/prog_tests/res_spin_lock.c
··· 25 25 26 26 while (!READ_ONCE(skip)) { 27 27 err = bpf_prog_test_run_opts(prog_fd, &topts); 28 - ASSERT_OK(err, "test_run"); 29 - ASSERT_OK(topts.retval, "test_run retval"); 28 + if (err || topts.retval) { 29 + ASSERT_OK(err, "test_run"); 30 + ASSERT_OK(topts.retval, "test_run retval"); 31 + break; 32 + } 30 33 } 31 34 pthread_exit(arg); 32 35 }
+7 -3
tools/testing/selftests/bpf/progs/res_spin_lock.c
··· 38 38 r = bpf_res_spin_lock(&elem1->lock); 39 39 if (r) 40 40 return r; 41 - if (!bpf_res_spin_lock(&elem2->lock)) { 41 + r = bpf_res_spin_lock(&elem2->lock); 42 + if (!r) { 42 43 bpf_res_spin_unlock(&elem2->lock); 43 44 bpf_res_spin_unlock(&elem1->lock); 44 45 return -1; 45 46 } 46 47 bpf_res_spin_unlock(&elem1->lock); 47 - return 0; 48 + return r != -EDEADLK; 48 49 } 49 50 50 51 SEC("tc") ··· 125 124 /* Trigger AA, after exhausting entries in the held lock table. This 126 125 * time, only the timeout can save us, as AA detection won't succeed. 127 126 */ 128 - if (!bpf_res_spin_lock(locks[34])) { 127 + ret = bpf_res_spin_lock(locks[34]); 128 + if (!ret) { 129 129 bpf_res_spin_unlock(locks[34]); 130 130 ret = 1; 131 131 goto end; 132 132 } 133 + 134 + ret = ret != -ETIMEDOUT ? 2 : 0; 133 135 134 136 end: 135 137 for (i = i - 1; i >= 0; i--)
+1
tools/testing/selftests/net/.gitignore
··· 39 39 sk_bind_sendto_listen 40 40 sk_connect_zero_addr 41 41 sk_so_peek_off 42 + skf_net_off 42 43 socket 43 44 so_incoming_cpu 44 45 so_netns_cookie
+2
tools/testing/selftests/net/Makefile
··· 106 106 TEST_PROGS += busy_poll_test.sh 107 107 TEST_GEN_PROGS += proc_net_pktgen 108 108 TEST_PROGS += lwt_dst_cache_ref_loop.sh 109 + TEST_PROGS += skf_net_off.sh 110 + TEST_GEN_FILES += skf_net_off 109 111 110 112 # YNL files, must be before "include ..lib.mk" 111 113 YNL_GEN_FILES := busy_poller netlink-dumps
+244
tools/testing/selftests/net/skf_net_off.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + /* Open a tun device. 4 + * 5 + * [modifications: use IFF_NAPI_FRAGS, add sk filter] 6 + * 7 + * Expects the device to have been configured previously, e.g.: 8 + * sudo ip tuntap add name tap1 mode tap 9 + * sudo ip link set tap1 up 10 + * sudo ip link set dev tap1 addr 02:00:00:00:00:01 11 + * sudo ip -6 addr add fdab::1 peer fdab::2 dev tap1 nodad 12 + * 13 + * And to avoid premature pskb_may_pull: 14 + * 15 + * sudo ethtool -K tap1 gro off 16 + * sudo bash -c 'echo 0 > /proc/sys/net/ipv4/ip_early_demux' 17 + */ 18 + 19 + #define _GNU_SOURCE 20 + 21 + #include <arpa/inet.h> 22 + #include <errno.h> 23 + #include <error.h> 24 + #include <fcntl.h> 25 + #include <getopt.h> 26 + #include <linux/filter.h> 27 + #include <linux/if.h> 28 + #include <linux/if_packet.h> 29 + #include <linux/if_tun.h> 30 + #include <linux/ipv6.h> 31 + #include <netinet/if_ether.h> 32 + #include <netinet/in.h> 33 + #include <netinet/ip.h> 34 + #include <netinet/ip6.h> 35 + #include <netinet/udp.h> 36 + #include <poll.h> 37 + #include <signal.h> 38 + #include <stdbool.h> 39 + #include <stddef.h> 40 + #include <stdio.h> 41 + #include <stdlib.h> 42 + #include <string.h> 43 + #include <sys/ioctl.h> 44 + #include <sys/socket.h> 45 + #include <sys/poll.h> 46 + #include <sys/types.h> 47 + #include <sys/uio.h> 48 + #include <unistd.h> 49 + 50 + static bool cfg_do_filter; 51 + static bool cfg_do_frags; 52 + static int cfg_dst_port = 8000; 53 + static char *cfg_ifname; 54 + 55 + static int tun_open(const char *tun_name) 56 + { 57 + struct ifreq ifr = {0}; 58 + int fd, ret; 59 + 60 + fd = open("/dev/net/tun", O_RDWR); 61 + if (fd == -1) 62 + error(1, errno, "open /dev/net/tun"); 63 + 64 + ifr.ifr_flags = IFF_TAP; 65 + if (cfg_do_frags) 66 + ifr.ifr_flags |= IFF_NAPI | IFF_NAPI_FRAGS; 67 + 68 + strncpy(ifr.ifr_name, tun_name, IFNAMSIZ - 1); 69 + 70 + ret = ioctl(fd, TUNSETIFF, &ifr); 71 + if (ret) 72 + error(1, ret, "ioctl TUNSETIFF"); 73 + 74 + return fd; 75 + } 76 + 77 + static void sk_set_filter(int fd) 78 + { 79 + const int offset_proto = offsetof(struct ip6_hdr, ip6_nxt); 80 + const int offset_dport = sizeof(struct ip6_hdr) + offsetof(struct udphdr, dest); 81 + 82 + /* Filter UDP packets with destination port cfg_dst_port */ 83 + struct sock_filter filter_code[] = { 84 + BPF_STMT(BPF_LD + BPF_B + BPF_ABS, SKF_AD_OFF + SKF_AD_PKTTYPE), 85 + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, PACKET_HOST, 0, 4), 86 + BPF_STMT(BPF_LD + BPF_B + BPF_ABS, SKF_NET_OFF + offset_proto), 87 + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 2), 88 + BPF_STMT(BPF_LD + BPF_H + BPF_ABS, SKF_NET_OFF + offset_dport), 89 + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, cfg_dst_port, 1, 0), 90 + BPF_STMT(BPF_RET + BPF_K, 0), 91 + BPF_STMT(BPF_RET + BPF_K, 0xFFFF), 92 + }; 93 + 94 + struct sock_fprog filter = { 95 + sizeof(filter_code) / sizeof(filter_code[0]), 96 + filter_code, 97 + }; 98 + 99 + if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter))) 100 + error(1, errno, "setsockopt attach filter"); 101 + } 102 + 103 + static int raw_open(void) 104 + { 105 + int fd; 106 + 107 + fd = socket(PF_INET6, SOCK_RAW, IPPROTO_UDP); 108 + if (fd == -1) 109 + error(1, errno, "socket raw (udp)"); 110 + 111 + if (cfg_do_filter) 112 + sk_set_filter(fd); 113 + 114 + return fd; 115 + } 116 + 117 + static void tun_write(int fd) 118 + { 119 + const char eth_src[] = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x02 }; 120 + const char eth_dst[] = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x01 }; 121 + struct tun_pi pi = {0}; 122 + struct ipv6hdr ip6h = {0}; 123 + struct udphdr uh = {0}; 124 + struct ethhdr eth = {0}; 125 + uint32_t payload; 126 + struct iovec iov[5]; 127 + int ret; 128 + 129 + pi.proto = htons(ETH_P_IPV6); 130 + 131 + memcpy(eth.h_source, eth_src, sizeof(eth_src)); 132 + memcpy(eth.h_dest, eth_dst, sizeof(eth_dst)); 133 + eth.h_proto = htons(ETH_P_IPV6); 134 + 135 + ip6h.version = 6; 136 + ip6h.payload_len = htons(sizeof(uh) + sizeof(uint32_t)); 137 + ip6h.nexthdr = IPPROTO_UDP; 138 + ip6h.hop_limit = 8; 139 + if (inet_pton(AF_INET6, "fdab::2", &ip6h.saddr) != 1) 140 + error(1, errno, "inet_pton src"); 141 + if (inet_pton(AF_INET6, "fdab::1", &ip6h.daddr) != 1) 142 + error(1, errno, "inet_pton src"); 143 + 144 + uh.source = htons(8000); 145 + uh.dest = htons(cfg_dst_port); 146 + uh.len = ip6h.payload_len; 147 + uh.check = 0; 148 + 149 + payload = htonl(0xABABABAB); /* Covered in IPv6 length */ 150 + 151 + iov[0].iov_base = &pi; 152 + iov[0].iov_len = sizeof(pi); 153 + iov[1].iov_base = &eth; 154 + iov[1].iov_len = sizeof(eth); 155 + iov[2].iov_base = &ip6h; 156 + iov[2].iov_len = sizeof(ip6h); 157 + iov[3].iov_base = &uh; 158 + iov[3].iov_len = sizeof(uh); 159 + iov[4].iov_base = &payload; 160 + iov[4].iov_len = sizeof(payload); 161 + 162 + ret = writev(fd, iov, sizeof(iov) / sizeof(iov[0])); 163 + if (ret <= 0) 164 + error(1, errno, "writev"); 165 + } 166 + 167 + static void raw_read(int fd) 168 + { 169 + struct timeval tv = { .tv_usec = 100 * 1000 }; 170 + struct msghdr msg = {0}; 171 + struct iovec iov[2]; 172 + struct udphdr uh; 173 + uint32_t payload[2]; 174 + int ret; 175 + 176 + if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))) 177 + error(1, errno, "setsockopt rcvtimeo udp"); 178 + 179 + iov[0].iov_base = &uh; 180 + iov[0].iov_len = sizeof(uh); 181 + 182 + iov[1].iov_base = payload; 183 + iov[1].iov_len = sizeof(payload); 184 + 185 + msg.msg_iov = iov; 186 + msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]); 187 + 188 + ret = recvmsg(fd, &msg, 0); 189 + if (ret <= 0) 190 + error(1, errno, "read raw"); 191 + if (ret != sizeof(uh) + sizeof(payload[0])) 192 + error(1, errno, "read raw: len=%d\n", ret); 193 + 194 + fprintf(stderr, "raw recv: 0x%x\n", payload[0]); 195 + } 196 + 197 + static void parse_opts(int argc, char **argv) 198 + { 199 + int c; 200 + 201 + while ((c = getopt(argc, argv, "fFi:")) != -1) { 202 + switch (c) { 203 + case 'f': 204 + cfg_do_filter = true; 205 + printf("bpf filter enabled\n"); 206 + break; 207 + case 'F': 208 + cfg_do_frags = true; 209 + printf("napi frags mode enabled\n"); 210 + break; 211 + case 'i': 212 + cfg_ifname = optarg; 213 + break; 214 + default: 215 + error(1, 0, "unknown option %c", optopt); 216 + break; 217 + } 218 + } 219 + 220 + if (!cfg_ifname) 221 + error(1, 0, "must specify tap interface name (-i)"); 222 + } 223 + 224 + int main(int argc, char **argv) 225 + { 226 + int fdt, fdr; 227 + 228 + parse_opts(argc, argv); 229 + 230 + fdr = raw_open(); 231 + fdt = tun_open(cfg_ifname); 232 + 233 + tun_write(fdt); 234 + raw_read(fdr); 235 + 236 + if (close(fdt)) 237 + error(1, errno, "close tun"); 238 + if (close(fdr)) 239 + error(1, errno, "close udp"); 240 + 241 + fprintf(stderr, "OK\n"); 242 + return 0; 243 + } 244 +
+30
tools/testing/selftests/net/skf_net_off.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + 4 + readonly NS="ns-$(mktemp -u XXXXXX)" 5 + 6 + cleanup() { 7 + ip netns del $NS 8 + } 9 + 10 + ip netns add $NS 11 + trap cleanup EXIT 12 + 13 + ip -netns $NS link set lo up 14 + ip -netns $NS tuntap add name tap1 mode tap 15 + ip -netns $NS link set tap1 up 16 + ip -netns $NS link set dev tap1 addr 02:00:00:00:00:01 17 + ip -netns $NS -6 addr add fdab::1 peer fdab::2 dev tap1 nodad 18 + ip netns exec $NS ethtool -K tap1 gro off 19 + 20 + # disable early demux, else udp_v6_early_demux pulls udp header into linear 21 + ip netns exec $NS sysctl -w net.ipv4.ip_early_demux=0 22 + 23 + echo "no filter" 24 + ip netns exec $NS ./skf_net_off -i tap1 25 + 26 + echo "filter, linear skb (-f)" 27 + ip netns exec $NS ./skf_net_off -i tap1 -f 28 + 29 + echo "filter, fragmented skb (-f) (-F)" 30 + ip netns exec $NS ./skf_net_off -i tap1 -f -F