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

bpf: Update BPF_CGROUP_RUN_PROG_INET_EGRESS calls

Update BPF_CGROUP_RUN_PROG_INET_EGRESS() callers to support returning
congestion notifications from the BPF programs.

Signed-off-by: Lawrence Brakmo <brakmo@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

brakmo and committed by
Alexei Starovoitov
956fe219 e7a3160d

+40 -20
+23 -11
net/ipv4/ip_output.c
··· 287 287 return ret; 288 288 } 289 289 290 - static int ip_finish_output(struct net *net, struct sock *sk, struct sk_buff *skb) 290 + static int __ip_finish_output(struct net *net, struct sock *sk, struct sk_buff *skb) 291 291 { 292 292 unsigned int mtu; 293 - int ret; 294 - 295 - ret = BPF_CGROUP_RUN_PROG_INET_EGRESS(sk, skb); 296 - if (ret) { 297 - kfree_skb(skb); 298 - return ret; 299 - } 300 293 301 294 #if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM) 302 295 /* Policy lookup after SNAT yielded a new policy */ ··· 308 315 return ip_finish_output2(net, sk, skb); 309 316 } 310 317 318 + static int ip_finish_output(struct net *net, struct sock *sk, struct sk_buff *skb) 319 + { 320 + int ret; 321 + 322 + ret = BPF_CGROUP_RUN_PROG_INET_EGRESS(sk, skb); 323 + switch (ret) { 324 + case NET_XMIT_SUCCESS: 325 + return __ip_finish_output(net, sk, skb); 326 + case NET_XMIT_CN: 327 + return __ip_finish_output(net, sk, skb) ? : ret; 328 + default: 329 + kfree_skb(skb); 330 + return ret; 331 + } 332 + } 333 + 311 334 static int ip_mc_finish_output(struct net *net, struct sock *sk, 312 335 struct sk_buff *skb) 313 336 { 314 337 int ret; 315 338 316 339 ret = BPF_CGROUP_RUN_PROG_INET_EGRESS(sk, skb); 317 - if (ret) { 340 + switch (ret) { 341 + case NET_XMIT_SUCCESS: 342 + return dev_loopback_xmit(net, sk, skb); 343 + case NET_XMIT_CN: 344 + return dev_loopback_xmit(net, sk, skb) ? : ret; 345 + default: 318 346 kfree_skb(skb); 319 347 return ret; 320 348 } 321 - 322 - return dev_loopback_xmit(net, sk, skb); 323 349 } 324 350 325 351 int ip_mc_output(struct net *net, struct sock *sk, struct sk_buff *skb)
+17 -9
net/ipv6/ip6_output.c
··· 128 128 return -EINVAL; 129 129 } 130 130 131 - static int ip6_finish_output(struct net *net, struct sock *sk, struct sk_buff *skb) 131 + static int __ip6_finish_output(struct net *net, struct sock *sk, struct sk_buff *skb) 132 132 { 133 - int ret; 134 - 135 - ret = BPF_CGROUP_RUN_PROG_INET_EGRESS(sk, skb); 136 - if (ret) { 137 - kfree_skb(skb); 138 - return ret; 139 - } 140 - 141 133 #if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM) 142 134 /* Policy lookup after SNAT yielded a new policy */ 143 135 if (skb_dst(skb)->xfrm) { ··· 144 152 return ip6_fragment(net, sk, skb, ip6_finish_output2); 145 153 else 146 154 return ip6_finish_output2(net, sk, skb); 155 + } 156 + 157 + static int ip6_finish_output(struct net *net, struct sock *sk, struct sk_buff *skb) 158 + { 159 + int ret; 160 + 161 + ret = BPF_CGROUP_RUN_PROG_INET_EGRESS(sk, skb); 162 + switch (ret) { 163 + case NET_XMIT_SUCCESS: 164 + return __ip6_finish_output(net, sk, skb); 165 + case NET_XMIT_CN: 166 + return __ip6_finish_output(net, sk, skb) ? : ret; 167 + default: 168 + kfree_skb(skb); 169 + return ret; 170 + } 147 171 } 148 172 149 173 int ip6_output(struct net *net, struct sock *sk, struct sk_buff *skb)