1 // SPDX-License-Identifier: GPL-2.0 2 #include <test_progs.h> 3 #include <network_helpers.h> 4 #include <net/if.h> 5 #include "empty_skb.skel.h" 6 7 void test_empty_skb(void) 8 { 9 LIBBPF_OPTS(bpf_test_run_opts, tattr); 10 struct empty_skb *bpf_obj = NULL; 11 struct nstoken *tok = NULL; 12 struct bpf_program *prog; 13 struct ethhdr eth_hlen; 14 char eth_hlen_pp[15]; 15 int veth_ifindex; 16 int ipip_ifindex; 17 int err; 18 int i; 19 20 struct { 21 const char *msg; 22 const void *data_in; 23 __u32 data_size_in; 24 int *ifindex; 25 int err; 26 int ret; 27 int lwt_egress_ret; /* expected retval at lwt/egress */ 28 __be16 h_proto; 29 bool success_on_tc; 30 bool adjust_room; 31 } tests[] = { 32 /* Empty packets are always rejected. */ 33 34 { 35 /* BPF_PROG_RUN ETH_HLEN size check */ 36 .msg = "veth empty ingress packet", 37 .data_in = NULL, 38 .data_size_in = 0, 39 .ifindex = &veth_ifindex, 40 .err = -EINVAL, 41 }, 42 { 43 /* BPF_PROG_RUN ETH_HLEN size check */ 44 .msg = "ipip empty ingress packet", 45 .data_in = NULL, 46 .data_size_in = 0, 47 .ifindex = &ipip_ifindex, 48 .err = -EINVAL, 49 }, 50 51 /* ETH_HLEN-sized packets with IPv4/IPv6 EtherType but 52 * no L3 header are rejected. 53 */ 54 { 55 .msg = "veth short IPv4 ingress packet", 56 .data_in = ð_hlen, 57 .data_size_in = sizeof(eth_hlen), 58 .ifindex = &veth_ifindex, 59 .err = -EINVAL, 60 .h_proto = htons(ETH_P_IP), 61 .adjust_room = true, 62 }, 63 { 64 .msg = "veth short IPv6 ingress packet", 65 .data_in = ð_hlen, 66 .data_size_in = sizeof(eth_hlen), 67 .ifindex = &veth_ifindex, 68 .err = -EINVAL, 69 .h_proto = htons(ETH_P_IPV6), 70 .adjust_room = true, 71 }, 72 73 /* ETH_HLEN-sized packets: 74 * - can not be redirected at LWT_XMIT 75 * - can be redirected at TC to non-tunneling dest 76 */ 77 78 { 79 /* __bpf_redirect_common */ 80 .msg = "veth ETH_HLEN packet ingress", 81 .data_in = ð_hlen, 82 .data_size_in = sizeof(eth_hlen), 83 .ifindex = &veth_ifindex, 84 .ret = -ERANGE, 85 .lwt_egress_ret = -ERANGE, 86 .success_on_tc = true, 87 }, 88 { 89 /* __bpf_redirect_no_mac 90 * 91 * lwt: skb->len=0 <= skb_network_offset=0 92 * tc: skb->len=14 <= skb_network_offset=14 93 */ 94 .msg = "ipip ETH_HLEN packet ingress", 95 .data_in = ð_hlen, 96 .data_size_in = sizeof(eth_hlen), 97 .ifindex = &ipip_ifindex, 98 .ret = -ERANGE, 99 .lwt_egress_ret = -ERANGE, 100 }, 101 102 /* ETH_HLEN+1-sized packet should be redirected. */ 103 104 { 105 .msg = "veth ETH_HLEN+1 packet ingress", 106 .data_in = eth_hlen_pp, 107 .data_size_in = sizeof(eth_hlen_pp), 108 .ifindex = &veth_ifindex, 109 .lwt_egress_ret = 1, /* veth_xmit NET_XMIT_DROP */ 110 }, 111 { 112 .msg = "ipip ETH_HLEN+1 packet ingress", 113 .data_in = eth_hlen_pp, 114 .data_size_in = sizeof(eth_hlen_pp), 115 .ifindex = &ipip_ifindex, 116 }, 117 }; 118 119 SYS(out, "ip netns add empty_skb"); 120 tok = open_netns("empty_skb"); 121 if (!ASSERT_OK_PTR(tok, "setns")) 122 goto out; 123 SYS(out, "ip link add veth0 type veth peer veth1"); 124 SYS(out, "ip link set dev veth0 up"); 125 SYS(out, "ip link set dev veth1 up"); 126 SYS(out, "ip addr add 10.0.0.1/8 dev veth0"); 127 SYS(out, "ip addr add 10.0.0.2/8 dev veth1"); 128 veth_ifindex = if_nametoindex("veth0"); 129 130 SYS(out, "ip link add ipip0 type ipip local 10.0.0.1 remote 10.0.0.2"); 131 SYS(out, "ip link set ipip0 up"); 132 SYS(out, "ip addr add 192.168.1.1/16 dev ipip0"); 133 ipip_ifindex = if_nametoindex("ipip0"); 134 135 memset(eth_hlen_pp, 0, sizeof(eth_hlen_pp)); 136 memset(ð_hlen, 0, sizeof(eth_hlen)); 137 138 bpf_obj = empty_skb__open_and_load(); 139 if (!ASSERT_OK_PTR(bpf_obj, "open skeleton")) 140 goto out; 141 142 for (i = 0; i < ARRAY_SIZE(tests); i++) { 143 if (tests[i].data_in == ð_hlen) 144 eth_hlen.h_proto = tests[i].h_proto; 145 146 bpf_object__for_each_program(prog, bpf_obj->obj) { 147 bool at_egress = strstr(bpf_program__name(prog), "egress") != NULL; 148 bool at_tc = !strncmp(bpf_program__section_name(prog), "tc", 2); 149 bool is_adjust_room = !strcmp(bpf_program__name(prog), "tc_adjust_room"); 150 int expected_ret; 151 char buf[128]; 152 153 if (tests[i].adjust_room != is_adjust_room) 154 continue; 155 156 expected_ret = at_egress && !at_tc ? tests[i].lwt_egress_ret : tests[i].ret; 157 158 tattr.data_in = tests[i].data_in; 159 tattr.data_size_in = tests[i].data_size_in; 160 161 tattr.data_size_out = 0; 162 bpf_obj->bss->ifindex = *tests[i].ifindex; 163 bpf_obj->bss->ret = 0; 164 err = bpf_prog_test_run_opts(bpf_program__fd(prog), &tattr); 165 sprintf(buf, "err: %s [%s]", tests[i].msg, bpf_program__name(prog)); 166 167 if (at_tc && tests[i].success_on_tc) 168 ASSERT_GE(err, 0, buf); 169 else 170 ASSERT_EQ(err, tests[i].err, buf); 171 sprintf(buf, "ret: %s [%s]", tests[i].msg, bpf_program__name(prog)); 172 if (at_tc && tests[i].success_on_tc) 173 ASSERT_GE(bpf_obj->bss->ret, 0, buf); 174 else 175 ASSERT_EQ(bpf_obj->bss->ret, expected_ret, buf); 176 } 177 } 178 179 out: 180 if (bpf_obj) 181 empty_skb__destroy(bpf_obj); 182 if (tok) 183 close_netns(tok); 184 SYS_NOFAIL("ip netns del empty_skb"); 185 } 186