blob: 5a7d66c59684d67173fa4c720de225a3ae36a27f [file] [log] [blame]
Jiri Pirko77b99002015-05-12 14:56:21 +02001/*
2 * net/sched/cls_flower.c Flower classifier
3 *
4 * Copyright (c) 2015 Jiri Pirko <jiri@resnulli.us>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <linux/kernel.h>
13#include <linux/init.h>
14#include <linux/module.h>
15#include <linux/rhashtable.h>
16
17#include <linux/if_ether.h>
18#include <linux/in6.h>
19#include <linux/ip.h>
20
21#include <net/sch_generic.h>
22#include <net/pkt_cls.h>
23#include <net/ip.h>
24#include <net/flow_dissector.h>
25
26struct fl_flow_key {
27 int indev_ifindex;
Tom Herbert42aecaa2015-06-04 09:16:39 -070028 struct flow_dissector_key_control control;
Jiri Pirko77b99002015-05-12 14:56:21 +020029 struct flow_dissector_key_basic basic;
30 struct flow_dissector_key_eth_addrs eth;
31 union {
32 struct flow_dissector_key_addrs ipv4;
33 struct flow_dissector_key_ipv6_addrs ipv6;
34 };
35 struct flow_dissector_key_ports tp;
36} __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */
37
38struct fl_flow_mask_range {
39 unsigned short int start;
40 unsigned short int end;
41};
42
43struct fl_flow_mask {
44 struct fl_flow_key key;
45 struct fl_flow_mask_range range;
46 struct rcu_head rcu;
47};
48
49struct cls_fl_head {
50 struct rhashtable ht;
51 struct fl_flow_mask mask;
52 struct flow_dissector dissector;
53 u32 hgen;
54 bool mask_assigned;
55 struct list_head filters;
56 struct rhashtable_params ht_params;
57 struct rcu_head rcu;
58};
59
60struct cls_fl_filter {
61 struct rhash_head ht_node;
62 struct fl_flow_key mkey;
63 struct tcf_exts exts;
64 struct tcf_result res;
65 struct fl_flow_key key;
66 struct list_head list;
67 u32 handle;
68 struct rcu_head rcu;
69};
70
71static unsigned short int fl_mask_range(const struct fl_flow_mask *mask)
72{
73 return mask->range.end - mask->range.start;
74}
75
76static void fl_mask_update_range(struct fl_flow_mask *mask)
77{
78 const u8 *bytes = (const u8 *) &mask->key;
79 size_t size = sizeof(mask->key);
80 size_t i, first = 0, last = size - 1;
81
82 for (i = 0; i < sizeof(mask->key); i++) {
83 if (bytes[i]) {
84 if (!first && i)
85 first = i;
86 last = i;
87 }
88 }
89 mask->range.start = rounddown(first, sizeof(long));
90 mask->range.end = roundup(last + 1, sizeof(long));
91}
92
93static void *fl_key_get_start(struct fl_flow_key *key,
94 const struct fl_flow_mask *mask)
95{
96 return (u8 *) key + mask->range.start;
97}
98
99static void fl_set_masked_key(struct fl_flow_key *mkey, struct fl_flow_key *key,
100 struct fl_flow_mask *mask)
101{
102 const long *lkey = fl_key_get_start(key, mask);
103 const long *lmask = fl_key_get_start(&mask->key, mask);
104 long *lmkey = fl_key_get_start(mkey, mask);
105 int i;
106
107 for (i = 0; i < fl_mask_range(mask); i += sizeof(long))
108 *lmkey++ = *lkey++ & *lmask++;
109}
110
111static void fl_clear_masked_range(struct fl_flow_key *key,
112 struct fl_flow_mask *mask)
113{
114 memset(fl_key_get_start(key, mask), 0, fl_mask_range(mask));
115}
116
117static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp,
118 struct tcf_result *res)
119{
120 struct cls_fl_head *head = rcu_dereference_bh(tp->root);
121 struct cls_fl_filter *f;
122 struct fl_flow_key skb_key;
123 struct fl_flow_key skb_mkey;
124
125 fl_clear_masked_range(&skb_key, &head->mask);
126 skb_key.indev_ifindex = skb->skb_iif;
127 /* skb_flow_dissect() does not set n_proto in case an unknown protocol,
128 * so do it rather here.
129 */
130 skb_key.basic.n_proto = skb->protocol;
131 skb_flow_dissect(skb, &head->dissector, &skb_key);
132
133 fl_set_masked_key(&skb_mkey, &skb_key, &head->mask);
134
135 f = rhashtable_lookup_fast(&head->ht,
136 fl_key_get_start(&skb_mkey, &head->mask),
137 head->ht_params);
138 if (f) {
139 *res = f->res;
140 return tcf_exts_exec(skb, &f->exts, res);
141 }
142 return -1;
143}
144
145static int fl_init(struct tcf_proto *tp)
146{
147 struct cls_fl_head *head;
148
149 head = kzalloc(sizeof(*head), GFP_KERNEL);
150 if (!head)
151 return -ENOBUFS;
152
153 INIT_LIST_HEAD_RCU(&head->filters);
154 rcu_assign_pointer(tp->root, head);
155
156 return 0;
157}
158
159static void fl_destroy_filter(struct rcu_head *head)
160{
161 struct cls_fl_filter *f = container_of(head, struct cls_fl_filter, rcu);
162
163 tcf_exts_destroy(&f->exts);
164 kfree(f);
165}
166
167static bool fl_destroy(struct tcf_proto *tp, bool force)
168{
169 struct cls_fl_head *head = rtnl_dereference(tp->root);
170 struct cls_fl_filter *f, *next;
171
172 if (!force && !list_empty(&head->filters))
173 return false;
174
175 list_for_each_entry_safe(f, next, &head->filters, list) {
176 list_del_rcu(&f->list);
177 call_rcu(&f->rcu, fl_destroy_filter);
178 }
179 RCU_INIT_POINTER(tp->root, NULL);
180 if (head->mask_assigned)
181 rhashtable_destroy(&head->ht);
182 kfree_rcu(head, rcu);
183 return true;
184}
185
186static unsigned long fl_get(struct tcf_proto *tp, u32 handle)
187{
188 struct cls_fl_head *head = rtnl_dereference(tp->root);
189 struct cls_fl_filter *f;
190
191 list_for_each_entry(f, &head->filters, list)
192 if (f->handle == handle)
193 return (unsigned long) f;
194 return 0;
195}
196
197static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = {
198 [TCA_FLOWER_UNSPEC] = { .type = NLA_UNSPEC },
199 [TCA_FLOWER_CLASSID] = { .type = NLA_U32 },
200 [TCA_FLOWER_INDEV] = { .type = NLA_STRING,
201 .len = IFNAMSIZ },
202 [TCA_FLOWER_KEY_ETH_DST] = { .len = ETH_ALEN },
203 [TCA_FLOWER_KEY_ETH_DST_MASK] = { .len = ETH_ALEN },
204 [TCA_FLOWER_KEY_ETH_SRC] = { .len = ETH_ALEN },
205 [TCA_FLOWER_KEY_ETH_SRC_MASK] = { .len = ETH_ALEN },
206 [TCA_FLOWER_KEY_ETH_TYPE] = { .type = NLA_U16 },
207 [TCA_FLOWER_KEY_IP_PROTO] = { .type = NLA_U8 },
208 [TCA_FLOWER_KEY_IPV4_SRC] = { .type = NLA_U32 },
209 [TCA_FLOWER_KEY_IPV4_SRC_MASK] = { .type = NLA_U32 },
210 [TCA_FLOWER_KEY_IPV4_DST] = { .type = NLA_U32 },
211 [TCA_FLOWER_KEY_IPV4_DST_MASK] = { .type = NLA_U32 },
212 [TCA_FLOWER_KEY_IPV6_SRC] = { .len = sizeof(struct in6_addr) },
213 [TCA_FLOWER_KEY_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) },
214 [TCA_FLOWER_KEY_IPV6_DST] = { .len = sizeof(struct in6_addr) },
215 [TCA_FLOWER_KEY_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) },
216 [TCA_FLOWER_KEY_TCP_SRC] = { .type = NLA_U16 },
217 [TCA_FLOWER_KEY_TCP_DST] = { .type = NLA_U16 },
218 [TCA_FLOWER_KEY_TCP_SRC] = { .type = NLA_U16 },
219 [TCA_FLOWER_KEY_TCP_DST] = { .type = NLA_U16 },
220};
221
222static void fl_set_key_val(struct nlattr **tb,
223 void *val, int val_type,
224 void *mask, int mask_type, int len)
225{
226 if (!tb[val_type])
227 return;
228 memcpy(val, nla_data(tb[val_type]), len);
229 if (mask_type == TCA_FLOWER_UNSPEC || !tb[mask_type])
230 memset(mask, 0xff, len);
231 else
232 memcpy(mask, nla_data(tb[mask_type]), len);
233}
234
235static int fl_set_key(struct net *net, struct nlattr **tb,
236 struct fl_flow_key *key, struct fl_flow_key *mask)
237{
Brian Haleydd3aa3b2015-05-14 13:20:15 -0400238#ifdef CONFIG_NET_CLS_IND
Jiri Pirko77b99002015-05-12 14:56:21 +0200239 if (tb[TCA_FLOWER_INDEV]) {
Brian Haleydd3aa3b2015-05-14 13:20:15 -0400240 int err = tcf_change_indev(net, tb[TCA_FLOWER_INDEV]);
Jiri Pirko77b99002015-05-12 14:56:21 +0200241 if (err < 0)
242 return err;
243 key->indev_ifindex = err;
244 mask->indev_ifindex = 0xffffffff;
245 }
Brian Haleydd3aa3b2015-05-14 13:20:15 -0400246#endif
Jiri Pirko77b99002015-05-12 14:56:21 +0200247
248 fl_set_key_val(tb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST,
249 mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK,
250 sizeof(key->eth.dst));
251 fl_set_key_val(tb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC,
252 mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK,
253 sizeof(key->eth.src));
254 fl_set_key_val(tb, &key->basic.n_proto, TCA_FLOWER_KEY_ETH_TYPE,
255 &mask->basic.n_proto, TCA_FLOWER_UNSPEC,
256 sizeof(key->basic.n_proto));
257 if (key->basic.n_proto == htons(ETH_P_IP) ||
258 key->basic.n_proto == htons(ETH_P_IPV6)) {
259 fl_set_key_val(tb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO,
260 &mask->basic.ip_proto, TCA_FLOWER_UNSPEC,
261 sizeof(key->basic.ip_proto));
262 }
263 if (key->basic.n_proto == htons(ETH_P_IP)) {
264 fl_set_key_val(tb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC,
265 &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK,
266 sizeof(key->ipv4.src));
267 fl_set_key_val(tb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST,
268 &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK,
269 sizeof(key->ipv4.dst));
270 } else if (key->basic.n_proto == htons(ETH_P_IPV6)) {
271 fl_set_key_val(tb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC,
272 &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK,
273 sizeof(key->ipv6.src));
274 fl_set_key_val(tb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST,
275 &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK,
276 sizeof(key->ipv6.dst));
277 }
278 if (key->basic.ip_proto == IPPROTO_TCP) {
279 fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC,
280 &mask->tp.src, TCA_FLOWER_UNSPEC,
281 sizeof(key->tp.src));
282 fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST,
283 &mask->tp.dst, TCA_FLOWER_UNSPEC,
284 sizeof(key->tp.dst));
285 } else if (key->basic.ip_proto == IPPROTO_UDP) {
286 fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC,
287 &mask->tp.src, TCA_FLOWER_UNSPEC,
288 sizeof(key->tp.src));
289 fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST,
290 &mask->tp.dst, TCA_FLOWER_UNSPEC,
291 sizeof(key->tp.dst));
292 }
293
294 return 0;
295}
296
297static bool fl_mask_eq(struct fl_flow_mask *mask1,
298 struct fl_flow_mask *mask2)
299{
300 const long *lmask1 = fl_key_get_start(&mask1->key, mask1);
301 const long *lmask2 = fl_key_get_start(&mask2->key, mask2);
302
303 return !memcmp(&mask1->range, &mask2->range, sizeof(mask1->range)) &&
304 !memcmp(lmask1, lmask2, fl_mask_range(mask1));
305}
306
307static const struct rhashtable_params fl_ht_params = {
308 .key_offset = offsetof(struct cls_fl_filter, mkey), /* base offset */
309 .head_offset = offsetof(struct cls_fl_filter, ht_node),
310 .automatic_shrinking = true,
311};
312
313static int fl_init_hashtable(struct cls_fl_head *head,
314 struct fl_flow_mask *mask)
315{
316 head->ht_params = fl_ht_params;
317 head->ht_params.key_len = fl_mask_range(mask);
318 head->ht_params.key_offset += mask->range.start;
319
320 return rhashtable_init(&head->ht, &head->ht_params);
321}
322
323#define FL_KEY_MEMBER_OFFSET(member) offsetof(struct fl_flow_key, member)
324#define FL_KEY_MEMBER_SIZE(member) (sizeof(((struct fl_flow_key *) 0)->member))
325#define FL_KEY_MEMBER_END_OFFSET(member) \
326 (FL_KEY_MEMBER_OFFSET(member) + FL_KEY_MEMBER_SIZE(member))
327
328#define FL_KEY_IN_RANGE(mask, member) \
329 (FL_KEY_MEMBER_OFFSET(member) <= (mask)->range.end && \
330 FL_KEY_MEMBER_END_OFFSET(member) >= (mask)->range.start)
331
332#define FL_KEY_SET(keys, cnt, id, member) \
333 do { \
334 keys[cnt].key_id = id; \
335 keys[cnt].offset = FL_KEY_MEMBER_OFFSET(member); \
336 cnt++; \
337 } while(0);
338
339#define FL_KEY_SET_IF_IN_RANGE(mask, keys, cnt, id, member) \
340 do { \
341 if (FL_KEY_IN_RANGE(mask, member)) \
342 FL_KEY_SET(keys, cnt, id, member); \
343 } while(0);
344
345static void fl_init_dissector(struct cls_fl_head *head,
346 struct fl_flow_mask *mask)
347{
348 struct flow_dissector_key keys[FLOW_DISSECTOR_KEY_MAX];
349 size_t cnt = 0;
350
Tom Herbert42aecaa2015-06-04 09:16:39 -0700351 FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_CONTROL, control);
Jiri Pirko77b99002015-05-12 14:56:21 +0200352 FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_BASIC, basic);
353 FL_KEY_SET_IF_IN_RANGE(mask, keys, cnt,
354 FLOW_DISSECTOR_KEY_ETH_ADDRS, eth);
355 FL_KEY_SET_IF_IN_RANGE(mask, keys, cnt,
356 FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4);
357 FL_KEY_SET_IF_IN_RANGE(mask, keys, cnt,
358 FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6);
359 FL_KEY_SET_IF_IN_RANGE(mask, keys, cnt,
360 FLOW_DISSECTOR_KEY_PORTS, tp);
361
362 skb_flow_dissector_init(&head->dissector, keys, cnt);
363}
364
365static int fl_check_assign_mask(struct cls_fl_head *head,
366 struct fl_flow_mask *mask)
367{
368 int err;
369
370 if (head->mask_assigned) {
371 if (!fl_mask_eq(&head->mask, mask))
372 return -EINVAL;
373 else
374 return 0;
375 }
376
377 /* Mask is not assigned yet. So assign it and init hashtable
378 * according to that.
379 */
380 err = fl_init_hashtable(head, mask);
381 if (err)
382 return err;
383 memcpy(&head->mask, mask, sizeof(head->mask));
384 head->mask_assigned = true;
385
386 fl_init_dissector(head, mask);
387
388 return 0;
389}
390
391static int fl_set_parms(struct net *net, struct tcf_proto *tp,
392 struct cls_fl_filter *f, struct fl_flow_mask *mask,
393 unsigned long base, struct nlattr **tb,
394 struct nlattr *est, bool ovr)
395{
396 struct tcf_exts e;
397 int err;
398
399 tcf_exts_init(&e, TCA_FLOWER_ACT, 0);
400 err = tcf_exts_validate(net, tp, tb, est, &e, ovr);
401 if (err < 0)
402 return err;
403
404 if (tb[TCA_FLOWER_CLASSID]) {
405 f->res.classid = nla_get_u32(tb[TCA_FLOWER_CLASSID]);
406 tcf_bind_filter(tp, &f->res, base);
407 }
408
409 err = fl_set_key(net, tb, &f->key, &mask->key);
410 if (err)
411 goto errout;
412
413 fl_mask_update_range(mask);
414 fl_set_masked_key(&f->mkey, &f->key, mask);
415
416 tcf_exts_change(tp, &f->exts, &e);
417
418 return 0;
419errout:
420 tcf_exts_destroy(&e);
421 return err;
422}
423
424static u32 fl_grab_new_handle(struct tcf_proto *tp,
425 struct cls_fl_head *head)
426{
427 unsigned int i = 0x80000000;
428 u32 handle;
429
430 do {
431 if (++head->hgen == 0x7FFFFFFF)
432 head->hgen = 1;
433 } while (--i > 0 && fl_get(tp, head->hgen));
434
435 if (unlikely(i == 0)) {
436 pr_err("Insufficient number of handles\n");
437 handle = 0;
438 } else {
439 handle = head->hgen;
440 }
441
442 return handle;
443}
444
445static int fl_change(struct net *net, struct sk_buff *in_skb,
446 struct tcf_proto *tp, unsigned long base,
447 u32 handle, struct nlattr **tca,
448 unsigned long *arg, bool ovr)
449{
450 struct cls_fl_head *head = rtnl_dereference(tp->root);
451 struct cls_fl_filter *fold = (struct cls_fl_filter *) *arg;
452 struct cls_fl_filter *fnew;
453 struct nlattr *tb[TCA_FLOWER_MAX + 1];
454 struct fl_flow_mask mask = {};
455 int err;
456
457 if (!tca[TCA_OPTIONS])
458 return -EINVAL;
459
460 err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS], fl_policy);
461 if (err < 0)
462 return err;
463
464 if (fold && handle && fold->handle != handle)
465 return -EINVAL;
466
467 fnew = kzalloc(sizeof(*fnew), GFP_KERNEL);
468 if (!fnew)
469 return -ENOBUFS;
470
471 tcf_exts_init(&fnew->exts, TCA_FLOWER_ACT, 0);
472
473 if (!handle) {
474 handle = fl_grab_new_handle(tp, head);
475 if (!handle) {
476 err = -EINVAL;
477 goto errout;
478 }
479 }
480 fnew->handle = handle;
481
482 err = fl_set_parms(net, tp, fnew, &mask, base, tb, tca[TCA_RATE], ovr);
483 if (err)
484 goto errout;
485
486 err = fl_check_assign_mask(head, &mask);
487 if (err)
488 goto errout;
489
490 err = rhashtable_insert_fast(&head->ht, &fnew->ht_node,
491 head->ht_params);
492 if (err)
493 goto errout;
494 if (fold)
495 rhashtable_remove_fast(&head->ht, &fold->ht_node,
496 head->ht_params);
497
498 *arg = (unsigned long) fnew;
499
500 if (fold) {
501 list_replace_rcu(&fnew->list, &fold->list);
502 tcf_unbind_filter(tp, &fold->res);
503 call_rcu(&fold->rcu, fl_destroy_filter);
504 } else {
505 list_add_tail_rcu(&fnew->list, &head->filters);
506 }
507
508 return 0;
509
510errout:
511 kfree(fnew);
512 return err;
513}
514
515static int fl_delete(struct tcf_proto *tp, unsigned long arg)
516{
517 struct cls_fl_head *head = rtnl_dereference(tp->root);
518 struct cls_fl_filter *f = (struct cls_fl_filter *) arg;
519
520 rhashtable_remove_fast(&head->ht, &f->ht_node,
521 head->ht_params);
522 list_del_rcu(&f->list);
523 tcf_unbind_filter(tp, &f->res);
524 call_rcu(&f->rcu, fl_destroy_filter);
525 return 0;
526}
527
528static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg)
529{
530 struct cls_fl_head *head = rtnl_dereference(tp->root);
531 struct cls_fl_filter *f;
532
533 list_for_each_entry_rcu(f, &head->filters, list) {
534 if (arg->count < arg->skip)
535 goto skip;
536 if (arg->fn(tp, (unsigned long) f, arg) < 0) {
537 arg->stop = 1;
538 break;
539 }
540skip:
541 arg->count++;
542 }
543}
544
545static int fl_dump_key_val(struct sk_buff *skb,
546 void *val, int val_type,
547 void *mask, int mask_type, int len)
548{
549 int err;
550
551 if (!memchr_inv(mask, 0, len))
552 return 0;
553 err = nla_put(skb, val_type, len, val);
554 if (err)
555 return err;
556 if (mask_type != TCA_FLOWER_UNSPEC) {
557 err = nla_put(skb, mask_type, len, mask);
558 if (err)
559 return err;
560 }
561 return 0;
562}
563
564static int fl_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
565 struct sk_buff *skb, struct tcmsg *t)
566{
567 struct cls_fl_head *head = rtnl_dereference(tp->root);
568 struct cls_fl_filter *f = (struct cls_fl_filter *) fh;
569 struct nlattr *nest;
570 struct fl_flow_key *key, *mask;
571
572 if (!f)
573 return skb->len;
574
575 t->tcm_handle = f->handle;
576
577 nest = nla_nest_start(skb, TCA_OPTIONS);
578 if (!nest)
579 goto nla_put_failure;
580
581 if (f->res.classid &&
582 nla_put_u32(skb, TCA_FLOWER_CLASSID, f->res.classid))
583 goto nla_put_failure;
584
585 key = &f->key;
586 mask = &head->mask.key;
587
588 if (mask->indev_ifindex) {
589 struct net_device *dev;
590
591 dev = __dev_get_by_index(net, key->indev_ifindex);
592 if (dev && nla_put_string(skb, TCA_FLOWER_INDEV, dev->name))
593 goto nla_put_failure;
594 }
595
596 if (fl_dump_key_val(skb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST,
597 mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK,
598 sizeof(key->eth.dst)) ||
599 fl_dump_key_val(skb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC,
600 mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK,
601 sizeof(key->eth.src)) ||
602 fl_dump_key_val(skb, &key->basic.n_proto, TCA_FLOWER_KEY_ETH_TYPE,
603 &mask->basic.n_proto, TCA_FLOWER_UNSPEC,
604 sizeof(key->basic.n_proto)))
605 goto nla_put_failure;
606 if ((key->basic.n_proto == htons(ETH_P_IP) ||
607 key->basic.n_proto == htons(ETH_P_IPV6)) &&
608 fl_dump_key_val(skb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO,
609 &mask->basic.ip_proto, TCA_FLOWER_UNSPEC,
610 sizeof(key->basic.ip_proto)))
611 goto nla_put_failure;
612
613 if (key->basic.n_proto == htons(ETH_P_IP) &&
614 (fl_dump_key_val(skb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC,
615 &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK,
616 sizeof(key->ipv4.src)) ||
617 fl_dump_key_val(skb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST,
618 &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK,
619 sizeof(key->ipv4.dst))))
620 goto nla_put_failure;
621 else if (key->basic.n_proto == htons(ETH_P_IPV6) &&
622 (fl_dump_key_val(skb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC,
623 &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK,
624 sizeof(key->ipv6.src)) ||
625 fl_dump_key_val(skb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST,
626 &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK,
627 sizeof(key->ipv6.dst))))
628 goto nla_put_failure;
629
630 if (key->basic.ip_proto == IPPROTO_TCP &&
631 (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC,
632 &mask->tp.src, TCA_FLOWER_UNSPEC,
633 sizeof(key->tp.src)) ||
634 fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST,
635 &mask->tp.dst, TCA_FLOWER_UNSPEC,
636 sizeof(key->tp.dst))))
637 goto nla_put_failure;
638 else if (key->basic.ip_proto == IPPROTO_UDP &&
639 (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC,
640 &mask->tp.src, TCA_FLOWER_UNSPEC,
641 sizeof(key->tp.src)) ||
642 fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST,
643 &mask->tp.dst, TCA_FLOWER_UNSPEC,
644 sizeof(key->tp.dst))))
645 goto nla_put_failure;
646
647 if (tcf_exts_dump(skb, &f->exts))
648 goto nla_put_failure;
649
650 nla_nest_end(skb, nest);
651
652 if (tcf_exts_dump_stats(skb, &f->exts) < 0)
653 goto nla_put_failure;
654
655 return skb->len;
656
657nla_put_failure:
658 nla_nest_cancel(skb, nest);
659 return -1;
660}
661
662static struct tcf_proto_ops cls_fl_ops __read_mostly = {
663 .kind = "flower",
664 .classify = fl_classify,
665 .init = fl_init,
666 .destroy = fl_destroy,
667 .get = fl_get,
668 .change = fl_change,
669 .delete = fl_delete,
670 .walk = fl_walk,
671 .dump = fl_dump,
672 .owner = THIS_MODULE,
673};
674
675static int __init cls_fl_init(void)
676{
677 return register_tcf_proto_ops(&cls_fl_ops);
678}
679
680static void __exit cls_fl_exit(void)
681{
682 unregister_tcf_proto_ops(&cls_fl_ops);
683}
684
685module_init(cls_fl_init);
686module_exit(cls_fl_exit);
687
688MODULE_AUTHOR("Jiri Pirko <jiri@resnulli.us>");
689MODULE_DESCRIPTION("Flower classifier");
690MODULE_LICENSE("GPL v2");