aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Borkmann <daniel@iogearbox.net>2015-09-29 19:41:51 -0400
committerDavid S. Miller <davem@davemloft.net>2015-10-03 08:02:41 -0400
commitc46646d0484f5d08e2bede9b45034ba5b8b489cc (patch)
treeb15b5132baba1198decf5966819dea7cdb7d2cfc
parenta91263d520246b63c63e75ddfb072ee6a853fe15 (diff)
sched, bpf: add helper for retrieving routing realms
Using routing realms as part of the classifier is quite useful, it can be viewed as a tag for one or multiple routing entries (think of an analogy to net_cls cgroup for processes), set by user space routing daemons or via iproute2 as an indicator for traffic classifiers and later on processed in the eBPF program. Unlike actions, the classifier can inspect device flags and enable netif_keep_dst() if necessary. tc actions don't have that possibility, but in case people know what they are doing, it can be used from there as well (e.g. via devs that must keep dsts by design anyway). If a realm is set, the handler returns the non-zero realm. User space can set the full 32bit realm for the dst. Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Alexei Starovoitov <ast@plumgrid.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/filter.h3
-rw-r--r--include/uapi/linux/bpf.h7
-rw-r--r--kernel/bpf/syscall.c2
-rw-r--r--net/core/filter.c22
-rw-r--r--net/sched/cls_bpf.c8
5 files changed, 39 insertions, 3 deletions
diff --git a/include/linux/filter.h b/include/linux/filter.h
index bad618f316d7..3d5fd24b321b 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -328,7 +328,8 @@ struct bpf_prog {
328 u16 pages; /* Number of allocated pages */ 328 u16 pages; /* Number of allocated pages */
329 kmemcheck_bitfield_begin(meta); 329 kmemcheck_bitfield_begin(meta);
330 u16 jited:1, /* Is our filter JIT'ed? */ 330 u16 jited:1, /* Is our filter JIT'ed? */
331 gpl_compatible:1; /* Is filter GPL compatible? */ 331 gpl_compatible:1, /* Is filter GPL compatible? */
332 dst_needed:1; /* Do we need dst entry? */
332 kmemcheck_bitfield_end(meta); 333 kmemcheck_bitfield_end(meta);
333 u32 len; /* Number of filter blocks */ 334 u32 len; /* Number of filter blocks */
334 enum bpf_prog_type type; /* Type of BPF program */ 335 enum bpf_prog_type type; /* Type of BPF program */
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 4ec0b5488294..564f1f091991 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -280,6 +280,13 @@ enum bpf_func_id {
280 * Return: TC_ACT_REDIRECT 280 * Return: TC_ACT_REDIRECT
281 */ 281 */
282 BPF_FUNC_redirect, 282 BPF_FUNC_redirect,
283
284 /**
285 * bpf_get_route_realm(skb) - retrieve a dst's tclassid
286 * @skb: pointer to skb
287 * Return: realm if != 0
288 */
289 BPF_FUNC_get_route_realm,
283 __BPF_FUNC_MAX_ID, 290 __BPF_FUNC_MAX_ID,
284}; 291};
285 292
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 2190ab14b763..5f35f420c12f 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -402,6 +402,8 @@ static void fixup_bpf_calls(struct bpf_prog *prog)
402 */ 402 */
403 BUG_ON(!prog->aux->ops->get_func_proto); 403 BUG_ON(!prog->aux->ops->get_func_proto);
404 404
405 if (insn->imm == BPF_FUNC_get_route_realm)
406 prog->dst_needed = 1;
405 if (insn->imm == BPF_FUNC_tail_call) { 407 if (insn->imm == BPF_FUNC_tail_call) {
406 /* mark bpf_tail_call as different opcode 408 /* mark bpf_tail_call as different opcode
407 * to avoid conditional branch in 409 * to avoid conditional branch in
diff --git a/net/core/filter.c b/net/core/filter.c
index 04664acb86ce..45c69ce4c847 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -49,6 +49,7 @@
49#include <net/sch_generic.h> 49#include <net/sch_generic.h>
50#include <net/cls_cgroup.h> 50#include <net/cls_cgroup.h>
51#include <net/dst_metadata.h> 51#include <net/dst_metadata.h>
52#include <net/dst.h>
52 53
53/** 54/**
54 * sk_filter - run a packet through a socket filter 55 * sk_filter - run a packet through a socket filter
@@ -1478,6 +1479,25 @@ static const struct bpf_func_proto bpf_get_cgroup_classid_proto = {
1478 .arg1_type = ARG_PTR_TO_CTX, 1479 .arg1_type = ARG_PTR_TO_CTX,
1479}; 1480};
1480 1481
1482static u64 bpf_get_route_realm(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5)
1483{
1484#ifdef CONFIG_IP_ROUTE_CLASSID
1485 const struct dst_entry *dst;
1486
1487 dst = skb_dst((struct sk_buff *) (unsigned long) r1);
1488 if (dst)
1489 return dst->tclassid;
1490#endif
1491 return 0;
1492}
1493
1494static const struct bpf_func_proto bpf_get_route_realm_proto = {
1495 .func = bpf_get_route_realm,
1496 .gpl_only = false,
1497 .ret_type = RET_INTEGER,
1498 .arg1_type = ARG_PTR_TO_CTX,
1499};
1500
1481static u64 bpf_skb_vlan_push(u64 r1, u64 r2, u64 vlan_tci, u64 r4, u64 r5) 1501static u64 bpf_skb_vlan_push(u64 r1, u64 r2, u64 vlan_tci, u64 r4, u64 r5)
1482{ 1502{
1483 struct sk_buff *skb = (struct sk_buff *) (long) r1; 1503 struct sk_buff *skb = (struct sk_buff *) (long) r1;
@@ -1648,6 +1668,8 @@ tc_cls_act_func_proto(enum bpf_func_id func_id)
1648 return bpf_get_skb_set_tunnel_key_proto(); 1668 return bpf_get_skb_set_tunnel_key_proto();
1649 case BPF_FUNC_redirect: 1669 case BPF_FUNC_redirect:
1650 return &bpf_redirect_proto; 1670 return &bpf_redirect_proto;
1671 case BPF_FUNC_get_route_realm:
1672 return &bpf_get_route_realm_proto;
1651 default: 1673 default:
1652 return sk_filter_func_proto(func_id); 1674 return sk_filter_func_proto(func_id);
1653 } 1675 }
diff --git a/net/sched/cls_bpf.c b/net/sched/cls_bpf.c
index 7eeffaf69c75..5faaa5425f7b 100644
--- a/net/sched/cls_bpf.c
+++ b/net/sched/cls_bpf.c
@@ -262,7 +262,8 @@ static int cls_bpf_prog_from_ops(struct nlattr **tb, struct cls_bpf_prog *prog)
262 return 0; 262 return 0;
263} 263}
264 264
265static int cls_bpf_prog_from_efd(struct nlattr **tb, struct cls_bpf_prog *prog) 265static int cls_bpf_prog_from_efd(struct nlattr **tb, struct cls_bpf_prog *prog,
266 const struct tcf_proto *tp)
266{ 267{
267 struct bpf_prog *fp; 268 struct bpf_prog *fp;
268 char *name = NULL; 269 char *name = NULL;
@@ -294,6 +295,9 @@ static int cls_bpf_prog_from_efd(struct nlattr **tb, struct cls_bpf_prog *prog)
294 prog->bpf_name = name; 295 prog->bpf_name = name;
295 prog->filter = fp; 296 prog->filter = fp;
296 297
298 if (fp->dst_needed)
299 netif_keep_dst(qdisc_dev(tp->q));
300
297 return 0; 301 return 0;
298} 302}
299 303
@@ -330,7 +334,7 @@ static int cls_bpf_modify_existing(struct net *net, struct tcf_proto *tp,
330 prog->exts_integrated = have_exts; 334 prog->exts_integrated = have_exts;
331 335
332 ret = is_bpf ? cls_bpf_prog_from_ops(tb, prog) : 336 ret = is_bpf ? cls_bpf_prog_from_ops(tb, prog) :
333 cls_bpf_prog_from_efd(tb, prog); 337 cls_bpf_prog_from_efd(tb, prog, tp);
334 if (ret < 0) { 338 if (ret < 0) {
335 tcf_exts_destroy(&exts); 339 tcf_exts_destroy(&exts);
336 return ret; 340 return ret;