blob: a8fb1ca03b3ea513a2822621db1e03aff92695b6 [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
Amir Vadaibc3103f2016-09-08 16:23:47 +030026#include <net/dst.h>
27#include <net/dst_metadata.h>
28
Jiri Pirko77b99002015-05-12 14:56:21 +020029struct fl_flow_key {
30 int indev_ifindex;
Tom Herbert42aecaa2015-06-04 09:16:39 -070031 struct flow_dissector_key_control control;
Amir Vadaibc3103f2016-09-08 16:23:47 +030032 struct flow_dissector_key_control enc_control;
Jiri Pirko77b99002015-05-12 14:56:21 +020033 struct flow_dissector_key_basic basic;
34 struct flow_dissector_key_eth_addrs eth;
Hadar Hen Zion9399ae92016-08-17 13:36:13 +030035 struct flow_dissector_key_vlan vlan;
Jiri Pirko77b99002015-05-12 14:56:21 +020036 union {
Tom Herbertc3f83242015-06-04 09:16:40 -070037 struct flow_dissector_key_ipv4_addrs ipv4;
Jiri Pirko77b99002015-05-12 14:56:21 +020038 struct flow_dissector_key_ipv6_addrs ipv6;
39 };
40 struct flow_dissector_key_ports tp;
Amir Vadaibc3103f2016-09-08 16:23:47 +030041 struct flow_dissector_key_keyid enc_key_id;
42 union {
43 struct flow_dissector_key_ipv4_addrs enc_ipv4;
44 struct flow_dissector_key_ipv6_addrs enc_ipv6;
45 };
Jiri Pirko77b99002015-05-12 14:56:21 +020046} __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */
47
48struct fl_flow_mask_range {
49 unsigned short int start;
50 unsigned short int end;
51};
52
53struct fl_flow_mask {
54 struct fl_flow_key key;
55 struct fl_flow_mask_range range;
56 struct rcu_head rcu;
57};
58
59struct cls_fl_head {
60 struct rhashtable ht;
61 struct fl_flow_mask mask;
62 struct flow_dissector dissector;
63 u32 hgen;
64 bool mask_assigned;
65 struct list_head filters;
66 struct rhashtable_params ht_params;
67 struct rcu_head rcu;
68};
69
70struct cls_fl_filter {
71 struct rhash_head ht_node;
72 struct fl_flow_key mkey;
73 struct tcf_exts exts;
74 struct tcf_result res;
75 struct fl_flow_key key;
76 struct list_head list;
77 u32 handle;
Amir Vadaie69985c2016-06-05 17:11:18 +030078 u32 flags;
Jiri Pirko77b99002015-05-12 14:56:21 +020079 struct rcu_head rcu;
80};
81
82static unsigned short int fl_mask_range(const struct fl_flow_mask *mask)
83{
84 return mask->range.end - mask->range.start;
85}
86
87static void fl_mask_update_range(struct fl_flow_mask *mask)
88{
89 const u8 *bytes = (const u8 *) &mask->key;
90 size_t size = sizeof(mask->key);
91 size_t i, first = 0, last = size - 1;
92
93 for (i = 0; i < sizeof(mask->key); i++) {
94 if (bytes[i]) {
95 if (!first && i)
96 first = i;
97 last = i;
98 }
99 }
100 mask->range.start = rounddown(first, sizeof(long));
101 mask->range.end = roundup(last + 1, sizeof(long));
102}
103
104static void *fl_key_get_start(struct fl_flow_key *key,
105 const struct fl_flow_mask *mask)
106{
107 return (u8 *) key + mask->range.start;
108}
109
110static void fl_set_masked_key(struct fl_flow_key *mkey, struct fl_flow_key *key,
111 struct fl_flow_mask *mask)
112{
113 const long *lkey = fl_key_get_start(key, mask);
114 const long *lmask = fl_key_get_start(&mask->key, mask);
115 long *lmkey = fl_key_get_start(mkey, mask);
116 int i;
117
118 for (i = 0; i < fl_mask_range(mask); i += sizeof(long))
119 *lmkey++ = *lkey++ & *lmask++;
120}
121
122static void fl_clear_masked_range(struct fl_flow_key *key,
123 struct fl_flow_mask *mask)
124{
125 memset(fl_key_get_start(key, mask), 0, fl_mask_range(mask));
126}
127
128static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp,
129 struct tcf_result *res)
130{
131 struct cls_fl_head *head = rcu_dereference_bh(tp->root);
132 struct cls_fl_filter *f;
133 struct fl_flow_key skb_key;
134 struct fl_flow_key skb_mkey;
Amir Vadaibc3103f2016-09-08 16:23:47 +0300135 struct ip_tunnel_info *info;
Jiri Pirko77b99002015-05-12 14:56:21 +0200136
Amir Vadaie69985c2016-06-05 17:11:18 +0300137 if (!atomic_read(&head->ht.nelems))
138 return -1;
139
Jiri Pirko77b99002015-05-12 14:56:21 +0200140 fl_clear_masked_range(&skb_key, &head->mask);
Amir Vadaibc3103f2016-09-08 16:23:47 +0300141
142 info = skb_tunnel_info(skb);
143 if (info) {
144 struct ip_tunnel_key *key = &info->key;
145
146 switch (ip_tunnel_info_af(info)) {
147 case AF_INET:
148 skb_key.enc_ipv4.src = key->u.ipv4.src;
149 skb_key.enc_ipv4.dst = key->u.ipv4.dst;
150 break;
151 case AF_INET6:
152 skb_key.enc_ipv6.src = key->u.ipv6.src;
153 skb_key.enc_ipv6.dst = key->u.ipv6.dst;
154 break;
155 }
156
157 skb_key.enc_key_id.keyid = tunnel_id_to_key32(key->tun_id);
158 }
159
Jiri Pirko77b99002015-05-12 14:56:21 +0200160 skb_key.indev_ifindex = skb->skb_iif;
161 /* skb_flow_dissect() does not set n_proto in case an unknown protocol,
162 * so do it rather here.
163 */
164 skb_key.basic.n_proto = skb->protocol;
Tom Herbertcd79a232015-09-01 09:24:27 -0700165 skb_flow_dissect(skb, &head->dissector, &skb_key, 0);
Jiri Pirko77b99002015-05-12 14:56:21 +0200166
167 fl_set_masked_key(&skb_mkey, &skb_key, &head->mask);
168
169 f = rhashtable_lookup_fast(&head->ht,
170 fl_key_get_start(&skb_mkey, &head->mask),
171 head->ht_params);
Amir Vadaie8eb36c2016-06-13 12:06:39 +0300172 if (f && !tc_skip_sw(f->flags)) {
Jiri Pirko77b99002015-05-12 14:56:21 +0200173 *res = f->res;
174 return tcf_exts_exec(skb, &f->exts, res);
175 }
176 return -1;
177}
178
179static int fl_init(struct tcf_proto *tp)
180{
181 struct cls_fl_head *head;
182
183 head = kzalloc(sizeof(*head), GFP_KERNEL);
184 if (!head)
185 return -ENOBUFS;
186
187 INIT_LIST_HEAD_RCU(&head->filters);
188 rcu_assign_pointer(tp->root, head);
189
190 return 0;
191}
192
193static void fl_destroy_filter(struct rcu_head *head)
194{
195 struct cls_fl_filter *f = container_of(head, struct cls_fl_filter, rcu);
196
197 tcf_exts_destroy(&f->exts);
198 kfree(f);
199}
200
Amir Vadai8208d212016-03-11 11:08:45 +0200201static void fl_hw_destroy_filter(struct tcf_proto *tp, unsigned long cookie)
Amir Vadai5b33f482016-03-08 12:42:29 +0200202{
203 struct net_device *dev = tp->q->dev_queue->dev;
204 struct tc_cls_flower_offload offload = {0};
205 struct tc_to_netdev tc;
206
Daniel Borkmann92c075d2016-06-06 22:50:39 +0200207 if (!tc_should_offload(dev, tp, 0))
Amir Vadai5b33f482016-03-08 12:42:29 +0200208 return;
209
210 offload.command = TC_CLSFLOWER_DESTROY;
211 offload.cookie = cookie;
212
213 tc.type = TC_SETUP_CLSFLOWER;
214 tc.cls_flower = &offload;
215
216 dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol, &tc);
217}
218
Amir Vadaie8eb36c2016-06-13 12:06:39 +0300219static int fl_hw_replace_filter(struct tcf_proto *tp,
220 struct flow_dissector *dissector,
221 struct fl_flow_key *mask,
222 struct fl_flow_key *key,
223 struct tcf_exts *actions,
224 unsigned long cookie, u32 flags)
Amir Vadai5b33f482016-03-08 12:42:29 +0200225{
226 struct net_device *dev = tp->q->dev_queue->dev;
227 struct tc_cls_flower_offload offload = {0};
228 struct tc_to_netdev tc;
Amir Vadaie8eb36c2016-06-13 12:06:39 +0300229 int err;
Amir Vadai5b33f482016-03-08 12:42:29 +0200230
Daniel Borkmann92c075d2016-06-06 22:50:39 +0200231 if (!tc_should_offload(dev, tp, flags))
Amir Vadaie8eb36c2016-06-13 12:06:39 +0300232 return tc_skip_sw(flags) ? -EINVAL : 0;
Amir Vadai5b33f482016-03-08 12:42:29 +0200233
234 offload.command = TC_CLSFLOWER_REPLACE;
235 offload.cookie = cookie;
236 offload.dissector = dissector;
237 offload.mask = mask;
238 offload.key = key;
239 offload.exts = actions;
240
241 tc.type = TC_SETUP_CLSFLOWER;
242 tc.cls_flower = &offload;
243
Jamal Hadi Salim5a7a5552016-09-18 08:45:33 -0400244 err = dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol,
245 &tc);
Amir Vadaie8eb36c2016-06-13 12:06:39 +0300246
247 if (tc_skip_sw(flags))
248 return err;
249
250 return 0;
Amir Vadai5b33f482016-03-08 12:42:29 +0200251}
252
Amir Vadai10cbc682016-05-13 12:55:37 +0000253static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f)
254{
255 struct net_device *dev = tp->q->dev_queue->dev;
256 struct tc_cls_flower_offload offload = {0};
257 struct tc_to_netdev tc;
258
Daniel Borkmann92c075d2016-06-06 22:50:39 +0200259 if (!tc_should_offload(dev, tp, 0))
Amir Vadai10cbc682016-05-13 12:55:37 +0000260 return;
261
262 offload.command = TC_CLSFLOWER_STATS;
263 offload.cookie = (unsigned long)f;
264 offload.exts = &f->exts;
265
266 tc.type = TC_SETUP_CLSFLOWER;
267 tc.cls_flower = &offload;
268
269 dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol, &tc);
270}
271
Roi Dayan13fa8762016-11-01 16:08:29 +0200272static void __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f)
273{
274 list_del_rcu(&f->list);
275 fl_hw_destroy_filter(tp, (unsigned long)f);
276 tcf_unbind_filter(tp, &f->res);
277 call_rcu(&f->rcu, fl_destroy_filter);
278}
279
Jiri Pirko77b99002015-05-12 14:56:21 +0200280static bool fl_destroy(struct tcf_proto *tp, bool force)
281{
282 struct cls_fl_head *head = rtnl_dereference(tp->root);
283 struct cls_fl_filter *f, *next;
284
285 if (!force && !list_empty(&head->filters))
286 return false;
287
Roi Dayan13fa8762016-11-01 16:08:29 +0200288 list_for_each_entry_safe(f, next, &head->filters, list)
289 __fl_delete(tp, f);
Jiri Pirko77b99002015-05-12 14:56:21 +0200290 RCU_INIT_POINTER(tp->root, NULL);
291 if (head->mask_assigned)
292 rhashtable_destroy(&head->ht);
293 kfree_rcu(head, rcu);
294 return true;
295}
296
297static unsigned long fl_get(struct tcf_proto *tp, u32 handle)
298{
299 struct cls_fl_head *head = rtnl_dereference(tp->root);
300 struct cls_fl_filter *f;
301
302 list_for_each_entry(f, &head->filters, list)
303 if (f->handle == handle)
304 return (unsigned long) f;
305 return 0;
306}
307
308static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = {
309 [TCA_FLOWER_UNSPEC] = { .type = NLA_UNSPEC },
310 [TCA_FLOWER_CLASSID] = { .type = NLA_U32 },
311 [TCA_FLOWER_INDEV] = { .type = NLA_STRING,
312 .len = IFNAMSIZ },
313 [TCA_FLOWER_KEY_ETH_DST] = { .len = ETH_ALEN },
314 [TCA_FLOWER_KEY_ETH_DST_MASK] = { .len = ETH_ALEN },
315 [TCA_FLOWER_KEY_ETH_SRC] = { .len = ETH_ALEN },
316 [TCA_FLOWER_KEY_ETH_SRC_MASK] = { .len = ETH_ALEN },
317 [TCA_FLOWER_KEY_ETH_TYPE] = { .type = NLA_U16 },
318 [TCA_FLOWER_KEY_IP_PROTO] = { .type = NLA_U8 },
319 [TCA_FLOWER_KEY_IPV4_SRC] = { .type = NLA_U32 },
320 [TCA_FLOWER_KEY_IPV4_SRC_MASK] = { .type = NLA_U32 },
321 [TCA_FLOWER_KEY_IPV4_DST] = { .type = NLA_U32 },
322 [TCA_FLOWER_KEY_IPV4_DST_MASK] = { .type = NLA_U32 },
323 [TCA_FLOWER_KEY_IPV6_SRC] = { .len = sizeof(struct in6_addr) },
324 [TCA_FLOWER_KEY_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) },
325 [TCA_FLOWER_KEY_IPV6_DST] = { .len = sizeof(struct in6_addr) },
326 [TCA_FLOWER_KEY_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) },
327 [TCA_FLOWER_KEY_TCP_SRC] = { .type = NLA_U16 },
328 [TCA_FLOWER_KEY_TCP_DST] = { .type = NLA_U16 },
Jamal Hadi Salimb175c3a2015-06-25 06:55:27 -0400329 [TCA_FLOWER_KEY_UDP_SRC] = { .type = NLA_U16 },
330 [TCA_FLOWER_KEY_UDP_DST] = { .type = NLA_U16 },
Hadar Hen Zion9399ae92016-08-17 13:36:13 +0300331 [TCA_FLOWER_KEY_VLAN_ID] = { .type = NLA_U16 },
332 [TCA_FLOWER_KEY_VLAN_PRIO] = { .type = NLA_U8 },
333 [TCA_FLOWER_KEY_VLAN_ETH_TYPE] = { .type = NLA_U16 },
Amir Vadaibc3103f2016-09-08 16:23:47 +0300334 [TCA_FLOWER_KEY_ENC_KEY_ID] = { .type = NLA_U32 },
335 [TCA_FLOWER_KEY_ENC_IPV4_SRC] = { .type = NLA_U32 },
336 [TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] = { .type = NLA_U32 },
337 [TCA_FLOWER_KEY_ENC_IPV4_DST] = { .type = NLA_U32 },
338 [TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] = { .type = NLA_U32 },
339 [TCA_FLOWER_KEY_ENC_IPV6_SRC] = { .len = sizeof(struct in6_addr) },
340 [TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) },
341 [TCA_FLOWER_KEY_ENC_IPV6_DST] = { .len = sizeof(struct in6_addr) },
342 [TCA_FLOWER_KEY_ENC_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) },
Or Gerlitzaa72d702016-09-15 15:28:22 +0300343 [TCA_FLOWER_KEY_TCP_SRC_MASK] = { .type = NLA_U16 },
344 [TCA_FLOWER_KEY_TCP_DST_MASK] = { .type = NLA_U16 },
345 [TCA_FLOWER_KEY_UDP_SRC_MASK] = { .type = NLA_U16 },
346 [TCA_FLOWER_KEY_UDP_DST_MASK] = { .type = NLA_U16 },
Jiri Pirko77b99002015-05-12 14:56:21 +0200347};
348
349static void fl_set_key_val(struct nlattr **tb,
350 void *val, int val_type,
351 void *mask, int mask_type, int len)
352{
353 if (!tb[val_type])
354 return;
355 memcpy(val, nla_data(tb[val_type]), len);
356 if (mask_type == TCA_FLOWER_UNSPEC || !tb[mask_type])
357 memset(mask, 0xff, len);
358 else
359 memcpy(mask, nla_data(tb[mask_type]), len);
360}
361
Hadar Hen Zion9399ae92016-08-17 13:36:13 +0300362static void fl_set_key_vlan(struct nlattr **tb,
363 struct flow_dissector_key_vlan *key_val,
364 struct flow_dissector_key_vlan *key_mask)
365{
366#define VLAN_PRIORITY_MASK 0x7
367
368 if (tb[TCA_FLOWER_KEY_VLAN_ID]) {
369 key_val->vlan_id =
370 nla_get_u16(tb[TCA_FLOWER_KEY_VLAN_ID]) & VLAN_VID_MASK;
371 key_mask->vlan_id = VLAN_VID_MASK;
372 }
373 if (tb[TCA_FLOWER_KEY_VLAN_PRIO]) {
374 key_val->vlan_priority =
375 nla_get_u8(tb[TCA_FLOWER_KEY_VLAN_PRIO]) &
376 VLAN_PRIORITY_MASK;
377 key_mask->vlan_priority = VLAN_PRIORITY_MASK;
378 }
379}
380
Jiri Pirko77b99002015-05-12 14:56:21 +0200381static int fl_set_key(struct net *net, struct nlattr **tb,
382 struct fl_flow_key *key, struct fl_flow_key *mask)
383{
Hadar Hen Zion9399ae92016-08-17 13:36:13 +0300384 __be16 ethertype;
Brian Haleydd3aa3b2015-05-14 13:20:15 -0400385#ifdef CONFIG_NET_CLS_IND
Jiri Pirko77b99002015-05-12 14:56:21 +0200386 if (tb[TCA_FLOWER_INDEV]) {
Brian Haleydd3aa3b2015-05-14 13:20:15 -0400387 int err = tcf_change_indev(net, tb[TCA_FLOWER_INDEV]);
Jiri Pirko77b99002015-05-12 14:56:21 +0200388 if (err < 0)
389 return err;
390 key->indev_ifindex = err;
391 mask->indev_ifindex = 0xffffffff;
392 }
Brian Haleydd3aa3b2015-05-14 13:20:15 -0400393#endif
Jiri Pirko77b99002015-05-12 14:56:21 +0200394
395 fl_set_key_val(tb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST,
396 mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK,
397 sizeof(key->eth.dst));
398 fl_set_key_val(tb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC,
399 mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK,
400 sizeof(key->eth.src));
Jamal Hadi Salim66530bd2016-01-10 11:47:01 -0500401
Arnd Bergmann0b498a52016-08-26 17:25:45 +0200402 if (tb[TCA_FLOWER_KEY_ETH_TYPE]) {
Hadar Hen Zion9399ae92016-08-17 13:36:13 +0300403 ethertype = nla_get_be16(tb[TCA_FLOWER_KEY_ETH_TYPE]);
404
Arnd Bergmann0b498a52016-08-26 17:25:45 +0200405 if (ethertype == htons(ETH_P_8021Q)) {
406 fl_set_key_vlan(tb, &key->vlan, &mask->vlan);
407 fl_set_key_val(tb, &key->basic.n_proto,
408 TCA_FLOWER_KEY_VLAN_ETH_TYPE,
409 &mask->basic.n_proto, TCA_FLOWER_UNSPEC,
410 sizeof(key->basic.n_proto));
411 } else {
412 key->basic.n_proto = ethertype;
413 mask->basic.n_proto = cpu_to_be16(~0);
414 }
Hadar Hen Zion9399ae92016-08-17 13:36:13 +0300415 }
Jamal Hadi Salim66530bd2016-01-10 11:47:01 -0500416
Jiri Pirko77b99002015-05-12 14:56:21 +0200417 if (key->basic.n_proto == htons(ETH_P_IP) ||
418 key->basic.n_proto == htons(ETH_P_IPV6)) {
419 fl_set_key_val(tb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO,
420 &mask->basic.ip_proto, TCA_FLOWER_UNSPEC,
421 sizeof(key->basic.ip_proto));
422 }
Jamal Hadi Salim66530bd2016-01-10 11:47:01 -0500423
424 if (tb[TCA_FLOWER_KEY_IPV4_SRC] || tb[TCA_FLOWER_KEY_IPV4_DST]) {
425 key->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
Jiri Pirko77b99002015-05-12 14:56:21 +0200426 fl_set_key_val(tb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC,
427 &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK,
428 sizeof(key->ipv4.src));
429 fl_set_key_val(tb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST,
430 &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK,
431 sizeof(key->ipv4.dst));
Jamal Hadi Salim66530bd2016-01-10 11:47:01 -0500432 } else if (tb[TCA_FLOWER_KEY_IPV6_SRC] || tb[TCA_FLOWER_KEY_IPV6_DST]) {
433 key->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
Jiri Pirko77b99002015-05-12 14:56:21 +0200434 fl_set_key_val(tb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC,
435 &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK,
436 sizeof(key->ipv6.src));
437 fl_set_key_val(tb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST,
438 &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK,
439 sizeof(key->ipv6.dst));
440 }
Jamal Hadi Salim66530bd2016-01-10 11:47:01 -0500441
Jiri Pirko77b99002015-05-12 14:56:21 +0200442 if (key->basic.ip_proto == IPPROTO_TCP) {
443 fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC,
Or Gerlitzaa72d702016-09-15 15:28:22 +0300444 &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK,
Jiri Pirko77b99002015-05-12 14:56:21 +0200445 sizeof(key->tp.src));
446 fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST,
Or Gerlitzaa72d702016-09-15 15:28:22 +0300447 &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK,
Jiri Pirko77b99002015-05-12 14:56:21 +0200448 sizeof(key->tp.dst));
449 } else if (key->basic.ip_proto == IPPROTO_UDP) {
450 fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC,
Or Gerlitzaa72d702016-09-15 15:28:22 +0300451 &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK,
Jiri Pirko77b99002015-05-12 14:56:21 +0200452 sizeof(key->tp.src));
453 fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST,
Or Gerlitzaa72d702016-09-15 15:28:22 +0300454 &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK,
Jiri Pirko77b99002015-05-12 14:56:21 +0200455 sizeof(key->tp.dst));
456 }
457
Amir Vadaibc3103f2016-09-08 16:23:47 +0300458 if (tb[TCA_FLOWER_KEY_ENC_IPV4_SRC] ||
459 tb[TCA_FLOWER_KEY_ENC_IPV4_DST]) {
460 key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
461 fl_set_key_val(tb, &key->enc_ipv4.src,
462 TCA_FLOWER_KEY_ENC_IPV4_SRC,
463 &mask->enc_ipv4.src,
464 TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
465 sizeof(key->enc_ipv4.src));
466 fl_set_key_val(tb, &key->enc_ipv4.dst,
467 TCA_FLOWER_KEY_ENC_IPV4_DST,
468 &mask->enc_ipv4.dst,
469 TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
470 sizeof(key->enc_ipv4.dst));
471 }
472
473 if (tb[TCA_FLOWER_KEY_ENC_IPV6_SRC] ||
474 tb[TCA_FLOWER_KEY_ENC_IPV6_DST]) {
475 key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
476 fl_set_key_val(tb, &key->enc_ipv6.src,
477 TCA_FLOWER_KEY_ENC_IPV6_SRC,
478 &mask->enc_ipv6.src,
479 TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
480 sizeof(key->enc_ipv6.src));
481 fl_set_key_val(tb, &key->enc_ipv6.dst,
482 TCA_FLOWER_KEY_ENC_IPV6_DST,
483 &mask->enc_ipv6.dst,
484 TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
485 sizeof(key->enc_ipv6.dst));
486 }
487
488 fl_set_key_val(tb, &key->enc_key_id.keyid, TCA_FLOWER_KEY_ENC_KEY_ID,
Hadar Hen Zioneb523f42016-09-27 11:21:18 +0300489 &mask->enc_key_id.keyid, TCA_FLOWER_UNSPEC,
Amir Vadaibc3103f2016-09-08 16:23:47 +0300490 sizeof(key->enc_key_id.keyid));
491
Jiri Pirko77b99002015-05-12 14:56:21 +0200492 return 0;
493}
494
495static bool fl_mask_eq(struct fl_flow_mask *mask1,
496 struct fl_flow_mask *mask2)
497{
498 const long *lmask1 = fl_key_get_start(&mask1->key, mask1);
499 const long *lmask2 = fl_key_get_start(&mask2->key, mask2);
500
501 return !memcmp(&mask1->range, &mask2->range, sizeof(mask1->range)) &&
502 !memcmp(lmask1, lmask2, fl_mask_range(mask1));
503}
504
505static const struct rhashtable_params fl_ht_params = {
506 .key_offset = offsetof(struct cls_fl_filter, mkey), /* base offset */
507 .head_offset = offsetof(struct cls_fl_filter, ht_node),
508 .automatic_shrinking = true,
509};
510
511static int fl_init_hashtable(struct cls_fl_head *head,
512 struct fl_flow_mask *mask)
513{
514 head->ht_params = fl_ht_params;
515 head->ht_params.key_len = fl_mask_range(mask);
516 head->ht_params.key_offset += mask->range.start;
517
518 return rhashtable_init(&head->ht, &head->ht_params);
519}
520
521#define FL_KEY_MEMBER_OFFSET(member) offsetof(struct fl_flow_key, member)
522#define FL_KEY_MEMBER_SIZE(member) (sizeof(((struct fl_flow_key *) 0)->member))
Jiri Pirko77b99002015-05-12 14:56:21 +0200523
Hadar Hen Zion339ba872016-08-17 13:36:12 +0300524#define FL_KEY_IS_MASKED(mask, member) \
525 memchr_inv(((char *)mask) + FL_KEY_MEMBER_OFFSET(member), \
526 0, FL_KEY_MEMBER_SIZE(member)) \
Jiri Pirko77b99002015-05-12 14:56:21 +0200527
528#define FL_KEY_SET(keys, cnt, id, member) \
529 do { \
530 keys[cnt].key_id = id; \
531 keys[cnt].offset = FL_KEY_MEMBER_OFFSET(member); \
532 cnt++; \
533 } while(0);
534
Hadar Hen Zion339ba872016-08-17 13:36:12 +0300535#define FL_KEY_SET_IF_MASKED(mask, keys, cnt, id, member) \
Jiri Pirko77b99002015-05-12 14:56:21 +0200536 do { \
Hadar Hen Zion339ba872016-08-17 13:36:12 +0300537 if (FL_KEY_IS_MASKED(mask, member)) \
Jiri Pirko77b99002015-05-12 14:56:21 +0200538 FL_KEY_SET(keys, cnt, id, member); \
539 } while(0);
540
541static void fl_init_dissector(struct cls_fl_head *head,
542 struct fl_flow_mask *mask)
543{
544 struct flow_dissector_key keys[FLOW_DISSECTOR_KEY_MAX];
545 size_t cnt = 0;
546
Tom Herbert42aecaa2015-06-04 09:16:39 -0700547 FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_CONTROL, control);
Jiri Pirko77b99002015-05-12 14:56:21 +0200548 FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_BASIC, basic);
Hadar Hen Zion339ba872016-08-17 13:36:12 +0300549 FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
550 FLOW_DISSECTOR_KEY_ETH_ADDRS, eth);
551 FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
552 FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4);
553 FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
554 FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6);
555 FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
556 FLOW_DISSECTOR_KEY_PORTS, tp);
Hadar Hen Zion9399ae92016-08-17 13:36:13 +0300557 FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
558 FLOW_DISSECTOR_KEY_VLAN, vlan);
Jiri Pirko77b99002015-05-12 14:56:21 +0200559
560 skb_flow_dissector_init(&head->dissector, keys, cnt);
561}
562
563static int fl_check_assign_mask(struct cls_fl_head *head,
564 struct fl_flow_mask *mask)
565{
566 int err;
567
568 if (head->mask_assigned) {
569 if (!fl_mask_eq(&head->mask, mask))
570 return -EINVAL;
571 else
572 return 0;
573 }
574
575 /* Mask is not assigned yet. So assign it and init hashtable
576 * according to that.
577 */
578 err = fl_init_hashtable(head, mask);
579 if (err)
580 return err;
581 memcpy(&head->mask, mask, sizeof(head->mask));
582 head->mask_assigned = true;
583
584 fl_init_dissector(head, mask);
585
586 return 0;
587}
588
589static int fl_set_parms(struct net *net, struct tcf_proto *tp,
590 struct cls_fl_filter *f, struct fl_flow_mask *mask,
591 unsigned long base, struct nlattr **tb,
592 struct nlattr *est, bool ovr)
593{
594 struct tcf_exts e;
595 int err;
596
WANG Congb9a24bb2016-08-19 12:36:54 -0700597 err = tcf_exts_init(&e, TCA_FLOWER_ACT, 0);
Jiri Pirko77b99002015-05-12 14:56:21 +0200598 if (err < 0)
599 return err;
WANG Congb9a24bb2016-08-19 12:36:54 -0700600 err = tcf_exts_validate(net, tp, tb, est, &e, ovr);
601 if (err < 0)
602 goto errout;
Jiri Pirko77b99002015-05-12 14:56:21 +0200603
604 if (tb[TCA_FLOWER_CLASSID]) {
605 f->res.classid = nla_get_u32(tb[TCA_FLOWER_CLASSID]);
606 tcf_bind_filter(tp, &f->res, base);
607 }
608
609 err = fl_set_key(net, tb, &f->key, &mask->key);
610 if (err)
611 goto errout;
612
613 fl_mask_update_range(mask);
614 fl_set_masked_key(&f->mkey, &f->key, mask);
615
616 tcf_exts_change(tp, &f->exts, &e);
617
618 return 0;
619errout:
620 tcf_exts_destroy(&e);
621 return err;
622}
623
624static u32 fl_grab_new_handle(struct tcf_proto *tp,
625 struct cls_fl_head *head)
626{
627 unsigned int i = 0x80000000;
628 u32 handle;
629
630 do {
631 if (++head->hgen == 0x7FFFFFFF)
632 head->hgen = 1;
633 } while (--i > 0 && fl_get(tp, head->hgen));
634
635 if (unlikely(i == 0)) {
636 pr_err("Insufficient number of handles\n");
637 handle = 0;
638 } else {
639 handle = head->hgen;
640 }
641
642 return handle;
643}
644
645static int fl_change(struct net *net, struct sk_buff *in_skb,
646 struct tcf_proto *tp, unsigned long base,
647 u32 handle, struct nlattr **tca,
648 unsigned long *arg, bool ovr)
649{
650 struct cls_fl_head *head = rtnl_dereference(tp->root);
651 struct cls_fl_filter *fold = (struct cls_fl_filter *) *arg;
652 struct cls_fl_filter *fnew;
653 struct nlattr *tb[TCA_FLOWER_MAX + 1];
654 struct fl_flow_mask mask = {};
655 int err;
656
657 if (!tca[TCA_OPTIONS])
658 return -EINVAL;
659
660 err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS], fl_policy);
661 if (err < 0)
662 return err;
663
664 if (fold && handle && fold->handle != handle)
665 return -EINVAL;
666
667 fnew = kzalloc(sizeof(*fnew), GFP_KERNEL);
668 if (!fnew)
669 return -ENOBUFS;
670
WANG Congb9a24bb2016-08-19 12:36:54 -0700671 err = tcf_exts_init(&fnew->exts, TCA_FLOWER_ACT, 0);
672 if (err < 0)
673 goto errout;
Jiri Pirko77b99002015-05-12 14:56:21 +0200674
675 if (!handle) {
676 handle = fl_grab_new_handle(tp, head);
677 if (!handle) {
678 err = -EINVAL;
679 goto errout;
680 }
681 }
682 fnew->handle = handle;
683
Amir Vadaie69985c2016-06-05 17:11:18 +0300684 if (tb[TCA_FLOWER_FLAGS]) {
685 fnew->flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]);
686
687 if (!tc_flags_valid(fnew->flags)) {
688 err = -EINVAL;
689 goto errout;
690 }
691 }
Amir Vadai5b33f482016-03-08 12:42:29 +0200692
Jiri Pirko77b99002015-05-12 14:56:21 +0200693 err = fl_set_parms(net, tp, fnew, &mask, base, tb, tca[TCA_RATE], ovr);
694 if (err)
695 goto errout;
696
697 err = fl_check_assign_mask(head, &mask);
698 if (err)
699 goto errout;
700
Amir Vadaie8eb36c2016-06-13 12:06:39 +0300701 if (!tc_skip_sw(fnew->flags)) {
Amir Vadaie69985c2016-06-05 17:11:18 +0300702 err = rhashtable_insert_fast(&head->ht, &fnew->ht_node,
703 head->ht_params);
704 if (err)
705 goto errout;
706 }
Amir Vadai5b33f482016-03-08 12:42:29 +0200707
Amir Vadaie8eb36c2016-06-13 12:06:39 +0300708 err = fl_hw_replace_filter(tp,
709 &head->dissector,
710 &mask.key,
711 &fnew->key,
712 &fnew->exts,
713 (unsigned long)fnew,
714 fnew->flags);
715 if (err)
716 goto errout;
Amir Vadai5b33f482016-03-08 12:42:29 +0200717
718 if (fold) {
Jiri Pirko77b99002015-05-12 14:56:21 +0200719 rhashtable_remove_fast(&head->ht, &fold->ht_node,
720 head->ht_params);
Amir Vadai8208d212016-03-11 11:08:45 +0200721 fl_hw_destroy_filter(tp, (unsigned long)fold);
Amir Vadai5b33f482016-03-08 12:42:29 +0200722 }
Jiri Pirko77b99002015-05-12 14:56:21 +0200723
724 *arg = (unsigned long) fnew;
725
726 if (fold) {
Daniel Borkmannff3532f2015-07-17 22:38:44 +0200727 list_replace_rcu(&fold->list, &fnew->list);
Jiri Pirko77b99002015-05-12 14:56:21 +0200728 tcf_unbind_filter(tp, &fold->res);
729 call_rcu(&fold->rcu, fl_destroy_filter);
730 } else {
731 list_add_tail_rcu(&fnew->list, &head->filters);
732 }
733
734 return 0;
735
736errout:
WANG Congb9a24bb2016-08-19 12:36:54 -0700737 tcf_exts_destroy(&fnew->exts);
Jiri Pirko77b99002015-05-12 14:56:21 +0200738 kfree(fnew);
739 return err;
740}
741
742static int fl_delete(struct tcf_proto *tp, unsigned long arg)
743{
744 struct cls_fl_head *head = rtnl_dereference(tp->root);
745 struct cls_fl_filter *f = (struct cls_fl_filter *) arg;
746
747 rhashtable_remove_fast(&head->ht, &f->ht_node,
748 head->ht_params);
Roi Dayan13fa8762016-11-01 16:08:29 +0200749 __fl_delete(tp, f);
Jiri Pirko77b99002015-05-12 14:56:21 +0200750 return 0;
751}
752
753static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg)
754{
755 struct cls_fl_head *head = rtnl_dereference(tp->root);
756 struct cls_fl_filter *f;
757
758 list_for_each_entry_rcu(f, &head->filters, list) {
759 if (arg->count < arg->skip)
760 goto skip;
761 if (arg->fn(tp, (unsigned long) f, arg) < 0) {
762 arg->stop = 1;
763 break;
764 }
765skip:
766 arg->count++;
767 }
768}
769
770static int fl_dump_key_val(struct sk_buff *skb,
771 void *val, int val_type,
772 void *mask, int mask_type, int len)
773{
774 int err;
775
776 if (!memchr_inv(mask, 0, len))
777 return 0;
778 err = nla_put(skb, val_type, len, val);
779 if (err)
780 return err;
781 if (mask_type != TCA_FLOWER_UNSPEC) {
782 err = nla_put(skb, mask_type, len, mask);
783 if (err)
784 return err;
785 }
786 return 0;
787}
788
Hadar Hen Zion9399ae92016-08-17 13:36:13 +0300789static int fl_dump_key_vlan(struct sk_buff *skb,
790 struct flow_dissector_key_vlan *vlan_key,
791 struct flow_dissector_key_vlan *vlan_mask)
792{
793 int err;
794
795 if (!memchr_inv(vlan_mask, 0, sizeof(*vlan_mask)))
796 return 0;
797 if (vlan_mask->vlan_id) {
798 err = nla_put_u16(skb, TCA_FLOWER_KEY_VLAN_ID,
799 vlan_key->vlan_id);
800 if (err)
801 return err;
802 }
803 if (vlan_mask->vlan_priority) {
804 err = nla_put_u8(skb, TCA_FLOWER_KEY_VLAN_PRIO,
805 vlan_key->vlan_priority);
806 if (err)
807 return err;
808 }
809 return 0;
810}
811
Jiri Pirko77b99002015-05-12 14:56:21 +0200812static int fl_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
813 struct sk_buff *skb, struct tcmsg *t)
814{
815 struct cls_fl_head *head = rtnl_dereference(tp->root);
816 struct cls_fl_filter *f = (struct cls_fl_filter *) fh;
817 struct nlattr *nest;
818 struct fl_flow_key *key, *mask;
819
820 if (!f)
821 return skb->len;
822
823 t->tcm_handle = f->handle;
824
825 nest = nla_nest_start(skb, TCA_OPTIONS);
826 if (!nest)
827 goto nla_put_failure;
828
829 if (f->res.classid &&
830 nla_put_u32(skb, TCA_FLOWER_CLASSID, f->res.classid))
831 goto nla_put_failure;
832
833 key = &f->key;
834 mask = &head->mask.key;
835
836 if (mask->indev_ifindex) {
837 struct net_device *dev;
838
839 dev = __dev_get_by_index(net, key->indev_ifindex);
840 if (dev && nla_put_string(skb, TCA_FLOWER_INDEV, dev->name))
841 goto nla_put_failure;
842 }
843
Amir Vadai10cbc682016-05-13 12:55:37 +0000844 fl_hw_update_stats(tp, f);
845
Jiri Pirko77b99002015-05-12 14:56:21 +0200846 if (fl_dump_key_val(skb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST,
847 mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK,
848 sizeof(key->eth.dst)) ||
849 fl_dump_key_val(skb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC,
850 mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK,
851 sizeof(key->eth.src)) ||
852 fl_dump_key_val(skb, &key->basic.n_proto, TCA_FLOWER_KEY_ETH_TYPE,
853 &mask->basic.n_proto, TCA_FLOWER_UNSPEC,
854 sizeof(key->basic.n_proto)))
855 goto nla_put_failure;
Hadar Hen Zion9399ae92016-08-17 13:36:13 +0300856
857 if (fl_dump_key_vlan(skb, &key->vlan, &mask->vlan))
858 goto nla_put_failure;
859
Jiri Pirko77b99002015-05-12 14:56:21 +0200860 if ((key->basic.n_proto == htons(ETH_P_IP) ||
861 key->basic.n_proto == htons(ETH_P_IPV6)) &&
862 fl_dump_key_val(skb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO,
863 &mask->basic.ip_proto, TCA_FLOWER_UNSPEC,
864 sizeof(key->basic.ip_proto)))
865 goto nla_put_failure;
866
Tom Herbertc3f83242015-06-04 09:16:40 -0700867 if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS &&
Jiri Pirko77b99002015-05-12 14:56:21 +0200868 (fl_dump_key_val(skb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC,
869 &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK,
870 sizeof(key->ipv4.src)) ||
871 fl_dump_key_val(skb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST,
872 &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK,
873 sizeof(key->ipv4.dst))))
874 goto nla_put_failure;
Tom Herbertc3f83242015-06-04 09:16:40 -0700875 else if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS &&
Jiri Pirko77b99002015-05-12 14:56:21 +0200876 (fl_dump_key_val(skb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC,
877 &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK,
878 sizeof(key->ipv6.src)) ||
879 fl_dump_key_val(skb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST,
880 &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK,
881 sizeof(key->ipv6.dst))))
882 goto nla_put_failure;
883
884 if (key->basic.ip_proto == IPPROTO_TCP &&
885 (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC,
Or Gerlitzaa72d702016-09-15 15:28:22 +0300886 &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK,
Jiri Pirko77b99002015-05-12 14:56:21 +0200887 sizeof(key->tp.src)) ||
888 fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST,
Or Gerlitzaa72d702016-09-15 15:28:22 +0300889 &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK,
Jiri Pirko77b99002015-05-12 14:56:21 +0200890 sizeof(key->tp.dst))))
891 goto nla_put_failure;
892 else if (key->basic.ip_proto == IPPROTO_UDP &&
893 (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC,
Or Gerlitzaa72d702016-09-15 15:28:22 +0300894 &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK,
Jiri Pirko77b99002015-05-12 14:56:21 +0200895 sizeof(key->tp.src)) ||
896 fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST,
Or Gerlitzaa72d702016-09-15 15:28:22 +0300897 &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK,
Jiri Pirko77b99002015-05-12 14:56:21 +0200898 sizeof(key->tp.dst))))
899 goto nla_put_failure;
900
Amir Vadaibc3103f2016-09-08 16:23:47 +0300901 if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS &&
902 (fl_dump_key_val(skb, &key->enc_ipv4.src,
903 TCA_FLOWER_KEY_ENC_IPV4_SRC, &mask->enc_ipv4.src,
904 TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
905 sizeof(key->enc_ipv4.src)) ||
906 fl_dump_key_val(skb, &key->enc_ipv4.dst,
907 TCA_FLOWER_KEY_ENC_IPV4_DST, &mask->enc_ipv4.dst,
908 TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
909 sizeof(key->enc_ipv4.dst))))
910 goto nla_put_failure;
911 else if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS &&
912 (fl_dump_key_val(skb, &key->enc_ipv6.src,
913 TCA_FLOWER_KEY_ENC_IPV6_SRC, &mask->enc_ipv6.src,
914 TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
915 sizeof(key->enc_ipv6.src)) ||
916 fl_dump_key_val(skb, &key->enc_ipv6.dst,
917 TCA_FLOWER_KEY_ENC_IPV6_DST,
918 &mask->enc_ipv6.dst,
919 TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
920 sizeof(key->enc_ipv6.dst))))
921 goto nla_put_failure;
922
923 if (fl_dump_key_val(skb, &key->enc_key_id, TCA_FLOWER_KEY_ENC_KEY_ID,
Hadar Hen Zioneb523f42016-09-27 11:21:18 +0300924 &mask->enc_key_id, TCA_FLOWER_UNSPEC,
Amir Vadaibc3103f2016-09-08 16:23:47 +0300925 sizeof(key->enc_key_id)))
926 goto nla_put_failure;
927
Amir Vadaie69985c2016-06-05 17:11:18 +0300928 nla_put_u32(skb, TCA_FLOWER_FLAGS, f->flags);
929
Jiri Pirko77b99002015-05-12 14:56:21 +0200930 if (tcf_exts_dump(skb, &f->exts))
931 goto nla_put_failure;
932
933 nla_nest_end(skb, nest);
934
935 if (tcf_exts_dump_stats(skb, &f->exts) < 0)
936 goto nla_put_failure;
937
938 return skb->len;
939
940nla_put_failure:
941 nla_nest_cancel(skb, nest);
942 return -1;
943}
944
945static struct tcf_proto_ops cls_fl_ops __read_mostly = {
946 .kind = "flower",
947 .classify = fl_classify,
948 .init = fl_init,
949 .destroy = fl_destroy,
950 .get = fl_get,
951 .change = fl_change,
952 .delete = fl_delete,
953 .walk = fl_walk,
954 .dump = fl_dump,
955 .owner = THIS_MODULE,
956};
957
958static int __init cls_fl_init(void)
959{
960 return register_tcf_proto_ops(&cls_fl_ops);
961}
962
963static void __exit cls_fl_exit(void)
964{
965 unregister_tcf_proto_ops(&cls_fl_ops);
966}
967
968module_init(cls_fl_init);
969module_exit(cls_fl_exit);
970
971MODULE_AUTHOR("Jiri Pirko <jiri@resnulli.us>");
972MODULE_DESCRIPTION("Flower classifier");
973MODULE_LICENSE("GPL v2");