Blame view
net/sched/cls_flower.c
57.2 KB
77b9900ef tc: introduce Flo... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/* * net/sched/cls_flower.c Flower classifier * * Copyright (c) 2015 Jiri Pirko <jiri@resnulli.us> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include <linux/kernel.h> #include <linux/init.h> #include <linux/module.h> #include <linux/rhashtable.h> |
d93637741 net, sched: respe... |
16 |
#include <linux/workqueue.h> |
77b9900ef tc: introduce Flo... |
17 18 19 20 |
#include <linux/if_ether.h> #include <linux/in6.h> #include <linux/ip.h> |
a577d8f79 cls_flower: add s... |
21 |
#include <linux/mpls.h> |
77b9900ef tc: introduce Flo... |
22 23 24 25 26 |
#include <net/sch_generic.h> #include <net/pkt_cls.h> #include <net/ip.h> #include <net/flow_dissector.h> |
0a6e77784 net/sched: allow ... |
27 |
#include <net/geneve.h> |
77b9900ef tc: introduce Flo... |
28 |
|
bc3103f1e net/sched: cls_fl... |
29 30 |
#include <net/dst.h> #include <net/dst_metadata.h> |
77b9900ef tc: introduce Flo... |
31 32 |
struct fl_flow_key { int indev_ifindex; |
42aecaa9b net: Get skb hash... |
33 |
struct flow_dissector_key_control control; |
bc3103f1e net/sched: cls_fl... |
34 |
struct flow_dissector_key_control enc_control; |
77b9900ef tc: introduce Flo... |
35 36 |
struct flow_dissector_key_basic basic; struct flow_dissector_key_eth_addrs eth; |
9399ae9a6 net_sched: flower... |
37 |
struct flow_dissector_key_vlan vlan; |
d64efd092 net/sched: flower... |
38 |
struct flow_dissector_key_vlan cvlan; |
77b9900ef tc: introduce Flo... |
39 |
union { |
c3f832418 net: Add full IPv... |
40 |
struct flow_dissector_key_ipv4_addrs ipv4; |
77b9900ef tc: introduce Flo... |
41 42 43 |
struct flow_dissector_key_ipv6_addrs ipv6; }; struct flow_dissector_key_ports tp; |
7b684884f net/sched: cls_fl... |
44 |
struct flow_dissector_key_icmp icmp; |
99d31326c net/sched: cls_fl... |
45 |
struct flow_dissector_key_arp arp; |
bc3103f1e net/sched: cls_fl... |
46 47 48 49 50 |
struct flow_dissector_key_keyid enc_key_id; union { struct flow_dissector_key_ipv4_addrs enc_ipv4; struct flow_dissector_key_ipv6_addrs enc_ipv6; }; |
f4d997fd6 net/sched: cls_fl... |
51 |
struct flow_dissector_key_ports enc_tp; |
a577d8f79 cls_flower: add s... |
52 |
struct flow_dissector_key_mpls mpls; |
fdfc7dd6c net/sched: flower... |
53 |
struct flow_dissector_key_tcp tcp; |
4d80cc0aa net/sched: cls_fl... |
54 |
struct flow_dissector_key_ip ip; |
0e2c17b64 net/sched: cls_fl... |
55 |
struct flow_dissector_key_ip enc_ip; |
0a6e77784 net/sched: allow ... |
56 |
struct flow_dissector_key_enc_opts enc_opts; |
77b9900ef tc: introduce Flo... |
57 58 59 60 61 62 63 64 65 66 |
} __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */ struct fl_flow_mask_range { unsigned short int start; unsigned short int end; }; struct fl_flow_mask { struct fl_flow_key key; struct fl_flow_mask_range range; |
05cd271fd cls_flower: Suppo... |
67 68 69 70 71 |
struct rhash_head ht_node; struct rhashtable ht; struct rhashtable_params filter_ht_params; struct flow_dissector dissector; struct list_head filters; |
44a5cd436 cls_flower: fix u... |
72 |
struct rcu_work rwork; |
05cd271fd cls_flower: Suppo... |
73 |
struct list_head list; |
77b9900ef tc: introduce Flo... |
74 |
}; |
b95ec7eb3 net: sched: cls_f... |
75 76 77 78 79 80 |
struct fl_flow_tmplt { struct fl_flow_key dummy_key; struct fl_flow_key mask; struct flow_dissector dissector; struct tcf_chain *chain; }; |
77b9900ef tc: introduce Flo... |
81 82 |
struct cls_fl_head { struct rhashtable ht; |
05cd271fd cls_flower: Suppo... |
83 |
struct list_head masks; |
aaa908ffb net_sched: switch... |
84 |
struct rcu_work rwork; |
c15ab236d net/sched: Change... |
85 |
struct idr handle_idr; |
77b9900ef tc: introduce Flo... |
86 87 88 |
}; struct cls_fl_filter { |
05cd271fd cls_flower: Suppo... |
89 |
struct fl_flow_mask *mask; |
77b9900ef tc: introduce Flo... |
90 91 92 93 94 95 96 |
struct rhash_head ht_node; struct fl_flow_key mkey; struct tcf_exts exts; struct tcf_result res; struct fl_flow_key key; struct list_head list; u32 handle; |
e69985c67 net/sched: cls_fl... |
97 |
u32 flags; |
31533cba4 net: sched: cls_f... |
98 |
unsigned int in_hw_count; |
aaa908ffb net_sched: switch... |
99 |
struct rcu_work rwork; |
7091d8c70 net/sched: cls_fl... |
100 |
struct net_device *hw_dev; |
77b9900ef tc: introduce Flo... |
101 |
}; |
05cd271fd cls_flower: Suppo... |
102 103 104 105 106 107 |
static const struct rhashtable_params mask_ht_params = { .key_offset = offsetof(struct fl_flow_mask, key), .key_len = sizeof(struct fl_flow_key), .head_offset = offsetof(struct fl_flow_mask, ht_node), .automatic_shrinking = true, }; |
77b9900ef tc: introduce Flo... |
108 109 110 111 112 113 114 115 116 |
static unsigned short int fl_mask_range(const struct fl_flow_mask *mask) { return mask->range.end - mask->range.start; } static void fl_mask_update_range(struct fl_flow_mask *mask) { const u8 *bytes = (const u8 *) &mask->key; size_t size = sizeof(mask->key); |
05cd271fd cls_flower: Suppo... |
117 |
size_t i, first = 0, last; |
77b9900ef tc: introduce Flo... |
118 |
|
05cd271fd cls_flower: Suppo... |
119 120 121 122 123 124 125 126 |
for (i = 0; i < size; i++) { if (bytes[i]) { first = i; break; } } last = first; for (i = size - 1; i != first; i--) { |
77b9900ef tc: introduce Flo... |
127 |
if (bytes[i]) { |
77b9900ef tc: introduce Flo... |
128 |
last = i; |
05cd271fd cls_flower: Suppo... |
129 |
break; |
77b9900ef tc: introduce Flo... |
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
} } mask->range.start = rounddown(first, sizeof(long)); mask->range.end = roundup(last + 1, sizeof(long)); } static void *fl_key_get_start(struct fl_flow_key *key, const struct fl_flow_mask *mask) { return (u8 *) key + mask->range.start; } static void fl_set_masked_key(struct fl_flow_key *mkey, struct fl_flow_key *key, struct fl_flow_mask *mask) { const long *lkey = fl_key_get_start(key, mask); const long *lmask = fl_key_get_start(&mask->key, mask); long *lmkey = fl_key_get_start(mkey, mask); int i; for (i = 0; i < fl_mask_range(mask); i += sizeof(long)) *lmkey++ = *lkey++ & *lmask++; } |
b95ec7eb3 net: sched: cls_f... |
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
static bool fl_mask_fits_tmplt(struct fl_flow_tmplt *tmplt, struct fl_flow_mask *mask) { const long *lmask = fl_key_get_start(&mask->key, mask); const long *ltmplt; int i; if (!tmplt) return true; ltmplt = fl_key_get_start(&tmplt->mask, mask); for (i = 0; i < fl_mask_range(mask); i += sizeof(long)) { if (~*ltmplt++ & *lmask++) return false; } return true; } |
77b9900ef tc: introduce Flo... |
169 170 171 172 173 |
static void fl_clear_masked_range(struct fl_flow_key *key, struct fl_flow_mask *mask) { memset(fl_key_get_start(key, mask), 0, fl_mask_range(mask)); } |
05cd271fd cls_flower: Suppo... |
174 |
static struct cls_fl_filter *fl_lookup(struct fl_flow_mask *mask, |
a3308d8fd net/sched: cls_fl... |
175 176 |
struct fl_flow_key *mkey) { |
05cd271fd cls_flower: Suppo... |
177 178 |
return rhashtable_lookup_fast(&mask->ht, fl_key_get_start(mkey, mask), mask->filter_ht_params); |
a3308d8fd net/sched: cls_fl... |
179 |
} |
77b9900ef tc: introduce Flo... |
180 181 182 183 184 |
static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp, struct tcf_result *res) { struct cls_fl_head *head = rcu_dereference_bh(tp->root); struct cls_fl_filter *f; |
05cd271fd cls_flower: Suppo... |
185 |
struct fl_flow_mask *mask; |
77b9900ef tc: introduce Flo... |
186 187 |
struct fl_flow_key skb_key; struct fl_flow_key skb_mkey; |
05cd271fd cls_flower: Suppo... |
188 189 |
list_for_each_entry_rcu(mask, &head->masks, list) { fl_clear_masked_range(&skb_key, mask); |
bc3103f1e net/sched: cls_fl... |
190 |
|
05cd271fd cls_flower: Suppo... |
191 192 193 194 195 196 197 |
skb_key.indev_ifindex = skb->skb_iif; /* skb_flow_dissect() does not set n_proto in case an unknown * protocol, so do it rather here. */ skb_key.basic.n_proto = skb->protocol; skb_flow_dissect_tunnel_info(skb, &mask->dissector, &skb_key); skb_flow_dissect(skb, &mask->dissector, &skb_key, 0); |
77b9900ef tc: introduce Flo... |
198 |
|
05cd271fd cls_flower: Suppo... |
199 |
fl_set_masked_key(&skb_mkey, &skb_key, mask); |
77b9900ef tc: introduce Flo... |
200 |
|
05cd271fd cls_flower: Suppo... |
201 202 203 204 205 |
f = fl_lookup(mask, &skb_mkey); if (f && !tc_skip_sw(f->flags)) { *res = f->res; return tcf_exts_exec(skb, &f->exts, res); } |
77b9900ef tc: introduce Flo... |
206 207 208 209 210 211 212 213 214 215 216 |
} return -1; } static int fl_init(struct tcf_proto *tp) { struct cls_fl_head *head; head = kzalloc(sizeof(*head), GFP_KERNEL); if (!head) return -ENOBUFS; |
05cd271fd cls_flower: Suppo... |
217 |
INIT_LIST_HEAD_RCU(&head->masks); |
77b9900ef tc: introduce Flo... |
218 |
rcu_assign_pointer(tp->root, head); |
c15ab236d net/sched: Change... |
219 |
idr_init(&head->handle_idr); |
77b9900ef tc: introduce Flo... |
220 |
|
05cd271fd cls_flower: Suppo... |
221 222 |
return rhashtable_init(&head->ht, &mask_ht_params); } |
44a5cd436 cls_flower: fix u... |
223 224 225 226 227 228 229 230 231 232 233 234 235 |
static void fl_mask_free(struct fl_flow_mask *mask) { rhashtable_destroy(&mask->ht); kfree(mask); } static void fl_mask_free_work(struct work_struct *work) { struct fl_flow_mask *mask = container_of(to_rcu_work(work), struct fl_flow_mask, rwork); fl_mask_free(mask); } |
05cd271fd cls_flower: Suppo... |
236 237 238 239 240 241 242 |
static bool fl_mask_put(struct cls_fl_head *head, struct fl_flow_mask *mask, bool async) { if (!list_empty(&mask->filters)) return false; rhashtable_remove_fast(&head->ht, &mask->ht_node, mask_ht_params); |
05cd271fd cls_flower: Suppo... |
243 244 |
list_del_rcu(&mask->list); if (async) |
44a5cd436 cls_flower: fix u... |
245 |
tcf_queue_work(&mask->rwork, fl_mask_free_work); |
05cd271fd cls_flower: Suppo... |
246 |
else |
44a5cd436 cls_flower: fix u... |
247 |
fl_mask_free(mask); |
05cd271fd cls_flower: Suppo... |
248 249 |
return true; |
77b9900ef tc: introduce Flo... |
250 |
} |
0dadc117a cls_flower: use t... |
251 252 253 254 255 256 |
static void __fl_destroy_filter(struct cls_fl_filter *f) { tcf_exts_destroy(&f->exts); tcf_exts_put_net(&f->exts); kfree(f); } |
0552c8afa net_sched: use tc... |
257 |
static void fl_destroy_filter_work(struct work_struct *work) |
77b9900ef tc: introduce Flo... |
258 |
{ |
aaa908ffb net_sched: switch... |
259 260 |
struct cls_fl_filter *f = container_of(to_rcu_work(work), struct cls_fl_filter, rwork); |
77b9900ef tc: introduce Flo... |
261 |
|
0552c8afa net_sched: use tc... |
262 |
rtnl_lock(); |
0dadc117a cls_flower: use t... |
263 |
__fl_destroy_filter(f); |
0552c8afa net_sched: use tc... |
264 265 |
rtnl_unlock(); } |
1b0f80375 cls_flower: propa... |
266 267 |
static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f, struct netlink_ext_ack *extack) |
5b33f4884 net/flower: Intro... |
268 |
{ |
de4784ca0 net: sched: get r... |
269 |
struct tc_cls_flower_offload cls_flower = {}; |
208c0f4b5 net: sched: use t... |
270 |
struct tcf_block *block = tp->chain->block; |
5b33f4884 net/flower: Intro... |
271 |
|
1b0f80375 cls_flower: propa... |
272 |
tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack); |
de4784ca0 net: sched: get r... |
273 274 |
cls_flower.command = TC_CLSFLOWER_DESTROY; cls_flower.cookie = (unsigned long) f; |
5b33f4884 net/flower: Intro... |
275 |
|
208c0f4b5 net: sched: use t... |
276 |
tc_setup_cb_call(block, &f->exts, TC_SETUP_CLSFLOWER, |
717503b9c net: sched: conve... |
277 |
&cls_flower, false); |
caa726015 net: sched: keep ... |
278 |
tcf_block_offload_dec(block, &f->flags); |
5b33f4884 net/flower: Intro... |
279 |
} |
e8eb36cd8 net/sched: flower... |
280 |
static int fl_hw_replace_filter(struct tcf_proto *tp, |
41002038f net: sched: cls_f... |
281 282 |
struct cls_fl_filter *f, struct netlink_ext_ack *extack) |
5b33f4884 net/flower: Intro... |
283 |
{ |
de4784ca0 net: sched: get r... |
284 |
struct tc_cls_flower_offload cls_flower = {}; |
208c0f4b5 net: sched: use t... |
285 |
struct tcf_block *block = tp->chain->block; |
717503b9c net: sched: conve... |
286 |
bool skip_sw = tc_skip_sw(f->flags); |
e8eb36cd8 net/sched: flower... |
287 |
int err; |
5b33f4884 net/flower: Intro... |
288 |
|
ea2059409 cls_flower: pass ... |
289 |
tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack); |
de4784ca0 net: sched: get r... |
290 291 |
cls_flower.command = TC_CLSFLOWER_REPLACE; cls_flower.cookie = (unsigned long) f; |
05cd271fd cls_flower: Suppo... |
292 293 |
cls_flower.dissector = &f->mask->dissector; cls_flower.mask = &f->mask->key; |
de4784ca0 net: sched: get r... |
294 295 |
cls_flower.key = &f->mkey; cls_flower.exts = &f->exts; |
384c181e3 net: sched: Ident... |
296 |
cls_flower.classid = f->res.classid; |
5b33f4884 net/flower: Intro... |
297 |
|
208c0f4b5 net: sched: use t... |
298 |
err = tc_setup_cb_call(block, &f->exts, TC_SETUP_CLSFLOWER, |
717503b9c net: sched: conve... |
299 300 |
&cls_flower, skip_sw); if (err < 0) { |
1b0f80375 cls_flower: propa... |
301 |
fl_hw_destroy_filter(tp, f, NULL); |
e8eb36cd8 net/sched: flower... |
302 |
return err; |
717503b9c net: sched: conve... |
303 |
} else if (err > 0) { |
31533cba4 net: sched: cls_f... |
304 |
f->in_hw_count = err; |
caa726015 net: sched: keep ... |
305 |
tcf_block_offload_inc(block, &f->flags); |
717503b9c net: sched: conve... |
306 307 308 309 |
} if (skip_sw && !(f->flags & TCA_CLS_FLAGS_IN_HW)) return -EINVAL; |
e8eb36cd8 net/sched: flower... |
310 |
return 0; |
5b33f4884 net/flower: Intro... |
311 |
} |
10cbc6843 net/sched: cls_fl... |
312 313 |
static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f) { |
de4784ca0 net: sched: get r... |
314 |
struct tc_cls_flower_offload cls_flower = {}; |
208c0f4b5 net: sched: use t... |
315 |
struct tcf_block *block = tp->chain->block; |
10cbc6843 net/sched: cls_fl... |
316 |
|
ea2059409 cls_flower: pass ... |
317 |
tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, NULL); |
de4784ca0 net: sched: get r... |
318 319 320 |
cls_flower.command = TC_CLSFLOWER_STATS; cls_flower.cookie = (unsigned long) f; cls_flower.exts = &f->exts; |
384c181e3 net: sched: Ident... |
321 |
cls_flower.classid = f->res.classid; |
10cbc6843 net/sched: cls_fl... |
322 |
|
208c0f4b5 net: sched: use t... |
323 |
tc_setup_cb_call(block, &f->exts, TC_SETUP_CLSFLOWER, |
717503b9c net: sched: conve... |
324 |
&cls_flower, false); |
10cbc6843 net/sched: cls_fl... |
325 |
} |
05cd271fd cls_flower: Suppo... |
326 |
static bool __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, |
1b0f80375 cls_flower: propa... |
327 |
struct netlink_ext_ack *extack) |
13fa876eb net/sched: cls_fl... |
328 |
{ |
c15ab236d net/sched: Change... |
329 |
struct cls_fl_head *head = rtnl_dereference(tp->root); |
05cd271fd cls_flower: Suppo... |
330 331 |
bool async = tcf_exts_get_net(&f->exts); bool last; |
c15ab236d net/sched: Change... |
332 |
|
9c1609414 idr: Delete idr_r... |
333 |
idr_remove(&head->handle_idr, f->handle); |
13fa876eb net/sched: cls_fl... |
334 |
list_del_rcu(&f->list); |
05cd271fd cls_flower: Suppo... |
335 |
last = fl_mask_put(head, f->mask, async); |
796852197 net/sched: cls_fl... |
336 |
if (!tc_skip_hw(f->flags)) |
1b0f80375 cls_flower: propa... |
337 |
fl_hw_destroy_filter(tp, f, extack); |
13fa876eb net/sched: cls_fl... |
338 |
tcf_unbind_filter(tp, &f->res); |
05cd271fd cls_flower: Suppo... |
339 |
if (async) |
aaa908ffb net_sched: switch... |
340 |
tcf_queue_work(&f->rwork, fl_destroy_filter_work); |
0dadc117a cls_flower: use t... |
341 342 |
else __fl_destroy_filter(f); |
05cd271fd cls_flower: Suppo... |
343 344 |
return last; |
13fa876eb net/sched: cls_fl... |
345 |
} |
d93637741 net, sched: respe... |
346 347 |
static void fl_destroy_sleepable(struct work_struct *work) { |
aaa908ffb net_sched: switch... |
348 349 350 |
struct cls_fl_head *head = container_of(to_rcu_work(work), struct cls_fl_head, rwork); |
de9dc650f cls_flower: Fix m... |
351 352 |
rhashtable_destroy(&head->ht); |
d93637741 net, sched: respe... |
353 354 355 |
kfree(head); module_put(THIS_MODULE); } |
715df5eca net: sched: propa... |
356 |
static void fl_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack) |
77b9900ef tc: introduce Flo... |
357 358 |
{ struct cls_fl_head *head = rtnl_dereference(tp->root); |
05cd271fd cls_flower: Suppo... |
359 |
struct fl_flow_mask *mask, *next_mask; |
77b9900ef tc: introduce Flo... |
360 |
struct cls_fl_filter *f, *next; |
05cd271fd cls_flower: Suppo... |
361 362 363 364 365 366 |
list_for_each_entry_safe(mask, next_mask, &head->masks, list) { list_for_each_entry_safe(f, next, &mask->filters, list) { if (__fl_delete(tp, f, extack)) break; } } |
c15ab236d net/sched: Change... |
367 |
idr_destroy(&head->handle_idr); |
d93637741 net, sched: respe... |
368 369 |
__module_get(THIS_MODULE); |
aaa908ffb net_sched: switch... |
370 |
tcf_queue_work(&head->rwork, fl_destroy_sleepable); |
77b9900ef tc: introduce Flo... |
371 |
} |
8113c0956 net_sched: use vo... |
372 |
static void *fl_get(struct tcf_proto *tp, u32 handle) |
77b9900ef tc: introduce Flo... |
373 374 |
{ struct cls_fl_head *head = rtnl_dereference(tp->root); |
77b9900ef tc: introduce Flo... |
375 |
|
322d884ba idr: Delete idr_f... |
376 |
return idr_find(&head->handle_idr, handle); |
77b9900ef tc: introduce Flo... |
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 |
} static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = { [TCA_FLOWER_UNSPEC] = { .type = NLA_UNSPEC }, [TCA_FLOWER_CLASSID] = { .type = NLA_U32 }, [TCA_FLOWER_INDEV] = { .type = NLA_STRING, .len = IFNAMSIZ }, [TCA_FLOWER_KEY_ETH_DST] = { .len = ETH_ALEN }, [TCA_FLOWER_KEY_ETH_DST_MASK] = { .len = ETH_ALEN }, [TCA_FLOWER_KEY_ETH_SRC] = { .len = ETH_ALEN }, [TCA_FLOWER_KEY_ETH_SRC_MASK] = { .len = ETH_ALEN }, [TCA_FLOWER_KEY_ETH_TYPE] = { .type = NLA_U16 }, [TCA_FLOWER_KEY_IP_PROTO] = { .type = NLA_U8 }, [TCA_FLOWER_KEY_IPV4_SRC] = { .type = NLA_U32 }, [TCA_FLOWER_KEY_IPV4_SRC_MASK] = { .type = NLA_U32 }, [TCA_FLOWER_KEY_IPV4_DST] = { .type = NLA_U32 }, [TCA_FLOWER_KEY_IPV4_DST_MASK] = { .type = NLA_U32 }, [TCA_FLOWER_KEY_IPV6_SRC] = { .len = sizeof(struct in6_addr) }, [TCA_FLOWER_KEY_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) }, [TCA_FLOWER_KEY_IPV6_DST] = { .len = sizeof(struct in6_addr) }, [TCA_FLOWER_KEY_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) }, [TCA_FLOWER_KEY_TCP_SRC] = { .type = NLA_U16 }, [TCA_FLOWER_KEY_TCP_DST] = { .type = NLA_U16 }, |
b175c3a44 net: sched: flowe... |
400 401 |
[TCA_FLOWER_KEY_UDP_SRC] = { .type = NLA_U16 }, [TCA_FLOWER_KEY_UDP_DST] = { .type = NLA_U16 }, |
9399ae9a6 net_sched: flower... |
402 403 404 |
[TCA_FLOWER_KEY_VLAN_ID] = { .type = NLA_U16 }, [TCA_FLOWER_KEY_VLAN_PRIO] = { .type = NLA_U8 }, [TCA_FLOWER_KEY_VLAN_ETH_TYPE] = { .type = NLA_U16 }, |
bc3103f1e net/sched: cls_fl... |
405 406 407 408 409 410 411 412 413 |
[TCA_FLOWER_KEY_ENC_KEY_ID] = { .type = NLA_U32 }, [TCA_FLOWER_KEY_ENC_IPV4_SRC] = { .type = NLA_U32 }, [TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] = { .type = NLA_U32 }, [TCA_FLOWER_KEY_ENC_IPV4_DST] = { .type = NLA_U32 }, [TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] = { .type = NLA_U32 }, [TCA_FLOWER_KEY_ENC_IPV6_SRC] = { .len = sizeof(struct in6_addr) }, [TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) }, [TCA_FLOWER_KEY_ENC_IPV6_DST] = { .len = sizeof(struct in6_addr) }, [TCA_FLOWER_KEY_ENC_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) }, |
aa72d7083 net/sched: cls_fl... |
414 415 416 417 |
[TCA_FLOWER_KEY_TCP_SRC_MASK] = { .type = NLA_U16 }, [TCA_FLOWER_KEY_TCP_DST_MASK] = { .type = NLA_U16 }, [TCA_FLOWER_KEY_UDP_SRC_MASK] = { .type = NLA_U16 }, [TCA_FLOWER_KEY_UDP_DST_MASK] = { .type = NLA_U16 }, |
5976c5f45 net/sched: cls_fl... |
418 419 420 421 |
[TCA_FLOWER_KEY_SCTP_SRC_MASK] = { .type = NLA_U16 }, [TCA_FLOWER_KEY_SCTP_DST_MASK] = { .type = NLA_U16 }, [TCA_FLOWER_KEY_SCTP_SRC] = { .type = NLA_U16 }, [TCA_FLOWER_KEY_SCTP_DST] = { .type = NLA_U16 }, |
f4d997fd6 net/sched: cls_fl... |
422 423 424 425 |
[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT] = { .type = NLA_U16 }, [TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK] = { .type = NLA_U16 }, [TCA_FLOWER_KEY_ENC_UDP_DST_PORT] = { .type = NLA_U16 }, [TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK] = { .type = NLA_U16 }, |
faa3ffce7 net/sched: cls_fl... |
426 427 |
[TCA_FLOWER_KEY_FLAGS] = { .type = NLA_U32 }, [TCA_FLOWER_KEY_FLAGS_MASK] = { .type = NLA_U32 }, |
7b684884f net/sched: cls_fl... |
428 429 430 431 432 433 434 435 |
[TCA_FLOWER_KEY_ICMPV4_TYPE] = { .type = NLA_U8 }, [TCA_FLOWER_KEY_ICMPV4_TYPE_MASK] = { .type = NLA_U8 }, [TCA_FLOWER_KEY_ICMPV4_CODE] = { .type = NLA_U8 }, [TCA_FLOWER_KEY_ICMPV4_CODE_MASK] = { .type = NLA_U8 }, [TCA_FLOWER_KEY_ICMPV6_TYPE] = { .type = NLA_U8 }, [TCA_FLOWER_KEY_ICMPV6_TYPE_MASK] = { .type = NLA_U8 }, [TCA_FLOWER_KEY_ICMPV6_CODE] = { .type = NLA_U8 }, [TCA_FLOWER_KEY_ICMPV6_CODE_MASK] = { .type = NLA_U8 }, |
99d31326c net/sched: cls_fl... |
436 437 438 439 440 441 442 443 444 445 |
[TCA_FLOWER_KEY_ARP_SIP] = { .type = NLA_U32 }, [TCA_FLOWER_KEY_ARP_SIP_MASK] = { .type = NLA_U32 }, [TCA_FLOWER_KEY_ARP_TIP] = { .type = NLA_U32 }, [TCA_FLOWER_KEY_ARP_TIP_MASK] = { .type = NLA_U32 }, [TCA_FLOWER_KEY_ARP_OP] = { .type = NLA_U8 }, [TCA_FLOWER_KEY_ARP_OP_MASK] = { .type = NLA_U8 }, [TCA_FLOWER_KEY_ARP_SHA] = { .len = ETH_ALEN }, [TCA_FLOWER_KEY_ARP_SHA_MASK] = { .len = ETH_ALEN }, [TCA_FLOWER_KEY_ARP_THA] = { .len = ETH_ALEN }, [TCA_FLOWER_KEY_ARP_THA_MASK] = { .len = ETH_ALEN }, |
a577d8f79 cls_flower: add s... |
446 447 448 449 |
[TCA_FLOWER_KEY_MPLS_TTL] = { .type = NLA_U8 }, [TCA_FLOWER_KEY_MPLS_BOS] = { .type = NLA_U8 }, [TCA_FLOWER_KEY_MPLS_TC] = { .type = NLA_U8 }, [TCA_FLOWER_KEY_MPLS_LABEL] = { .type = NLA_U32 }, |
fdfc7dd6c net/sched: flower... |
450 451 |
[TCA_FLOWER_KEY_TCP_FLAGS] = { .type = NLA_U16 }, [TCA_FLOWER_KEY_TCP_FLAGS_MASK] = { .type = NLA_U16 }, |
4d80cc0aa net/sched: cls_fl... |
452 453 454 455 |
[TCA_FLOWER_KEY_IP_TOS] = { .type = NLA_U8 }, [TCA_FLOWER_KEY_IP_TOS_MASK] = { .type = NLA_U8 }, [TCA_FLOWER_KEY_IP_TTL] = { .type = NLA_U8 }, [TCA_FLOWER_KEY_IP_TTL_MASK] = { .type = NLA_U8 }, |
d64efd092 net/sched: flower... |
456 457 458 |
[TCA_FLOWER_KEY_CVLAN_ID] = { .type = NLA_U16 }, [TCA_FLOWER_KEY_CVLAN_PRIO] = { .type = NLA_U8 }, [TCA_FLOWER_KEY_CVLAN_ETH_TYPE] = { .type = NLA_U16 }, |
0e2c17b64 net/sched: cls_fl... |
459 460 461 462 |
[TCA_FLOWER_KEY_ENC_IP_TOS] = { .type = NLA_U8 }, [TCA_FLOWER_KEY_ENC_IP_TOS_MASK] = { .type = NLA_U8 }, [TCA_FLOWER_KEY_ENC_IP_TTL] = { .type = NLA_U8 }, [TCA_FLOWER_KEY_ENC_IP_TTL_MASK] = { .type = NLA_U8 }, |
0a6e77784 net/sched: allow ... |
463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 |
[TCA_FLOWER_KEY_ENC_OPTS] = { .type = NLA_NESTED }, [TCA_FLOWER_KEY_ENC_OPTS_MASK] = { .type = NLA_NESTED }, }; static const struct nla_policy enc_opts_policy[TCA_FLOWER_KEY_ENC_OPTS_MAX + 1] = { [TCA_FLOWER_KEY_ENC_OPTS_GENEVE] = { .type = NLA_NESTED }, }; static const struct nla_policy geneve_opt_policy[TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX + 1] = { [TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS] = { .type = NLA_U16 }, [TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE] = { .type = NLA_U8 }, [TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA] = { .type = NLA_BINARY, .len = 128 }, |
77b9900ef tc: introduce Flo... |
478 479 480 481 482 483 484 485 486 487 488 489 490 491 |
}; static void fl_set_key_val(struct nlattr **tb, void *val, int val_type, void *mask, int mask_type, int len) { if (!tb[val_type]) return; memcpy(val, nla_data(tb[val_type]), len); if (mask_type == TCA_FLOWER_UNSPEC || !tb[mask_type]) memset(mask, 0xff, len); else memcpy(mask, nla_data(tb[mask_type]), len); } |
1a7fca63c flower: check unu... |
492 493 494 |
static int fl_set_key_mpls(struct nlattr **tb, struct flow_dissector_key_mpls *key_val, struct flow_dissector_key_mpls *key_mask) |
a577d8f79 cls_flower: add s... |
495 496 497 498 499 500 |
{ if (tb[TCA_FLOWER_KEY_MPLS_TTL]) { key_val->mpls_ttl = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TTL]); key_mask->mpls_ttl = MPLS_TTL_MASK; } if (tb[TCA_FLOWER_KEY_MPLS_BOS]) { |
1a7fca63c flower: check unu... |
501 502 503 504 505 |
u8 bos = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_BOS]); if (bos & ~MPLS_BOS_MASK) return -EINVAL; key_val->mpls_bos = bos; |
a577d8f79 cls_flower: add s... |
506 507 508 |
key_mask->mpls_bos = MPLS_BOS_MASK; } if (tb[TCA_FLOWER_KEY_MPLS_TC]) { |
1a7fca63c flower: check unu... |
509 510 511 512 513 |
u8 tc = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TC]); if (tc & ~MPLS_TC_MASK) return -EINVAL; key_val->mpls_tc = tc; |
a577d8f79 cls_flower: add s... |
514 515 516 |
key_mask->mpls_tc = MPLS_TC_MASK; } if (tb[TCA_FLOWER_KEY_MPLS_LABEL]) { |
1a7fca63c flower: check unu... |
517 518 519 520 521 |
u32 label = nla_get_u32(tb[TCA_FLOWER_KEY_MPLS_LABEL]); if (label & ~MPLS_LABEL_MASK) return -EINVAL; key_val->mpls_label = label; |
a577d8f79 cls_flower: add s... |
522 523 |
key_mask->mpls_label = MPLS_LABEL_MASK; } |
1a7fca63c flower: check unu... |
524 |
return 0; |
a577d8f79 cls_flower: add s... |
525 |
} |
9399ae9a6 net_sched: flower... |
526 |
static void fl_set_key_vlan(struct nlattr **tb, |
aaab08344 net/sched: flower... |
527 |
__be16 ethertype, |
d64efd092 net/sched: flower... |
528 |
int vlan_id_key, int vlan_prio_key, |
9399ae9a6 net_sched: flower... |
529 530 531 532 |
struct flow_dissector_key_vlan *key_val, struct flow_dissector_key_vlan *key_mask) { #define VLAN_PRIORITY_MASK 0x7 |
d64efd092 net/sched: flower... |
533 |
if (tb[vlan_id_key]) { |
9399ae9a6 net_sched: flower... |
534 |
key_val->vlan_id = |
d64efd092 net/sched: flower... |
535 |
nla_get_u16(tb[vlan_id_key]) & VLAN_VID_MASK; |
9399ae9a6 net_sched: flower... |
536 537 |
key_mask->vlan_id = VLAN_VID_MASK; } |
d64efd092 net/sched: flower... |
538 |
if (tb[vlan_prio_key]) { |
9399ae9a6 net_sched: flower... |
539 |
key_val->vlan_priority = |
d64efd092 net/sched: flower... |
540 |
nla_get_u8(tb[vlan_prio_key]) & |
9399ae9a6 net_sched: flower... |
541 542 543 |
VLAN_PRIORITY_MASK; key_mask->vlan_priority = VLAN_PRIORITY_MASK; } |
aaab08344 net/sched: flower... |
544 545 |
key_val->vlan_tpid = ethertype; key_mask->vlan_tpid = cpu_to_be16(~0); |
9399ae9a6 net_sched: flower... |
546 |
} |
faa3ffce7 net/sched: cls_fl... |
547 548 549 550 551 552 553 554 555 556 |
static void fl_set_key_flag(u32 flower_key, u32 flower_mask, u32 *dissector_key, u32 *dissector_mask, u32 flower_flag_bit, u32 dissector_flag_bit) { if (flower_mask & flower_flag_bit) { *dissector_mask |= dissector_flag_bit; if (flower_key & flower_flag_bit) *dissector_key |= dissector_flag_bit; } } |
d9724772e net/sched: cls_fl... |
557 558 |
static int fl_set_key_flags(struct nlattr **tb, u32 *flags_key, u32 *flags_mask) |
faa3ffce7 net/sched: cls_fl... |
559 560 |
{ u32 key, mask; |
d9724772e net/sched: cls_fl... |
561 562 563 |
/* mask is mandatory for flags */ if (!tb[TCA_FLOWER_KEY_FLAGS_MASK]) return -EINVAL; |
faa3ffce7 net/sched: cls_fl... |
564 565 |
key = be32_to_cpu(nla_get_u32(tb[TCA_FLOWER_KEY_FLAGS])); |
d9724772e net/sched: cls_fl... |
566 |
mask = be32_to_cpu(nla_get_u32(tb[TCA_FLOWER_KEY_FLAGS_MASK])); |
faa3ffce7 net/sched: cls_fl... |
567 568 569 570 571 572 |
*flags_key = 0; *flags_mask = 0; fl_set_key_flag(key, mask, flags_key, flags_mask, TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT); |
459d153d9 net/sched: cls_fl... |
573 574 575 |
fl_set_key_flag(key, mask, flags_key, flags_mask, TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST, FLOW_DIS_FIRST_FRAG); |
d9724772e net/sched: cls_fl... |
576 577 |
return 0; |
faa3ffce7 net/sched: cls_fl... |
578 |
} |
0e2c17b64 net/sched: cls_fl... |
579 |
static void fl_set_key_ip(struct nlattr **tb, bool encap, |
4d80cc0aa net/sched: cls_fl... |
580 581 582 |
struct flow_dissector_key_ip *key, struct flow_dissector_key_ip *mask) { |
0e2c17b64 net/sched: cls_fl... |
583 584 585 586 |
int tos_key = encap ? TCA_FLOWER_KEY_ENC_IP_TOS : TCA_FLOWER_KEY_IP_TOS; int ttl_key = encap ? TCA_FLOWER_KEY_ENC_IP_TTL : TCA_FLOWER_KEY_IP_TTL; int tos_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TOS_MASK : TCA_FLOWER_KEY_IP_TOS_MASK; int ttl_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TTL_MASK : TCA_FLOWER_KEY_IP_TTL_MASK; |
4d80cc0aa net/sched: cls_fl... |
587 |
|
0e2c17b64 net/sched: cls_fl... |
588 589 |
fl_set_key_val(tb, &key->tos, tos_key, &mask->tos, tos_mask, sizeof(key->tos)); fl_set_key_val(tb, &key->ttl, ttl_key, &mask->ttl, ttl_mask, sizeof(key->ttl)); |
4d80cc0aa net/sched: cls_fl... |
590 |
} |
0a6e77784 net/sched: allow ... |
591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 |
static int fl_set_geneve_opt(const struct nlattr *nla, struct fl_flow_key *key, int depth, int option_len, struct netlink_ext_ack *extack) { struct nlattr *tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX + 1]; struct nlattr *class = NULL, *type = NULL, *data = NULL; struct geneve_opt *opt; int err, data_len = 0; if (option_len > sizeof(struct geneve_opt)) data_len = option_len - sizeof(struct geneve_opt); opt = (struct geneve_opt *)&key->enc_opts.data[key->enc_opts.len]; memset(opt, 0xff, option_len); opt->length = data_len / 4; opt->r1 = 0; opt->r2 = 0; opt->r3 = 0; /* If no mask has been prodived we assume an exact match. */ if (!depth) return sizeof(struct geneve_opt) + data_len; if (nla_type(nla) != TCA_FLOWER_KEY_ENC_OPTS_GENEVE) { NL_SET_ERR_MSG(extack, "Non-geneve option type for mask"); return -EINVAL; } err = nla_parse_nested(tb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX, nla, geneve_opt_policy, extack); if (err < 0) return err; /* We are not allowed to omit any of CLASS, TYPE or DATA * fields from the key. */ if (!option_len && (!tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS] || !tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE] || !tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA])) { NL_SET_ERR_MSG(extack, "Missing tunnel key geneve option class, type or data"); return -EINVAL; } /* Omitting any of CLASS, TYPE or DATA fields is allowed * for the mask. */ if (tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA]) { int new_len = key->enc_opts.len; data = tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA]; data_len = nla_len(data); if (data_len < 4) { NL_SET_ERR_MSG(extack, "Tunnel key geneve option data is less than 4 bytes long"); return -ERANGE; } if (data_len % 4) { NL_SET_ERR_MSG(extack, "Tunnel key geneve option data is not a multiple of 4 bytes long"); return -ERANGE; } new_len += sizeof(struct geneve_opt) + data_len; BUILD_BUG_ON(FLOW_DIS_TUN_OPTS_MAX != IP_TUNNEL_OPTS_MAX); if (new_len > FLOW_DIS_TUN_OPTS_MAX) { NL_SET_ERR_MSG(extack, "Tunnel options exceeds max size"); return -ERANGE; } opt->length = data_len / 4; memcpy(opt->opt_data, nla_data(data), data_len); } if (tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS]) { class = tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS]; opt->opt_class = nla_get_be16(class); } if (tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE]) { type = tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE]; opt->type = nla_get_u8(type); } return sizeof(struct geneve_opt) + data_len; } static int fl_set_enc_opt(struct nlattr **tb, struct fl_flow_key *key, struct fl_flow_key *mask, struct netlink_ext_ack *extack) { const struct nlattr *nla_enc_key, *nla_opt_key, *nla_opt_msk = NULL; |
ed25a2066 net: sched: cls_f... |
680 681 682 683 684 685 686 |
int err, option_len, key_depth, msk_depth = 0; err = nla_validate_nested(tb[TCA_FLOWER_KEY_ENC_OPTS], TCA_FLOWER_KEY_ENC_OPTS_MAX, enc_opts_policy, extack); if (err) return err; |
0a6e77784 net/sched: allow ... |
687 688 689 690 |
nla_enc_key = nla_data(tb[TCA_FLOWER_KEY_ENC_OPTS]); if (tb[TCA_FLOWER_KEY_ENC_OPTS_MASK]) { |
ed25a2066 net: sched: cls_f... |
691 692 693 694 695 |
err = nla_validate_nested(tb[TCA_FLOWER_KEY_ENC_OPTS_MASK], TCA_FLOWER_KEY_ENC_OPTS_MAX, enc_opts_policy, extack); if (err) return err; |
0a6e77784 net/sched: allow ... |
696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 |
nla_opt_msk = nla_data(tb[TCA_FLOWER_KEY_ENC_OPTS_MASK]); msk_depth = nla_len(tb[TCA_FLOWER_KEY_ENC_OPTS_MASK]); } nla_for_each_attr(nla_opt_key, nla_enc_key, nla_len(tb[TCA_FLOWER_KEY_ENC_OPTS]), key_depth) { switch (nla_type(nla_opt_key)) { case TCA_FLOWER_KEY_ENC_OPTS_GENEVE: option_len = 0; key->enc_opts.dst_opt_type = TUNNEL_GENEVE_OPT; option_len = fl_set_geneve_opt(nla_opt_key, key, key_depth, option_len, extack); if (option_len < 0) return option_len; key->enc_opts.len += option_len; /* At the same time we need to parse through the mask * in order to verify exact and mask attribute lengths. */ mask->enc_opts.dst_opt_type = TUNNEL_GENEVE_OPT; option_len = fl_set_geneve_opt(nla_opt_msk, mask, msk_depth, option_len, extack); if (option_len < 0) return option_len; mask->enc_opts.len += option_len; if (key->enc_opts.len != mask->enc_opts.len) { NL_SET_ERR_MSG(extack, "Key and mask miss aligned"); return -EINVAL; } if (msk_depth) nla_opt_msk = nla_next(nla_opt_msk, &msk_depth); break; default: NL_SET_ERR_MSG(extack, "Unknown tunnel option type"); return -EINVAL; } } return 0; } |
77b9900ef tc: introduce Flo... |
740 |
static int fl_set_key(struct net *net, struct nlattr **tb, |
1057c55f6 net: sched: cls: ... |
741 742 |
struct fl_flow_key *key, struct fl_flow_key *mask, struct netlink_ext_ack *extack) |
77b9900ef tc: introduce Flo... |
743 |
{ |
9399ae9a6 net_sched: flower... |
744 |
__be16 ethertype; |
d9724772e net/sched: cls_fl... |
745 |
int ret = 0; |
dd3aa3b5f cls_flower: Fix c... |
746 |
#ifdef CONFIG_NET_CLS_IND |
77b9900ef tc: introduce Flo... |
747 |
if (tb[TCA_FLOWER_INDEV]) { |
1057c55f6 net: sched: cls: ... |
748 |
int err = tcf_change_indev(net, tb[TCA_FLOWER_INDEV], extack); |
77b9900ef tc: introduce Flo... |
749 750 751 752 753 |
if (err < 0) return err; key->indev_ifindex = err; mask->indev_ifindex = 0xffffffff; } |
dd3aa3b5f cls_flower: Fix c... |
754 |
#endif |
77b9900ef tc: introduce Flo... |
755 756 757 758 759 760 761 |
fl_set_key_val(tb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST, mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK, sizeof(key->eth.dst)); fl_set_key_val(tb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC, mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK, sizeof(key->eth.src)); |
66530bdf8 sched,cls_flower:... |
762 |
|
0b498a527 net_sched: fix us... |
763 |
if (tb[TCA_FLOWER_KEY_ETH_TYPE]) { |
9399ae9a6 net_sched: flower... |
764 |
ethertype = nla_get_be16(tb[TCA_FLOWER_KEY_ETH_TYPE]); |
aaab08344 net/sched: flower... |
765 |
if (eth_type_vlan(ethertype)) { |
d64efd092 net/sched: flower... |
766 767 768 |
fl_set_key_vlan(tb, ethertype, TCA_FLOWER_KEY_VLAN_ID, TCA_FLOWER_KEY_VLAN_PRIO, &key->vlan, &mask->vlan); |
5e9a0fe49 net/sched: flower... |
769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 |
if (tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]) { ethertype = nla_get_be16(tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]); if (eth_type_vlan(ethertype)) { fl_set_key_vlan(tb, ethertype, TCA_FLOWER_KEY_CVLAN_ID, TCA_FLOWER_KEY_CVLAN_PRIO, &key->cvlan, &mask->cvlan); fl_set_key_val(tb, &key->basic.n_proto, TCA_FLOWER_KEY_CVLAN_ETH_TYPE, &mask->basic.n_proto, TCA_FLOWER_UNSPEC, sizeof(key->basic.n_proto)); } else { key->basic.n_proto = ethertype; mask->basic.n_proto = cpu_to_be16(~0); } |
d64efd092 net/sched: flower... |
785 |
} |
0b498a527 net_sched: fix us... |
786 787 788 789 |
} else { key->basic.n_proto = ethertype; mask->basic.n_proto = cpu_to_be16(~0); } |
9399ae9a6 net_sched: flower... |
790 |
} |
66530bdf8 sched,cls_flower:... |
791 |
|
77b9900ef tc: introduce Flo... |
792 793 794 795 796 |
if (key->basic.n_proto == htons(ETH_P_IP) || key->basic.n_proto == htons(ETH_P_IPV6)) { fl_set_key_val(tb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO, &mask->basic.ip_proto, TCA_FLOWER_UNSPEC, sizeof(key->basic.ip_proto)); |
0e2c17b64 net/sched: cls_fl... |
797 |
fl_set_key_ip(tb, false, &key->ip, &mask->ip); |
77b9900ef tc: introduce Flo... |
798 |
} |
66530bdf8 sched,cls_flower:... |
799 800 801 |
if (tb[TCA_FLOWER_KEY_IPV4_SRC] || tb[TCA_FLOWER_KEY_IPV4_DST]) { key->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; |
970bfcd09 net/sched: cls_fl... |
802 |
mask->control.addr_type = ~0; |
77b9900ef tc: introduce Flo... |
803 804 805 806 807 808 |
fl_set_key_val(tb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC, &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK, sizeof(key->ipv4.src)); fl_set_key_val(tb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST, &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK, sizeof(key->ipv4.dst)); |
66530bdf8 sched,cls_flower:... |
809 810 |
} else if (tb[TCA_FLOWER_KEY_IPV6_SRC] || tb[TCA_FLOWER_KEY_IPV6_DST]) { key->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; |
970bfcd09 net/sched: cls_fl... |
811 |
mask->control.addr_type = ~0; |
77b9900ef tc: introduce Flo... |
812 813 814 815 816 817 818 |
fl_set_key_val(tb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC, &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK, sizeof(key->ipv6.src)); fl_set_key_val(tb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST, &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK, sizeof(key->ipv6.dst)); } |
66530bdf8 sched,cls_flower:... |
819 |
|
77b9900ef tc: introduce Flo... |
820 821 |
if (key->basic.ip_proto == IPPROTO_TCP) { fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC, |
aa72d7083 net/sched: cls_fl... |
822 |
&mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK, |
77b9900ef tc: introduce Flo... |
823 824 |
sizeof(key->tp.src)); fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST, |
aa72d7083 net/sched: cls_fl... |
825 |
&mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK, |
77b9900ef tc: introduce Flo... |
826 |
sizeof(key->tp.dst)); |
fdfc7dd6c net/sched: flower... |
827 828 829 |
fl_set_key_val(tb, &key->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS, &mask->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS_MASK, sizeof(key->tcp.flags)); |
77b9900ef tc: introduce Flo... |
830 831 |
} else if (key->basic.ip_proto == IPPROTO_UDP) { fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC, |
aa72d7083 net/sched: cls_fl... |
832 |
&mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK, |
77b9900ef tc: introduce Flo... |
833 834 |
sizeof(key->tp.src)); fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST, |
aa72d7083 net/sched: cls_fl... |
835 |
&mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK, |
77b9900ef tc: introduce Flo... |
836 |
sizeof(key->tp.dst)); |
5976c5f45 net/sched: cls_fl... |
837 838 839 840 841 842 843 |
} else if (key->basic.ip_proto == IPPROTO_SCTP) { fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC, &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK, sizeof(key->tp.src)); fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST, &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK, sizeof(key->tp.dst)); |
7b684884f net/sched: cls_fl... |
844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 |
} else if (key->basic.n_proto == htons(ETH_P_IP) && key->basic.ip_proto == IPPROTO_ICMP) { fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV4_TYPE, &mask->icmp.type, TCA_FLOWER_KEY_ICMPV4_TYPE_MASK, sizeof(key->icmp.type)); fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV4_CODE, &mask->icmp.code, TCA_FLOWER_KEY_ICMPV4_CODE_MASK, sizeof(key->icmp.code)); } else if (key->basic.n_proto == htons(ETH_P_IPV6) && key->basic.ip_proto == IPPROTO_ICMPV6) { fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV6_TYPE, &mask->icmp.type, TCA_FLOWER_KEY_ICMPV6_TYPE_MASK, sizeof(key->icmp.type)); |
040587af3 net/sched: cls_fl... |
860 |
fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV6_CODE, |
7b684884f net/sched: cls_fl... |
861 |
&mask->icmp.code, |
040587af3 net/sched: cls_fl... |
862 |
TCA_FLOWER_KEY_ICMPV6_CODE_MASK, |
7b684884f net/sched: cls_fl... |
863 |
sizeof(key->icmp.code)); |
a577d8f79 cls_flower: add s... |
864 865 |
} else if (key->basic.n_proto == htons(ETH_P_MPLS_UC) || key->basic.n_proto == htons(ETH_P_MPLS_MC)) { |
1a7fca63c flower: check unu... |
866 867 868 |
ret = fl_set_key_mpls(tb, &key->mpls, &mask->mpls); if (ret) return ret; |
99d31326c net/sched: cls_fl... |
869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 |
} else if (key->basic.n_proto == htons(ETH_P_ARP) || key->basic.n_proto == htons(ETH_P_RARP)) { fl_set_key_val(tb, &key->arp.sip, TCA_FLOWER_KEY_ARP_SIP, &mask->arp.sip, TCA_FLOWER_KEY_ARP_SIP_MASK, sizeof(key->arp.sip)); fl_set_key_val(tb, &key->arp.tip, TCA_FLOWER_KEY_ARP_TIP, &mask->arp.tip, TCA_FLOWER_KEY_ARP_TIP_MASK, sizeof(key->arp.tip)); fl_set_key_val(tb, &key->arp.op, TCA_FLOWER_KEY_ARP_OP, &mask->arp.op, TCA_FLOWER_KEY_ARP_OP_MASK, sizeof(key->arp.op)); fl_set_key_val(tb, key->arp.sha, TCA_FLOWER_KEY_ARP_SHA, mask->arp.sha, TCA_FLOWER_KEY_ARP_SHA_MASK, sizeof(key->arp.sha)); fl_set_key_val(tb, key->arp.tha, TCA_FLOWER_KEY_ARP_THA, mask->arp.tha, TCA_FLOWER_KEY_ARP_THA_MASK, sizeof(key->arp.tha)); |
77b9900ef tc: introduce Flo... |
886 |
} |
bc3103f1e net/sched: cls_fl... |
887 888 889 |
if (tb[TCA_FLOWER_KEY_ENC_IPV4_SRC] || tb[TCA_FLOWER_KEY_ENC_IPV4_DST]) { key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; |
970bfcd09 net/sched: cls_fl... |
890 |
mask->enc_control.addr_type = ~0; |
bc3103f1e net/sched: cls_fl... |
891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 |
fl_set_key_val(tb, &key->enc_ipv4.src, TCA_FLOWER_KEY_ENC_IPV4_SRC, &mask->enc_ipv4.src, TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK, sizeof(key->enc_ipv4.src)); fl_set_key_val(tb, &key->enc_ipv4.dst, TCA_FLOWER_KEY_ENC_IPV4_DST, &mask->enc_ipv4.dst, TCA_FLOWER_KEY_ENC_IPV4_DST_MASK, sizeof(key->enc_ipv4.dst)); } if (tb[TCA_FLOWER_KEY_ENC_IPV6_SRC] || tb[TCA_FLOWER_KEY_ENC_IPV6_DST]) { key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; |
970bfcd09 net/sched: cls_fl... |
906 |
mask->enc_control.addr_type = ~0; |
bc3103f1e net/sched: cls_fl... |
907 908 909 910 911 912 913 914 915 916 917 918 919 |
fl_set_key_val(tb, &key->enc_ipv6.src, TCA_FLOWER_KEY_ENC_IPV6_SRC, &mask->enc_ipv6.src, TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK, sizeof(key->enc_ipv6.src)); fl_set_key_val(tb, &key->enc_ipv6.dst, TCA_FLOWER_KEY_ENC_IPV6_DST, &mask->enc_ipv6.dst, TCA_FLOWER_KEY_ENC_IPV6_DST_MASK, sizeof(key->enc_ipv6.dst)); } fl_set_key_val(tb, &key->enc_key_id.keyid, TCA_FLOWER_KEY_ENC_KEY_ID, |
eb523f42d net/sched: cls_fl... |
920 |
&mask->enc_key_id.keyid, TCA_FLOWER_UNSPEC, |
bc3103f1e net/sched: cls_fl... |
921 |
sizeof(key->enc_key_id.keyid)); |
f4d997fd6 net/sched: cls_fl... |
922 923 924 925 926 927 928 |
fl_set_key_val(tb, &key->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT, &mask->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK, sizeof(key->enc_tp.src)); fl_set_key_val(tb, &key->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT, &mask->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK, sizeof(key->enc_tp.dst)); |
0e2c17b64 net/sched: cls_fl... |
929 |
fl_set_key_ip(tb, true, &key->enc_ip, &mask->enc_ip); |
0a6e77784 net/sched: allow ... |
930 931 932 933 934 |
if (tb[TCA_FLOWER_KEY_ENC_OPTS]) { ret = fl_set_enc_opt(tb, key, mask, extack); if (ret) return ret; } |
d9724772e net/sched: cls_fl... |
935 936 |
if (tb[TCA_FLOWER_KEY_FLAGS]) ret = fl_set_key_flags(tb, &key->control.flags, &mask->control.flags); |
faa3ffce7 net/sched: cls_fl... |
937 |
|
d9724772e net/sched: cls_fl... |
938 |
return ret; |
77b9900ef tc: introduce Flo... |
939 |
} |
05cd271fd cls_flower: Suppo... |
940 941 |
static void fl_mask_copy(struct fl_flow_mask *dst, struct fl_flow_mask *src) |
77b9900ef tc: introduce Flo... |
942 |
{ |
05cd271fd cls_flower: Suppo... |
943 944 |
const void *psrc = fl_key_get_start(&src->key, src); void *pdst = fl_key_get_start(&dst->key, src); |
77b9900ef tc: introduce Flo... |
945 |
|
05cd271fd cls_flower: Suppo... |
946 947 |
memcpy(pdst, psrc, fl_mask_range(src)); dst->range = src->range; |
77b9900ef tc: introduce Flo... |
948 949 950 951 952 953 954 |
} static const struct rhashtable_params fl_ht_params = { .key_offset = offsetof(struct cls_fl_filter, mkey), /* base offset */ .head_offset = offsetof(struct cls_fl_filter, ht_node), .automatic_shrinking = true, }; |
05cd271fd cls_flower: Suppo... |
955 |
static int fl_init_mask_hashtable(struct fl_flow_mask *mask) |
77b9900ef tc: introduce Flo... |
956 |
{ |
05cd271fd cls_flower: Suppo... |
957 958 959 |
mask->filter_ht_params = fl_ht_params; mask->filter_ht_params.key_len = fl_mask_range(mask); mask->filter_ht_params.key_offset += mask->range.start; |
77b9900ef tc: introduce Flo... |
960 |
|
05cd271fd cls_flower: Suppo... |
961 |
return rhashtable_init(&mask->ht, &mask->filter_ht_params); |
77b9900ef tc: introduce Flo... |
962 963 964 965 |
} #define FL_KEY_MEMBER_OFFSET(member) offsetof(struct fl_flow_key, member) #define FL_KEY_MEMBER_SIZE(member) (sizeof(((struct fl_flow_key *) 0)->member)) |
77b9900ef tc: introduce Flo... |
966 |
|
339ba878c net_sched: flower... |
967 968 969 |
#define FL_KEY_IS_MASKED(mask, member) \ memchr_inv(((char *)mask) + FL_KEY_MEMBER_OFFSET(member), \ 0, FL_KEY_MEMBER_SIZE(member)) \ |
77b9900ef tc: introduce Flo... |
970 971 972 973 974 975 976 |
#define FL_KEY_SET(keys, cnt, id, member) \ do { \ keys[cnt].key_id = id; \ keys[cnt].offset = FL_KEY_MEMBER_OFFSET(member); \ cnt++; \ } while(0); |
339ba878c net_sched: flower... |
977 |
#define FL_KEY_SET_IF_MASKED(mask, keys, cnt, id, member) \ |
77b9900ef tc: introduce Flo... |
978 |
do { \ |
339ba878c net_sched: flower... |
979 |
if (FL_KEY_IS_MASKED(mask, member)) \ |
77b9900ef tc: introduce Flo... |
980 981 |
FL_KEY_SET(keys, cnt, id, member); \ } while(0); |
33fb5cba1 net: sched: cls_f... |
982 983 |
static void fl_init_dissector(struct flow_dissector *dissector, struct fl_flow_key *mask) |
77b9900ef tc: introduce Flo... |
984 985 986 |
{ struct flow_dissector_key keys[FLOW_DISSECTOR_KEY_MAX]; size_t cnt = 0; |
42aecaa9b net: Get skb hash... |
987 |
FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_CONTROL, control); |
77b9900ef tc: introduce Flo... |
988 |
FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_BASIC, basic); |
33fb5cba1 net: sched: cls_f... |
989 |
FL_KEY_SET_IF_MASKED(mask, keys, cnt, |
339ba878c net_sched: flower... |
990 |
FLOW_DISSECTOR_KEY_ETH_ADDRS, eth); |
33fb5cba1 net: sched: cls_f... |
991 |
FL_KEY_SET_IF_MASKED(mask, keys, cnt, |
339ba878c net_sched: flower... |
992 |
FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4); |
33fb5cba1 net: sched: cls_f... |
993 |
FL_KEY_SET_IF_MASKED(mask, keys, cnt, |
339ba878c net_sched: flower... |
994 |
FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6); |
33fb5cba1 net: sched: cls_f... |
995 |
FL_KEY_SET_IF_MASKED(mask, keys, cnt, |
339ba878c net_sched: flower... |
996 |
FLOW_DISSECTOR_KEY_PORTS, tp); |
33fb5cba1 net: sched: cls_f... |
997 |
FL_KEY_SET_IF_MASKED(mask, keys, cnt, |
4d80cc0aa net/sched: cls_fl... |
998 |
FLOW_DISSECTOR_KEY_IP, ip); |
33fb5cba1 net: sched: cls_f... |
999 |
FL_KEY_SET_IF_MASKED(mask, keys, cnt, |
fdfc7dd6c net/sched: flower... |
1000 |
FLOW_DISSECTOR_KEY_TCP, tcp); |
33fb5cba1 net: sched: cls_f... |
1001 |
FL_KEY_SET_IF_MASKED(mask, keys, cnt, |
7b684884f net/sched: cls_fl... |
1002 |
FLOW_DISSECTOR_KEY_ICMP, icmp); |
33fb5cba1 net: sched: cls_f... |
1003 |
FL_KEY_SET_IF_MASKED(mask, keys, cnt, |
99d31326c net/sched: cls_fl... |
1004 |
FLOW_DISSECTOR_KEY_ARP, arp); |
33fb5cba1 net: sched: cls_f... |
1005 |
FL_KEY_SET_IF_MASKED(mask, keys, cnt, |
a577d8f79 cls_flower: add s... |
1006 |
FLOW_DISSECTOR_KEY_MPLS, mpls); |
33fb5cba1 net: sched: cls_f... |
1007 |
FL_KEY_SET_IF_MASKED(mask, keys, cnt, |
9399ae9a6 net_sched: flower... |
1008 |
FLOW_DISSECTOR_KEY_VLAN, vlan); |
33fb5cba1 net: sched: cls_f... |
1009 |
FL_KEY_SET_IF_MASKED(mask, keys, cnt, |
d64efd092 net/sched: flower... |
1010 |
FLOW_DISSECTOR_KEY_CVLAN, cvlan); |
33fb5cba1 net: sched: cls_f... |
1011 |
FL_KEY_SET_IF_MASKED(mask, keys, cnt, |
519d10521 net/sched: cls_fl... |
1012 |
FLOW_DISSECTOR_KEY_ENC_KEYID, enc_key_id); |
33fb5cba1 net: sched: cls_f... |
1013 |
FL_KEY_SET_IF_MASKED(mask, keys, cnt, |
519d10521 net/sched: cls_fl... |
1014 |
FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, enc_ipv4); |
33fb5cba1 net: sched: cls_f... |
1015 |
FL_KEY_SET_IF_MASKED(mask, keys, cnt, |
519d10521 net/sched: cls_fl... |
1016 |
FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, enc_ipv6); |
33fb5cba1 net: sched: cls_f... |
1017 1018 |
if (FL_KEY_IS_MASKED(mask, enc_ipv4) || FL_KEY_IS_MASKED(mask, enc_ipv6)) |
519d10521 net/sched: cls_fl... |
1019 1020 |
FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_ENC_CONTROL, enc_control); |
33fb5cba1 net: sched: cls_f... |
1021 |
FL_KEY_SET_IF_MASKED(mask, keys, cnt, |
f4d997fd6 net/sched: cls_fl... |
1022 |
FLOW_DISSECTOR_KEY_ENC_PORTS, enc_tp); |
33fb5cba1 net: sched: cls_f... |
1023 |
FL_KEY_SET_IF_MASKED(mask, keys, cnt, |
0e2c17b64 net/sched: cls_fl... |
1024 |
FLOW_DISSECTOR_KEY_ENC_IP, enc_ip); |
0a6e77784 net/sched: allow ... |
1025 1026 |
FL_KEY_SET_IF_MASKED(mask, keys, cnt, FLOW_DISSECTOR_KEY_ENC_OPTS, enc_opts); |
77b9900ef tc: introduce Flo... |
1027 |
|
33fb5cba1 net: sched: cls_f... |
1028 |
skb_flow_dissector_init(dissector, keys, cnt); |
05cd271fd cls_flower: Suppo... |
1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 |
} static struct fl_flow_mask *fl_create_new_mask(struct cls_fl_head *head, struct fl_flow_mask *mask) { struct fl_flow_mask *newmask; int err; newmask = kzalloc(sizeof(*newmask), GFP_KERNEL); if (!newmask) return ERR_PTR(-ENOMEM); fl_mask_copy(newmask, mask); err = fl_init_mask_hashtable(newmask); if (err) goto errout_free; |
33fb5cba1 net: sched: cls_f... |
1046 |
fl_init_dissector(&newmask->dissector, &newmask->key); |
05cd271fd cls_flower: Suppo... |
1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 |
INIT_LIST_HEAD_RCU(&newmask->filters); err = rhashtable_insert_fast(&head->ht, &newmask->ht_node, mask_ht_params); if (err) goto errout_destroy; list_add_tail_rcu(&newmask->list, &head->masks); return newmask; errout_destroy: rhashtable_destroy(&newmask->ht); errout_free: kfree(newmask); return ERR_PTR(err); |
77b9900ef tc: introduce Flo... |
1065 1066 1067 |
} static int fl_check_assign_mask(struct cls_fl_head *head, |
05cd271fd cls_flower: Suppo... |
1068 1069 |
struct cls_fl_filter *fnew, struct cls_fl_filter *fold, |
77b9900ef tc: introduce Flo... |
1070 1071 |
struct fl_flow_mask *mask) { |
05cd271fd cls_flower: Suppo... |
1072 |
struct fl_flow_mask *newmask; |
77b9900ef tc: introduce Flo... |
1073 |
|
05cd271fd cls_flower: Suppo... |
1074 1075 1076 |
fnew->mask = rhashtable_lookup_fast(&head->ht, mask, mask_ht_params); if (!fnew->mask) { if (fold) |
77b9900ef tc: introduce Flo... |
1077 |
return -EINVAL; |
77b9900ef tc: introduce Flo... |
1078 |
|
05cd271fd cls_flower: Suppo... |
1079 1080 1081 |
newmask = fl_create_new_mask(head, mask); if (IS_ERR(newmask)) return PTR_ERR(newmask); |
77b9900ef tc: introduce Flo... |
1082 |
|
05cd271fd cls_flower: Suppo... |
1083 |
fnew->mask = newmask; |
f6521c587 cls_flower: Fix c... |
1084 |
} else if (fold && fold->mask != fnew->mask) { |
05cd271fd cls_flower: Suppo... |
1085 1086 |
return -EINVAL; } |
77b9900ef tc: introduce Flo... |
1087 1088 1089 1090 1091 1092 1093 |
return 0; } static int fl_set_parms(struct net *net, struct tcf_proto *tp, struct cls_fl_filter *f, struct fl_flow_mask *mask, unsigned long base, struct nlattr **tb, |
50a561900 net: sched: cls: ... |
1094 |
struct nlattr *est, bool ovr, |
b95ec7eb3 net: sched: cls_f... |
1095 |
struct fl_flow_tmplt *tmplt, |
50a561900 net: sched: cls: ... |
1096 |
struct netlink_ext_ack *extack) |
77b9900ef tc: introduce Flo... |
1097 |
{ |
77b9900ef tc: introduce Flo... |
1098 |
int err; |
50a561900 net: sched: cls: ... |
1099 |
err = tcf_exts_validate(net, tp, tb, est, &f->exts, ovr, extack); |
77b9900ef tc: introduce Flo... |
1100 1101 1102 1103 1104 1105 1106 |
if (err < 0) return err; if (tb[TCA_FLOWER_CLASSID]) { f->res.classid = nla_get_u32(tb[TCA_FLOWER_CLASSID]); tcf_bind_filter(tp, &f->res, base); } |
1057c55f6 net: sched: cls: ... |
1107 |
err = fl_set_key(net, tb, &f->key, &mask->key, extack); |
77b9900ef tc: introduce Flo... |
1108 |
if (err) |
455075292 net: sched: cls_f... |
1109 |
return err; |
77b9900ef tc: introduce Flo... |
1110 1111 1112 |
fl_mask_update_range(mask); fl_set_masked_key(&f->mkey, &f->key, mask); |
b95ec7eb3 net: sched: cls_f... |
1113 1114 1115 1116 |
if (!fl_mask_fits_tmplt(tmplt, mask)) { NL_SET_ERR_MSG_MOD(extack, "Mask does not fit the template"); return -EINVAL; } |
77b9900ef tc: introduce Flo... |
1117 |
return 0; |
77b9900ef tc: introduce Flo... |
1118 |
} |
77b9900ef tc: introduce Flo... |
1119 1120 1121 |
static int fl_change(struct net *net, struct sk_buff *in_skb, struct tcf_proto *tp, unsigned long base, u32 handle, struct nlattr **tca, |
7306db38a net: sched: cls: ... |
1122 |
void **arg, bool ovr, struct netlink_ext_ack *extack) |
77b9900ef tc: introduce Flo... |
1123 1124 |
{ struct cls_fl_head *head = rtnl_dereference(tp->root); |
8113c0956 net_sched: use vo... |
1125 |
struct cls_fl_filter *fold = *arg; |
77b9900ef tc: introduce Flo... |
1126 |
struct cls_fl_filter *fnew; |
84bf74307 net/sched: cls_fl... |
1127 |
struct fl_flow_mask *mask; |
39b7b6a62 net/sched: cls_fl... |
1128 |
struct nlattr **tb; |
77b9900ef tc: introduce Flo... |
1129 1130 1131 1132 |
int err; if (!tca[TCA_OPTIONS]) return -EINVAL; |
84bf74307 net/sched: cls_fl... |
1133 1134 |
mask = kzalloc(sizeof(struct fl_flow_mask), GFP_KERNEL); if (!mask) |
39b7b6a62 net/sched: cls_fl... |
1135 |
return -ENOBUFS; |
84bf74307 net/sched: cls_fl... |
1136 1137 1138 1139 1140 |
tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL); if (!tb) { err = -ENOBUFS; goto errout_mask_alloc; } |
fceb6435e netlink: pass ext... |
1141 1142 |
err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS], fl_policy, NULL); |
77b9900ef tc: introduce Flo... |
1143 |
if (err < 0) |
39b7b6a62 net/sched: cls_fl... |
1144 |
goto errout_tb; |
77b9900ef tc: introduce Flo... |
1145 |
|
39b7b6a62 net/sched: cls_fl... |
1146 1147 1148 1149 |
if (fold && handle && fold->handle != handle) { err = -EINVAL; goto errout_tb; } |
77b9900ef tc: introduce Flo... |
1150 1151 |
fnew = kzalloc(sizeof(*fnew), GFP_KERNEL); |
39b7b6a62 net/sched: cls_fl... |
1152 1153 1154 1155 |
if (!fnew) { err = -ENOBUFS; goto errout_tb; } |
77b9900ef tc: introduce Flo... |
1156 |
|
b9a24bb76 net_sched: proper... |
1157 1158 1159 |
err = tcf_exts_init(&fnew->exts, TCA_FLOWER_ACT, 0); if (err < 0) goto errout; |
77b9900ef tc: introduce Flo... |
1160 |
|
e69985c67 net/sched: cls_fl... |
1161 1162 1163 1164 1165 |
if (tb[TCA_FLOWER_FLAGS]) { fnew->flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]); if (!tc_flags_valid(fnew->flags)) { err = -EINVAL; |
275a2c08c net: sched: flowe... |
1166 |
goto errout; |
e69985c67 net/sched: cls_fl... |
1167 1168 |
} } |
5b33f4884 net/flower: Intro... |
1169 |
|
84bf74307 net/sched: cls_fl... |
1170 |
err = fl_set_parms(net, tp, fnew, mask, base, tb, tca[TCA_RATE], ovr, |
b95ec7eb3 net: sched: cls_f... |
1171 |
tp->chain->tmplt_priv, extack); |
77b9900ef tc: introduce Flo... |
1172 |
if (err) |
275a2c08c net: sched: flowe... |
1173 |
goto errout; |
77b9900ef tc: introduce Flo... |
1174 |
|
84bf74307 net/sched: cls_fl... |
1175 |
err = fl_check_assign_mask(head, fnew, fold, mask); |
77b9900ef tc: introduce Flo... |
1176 |
if (err) |
275a2c08c net: sched: flowe... |
1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 |
goto errout; if (!handle) { handle = 1; err = idr_alloc_u32(&head->handle_idr, fnew, &handle, INT_MAX, GFP_KERNEL); } else if (!fold) { /* user specifies a handle and it doesn't exist */ err = idr_alloc_u32(&head->handle_idr, fnew, &handle, handle, GFP_KERNEL); } if (err) goto errout_mask; fnew->handle = handle; |
77b9900ef tc: introduce Flo... |
1191 |
|
e8eb36cd8 net/sched: flower... |
1192 |
if (!tc_skip_sw(fnew->flags)) { |
05cd271fd cls_flower: Suppo... |
1193 |
if (!fold && fl_lookup(fnew->mask, &fnew->mkey)) { |
a3308d8fd net/sched: cls_fl... |
1194 |
err = -EEXIST; |
275a2c08c net: sched: flowe... |
1195 |
goto errout_idr; |
a3308d8fd net/sched: cls_fl... |
1196 |
} |
05cd271fd cls_flower: Suppo... |
1197 1198 |
err = rhashtable_insert_fast(&fnew->mask->ht, &fnew->ht_node, fnew->mask->filter_ht_params); |
e69985c67 net/sched: cls_fl... |
1199 |
if (err) |
275a2c08c net: sched: flowe... |
1200 |
goto errout_idr; |
e69985c67 net/sched: cls_fl... |
1201 |
} |
5b33f4884 net/flower: Intro... |
1202 |
|
796852197 net/sched: cls_fl... |
1203 |
if (!tc_skip_hw(fnew->flags)) { |
05cd271fd cls_flower: Suppo... |
1204 |
err = fl_hw_replace_filter(tp, fnew, extack); |
796852197 net/sched: cls_fl... |
1205 |
if (err) |
05cd271fd cls_flower: Suppo... |
1206 |
goto errout_mask; |
796852197 net/sched: cls_fl... |
1207 |
} |
5b33f4884 net/flower: Intro... |
1208 |
|
55593960d net/sched: cls_fl... |
1209 1210 |
if (!tc_in_hw(fnew->flags)) fnew->flags |= TCA_CLS_FLAGS_NOT_IN_HW; |
5b33f4884 net/flower: Intro... |
1211 |
if (fold) { |
725cbb62e sched: cls_flower... |
1212 |
if (!tc_skip_sw(fold->flags)) |
05cd271fd cls_flower: Suppo... |
1213 1214 1215 |
rhashtable_remove_fast(&fold->mask->ht, &fold->ht_node, fold->mask->filter_ht_params); |
796852197 net/sched: cls_fl... |
1216 |
if (!tc_skip_hw(fold->flags)) |
1b0f80375 cls_flower: propa... |
1217 |
fl_hw_destroy_filter(tp, fold, NULL); |
5b33f4884 net/flower: Intro... |
1218 |
} |
77b9900ef tc: introduce Flo... |
1219 |
|
8113c0956 net_sched: use vo... |
1220 |
*arg = fnew; |
77b9900ef tc: introduce Flo... |
1221 1222 |
if (fold) { |
234a4624e idr: Delete idr_r... |
1223 |
idr_replace(&head->handle_idr, fnew, fnew->handle); |
ff3532f26 sched: cls_flower... |
1224 |
list_replace_rcu(&fold->list, &fnew->list); |
77b9900ef tc: introduce Flo... |
1225 |
tcf_unbind_filter(tp, &fold->res); |
0dadc117a cls_flower: use t... |
1226 |
tcf_exts_get_net(&fold->exts); |
aaa908ffb net_sched: switch... |
1227 |
tcf_queue_work(&fold->rwork, fl_destroy_filter_work); |
77b9900ef tc: introduce Flo... |
1228 |
} else { |
05cd271fd cls_flower: Suppo... |
1229 |
list_add_tail_rcu(&fnew->list, &fnew->mask->filters); |
77b9900ef tc: introduce Flo... |
1230 |
} |
39b7b6a62 net/sched: cls_fl... |
1231 |
kfree(tb); |
84bf74307 net/sched: cls_fl... |
1232 |
kfree(mask); |
77b9900ef tc: introduce Flo... |
1233 |
return 0; |
fe2502e49 net_sched: remove... |
1234 |
errout_idr: |
8258d2da9 cls_flower: Fix i... |
1235 |
if (!fold) |
9c1609414 idr: Delete idr_r... |
1236 |
idr_remove(&head->handle_idr, fnew->handle); |
275a2c08c net: sched: flowe... |
1237 1238 1239 |
errout_mask: fl_mask_put(head, fnew->mask, false); |
77b9900ef tc: introduce Flo... |
1240 |
errout: |
b9a24bb76 net_sched: proper... |
1241 |
tcf_exts_destroy(&fnew->exts); |
77b9900ef tc: introduce Flo... |
1242 |
kfree(fnew); |
39b7b6a62 net/sched: cls_fl... |
1243 1244 |
errout_tb: kfree(tb); |
84bf74307 net/sched: cls_fl... |
1245 1246 |
errout_mask_alloc: kfree(mask); |
77b9900ef tc: introduce Flo... |
1247 1248 |
return err; } |
571acf210 net: sched: cls: ... |
1249 1250 |
static int fl_delete(struct tcf_proto *tp, void *arg, bool *last, struct netlink_ext_ack *extack) |
77b9900ef tc: introduce Flo... |
1251 1252 |
{ struct cls_fl_head *head = rtnl_dereference(tp->root); |
8113c0956 net_sched: use vo... |
1253 |
struct cls_fl_filter *f = arg; |
77b9900ef tc: introduce Flo... |
1254 |
|
725cbb62e sched: cls_flower... |
1255 |
if (!tc_skip_sw(f->flags)) |
05cd271fd cls_flower: Suppo... |
1256 1257 |
rhashtable_remove_fast(&f->mask->ht, &f->ht_node, f->mask->filter_ht_params); |
1b0f80375 cls_flower: propa... |
1258 |
__fl_delete(tp, f, extack); |
05cd271fd cls_flower: Suppo... |
1259 |
*last = list_empty(&head->masks); |
77b9900ef tc: introduce Flo... |
1260 1261 1262 1263 1264 1265 1266 |
return 0; } static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg) { struct cls_fl_head *head = rtnl_dereference(tp->root); struct cls_fl_filter *f; |
05cd271fd cls_flower: Suppo... |
1267 |
|
01683a146 net: sched: refac... |
1268 1269 1270 1271 1272 1273 1274 |
arg->count = arg->skip; while ((f = idr_get_next_ul(&head->handle_idr, &arg->cookie)) != NULL) { if (arg->fn(tp, f, arg) < 0) { arg->stop = 1; break; |
05cd271fd cls_flower: Suppo... |
1275 |
} |
01683a146 net: sched: refac... |
1276 1277 |
arg->cookie = f->handle + 1; arg->count++; |
77b9900ef tc: introduce Flo... |
1278 1279 |
} } |
31533cba4 net: sched: cls_f... |
1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 |
static int fl_reoffload(struct tcf_proto *tp, bool add, tc_setup_cb_t *cb, void *cb_priv, struct netlink_ext_ack *extack) { struct cls_fl_head *head = rtnl_dereference(tp->root); struct tc_cls_flower_offload cls_flower = {}; struct tcf_block *block = tp->chain->block; struct fl_flow_mask *mask; struct cls_fl_filter *f; int err; list_for_each_entry(mask, &head->masks, list) { list_for_each_entry(f, &mask->filters, list) { if (tc_skip_hw(f->flags)) continue; tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack); cls_flower.command = add ? TC_CLSFLOWER_REPLACE : TC_CLSFLOWER_DESTROY; cls_flower.cookie = (unsigned long)f; cls_flower.dissector = &mask->dissector; |
9ca616300 net: sched: cls_f... |
1301 1302 |
cls_flower.mask = &mask->key; cls_flower.key = &f->mkey; |
31533cba4 net: sched: cls_f... |
1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 |
cls_flower.exts = &f->exts; cls_flower.classid = f->res.classid; err = cb(TC_SETUP_CLSFLOWER, &cls_flower, cb_priv); if (err) { if (add && tc_skip_sw(f->flags)) return err; continue; } tc_cls_offload_cnt_update(block, &f->in_hw_count, &f->flags, add); } } return 0; } |
347384527 net: sched: cls_f... |
1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 |
static void fl_hw_create_tmplt(struct tcf_chain *chain, struct fl_flow_tmplt *tmplt) { struct tc_cls_flower_offload cls_flower = {}; struct tcf_block *block = chain->block; struct tcf_exts dummy_exts = { 0, }; cls_flower.common.chain_index = chain->index; cls_flower.command = TC_CLSFLOWER_TMPLT_CREATE; cls_flower.cookie = (unsigned long) tmplt; cls_flower.dissector = &tmplt->dissector; cls_flower.mask = &tmplt->mask; cls_flower.key = &tmplt->dummy_key; cls_flower.exts = &dummy_exts; /* We don't care if driver (any of them) fails to handle this * call. It serves just as a hint for it. */ tc_setup_cb_call(block, NULL, TC_SETUP_CLSFLOWER, &cls_flower, false); } static void fl_hw_destroy_tmplt(struct tcf_chain *chain, struct fl_flow_tmplt *tmplt) { struct tc_cls_flower_offload cls_flower = {}; struct tcf_block *block = chain->block; cls_flower.common.chain_index = chain->index; cls_flower.command = TC_CLSFLOWER_TMPLT_DESTROY; cls_flower.cookie = (unsigned long) tmplt; tc_setup_cb_call(block, NULL, TC_SETUP_CLSFLOWER, &cls_flower, false); } |
b95ec7eb3 net: sched: cls_f... |
1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 |
static void *fl_tmplt_create(struct net *net, struct tcf_chain *chain, struct nlattr **tca, struct netlink_ext_ack *extack) { struct fl_flow_tmplt *tmplt; struct nlattr **tb; int err; if (!tca[TCA_OPTIONS]) return ERR_PTR(-EINVAL); tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL); if (!tb) return ERR_PTR(-ENOBUFS); err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS], fl_policy, NULL); if (err) goto errout_tb; tmplt = kzalloc(sizeof(*tmplt), GFP_KERNEL); |
1cbc36a53 net: sched: cls_f... |
1375 1376 |
if (!tmplt) { err = -ENOMEM; |
b95ec7eb3 net: sched: cls_f... |
1377 |
goto errout_tb; |
1cbc36a53 net: sched: cls_f... |
1378 |
} |
b95ec7eb3 net: sched: cls_f... |
1379 1380 1381 1382 1383 1384 1385 |
tmplt->chain = chain; err = fl_set_key(net, tb, &tmplt->dummy_key, &tmplt->mask, extack); if (err) goto errout_tmplt; kfree(tb); fl_init_dissector(&tmplt->dissector, &tmplt->mask); |
347384527 net: sched: cls_f... |
1386 |
fl_hw_create_tmplt(chain, tmplt); |
b95ec7eb3 net: sched: cls_f... |
1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 |
return tmplt; errout_tmplt: kfree(tmplt); errout_tb: kfree(tb); return ERR_PTR(err); } static void fl_tmplt_destroy(void *tmplt_priv) { struct fl_flow_tmplt *tmplt = tmplt_priv; |
347384527 net: sched: cls_f... |
1399 |
fl_hw_destroy_tmplt(tmplt->chain, tmplt); |
b95ec7eb3 net: sched: cls_f... |
1400 1401 |
kfree(tmplt); } |
77b9900ef tc: introduce Flo... |
1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 |
static int fl_dump_key_val(struct sk_buff *skb, void *val, int val_type, void *mask, int mask_type, int len) { int err; if (!memchr_inv(mask, 0, len)) return 0; err = nla_put(skb, val_type, len, val); if (err) return err; if (mask_type != TCA_FLOWER_UNSPEC) { err = nla_put(skb, mask_type, len, mask); if (err) return err; } return 0; } |
a577d8f79 cls_flower: add s... |
1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 |
static int fl_dump_key_mpls(struct sk_buff *skb, struct flow_dissector_key_mpls *mpls_key, struct flow_dissector_key_mpls *mpls_mask) { int err; if (!memchr_inv(mpls_mask, 0, sizeof(*mpls_mask))) return 0; if (mpls_mask->mpls_ttl) { err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TTL, mpls_key->mpls_ttl); if (err) return err; } if (mpls_mask->mpls_tc) { err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TC, mpls_key->mpls_tc); if (err) return err; } if (mpls_mask->mpls_label) { err = nla_put_u32(skb, TCA_FLOWER_KEY_MPLS_LABEL, mpls_key->mpls_label); if (err) return err; } if (mpls_mask->mpls_bos) { err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_BOS, mpls_key->mpls_bos); if (err) return err; } return 0; } |
0e2c17b64 net/sched: cls_fl... |
1454 |
static int fl_dump_key_ip(struct sk_buff *skb, bool encap, |
4d80cc0aa net/sched: cls_fl... |
1455 1456 1457 |
struct flow_dissector_key_ip *key, struct flow_dissector_key_ip *mask) { |
0e2c17b64 net/sched: cls_fl... |
1458 1459 1460 1461 1462 1463 1464 |
int tos_key = encap ? TCA_FLOWER_KEY_ENC_IP_TOS : TCA_FLOWER_KEY_IP_TOS; int ttl_key = encap ? TCA_FLOWER_KEY_ENC_IP_TTL : TCA_FLOWER_KEY_IP_TTL; int tos_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TOS_MASK : TCA_FLOWER_KEY_IP_TOS_MASK; int ttl_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TTL_MASK : TCA_FLOWER_KEY_IP_TTL_MASK; if (fl_dump_key_val(skb, &key->tos, tos_key, &mask->tos, tos_mask, sizeof(key->tos)) || fl_dump_key_val(skb, &key->ttl, ttl_key, &mask->ttl, ttl_mask, sizeof(key->ttl))) |
4d80cc0aa net/sched: cls_fl... |
1465 1466 1467 1468 |
return -1; return 0; } |
9399ae9a6 net_sched: flower... |
1469 |
static int fl_dump_key_vlan(struct sk_buff *skb, |
d64efd092 net/sched: flower... |
1470 |
int vlan_id_key, int vlan_prio_key, |
9399ae9a6 net_sched: flower... |
1471 1472 1473 1474 1475 1476 1477 1478 |
struct flow_dissector_key_vlan *vlan_key, struct flow_dissector_key_vlan *vlan_mask) { int err; if (!memchr_inv(vlan_mask, 0, sizeof(*vlan_mask))) return 0; if (vlan_mask->vlan_id) { |
d64efd092 net/sched: flower... |
1479 |
err = nla_put_u16(skb, vlan_id_key, |
9399ae9a6 net_sched: flower... |
1480 1481 1482 1483 1484 |
vlan_key->vlan_id); if (err) return err; } if (vlan_mask->vlan_priority) { |
d64efd092 net/sched: flower... |
1485 |
err = nla_put_u8(skb, vlan_prio_key, |
9399ae9a6 net_sched: flower... |
1486 1487 1488 1489 1490 1491 |
vlan_key->vlan_priority); if (err) return err; } return 0; } |
faa3ffce7 net/sched: cls_fl... |
1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 |
static void fl_get_key_flag(u32 dissector_key, u32 dissector_mask, u32 *flower_key, u32 *flower_mask, u32 flower_flag_bit, u32 dissector_flag_bit) { if (dissector_mask & dissector_flag_bit) { *flower_mask |= flower_flag_bit; if (dissector_key & dissector_flag_bit) *flower_key |= flower_flag_bit; } } static int fl_dump_key_flags(struct sk_buff *skb, u32 flags_key, u32 flags_mask) { u32 key, mask; __be32 _key, _mask; int err; if (!memchr_inv(&flags_mask, 0, sizeof(flags_mask))) return 0; key = 0; mask = 0; fl_get_key_flag(flags_key, flags_mask, &key, &mask, TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT); |
459d153d9 net/sched: cls_fl... |
1517 1518 1519 |
fl_get_key_flag(flags_key, flags_mask, &key, &mask, TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST, FLOW_DIS_FIRST_FRAG); |
faa3ffce7 net/sched: cls_fl... |
1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 |
_key = cpu_to_be32(key); _mask = cpu_to_be32(mask); err = nla_put(skb, TCA_FLOWER_KEY_FLAGS, 4, &_key); if (err) return err; return nla_put(skb, TCA_FLOWER_KEY_FLAGS_MASK, 4, &_mask); } |
0a6e77784 net/sched: allow ... |
1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 |
static int fl_dump_key_geneve_opt(struct sk_buff *skb, struct flow_dissector_key_enc_opts *enc_opts) { struct geneve_opt *opt; struct nlattr *nest; int opt_off = 0; nest = nla_nest_start(skb, TCA_FLOWER_KEY_ENC_OPTS_GENEVE); if (!nest) goto nla_put_failure; while (enc_opts->len > opt_off) { opt = (struct geneve_opt *)&enc_opts->data[opt_off]; if (nla_put_be16(skb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS, opt->opt_class)) goto nla_put_failure; if (nla_put_u8(skb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE, opt->type)) goto nla_put_failure; if (nla_put(skb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA, opt->length * 4, opt->opt_data)) goto nla_put_failure; opt_off += sizeof(struct geneve_opt) + opt->length * 4; } nla_nest_end(skb, nest); return 0; nla_put_failure: nla_nest_cancel(skb, nest); return -EMSGSIZE; } static int fl_dump_key_options(struct sk_buff *skb, int enc_opt_type, struct flow_dissector_key_enc_opts *enc_opts) { struct nlattr *nest; int err; if (!enc_opts->len) return 0; nest = nla_nest_start(skb, enc_opt_type); if (!nest) goto nla_put_failure; switch (enc_opts->dst_opt_type) { case TUNNEL_GENEVE_OPT: err = fl_dump_key_geneve_opt(skb, enc_opts); if (err) goto nla_put_failure; break; default: goto nla_put_failure; } nla_nest_end(skb, nest); return 0; nla_put_failure: nla_nest_cancel(skb, nest); return -EMSGSIZE; } static int fl_dump_key_enc_opt(struct sk_buff *skb, struct flow_dissector_key_enc_opts *key_opts, struct flow_dissector_key_enc_opts *msk_opts) { int err; err = fl_dump_key_options(skb, TCA_FLOWER_KEY_ENC_OPTS, key_opts); if (err) return err; return fl_dump_key_options(skb, TCA_FLOWER_KEY_ENC_OPTS_MASK, msk_opts); } |
f5749081f net: sched: cls_f... |
1606 1607 |
static int fl_dump_key(struct sk_buff *skb, struct net *net, struct fl_flow_key *key, struct fl_flow_key *mask) |
77b9900ef tc: introduce Flo... |
1608 |
{ |
77b9900ef tc: introduce Flo... |
1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 |
if (mask->indev_ifindex) { struct net_device *dev; dev = __dev_get_by_index(net, key->indev_ifindex); if (dev && nla_put_string(skb, TCA_FLOWER_INDEV, dev->name)) goto nla_put_failure; } if (fl_dump_key_val(skb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST, mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK, sizeof(key->eth.dst)) || fl_dump_key_val(skb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC, mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK, sizeof(key->eth.src)) || fl_dump_key_val(skb, &key->basic.n_proto, TCA_FLOWER_KEY_ETH_TYPE, &mask->basic.n_proto, TCA_FLOWER_UNSPEC, sizeof(key->basic.n_proto))) goto nla_put_failure; |
9399ae9a6 net_sched: flower... |
1627 |
|
a577d8f79 cls_flower: add s... |
1628 1629 |
if (fl_dump_key_mpls(skb, &key->mpls, &mask->mpls)) goto nla_put_failure; |
d64efd092 net/sched: flower... |
1630 1631 |
if (fl_dump_key_vlan(skb, TCA_FLOWER_KEY_VLAN_ID, TCA_FLOWER_KEY_VLAN_PRIO, &key->vlan, &mask->vlan)) |
9399ae9a6 net_sched: flower... |
1632 |
goto nla_put_failure; |
d64efd092 net/sched: flower... |
1633 1634 1635 1636 |
if (fl_dump_key_vlan(skb, TCA_FLOWER_KEY_CVLAN_ID, TCA_FLOWER_KEY_CVLAN_PRIO, &key->cvlan, &mask->cvlan) || (mask->cvlan.vlan_tpid && |
158abbf17 net/sched: cls_fl... |
1637 1638 |
nla_put_be16(skb, TCA_FLOWER_KEY_VLAN_ETH_TYPE, key->cvlan.vlan_tpid))) |
d30695126 net/sched: flower... |
1639 |
goto nla_put_failure; |
5e9a0fe49 net/sched: flower... |
1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 |
if (mask->basic.n_proto) { if (mask->cvlan.vlan_tpid) { if (nla_put_be16(skb, TCA_FLOWER_KEY_CVLAN_ETH_TYPE, key->basic.n_proto)) goto nla_put_failure; } else if (mask->vlan.vlan_tpid) { if (nla_put_be16(skb, TCA_FLOWER_KEY_VLAN_ETH_TYPE, key->basic.n_proto)) goto nla_put_failure; } |
d64efd092 net/sched: flower... |
1650 |
} |
77b9900ef tc: introduce Flo... |
1651 1652 |
if ((key->basic.n_proto == htons(ETH_P_IP) || key->basic.n_proto == htons(ETH_P_IPV6)) && |
4d80cc0aa net/sched: cls_fl... |
1653 |
(fl_dump_key_val(skb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO, |
77b9900ef tc: introduce Flo... |
1654 |
&mask->basic.ip_proto, TCA_FLOWER_UNSPEC, |
4d80cc0aa net/sched: cls_fl... |
1655 |
sizeof(key->basic.ip_proto)) || |
0e2c17b64 net/sched: cls_fl... |
1656 |
fl_dump_key_ip(skb, false, &key->ip, &mask->ip))) |
77b9900ef tc: introduce Flo... |
1657 |
goto nla_put_failure; |
c3f832418 net: Add full IPv... |
1658 |
if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS && |
77b9900ef tc: introduce Flo... |
1659 1660 1661 1662 1663 1664 1665 |
(fl_dump_key_val(skb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC, &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK, sizeof(key->ipv4.src)) || fl_dump_key_val(skb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST, &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK, sizeof(key->ipv4.dst)))) goto nla_put_failure; |
c3f832418 net: Add full IPv... |
1666 |
else if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS && |
77b9900ef tc: introduce Flo... |
1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 |
(fl_dump_key_val(skb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC, &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK, sizeof(key->ipv6.src)) || fl_dump_key_val(skb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST, &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK, sizeof(key->ipv6.dst)))) goto nla_put_failure; if (key->basic.ip_proto == IPPROTO_TCP && (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC, |
aa72d7083 net/sched: cls_fl... |
1677 |
&mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK, |
77b9900ef tc: introduce Flo... |
1678 1679 |
sizeof(key->tp.src)) || fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST, |
aa72d7083 net/sched: cls_fl... |
1680 |
&mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK, |
fdfc7dd6c net/sched: flower... |
1681 1682 1683 1684 |
sizeof(key->tp.dst)) || fl_dump_key_val(skb, &key->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS, &mask->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS_MASK, sizeof(key->tcp.flags)))) |
77b9900ef tc: introduce Flo... |
1685 1686 1687 |
goto nla_put_failure; else if (key->basic.ip_proto == IPPROTO_UDP && (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC, |
aa72d7083 net/sched: cls_fl... |
1688 |
&mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK, |
77b9900ef tc: introduce Flo... |
1689 1690 |
sizeof(key->tp.src)) || fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST, |
aa72d7083 net/sched: cls_fl... |
1691 |
&mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK, |
5976c5f45 net/sched: cls_fl... |
1692 1693 1694 1695 1696 1697 1698 1699 |
sizeof(key->tp.dst)))) goto nla_put_failure; else if (key->basic.ip_proto == IPPROTO_SCTP && (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC, &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK, sizeof(key->tp.src)) || fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST, &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK, |
77b9900ef tc: introduce Flo... |
1700 1701 |
sizeof(key->tp.dst)))) goto nla_put_failure; |
7b684884f net/sched: cls_fl... |
1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 |
else if (key->basic.n_proto == htons(ETH_P_IP) && key->basic.ip_proto == IPPROTO_ICMP && (fl_dump_key_val(skb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV4_TYPE, &mask->icmp.type, TCA_FLOWER_KEY_ICMPV4_TYPE_MASK, sizeof(key->icmp.type)) || fl_dump_key_val(skb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV4_CODE, &mask->icmp.code, TCA_FLOWER_KEY_ICMPV4_CODE_MASK, sizeof(key->icmp.code)))) goto nla_put_failure; else if (key->basic.n_proto == htons(ETH_P_IPV6) && key->basic.ip_proto == IPPROTO_ICMPV6 && (fl_dump_key_val(skb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV6_TYPE, &mask->icmp.type, TCA_FLOWER_KEY_ICMPV6_TYPE_MASK, sizeof(key->icmp.type)) || fl_dump_key_val(skb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV6_CODE, &mask->icmp.code, TCA_FLOWER_KEY_ICMPV6_CODE_MASK, sizeof(key->icmp.code)))) goto nla_put_failure; |
99d31326c net/sched: cls_fl... |
1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 |
else if ((key->basic.n_proto == htons(ETH_P_ARP) || key->basic.n_proto == htons(ETH_P_RARP)) && (fl_dump_key_val(skb, &key->arp.sip, TCA_FLOWER_KEY_ARP_SIP, &mask->arp.sip, TCA_FLOWER_KEY_ARP_SIP_MASK, sizeof(key->arp.sip)) || fl_dump_key_val(skb, &key->arp.tip, TCA_FLOWER_KEY_ARP_TIP, &mask->arp.tip, TCA_FLOWER_KEY_ARP_TIP_MASK, sizeof(key->arp.tip)) || fl_dump_key_val(skb, &key->arp.op, TCA_FLOWER_KEY_ARP_OP, &mask->arp.op, TCA_FLOWER_KEY_ARP_OP_MASK, sizeof(key->arp.op)) || fl_dump_key_val(skb, key->arp.sha, TCA_FLOWER_KEY_ARP_SHA, mask->arp.sha, TCA_FLOWER_KEY_ARP_SHA_MASK, sizeof(key->arp.sha)) || fl_dump_key_val(skb, key->arp.tha, TCA_FLOWER_KEY_ARP_THA, mask->arp.tha, TCA_FLOWER_KEY_ARP_THA_MASK, sizeof(key->arp.tha)))) goto nla_put_failure; |
77b9900ef tc: introduce Flo... |
1745 |
|
bc3103f1e net/sched: cls_fl... |
1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 |
if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS && (fl_dump_key_val(skb, &key->enc_ipv4.src, TCA_FLOWER_KEY_ENC_IPV4_SRC, &mask->enc_ipv4.src, TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK, sizeof(key->enc_ipv4.src)) || fl_dump_key_val(skb, &key->enc_ipv4.dst, TCA_FLOWER_KEY_ENC_IPV4_DST, &mask->enc_ipv4.dst, TCA_FLOWER_KEY_ENC_IPV4_DST_MASK, sizeof(key->enc_ipv4.dst)))) goto nla_put_failure; else if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS && (fl_dump_key_val(skb, &key->enc_ipv6.src, TCA_FLOWER_KEY_ENC_IPV6_SRC, &mask->enc_ipv6.src, TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK, sizeof(key->enc_ipv6.src)) || fl_dump_key_val(skb, &key->enc_ipv6.dst, TCA_FLOWER_KEY_ENC_IPV6_DST, &mask->enc_ipv6.dst, TCA_FLOWER_KEY_ENC_IPV6_DST_MASK, sizeof(key->enc_ipv6.dst)))) goto nla_put_failure; if (fl_dump_key_val(skb, &key->enc_key_id, TCA_FLOWER_KEY_ENC_KEY_ID, |
eb523f42d net/sched: cls_fl... |
1769 |
&mask->enc_key_id, TCA_FLOWER_UNSPEC, |
f4d997fd6 net/sched: cls_fl... |
1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 |
sizeof(key->enc_key_id)) || fl_dump_key_val(skb, &key->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT, &mask->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK, sizeof(key->enc_tp.src)) || fl_dump_key_val(skb, &key->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT, &mask->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK, |
0e2c17b64 net/sched: cls_fl... |
1780 |
sizeof(key->enc_tp.dst)) || |
0a6e77784 net/sched: allow ... |
1781 1782 |
fl_dump_key_ip(skb, true, &key->enc_ip, &mask->enc_ip) || fl_dump_key_enc_opt(skb, &key->enc_opts, &mask->enc_opts)) |
bc3103f1e net/sched: cls_fl... |
1783 |
goto nla_put_failure; |
faa3ffce7 net/sched: cls_fl... |
1784 1785 |
if (fl_dump_key_flags(skb, key->control.flags, mask->control.flags)) goto nla_put_failure; |
f5749081f net: sched: cls_f... |
1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 |
return 0; nla_put_failure: return -EMSGSIZE; } static int fl_dump(struct net *net, struct tcf_proto *tp, void *fh, struct sk_buff *skb, struct tcmsg *t) { struct cls_fl_filter *f = fh; struct nlattr *nest; struct fl_flow_key *key, *mask; if (!f) return skb->len; t->tcm_handle = f->handle; nest = nla_nest_start(skb, TCA_OPTIONS); if (!nest) goto nla_put_failure; if (f->res.classid && nla_put_u32(skb, TCA_FLOWER_CLASSID, f->res.classid)) goto nla_put_failure; key = &f->key; mask = &f->mask->key; if (fl_dump_key(skb, net, key, mask)) goto nla_put_failure; if (!tc_skip_hw(f->flags)) fl_hw_update_stats(tp, f); |
749e6720d net/sched: cls_fl... |
1820 1821 |
if (f->flags && nla_put_u32(skb, TCA_FLOWER_FLAGS, f->flags)) goto nla_put_failure; |
e69985c67 net/sched: cls_fl... |
1822 |
|
77b9900ef tc: introduce Flo... |
1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 |
if (tcf_exts_dump(skb, &f->exts)) goto nla_put_failure; nla_nest_end(skb, nest); if (tcf_exts_dump_stats(skb, &f->exts) < 0) goto nla_put_failure; return skb->len; nla_put_failure: nla_nest_cancel(skb, nest); return -1; } |
b95ec7eb3 net: sched: cls_f... |
1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 |
static int fl_tmplt_dump(struct sk_buff *skb, struct net *net, void *tmplt_priv) { struct fl_flow_tmplt *tmplt = tmplt_priv; struct fl_flow_key *key, *mask; struct nlattr *nest; nest = nla_nest_start(skb, TCA_OPTIONS); if (!nest) goto nla_put_failure; key = &tmplt->dummy_key; mask = &tmplt->mask; if (fl_dump_key(skb, net, key, mask)) goto nla_put_failure; nla_nest_end(skb, nest); return skb->len; nla_put_failure: nla_nest_cancel(skb, nest); return -EMSGSIZE; } |
07d79fc7d net_sched: add re... |
1861 1862 1863 1864 1865 1866 1867 |
static void fl_bind_class(void *fh, u32 classid, unsigned long cl) { struct cls_fl_filter *f = fh; if (f && f->res.classid == classid) f->res.class = cl; } |
77b9900ef tc: introduce Flo... |
1868 1869 1870 1871 1872 1873 1874 1875 1876 |
static struct tcf_proto_ops cls_fl_ops __read_mostly = { .kind = "flower", .classify = fl_classify, .init = fl_init, .destroy = fl_destroy, .get = fl_get, .change = fl_change, .delete = fl_delete, .walk = fl_walk, |
31533cba4 net: sched: cls_f... |
1877 |
.reoffload = fl_reoffload, |
77b9900ef tc: introduce Flo... |
1878 |
.dump = fl_dump, |
07d79fc7d net_sched: add re... |
1879 |
.bind_class = fl_bind_class, |
b95ec7eb3 net: sched: cls_f... |
1880 1881 1882 |
.tmplt_create = fl_tmplt_create, .tmplt_destroy = fl_tmplt_destroy, .tmplt_dump = fl_tmplt_dump, |
77b9900ef tc: introduce Flo... |
1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 |
.owner = THIS_MODULE, }; static int __init cls_fl_init(void) { return register_tcf_proto_ops(&cls_fl_ops); } static void __exit cls_fl_exit(void) { unregister_tcf_proto_ops(&cls_fl_ops); } module_init(cls_fl_init); module_exit(cls_fl_exit); MODULE_AUTHOR("Jiri Pirko <jiri@resnulli.us>"); MODULE_DESCRIPTION("Flower classifier"); MODULE_LICENSE("GPL v2"); |