History

cls_bpf: introduce integrated actions

Often cls_bpf classifier is used with single action drop attached. Optimize this use case and let cls_bpf return both classid and action. For backwards compatibility reasons enable this feature under TCA_BPF_FLAG_ACT_DIRECT flag. Then more interesting programs like the following are easier to write: int cls_bpf_prog(struct __sk_buff *skb) { /* classify arp, ip, ipv6 into different traffic classes * and drop all other packets */ switch (skb->protocol) { case htons(ETH_P_ARP): skb->tc_classid = 1; break; case htons(ETH_P_IP): skb->tc_classid = 2; break; case htons(ETH_P_IPV6): skb->tc_classid = 3; break; default: return TC_ACT_SHOT; } return TC_ACT_OK; } Joint work with Daniel Borkmann.

Daniel Borkmann committed 11 years ago

Commit 045efa81 parent f6c53335 files · +68 −12Browse files

Unified · Split

5 files
  1. include/net/sch_generic.h +1 −1
  2. include/uapi/linux/bpf.h +1 −0
  3. include/uapi/linux/pkt_cls.h +3 −0
  4. net/core/filter.c +14 −0
  5. net/sched/cls_bpf.c +49 −11
include/net/sch_generic.h+1−1
@@ -251,7 +251,7 @@ struct tcf_proto { · 250 unmodified lines
251struct qdisc_skb_cb {251struct qdisc_skb_cb {
252 unsigned int pkt_len;252 unsigned int pkt_len;
253 u16 slave_dev_queue_mapping;253 u16 slave_dev_queue_mapping;
254 u16 _pad;254 u16 tc_classid;
255#define QDISC_CB_PRIV_LEN 20255#define QDISC_CB_PRIV_LEN 20
256 unsigned char data[QDISC_CB_PRIV_LEN];256 unsigned char data[QDISC_CB_PRIV_LEN];
257};257};
include/uapi/linux/bpf.h+1−0
@@ -293,6 +293,7 @@ struct __sk_buff { · 292 unmodified lines
293 __u32 tc_index;293 __u32 tc_index;
294 __u32 cb[5];294 __u32 cb[5];
295 __u32 hash;295 __u32 hash;
296 __u32 tc_classid;
296};297};
297 298
298struct bpf_tunnel_key {299struct bpf_tunnel_key {
include/uapi/linux/pkt_cls.h+3−0
@@ -373,6 +373,8 @@ enum { · 372 unmodified lines
373 373
374/* BPF classifier */374/* BPF classifier */
375 375
376#define TCA_BPF_FLAG_ACT_DIRECT (1 << 0)
377
376enum {378enum {
377 TCA_BPF_UNSPEC,379 TCA_BPF_UNSPEC,
378 TCA_BPF_ACT,380 TCA_BPF_ACT,
@@ -382,6 +384,7 @@ enum { · 3 unmodified lines
382 TCA_BPF_OPS,384 TCA_BPF_OPS,
383 TCA_BPF_FD,385 TCA_BPF_FD,
384 TCA_BPF_NAME,386 TCA_BPF_NAME,
387 TCA_BPF_FLAGS,
385 __TCA_BPF_MAX,388 __TCA_BPF_MAX,
386};389};
387 390
net/core/filter.c+14−0
@@ -1632,6 +1632,9 @@ static bool __is_valid_access(int off, int size, enum bpf_access_type type) · 1631 unmodified lines
1632static bool sk_filter_is_valid_access(int off, int size,1632static bool sk_filter_is_valid_access(int off, int size,
1633 enum bpf_access_type type)1633 enum bpf_access_type type)
1634{1634{
1635 if (off == offsetof(struct __sk_buff, tc_classid))
1636 return false;
1637
1635 if (type == BPF_WRITE) {1638 if (type == BPF_WRITE) {
1636 switch (off) {1639 switch (off) {
1637 case offsetof(struct __sk_buff, cb[0]) ...1640 case offsetof(struct __sk_buff, cb[0]) ...
@@ -1648,6 +1651,9 @@ static bool sk_filter_is_valid_access(int off, int size, · 10 unmodified lines
1648static bool tc_cls_act_is_valid_access(int off, int size,1651static bool tc_cls_act_is_valid_access(int off, int size,
1649 enum bpf_access_type type)1652 enum bpf_access_type type)
1650{1653{
1654 if (off == offsetof(struct __sk_buff, tc_classid))
1655 return type == BPF_WRITE ? true : false;
1656
1651 if (type == BPF_WRITE) {1657 if (type == BPF_WRITE) {
1652 switch (off) {1658 switch (off) {
1653 case offsetof(struct __sk_buff, mark):1659 case offsetof(struct __sk_buff, mark):
@@ -1760,6 +1766,14 @@ static u32 bpf_net_convert_ctx_access(enum bpf_access_type type, int dst_reg, · 106 unmodified lines
1760 *insn++ = BPF_LDX_MEM(BPF_W, dst_reg, src_reg, ctx_off);1766 *insn++ = BPF_LDX_MEM(BPF_W, dst_reg, src_reg, ctx_off);
1761 break;1767 break;
1762 1768
1769 case offsetof(struct __sk_buff, tc_classid):
1770 ctx_off -= offsetof(struct __sk_buff, tc_classid);
1771 ctx_off += offsetof(struct sk_buff, cb);
1772 ctx_off += offsetof(struct qdisc_skb_cb, tc_classid);
1773 WARN_ON(type != BPF_WRITE);
1774 *insn++ = BPF_STX_MEM(BPF_H, dst_reg, src_reg, ctx_off);
1775 break;
1776
1763 case offsetof(struct __sk_buff, tc_index):1777 case offsetof(struct __sk_buff, tc_index):
1764#ifdef CONFIG_NET_SCHED1778#ifdef CONFIG_NET_SCHED
1765 BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, tc_index) != 2);1779 BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, tc_index) != 2);
net/sched/cls_bpf.c+49−11
@@ -38,6 +38,7 @@ struct cls_bpf_prog { · 37 unmodified lines
38 struct bpf_prog *filter;38 struct bpf_prog *filter;
39 struct list_head link;39 struct list_head link;
40 struct tcf_result res;40 struct tcf_result res;
41 bool exts_integrated;
41 struct tcf_exts exts;42 struct tcf_exts exts;
42 u32 handle;43 u32 handle;
43 union {44 union {
@@ -52,6 +53,7 @@ struct cls_bpf_prog { · 8 unmodified lines
52 53
53static const struct nla_policy bpf_policy[TCA_BPF_MAX + 1] = {54static const struct nla_policy bpf_policy[TCA_BPF_MAX + 1] = {
54 [TCA_BPF_CLASSID] = { .type = NLA_U32 },55 [TCA_BPF_CLASSID] = { .type = NLA_U32 },
56 [TCA_BPF_FLAGS] = { .type = NLA_U32 },
55 [TCA_BPF_FD] = { .type = NLA_U32 },57 [TCA_BPF_FD] = { .type = NLA_U32 },
56 [TCA_BPF_NAME] = { .type = NLA_NUL_STRING, .len = CLS_BPF_NAME_LEN },58 [TCA_BPF_NAME] = { .type = NLA_NUL_STRING, .len = CLS_BPF_NAME_LEN },
57 [TCA_BPF_OPS_LEN] = { .type = NLA_U16 },59 [TCA_BPF_OPS_LEN] = { .type = NLA_U16 },
@@ -59,6 +61,22 @@ static const struct nla_policy bpf_policy[TCA_BPF_MAX + 1] = { · 1 unmodified line
59 .len = sizeof(struct sock_filter) * BPF_MAXINSNS },61 .len = sizeof(struct sock_filter) * BPF_MAXINSNS },
60};62};
61 63
64static int cls_bpf_exec_opcode(int code)
65{
66 switch (code) {
67 case TC_ACT_OK:
68 case TC_ACT_RECLASSIFY:
69 case TC_ACT_SHOT:
70 case TC_ACT_PIPE:
71 case TC_ACT_STOLEN:
72 case TC_ACT_QUEUED:
73 case TC_ACT_UNSPEC:
74 return code;
75 default:
76 return TC_ACT_UNSPEC;
77 }
78}
79
62static int cls_bpf_classify(struct sk_buff *skb, const struct tcf_proto *tp,80static int cls_bpf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
63 struct tcf_result *res)81 struct tcf_result *res)
64{82{
@@ -79,6 +97,8 @@ static int cls_bpf_classify(struct sk_buff *skb, const struct tcf_proto *tp, · 14 unmodified lines
79 list_for_each_entry_rcu(prog, &head->plist, link) {97 list_for_each_entry_rcu(prog, &head->plist, link) {
80 int filter_res;98 int filter_res;
81 99
100 qdisc_skb_cb(skb)->tc_classid = prog->res.classid;
101
82 if (at_ingress) {102 if (at_ingress) {
83 /* It is safe to push/pull even if skb_shared() */103 /* It is safe to push/pull even if skb_shared() */
84 __skb_push(skb, skb->mac_len);104 __skb_push(skb, skb->mac_len);
@@ -88,6 +108,16 @@ static int cls_bpf_classify(struct sk_buff *skb, const struct tcf_proto *tp, · 3 unmodified lines
88 filter_res = BPF_PROG_RUN(prog->filter, skb);108 filter_res = BPF_PROG_RUN(prog->filter, skb);
89 }109 }
90 110
111 if (prog->exts_integrated) {
112 res->class = prog->res.class;
113 res->classid = qdisc_skb_cb(skb)->tc_classid;
114
115 ret = cls_bpf_exec_opcode(filter_res);
116 if (ret == TC_ACT_UNSPEC)
117 continue;
118 break;
119 }
120
91 if (filter_res == 0)121 if (filter_res == 0)
92 continue;122 continue;
93 123
@@ -195,8 +225,7 @@ static unsigned long cls_bpf_get(struct tcf_proto *tp, u32 handle) · 101 unmodified lines
195 return ret;225 return ret;
196}226}
197 227
198static int cls_bpf_prog_from_ops(struct nlattr **tb,228static int cls_bpf_prog_from_ops(struct nlattr **tb, struct cls_bpf_prog *prog)
199 struct cls_bpf_prog *prog, u32 classid)
200{229{
201 struct sock_filter *bpf_ops;230 struct sock_filter *bpf_ops;
202 struct sock_fprog_kern fprog_tmp;231 struct sock_fprog_kern fprog_tmp;
@@ -230,15 +259,13 @@ static int cls_bpf_prog_from_ops(struct nlattr **tb, · 27 unmodified lines
230 prog->bpf_ops = bpf_ops;259 prog->bpf_ops = bpf_ops;
231 prog->bpf_num_ops = bpf_num_ops;260 prog->bpf_num_ops = bpf_num_ops;
232 prog->bpf_name = NULL;261 prog->bpf_name = NULL;
233
234 prog->filter = fp;262 prog->filter = fp;
235 prog->res.classid = classid;
236 263
237 return 0;264 return 0;
238}265}
239 266
240static int cls_bpf_prog_from_efd(struct nlattr **tb,267static int cls_bpf_prog_from_efd(struct nlattr **tb, struct cls_bpf_prog *prog,
241 struct cls_bpf_prog *prog, u32 classid)268 const struct tcf_proto *tp)
242{269{
243 struct bpf_prog *fp;270 struct bpf_prog *fp;
244 char *name = NULL;271 char *name = NULL;
@@ -268,9 +295,7 @@ static int cls_bpf_prog_from_efd(struct nlattr **tb, · 23 unmodified lines
268 prog->bpf_ops = NULL;295 prog->bpf_ops = NULL;
269 prog->bpf_fd = bpf_fd;296 prog->bpf_fd = bpf_fd;
270 prog->bpf_name = name;297 prog->bpf_name = name;
271
272 prog->filter = fp;298 prog->filter = fp;
273 prog->res.classid = classid;
274 299
275 return 0;300 return 0;
276}301}
@@ -280,8 +305,8 @@ static int cls_bpf_modify_existing(struct net *net, struct tcf_proto *tp, · 3 unmodified lines
280 unsigned long base, struct nlattr **tb,305 unsigned long base, struct nlattr **tb,
281 struct nlattr *est, bool ovr)306 struct nlattr *est, bool ovr)
282{307{
308 bool is_bpf, is_ebpf, have_exts = false;
283 struct tcf_exts exts;309 struct tcf_exts exts;
284 bool is_bpf, is_ebpf;
285 u32 classid;310 u32 classid;
286 int ret;311 int ret;
287 312
@@ -298,9 +323,22 @@ static int cls_bpf_modify_existing(struct net *net, struct tcf_proto *tp, · 10 unmodified lines
298 return ret;323 return ret;
299 324
300 classid = nla_get_u32(tb[TCA_BPF_CLASSID]);325 classid = nla_get_u32(tb[TCA_BPF_CLASSID]);
326 if (tb[TCA_BPF_FLAGS]) {
327 u32 bpf_flags = nla_get_u32(tb[TCA_BPF_FLAGS]);
328
329 if (bpf_flags & ~TCA_BPF_FLAG_ACT_DIRECT) {
330 tcf_exts_destroy(&exts);
331 return -EINVAL;
332 }
333
334 have_exts = bpf_flags & TCA_BPF_FLAG_ACT_DIRECT;
335 }
336
337 prog->res.classid = classid;
338 prog->exts_integrated = have_exts;
301 339
302 ret = is_bpf ? cls_bpf_prog_from_ops(tb, prog, classid) :340 ret = is_bpf ? cls_bpf_prog_from_ops(tb, prog) :
303 cls_bpf_prog_from_efd(tb, prog, classid);341 cls_bpf_prog_from_efd(tb, prog, tp);
304 if (ret < 0) {342 if (ret < 0) {
305 tcf_exts_destroy(&exts);343 tcf_exts_destroy(&exts);
306 return ret;344 return ret;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t