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
251251 struct qdisc_skb_cb {
252252 unsigned int pkt_len;
253253 u16 slave_dev_queue_mapping;
254− u16 _pad;
254+ u16 tc_classid;
255255 #define QDISC_CB_PRIV_LEN 20
256256 unsigned char data[QDISC_CB_PRIV_LEN];
257257 };
include/uapi/linux/bpf.h+1−0
@@ -293,6 +293,7 @@ struct __sk_buff { · 292 unmodified lines
293293 __u32 tc_index;
294294 __u32 cb[5];
295295 __u32 hash;
296+ __u32 tc_classid;
296297 };
297298
298299 struct bpf_tunnel_key {
include/uapi/linux/pkt_cls.h+3−0
@@ -373,6 +373,8 @@ enum { · 372 unmodified lines
373373
374374 /* BPF classifier */
375375
376+#define TCA_BPF_FLAG_ACT_DIRECT (1 << 0)
377+
376378 enum {
377379 TCA_BPF_UNSPEC,
378380 TCA_BPF_ACT,
@@ -382,6 +384,7 @@ enum { · 3 unmodified lines
382384 TCA_BPF_OPS,
383385 TCA_BPF_FD,
384386 TCA_BPF_NAME,
387+ TCA_BPF_FLAGS,
385388 __TCA_BPF_MAX,
386389 };
387390
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
16321632 static bool sk_filter_is_valid_access(int off, int size,
16331633 enum bpf_access_type type)
16341634 {
1635+ if (off == offsetof(struct __sk_buff, tc_classid))
1636+ return false;
1637+
16351638 if (type == BPF_WRITE) {
16361639 switch (off) {
16371640 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
16481651 static bool tc_cls_act_is_valid_access(int off, int size,
16491652 enum bpf_access_type type)
16501653 {
1654+ if (off == offsetof(struct __sk_buff, tc_classid))
1655+ return type == BPF_WRITE ? true : false;
1656+
16511657 if (type == BPF_WRITE) {
16521658 switch (off) {
16531659 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
17601766 *insn++ = BPF_LDX_MEM(BPF_W, dst_reg, src_reg, ctx_off);
17611767 break;
17621768
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+
17631777 case offsetof(struct __sk_buff, tc_index):
17641778 #ifdef CONFIG_NET_SCHED
17651779 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
3838 struct bpf_prog *filter;
3939 struct list_head link;
4040 struct tcf_result res;
41+ bool exts_integrated;
4142 struct tcf_exts exts;
4243 u32 handle;
4344 union {
@@ -52,6 +53,7 @@ struct cls_bpf_prog { · 8 unmodified lines
5253
5354 static const struct nla_policy bpf_policy[TCA_BPF_MAX + 1] = {
5455 [TCA_BPF_CLASSID] = { .type = NLA_U32 },
56+ [TCA_BPF_FLAGS] = { .type = NLA_U32 },
5557 [TCA_BPF_FD] = { .type = NLA_U32 },
5658 [TCA_BPF_NAME] = { .type = NLA_NUL_STRING, .len = CLS_BPF_NAME_LEN },
5759 [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
5961 .len = sizeof(struct sock_filter) * BPF_MAXINSNS },
6062 };
6163
64+static 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+
6280 static int cls_bpf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
6381 struct tcf_result *res)
6482 {
@@ -79,6 +97,8 @@ static int cls_bpf_classify(struct sk_buff *skb, const struct tcf_proto *tp, · 14 unmodified lines
7997 list_for_each_entry_rcu(prog, &head->plist, link) {
8098 int filter_res;
8199
100+ qdisc_skb_cb(skb)->tc_classid = prog->res.classid;
101+
82102 if (at_ingress) {
83103 /* It is safe to push/pull even if skb_shared() */
84104 __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
88108 filter_res = BPF_PROG_RUN(prog->filter, skb);
89109 }
90110
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+
91121 if (filter_res == 0)
92122 continue;
93123
@@ -195,8 +225,7 @@ static unsigned long cls_bpf_get(struct tcf_proto *tp, u32 handle) · 101 unmodified lines
195225 return ret;
196226 }
197227
198−static int cls_bpf_prog_from_ops(struct nlattr **tb,
199− struct cls_bpf_prog *prog, u32 classid)
228+static int cls_bpf_prog_from_ops(struct nlattr **tb, struct cls_bpf_prog *prog)
200229 {
201230 struct sock_filter *bpf_ops;
202231 struct sock_fprog_kern fprog_tmp;
@@ -230,15 +259,13 @@ static int cls_bpf_prog_from_ops(struct nlattr **tb, · 27 unmodified lines
230259 prog->bpf_ops = bpf_ops;
231260 prog->bpf_num_ops = bpf_num_ops;
232261 prog->bpf_name = NULL;
233−
234262 prog->filter = fp;
235− prog->res.classid = classid;
236263
237264 return 0;
238265 }
239266
240−static int cls_bpf_prog_from_efd(struct nlattr **tb,
241− struct cls_bpf_prog *prog, u32 classid)
267+static int cls_bpf_prog_from_efd(struct nlattr **tb, struct cls_bpf_prog *prog,
268+ const struct tcf_proto *tp)
242269 {
243270 struct bpf_prog *fp;
244271 char *name = NULL;
@@ -268,9 +295,7 @@ static int cls_bpf_prog_from_efd(struct nlattr **tb, · 23 unmodified lines
268295 prog->bpf_ops = NULL;
269296 prog->bpf_fd = bpf_fd;
270297 prog->bpf_name = name;
271−
272298 prog->filter = fp;
273− prog->res.classid = classid;
274299
275300 return 0;
276301 }
@@ -280,8 +305,8 @@ static int cls_bpf_modify_existing(struct net *net, struct tcf_proto *tp, · 3 unmodified lines
280305 unsigned long base, struct nlattr **tb,
281306 struct nlattr *est, bool ovr)
282307 {
308+ bool is_bpf, is_ebpf, have_exts = false;
283309 struct tcf_exts exts;
284− bool is_bpf, is_ebpf;
285310 u32 classid;
286311 int ret;
287312
@@ -298,9 +323,22 @@ static int cls_bpf_modify_existing(struct net *net, struct tcf_proto *tp, · 10 unmodified lines
298323 return ret;
299324
300325 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;
301339
302− ret = is_bpf ? cls_bpf_prog_from_ops(tb, prog, classid) :
303− cls_bpf_prog_from_efd(tb, prog, classid);
340+ ret = is_bpf ? cls_bpf_prog_from_ops(tb, prog) :
341+ cls_bpf_prog_from_efd(tb, prog, tp);
304342 if (ret < 0) {
305343 tcf_exts_destroy(&exts);
306344 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