aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/ip_output.c
diff options
context:
space:
mode:
authorDaniel Mack <daniel@zonque.org>2016-11-23 10:52:29 -0500
committerDavid S. Miller <davem@davemloft.net>2016-11-25 16:26:04 -0500
commit33b486793cb31311f3a91ae4fe4be5926e7677b0 (patch)
tree2985be4f76a478cab89536ffd1efaaa0fddbb36f /net/ipv4/ip_output.c
parentc11cd3a6ec3a817c6b71b00c559e25d855f7e5b4 (diff)
net: ipv4, ipv6: run cgroup eBPF egress programs
If the cgroup associated with the receiving socket has an eBPF programs installed, run them from ip_output(), ip6_output() and ip_mc_output(). From mentioned functions we have two socket contexts as per 7026b1ddb6b8 ("netfilter: Pass socket pointer down through okfn()."). We explicitly need to use sk instead of skb->sk here, since otherwise the same program would run multiple times on egress when encap devices are involved, which is not desired in our case. eBPF programs used in this context are expected to either return 1 to let the packet pass, or != 1 to drop them. The programs have access to the skb through bpf_skb_load_bytes(), and the payload starts at the network headers (L3). Note that cgroup_bpf_run_filter() is stubbed out as static inline nop for !CONFIG_CGROUP_BPF, and is otherwise guarded by a static key if the feature is unused. Signed-off-by: Daniel Mack <daniel@zonque.org> Acked-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/ip_output.c')
-rw-r--r--net/ipv4/ip_output.c26
1 files changed, 24 insertions, 2 deletions
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 358f2c82b030..9af2b7853be4 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -74,6 +74,7 @@
74#include <net/checksum.h> 74#include <net/checksum.h>
75#include <net/inetpeer.h> 75#include <net/inetpeer.h>
76#include <net/lwtunnel.h> 76#include <net/lwtunnel.h>
77#include <linux/bpf-cgroup.h>
77#include <linux/igmp.h> 78#include <linux/igmp.h>
78#include <linux/netfilter_ipv4.h> 79#include <linux/netfilter_ipv4.h>
79#include <linux/netfilter_bridge.h> 80#include <linux/netfilter_bridge.h>
@@ -285,6 +286,13 @@ static int ip_finish_output_gso(struct net *net, struct sock *sk,
285static int ip_finish_output(struct net *net, struct sock *sk, struct sk_buff *skb) 286static int ip_finish_output(struct net *net, struct sock *sk, struct sk_buff *skb)
286{ 287{
287 unsigned int mtu; 288 unsigned int mtu;
289 int ret;
290
291 ret = BPF_CGROUP_RUN_PROG_INET_EGRESS(sk, skb);
292 if (ret) {
293 kfree_skb(skb);
294 return ret;
295 }
288 296
289#if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM) 297#if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM)
290 /* Policy lookup after SNAT yielded a new policy */ 298 /* Policy lookup after SNAT yielded a new policy */
@@ -303,6 +311,20 @@ static int ip_finish_output(struct net *net, struct sock *sk, struct sk_buff *sk
303 return ip_finish_output2(net, sk, skb); 311 return ip_finish_output2(net, sk, skb);
304} 312}
305 313
314static int ip_mc_finish_output(struct net *net, struct sock *sk,
315 struct sk_buff *skb)
316{
317 int ret;
318
319 ret = BPF_CGROUP_RUN_PROG_INET_EGRESS(sk, skb);
320 if (ret) {
321 kfree_skb(skb);
322 return ret;
323 }
324
325 return dev_loopback_xmit(net, sk, skb);
326}
327
306int ip_mc_output(struct net *net, struct sock *sk, struct sk_buff *skb) 328int ip_mc_output(struct net *net, struct sock *sk, struct sk_buff *skb)
307{ 329{
308 struct rtable *rt = skb_rtable(skb); 330 struct rtable *rt = skb_rtable(skb);
@@ -340,7 +362,7 @@ int ip_mc_output(struct net *net, struct sock *sk, struct sk_buff *skb)
340 if (newskb) 362 if (newskb)
341 NF_HOOK(NFPROTO_IPV4, NF_INET_POST_ROUTING, 363 NF_HOOK(NFPROTO_IPV4, NF_INET_POST_ROUTING,
342 net, sk, newskb, NULL, newskb->dev, 364 net, sk, newskb, NULL, newskb->dev,
343 dev_loopback_xmit); 365 ip_mc_finish_output);
344 } 366 }
345 367
346 /* Multicasts with ttl 0 must not go beyond the host */ 368 /* Multicasts with ttl 0 must not go beyond the host */
@@ -356,7 +378,7 @@ int ip_mc_output(struct net *net, struct sock *sk, struct sk_buff *skb)
356 if (newskb) 378 if (newskb)
357 NF_HOOK(NFPROTO_IPV4, NF_INET_POST_ROUTING, 379 NF_HOOK(NFPROTO_IPV4, NF_INET_POST_ROUTING,
358 net, sk, newskb, NULL, newskb->dev, 380 net, sk, newskb, NULL, newskb->dev,
359 dev_loopback_xmit); 381 ip_mc_finish_output);
360 } 382 }
361 383
362 return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, 384 return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING,