12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 277b9900eSJiri Pirko /* 377b9900eSJiri Pirko * net/sched/cls_flower.c Flower classifier 477b9900eSJiri Pirko * 577b9900eSJiri Pirko * Copyright (c) 2015 Jiri Pirko <jiri@resnulli.us> 677b9900eSJiri Pirko */ 777b9900eSJiri Pirko 877b9900eSJiri Pirko #include <linux/kernel.h> 977b9900eSJiri Pirko #include <linux/init.h> 1077b9900eSJiri Pirko #include <linux/module.h> 1177b9900eSJiri Pirko #include <linux/rhashtable.h> 12d9363774SDaniel Borkmann #include <linux/workqueue.h> 1306177558SVlad Buslov #include <linux/refcount.h> 1477b9900eSJiri Pirko 1577b9900eSJiri Pirko #include <linux/if_ether.h> 1677b9900eSJiri Pirko #include <linux/in6.h> 1777b9900eSJiri Pirko #include <linux/ip.h> 18a577d8f7SBenjamin LaHaise #include <linux/mpls.h> 1977b9900eSJiri Pirko 2077b9900eSJiri Pirko #include <net/sch_generic.h> 2177b9900eSJiri Pirko #include <net/pkt_cls.h> 2277b9900eSJiri Pirko #include <net/ip.h> 2377b9900eSJiri Pirko #include <net/flow_dissector.h> 240a6e7778SPieter Jansen van Vuuren #include <net/geneve.h> 25d8f9dfaeSXin Long #include <net/vxlan.h> 2679b1011cSXin Long #include <net/erspan.h> 2777b9900eSJiri Pirko 28bc3103f1SAmir Vadai #include <net/dst.h> 29bc3103f1SAmir Vadai #include <net/dst_metadata.h> 30bc3103f1SAmir Vadai 31e0ace68aSPaul Blakey #include <uapi/linux/netfilter/nf_conntrack_common.h> 32e0ace68aSPaul Blakey 331bcc51acSwenxu #define TCA_FLOWER_KEY_CT_FLAGS_MAX \ 341bcc51acSwenxu ((__TCA_FLOWER_KEY_CT_FLAGS_MAX - 1) << 1) 351bcc51acSwenxu #define TCA_FLOWER_KEY_CT_FLAGS_MASK \ 361bcc51acSwenxu (TCA_FLOWER_KEY_CT_FLAGS_MAX - 1) 371bcc51acSwenxu 3877b9900eSJiri Pirko struct fl_flow_key { 398212ed77SJiri Pirko struct flow_dissector_key_meta meta; 4042aecaa9STom Herbert struct flow_dissector_key_control control; 41bc3103f1SAmir Vadai struct flow_dissector_key_control enc_control; 4277b9900eSJiri Pirko struct flow_dissector_key_basic basic; 4377b9900eSJiri Pirko struct flow_dissector_key_eth_addrs eth; 449399ae9aSHadar Hen Zion struct flow_dissector_key_vlan vlan; 45d64efd09SJianbo Liu struct flow_dissector_key_vlan cvlan; 4677b9900eSJiri Pirko union { 47c3f83241STom Herbert struct flow_dissector_key_ipv4_addrs ipv4; 4877b9900eSJiri Pirko struct flow_dissector_key_ipv6_addrs ipv6; 4977b9900eSJiri Pirko }; 5077b9900eSJiri Pirko struct flow_dissector_key_ports tp; 517b684884SSimon Horman struct flow_dissector_key_icmp icmp; 5299d31326SSimon Horman struct flow_dissector_key_arp arp; 53bc3103f1SAmir Vadai struct flow_dissector_key_keyid enc_key_id; 54bc3103f1SAmir Vadai union { 55bc3103f1SAmir Vadai struct flow_dissector_key_ipv4_addrs enc_ipv4; 56bc3103f1SAmir Vadai struct flow_dissector_key_ipv6_addrs enc_ipv6; 57bc3103f1SAmir Vadai }; 58f4d997fdSHadar Hen Zion struct flow_dissector_key_ports enc_tp; 59a577d8f7SBenjamin LaHaise struct flow_dissector_key_mpls mpls; 60fdfc7dd6SJiri Pirko struct flow_dissector_key_tcp tcp; 614d80cc0aSOr Gerlitz struct flow_dissector_key_ip ip; 620e2c17b6SOr Gerlitz struct flow_dissector_key_ip enc_ip; 630a6e7778SPieter Jansen van Vuuren struct flow_dissector_key_enc_opts enc_opts; 648ffb055bSYoshiki Komachi union { 658ffb055bSYoshiki Komachi struct flow_dissector_key_ports tp; 668ffb055bSYoshiki Komachi struct { 675c72299fSAmritha Nambiar struct flow_dissector_key_ports tp_min; 685c72299fSAmritha Nambiar struct flow_dissector_key_ports tp_max; 698ffb055bSYoshiki Komachi }; 708ffb055bSYoshiki Komachi } tp_range; 71e0ace68aSPaul Blakey struct flow_dissector_key_ct ct; 725923b8f7SAriel Levkovich struct flow_dissector_key_hash hash; 7377b9900eSJiri Pirko } __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */ 7477b9900eSJiri Pirko 7577b9900eSJiri Pirko struct fl_flow_mask_range { 7677b9900eSJiri Pirko unsigned short int start; 7777b9900eSJiri Pirko unsigned short int end; 7877b9900eSJiri Pirko }; 7977b9900eSJiri Pirko 8077b9900eSJiri Pirko struct fl_flow_mask { 8177b9900eSJiri Pirko struct fl_flow_key key; 8277b9900eSJiri Pirko struct fl_flow_mask_range range; 835c72299fSAmritha Nambiar u32 flags; 8405cd271fSPaul Blakey struct rhash_head ht_node; 8505cd271fSPaul Blakey struct rhashtable ht; 8605cd271fSPaul Blakey struct rhashtable_params filter_ht_params; 8705cd271fSPaul Blakey struct flow_dissector dissector; 8805cd271fSPaul Blakey struct list_head filters; 8944a5cd43SPaolo Abeni struct rcu_work rwork; 9005cd271fSPaul Blakey struct list_head list; 91f48ef4d5SVlad Buslov refcount_t refcnt; 9277b9900eSJiri Pirko }; 9377b9900eSJiri Pirko 94b95ec7ebSJiri Pirko struct fl_flow_tmplt { 95b95ec7ebSJiri Pirko struct fl_flow_key dummy_key; 96b95ec7ebSJiri Pirko struct fl_flow_key mask; 97b95ec7ebSJiri Pirko struct flow_dissector dissector; 98b95ec7ebSJiri Pirko struct tcf_chain *chain; 99b95ec7ebSJiri Pirko }; 100b95ec7ebSJiri Pirko 10177b9900eSJiri Pirko struct cls_fl_head { 10277b9900eSJiri Pirko struct rhashtable ht; 103259e60f9SVlad Buslov spinlock_t masks_lock; /* Protect masks list */ 10405cd271fSPaul Blakey struct list_head masks; 105c049d56eSVlad Buslov struct list_head hw_filters; 106aaa908ffSCong Wang struct rcu_work rwork; 107c15ab236SChris Mi struct idr handle_idr; 108d9363774SDaniel Borkmann }; 10977b9900eSJiri Pirko 11077b9900eSJiri Pirko struct cls_fl_filter { 11105cd271fSPaul Blakey struct fl_flow_mask *mask; 11277b9900eSJiri Pirko struct rhash_head ht_node; 11377b9900eSJiri Pirko struct fl_flow_key mkey; 11477b9900eSJiri Pirko struct tcf_exts exts; 11577b9900eSJiri Pirko struct tcf_result res; 11677b9900eSJiri Pirko struct fl_flow_key key; 11777b9900eSJiri Pirko struct list_head list; 118c049d56eSVlad Buslov struct list_head hw_list; 11977b9900eSJiri Pirko u32 handle; 120e69985c6SAmir Vadai u32 flags; 12186c55361SVlad Buslov u32 in_hw_count; 122aaa908ffSCong Wang struct rcu_work rwork; 1237091d8c7SHadar Hen Zion struct net_device *hw_dev; 12406177558SVlad Buslov /* Flower classifier is unlocked, which means that its reference counter 12506177558SVlad Buslov * can be changed concurrently without any kind of external 12606177558SVlad Buslov * synchronization. Use atomic reference counter to be concurrency-safe. 12706177558SVlad Buslov */ 12806177558SVlad Buslov refcount_t refcnt; 129b2552b8cSVlad Buslov bool deleted; 13077b9900eSJiri Pirko }; 13177b9900eSJiri Pirko 13205cd271fSPaul Blakey static const struct rhashtable_params mask_ht_params = { 13305cd271fSPaul Blakey .key_offset = offsetof(struct fl_flow_mask, key), 13405cd271fSPaul Blakey .key_len = sizeof(struct fl_flow_key), 13505cd271fSPaul Blakey .head_offset = offsetof(struct fl_flow_mask, ht_node), 13605cd271fSPaul Blakey .automatic_shrinking = true, 13705cd271fSPaul Blakey }; 13805cd271fSPaul Blakey 13977b9900eSJiri Pirko static unsigned short int fl_mask_range(const struct fl_flow_mask *mask) 14077b9900eSJiri Pirko { 14177b9900eSJiri Pirko return mask->range.end - mask->range.start; 14277b9900eSJiri Pirko } 14377b9900eSJiri Pirko 14477b9900eSJiri Pirko static void fl_mask_update_range(struct fl_flow_mask *mask) 14577b9900eSJiri Pirko { 14677b9900eSJiri Pirko const u8 *bytes = (const u8 *) &mask->key; 14777b9900eSJiri Pirko size_t size = sizeof(mask->key); 14805cd271fSPaul Blakey size_t i, first = 0, last; 14977b9900eSJiri Pirko 15005cd271fSPaul Blakey for (i = 0; i < size; i++) { 15177b9900eSJiri Pirko if (bytes[i]) { 15277b9900eSJiri Pirko first = i; 15305cd271fSPaul Blakey break; 15405cd271fSPaul Blakey } 15505cd271fSPaul Blakey } 15605cd271fSPaul Blakey last = first; 15705cd271fSPaul Blakey for (i = size - 1; i != first; i--) { 15805cd271fSPaul Blakey if (bytes[i]) { 15977b9900eSJiri Pirko last = i; 16005cd271fSPaul Blakey break; 16177b9900eSJiri Pirko } 16277b9900eSJiri Pirko } 16377b9900eSJiri Pirko mask->range.start = rounddown(first, sizeof(long)); 16477b9900eSJiri Pirko mask->range.end = roundup(last + 1, sizeof(long)); 16577b9900eSJiri Pirko } 16677b9900eSJiri Pirko 16777b9900eSJiri Pirko static void *fl_key_get_start(struct fl_flow_key *key, 16877b9900eSJiri Pirko const struct fl_flow_mask *mask) 16977b9900eSJiri Pirko { 17077b9900eSJiri Pirko return (u8 *) key + mask->range.start; 17177b9900eSJiri Pirko } 17277b9900eSJiri Pirko 17377b9900eSJiri Pirko static void fl_set_masked_key(struct fl_flow_key *mkey, struct fl_flow_key *key, 17477b9900eSJiri Pirko struct fl_flow_mask *mask) 17577b9900eSJiri Pirko { 17677b9900eSJiri Pirko const long *lkey = fl_key_get_start(key, mask); 17777b9900eSJiri Pirko const long *lmask = fl_key_get_start(&mask->key, mask); 17877b9900eSJiri Pirko long *lmkey = fl_key_get_start(mkey, mask); 17977b9900eSJiri Pirko int i; 18077b9900eSJiri Pirko 18177b9900eSJiri Pirko for (i = 0; i < fl_mask_range(mask); i += sizeof(long)) 18277b9900eSJiri Pirko *lmkey++ = *lkey++ & *lmask++; 18377b9900eSJiri Pirko } 18477b9900eSJiri Pirko 185b95ec7ebSJiri Pirko static bool fl_mask_fits_tmplt(struct fl_flow_tmplt *tmplt, 186b95ec7ebSJiri Pirko struct fl_flow_mask *mask) 187b95ec7ebSJiri Pirko { 188b95ec7ebSJiri Pirko const long *lmask = fl_key_get_start(&mask->key, mask); 189b95ec7ebSJiri Pirko const long *ltmplt; 190b95ec7ebSJiri Pirko int i; 191b95ec7ebSJiri Pirko 192b95ec7ebSJiri Pirko if (!tmplt) 193b95ec7ebSJiri Pirko return true; 194b95ec7ebSJiri Pirko ltmplt = fl_key_get_start(&tmplt->mask, mask); 195b95ec7ebSJiri Pirko for (i = 0; i < fl_mask_range(mask); i += sizeof(long)) { 196b95ec7ebSJiri Pirko if (~*ltmplt++ & *lmask++) 197b95ec7ebSJiri Pirko return false; 198b95ec7ebSJiri Pirko } 199b95ec7ebSJiri Pirko return true; 200b95ec7ebSJiri Pirko } 201b95ec7ebSJiri Pirko 20277b9900eSJiri Pirko static void fl_clear_masked_range(struct fl_flow_key *key, 20377b9900eSJiri Pirko struct fl_flow_mask *mask) 20477b9900eSJiri Pirko { 20577b9900eSJiri Pirko memset(fl_key_get_start(key, mask), 0, fl_mask_range(mask)); 20677b9900eSJiri Pirko } 20777b9900eSJiri Pirko 2085c72299fSAmritha Nambiar static bool fl_range_port_dst_cmp(struct cls_fl_filter *filter, 2095c72299fSAmritha Nambiar struct fl_flow_key *key, 2105c72299fSAmritha Nambiar struct fl_flow_key *mkey) 2115c72299fSAmritha Nambiar { 2126215afcbSVladimir Oltean u16 min_mask, max_mask, min_val, max_val; 2135c72299fSAmritha Nambiar 2146215afcbSVladimir Oltean min_mask = ntohs(filter->mask->key.tp_range.tp_min.dst); 2156215afcbSVladimir Oltean max_mask = ntohs(filter->mask->key.tp_range.tp_max.dst); 2166215afcbSVladimir Oltean min_val = ntohs(filter->key.tp_range.tp_min.dst); 2176215afcbSVladimir Oltean max_val = ntohs(filter->key.tp_range.tp_max.dst); 2185c72299fSAmritha Nambiar 2195c72299fSAmritha Nambiar if (min_mask && max_mask) { 2206215afcbSVladimir Oltean if (ntohs(key->tp_range.tp.dst) < min_val || 2216215afcbSVladimir Oltean ntohs(key->tp_range.tp.dst) > max_val) 2225c72299fSAmritha Nambiar return false; 2235c72299fSAmritha Nambiar 2245c72299fSAmritha Nambiar /* skb does not have min and max values */ 2258ffb055bSYoshiki Komachi mkey->tp_range.tp_min.dst = filter->mkey.tp_range.tp_min.dst; 2268ffb055bSYoshiki Komachi mkey->tp_range.tp_max.dst = filter->mkey.tp_range.tp_max.dst; 2275c72299fSAmritha Nambiar } 2285c72299fSAmritha Nambiar return true; 2295c72299fSAmritha Nambiar } 2305c72299fSAmritha Nambiar 2315c72299fSAmritha Nambiar static bool fl_range_port_src_cmp(struct cls_fl_filter *filter, 2325c72299fSAmritha Nambiar struct fl_flow_key *key, 2335c72299fSAmritha Nambiar struct fl_flow_key *mkey) 2345c72299fSAmritha Nambiar { 2356215afcbSVladimir Oltean u16 min_mask, max_mask, min_val, max_val; 2365c72299fSAmritha Nambiar 2376215afcbSVladimir Oltean min_mask = ntohs(filter->mask->key.tp_range.tp_min.src); 2386215afcbSVladimir Oltean max_mask = ntohs(filter->mask->key.tp_range.tp_max.src); 2396215afcbSVladimir Oltean min_val = ntohs(filter->key.tp_range.tp_min.src); 2406215afcbSVladimir Oltean max_val = ntohs(filter->key.tp_range.tp_max.src); 2415c72299fSAmritha Nambiar 2425c72299fSAmritha Nambiar if (min_mask && max_mask) { 2436215afcbSVladimir Oltean if (ntohs(key->tp_range.tp.src) < min_val || 2446215afcbSVladimir Oltean ntohs(key->tp_range.tp.src) > max_val) 2455c72299fSAmritha Nambiar return false; 2465c72299fSAmritha Nambiar 2475c72299fSAmritha Nambiar /* skb does not have min and max values */ 2488ffb055bSYoshiki Komachi mkey->tp_range.tp_min.src = filter->mkey.tp_range.tp_min.src; 2498ffb055bSYoshiki Komachi mkey->tp_range.tp_max.src = filter->mkey.tp_range.tp_max.src; 2505c72299fSAmritha Nambiar } 2515c72299fSAmritha Nambiar return true; 2525c72299fSAmritha Nambiar } 2535c72299fSAmritha Nambiar 2545c72299fSAmritha Nambiar static struct cls_fl_filter *__fl_lookup(struct fl_flow_mask *mask, 255a3308d8fSPaul Blakey struct fl_flow_key *mkey) 256a3308d8fSPaul Blakey { 25705cd271fSPaul Blakey return rhashtable_lookup_fast(&mask->ht, fl_key_get_start(mkey, mask), 25805cd271fSPaul Blakey mask->filter_ht_params); 259a3308d8fSPaul Blakey } 260a3308d8fSPaul Blakey 2615c72299fSAmritha Nambiar static struct cls_fl_filter *fl_lookup_range(struct fl_flow_mask *mask, 2625c72299fSAmritha Nambiar struct fl_flow_key *mkey, 2635c72299fSAmritha Nambiar struct fl_flow_key *key) 2645c72299fSAmritha Nambiar { 2655c72299fSAmritha Nambiar struct cls_fl_filter *filter, *f; 2665c72299fSAmritha Nambiar 2675c72299fSAmritha Nambiar list_for_each_entry_rcu(filter, &mask->filters, list) { 2685c72299fSAmritha Nambiar if (!fl_range_port_dst_cmp(filter, key, mkey)) 2695c72299fSAmritha Nambiar continue; 2705c72299fSAmritha Nambiar 2715c72299fSAmritha Nambiar if (!fl_range_port_src_cmp(filter, key, mkey)) 2725c72299fSAmritha Nambiar continue; 2735c72299fSAmritha Nambiar 2745c72299fSAmritha Nambiar f = __fl_lookup(mask, mkey); 2755c72299fSAmritha Nambiar if (f) 2765c72299fSAmritha Nambiar return f; 2775c72299fSAmritha Nambiar } 2785c72299fSAmritha Nambiar return NULL; 2795c72299fSAmritha Nambiar } 2805c72299fSAmritha Nambiar 2810af413bdSArnd Bergmann static noinline_for_stack 2820af413bdSArnd Bergmann struct cls_fl_filter *fl_mask_lookup(struct fl_flow_mask *mask, struct fl_flow_key *key) 2835c72299fSAmritha Nambiar { 2840af413bdSArnd Bergmann struct fl_flow_key mkey; 2855c72299fSAmritha Nambiar 2860af413bdSArnd Bergmann fl_set_masked_key(&mkey, key, mask); 2870af413bdSArnd Bergmann if ((mask->flags & TCA_FLOWER_MASK_FLAGS_RANGE)) 2880af413bdSArnd Bergmann return fl_lookup_range(mask, &mkey, key); 2890af413bdSArnd Bergmann 2900af413bdSArnd Bergmann return __fl_lookup(mask, &mkey); 2915c72299fSAmritha Nambiar } 2925c72299fSAmritha Nambiar 293e0ace68aSPaul Blakey static u16 fl_ct_info_to_flower_map[] = { 294e0ace68aSPaul Blakey [IP_CT_ESTABLISHED] = TCA_FLOWER_KEY_CT_FLAGS_TRACKED | 295e0ace68aSPaul Blakey TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED, 296e0ace68aSPaul Blakey [IP_CT_RELATED] = TCA_FLOWER_KEY_CT_FLAGS_TRACKED | 297e0ace68aSPaul Blakey TCA_FLOWER_KEY_CT_FLAGS_RELATED, 298e0ace68aSPaul Blakey [IP_CT_ESTABLISHED_REPLY] = TCA_FLOWER_KEY_CT_FLAGS_TRACKED | 2998c85d18cSPaul Blakey TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED | 3008c85d18cSPaul Blakey TCA_FLOWER_KEY_CT_FLAGS_REPLY, 301e0ace68aSPaul Blakey [IP_CT_RELATED_REPLY] = TCA_FLOWER_KEY_CT_FLAGS_TRACKED | 3028c85d18cSPaul Blakey TCA_FLOWER_KEY_CT_FLAGS_RELATED | 3038c85d18cSPaul Blakey TCA_FLOWER_KEY_CT_FLAGS_REPLY, 304e0ace68aSPaul Blakey [IP_CT_NEW] = TCA_FLOWER_KEY_CT_FLAGS_TRACKED | 305e0ace68aSPaul Blakey TCA_FLOWER_KEY_CT_FLAGS_NEW, 306e0ace68aSPaul Blakey }; 307e0ace68aSPaul Blakey 30877b9900eSJiri Pirko static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp, 30977b9900eSJiri Pirko struct tcf_result *res) 31077b9900eSJiri Pirko { 31177b9900eSJiri Pirko struct cls_fl_head *head = rcu_dereference_bh(tp->root); 3127baf2429Swenxu bool post_ct = qdisc_skb_cb(skb)->post_ct; 313e0ace68aSPaul Blakey struct fl_flow_key skb_key; 314e0ace68aSPaul Blakey struct fl_flow_mask *mask; 315e0ace68aSPaul Blakey struct cls_fl_filter *f; 31677b9900eSJiri Pirko 31705cd271fSPaul Blakey list_for_each_entry_rcu(mask, &head->masks, list) { 3188a9093c7SJason Baron flow_dissector_init_keys(&skb_key.control, &skb_key.basic); 31905cd271fSPaul Blakey fl_clear_masked_range(&skb_key, mask); 320bc3103f1SAmir Vadai 3218212ed77SJiri Pirko skb_flow_dissect_meta(skb, &mask->dissector, &skb_key); 32205cd271fSPaul Blakey /* skb_flow_dissect() does not set n_proto in case an unknown 32305cd271fSPaul Blakey * protocol, so do it rather here. 32477b9900eSJiri Pirko */ 325d7bf2ebeSToke Høiland-Jørgensen skb_key.basic.n_proto = skb_protocol(skb, false); 32605cd271fSPaul Blakey skb_flow_dissect_tunnel_info(skb, &mask->dissector, &skb_key); 327e0ace68aSPaul Blakey skb_flow_dissect_ct(skb, &mask->dissector, &skb_key, 328e0ace68aSPaul Blakey fl_ct_info_to_flower_map, 3297baf2429Swenxu ARRAY_SIZE(fl_ct_info_to_flower_map), 3307baf2429Swenxu post_ct); 3315923b8f7SAriel Levkovich skb_flow_dissect_hash(skb, &mask->dissector, &skb_key); 33205cd271fSPaul Blakey skb_flow_dissect(skb, &mask->dissector, &skb_key, 0); 33377b9900eSJiri Pirko 3340af413bdSArnd Bergmann f = fl_mask_lookup(mask, &skb_key); 335e8eb36cdSAmir Vadai if (f && !tc_skip_sw(f->flags)) { 33677b9900eSJiri Pirko *res = f->res; 33777b9900eSJiri Pirko return tcf_exts_exec(skb, &f->exts, res); 33877b9900eSJiri Pirko } 33905cd271fSPaul Blakey } 34077b9900eSJiri Pirko return -1; 34177b9900eSJiri Pirko } 34277b9900eSJiri Pirko 34377b9900eSJiri Pirko static int fl_init(struct tcf_proto *tp) 34477b9900eSJiri Pirko { 34577b9900eSJiri Pirko struct cls_fl_head *head; 34677b9900eSJiri Pirko 34777b9900eSJiri Pirko head = kzalloc(sizeof(*head), GFP_KERNEL); 34877b9900eSJiri Pirko if (!head) 34977b9900eSJiri Pirko return -ENOBUFS; 35077b9900eSJiri Pirko 351259e60f9SVlad Buslov spin_lock_init(&head->masks_lock); 35205cd271fSPaul Blakey INIT_LIST_HEAD_RCU(&head->masks); 353c049d56eSVlad Buslov INIT_LIST_HEAD(&head->hw_filters); 35477b9900eSJiri Pirko rcu_assign_pointer(tp->root, head); 355c15ab236SChris Mi idr_init(&head->handle_idr); 35677b9900eSJiri Pirko 35705cd271fSPaul Blakey return rhashtable_init(&head->ht, &mask_ht_params); 35805cd271fSPaul Blakey } 35905cd271fSPaul Blakey 36099815f50SVlad Buslov static void fl_mask_free(struct fl_flow_mask *mask, bool mask_init_done) 36144a5cd43SPaolo Abeni { 36299815f50SVlad Buslov /* temporary masks don't have their filters list and ht initialized */ 36399815f50SVlad Buslov if (mask_init_done) { 364f48ef4d5SVlad Buslov WARN_ON(!list_empty(&mask->filters)); 36544a5cd43SPaolo Abeni rhashtable_destroy(&mask->ht); 36699815f50SVlad Buslov } 36744a5cd43SPaolo Abeni kfree(mask); 36844a5cd43SPaolo Abeni } 36944a5cd43SPaolo Abeni 37044a5cd43SPaolo Abeni static void fl_mask_free_work(struct work_struct *work) 37144a5cd43SPaolo Abeni { 37244a5cd43SPaolo Abeni struct fl_flow_mask *mask = container_of(to_rcu_work(work), 37344a5cd43SPaolo Abeni struct fl_flow_mask, rwork); 37444a5cd43SPaolo Abeni 37599815f50SVlad Buslov fl_mask_free(mask, true); 37699815f50SVlad Buslov } 37799815f50SVlad Buslov 37899815f50SVlad Buslov static void fl_uninit_mask_free_work(struct work_struct *work) 37999815f50SVlad Buslov { 38099815f50SVlad Buslov struct fl_flow_mask *mask = container_of(to_rcu_work(work), 38199815f50SVlad Buslov struct fl_flow_mask, rwork); 38299815f50SVlad Buslov 38399815f50SVlad Buslov fl_mask_free(mask, false); 38444a5cd43SPaolo Abeni } 38544a5cd43SPaolo Abeni 3869994677cSVlad Buslov static bool fl_mask_put(struct cls_fl_head *head, struct fl_flow_mask *mask) 38705cd271fSPaul Blakey { 388f48ef4d5SVlad Buslov if (!refcount_dec_and_test(&mask->refcnt)) 38905cd271fSPaul Blakey return false; 39005cd271fSPaul Blakey 39105cd271fSPaul Blakey rhashtable_remove_fast(&head->ht, &mask->ht_node, mask_ht_params); 392259e60f9SVlad Buslov 393259e60f9SVlad Buslov spin_lock(&head->masks_lock); 39405cd271fSPaul Blakey list_del_rcu(&mask->list); 395259e60f9SVlad Buslov spin_unlock(&head->masks_lock); 396259e60f9SVlad Buslov 39744a5cd43SPaolo Abeni tcf_queue_work(&mask->rwork, fl_mask_free_work); 39805cd271fSPaul Blakey 39905cd271fSPaul Blakey return true; 40077b9900eSJiri Pirko } 40177b9900eSJiri Pirko 402c049d56eSVlad Buslov static struct cls_fl_head *fl_head_dereference(struct tcf_proto *tp) 403c049d56eSVlad Buslov { 404c049d56eSVlad Buslov /* Flower classifier only changes root pointer during init and destroy. 405c049d56eSVlad Buslov * Users must obtain reference to tcf_proto instance before calling its 406c049d56eSVlad Buslov * API, so tp->root pointer is protected from concurrent call to 407c049d56eSVlad Buslov * fl_destroy() by reference counting. 408c049d56eSVlad Buslov */ 409c049d56eSVlad Buslov return rcu_dereference_raw(tp->root); 410c049d56eSVlad Buslov } 411c049d56eSVlad Buslov 4120dadc117SCong Wang static void __fl_destroy_filter(struct cls_fl_filter *f) 4130dadc117SCong Wang { 4140dadc117SCong Wang tcf_exts_destroy(&f->exts); 4150dadc117SCong Wang tcf_exts_put_net(&f->exts); 4160dadc117SCong Wang kfree(f); 4170dadc117SCong Wang } 4180dadc117SCong Wang 4190552c8afSCong Wang static void fl_destroy_filter_work(struct work_struct *work) 4200552c8afSCong Wang { 421aaa908ffSCong Wang struct cls_fl_filter *f = container_of(to_rcu_work(work), 422aaa908ffSCong Wang struct cls_fl_filter, rwork); 4230552c8afSCong Wang 4240dadc117SCong Wang __fl_destroy_filter(f); 4250552c8afSCong Wang } 4260552c8afSCong Wang 4271b0f8037SJakub Kicinski static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f, 428c24e43d8SVlad Buslov bool rtnl_held, struct netlink_ext_ack *extack) 4295b33f488SAmir Vadai { 430208c0f4bSJiri Pirko struct tcf_block *block = tp->chain->block; 431f9e30088SPablo Neira Ayuso struct flow_cls_offload cls_flower = {}; 4325b33f488SAmir Vadai 433d6787147SPieter Jansen van Vuuren tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack); 434f9e30088SPablo Neira Ayuso cls_flower.command = FLOW_CLS_DESTROY; 435de4784caSJiri Pirko cls_flower.cookie = (unsigned long) f; 4365b33f488SAmir Vadai 43740119211SVlad Buslov tc_setup_cb_destroy(block, tp, TC_SETUP_CLSFLOWER, &cls_flower, false, 438918190f5SVlad Buslov &f->flags, &f->in_hw_count, rtnl_held); 439c24e43d8SVlad Buslov 4405b33f488SAmir Vadai } 4415b33f488SAmir Vadai 442e8eb36cdSAmir Vadai static int fl_hw_replace_filter(struct tcf_proto *tp, 443c24e43d8SVlad Buslov struct cls_fl_filter *f, bool rtnl_held, 44441002038SQuentin Monnet struct netlink_ext_ack *extack) 4455b33f488SAmir Vadai { 446208c0f4bSJiri Pirko struct tcf_block *block = tp->chain->block; 447f9e30088SPablo Neira Ayuso struct flow_cls_offload cls_flower = {}; 448717503b9SJiri Pirko bool skip_sw = tc_skip_sw(f->flags); 449c24e43d8SVlad Buslov int err = 0; 450c24e43d8SVlad Buslov 451e3ab786bSPablo Neira Ayuso cls_flower.rule = flow_rule_alloc(tcf_exts_num_actions(&f->exts)); 452918190f5SVlad Buslov if (!cls_flower.rule) 453918190f5SVlad Buslov return -ENOMEM; 4548f256622SPablo Neira Ayuso 455d6787147SPieter Jansen van Vuuren tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack); 456f9e30088SPablo Neira Ayuso cls_flower.command = FLOW_CLS_REPLACE; 457de4784caSJiri Pirko cls_flower.cookie = (unsigned long) f; 4588f256622SPablo Neira Ayuso cls_flower.rule->match.dissector = &f->mask->dissector; 4598f256622SPablo Neira Ayuso cls_flower.rule->match.mask = &f->mask->key; 4608f256622SPablo Neira Ayuso cls_flower.rule->match.key = &f->mkey; 461384c181eSAmritha Nambiar cls_flower.classid = f->res.classid; 4625b33f488SAmir Vadai 463b15e7a6eSVlad Buslov err = tc_setup_flow_action(&cls_flower.rule->action, &f->exts); 4643a7b6861SPablo Neira Ayuso if (err) { 4653a7b6861SPablo Neira Ayuso kfree(cls_flower.rule); 466918190f5SVlad Buslov if (skip_sw) { 4671f15bb4fSVlad Buslov NL_SET_ERR_MSG_MOD(extack, "Failed to setup flow action"); 468918190f5SVlad Buslov return err; 469918190f5SVlad Buslov } 470918190f5SVlad Buslov return 0; 4711f15bb4fSVlad Buslov } 4723a7b6861SPablo Neira Ayuso 47340119211SVlad Buslov err = tc_setup_cb_add(block, tp, TC_SETUP_CLSFLOWER, &cls_flower, 474918190f5SVlad Buslov skip_sw, &f->flags, &f->in_hw_count, rtnl_held); 4755a6ff4b1SVlad Buslov tc_cleanup_flow_action(&cls_flower.rule->action); 4768f256622SPablo Neira Ayuso kfree(cls_flower.rule); 4778f256622SPablo Neira Ayuso 47840119211SVlad Buslov if (err) { 479918190f5SVlad Buslov fl_hw_destroy_filter(tp, f, rtnl_held, NULL); 480c24e43d8SVlad Buslov return err; 481c24e43d8SVlad Buslov } 482c24e43d8SVlad Buslov 483918190f5SVlad Buslov if (skip_sw && !(f->flags & TCA_CLS_FLAGS_IN_HW)) 484918190f5SVlad Buslov return -EINVAL; 485918190f5SVlad Buslov 486918190f5SVlad Buslov return 0; 487918190f5SVlad Buslov } 488918190f5SVlad Buslov 489c24e43d8SVlad Buslov static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f, 490c24e43d8SVlad Buslov bool rtnl_held) 49110cbc684SAmir Vadai { 492208c0f4bSJiri Pirko struct tcf_block *block = tp->chain->block; 493f9e30088SPablo Neira Ayuso struct flow_cls_offload cls_flower = {}; 49410cbc684SAmir Vadai 495d6787147SPieter Jansen van Vuuren tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, NULL); 496f9e30088SPablo Neira Ayuso cls_flower.command = FLOW_CLS_STATS; 497de4784caSJiri Pirko cls_flower.cookie = (unsigned long) f; 498384c181eSAmritha Nambiar cls_flower.classid = f->res.classid; 49910cbc684SAmir Vadai 500918190f5SVlad Buslov tc_setup_cb_call(block, TC_SETUP_CLSFLOWER, &cls_flower, false, 501918190f5SVlad Buslov rtnl_held); 5023b1903efSPablo Neira Ayuso 5033b1903efSPablo Neira Ayuso tcf_exts_stats_update(&f->exts, cls_flower.stats.bytes, 5043b1903efSPablo Neira Ayuso cls_flower.stats.pkts, 5054b61d3e8SPo Liu cls_flower.stats.drops, 50693a129ebSJiri Pirko cls_flower.stats.lastused, 50793a129ebSJiri Pirko cls_flower.stats.used_hw_stats, 50893a129ebSJiri Pirko cls_flower.stats.used_hw_stats_valid); 50910cbc684SAmir Vadai } 51010cbc684SAmir Vadai 51106177558SVlad Buslov static void __fl_put(struct cls_fl_filter *f) 51206177558SVlad Buslov { 51306177558SVlad Buslov if (!refcount_dec_and_test(&f->refcnt)) 51406177558SVlad Buslov return; 51506177558SVlad Buslov 51606177558SVlad Buslov if (tcf_exts_get_net(&f->exts)) 51706177558SVlad Buslov tcf_queue_work(&f->rwork, fl_destroy_filter_work); 51806177558SVlad Buslov else 51906177558SVlad Buslov __fl_destroy_filter(f); 52006177558SVlad Buslov } 52106177558SVlad Buslov 52206177558SVlad Buslov static struct cls_fl_filter *__fl_get(struct cls_fl_head *head, u32 handle) 52306177558SVlad Buslov { 52406177558SVlad Buslov struct cls_fl_filter *f; 52506177558SVlad Buslov 52606177558SVlad Buslov rcu_read_lock(); 52706177558SVlad Buslov f = idr_find(&head->handle_idr, handle); 52806177558SVlad Buslov if (f && !refcount_inc_not_zero(&f->refcnt)) 52906177558SVlad Buslov f = NULL; 53006177558SVlad Buslov rcu_read_unlock(); 53106177558SVlad Buslov 53206177558SVlad Buslov return f; 53306177558SVlad Buslov } 53406177558SVlad Buslov 535b2552b8cSVlad Buslov static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, 536c24e43d8SVlad Buslov bool *last, bool rtnl_held, 537c24e43d8SVlad Buslov struct netlink_ext_ack *extack) 53813fa876eSRoi Dayan { 539e474619aSVlad Buslov struct cls_fl_head *head = fl_head_dereference(tp); 540c15ab236SChris Mi 541b2552b8cSVlad Buslov *last = false; 542b2552b8cSVlad Buslov 5433d81e711SVlad Buslov spin_lock(&tp->lock); 5443d81e711SVlad Buslov if (f->deleted) { 5453d81e711SVlad Buslov spin_unlock(&tp->lock); 546b2552b8cSVlad Buslov return -ENOENT; 5473d81e711SVlad Buslov } 548b2552b8cSVlad Buslov 549b2552b8cSVlad Buslov f->deleted = true; 550b2552b8cSVlad Buslov rhashtable_remove_fast(&f->mask->ht, &f->ht_node, 551b2552b8cSVlad Buslov f->mask->filter_ht_params); 5529c160941SMatthew Wilcox idr_remove(&head->handle_idr, f->handle); 55313fa876eSRoi Dayan list_del_rcu(&f->list); 5543d81e711SVlad Buslov spin_unlock(&tp->lock); 5553d81e711SVlad Buslov 5569994677cSVlad Buslov *last = fl_mask_put(head, f->mask); 55779685219SHadar Hen Zion if (!tc_skip_hw(f->flags)) 558c24e43d8SVlad Buslov fl_hw_destroy_filter(tp, f, rtnl_held, extack); 55913fa876eSRoi Dayan tcf_unbind_filter(tp, &f->res); 56006177558SVlad Buslov __fl_put(f); 56105cd271fSPaul Blakey 562b2552b8cSVlad Buslov return 0; 56313fa876eSRoi Dayan } 56413fa876eSRoi Dayan 565d9363774SDaniel Borkmann static void fl_destroy_sleepable(struct work_struct *work) 566d9363774SDaniel Borkmann { 567aaa908ffSCong Wang struct cls_fl_head *head = container_of(to_rcu_work(work), 568aaa908ffSCong Wang struct cls_fl_head, 569aaa908ffSCong Wang rwork); 570de9dc650SPaul Blakey 571de9dc650SPaul Blakey rhashtable_destroy(&head->ht); 572d9363774SDaniel Borkmann kfree(head); 573d9363774SDaniel Borkmann module_put(THIS_MODULE); 574d9363774SDaniel Borkmann } 575d9363774SDaniel Borkmann 57612db03b6SVlad Buslov static void fl_destroy(struct tcf_proto *tp, bool rtnl_held, 57712db03b6SVlad Buslov struct netlink_ext_ack *extack) 57877b9900eSJiri Pirko { 579e474619aSVlad Buslov struct cls_fl_head *head = fl_head_dereference(tp); 58005cd271fSPaul Blakey struct fl_flow_mask *mask, *next_mask; 58177b9900eSJiri Pirko struct cls_fl_filter *f, *next; 582b2552b8cSVlad Buslov bool last; 58377b9900eSJiri Pirko 58405cd271fSPaul Blakey list_for_each_entry_safe(mask, next_mask, &head->masks, list) { 58505cd271fSPaul Blakey list_for_each_entry_safe(f, next, &mask->filters, list) { 586c24e43d8SVlad Buslov __fl_delete(tp, f, &last, rtnl_held, extack); 587b2552b8cSVlad Buslov if (last) 58805cd271fSPaul Blakey break; 58905cd271fSPaul Blakey } 59005cd271fSPaul Blakey } 591c15ab236SChris Mi idr_destroy(&head->handle_idr); 592d9363774SDaniel Borkmann 593d9363774SDaniel Borkmann __module_get(THIS_MODULE); 594aaa908ffSCong Wang tcf_queue_work(&head->rwork, fl_destroy_sleepable); 59577b9900eSJiri Pirko } 59677b9900eSJiri Pirko 59706177558SVlad Buslov static void fl_put(struct tcf_proto *tp, void *arg) 59806177558SVlad Buslov { 59906177558SVlad Buslov struct cls_fl_filter *f = arg; 60006177558SVlad Buslov 60106177558SVlad Buslov __fl_put(f); 60206177558SVlad Buslov } 60306177558SVlad Buslov 6048113c095SWANG Cong static void *fl_get(struct tcf_proto *tp, u32 handle) 60577b9900eSJiri Pirko { 606e474619aSVlad Buslov struct cls_fl_head *head = fl_head_dereference(tp); 60777b9900eSJiri Pirko 60806177558SVlad Buslov return __fl_get(head, handle); 60977b9900eSJiri Pirko } 61077b9900eSJiri Pirko 61177b9900eSJiri Pirko static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = { 61277b9900eSJiri Pirko [TCA_FLOWER_UNSPEC] = { .type = NLA_UNSPEC }, 61377b9900eSJiri Pirko [TCA_FLOWER_CLASSID] = { .type = NLA_U32 }, 61477b9900eSJiri Pirko [TCA_FLOWER_INDEV] = { .type = NLA_STRING, 61577b9900eSJiri Pirko .len = IFNAMSIZ }, 61677b9900eSJiri Pirko [TCA_FLOWER_KEY_ETH_DST] = { .len = ETH_ALEN }, 61777b9900eSJiri Pirko [TCA_FLOWER_KEY_ETH_DST_MASK] = { .len = ETH_ALEN }, 61877b9900eSJiri Pirko [TCA_FLOWER_KEY_ETH_SRC] = { .len = ETH_ALEN }, 61977b9900eSJiri Pirko [TCA_FLOWER_KEY_ETH_SRC_MASK] = { .len = ETH_ALEN }, 62077b9900eSJiri Pirko [TCA_FLOWER_KEY_ETH_TYPE] = { .type = NLA_U16 }, 62177b9900eSJiri Pirko [TCA_FLOWER_KEY_IP_PROTO] = { .type = NLA_U8 }, 62277b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV4_SRC] = { .type = NLA_U32 }, 62377b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV4_SRC_MASK] = { .type = NLA_U32 }, 62477b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV4_DST] = { .type = NLA_U32 }, 62577b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV4_DST_MASK] = { .type = NLA_U32 }, 62677b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV6_SRC] = { .len = sizeof(struct in6_addr) }, 62777b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) }, 62877b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV6_DST] = { .len = sizeof(struct in6_addr) }, 62977b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) }, 63077b9900eSJiri Pirko [TCA_FLOWER_KEY_TCP_SRC] = { .type = NLA_U16 }, 63177b9900eSJiri Pirko [TCA_FLOWER_KEY_TCP_DST] = { .type = NLA_U16 }, 632b175c3a4SJamal Hadi Salim [TCA_FLOWER_KEY_UDP_SRC] = { .type = NLA_U16 }, 633b175c3a4SJamal Hadi Salim [TCA_FLOWER_KEY_UDP_DST] = { .type = NLA_U16 }, 6349399ae9aSHadar Hen Zion [TCA_FLOWER_KEY_VLAN_ID] = { .type = NLA_U16 }, 6359399ae9aSHadar Hen Zion [TCA_FLOWER_KEY_VLAN_PRIO] = { .type = NLA_U8 }, 6369399ae9aSHadar Hen Zion [TCA_FLOWER_KEY_VLAN_ETH_TYPE] = { .type = NLA_U16 }, 637bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_KEY_ID] = { .type = NLA_U32 }, 638bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV4_SRC] = { .type = NLA_U32 }, 639bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] = { .type = NLA_U32 }, 640bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV4_DST] = { .type = NLA_U32 }, 641bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] = { .type = NLA_U32 }, 642bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV6_SRC] = { .len = sizeof(struct in6_addr) }, 643bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) }, 644bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV6_DST] = { .len = sizeof(struct in6_addr) }, 645bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) }, 646aa72d708SOr Gerlitz [TCA_FLOWER_KEY_TCP_SRC_MASK] = { .type = NLA_U16 }, 647aa72d708SOr Gerlitz [TCA_FLOWER_KEY_TCP_DST_MASK] = { .type = NLA_U16 }, 648aa72d708SOr Gerlitz [TCA_FLOWER_KEY_UDP_SRC_MASK] = { .type = NLA_U16 }, 649aa72d708SOr Gerlitz [TCA_FLOWER_KEY_UDP_DST_MASK] = { .type = NLA_U16 }, 6505976c5f4SSimon Horman [TCA_FLOWER_KEY_SCTP_SRC_MASK] = { .type = NLA_U16 }, 6515976c5f4SSimon Horman [TCA_FLOWER_KEY_SCTP_DST_MASK] = { .type = NLA_U16 }, 6525976c5f4SSimon Horman [TCA_FLOWER_KEY_SCTP_SRC] = { .type = NLA_U16 }, 6535976c5f4SSimon Horman [TCA_FLOWER_KEY_SCTP_DST] = { .type = NLA_U16 }, 654f4d997fdSHadar Hen Zion [TCA_FLOWER_KEY_ENC_UDP_SRC_PORT] = { .type = NLA_U16 }, 655f4d997fdSHadar Hen Zion [TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK] = { .type = NLA_U16 }, 656f4d997fdSHadar Hen Zion [TCA_FLOWER_KEY_ENC_UDP_DST_PORT] = { .type = NLA_U16 }, 657f4d997fdSHadar Hen Zion [TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK] = { .type = NLA_U16 }, 658faa3ffceSOr Gerlitz [TCA_FLOWER_KEY_FLAGS] = { .type = NLA_U32 }, 659faa3ffceSOr Gerlitz [TCA_FLOWER_KEY_FLAGS_MASK] = { .type = NLA_U32 }, 6607b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV4_TYPE] = { .type = NLA_U8 }, 6617b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV4_TYPE_MASK] = { .type = NLA_U8 }, 6627b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV4_CODE] = { .type = NLA_U8 }, 6637b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV4_CODE_MASK] = { .type = NLA_U8 }, 6647b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV6_TYPE] = { .type = NLA_U8 }, 6657b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV6_TYPE_MASK] = { .type = NLA_U8 }, 6667b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV6_CODE] = { .type = NLA_U8 }, 6677b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV6_CODE_MASK] = { .type = NLA_U8 }, 66899d31326SSimon Horman [TCA_FLOWER_KEY_ARP_SIP] = { .type = NLA_U32 }, 66999d31326SSimon Horman [TCA_FLOWER_KEY_ARP_SIP_MASK] = { .type = NLA_U32 }, 67099d31326SSimon Horman [TCA_FLOWER_KEY_ARP_TIP] = { .type = NLA_U32 }, 67199d31326SSimon Horman [TCA_FLOWER_KEY_ARP_TIP_MASK] = { .type = NLA_U32 }, 67299d31326SSimon Horman [TCA_FLOWER_KEY_ARP_OP] = { .type = NLA_U8 }, 67399d31326SSimon Horman [TCA_FLOWER_KEY_ARP_OP_MASK] = { .type = NLA_U8 }, 67499d31326SSimon Horman [TCA_FLOWER_KEY_ARP_SHA] = { .len = ETH_ALEN }, 67599d31326SSimon Horman [TCA_FLOWER_KEY_ARP_SHA_MASK] = { .len = ETH_ALEN }, 67699d31326SSimon Horman [TCA_FLOWER_KEY_ARP_THA] = { .len = ETH_ALEN }, 67799d31326SSimon Horman [TCA_FLOWER_KEY_ARP_THA_MASK] = { .len = ETH_ALEN }, 678a577d8f7SBenjamin LaHaise [TCA_FLOWER_KEY_MPLS_TTL] = { .type = NLA_U8 }, 679a577d8f7SBenjamin LaHaise [TCA_FLOWER_KEY_MPLS_BOS] = { .type = NLA_U8 }, 680a577d8f7SBenjamin LaHaise [TCA_FLOWER_KEY_MPLS_TC] = { .type = NLA_U8 }, 681a577d8f7SBenjamin LaHaise [TCA_FLOWER_KEY_MPLS_LABEL] = { .type = NLA_U32 }, 68261aec25aSGuillaume Nault [TCA_FLOWER_KEY_MPLS_OPTS] = { .type = NLA_NESTED }, 683fdfc7dd6SJiri Pirko [TCA_FLOWER_KEY_TCP_FLAGS] = { .type = NLA_U16 }, 684fdfc7dd6SJiri Pirko [TCA_FLOWER_KEY_TCP_FLAGS_MASK] = { .type = NLA_U16 }, 6854d80cc0aSOr Gerlitz [TCA_FLOWER_KEY_IP_TOS] = { .type = NLA_U8 }, 6864d80cc0aSOr Gerlitz [TCA_FLOWER_KEY_IP_TOS_MASK] = { .type = NLA_U8 }, 6874d80cc0aSOr Gerlitz [TCA_FLOWER_KEY_IP_TTL] = { .type = NLA_U8 }, 6884d80cc0aSOr Gerlitz [TCA_FLOWER_KEY_IP_TTL_MASK] = { .type = NLA_U8 }, 689d64efd09SJianbo Liu [TCA_FLOWER_KEY_CVLAN_ID] = { .type = NLA_U16 }, 690d64efd09SJianbo Liu [TCA_FLOWER_KEY_CVLAN_PRIO] = { .type = NLA_U8 }, 691d64efd09SJianbo Liu [TCA_FLOWER_KEY_CVLAN_ETH_TYPE] = { .type = NLA_U16 }, 6920e2c17b6SOr Gerlitz [TCA_FLOWER_KEY_ENC_IP_TOS] = { .type = NLA_U8 }, 6930e2c17b6SOr Gerlitz [TCA_FLOWER_KEY_ENC_IP_TOS_MASK] = { .type = NLA_U8 }, 6940e2c17b6SOr Gerlitz [TCA_FLOWER_KEY_ENC_IP_TTL] = { .type = NLA_U8 }, 6950e2c17b6SOr Gerlitz [TCA_FLOWER_KEY_ENC_IP_TTL_MASK] = { .type = NLA_U8 }, 6960a6e7778SPieter Jansen van Vuuren [TCA_FLOWER_KEY_ENC_OPTS] = { .type = NLA_NESTED }, 6970a6e7778SPieter Jansen van Vuuren [TCA_FLOWER_KEY_ENC_OPTS_MASK] = { .type = NLA_NESTED }, 6981bcc51acSwenxu [TCA_FLOWER_KEY_CT_STATE] = 6991bcc51acSwenxu NLA_POLICY_MASK(NLA_U16, TCA_FLOWER_KEY_CT_FLAGS_MASK), 7001bcc51acSwenxu [TCA_FLOWER_KEY_CT_STATE_MASK] = 7011bcc51acSwenxu NLA_POLICY_MASK(NLA_U16, TCA_FLOWER_KEY_CT_FLAGS_MASK), 702e0ace68aSPaul Blakey [TCA_FLOWER_KEY_CT_ZONE] = { .type = NLA_U16 }, 703e0ace68aSPaul Blakey [TCA_FLOWER_KEY_CT_ZONE_MASK] = { .type = NLA_U16 }, 704e0ace68aSPaul Blakey [TCA_FLOWER_KEY_CT_MARK] = { .type = NLA_U32 }, 705e0ace68aSPaul Blakey [TCA_FLOWER_KEY_CT_MARK_MASK] = { .type = NLA_U32 }, 706e0ace68aSPaul Blakey [TCA_FLOWER_KEY_CT_LABELS] = { .type = NLA_BINARY, 707e0ace68aSPaul Blakey .len = 128 / BITS_PER_BYTE }, 708e0ace68aSPaul Blakey [TCA_FLOWER_KEY_CT_LABELS_MASK] = { .type = NLA_BINARY, 709e0ace68aSPaul Blakey .len = 128 / BITS_PER_BYTE }, 710e2debf08SDavide Caratti [TCA_FLOWER_FLAGS] = { .type = NLA_U32 }, 7115923b8f7SAriel Levkovich [TCA_FLOWER_KEY_HASH] = { .type = NLA_U32 }, 7125923b8f7SAriel Levkovich [TCA_FLOWER_KEY_HASH_MASK] = { .type = NLA_U32 }, 7135923b8f7SAriel Levkovich 7140a6e7778SPieter Jansen van Vuuren }; 7150a6e7778SPieter Jansen van Vuuren 7160a6e7778SPieter Jansen van Vuuren static const struct nla_policy 7170a6e7778SPieter Jansen van Vuuren enc_opts_policy[TCA_FLOWER_KEY_ENC_OPTS_MAX + 1] = { 718d8f9dfaeSXin Long [TCA_FLOWER_KEY_ENC_OPTS_UNSPEC] = { 719d8f9dfaeSXin Long .strict_start_type = TCA_FLOWER_KEY_ENC_OPTS_VXLAN }, 7200a6e7778SPieter Jansen van Vuuren [TCA_FLOWER_KEY_ENC_OPTS_GENEVE] = { .type = NLA_NESTED }, 721d8f9dfaeSXin Long [TCA_FLOWER_KEY_ENC_OPTS_VXLAN] = { .type = NLA_NESTED }, 72279b1011cSXin Long [TCA_FLOWER_KEY_ENC_OPTS_ERSPAN] = { .type = NLA_NESTED }, 7230a6e7778SPieter Jansen van Vuuren }; 7240a6e7778SPieter Jansen van Vuuren 7250a6e7778SPieter Jansen van Vuuren static const struct nla_policy 7260a6e7778SPieter Jansen van Vuuren geneve_opt_policy[TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX + 1] = { 7270a6e7778SPieter Jansen van Vuuren [TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS] = { .type = NLA_U16 }, 7280a6e7778SPieter Jansen van Vuuren [TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE] = { .type = NLA_U8 }, 7290a6e7778SPieter Jansen van Vuuren [TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA] = { .type = NLA_BINARY, 7300a6e7778SPieter Jansen van Vuuren .len = 128 }, 73177b9900eSJiri Pirko }; 73277b9900eSJiri Pirko 733d8f9dfaeSXin Long static const struct nla_policy 734d8f9dfaeSXin Long vxlan_opt_policy[TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX + 1] = { 735d8f9dfaeSXin Long [TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP] = { .type = NLA_U32 }, 736d8f9dfaeSXin Long }; 737d8f9dfaeSXin Long 73879b1011cSXin Long static const struct nla_policy 73979b1011cSXin Long erspan_opt_policy[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX + 1] = { 74079b1011cSXin Long [TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER] = { .type = NLA_U8 }, 74179b1011cSXin Long [TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX] = { .type = NLA_U32 }, 74279b1011cSXin Long [TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR] = { .type = NLA_U8 }, 74379b1011cSXin Long [TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID] = { .type = NLA_U8 }, 74479b1011cSXin Long }; 74579b1011cSXin Long 74661aec25aSGuillaume Nault static const struct nla_policy 74761aec25aSGuillaume Nault mpls_stack_entry_policy[TCA_FLOWER_KEY_MPLS_OPT_LSE_MAX + 1] = { 74861aec25aSGuillaume Nault [TCA_FLOWER_KEY_MPLS_OPT_LSE_DEPTH] = { .type = NLA_U8 }, 74961aec25aSGuillaume Nault [TCA_FLOWER_KEY_MPLS_OPT_LSE_TTL] = { .type = NLA_U8 }, 75061aec25aSGuillaume Nault [TCA_FLOWER_KEY_MPLS_OPT_LSE_BOS] = { .type = NLA_U8 }, 75161aec25aSGuillaume Nault [TCA_FLOWER_KEY_MPLS_OPT_LSE_TC] = { .type = NLA_U8 }, 75261aec25aSGuillaume Nault [TCA_FLOWER_KEY_MPLS_OPT_LSE_LABEL] = { .type = NLA_U32 }, 75361aec25aSGuillaume Nault }; 75461aec25aSGuillaume Nault 75577b9900eSJiri Pirko static void fl_set_key_val(struct nlattr **tb, 75677b9900eSJiri Pirko void *val, int val_type, 75777b9900eSJiri Pirko void *mask, int mask_type, int len) 75877b9900eSJiri Pirko { 75977b9900eSJiri Pirko if (!tb[val_type]) 76077b9900eSJiri Pirko return; 761e0ace68aSPaul Blakey nla_memcpy(val, tb[val_type], len); 76277b9900eSJiri Pirko if (mask_type == TCA_FLOWER_UNSPEC || !tb[mask_type]) 76377b9900eSJiri Pirko memset(mask, 0xff, len); 76477b9900eSJiri Pirko else 765e0ace68aSPaul Blakey nla_memcpy(mask, tb[mask_type], len); 76677b9900eSJiri Pirko } 76777b9900eSJiri Pirko 7685c72299fSAmritha Nambiar static int fl_set_key_port_range(struct nlattr **tb, struct fl_flow_key *key, 769bd7d4c12SGuillaume Nault struct fl_flow_key *mask, 770bd7d4c12SGuillaume Nault struct netlink_ext_ack *extack) 7715c72299fSAmritha Nambiar { 7728ffb055bSYoshiki Komachi fl_set_key_val(tb, &key->tp_range.tp_min.dst, 7738ffb055bSYoshiki Komachi TCA_FLOWER_KEY_PORT_DST_MIN, &mask->tp_range.tp_min.dst, 7748ffb055bSYoshiki Komachi TCA_FLOWER_UNSPEC, sizeof(key->tp_range.tp_min.dst)); 7758ffb055bSYoshiki Komachi fl_set_key_val(tb, &key->tp_range.tp_max.dst, 7768ffb055bSYoshiki Komachi TCA_FLOWER_KEY_PORT_DST_MAX, &mask->tp_range.tp_max.dst, 7778ffb055bSYoshiki Komachi TCA_FLOWER_UNSPEC, sizeof(key->tp_range.tp_max.dst)); 7788ffb055bSYoshiki Komachi fl_set_key_val(tb, &key->tp_range.tp_min.src, 7798ffb055bSYoshiki Komachi TCA_FLOWER_KEY_PORT_SRC_MIN, &mask->tp_range.tp_min.src, 7808ffb055bSYoshiki Komachi TCA_FLOWER_UNSPEC, sizeof(key->tp_range.tp_min.src)); 7818ffb055bSYoshiki Komachi fl_set_key_val(tb, &key->tp_range.tp_max.src, 7828ffb055bSYoshiki Komachi TCA_FLOWER_KEY_PORT_SRC_MAX, &mask->tp_range.tp_max.src, 7838ffb055bSYoshiki Komachi TCA_FLOWER_UNSPEC, sizeof(key->tp_range.tp_max.src)); 7845c72299fSAmritha Nambiar 785bd7d4c12SGuillaume Nault if (mask->tp_range.tp_min.dst && mask->tp_range.tp_max.dst && 7866215afcbSVladimir Oltean ntohs(key->tp_range.tp_max.dst) <= 7876215afcbSVladimir Oltean ntohs(key->tp_range.tp_min.dst)) { 788bd7d4c12SGuillaume Nault NL_SET_ERR_MSG_ATTR(extack, 789bd7d4c12SGuillaume Nault tb[TCA_FLOWER_KEY_PORT_DST_MIN], 790bd7d4c12SGuillaume Nault "Invalid destination port range (min must be strictly smaller than max)"); 7915c72299fSAmritha Nambiar return -EINVAL; 792bd7d4c12SGuillaume Nault } 793bd7d4c12SGuillaume Nault if (mask->tp_range.tp_min.src && mask->tp_range.tp_max.src && 7946215afcbSVladimir Oltean ntohs(key->tp_range.tp_max.src) <= 7956215afcbSVladimir Oltean ntohs(key->tp_range.tp_min.src)) { 796bd7d4c12SGuillaume Nault NL_SET_ERR_MSG_ATTR(extack, 797bd7d4c12SGuillaume Nault tb[TCA_FLOWER_KEY_PORT_SRC_MIN], 798bd7d4c12SGuillaume Nault "Invalid source port range (min must be strictly smaller than max)"); 799bd7d4c12SGuillaume Nault return -EINVAL; 800bd7d4c12SGuillaume Nault } 8015c72299fSAmritha Nambiar 8025c72299fSAmritha Nambiar return 0; 8035c72299fSAmritha Nambiar } 8045c72299fSAmritha Nambiar 80561aec25aSGuillaume Nault static int fl_set_key_mpls_lse(const struct nlattr *nla_lse, 80661aec25aSGuillaume Nault struct flow_dissector_key_mpls *key_val, 80761aec25aSGuillaume Nault struct flow_dissector_key_mpls *key_mask, 80861aec25aSGuillaume Nault struct netlink_ext_ack *extack) 80961aec25aSGuillaume Nault { 81061aec25aSGuillaume Nault struct nlattr *tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_MAX + 1]; 81161aec25aSGuillaume Nault struct flow_dissector_mpls_lse *lse_mask; 81261aec25aSGuillaume Nault struct flow_dissector_mpls_lse *lse_val; 81361aec25aSGuillaume Nault u8 lse_index; 81461aec25aSGuillaume Nault u8 depth; 81561aec25aSGuillaume Nault int err; 81661aec25aSGuillaume Nault 81761aec25aSGuillaume Nault err = nla_parse_nested(tb, TCA_FLOWER_KEY_MPLS_OPT_LSE_MAX, nla_lse, 81861aec25aSGuillaume Nault mpls_stack_entry_policy, extack); 81961aec25aSGuillaume Nault if (err < 0) 82061aec25aSGuillaume Nault return err; 82161aec25aSGuillaume Nault 82261aec25aSGuillaume Nault if (!tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_DEPTH]) { 82361aec25aSGuillaume Nault NL_SET_ERR_MSG(extack, "Missing MPLS option \"depth\""); 82461aec25aSGuillaume Nault return -EINVAL; 82561aec25aSGuillaume Nault } 82661aec25aSGuillaume Nault 82761aec25aSGuillaume Nault depth = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_DEPTH]); 82861aec25aSGuillaume Nault 82961aec25aSGuillaume Nault /* LSE depth starts at 1, for consistency with terminology used by 83061aec25aSGuillaume Nault * RFC 3031 (section 3.9), where depth 0 refers to unlabeled packets. 83161aec25aSGuillaume Nault */ 83261aec25aSGuillaume Nault if (depth < 1 || depth > FLOW_DIS_MPLS_MAX) { 83361aec25aSGuillaume Nault NL_SET_ERR_MSG_ATTR(extack, 83461aec25aSGuillaume Nault tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_DEPTH], 83561aec25aSGuillaume Nault "Invalid MPLS depth"); 83661aec25aSGuillaume Nault return -EINVAL; 83761aec25aSGuillaume Nault } 83861aec25aSGuillaume Nault lse_index = depth - 1; 83961aec25aSGuillaume Nault 84061aec25aSGuillaume Nault dissector_set_mpls_lse(key_val, lse_index); 84161aec25aSGuillaume Nault dissector_set_mpls_lse(key_mask, lse_index); 84261aec25aSGuillaume Nault 84361aec25aSGuillaume Nault lse_val = &key_val->ls[lse_index]; 84461aec25aSGuillaume Nault lse_mask = &key_mask->ls[lse_index]; 84561aec25aSGuillaume Nault 84661aec25aSGuillaume Nault if (tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_TTL]) { 84761aec25aSGuillaume Nault lse_val->mpls_ttl = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_TTL]); 84861aec25aSGuillaume Nault lse_mask->mpls_ttl = MPLS_TTL_MASK; 84961aec25aSGuillaume Nault } 85061aec25aSGuillaume Nault if (tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_BOS]) { 85161aec25aSGuillaume Nault u8 bos = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_BOS]); 85261aec25aSGuillaume Nault 85361aec25aSGuillaume Nault if (bos & ~MPLS_BOS_MASK) { 85461aec25aSGuillaume Nault NL_SET_ERR_MSG_ATTR(extack, 85561aec25aSGuillaume Nault tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_BOS], 85661aec25aSGuillaume Nault "Bottom Of Stack (BOS) must be 0 or 1"); 85761aec25aSGuillaume Nault return -EINVAL; 85861aec25aSGuillaume Nault } 85961aec25aSGuillaume Nault lse_val->mpls_bos = bos; 86061aec25aSGuillaume Nault lse_mask->mpls_bos = MPLS_BOS_MASK; 86161aec25aSGuillaume Nault } 86261aec25aSGuillaume Nault if (tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_TC]) { 86361aec25aSGuillaume Nault u8 tc = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_TC]); 86461aec25aSGuillaume Nault 86561aec25aSGuillaume Nault if (tc & ~MPLS_TC_MASK) { 86661aec25aSGuillaume Nault NL_SET_ERR_MSG_ATTR(extack, 86761aec25aSGuillaume Nault tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_TC], 86861aec25aSGuillaume Nault "Traffic Class (TC) must be between 0 and 7"); 86961aec25aSGuillaume Nault return -EINVAL; 87061aec25aSGuillaume Nault } 87161aec25aSGuillaume Nault lse_val->mpls_tc = tc; 87261aec25aSGuillaume Nault lse_mask->mpls_tc = MPLS_TC_MASK; 87361aec25aSGuillaume Nault } 87461aec25aSGuillaume Nault if (tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_LABEL]) { 87561aec25aSGuillaume Nault u32 label = nla_get_u32(tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_LABEL]); 87661aec25aSGuillaume Nault 87761aec25aSGuillaume Nault if (label & ~MPLS_LABEL_MASK) { 87861aec25aSGuillaume Nault NL_SET_ERR_MSG_ATTR(extack, 87961aec25aSGuillaume Nault tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_LABEL], 88061aec25aSGuillaume Nault "Label must be between 0 and 1048575"); 88161aec25aSGuillaume Nault return -EINVAL; 88261aec25aSGuillaume Nault } 88361aec25aSGuillaume Nault lse_val->mpls_label = label; 88461aec25aSGuillaume Nault lse_mask->mpls_label = MPLS_LABEL_MASK; 88561aec25aSGuillaume Nault } 88661aec25aSGuillaume Nault 88761aec25aSGuillaume Nault return 0; 88861aec25aSGuillaume Nault } 88961aec25aSGuillaume Nault 89061aec25aSGuillaume Nault static int fl_set_key_mpls_opts(const struct nlattr *nla_mpls_opts, 89161aec25aSGuillaume Nault struct flow_dissector_key_mpls *key_val, 89261aec25aSGuillaume Nault struct flow_dissector_key_mpls *key_mask, 89361aec25aSGuillaume Nault struct netlink_ext_ack *extack) 89461aec25aSGuillaume Nault { 89561aec25aSGuillaume Nault struct nlattr *nla_lse; 89661aec25aSGuillaume Nault int rem; 89761aec25aSGuillaume Nault int err; 89861aec25aSGuillaume Nault 89961aec25aSGuillaume Nault if (!(nla_mpls_opts->nla_type & NLA_F_NESTED)) { 90061aec25aSGuillaume Nault NL_SET_ERR_MSG_ATTR(extack, nla_mpls_opts, 90161aec25aSGuillaume Nault "NLA_F_NESTED is missing"); 90261aec25aSGuillaume Nault return -EINVAL; 90361aec25aSGuillaume Nault } 90461aec25aSGuillaume Nault 90561aec25aSGuillaume Nault nla_for_each_nested(nla_lse, nla_mpls_opts, rem) { 90661aec25aSGuillaume Nault if (nla_type(nla_lse) != TCA_FLOWER_KEY_MPLS_OPTS_LSE) { 90761aec25aSGuillaume Nault NL_SET_ERR_MSG_ATTR(extack, nla_lse, 90861aec25aSGuillaume Nault "Invalid MPLS option type"); 90961aec25aSGuillaume Nault return -EINVAL; 91061aec25aSGuillaume Nault } 91161aec25aSGuillaume Nault 91261aec25aSGuillaume Nault err = fl_set_key_mpls_lse(nla_lse, key_val, key_mask, extack); 91361aec25aSGuillaume Nault if (err < 0) 91461aec25aSGuillaume Nault return err; 91561aec25aSGuillaume Nault } 91661aec25aSGuillaume Nault if (rem) { 91761aec25aSGuillaume Nault NL_SET_ERR_MSG(extack, 91861aec25aSGuillaume Nault "Bytes leftover after parsing MPLS options"); 91961aec25aSGuillaume Nault return -EINVAL; 92061aec25aSGuillaume Nault } 92161aec25aSGuillaume Nault 92261aec25aSGuillaume Nault return 0; 92361aec25aSGuillaume Nault } 92461aec25aSGuillaume Nault 9251a7fca63SBenjamin LaHaise static int fl_set_key_mpls(struct nlattr **tb, 926a577d8f7SBenjamin LaHaise struct flow_dissector_key_mpls *key_val, 927442f730eSGuillaume Nault struct flow_dissector_key_mpls *key_mask, 928442f730eSGuillaume Nault struct netlink_ext_ack *extack) 929a577d8f7SBenjamin LaHaise { 93058cff782SGuillaume Nault struct flow_dissector_mpls_lse *lse_mask; 93158cff782SGuillaume Nault struct flow_dissector_mpls_lse *lse_val; 93258cff782SGuillaume Nault 93361aec25aSGuillaume Nault if (tb[TCA_FLOWER_KEY_MPLS_OPTS]) { 93461aec25aSGuillaume Nault if (tb[TCA_FLOWER_KEY_MPLS_TTL] || 93561aec25aSGuillaume Nault tb[TCA_FLOWER_KEY_MPLS_BOS] || 93661aec25aSGuillaume Nault tb[TCA_FLOWER_KEY_MPLS_TC] || 93761aec25aSGuillaume Nault tb[TCA_FLOWER_KEY_MPLS_LABEL]) { 93861aec25aSGuillaume Nault NL_SET_ERR_MSG_ATTR(extack, 93961aec25aSGuillaume Nault tb[TCA_FLOWER_KEY_MPLS_OPTS], 94061aec25aSGuillaume Nault "MPLS label, Traffic Class, Bottom Of Stack and Time To Live must be encapsulated in the MPLS options attribute"); 94161aec25aSGuillaume Nault return -EBADMSG; 94261aec25aSGuillaume Nault } 94361aec25aSGuillaume Nault 94461aec25aSGuillaume Nault return fl_set_key_mpls_opts(tb[TCA_FLOWER_KEY_MPLS_OPTS], 94561aec25aSGuillaume Nault key_val, key_mask, extack); 94661aec25aSGuillaume Nault } 94761aec25aSGuillaume Nault 94858cff782SGuillaume Nault lse_val = &key_val->ls[0]; 94958cff782SGuillaume Nault lse_mask = &key_mask->ls[0]; 95058cff782SGuillaume Nault 951a577d8f7SBenjamin LaHaise if (tb[TCA_FLOWER_KEY_MPLS_TTL]) { 95258cff782SGuillaume Nault lse_val->mpls_ttl = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TTL]); 95358cff782SGuillaume Nault lse_mask->mpls_ttl = MPLS_TTL_MASK; 95458cff782SGuillaume Nault dissector_set_mpls_lse(key_val, 0); 95558cff782SGuillaume Nault dissector_set_mpls_lse(key_mask, 0); 956a577d8f7SBenjamin LaHaise } 957a577d8f7SBenjamin LaHaise if (tb[TCA_FLOWER_KEY_MPLS_BOS]) { 9581a7fca63SBenjamin LaHaise u8 bos = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_BOS]); 9591a7fca63SBenjamin LaHaise 960442f730eSGuillaume Nault if (bos & ~MPLS_BOS_MASK) { 961442f730eSGuillaume Nault NL_SET_ERR_MSG_ATTR(extack, 962442f730eSGuillaume Nault tb[TCA_FLOWER_KEY_MPLS_BOS], 963442f730eSGuillaume Nault "Bottom Of Stack (BOS) must be 0 or 1"); 9641a7fca63SBenjamin LaHaise return -EINVAL; 965442f730eSGuillaume Nault } 96658cff782SGuillaume Nault lse_val->mpls_bos = bos; 96758cff782SGuillaume Nault lse_mask->mpls_bos = MPLS_BOS_MASK; 96858cff782SGuillaume Nault dissector_set_mpls_lse(key_val, 0); 96958cff782SGuillaume Nault dissector_set_mpls_lse(key_mask, 0); 970a577d8f7SBenjamin LaHaise } 971a577d8f7SBenjamin LaHaise if (tb[TCA_FLOWER_KEY_MPLS_TC]) { 9721a7fca63SBenjamin LaHaise u8 tc = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TC]); 9731a7fca63SBenjamin LaHaise 974442f730eSGuillaume Nault if (tc & ~MPLS_TC_MASK) { 975442f730eSGuillaume Nault NL_SET_ERR_MSG_ATTR(extack, 976442f730eSGuillaume Nault tb[TCA_FLOWER_KEY_MPLS_TC], 977442f730eSGuillaume Nault "Traffic Class (TC) must be between 0 and 7"); 9781a7fca63SBenjamin LaHaise return -EINVAL; 979442f730eSGuillaume Nault } 98058cff782SGuillaume Nault lse_val->mpls_tc = tc; 98158cff782SGuillaume Nault lse_mask->mpls_tc = MPLS_TC_MASK; 98258cff782SGuillaume Nault dissector_set_mpls_lse(key_val, 0); 98358cff782SGuillaume Nault dissector_set_mpls_lse(key_mask, 0); 984a577d8f7SBenjamin LaHaise } 985a577d8f7SBenjamin LaHaise if (tb[TCA_FLOWER_KEY_MPLS_LABEL]) { 9861a7fca63SBenjamin LaHaise u32 label = nla_get_u32(tb[TCA_FLOWER_KEY_MPLS_LABEL]); 9871a7fca63SBenjamin LaHaise 988442f730eSGuillaume Nault if (label & ~MPLS_LABEL_MASK) { 989442f730eSGuillaume Nault NL_SET_ERR_MSG_ATTR(extack, 990442f730eSGuillaume Nault tb[TCA_FLOWER_KEY_MPLS_LABEL], 991442f730eSGuillaume Nault "Label must be between 0 and 1048575"); 9921a7fca63SBenjamin LaHaise return -EINVAL; 993442f730eSGuillaume Nault } 99458cff782SGuillaume Nault lse_val->mpls_label = label; 99558cff782SGuillaume Nault lse_mask->mpls_label = MPLS_LABEL_MASK; 99658cff782SGuillaume Nault dissector_set_mpls_lse(key_val, 0); 99758cff782SGuillaume Nault dissector_set_mpls_lse(key_mask, 0); 998a577d8f7SBenjamin LaHaise } 9991a7fca63SBenjamin LaHaise return 0; 1000a577d8f7SBenjamin LaHaise } 1001a577d8f7SBenjamin LaHaise 10029399ae9aSHadar Hen Zion static void fl_set_key_vlan(struct nlattr **tb, 1003aaab0834SJianbo Liu __be16 ethertype, 1004d64efd09SJianbo Liu int vlan_id_key, int vlan_prio_key, 10059399ae9aSHadar Hen Zion struct flow_dissector_key_vlan *key_val, 10069399ae9aSHadar Hen Zion struct flow_dissector_key_vlan *key_mask) 10079399ae9aSHadar Hen Zion { 10089399ae9aSHadar Hen Zion #define VLAN_PRIORITY_MASK 0x7 10099399ae9aSHadar Hen Zion 1010d64efd09SJianbo Liu if (tb[vlan_id_key]) { 10119399ae9aSHadar Hen Zion key_val->vlan_id = 1012d64efd09SJianbo Liu nla_get_u16(tb[vlan_id_key]) & VLAN_VID_MASK; 10139399ae9aSHadar Hen Zion key_mask->vlan_id = VLAN_VID_MASK; 10149399ae9aSHadar Hen Zion } 1015d64efd09SJianbo Liu if (tb[vlan_prio_key]) { 10169399ae9aSHadar Hen Zion key_val->vlan_priority = 1017d64efd09SJianbo Liu nla_get_u8(tb[vlan_prio_key]) & 10189399ae9aSHadar Hen Zion VLAN_PRIORITY_MASK; 10199399ae9aSHadar Hen Zion key_mask->vlan_priority = VLAN_PRIORITY_MASK; 10209399ae9aSHadar Hen Zion } 1021aaab0834SJianbo Liu key_val->vlan_tpid = ethertype; 1022aaab0834SJianbo Liu key_mask->vlan_tpid = cpu_to_be16(~0); 10239399ae9aSHadar Hen Zion } 10249399ae9aSHadar Hen Zion 1025faa3ffceSOr Gerlitz static void fl_set_key_flag(u32 flower_key, u32 flower_mask, 1026faa3ffceSOr Gerlitz u32 *dissector_key, u32 *dissector_mask, 1027faa3ffceSOr Gerlitz u32 flower_flag_bit, u32 dissector_flag_bit) 1028faa3ffceSOr Gerlitz { 1029faa3ffceSOr Gerlitz if (flower_mask & flower_flag_bit) { 1030faa3ffceSOr Gerlitz *dissector_mask |= dissector_flag_bit; 1031faa3ffceSOr Gerlitz if (flower_key & flower_flag_bit) 1032faa3ffceSOr Gerlitz *dissector_key |= dissector_flag_bit; 1033faa3ffceSOr Gerlitz } 1034faa3ffceSOr Gerlitz } 1035faa3ffceSOr Gerlitz 1036e304e21aSGuillaume Nault static int fl_set_key_flags(struct nlattr **tb, u32 *flags_key, 1037e304e21aSGuillaume Nault u32 *flags_mask, struct netlink_ext_ack *extack) 1038faa3ffceSOr Gerlitz { 1039faa3ffceSOr Gerlitz u32 key, mask; 1040faa3ffceSOr Gerlitz 1041d9724772SOr Gerlitz /* mask is mandatory for flags */ 1042e304e21aSGuillaume Nault if (!tb[TCA_FLOWER_KEY_FLAGS_MASK]) { 1043e304e21aSGuillaume Nault NL_SET_ERR_MSG(extack, "Missing flags mask"); 1044d9724772SOr Gerlitz return -EINVAL; 1045e304e21aSGuillaume Nault } 1046faa3ffceSOr Gerlitz 1047*abee13f5SVladimir Oltean key = be32_to_cpu(nla_get_be32(tb[TCA_FLOWER_KEY_FLAGS])); 1048*abee13f5SVladimir Oltean mask = be32_to_cpu(nla_get_be32(tb[TCA_FLOWER_KEY_FLAGS_MASK])); 1049faa3ffceSOr Gerlitz 1050faa3ffceSOr Gerlitz *flags_key = 0; 1051faa3ffceSOr Gerlitz *flags_mask = 0; 1052faa3ffceSOr Gerlitz 1053faa3ffceSOr Gerlitz fl_set_key_flag(key, mask, flags_key, flags_mask, 1054faa3ffceSOr Gerlitz TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT); 1055459d153dSPieter Jansen van Vuuren fl_set_key_flag(key, mask, flags_key, flags_mask, 1056459d153dSPieter Jansen van Vuuren TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST, 1057459d153dSPieter Jansen van Vuuren FLOW_DIS_FIRST_FRAG); 1058d9724772SOr Gerlitz 1059d9724772SOr Gerlitz return 0; 1060faa3ffceSOr Gerlitz } 1061faa3ffceSOr Gerlitz 10620e2c17b6SOr Gerlitz static void fl_set_key_ip(struct nlattr **tb, bool encap, 10634d80cc0aSOr Gerlitz struct flow_dissector_key_ip *key, 10644d80cc0aSOr Gerlitz struct flow_dissector_key_ip *mask) 10654d80cc0aSOr Gerlitz { 10660e2c17b6SOr Gerlitz int tos_key = encap ? TCA_FLOWER_KEY_ENC_IP_TOS : TCA_FLOWER_KEY_IP_TOS; 10670e2c17b6SOr Gerlitz int ttl_key = encap ? TCA_FLOWER_KEY_ENC_IP_TTL : TCA_FLOWER_KEY_IP_TTL; 10680e2c17b6SOr Gerlitz int tos_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TOS_MASK : TCA_FLOWER_KEY_IP_TOS_MASK; 10690e2c17b6SOr Gerlitz int ttl_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TTL_MASK : TCA_FLOWER_KEY_IP_TTL_MASK; 10704d80cc0aSOr Gerlitz 10710e2c17b6SOr Gerlitz fl_set_key_val(tb, &key->tos, tos_key, &mask->tos, tos_mask, sizeof(key->tos)); 10720e2c17b6SOr Gerlitz fl_set_key_val(tb, &key->ttl, ttl_key, &mask->ttl, ttl_mask, sizeof(key->ttl)); 10734d80cc0aSOr Gerlitz } 10744d80cc0aSOr Gerlitz 10750a6e7778SPieter Jansen van Vuuren static int fl_set_geneve_opt(const struct nlattr *nla, struct fl_flow_key *key, 10760a6e7778SPieter Jansen van Vuuren int depth, int option_len, 10770a6e7778SPieter Jansen van Vuuren struct netlink_ext_ack *extack) 10780a6e7778SPieter Jansen van Vuuren { 10790a6e7778SPieter Jansen van Vuuren struct nlattr *tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX + 1]; 10800a6e7778SPieter Jansen van Vuuren struct nlattr *class = NULL, *type = NULL, *data = NULL; 10810a6e7778SPieter Jansen van Vuuren struct geneve_opt *opt; 10820a6e7778SPieter Jansen van Vuuren int err, data_len = 0; 10830a6e7778SPieter Jansen van Vuuren 10840a6e7778SPieter Jansen van Vuuren if (option_len > sizeof(struct geneve_opt)) 10850a6e7778SPieter Jansen van Vuuren data_len = option_len - sizeof(struct geneve_opt); 10860a6e7778SPieter Jansen van Vuuren 10870a6e7778SPieter Jansen van Vuuren opt = (struct geneve_opt *)&key->enc_opts.data[key->enc_opts.len]; 10880a6e7778SPieter Jansen van Vuuren memset(opt, 0xff, option_len); 10890a6e7778SPieter Jansen van Vuuren opt->length = data_len / 4; 10900a6e7778SPieter Jansen van Vuuren opt->r1 = 0; 10910a6e7778SPieter Jansen van Vuuren opt->r2 = 0; 10920a6e7778SPieter Jansen van Vuuren opt->r3 = 0; 10930a6e7778SPieter Jansen van Vuuren 10940a6e7778SPieter Jansen van Vuuren /* If no mask has been prodived we assume an exact match. */ 10950a6e7778SPieter Jansen van Vuuren if (!depth) 10960a6e7778SPieter Jansen van Vuuren return sizeof(struct geneve_opt) + data_len; 10970a6e7778SPieter Jansen van Vuuren 10980a6e7778SPieter Jansen van Vuuren if (nla_type(nla) != TCA_FLOWER_KEY_ENC_OPTS_GENEVE) { 10990a6e7778SPieter Jansen van Vuuren NL_SET_ERR_MSG(extack, "Non-geneve option type for mask"); 11000a6e7778SPieter Jansen van Vuuren return -EINVAL; 11010a6e7778SPieter Jansen van Vuuren } 11020a6e7778SPieter Jansen van Vuuren 11038cb08174SJohannes Berg err = nla_parse_nested_deprecated(tb, 11048cb08174SJohannes Berg TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX, 11050a6e7778SPieter Jansen van Vuuren nla, geneve_opt_policy, extack); 11060a6e7778SPieter Jansen van Vuuren if (err < 0) 11070a6e7778SPieter Jansen van Vuuren return err; 11080a6e7778SPieter Jansen van Vuuren 11090a6e7778SPieter Jansen van Vuuren /* We are not allowed to omit any of CLASS, TYPE or DATA 11100a6e7778SPieter Jansen van Vuuren * fields from the key. 11110a6e7778SPieter Jansen van Vuuren */ 11120a6e7778SPieter Jansen van Vuuren if (!option_len && 11130a6e7778SPieter Jansen van Vuuren (!tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS] || 11140a6e7778SPieter Jansen van Vuuren !tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE] || 11150a6e7778SPieter Jansen van Vuuren !tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA])) { 11160a6e7778SPieter Jansen van Vuuren NL_SET_ERR_MSG(extack, "Missing tunnel key geneve option class, type or data"); 11170a6e7778SPieter Jansen van Vuuren return -EINVAL; 11180a6e7778SPieter Jansen van Vuuren } 11190a6e7778SPieter Jansen van Vuuren 11200a6e7778SPieter Jansen van Vuuren /* Omitting any of CLASS, TYPE or DATA fields is allowed 11210a6e7778SPieter Jansen van Vuuren * for the mask. 11220a6e7778SPieter Jansen van Vuuren */ 11230a6e7778SPieter Jansen van Vuuren if (tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA]) { 11240a6e7778SPieter Jansen van Vuuren int new_len = key->enc_opts.len; 11250a6e7778SPieter Jansen van Vuuren 11260a6e7778SPieter Jansen van Vuuren data = tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA]; 11270a6e7778SPieter Jansen van Vuuren data_len = nla_len(data); 11280a6e7778SPieter Jansen van Vuuren if (data_len < 4) { 11290a6e7778SPieter Jansen van Vuuren NL_SET_ERR_MSG(extack, "Tunnel key geneve option data is less than 4 bytes long"); 11300a6e7778SPieter Jansen van Vuuren return -ERANGE; 11310a6e7778SPieter Jansen van Vuuren } 11320a6e7778SPieter Jansen van Vuuren if (data_len % 4) { 11330a6e7778SPieter Jansen van Vuuren NL_SET_ERR_MSG(extack, "Tunnel key geneve option data is not a multiple of 4 bytes long"); 11340a6e7778SPieter Jansen van Vuuren return -ERANGE; 11350a6e7778SPieter Jansen van Vuuren } 11360a6e7778SPieter Jansen van Vuuren 11370a6e7778SPieter Jansen van Vuuren new_len += sizeof(struct geneve_opt) + data_len; 11380a6e7778SPieter Jansen van Vuuren BUILD_BUG_ON(FLOW_DIS_TUN_OPTS_MAX != IP_TUNNEL_OPTS_MAX); 11390a6e7778SPieter Jansen van Vuuren if (new_len > FLOW_DIS_TUN_OPTS_MAX) { 11400a6e7778SPieter Jansen van Vuuren NL_SET_ERR_MSG(extack, "Tunnel options exceeds max size"); 11410a6e7778SPieter Jansen van Vuuren return -ERANGE; 11420a6e7778SPieter Jansen van Vuuren } 11430a6e7778SPieter Jansen van Vuuren opt->length = data_len / 4; 11440a6e7778SPieter Jansen van Vuuren memcpy(opt->opt_data, nla_data(data), data_len); 11450a6e7778SPieter Jansen van Vuuren } 11460a6e7778SPieter Jansen van Vuuren 11470a6e7778SPieter Jansen van Vuuren if (tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS]) { 11480a6e7778SPieter Jansen van Vuuren class = tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS]; 11490a6e7778SPieter Jansen van Vuuren opt->opt_class = nla_get_be16(class); 11500a6e7778SPieter Jansen van Vuuren } 11510a6e7778SPieter Jansen van Vuuren 11520a6e7778SPieter Jansen van Vuuren if (tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE]) { 11530a6e7778SPieter Jansen van Vuuren type = tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE]; 11540a6e7778SPieter Jansen van Vuuren opt->type = nla_get_u8(type); 11550a6e7778SPieter Jansen van Vuuren } 11560a6e7778SPieter Jansen van Vuuren 11570a6e7778SPieter Jansen van Vuuren return sizeof(struct geneve_opt) + data_len; 11580a6e7778SPieter Jansen van Vuuren } 11590a6e7778SPieter Jansen van Vuuren 1160d8f9dfaeSXin Long static int fl_set_vxlan_opt(const struct nlattr *nla, struct fl_flow_key *key, 1161d8f9dfaeSXin Long int depth, int option_len, 1162d8f9dfaeSXin Long struct netlink_ext_ack *extack) 1163d8f9dfaeSXin Long { 1164d8f9dfaeSXin Long struct nlattr *tb[TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX + 1]; 1165d8f9dfaeSXin Long struct vxlan_metadata *md; 1166d8f9dfaeSXin Long int err; 1167d8f9dfaeSXin Long 1168d8f9dfaeSXin Long md = (struct vxlan_metadata *)&key->enc_opts.data[key->enc_opts.len]; 1169d8f9dfaeSXin Long memset(md, 0xff, sizeof(*md)); 1170d8f9dfaeSXin Long 1171d8f9dfaeSXin Long if (!depth) 1172d8f9dfaeSXin Long return sizeof(*md); 1173d8f9dfaeSXin Long 1174d8f9dfaeSXin Long if (nla_type(nla) != TCA_FLOWER_KEY_ENC_OPTS_VXLAN) { 1175d8f9dfaeSXin Long NL_SET_ERR_MSG(extack, "Non-vxlan option type for mask"); 1176d8f9dfaeSXin Long return -EINVAL; 1177d8f9dfaeSXin Long } 1178d8f9dfaeSXin Long 1179d8f9dfaeSXin Long err = nla_parse_nested(tb, TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX, nla, 1180d8f9dfaeSXin Long vxlan_opt_policy, extack); 1181d8f9dfaeSXin Long if (err < 0) 1182d8f9dfaeSXin Long return err; 1183d8f9dfaeSXin Long 1184d8f9dfaeSXin Long if (!option_len && !tb[TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP]) { 1185d8f9dfaeSXin Long NL_SET_ERR_MSG(extack, "Missing tunnel key vxlan option gbp"); 1186d8f9dfaeSXin Long return -EINVAL; 1187d8f9dfaeSXin Long } 1188d8f9dfaeSXin Long 118913e6ce98SXin Long if (tb[TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP]) { 1190d8f9dfaeSXin Long md->gbp = nla_get_u32(tb[TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP]); 119113e6ce98SXin Long md->gbp &= VXLAN_GBP_MASK; 119213e6ce98SXin Long } 1193d8f9dfaeSXin Long 1194d8f9dfaeSXin Long return sizeof(*md); 1195d8f9dfaeSXin Long } 1196d8f9dfaeSXin Long 119779b1011cSXin Long static int fl_set_erspan_opt(const struct nlattr *nla, struct fl_flow_key *key, 119879b1011cSXin Long int depth, int option_len, 119979b1011cSXin Long struct netlink_ext_ack *extack) 120079b1011cSXin Long { 120179b1011cSXin Long struct nlattr *tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX + 1]; 120279b1011cSXin Long struct erspan_metadata *md; 120379b1011cSXin Long int err; 120479b1011cSXin Long 120579b1011cSXin Long md = (struct erspan_metadata *)&key->enc_opts.data[key->enc_opts.len]; 120679b1011cSXin Long memset(md, 0xff, sizeof(*md)); 120779b1011cSXin Long md->version = 1; 120879b1011cSXin Long 120979b1011cSXin Long if (!depth) 121079b1011cSXin Long return sizeof(*md); 121179b1011cSXin Long 121279b1011cSXin Long if (nla_type(nla) != TCA_FLOWER_KEY_ENC_OPTS_ERSPAN) { 121379b1011cSXin Long NL_SET_ERR_MSG(extack, "Non-erspan option type for mask"); 121479b1011cSXin Long return -EINVAL; 121579b1011cSXin Long } 121679b1011cSXin Long 121779b1011cSXin Long err = nla_parse_nested(tb, TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX, nla, 121879b1011cSXin Long erspan_opt_policy, extack); 121979b1011cSXin Long if (err < 0) 122079b1011cSXin Long return err; 122179b1011cSXin Long 122279b1011cSXin Long if (!option_len && !tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER]) { 122379b1011cSXin Long NL_SET_ERR_MSG(extack, "Missing tunnel key erspan option ver"); 122479b1011cSXin Long return -EINVAL; 122579b1011cSXin Long } 122679b1011cSXin Long 122779b1011cSXin Long if (tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER]) 122879b1011cSXin Long md->version = nla_get_u8(tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER]); 122979b1011cSXin Long 123079b1011cSXin Long if (md->version == 1) { 123179b1011cSXin Long if (!option_len && !tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX]) { 123279b1011cSXin Long NL_SET_ERR_MSG(extack, "Missing tunnel key erspan option index"); 123379b1011cSXin Long return -EINVAL; 123479b1011cSXin Long } 123579b1011cSXin Long if (tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX]) { 123679b1011cSXin Long nla = tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX]; 12378e1b3ac4SXin Long memset(&md->u, 0x00, sizeof(md->u)); 123879b1011cSXin Long md->u.index = nla_get_be32(nla); 123979b1011cSXin Long } 124079b1011cSXin Long } else if (md->version == 2) { 124179b1011cSXin Long if (!option_len && (!tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR] || 124279b1011cSXin Long !tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID])) { 124379b1011cSXin Long NL_SET_ERR_MSG(extack, "Missing tunnel key erspan option dir or hwid"); 124479b1011cSXin Long return -EINVAL; 124579b1011cSXin Long } 124679b1011cSXin Long if (tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR]) { 124779b1011cSXin Long nla = tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR]; 124879b1011cSXin Long md->u.md2.dir = nla_get_u8(nla); 124979b1011cSXin Long } 125079b1011cSXin Long if (tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID]) { 125179b1011cSXin Long nla = tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID]; 125279b1011cSXin Long set_hwid(&md->u.md2, nla_get_u8(nla)); 125379b1011cSXin Long } 125479b1011cSXin Long } else { 125579b1011cSXin Long NL_SET_ERR_MSG(extack, "Tunnel key erspan option ver is incorrect"); 125679b1011cSXin Long return -EINVAL; 125779b1011cSXin Long } 125879b1011cSXin Long 125979b1011cSXin Long return sizeof(*md); 126079b1011cSXin Long } 126179b1011cSXin Long 12620a6e7778SPieter Jansen van Vuuren static int fl_set_enc_opt(struct nlattr **tb, struct fl_flow_key *key, 12630a6e7778SPieter Jansen van Vuuren struct fl_flow_key *mask, 12640a6e7778SPieter Jansen van Vuuren struct netlink_ext_ack *extack) 12650a6e7778SPieter Jansen van Vuuren { 12660a6e7778SPieter Jansen van Vuuren const struct nlattr *nla_enc_key, *nla_opt_key, *nla_opt_msk = NULL; 126763c82997SJakub Kicinski int err, option_len, key_depth, msk_depth = 0; 126863c82997SJakub Kicinski 12698cb08174SJohannes Berg err = nla_validate_nested_deprecated(tb[TCA_FLOWER_KEY_ENC_OPTS], 127063c82997SJakub Kicinski TCA_FLOWER_KEY_ENC_OPTS_MAX, 127163c82997SJakub Kicinski enc_opts_policy, extack); 127263c82997SJakub Kicinski if (err) 127363c82997SJakub Kicinski return err; 12740a6e7778SPieter Jansen van Vuuren 12750a6e7778SPieter Jansen van Vuuren nla_enc_key = nla_data(tb[TCA_FLOWER_KEY_ENC_OPTS]); 12760a6e7778SPieter Jansen van Vuuren 12770a6e7778SPieter Jansen van Vuuren if (tb[TCA_FLOWER_KEY_ENC_OPTS_MASK]) { 12788cb08174SJohannes Berg err = nla_validate_nested_deprecated(tb[TCA_FLOWER_KEY_ENC_OPTS_MASK], 127963c82997SJakub Kicinski TCA_FLOWER_KEY_ENC_OPTS_MAX, 128063c82997SJakub Kicinski enc_opts_policy, extack); 128163c82997SJakub Kicinski if (err) 128263c82997SJakub Kicinski return err; 128363c82997SJakub Kicinski 12840a6e7778SPieter Jansen van Vuuren nla_opt_msk = nla_data(tb[TCA_FLOWER_KEY_ENC_OPTS_MASK]); 12850a6e7778SPieter Jansen van Vuuren msk_depth = nla_len(tb[TCA_FLOWER_KEY_ENC_OPTS_MASK]); 1286c96adff9SCong Wang if (!nla_ok(nla_opt_msk, msk_depth)) { 1287c96adff9SCong Wang NL_SET_ERR_MSG(extack, "Invalid nested attribute for masks"); 1288c96adff9SCong Wang return -EINVAL; 1289c96adff9SCong Wang } 12900a6e7778SPieter Jansen van Vuuren } 12910a6e7778SPieter Jansen van Vuuren 12920a6e7778SPieter Jansen van Vuuren nla_for_each_attr(nla_opt_key, nla_enc_key, 12930a6e7778SPieter Jansen van Vuuren nla_len(tb[TCA_FLOWER_KEY_ENC_OPTS]), key_depth) { 12940a6e7778SPieter Jansen van Vuuren switch (nla_type(nla_opt_key)) { 12950a6e7778SPieter Jansen van Vuuren case TCA_FLOWER_KEY_ENC_OPTS_GENEVE: 1296d8f9dfaeSXin Long if (key->enc_opts.dst_opt_type && 1297d8f9dfaeSXin Long key->enc_opts.dst_opt_type != TUNNEL_GENEVE_OPT) { 1298d8f9dfaeSXin Long NL_SET_ERR_MSG(extack, "Duplicate type for geneve options"); 1299d8f9dfaeSXin Long return -EINVAL; 1300d8f9dfaeSXin Long } 13010a6e7778SPieter Jansen van Vuuren option_len = 0; 13020a6e7778SPieter Jansen van Vuuren key->enc_opts.dst_opt_type = TUNNEL_GENEVE_OPT; 13030a6e7778SPieter Jansen van Vuuren option_len = fl_set_geneve_opt(nla_opt_key, key, 13040a6e7778SPieter Jansen van Vuuren key_depth, option_len, 13050a6e7778SPieter Jansen van Vuuren extack); 13060a6e7778SPieter Jansen van Vuuren if (option_len < 0) 13070a6e7778SPieter Jansen van Vuuren return option_len; 13080a6e7778SPieter Jansen van Vuuren 13090a6e7778SPieter Jansen van Vuuren key->enc_opts.len += option_len; 13100a6e7778SPieter Jansen van Vuuren /* At the same time we need to parse through the mask 13110a6e7778SPieter Jansen van Vuuren * in order to verify exact and mask attribute lengths. 13120a6e7778SPieter Jansen van Vuuren */ 13130a6e7778SPieter Jansen van Vuuren mask->enc_opts.dst_opt_type = TUNNEL_GENEVE_OPT; 13140a6e7778SPieter Jansen van Vuuren option_len = fl_set_geneve_opt(nla_opt_msk, mask, 13150a6e7778SPieter Jansen van Vuuren msk_depth, option_len, 13160a6e7778SPieter Jansen van Vuuren extack); 13170a6e7778SPieter Jansen van Vuuren if (option_len < 0) 13180a6e7778SPieter Jansen van Vuuren return option_len; 13190a6e7778SPieter Jansen van Vuuren 13200a6e7778SPieter Jansen van Vuuren mask->enc_opts.len += option_len; 13210a6e7778SPieter Jansen van Vuuren if (key->enc_opts.len != mask->enc_opts.len) { 13220a6e7778SPieter Jansen van Vuuren NL_SET_ERR_MSG(extack, "Key and mask miss aligned"); 13230a6e7778SPieter Jansen van Vuuren return -EINVAL; 13240a6e7778SPieter Jansen van Vuuren } 13250a6e7778SPieter Jansen van Vuuren break; 1326d8f9dfaeSXin Long case TCA_FLOWER_KEY_ENC_OPTS_VXLAN: 1327d8f9dfaeSXin Long if (key->enc_opts.dst_opt_type) { 1328d8f9dfaeSXin Long NL_SET_ERR_MSG(extack, "Duplicate type for vxlan options"); 1329d8f9dfaeSXin Long return -EINVAL; 1330d8f9dfaeSXin Long } 1331d8f9dfaeSXin Long option_len = 0; 1332d8f9dfaeSXin Long key->enc_opts.dst_opt_type = TUNNEL_VXLAN_OPT; 1333d8f9dfaeSXin Long option_len = fl_set_vxlan_opt(nla_opt_key, key, 1334d8f9dfaeSXin Long key_depth, option_len, 1335d8f9dfaeSXin Long extack); 1336d8f9dfaeSXin Long if (option_len < 0) 1337d8f9dfaeSXin Long return option_len; 1338d8f9dfaeSXin Long 1339d8f9dfaeSXin Long key->enc_opts.len += option_len; 1340d8f9dfaeSXin Long /* At the same time we need to parse through the mask 1341d8f9dfaeSXin Long * in order to verify exact and mask attribute lengths. 1342d8f9dfaeSXin Long */ 1343d8f9dfaeSXin Long mask->enc_opts.dst_opt_type = TUNNEL_VXLAN_OPT; 1344d8f9dfaeSXin Long option_len = fl_set_vxlan_opt(nla_opt_msk, mask, 1345d8f9dfaeSXin Long msk_depth, option_len, 1346d8f9dfaeSXin Long extack); 1347d8f9dfaeSXin Long if (option_len < 0) 1348d8f9dfaeSXin Long return option_len; 1349d8f9dfaeSXin Long 1350d8f9dfaeSXin Long mask->enc_opts.len += option_len; 1351d8f9dfaeSXin Long if (key->enc_opts.len != mask->enc_opts.len) { 1352d8f9dfaeSXin Long NL_SET_ERR_MSG(extack, "Key and mask miss aligned"); 1353d8f9dfaeSXin Long return -EINVAL; 1354d8f9dfaeSXin Long } 1355d8f9dfaeSXin Long break; 135679b1011cSXin Long case TCA_FLOWER_KEY_ENC_OPTS_ERSPAN: 135779b1011cSXin Long if (key->enc_opts.dst_opt_type) { 135879b1011cSXin Long NL_SET_ERR_MSG(extack, "Duplicate type for erspan options"); 135979b1011cSXin Long return -EINVAL; 136079b1011cSXin Long } 136179b1011cSXin Long option_len = 0; 136279b1011cSXin Long key->enc_opts.dst_opt_type = TUNNEL_ERSPAN_OPT; 136379b1011cSXin Long option_len = fl_set_erspan_opt(nla_opt_key, key, 136479b1011cSXin Long key_depth, option_len, 136579b1011cSXin Long extack); 136679b1011cSXin Long if (option_len < 0) 136779b1011cSXin Long return option_len; 136879b1011cSXin Long 136979b1011cSXin Long key->enc_opts.len += option_len; 137079b1011cSXin Long /* At the same time we need to parse through the mask 137179b1011cSXin Long * in order to verify exact and mask attribute lengths. 137279b1011cSXin Long */ 137379b1011cSXin Long mask->enc_opts.dst_opt_type = TUNNEL_ERSPAN_OPT; 137479b1011cSXin Long option_len = fl_set_erspan_opt(nla_opt_msk, mask, 137579b1011cSXin Long msk_depth, option_len, 137679b1011cSXin Long extack); 137779b1011cSXin Long if (option_len < 0) 137879b1011cSXin Long return option_len; 137979b1011cSXin Long 138079b1011cSXin Long mask->enc_opts.len += option_len; 138179b1011cSXin Long if (key->enc_opts.len != mask->enc_opts.len) { 138279b1011cSXin Long NL_SET_ERR_MSG(extack, "Key and mask miss aligned"); 138379b1011cSXin Long return -EINVAL; 138479b1011cSXin Long } 138579b1011cSXin Long break; 13860a6e7778SPieter Jansen van Vuuren default: 13870a6e7778SPieter Jansen van Vuuren NL_SET_ERR_MSG(extack, "Unknown tunnel option type"); 13880a6e7778SPieter Jansen van Vuuren return -EINVAL; 13890a6e7778SPieter Jansen van Vuuren } 1390c96adff9SCong Wang 1391c96adff9SCong Wang if (!msk_depth) 1392c96adff9SCong Wang continue; 1393c96adff9SCong Wang 1394c96adff9SCong Wang if (!nla_ok(nla_opt_msk, msk_depth)) { 1395c96adff9SCong Wang NL_SET_ERR_MSG(extack, "A mask attribute is invalid"); 1396c96adff9SCong Wang return -EINVAL; 1397c96adff9SCong Wang } 1398c96adff9SCong Wang nla_opt_msk = nla_next(nla_opt_msk, &msk_depth); 13990a6e7778SPieter Jansen van Vuuren } 14000a6e7778SPieter Jansen van Vuuren 14010a6e7778SPieter Jansen van Vuuren return 0; 14020a6e7778SPieter Jansen van Vuuren } 14030a6e7778SPieter Jansen van Vuuren 14041bcc51acSwenxu static int fl_validate_ct_state(u16 state, struct nlattr *tb, 14051bcc51acSwenxu struct netlink_ext_ack *extack) 14061bcc51acSwenxu { 14071bcc51acSwenxu if (state && !(state & TCA_FLOWER_KEY_CT_FLAGS_TRACKED)) { 14081bcc51acSwenxu NL_SET_ERR_MSG_ATTR(extack, tb, 14091bcc51acSwenxu "no trk, so no other flag can be set"); 14101bcc51acSwenxu return -EINVAL; 14111bcc51acSwenxu } 14121bcc51acSwenxu 14131bcc51acSwenxu if (state & TCA_FLOWER_KEY_CT_FLAGS_NEW && 14141bcc51acSwenxu state & TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED) { 14151bcc51acSwenxu NL_SET_ERR_MSG_ATTR(extack, tb, 14161bcc51acSwenxu "new and est are mutually exclusive"); 14171bcc51acSwenxu return -EINVAL; 14181bcc51acSwenxu } 14191bcc51acSwenxu 14203aed8b63Swenxu if (state & TCA_FLOWER_KEY_CT_FLAGS_INVALID && 14213aed8b63Swenxu state & ~(TCA_FLOWER_KEY_CT_FLAGS_TRACKED | 14223aed8b63Swenxu TCA_FLOWER_KEY_CT_FLAGS_INVALID)) { 14233aed8b63Swenxu NL_SET_ERR_MSG_ATTR(extack, tb, 14243aed8b63Swenxu "when inv is set, only trk may be set"); 14253aed8b63Swenxu return -EINVAL; 14263aed8b63Swenxu } 14273aed8b63Swenxu 14283aed8b63Swenxu if (state & TCA_FLOWER_KEY_CT_FLAGS_NEW && 14293aed8b63Swenxu state & TCA_FLOWER_KEY_CT_FLAGS_REPLY) { 14303aed8b63Swenxu NL_SET_ERR_MSG_ATTR(extack, tb, 14313aed8b63Swenxu "new and rpl are mutually exclusive"); 14323aed8b63Swenxu return -EINVAL; 14333aed8b63Swenxu } 14343aed8b63Swenxu 14351bcc51acSwenxu return 0; 14361bcc51acSwenxu } 14371bcc51acSwenxu 1438e0ace68aSPaul Blakey static int fl_set_key_ct(struct nlattr **tb, 1439e0ace68aSPaul Blakey struct flow_dissector_key_ct *key, 1440e0ace68aSPaul Blakey struct flow_dissector_key_ct *mask, 1441e0ace68aSPaul Blakey struct netlink_ext_ack *extack) 1442e0ace68aSPaul Blakey { 1443e0ace68aSPaul Blakey if (tb[TCA_FLOWER_KEY_CT_STATE]) { 14441bcc51acSwenxu int err; 14451bcc51acSwenxu 1446e0ace68aSPaul Blakey if (!IS_ENABLED(CONFIG_NF_CONNTRACK)) { 1447e0ace68aSPaul Blakey NL_SET_ERR_MSG(extack, "Conntrack isn't enabled"); 1448e0ace68aSPaul Blakey return -EOPNOTSUPP; 1449e0ace68aSPaul Blakey } 1450e0ace68aSPaul Blakey fl_set_key_val(tb, &key->ct_state, TCA_FLOWER_KEY_CT_STATE, 1451e0ace68aSPaul Blakey &mask->ct_state, TCA_FLOWER_KEY_CT_STATE_MASK, 1452e0ace68aSPaul Blakey sizeof(key->ct_state)); 14531bcc51acSwenxu 14541bcc51acSwenxu err = fl_validate_ct_state(mask->ct_state, 14551bcc51acSwenxu tb[TCA_FLOWER_KEY_CT_STATE_MASK], 14561bcc51acSwenxu extack); 14571bcc51acSwenxu if (err) 14581bcc51acSwenxu return err; 14591bcc51acSwenxu 1460e0ace68aSPaul Blakey } 1461e0ace68aSPaul Blakey if (tb[TCA_FLOWER_KEY_CT_ZONE]) { 1462e0ace68aSPaul Blakey if (!IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES)) { 1463e0ace68aSPaul Blakey NL_SET_ERR_MSG(extack, "Conntrack zones isn't enabled"); 1464e0ace68aSPaul Blakey return -EOPNOTSUPP; 1465e0ace68aSPaul Blakey } 1466e0ace68aSPaul Blakey fl_set_key_val(tb, &key->ct_zone, TCA_FLOWER_KEY_CT_ZONE, 1467e0ace68aSPaul Blakey &mask->ct_zone, TCA_FLOWER_KEY_CT_ZONE_MASK, 1468e0ace68aSPaul Blakey sizeof(key->ct_zone)); 1469e0ace68aSPaul Blakey } 1470e0ace68aSPaul Blakey if (tb[TCA_FLOWER_KEY_CT_MARK]) { 1471e0ace68aSPaul Blakey if (!IS_ENABLED(CONFIG_NF_CONNTRACK_MARK)) { 1472e0ace68aSPaul Blakey NL_SET_ERR_MSG(extack, "Conntrack mark isn't enabled"); 1473e0ace68aSPaul Blakey return -EOPNOTSUPP; 1474e0ace68aSPaul Blakey } 1475e0ace68aSPaul Blakey fl_set_key_val(tb, &key->ct_mark, TCA_FLOWER_KEY_CT_MARK, 1476e0ace68aSPaul Blakey &mask->ct_mark, TCA_FLOWER_KEY_CT_MARK_MASK, 1477e0ace68aSPaul Blakey sizeof(key->ct_mark)); 1478e0ace68aSPaul Blakey } 1479e0ace68aSPaul Blakey if (tb[TCA_FLOWER_KEY_CT_LABELS]) { 1480e0ace68aSPaul Blakey if (!IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS)) { 1481e0ace68aSPaul Blakey NL_SET_ERR_MSG(extack, "Conntrack labels aren't enabled"); 1482e0ace68aSPaul Blakey return -EOPNOTSUPP; 1483e0ace68aSPaul Blakey } 1484e0ace68aSPaul Blakey fl_set_key_val(tb, key->ct_labels, TCA_FLOWER_KEY_CT_LABELS, 1485e0ace68aSPaul Blakey mask->ct_labels, TCA_FLOWER_KEY_CT_LABELS_MASK, 1486e0ace68aSPaul Blakey sizeof(key->ct_labels)); 1487e0ace68aSPaul Blakey } 1488e0ace68aSPaul Blakey 1489e0ace68aSPaul Blakey return 0; 1490e0ace68aSPaul Blakey } 1491e0ace68aSPaul Blakey 149277b9900eSJiri Pirko static int fl_set_key(struct net *net, struct nlattr **tb, 14931057c55fSAlexander Aring struct fl_flow_key *key, struct fl_flow_key *mask, 14941057c55fSAlexander Aring struct netlink_ext_ack *extack) 149577b9900eSJiri Pirko { 14969399ae9aSHadar Hen Zion __be16 ethertype; 1497d9724772SOr Gerlitz int ret = 0; 1498a5148626SJiri Pirko 149977b9900eSJiri Pirko if (tb[TCA_FLOWER_INDEV]) { 15001057c55fSAlexander Aring int err = tcf_change_indev(net, tb[TCA_FLOWER_INDEV], extack); 150177b9900eSJiri Pirko if (err < 0) 150277b9900eSJiri Pirko return err; 15038212ed77SJiri Pirko key->meta.ingress_ifindex = err; 15048212ed77SJiri Pirko mask->meta.ingress_ifindex = 0xffffffff; 150577b9900eSJiri Pirko } 150677b9900eSJiri Pirko 150777b9900eSJiri Pirko fl_set_key_val(tb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST, 150877b9900eSJiri Pirko mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK, 150977b9900eSJiri Pirko sizeof(key->eth.dst)); 151077b9900eSJiri Pirko fl_set_key_val(tb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC, 151177b9900eSJiri Pirko mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK, 151277b9900eSJiri Pirko sizeof(key->eth.src)); 151366530bdfSJamal Hadi Salim 15140b498a52SArnd Bergmann if (tb[TCA_FLOWER_KEY_ETH_TYPE]) { 15159399ae9aSHadar Hen Zion ethertype = nla_get_be16(tb[TCA_FLOWER_KEY_ETH_TYPE]); 15169399ae9aSHadar Hen Zion 1517aaab0834SJianbo Liu if (eth_type_vlan(ethertype)) { 1518d64efd09SJianbo Liu fl_set_key_vlan(tb, ethertype, TCA_FLOWER_KEY_VLAN_ID, 1519d64efd09SJianbo Liu TCA_FLOWER_KEY_VLAN_PRIO, &key->vlan, 1520d64efd09SJianbo Liu &mask->vlan); 1521d64efd09SJianbo Liu 15225e9a0fe4SJianbo Liu if (tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]) { 1523d64efd09SJianbo Liu ethertype = nla_get_be16(tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]); 1524d64efd09SJianbo Liu if (eth_type_vlan(ethertype)) { 1525d64efd09SJianbo Liu fl_set_key_vlan(tb, ethertype, 1526d64efd09SJianbo Liu TCA_FLOWER_KEY_CVLAN_ID, 1527d64efd09SJianbo Liu TCA_FLOWER_KEY_CVLAN_PRIO, 1528d64efd09SJianbo Liu &key->cvlan, &mask->cvlan); 15299399ae9aSHadar Hen Zion fl_set_key_val(tb, &key->basic.n_proto, 1530d64efd09SJianbo Liu TCA_FLOWER_KEY_CVLAN_ETH_TYPE, 1531d64efd09SJianbo Liu &mask->basic.n_proto, 1532d64efd09SJianbo Liu TCA_FLOWER_UNSPEC, 153377b9900eSJiri Pirko sizeof(key->basic.n_proto)); 15349399ae9aSHadar Hen Zion } else { 15359399ae9aSHadar Hen Zion key->basic.n_proto = ethertype; 15369399ae9aSHadar Hen Zion mask->basic.n_proto = cpu_to_be16(~0); 15379399ae9aSHadar Hen Zion } 15385e9a0fe4SJianbo Liu } 1539d64efd09SJianbo Liu } else { 1540d64efd09SJianbo Liu key->basic.n_proto = ethertype; 1541d64efd09SJianbo Liu mask->basic.n_proto = cpu_to_be16(~0); 1542d64efd09SJianbo Liu } 15430b498a52SArnd Bergmann } 154466530bdfSJamal Hadi Salim 154577b9900eSJiri Pirko if (key->basic.n_proto == htons(ETH_P_IP) || 154677b9900eSJiri Pirko key->basic.n_proto == htons(ETH_P_IPV6)) { 154777b9900eSJiri Pirko fl_set_key_val(tb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO, 154877b9900eSJiri Pirko &mask->basic.ip_proto, TCA_FLOWER_UNSPEC, 154977b9900eSJiri Pirko sizeof(key->basic.ip_proto)); 15500e2c17b6SOr Gerlitz fl_set_key_ip(tb, false, &key->ip, &mask->ip); 155177b9900eSJiri Pirko } 155266530bdfSJamal Hadi Salim 155366530bdfSJamal Hadi Salim if (tb[TCA_FLOWER_KEY_IPV4_SRC] || tb[TCA_FLOWER_KEY_IPV4_DST]) { 155466530bdfSJamal Hadi Salim key->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; 1555970bfcd0SPaul Blakey mask->control.addr_type = ~0; 155677b9900eSJiri Pirko fl_set_key_val(tb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC, 155777b9900eSJiri Pirko &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK, 155877b9900eSJiri Pirko sizeof(key->ipv4.src)); 155977b9900eSJiri Pirko fl_set_key_val(tb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST, 156077b9900eSJiri Pirko &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK, 156177b9900eSJiri Pirko sizeof(key->ipv4.dst)); 156266530bdfSJamal Hadi Salim } else if (tb[TCA_FLOWER_KEY_IPV6_SRC] || tb[TCA_FLOWER_KEY_IPV6_DST]) { 156366530bdfSJamal Hadi Salim key->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; 1564970bfcd0SPaul Blakey mask->control.addr_type = ~0; 156577b9900eSJiri Pirko fl_set_key_val(tb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC, 156677b9900eSJiri Pirko &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK, 156777b9900eSJiri Pirko sizeof(key->ipv6.src)); 156877b9900eSJiri Pirko fl_set_key_val(tb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST, 156977b9900eSJiri Pirko &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK, 157077b9900eSJiri Pirko sizeof(key->ipv6.dst)); 157177b9900eSJiri Pirko } 157266530bdfSJamal Hadi Salim 157377b9900eSJiri Pirko if (key->basic.ip_proto == IPPROTO_TCP) { 157477b9900eSJiri Pirko fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC, 1575aa72d708SOr Gerlitz &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK, 157677b9900eSJiri Pirko sizeof(key->tp.src)); 157777b9900eSJiri Pirko fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST, 1578aa72d708SOr Gerlitz &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK, 157977b9900eSJiri Pirko sizeof(key->tp.dst)); 1580fdfc7dd6SJiri Pirko fl_set_key_val(tb, &key->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS, 1581fdfc7dd6SJiri Pirko &mask->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS_MASK, 1582fdfc7dd6SJiri Pirko sizeof(key->tcp.flags)); 158377b9900eSJiri Pirko } else if (key->basic.ip_proto == IPPROTO_UDP) { 158477b9900eSJiri Pirko fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC, 1585aa72d708SOr Gerlitz &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK, 158677b9900eSJiri Pirko sizeof(key->tp.src)); 158777b9900eSJiri Pirko fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST, 1588aa72d708SOr Gerlitz &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK, 158977b9900eSJiri Pirko sizeof(key->tp.dst)); 15905976c5f4SSimon Horman } else if (key->basic.ip_proto == IPPROTO_SCTP) { 15915976c5f4SSimon Horman fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC, 15925976c5f4SSimon Horman &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK, 15935976c5f4SSimon Horman sizeof(key->tp.src)); 15945976c5f4SSimon Horman fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST, 15955976c5f4SSimon Horman &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK, 15965976c5f4SSimon Horman sizeof(key->tp.dst)); 15977b684884SSimon Horman } else if (key->basic.n_proto == htons(ETH_P_IP) && 15987b684884SSimon Horman key->basic.ip_proto == IPPROTO_ICMP) { 15997b684884SSimon Horman fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV4_TYPE, 16007b684884SSimon Horman &mask->icmp.type, 16017b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_TYPE_MASK, 16027b684884SSimon Horman sizeof(key->icmp.type)); 16037b684884SSimon Horman fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV4_CODE, 16047b684884SSimon Horman &mask->icmp.code, 16057b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_CODE_MASK, 16067b684884SSimon Horman sizeof(key->icmp.code)); 16077b684884SSimon Horman } else if (key->basic.n_proto == htons(ETH_P_IPV6) && 16087b684884SSimon Horman key->basic.ip_proto == IPPROTO_ICMPV6) { 16097b684884SSimon Horman fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV6_TYPE, 16107b684884SSimon Horman &mask->icmp.type, 16117b684884SSimon Horman TCA_FLOWER_KEY_ICMPV6_TYPE_MASK, 16127b684884SSimon Horman sizeof(key->icmp.type)); 1613040587afSSimon Horman fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV6_CODE, 16147b684884SSimon Horman &mask->icmp.code, 1615040587afSSimon Horman TCA_FLOWER_KEY_ICMPV6_CODE_MASK, 16167b684884SSimon Horman sizeof(key->icmp.code)); 1617a577d8f7SBenjamin LaHaise } else if (key->basic.n_proto == htons(ETH_P_MPLS_UC) || 1618a577d8f7SBenjamin LaHaise key->basic.n_proto == htons(ETH_P_MPLS_MC)) { 1619442f730eSGuillaume Nault ret = fl_set_key_mpls(tb, &key->mpls, &mask->mpls, extack); 16201a7fca63SBenjamin LaHaise if (ret) 16211a7fca63SBenjamin LaHaise return ret; 162299d31326SSimon Horman } else if (key->basic.n_proto == htons(ETH_P_ARP) || 162399d31326SSimon Horman key->basic.n_proto == htons(ETH_P_RARP)) { 162499d31326SSimon Horman fl_set_key_val(tb, &key->arp.sip, TCA_FLOWER_KEY_ARP_SIP, 162599d31326SSimon Horman &mask->arp.sip, TCA_FLOWER_KEY_ARP_SIP_MASK, 162699d31326SSimon Horman sizeof(key->arp.sip)); 162799d31326SSimon Horman fl_set_key_val(tb, &key->arp.tip, TCA_FLOWER_KEY_ARP_TIP, 162899d31326SSimon Horman &mask->arp.tip, TCA_FLOWER_KEY_ARP_TIP_MASK, 162999d31326SSimon Horman sizeof(key->arp.tip)); 163099d31326SSimon Horman fl_set_key_val(tb, &key->arp.op, TCA_FLOWER_KEY_ARP_OP, 163199d31326SSimon Horman &mask->arp.op, TCA_FLOWER_KEY_ARP_OP_MASK, 163299d31326SSimon Horman sizeof(key->arp.op)); 163399d31326SSimon Horman fl_set_key_val(tb, key->arp.sha, TCA_FLOWER_KEY_ARP_SHA, 163499d31326SSimon Horman mask->arp.sha, TCA_FLOWER_KEY_ARP_SHA_MASK, 163599d31326SSimon Horman sizeof(key->arp.sha)); 163699d31326SSimon Horman fl_set_key_val(tb, key->arp.tha, TCA_FLOWER_KEY_ARP_THA, 163799d31326SSimon Horman mask->arp.tha, TCA_FLOWER_KEY_ARP_THA_MASK, 163899d31326SSimon Horman sizeof(key->arp.tha)); 163977b9900eSJiri Pirko } 164077b9900eSJiri Pirko 16415c72299fSAmritha Nambiar if (key->basic.ip_proto == IPPROTO_TCP || 16425c72299fSAmritha Nambiar key->basic.ip_proto == IPPROTO_UDP || 16435c72299fSAmritha Nambiar key->basic.ip_proto == IPPROTO_SCTP) { 1644bd7d4c12SGuillaume Nault ret = fl_set_key_port_range(tb, key, mask, extack); 16455c72299fSAmritha Nambiar if (ret) 16465c72299fSAmritha Nambiar return ret; 16475c72299fSAmritha Nambiar } 16485c72299fSAmritha Nambiar 1649bc3103f1SAmir Vadai if (tb[TCA_FLOWER_KEY_ENC_IPV4_SRC] || 1650bc3103f1SAmir Vadai tb[TCA_FLOWER_KEY_ENC_IPV4_DST]) { 1651bc3103f1SAmir Vadai key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; 1652970bfcd0SPaul Blakey mask->enc_control.addr_type = ~0; 1653bc3103f1SAmir Vadai fl_set_key_val(tb, &key->enc_ipv4.src, 1654bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_SRC, 1655bc3103f1SAmir Vadai &mask->enc_ipv4.src, 1656bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK, 1657bc3103f1SAmir Vadai sizeof(key->enc_ipv4.src)); 1658bc3103f1SAmir Vadai fl_set_key_val(tb, &key->enc_ipv4.dst, 1659bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_DST, 1660bc3103f1SAmir Vadai &mask->enc_ipv4.dst, 1661bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_DST_MASK, 1662bc3103f1SAmir Vadai sizeof(key->enc_ipv4.dst)); 1663bc3103f1SAmir Vadai } 1664bc3103f1SAmir Vadai 1665bc3103f1SAmir Vadai if (tb[TCA_FLOWER_KEY_ENC_IPV6_SRC] || 1666bc3103f1SAmir Vadai tb[TCA_FLOWER_KEY_ENC_IPV6_DST]) { 1667bc3103f1SAmir Vadai key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; 1668970bfcd0SPaul Blakey mask->enc_control.addr_type = ~0; 1669bc3103f1SAmir Vadai fl_set_key_val(tb, &key->enc_ipv6.src, 1670bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_SRC, 1671bc3103f1SAmir Vadai &mask->enc_ipv6.src, 1672bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK, 1673bc3103f1SAmir Vadai sizeof(key->enc_ipv6.src)); 1674bc3103f1SAmir Vadai fl_set_key_val(tb, &key->enc_ipv6.dst, 1675bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_DST, 1676bc3103f1SAmir Vadai &mask->enc_ipv6.dst, 1677bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_DST_MASK, 1678bc3103f1SAmir Vadai sizeof(key->enc_ipv6.dst)); 1679bc3103f1SAmir Vadai } 1680bc3103f1SAmir Vadai 1681bc3103f1SAmir Vadai fl_set_key_val(tb, &key->enc_key_id.keyid, TCA_FLOWER_KEY_ENC_KEY_ID, 1682eb523f42SHadar Hen Zion &mask->enc_key_id.keyid, TCA_FLOWER_UNSPEC, 1683bc3103f1SAmir Vadai sizeof(key->enc_key_id.keyid)); 1684bc3103f1SAmir Vadai 1685f4d997fdSHadar Hen Zion fl_set_key_val(tb, &key->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT, 1686f4d997fdSHadar Hen Zion &mask->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK, 1687f4d997fdSHadar Hen Zion sizeof(key->enc_tp.src)); 1688f4d997fdSHadar Hen Zion 1689f4d997fdSHadar Hen Zion fl_set_key_val(tb, &key->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT, 1690f4d997fdSHadar Hen Zion &mask->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK, 1691f4d997fdSHadar Hen Zion sizeof(key->enc_tp.dst)); 1692f4d997fdSHadar Hen Zion 16930e2c17b6SOr Gerlitz fl_set_key_ip(tb, true, &key->enc_ip, &mask->enc_ip); 16940e2c17b6SOr Gerlitz 16955923b8f7SAriel Levkovich fl_set_key_val(tb, &key->hash.hash, TCA_FLOWER_KEY_HASH, 16965923b8f7SAriel Levkovich &mask->hash.hash, TCA_FLOWER_KEY_HASH_MASK, 16975923b8f7SAriel Levkovich sizeof(key->hash.hash)); 16985923b8f7SAriel Levkovich 16990a6e7778SPieter Jansen van Vuuren if (tb[TCA_FLOWER_KEY_ENC_OPTS]) { 17000a6e7778SPieter Jansen van Vuuren ret = fl_set_enc_opt(tb, key, mask, extack); 17010a6e7778SPieter Jansen van Vuuren if (ret) 17020a6e7778SPieter Jansen van Vuuren return ret; 17030a6e7778SPieter Jansen van Vuuren } 17040a6e7778SPieter Jansen van Vuuren 1705e0ace68aSPaul Blakey ret = fl_set_key_ct(tb, &key->ct, &mask->ct, extack); 1706e0ace68aSPaul Blakey if (ret) 1707e0ace68aSPaul Blakey return ret; 1708e0ace68aSPaul Blakey 1709d9724772SOr Gerlitz if (tb[TCA_FLOWER_KEY_FLAGS]) 1710e304e21aSGuillaume Nault ret = fl_set_key_flags(tb, &key->control.flags, 1711e304e21aSGuillaume Nault &mask->control.flags, extack); 1712faa3ffceSOr Gerlitz 1713d9724772SOr Gerlitz return ret; 171477b9900eSJiri Pirko } 171577b9900eSJiri Pirko 171605cd271fSPaul Blakey static void fl_mask_copy(struct fl_flow_mask *dst, 171705cd271fSPaul Blakey struct fl_flow_mask *src) 171877b9900eSJiri Pirko { 171905cd271fSPaul Blakey const void *psrc = fl_key_get_start(&src->key, src); 172005cd271fSPaul Blakey void *pdst = fl_key_get_start(&dst->key, src); 172177b9900eSJiri Pirko 172205cd271fSPaul Blakey memcpy(pdst, psrc, fl_mask_range(src)); 172305cd271fSPaul Blakey dst->range = src->range; 172477b9900eSJiri Pirko } 172577b9900eSJiri Pirko 172677b9900eSJiri Pirko static const struct rhashtable_params fl_ht_params = { 172777b9900eSJiri Pirko .key_offset = offsetof(struct cls_fl_filter, mkey), /* base offset */ 172877b9900eSJiri Pirko .head_offset = offsetof(struct cls_fl_filter, ht_node), 172977b9900eSJiri Pirko .automatic_shrinking = true, 173077b9900eSJiri Pirko }; 173177b9900eSJiri Pirko 173205cd271fSPaul Blakey static int fl_init_mask_hashtable(struct fl_flow_mask *mask) 173377b9900eSJiri Pirko { 173405cd271fSPaul Blakey mask->filter_ht_params = fl_ht_params; 173505cd271fSPaul Blakey mask->filter_ht_params.key_len = fl_mask_range(mask); 173605cd271fSPaul Blakey mask->filter_ht_params.key_offset += mask->range.start; 173777b9900eSJiri Pirko 173805cd271fSPaul Blakey return rhashtable_init(&mask->ht, &mask->filter_ht_params); 173977b9900eSJiri Pirko } 174077b9900eSJiri Pirko 174177b9900eSJiri Pirko #define FL_KEY_MEMBER_OFFSET(member) offsetof(struct fl_flow_key, member) 1742c593642cSPankaj Bharadiya #define FL_KEY_MEMBER_SIZE(member) sizeof_field(struct fl_flow_key, member) 174377b9900eSJiri Pirko 1744339ba878SHadar Hen Zion #define FL_KEY_IS_MASKED(mask, member) \ 1745339ba878SHadar Hen Zion memchr_inv(((char *)mask) + FL_KEY_MEMBER_OFFSET(member), \ 1746339ba878SHadar Hen Zion 0, FL_KEY_MEMBER_SIZE(member)) \ 174777b9900eSJiri Pirko 174877b9900eSJiri Pirko #define FL_KEY_SET(keys, cnt, id, member) \ 174977b9900eSJiri Pirko do { \ 175077b9900eSJiri Pirko keys[cnt].key_id = id; \ 175177b9900eSJiri Pirko keys[cnt].offset = FL_KEY_MEMBER_OFFSET(member); \ 175277b9900eSJiri Pirko cnt++; \ 175377b9900eSJiri Pirko } while(0); 175477b9900eSJiri Pirko 1755339ba878SHadar Hen Zion #define FL_KEY_SET_IF_MASKED(mask, keys, cnt, id, member) \ 175677b9900eSJiri Pirko do { \ 1757339ba878SHadar Hen Zion if (FL_KEY_IS_MASKED(mask, member)) \ 175877b9900eSJiri Pirko FL_KEY_SET(keys, cnt, id, member); \ 175977b9900eSJiri Pirko } while(0); 176077b9900eSJiri Pirko 176133fb5cbaSJiri Pirko static void fl_init_dissector(struct flow_dissector *dissector, 176233fb5cbaSJiri Pirko struct fl_flow_key *mask) 176377b9900eSJiri Pirko { 176477b9900eSJiri Pirko struct flow_dissector_key keys[FLOW_DISSECTOR_KEY_MAX]; 176577b9900eSJiri Pirko size_t cnt = 0; 176677b9900eSJiri Pirko 17678212ed77SJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 17688212ed77SJiri Pirko FLOW_DISSECTOR_KEY_META, meta); 176942aecaa9STom Herbert FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_CONTROL, control); 177077b9900eSJiri Pirko FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_BASIC, basic); 177133fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 177277b9900eSJiri Pirko FLOW_DISSECTOR_KEY_ETH_ADDRS, eth); 177333fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 177477b9900eSJiri Pirko FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4); 177533fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 177677b9900eSJiri Pirko FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6); 17778ffb055bSYoshiki Komachi FL_KEY_SET_IF_MASKED(mask, keys, cnt, 17788ffb055bSYoshiki Komachi FLOW_DISSECTOR_KEY_PORTS, tp); 17798ffb055bSYoshiki Komachi FL_KEY_SET_IF_MASKED(mask, keys, cnt, 17808ffb055bSYoshiki Komachi FLOW_DISSECTOR_KEY_PORTS_RANGE, tp_range); 178133fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 17824d80cc0aSOr Gerlitz FLOW_DISSECTOR_KEY_IP, ip); 178333fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 1784fdfc7dd6SJiri Pirko FLOW_DISSECTOR_KEY_TCP, tcp); 178533fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 17867b684884SSimon Horman FLOW_DISSECTOR_KEY_ICMP, icmp); 178733fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 178899d31326SSimon Horman FLOW_DISSECTOR_KEY_ARP, arp); 178933fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 1790a577d8f7SBenjamin LaHaise FLOW_DISSECTOR_KEY_MPLS, mpls); 179133fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 17929399ae9aSHadar Hen Zion FLOW_DISSECTOR_KEY_VLAN, vlan); 179333fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 1794d64efd09SJianbo Liu FLOW_DISSECTOR_KEY_CVLAN, cvlan); 179533fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 1796519d1052SHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_KEYID, enc_key_id); 179733fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 1798519d1052SHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, enc_ipv4); 179933fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 1800519d1052SHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, enc_ipv6); 180133fb5cbaSJiri Pirko if (FL_KEY_IS_MASKED(mask, enc_ipv4) || 180233fb5cbaSJiri Pirko FL_KEY_IS_MASKED(mask, enc_ipv6)) 1803519d1052SHadar Hen Zion FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_ENC_CONTROL, 1804519d1052SHadar Hen Zion enc_control); 180533fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 1806f4d997fdSHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_PORTS, enc_tp); 180733fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 18080e2c17b6SOr Gerlitz FLOW_DISSECTOR_KEY_ENC_IP, enc_ip); 18090a6e7778SPieter Jansen van Vuuren FL_KEY_SET_IF_MASKED(mask, keys, cnt, 18100a6e7778SPieter Jansen van Vuuren FLOW_DISSECTOR_KEY_ENC_OPTS, enc_opts); 1811e0ace68aSPaul Blakey FL_KEY_SET_IF_MASKED(mask, keys, cnt, 1812e0ace68aSPaul Blakey FLOW_DISSECTOR_KEY_CT, ct); 18135923b8f7SAriel Levkovich FL_KEY_SET_IF_MASKED(mask, keys, cnt, 18145923b8f7SAriel Levkovich FLOW_DISSECTOR_KEY_HASH, hash); 181577b9900eSJiri Pirko 181633fb5cbaSJiri Pirko skb_flow_dissector_init(dissector, keys, cnt); 181705cd271fSPaul Blakey } 181805cd271fSPaul Blakey 181905cd271fSPaul Blakey static struct fl_flow_mask *fl_create_new_mask(struct cls_fl_head *head, 182005cd271fSPaul Blakey struct fl_flow_mask *mask) 182105cd271fSPaul Blakey { 182205cd271fSPaul Blakey struct fl_flow_mask *newmask; 182305cd271fSPaul Blakey int err; 182405cd271fSPaul Blakey 182505cd271fSPaul Blakey newmask = kzalloc(sizeof(*newmask), GFP_KERNEL); 182605cd271fSPaul Blakey if (!newmask) 182705cd271fSPaul Blakey return ERR_PTR(-ENOMEM); 182805cd271fSPaul Blakey 182905cd271fSPaul Blakey fl_mask_copy(newmask, mask); 183005cd271fSPaul Blakey 18318ffb055bSYoshiki Komachi if ((newmask->key.tp_range.tp_min.dst && 18328ffb055bSYoshiki Komachi newmask->key.tp_range.tp_max.dst) || 18338ffb055bSYoshiki Komachi (newmask->key.tp_range.tp_min.src && 18348ffb055bSYoshiki Komachi newmask->key.tp_range.tp_max.src)) 18355c72299fSAmritha Nambiar newmask->flags |= TCA_FLOWER_MASK_FLAGS_RANGE; 18365c72299fSAmritha Nambiar 183705cd271fSPaul Blakey err = fl_init_mask_hashtable(newmask); 183805cd271fSPaul Blakey if (err) 183905cd271fSPaul Blakey goto errout_free; 184005cd271fSPaul Blakey 184133fb5cbaSJiri Pirko fl_init_dissector(&newmask->dissector, &newmask->key); 184205cd271fSPaul Blakey 184305cd271fSPaul Blakey INIT_LIST_HEAD_RCU(&newmask->filters); 184405cd271fSPaul Blakey 1845f48ef4d5SVlad Buslov refcount_set(&newmask->refcnt, 1); 1846195c234dSVlad Buslov err = rhashtable_replace_fast(&head->ht, &mask->ht_node, 1847195c234dSVlad Buslov &newmask->ht_node, mask_ht_params); 184805cd271fSPaul Blakey if (err) 184905cd271fSPaul Blakey goto errout_destroy; 185005cd271fSPaul Blakey 1851259e60f9SVlad Buslov spin_lock(&head->masks_lock); 185205cd271fSPaul Blakey list_add_tail_rcu(&newmask->list, &head->masks); 1853259e60f9SVlad Buslov spin_unlock(&head->masks_lock); 185405cd271fSPaul Blakey 185505cd271fSPaul Blakey return newmask; 185605cd271fSPaul Blakey 185705cd271fSPaul Blakey errout_destroy: 185805cd271fSPaul Blakey rhashtable_destroy(&newmask->ht); 185905cd271fSPaul Blakey errout_free: 186005cd271fSPaul Blakey kfree(newmask); 186105cd271fSPaul Blakey 186205cd271fSPaul Blakey return ERR_PTR(err); 186377b9900eSJiri Pirko } 186477b9900eSJiri Pirko 186577b9900eSJiri Pirko static int fl_check_assign_mask(struct cls_fl_head *head, 186605cd271fSPaul Blakey struct cls_fl_filter *fnew, 186705cd271fSPaul Blakey struct cls_fl_filter *fold, 186877b9900eSJiri Pirko struct fl_flow_mask *mask) 186977b9900eSJiri Pirko { 187005cd271fSPaul Blakey struct fl_flow_mask *newmask; 1871f48ef4d5SVlad Buslov int ret = 0; 187277b9900eSJiri Pirko 1873f48ef4d5SVlad Buslov rcu_read_lock(); 1874195c234dSVlad Buslov 1875195c234dSVlad Buslov /* Insert mask as temporary node to prevent concurrent creation of mask 1876195c234dSVlad Buslov * with same key. Any concurrent lookups with same key will return 187799815f50SVlad Buslov * -EAGAIN because mask's refcnt is zero. 1878195c234dSVlad Buslov */ 1879195c234dSVlad Buslov fnew->mask = rhashtable_lookup_get_insert_fast(&head->ht, 1880195c234dSVlad Buslov &mask->ht_node, 1881195c234dSVlad Buslov mask_ht_params); 188205cd271fSPaul Blakey if (!fnew->mask) { 1883f48ef4d5SVlad Buslov rcu_read_unlock(); 1884f48ef4d5SVlad Buslov 1885195c234dSVlad Buslov if (fold) { 1886195c234dSVlad Buslov ret = -EINVAL; 1887195c234dSVlad Buslov goto errout_cleanup; 1888195c234dSVlad Buslov } 188905cd271fSPaul Blakey 189005cd271fSPaul Blakey newmask = fl_create_new_mask(head, mask); 1891195c234dSVlad Buslov if (IS_ERR(newmask)) { 1892195c234dSVlad Buslov ret = PTR_ERR(newmask); 1893195c234dSVlad Buslov goto errout_cleanup; 1894195c234dSVlad Buslov } 189505cd271fSPaul Blakey 189605cd271fSPaul Blakey fnew->mask = newmask; 189777b9900eSJiri Pirko return 0; 1898195c234dSVlad Buslov } else if (IS_ERR(fnew->mask)) { 1899195c234dSVlad Buslov ret = PTR_ERR(fnew->mask); 1900f48ef4d5SVlad Buslov } else if (fold && fold->mask != fnew->mask) { 1901f48ef4d5SVlad Buslov ret = -EINVAL; 1902f48ef4d5SVlad Buslov } else if (!refcount_inc_not_zero(&fnew->mask->refcnt)) { 1903f48ef4d5SVlad Buslov /* Mask was deleted concurrently, try again */ 1904f48ef4d5SVlad Buslov ret = -EAGAIN; 1905f48ef4d5SVlad Buslov } 1906f48ef4d5SVlad Buslov rcu_read_unlock(); 1907f48ef4d5SVlad Buslov return ret; 1908195c234dSVlad Buslov 1909195c234dSVlad Buslov errout_cleanup: 1910195c234dSVlad Buslov rhashtable_remove_fast(&head->ht, &mask->ht_node, 1911195c234dSVlad Buslov mask_ht_params); 1912195c234dSVlad Buslov return ret; 191377b9900eSJiri Pirko } 191477b9900eSJiri Pirko 191577b9900eSJiri Pirko static int fl_set_parms(struct net *net, struct tcf_proto *tp, 191677b9900eSJiri Pirko struct cls_fl_filter *f, struct fl_flow_mask *mask, 191777b9900eSJiri Pirko unsigned long base, struct nlattr **tb, 191850a56190SAlexander Aring struct nlattr *est, bool ovr, 1919c24e43d8SVlad Buslov struct fl_flow_tmplt *tmplt, bool rtnl_held, 192050a56190SAlexander Aring struct netlink_ext_ack *extack) 192177b9900eSJiri Pirko { 192277b9900eSJiri Pirko int err; 192377b9900eSJiri Pirko 1924c24e43d8SVlad Buslov err = tcf_exts_validate(net, tp, tb, est, &f->exts, ovr, rtnl_held, 1925ec6743a1SVlad Buslov extack); 192677b9900eSJiri Pirko if (err < 0) 192777b9900eSJiri Pirko return err; 192877b9900eSJiri Pirko 192977b9900eSJiri Pirko if (tb[TCA_FLOWER_CLASSID]) { 193077b9900eSJiri Pirko f->res.classid = nla_get_u32(tb[TCA_FLOWER_CLASSID]); 1931c24e43d8SVlad Buslov if (!rtnl_held) 1932c24e43d8SVlad Buslov rtnl_lock(); 193377b9900eSJiri Pirko tcf_bind_filter(tp, &f->res, base); 1934c24e43d8SVlad Buslov if (!rtnl_held) 1935c24e43d8SVlad Buslov rtnl_unlock(); 193677b9900eSJiri Pirko } 193777b9900eSJiri Pirko 19381057c55fSAlexander Aring err = fl_set_key(net, tb, &f->key, &mask->key, extack); 193977b9900eSJiri Pirko if (err) 194045507529SJiri Pirko return err; 194177b9900eSJiri Pirko 194277b9900eSJiri Pirko fl_mask_update_range(mask); 194377b9900eSJiri Pirko fl_set_masked_key(&f->mkey, &f->key, mask); 194477b9900eSJiri Pirko 1945b95ec7ebSJiri Pirko if (!fl_mask_fits_tmplt(tmplt, mask)) { 1946b95ec7ebSJiri Pirko NL_SET_ERR_MSG_MOD(extack, "Mask does not fit the template"); 1947b95ec7ebSJiri Pirko return -EINVAL; 1948b95ec7ebSJiri Pirko } 1949b95ec7ebSJiri Pirko 195077b9900eSJiri Pirko return 0; 195177b9900eSJiri Pirko } 195277b9900eSJiri Pirko 19531f17f774SVlad Buslov static int fl_ht_insert_unique(struct cls_fl_filter *fnew, 19541f17f774SVlad Buslov struct cls_fl_filter *fold, 19551f17f774SVlad Buslov bool *in_ht) 19561f17f774SVlad Buslov { 19571f17f774SVlad Buslov struct fl_flow_mask *mask = fnew->mask; 19581f17f774SVlad Buslov int err; 19591f17f774SVlad Buslov 19609e35552aSVlad Buslov err = rhashtable_lookup_insert_fast(&mask->ht, 19611f17f774SVlad Buslov &fnew->ht_node, 19621f17f774SVlad Buslov mask->filter_ht_params); 19631f17f774SVlad Buslov if (err) { 19641f17f774SVlad Buslov *in_ht = false; 19651f17f774SVlad Buslov /* It is okay if filter with same key exists when 19661f17f774SVlad Buslov * overwriting. 19671f17f774SVlad Buslov */ 19681f17f774SVlad Buslov return fold && err == -EEXIST ? 0 : err; 19691f17f774SVlad Buslov } 19701f17f774SVlad Buslov 19711f17f774SVlad Buslov *in_ht = true; 19721f17f774SVlad Buslov return 0; 19731f17f774SVlad Buslov } 19741f17f774SVlad Buslov 197577b9900eSJiri Pirko static int fl_change(struct net *net, struct sk_buff *in_skb, 197677b9900eSJiri Pirko struct tcf_proto *tp, unsigned long base, 197777b9900eSJiri Pirko u32 handle, struct nlattr **tca, 197812db03b6SVlad Buslov void **arg, bool ovr, bool rtnl_held, 197912db03b6SVlad Buslov struct netlink_ext_ack *extack) 198077b9900eSJiri Pirko { 1981e474619aSVlad Buslov struct cls_fl_head *head = fl_head_dereference(tp); 19828113c095SWANG Cong struct cls_fl_filter *fold = *arg; 198377b9900eSJiri Pirko struct cls_fl_filter *fnew; 19842cddd201SIvan Vecera struct fl_flow_mask *mask; 198539b7b6a6SArnd Bergmann struct nlattr **tb; 19861f17f774SVlad Buslov bool in_ht; 198777b9900eSJiri Pirko int err; 198877b9900eSJiri Pirko 198906177558SVlad Buslov if (!tca[TCA_OPTIONS]) { 199006177558SVlad Buslov err = -EINVAL; 199106177558SVlad Buslov goto errout_fold; 199206177558SVlad Buslov } 199377b9900eSJiri Pirko 19942cddd201SIvan Vecera mask = kzalloc(sizeof(struct fl_flow_mask), GFP_KERNEL); 199506177558SVlad Buslov if (!mask) { 199606177558SVlad Buslov err = -ENOBUFS; 199706177558SVlad Buslov goto errout_fold; 199806177558SVlad Buslov } 199939b7b6a6SArnd Bergmann 20002cddd201SIvan Vecera tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL); 20012cddd201SIvan Vecera if (!tb) { 20022cddd201SIvan Vecera err = -ENOBUFS; 20032cddd201SIvan Vecera goto errout_mask_alloc; 20042cddd201SIvan Vecera } 20052cddd201SIvan Vecera 20068cb08174SJohannes Berg err = nla_parse_nested_deprecated(tb, TCA_FLOWER_MAX, 20078cb08174SJohannes Berg tca[TCA_OPTIONS], fl_policy, NULL); 200877b9900eSJiri Pirko if (err < 0) 200939b7b6a6SArnd Bergmann goto errout_tb; 201077b9900eSJiri Pirko 201139b7b6a6SArnd Bergmann if (fold && handle && fold->handle != handle) { 201239b7b6a6SArnd Bergmann err = -EINVAL; 201339b7b6a6SArnd Bergmann goto errout_tb; 201439b7b6a6SArnd Bergmann } 201577b9900eSJiri Pirko 201677b9900eSJiri Pirko fnew = kzalloc(sizeof(*fnew), GFP_KERNEL); 201739b7b6a6SArnd Bergmann if (!fnew) { 201839b7b6a6SArnd Bergmann err = -ENOBUFS; 201939b7b6a6SArnd Bergmann goto errout_tb; 202039b7b6a6SArnd Bergmann } 2021c049d56eSVlad Buslov INIT_LIST_HEAD(&fnew->hw_list); 202206177558SVlad Buslov refcount_set(&fnew->refcnt, 1); 202377b9900eSJiri Pirko 202414215108SCong Wang err = tcf_exts_init(&fnew->exts, net, TCA_FLOWER_ACT, 0); 2025b9a24bb7SWANG Cong if (err < 0) 2026b9a24bb7SWANG Cong goto errout; 202777b9900eSJiri Pirko 2028ecb3dea4SVlad Buslov if (tb[TCA_FLOWER_FLAGS]) { 2029ecb3dea4SVlad Buslov fnew->flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]); 2030ecb3dea4SVlad Buslov 2031ecb3dea4SVlad Buslov if (!tc_flags_valid(fnew->flags)) { 2032ecb3dea4SVlad Buslov err = -EINVAL; 2033ecb3dea4SVlad Buslov goto errout; 2034ecb3dea4SVlad Buslov } 2035ecb3dea4SVlad Buslov } 2036ecb3dea4SVlad Buslov 2037ecb3dea4SVlad Buslov err = fl_set_parms(net, tp, fnew, mask, base, tb, tca[TCA_RATE], ovr, 2038c24e43d8SVlad Buslov tp->chain->tmplt_priv, rtnl_held, extack); 2039ecb3dea4SVlad Buslov if (err) 2040ecb3dea4SVlad Buslov goto errout; 2041ecb3dea4SVlad Buslov 2042ecb3dea4SVlad Buslov err = fl_check_assign_mask(head, fnew, fold, mask); 2043ecb3dea4SVlad Buslov if (err) 2044ecb3dea4SVlad Buslov goto errout; 2045ecb3dea4SVlad Buslov 20461f17f774SVlad Buslov err = fl_ht_insert_unique(fnew, fold, &in_ht); 20471f17f774SVlad Buslov if (err) 20481f17f774SVlad Buslov goto errout_mask; 20491f17f774SVlad Buslov 205079685219SHadar Hen Zion if (!tc_skip_hw(fnew->flags)) { 2051c24e43d8SVlad Buslov err = fl_hw_replace_filter(tp, fnew, rtnl_held, extack); 2052e8eb36cdSAmir Vadai if (err) 20531f17f774SVlad Buslov goto errout_ht; 205479685219SHadar Hen Zion } 20555b33f488SAmir Vadai 205655593960SOr Gerlitz if (!tc_in_hw(fnew->flags)) 205755593960SOr Gerlitz fnew->flags |= TCA_CLS_FLAGS_NOT_IN_HW; 205855593960SOr Gerlitz 20593d81e711SVlad Buslov spin_lock(&tp->lock); 20603d81e711SVlad Buslov 2061272ffaadSVlad Buslov /* tp was deleted concurrently. -EAGAIN will cause caller to lookup 2062272ffaadSVlad Buslov * proto again or create new one, if necessary. 2063272ffaadSVlad Buslov */ 2064272ffaadSVlad Buslov if (tp->deleting) { 2065272ffaadSVlad Buslov err = -EAGAIN; 2066272ffaadSVlad Buslov goto errout_hw; 2067272ffaadSVlad Buslov } 2068272ffaadSVlad Buslov 20695b33f488SAmir Vadai if (fold) { 2070b2552b8cSVlad Buslov /* Fold filter was deleted concurrently. Retry lookup. */ 2071b2552b8cSVlad Buslov if (fold->deleted) { 2072b2552b8cSVlad Buslov err = -EAGAIN; 2073b2552b8cSVlad Buslov goto errout_hw; 2074b2552b8cSVlad Buslov } 2075b2552b8cSVlad Buslov 2076620da486SVlad Buslov fnew->handle = handle; 2077620da486SVlad Buslov 20781f17f774SVlad Buslov if (!in_ht) { 20791f17f774SVlad Buslov struct rhashtable_params params = 20801f17f774SVlad Buslov fnew->mask->filter_ht_params; 20811f17f774SVlad Buslov 20821f17f774SVlad Buslov err = rhashtable_insert_fast(&fnew->mask->ht, 20831f17f774SVlad Buslov &fnew->ht_node, 20841f17f774SVlad Buslov params); 2085620da486SVlad Buslov if (err) 2086620da486SVlad Buslov goto errout_hw; 20871f17f774SVlad Buslov in_ht = true; 20881f17f774SVlad Buslov } 2089620da486SVlad Buslov 2090c049d56eSVlad Buslov refcount_inc(&fnew->refcnt); 209105cd271fSPaul Blakey rhashtable_remove_fast(&fold->mask->ht, 209205cd271fSPaul Blakey &fold->ht_node, 209305cd271fSPaul Blakey fold->mask->filter_ht_params); 2094234a4624SMatthew Wilcox idr_replace(&head->handle_idr, fnew, fnew->handle); 2095ff3532f2SDaniel Borkmann list_replace_rcu(&fold->list, &fnew->list); 2096b2552b8cSVlad Buslov fold->deleted = true; 2097620da486SVlad Buslov 20983d81e711SVlad Buslov spin_unlock(&tp->lock); 20993d81e711SVlad Buslov 21009994677cSVlad Buslov fl_mask_put(head, fold->mask); 2101620da486SVlad Buslov if (!tc_skip_hw(fold->flags)) 2102c24e43d8SVlad Buslov fl_hw_destroy_filter(tp, fold, rtnl_held, NULL); 210377b9900eSJiri Pirko tcf_unbind_filter(tp, &fold->res); 210406177558SVlad Buslov /* Caller holds reference to fold, so refcnt is always > 0 210506177558SVlad Buslov * after this. 210606177558SVlad Buslov */ 210706177558SVlad Buslov refcount_dec(&fold->refcnt); 210806177558SVlad Buslov __fl_put(fold); 210977b9900eSJiri Pirko } else { 2110620da486SVlad Buslov if (handle) { 2111620da486SVlad Buslov /* user specifies a handle and it doesn't exist */ 2112620da486SVlad Buslov err = idr_alloc_u32(&head->handle_idr, fnew, &handle, 2113620da486SVlad Buslov handle, GFP_ATOMIC); 21149a2d9389SVlad Buslov 21159a2d9389SVlad Buslov /* Filter with specified handle was concurrently 21169a2d9389SVlad Buslov * inserted after initial check in cls_api. This is not 21179a2d9389SVlad Buslov * necessarily an error if NLM_F_EXCL is not set in 21189a2d9389SVlad Buslov * message flags. Returning EAGAIN will cause cls_api to 21199a2d9389SVlad Buslov * try to update concurrently inserted rule. 21209a2d9389SVlad Buslov */ 21219a2d9389SVlad Buslov if (err == -ENOSPC) 21229a2d9389SVlad Buslov err = -EAGAIN; 2123620da486SVlad Buslov } else { 2124620da486SVlad Buslov handle = 1; 2125620da486SVlad Buslov err = idr_alloc_u32(&head->handle_idr, fnew, &handle, 2126620da486SVlad Buslov INT_MAX, GFP_ATOMIC); 2127620da486SVlad Buslov } 2128620da486SVlad Buslov if (err) 2129620da486SVlad Buslov goto errout_hw; 2130620da486SVlad Buslov 2131c049d56eSVlad Buslov refcount_inc(&fnew->refcnt); 2132620da486SVlad Buslov fnew->handle = handle; 213305cd271fSPaul Blakey list_add_tail_rcu(&fnew->list, &fnew->mask->filters); 21343d81e711SVlad Buslov spin_unlock(&tp->lock); 213577b9900eSJiri Pirko } 213677b9900eSJiri Pirko 2137620da486SVlad Buslov *arg = fnew; 2138620da486SVlad Buslov 213939b7b6a6SArnd Bergmann kfree(tb); 214099815f50SVlad Buslov tcf_queue_work(&mask->rwork, fl_uninit_mask_free_work); 214177b9900eSJiri Pirko return 0; 214277b9900eSJiri Pirko 2143c049d56eSVlad Buslov errout_ht: 2144c049d56eSVlad Buslov spin_lock(&tp->lock); 2145620da486SVlad Buslov errout_hw: 2146c049d56eSVlad Buslov fnew->deleted = true; 21473d81e711SVlad Buslov spin_unlock(&tp->lock); 2148620da486SVlad Buslov if (!tc_skip_hw(fnew->flags)) 2149c24e43d8SVlad Buslov fl_hw_destroy_filter(tp, fnew, rtnl_held, NULL); 21501f17f774SVlad Buslov if (in_ht) 21511f17f774SVlad Buslov rhashtable_remove_fast(&fnew->mask->ht, &fnew->ht_node, 21521f17f774SVlad Buslov fnew->mask->filter_ht_params); 2153ecb3dea4SVlad Buslov errout_mask: 21549994677cSVlad Buslov fl_mask_put(head, fnew->mask); 215577b9900eSJiri Pirko errout: 2156c049d56eSVlad Buslov __fl_put(fnew); 215739b7b6a6SArnd Bergmann errout_tb: 215839b7b6a6SArnd Bergmann kfree(tb); 21592cddd201SIvan Vecera errout_mask_alloc: 216099815f50SVlad Buslov tcf_queue_work(&mask->rwork, fl_uninit_mask_free_work); 216106177558SVlad Buslov errout_fold: 216206177558SVlad Buslov if (fold) 216306177558SVlad Buslov __fl_put(fold); 216477b9900eSJiri Pirko return err; 216577b9900eSJiri Pirko } 216677b9900eSJiri Pirko 2167571acf21SAlexander Aring static int fl_delete(struct tcf_proto *tp, void *arg, bool *last, 216812db03b6SVlad Buslov bool rtnl_held, struct netlink_ext_ack *extack) 216977b9900eSJiri Pirko { 2170e474619aSVlad Buslov struct cls_fl_head *head = fl_head_dereference(tp); 21718113c095SWANG Cong struct cls_fl_filter *f = arg; 2172b2552b8cSVlad Buslov bool last_on_mask; 2173b2552b8cSVlad Buslov int err = 0; 217477b9900eSJiri Pirko 2175c24e43d8SVlad Buslov err = __fl_delete(tp, f, &last_on_mask, rtnl_held, extack); 217605cd271fSPaul Blakey *last = list_empty(&head->masks); 217706177558SVlad Buslov __fl_put(f); 217806177558SVlad Buslov 2179b2552b8cSVlad Buslov return err; 218077b9900eSJiri Pirko } 218177b9900eSJiri Pirko 218212db03b6SVlad Buslov static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg, 218312db03b6SVlad Buslov bool rtnl_held) 218477b9900eSJiri Pirko { 2185d39d7149SCong Wang struct cls_fl_head *head = fl_head_dereference(tp); 2186d39d7149SCong Wang unsigned long id = arg->cookie, tmp; 218777b9900eSJiri Pirko struct cls_fl_filter *f; 218877b9900eSJiri Pirko 218901683a14SVlad Buslov arg->count = arg->skip; 219001683a14SVlad Buslov 2191d39d7149SCong Wang idr_for_each_entry_continue_ul(&head->handle_idr, f, tmp, id) { 2192d39d7149SCong Wang /* don't return filters that are being deleted */ 2193d39d7149SCong Wang if (!refcount_inc_not_zero(&f->refcnt)) 2194d39d7149SCong Wang continue; 21958113c095SWANG Cong if (arg->fn(tp, f, arg) < 0) { 219606177558SVlad Buslov __fl_put(f); 219777b9900eSJiri Pirko arg->stop = 1; 219877b9900eSJiri Pirko break; 219977b9900eSJiri Pirko } 220006177558SVlad Buslov __fl_put(f); 220177b9900eSJiri Pirko arg->count++; 220277b9900eSJiri Pirko } 2203d39d7149SCong Wang arg->cookie = id; 220477b9900eSJiri Pirko } 220577b9900eSJiri Pirko 2206c049d56eSVlad Buslov static struct cls_fl_filter * 2207c049d56eSVlad Buslov fl_get_next_hw_filter(struct tcf_proto *tp, struct cls_fl_filter *f, bool add) 2208c049d56eSVlad Buslov { 2209c049d56eSVlad Buslov struct cls_fl_head *head = fl_head_dereference(tp); 2210c049d56eSVlad Buslov 2211c049d56eSVlad Buslov spin_lock(&tp->lock); 2212c049d56eSVlad Buslov if (list_empty(&head->hw_filters)) { 2213c049d56eSVlad Buslov spin_unlock(&tp->lock); 2214c049d56eSVlad Buslov return NULL; 2215c049d56eSVlad Buslov } 2216c049d56eSVlad Buslov 2217c049d56eSVlad Buslov if (!f) 2218c049d56eSVlad Buslov f = list_entry(&head->hw_filters, struct cls_fl_filter, 2219c049d56eSVlad Buslov hw_list); 2220c049d56eSVlad Buslov list_for_each_entry_continue(f, &head->hw_filters, hw_list) { 2221c049d56eSVlad Buslov if (!(add && f->deleted) && refcount_inc_not_zero(&f->refcnt)) { 2222c049d56eSVlad Buslov spin_unlock(&tp->lock); 2223c049d56eSVlad Buslov return f; 2224c049d56eSVlad Buslov } 2225c049d56eSVlad Buslov } 2226c049d56eSVlad Buslov 2227c049d56eSVlad Buslov spin_unlock(&tp->lock); 2228c049d56eSVlad Buslov return NULL; 2229c049d56eSVlad Buslov } 2230c049d56eSVlad Buslov 2231a7323311SPablo Neira Ayuso static int fl_reoffload(struct tcf_proto *tp, bool add, flow_setup_cb_t *cb, 223231533cbaSJohn Hurley void *cb_priv, struct netlink_ext_ack *extack) 223331533cbaSJohn Hurley { 223431533cbaSJohn Hurley struct tcf_block *block = tp->chain->block; 2235f9e30088SPablo Neira Ayuso struct flow_cls_offload cls_flower = {}; 2236c049d56eSVlad Buslov struct cls_fl_filter *f = NULL; 223731533cbaSJohn Hurley int err; 223831533cbaSJohn Hurley 2239c049d56eSVlad Buslov /* hw_filters list can only be changed by hw offload functions after 2240c049d56eSVlad Buslov * obtaining rtnl lock. Make sure it is not changed while reoffload is 2241c049d56eSVlad Buslov * iterating it. 2242c049d56eSVlad Buslov */ 2243c049d56eSVlad Buslov ASSERT_RTNL(); 224431533cbaSJohn Hurley 2245c049d56eSVlad Buslov while ((f = fl_get_next_hw_filter(tp, f, add))) { 2246e3ab786bSPablo Neira Ayuso cls_flower.rule = 2247e3ab786bSPablo Neira Ayuso flow_rule_alloc(tcf_exts_num_actions(&f->exts)); 224895e27a4dSJohn Hurley if (!cls_flower.rule) { 224995e27a4dSJohn Hurley __fl_put(f); 22508f256622SPablo Neira Ayuso return -ENOMEM; 225195e27a4dSJohn Hurley } 22528f256622SPablo Neira Ayuso 225395e27a4dSJohn Hurley tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, 2254d6787147SPieter Jansen van Vuuren extack); 225531533cbaSJohn Hurley cls_flower.command = add ? 2256f9e30088SPablo Neira Ayuso FLOW_CLS_REPLACE : FLOW_CLS_DESTROY; 225731533cbaSJohn Hurley cls_flower.cookie = (unsigned long)f; 225895e27a4dSJohn Hurley cls_flower.rule->match.dissector = &f->mask->dissector; 225995e27a4dSJohn Hurley cls_flower.rule->match.mask = &f->mask->key; 22608f256622SPablo Neira Ayuso cls_flower.rule->match.key = &f->mkey; 22613a7b6861SPablo Neira Ayuso 2262b15e7a6eSVlad Buslov err = tc_setup_flow_action(&cls_flower.rule->action, &f->exts); 22633a7b6861SPablo Neira Ayuso if (err) { 22643a7b6861SPablo Neira Ayuso kfree(cls_flower.rule); 22651f15bb4fSVlad Buslov if (tc_skip_sw(f->flags)) { 22661f15bb4fSVlad Buslov NL_SET_ERR_MSG_MOD(extack, "Failed to setup flow action"); 226795e27a4dSJohn Hurley __fl_put(f); 22683a7b6861SPablo Neira Ayuso return err; 22693a7b6861SPablo Neira Ayuso } 227095e27a4dSJohn Hurley goto next_flow; 22711f15bb4fSVlad Buslov } 22723a7b6861SPablo Neira Ayuso 227331533cbaSJohn Hurley cls_flower.classid = f->res.classid; 227431533cbaSJohn Hurley 227540119211SVlad Buslov err = tc_setup_cb_reoffload(block, tp, add, cb, 227640119211SVlad Buslov TC_SETUP_CLSFLOWER, &cls_flower, 227740119211SVlad Buslov cb_priv, &f->flags, 227840119211SVlad Buslov &f->in_hw_count); 22795a6ff4b1SVlad Buslov tc_cleanup_flow_action(&cls_flower.rule->action); 22808f256622SPablo Neira Ayuso kfree(cls_flower.rule); 22818f256622SPablo Neira Ayuso 228231533cbaSJohn Hurley if (err) { 228395e27a4dSJohn Hurley __fl_put(f); 228431533cbaSJohn Hurley return err; 228595e27a4dSJohn Hurley } 228695e27a4dSJohn Hurley next_flow: 228795e27a4dSJohn Hurley __fl_put(f); 228831533cbaSJohn Hurley } 228931533cbaSJohn Hurley 229031533cbaSJohn Hurley return 0; 229131533cbaSJohn Hurley } 229231533cbaSJohn Hurley 2293a449a3e7SVlad Buslov static void fl_hw_add(struct tcf_proto *tp, void *type_data) 2294a449a3e7SVlad Buslov { 2295a449a3e7SVlad Buslov struct flow_cls_offload *cls_flower = type_data; 2296a449a3e7SVlad Buslov struct cls_fl_filter *f = 2297a449a3e7SVlad Buslov (struct cls_fl_filter *) cls_flower->cookie; 2298a449a3e7SVlad Buslov struct cls_fl_head *head = fl_head_dereference(tp); 2299a449a3e7SVlad Buslov 2300a449a3e7SVlad Buslov spin_lock(&tp->lock); 2301a449a3e7SVlad Buslov list_add(&f->hw_list, &head->hw_filters); 2302a449a3e7SVlad Buslov spin_unlock(&tp->lock); 2303a449a3e7SVlad Buslov } 2304a449a3e7SVlad Buslov 2305a449a3e7SVlad Buslov static void fl_hw_del(struct tcf_proto *tp, void *type_data) 2306a449a3e7SVlad Buslov { 2307a449a3e7SVlad Buslov struct flow_cls_offload *cls_flower = type_data; 2308a449a3e7SVlad Buslov struct cls_fl_filter *f = 2309a449a3e7SVlad Buslov (struct cls_fl_filter *) cls_flower->cookie; 2310a449a3e7SVlad Buslov 2311a449a3e7SVlad Buslov spin_lock(&tp->lock); 2312a449a3e7SVlad Buslov if (!list_empty(&f->hw_list)) 2313a449a3e7SVlad Buslov list_del_init(&f->hw_list); 2314a449a3e7SVlad Buslov spin_unlock(&tp->lock); 2315a449a3e7SVlad Buslov } 2316a449a3e7SVlad Buslov 23178f256622SPablo Neira Ayuso static int fl_hw_create_tmplt(struct tcf_chain *chain, 231834738452SJiri Pirko struct fl_flow_tmplt *tmplt) 231934738452SJiri Pirko { 2320f9e30088SPablo Neira Ayuso struct flow_cls_offload cls_flower = {}; 232134738452SJiri Pirko struct tcf_block *block = chain->block; 232234738452SJiri Pirko 2323e3ab786bSPablo Neira Ayuso cls_flower.rule = flow_rule_alloc(0); 23248f256622SPablo Neira Ayuso if (!cls_flower.rule) 23258f256622SPablo Neira Ayuso return -ENOMEM; 23268f256622SPablo Neira Ayuso 232734738452SJiri Pirko cls_flower.common.chain_index = chain->index; 2328f9e30088SPablo Neira Ayuso cls_flower.command = FLOW_CLS_TMPLT_CREATE; 232934738452SJiri Pirko cls_flower.cookie = (unsigned long) tmplt; 23308f256622SPablo Neira Ayuso cls_flower.rule->match.dissector = &tmplt->dissector; 23318f256622SPablo Neira Ayuso cls_flower.rule->match.mask = &tmplt->mask; 23328f256622SPablo Neira Ayuso cls_flower.rule->match.key = &tmplt->dummy_key; 233334738452SJiri Pirko 233434738452SJiri Pirko /* We don't care if driver (any of them) fails to handle this 233534738452SJiri Pirko * call. It serves just as a hint for it. 233634738452SJiri Pirko */ 233740119211SVlad Buslov tc_setup_cb_call(block, TC_SETUP_CLSFLOWER, &cls_flower, false, true); 23388f256622SPablo Neira Ayuso kfree(cls_flower.rule); 23398f256622SPablo Neira Ayuso 23408f256622SPablo Neira Ayuso return 0; 234134738452SJiri Pirko } 234234738452SJiri Pirko 234334738452SJiri Pirko static void fl_hw_destroy_tmplt(struct tcf_chain *chain, 234434738452SJiri Pirko struct fl_flow_tmplt *tmplt) 234534738452SJiri Pirko { 2346f9e30088SPablo Neira Ayuso struct flow_cls_offload cls_flower = {}; 234734738452SJiri Pirko struct tcf_block *block = chain->block; 234834738452SJiri Pirko 234934738452SJiri Pirko cls_flower.common.chain_index = chain->index; 2350f9e30088SPablo Neira Ayuso cls_flower.command = FLOW_CLS_TMPLT_DESTROY; 235134738452SJiri Pirko cls_flower.cookie = (unsigned long) tmplt; 235234738452SJiri Pirko 235340119211SVlad Buslov tc_setup_cb_call(block, TC_SETUP_CLSFLOWER, &cls_flower, false, true); 235434738452SJiri Pirko } 235534738452SJiri Pirko 2356b95ec7ebSJiri Pirko static void *fl_tmplt_create(struct net *net, struct tcf_chain *chain, 2357b95ec7ebSJiri Pirko struct nlattr **tca, 2358b95ec7ebSJiri Pirko struct netlink_ext_ack *extack) 2359b95ec7ebSJiri Pirko { 2360b95ec7ebSJiri Pirko struct fl_flow_tmplt *tmplt; 2361b95ec7ebSJiri Pirko struct nlattr **tb; 2362b95ec7ebSJiri Pirko int err; 2363b95ec7ebSJiri Pirko 2364b95ec7ebSJiri Pirko if (!tca[TCA_OPTIONS]) 2365b95ec7ebSJiri Pirko return ERR_PTR(-EINVAL); 2366b95ec7ebSJiri Pirko 2367b95ec7ebSJiri Pirko tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL); 2368b95ec7ebSJiri Pirko if (!tb) 2369b95ec7ebSJiri Pirko return ERR_PTR(-ENOBUFS); 23708cb08174SJohannes Berg err = nla_parse_nested_deprecated(tb, TCA_FLOWER_MAX, 23718cb08174SJohannes Berg tca[TCA_OPTIONS], fl_policy, NULL); 2372b95ec7ebSJiri Pirko if (err) 2373b95ec7ebSJiri Pirko goto errout_tb; 2374b95ec7ebSJiri Pirko 2375b95ec7ebSJiri Pirko tmplt = kzalloc(sizeof(*tmplt), GFP_KERNEL); 23761cbc36a5SDan Carpenter if (!tmplt) { 23771cbc36a5SDan Carpenter err = -ENOMEM; 2378b95ec7ebSJiri Pirko goto errout_tb; 23791cbc36a5SDan Carpenter } 2380b95ec7ebSJiri Pirko tmplt->chain = chain; 2381b95ec7ebSJiri Pirko err = fl_set_key(net, tb, &tmplt->dummy_key, &tmplt->mask, extack); 2382b95ec7ebSJiri Pirko if (err) 2383b95ec7ebSJiri Pirko goto errout_tmplt; 2384b95ec7ebSJiri Pirko 2385b95ec7ebSJiri Pirko fl_init_dissector(&tmplt->dissector, &tmplt->mask); 2386b95ec7ebSJiri Pirko 23878f256622SPablo Neira Ayuso err = fl_hw_create_tmplt(chain, tmplt); 23888f256622SPablo Neira Ayuso if (err) 23898f256622SPablo Neira Ayuso goto errout_tmplt; 239034738452SJiri Pirko 23918f256622SPablo Neira Ayuso kfree(tb); 2392b95ec7ebSJiri Pirko return tmplt; 2393b95ec7ebSJiri Pirko 2394b95ec7ebSJiri Pirko errout_tmplt: 2395b95ec7ebSJiri Pirko kfree(tmplt); 2396b95ec7ebSJiri Pirko errout_tb: 2397b95ec7ebSJiri Pirko kfree(tb); 2398b95ec7ebSJiri Pirko return ERR_PTR(err); 2399b95ec7ebSJiri Pirko } 2400b95ec7ebSJiri Pirko 2401b95ec7ebSJiri Pirko static void fl_tmplt_destroy(void *tmplt_priv) 2402b95ec7ebSJiri Pirko { 2403b95ec7ebSJiri Pirko struct fl_flow_tmplt *tmplt = tmplt_priv; 2404b95ec7ebSJiri Pirko 240595278ddaSCong Wang fl_hw_destroy_tmplt(tmplt->chain, tmplt); 240695278ddaSCong Wang kfree(tmplt); 2407b95ec7ebSJiri Pirko } 2408b95ec7ebSJiri Pirko 240977b9900eSJiri Pirko static int fl_dump_key_val(struct sk_buff *skb, 241077b9900eSJiri Pirko void *val, int val_type, 241177b9900eSJiri Pirko void *mask, int mask_type, int len) 241277b9900eSJiri Pirko { 241377b9900eSJiri Pirko int err; 241477b9900eSJiri Pirko 241577b9900eSJiri Pirko if (!memchr_inv(mask, 0, len)) 241677b9900eSJiri Pirko return 0; 241777b9900eSJiri Pirko err = nla_put(skb, val_type, len, val); 241877b9900eSJiri Pirko if (err) 241977b9900eSJiri Pirko return err; 242077b9900eSJiri Pirko if (mask_type != TCA_FLOWER_UNSPEC) { 242177b9900eSJiri Pirko err = nla_put(skb, mask_type, len, mask); 242277b9900eSJiri Pirko if (err) 242377b9900eSJiri Pirko return err; 242477b9900eSJiri Pirko } 242577b9900eSJiri Pirko return 0; 242677b9900eSJiri Pirko } 242777b9900eSJiri Pirko 24285c72299fSAmritha Nambiar static int fl_dump_key_port_range(struct sk_buff *skb, struct fl_flow_key *key, 24295c72299fSAmritha Nambiar struct fl_flow_key *mask) 24305c72299fSAmritha Nambiar { 24318ffb055bSYoshiki Komachi if (fl_dump_key_val(skb, &key->tp_range.tp_min.dst, 24328ffb055bSYoshiki Komachi TCA_FLOWER_KEY_PORT_DST_MIN, 24338ffb055bSYoshiki Komachi &mask->tp_range.tp_min.dst, TCA_FLOWER_UNSPEC, 24348ffb055bSYoshiki Komachi sizeof(key->tp_range.tp_min.dst)) || 24358ffb055bSYoshiki Komachi fl_dump_key_val(skb, &key->tp_range.tp_max.dst, 24368ffb055bSYoshiki Komachi TCA_FLOWER_KEY_PORT_DST_MAX, 24378ffb055bSYoshiki Komachi &mask->tp_range.tp_max.dst, TCA_FLOWER_UNSPEC, 24388ffb055bSYoshiki Komachi sizeof(key->tp_range.tp_max.dst)) || 24398ffb055bSYoshiki Komachi fl_dump_key_val(skb, &key->tp_range.tp_min.src, 24408ffb055bSYoshiki Komachi TCA_FLOWER_KEY_PORT_SRC_MIN, 24418ffb055bSYoshiki Komachi &mask->tp_range.tp_min.src, TCA_FLOWER_UNSPEC, 24428ffb055bSYoshiki Komachi sizeof(key->tp_range.tp_min.src)) || 24438ffb055bSYoshiki Komachi fl_dump_key_val(skb, &key->tp_range.tp_max.src, 24448ffb055bSYoshiki Komachi TCA_FLOWER_KEY_PORT_SRC_MAX, 24458ffb055bSYoshiki Komachi &mask->tp_range.tp_max.src, TCA_FLOWER_UNSPEC, 24468ffb055bSYoshiki Komachi sizeof(key->tp_range.tp_max.src))) 24475c72299fSAmritha Nambiar return -1; 24485c72299fSAmritha Nambiar 24495c72299fSAmritha Nambiar return 0; 24505c72299fSAmritha Nambiar } 24515c72299fSAmritha Nambiar 245261aec25aSGuillaume Nault static int fl_dump_key_mpls_opt_lse(struct sk_buff *skb, 245361aec25aSGuillaume Nault struct flow_dissector_key_mpls *mpls_key, 245461aec25aSGuillaume Nault struct flow_dissector_key_mpls *mpls_mask, 245561aec25aSGuillaume Nault u8 lse_index) 245661aec25aSGuillaume Nault { 245761aec25aSGuillaume Nault struct flow_dissector_mpls_lse *lse_mask = &mpls_mask->ls[lse_index]; 245861aec25aSGuillaume Nault struct flow_dissector_mpls_lse *lse_key = &mpls_key->ls[lse_index]; 245961aec25aSGuillaume Nault int err; 246061aec25aSGuillaume Nault 246161aec25aSGuillaume Nault err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_OPT_LSE_DEPTH, 246261aec25aSGuillaume Nault lse_index + 1); 246361aec25aSGuillaume Nault if (err) 246461aec25aSGuillaume Nault return err; 246561aec25aSGuillaume Nault 246661aec25aSGuillaume Nault if (lse_mask->mpls_ttl) { 246761aec25aSGuillaume Nault err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_OPT_LSE_TTL, 246861aec25aSGuillaume Nault lse_key->mpls_ttl); 246961aec25aSGuillaume Nault if (err) 247061aec25aSGuillaume Nault return err; 247161aec25aSGuillaume Nault } 247261aec25aSGuillaume Nault if (lse_mask->mpls_bos) { 247361aec25aSGuillaume Nault err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_OPT_LSE_BOS, 247461aec25aSGuillaume Nault lse_key->mpls_bos); 247561aec25aSGuillaume Nault if (err) 247661aec25aSGuillaume Nault return err; 247761aec25aSGuillaume Nault } 247861aec25aSGuillaume Nault if (lse_mask->mpls_tc) { 247961aec25aSGuillaume Nault err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_OPT_LSE_TC, 248061aec25aSGuillaume Nault lse_key->mpls_tc); 248161aec25aSGuillaume Nault if (err) 248261aec25aSGuillaume Nault return err; 248361aec25aSGuillaume Nault } 248461aec25aSGuillaume Nault if (lse_mask->mpls_label) { 24857fdd375eSGuillaume Nault err = nla_put_u32(skb, TCA_FLOWER_KEY_MPLS_OPT_LSE_LABEL, 248661aec25aSGuillaume Nault lse_key->mpls_label); 248761aec25aSGuillaume Nault if (err) 248861aec25aSGuillaume Nault return err; 248961aec25aSGuillaume Nault } 249061aec25aSGuillaume Nault 249161aec25aSGuillaume Nault return 0; 249261aec25aSGuillaume Nault } 249361aec25aSGuillaume Nault 249461aec25aSGuillaume Nault static int fl_dump_key_mpls_opts(struct sk_buff *skb, 249561aec25aSGuillaume Nault struct flow_dissector_key_mpls *mpls_key, 249661aec25aSGuillaume Nault struct flow_dissector_key_mpls *mpls_mask) 249761aec25aSGuillaume Nault { 249861aec25aSGuillaume Nault struct nlattr *opts; 249961aec25aSGuillaume Nault struct nlattr *lse; 250061aec25aSGuillaume Nault u8 lse_index; 250161aec25aSGuillaume Nault int err; 250261aec25aSGuillaume Nault 250361aec25aSGuillaume Nault opts = nla_nest_start(skb, TCA_FLOWER_KEY_MPLS_OPTS); 250461aec25aSGuillaume Nault if (!opts) 250561aec25aSGuillaume Nault return -EMSGSIZE; 250661aec25aSGuillaume Nault 250761aec25aSGuillaume Nault for (lse_index = 0; lse_index < FLOW_DIS_MPLS_MAX; lse_index++) { 250861aec25aSGuillaume Nault if (!(mpls_mask->used_lses & 1 << lse_index)) 250961aec25aSGuillaume Nault continue; 251061aec25aSGuillaume Nault 251161aec25aSGuillaume Nault lse = nla_nest_start(skb, TCA_FLOWER_KEY_MPLS_OPTS_LSE); 251261aec25aSGuillaume Nault if (!lse) { 251361aec25aSGuillaume Nault err = -EMSGSIZE; 251461aec25aSGuillaume Nault goto err_opts; 251561aec25aSGuillaume Nault } 251661aec25aSGuillaume Nault 251761aec25aSGuillaume Nault err = fl_dump_key_mpls_opt_lse(skb, mpls_key, mpls_mask, 251861aec25aSGuillaume Nault lse_index); 251961aec25aSGuillaume Nault if (err) 252061aec25aSGuillaume Nault goto err_opts_lse; 252161aec25aSGuillaume Nault nla_nest_end(skb, lse); 252261aec25aSGuillaume Nault } 252361aec25aSGuillaume Nault nla_nest_end(skb, opts); 252461aec25aSGuillaume Nault 252561aec25aSGuillaume Nault return 0; 252661aec25aSGuillaume Nault 252761aec25aSGuillaume Nault err_opts_lse: 252861aec25aSGuillaume Nault nla_nest_cancel(skb, lse); 252961aec25aSGuillaume Nault err_opts: 253061aec25aSGuillaume Nault nla_nest_cancel(skb, opts); 253161aec25aSGuillaume Nault 253261aec25aSGuillaume Nault return err; 253361aec25aSGuillaume Nault } 253461aec25aSGuillaume Nault 2535a577d8f7SBenjamin LaHaise static int fl_dump_key_mpls(struct sk_buff *skb, 2536a577d8f7SBenjamin LaHaise struct flow_dissector_key_mpls *mpls_key, 2537a577d8f7SBenjamin LaHaise struct flow_dissector_key_mpls *mpls_mask) 2538a577d8f7SBenjamin LaHaise { 253958cff782SGuillaume Nault struct flow_dissector_mpls_lse *lse_mask; 254058cff782SGuillaume Nault struct flow_dissector_mpls_lse *lse_key; 2541a577d8f7SBenjamin LaHaise int err; 2542a577d8f7SBenjamin LaHaise 254361aec25aSGuillaume Nault if (!mpls_mask->used_lses) 2544a577d8f7SBenjamin LaHaise return 0; 254558cff782SGuillaume Nault 254658cff782SGuillaume Nault lse_mask = &mpls_mask->ls[0]; 254758cff782SGuillaume Nault lse_key = &mpls_key->ls[0]; 254858cff782SGuillaume Nault 254961aec25aSGuillaume Nault /* For backward compatibility, don't use the MPLS nested attributes if 255061aec25aSGuillaume Nault * the rule can be expressed using the old attributes. 255161aec25aSGuillaume Nault */ 255261aec25aSGuillaume Nault if (mpls_mask->used_lses & ~1 || 255361aec25aSGuillaume Nault (!lse_mask->mpls_ttl && !lse_mask->mpls_bos && 255461aec25aSGuillaume Nault !lse_mask->mpls_tc && !lse_mask->mpls_label)) 255561aec25aSGuillaume Nault return fl_dump_key_mpls_opts(skb, mpls_key, mpls_mask); 255661aec25aSGuillaume Nault 255758cff782SGuillaume Nault if (lse_mask->mpls_ttl) { 2558a577d8f7SBenjamin LaHaise err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TTL, 255958cff782SGuillaume Nault lse_key->mpls_ttl); 2560a577d8f7SBenjamin LaHaise if (err) 2561a577d8f7SBenjamin LaHaise return err; 2562a577d8f7SBenjamin LaHaise } 256358cff782SGuillaume Nault if (lse_mask->mpls_tc) { 2564a577d8f7SBenjamin LaHaise err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TC, 256558cff782SGuillaume Nault lse_key->mpls_tc); 2566a577d8f7SBenjamin LaHaise if (err) 2567a577d8f7SBenjamin LaHaise return err; 2568a577d8f7SBenjamin LaHaise } 256958cff782SGuillaume Nault if (lse_mask->mpls_label) { 2570a577d8f7SBenjamin LaHaise err = nla_put_u32(skb, TCA_FLOWER_KEY_MPLS_LABEL, 257158cff782SGuillaume Nault lse_key->mpls_label); 2572a577d8f7SBenjamin LaHaise if (err) 2573a577d8f7SBenjamin LaHaise return err; 2574a577d8f7SBenjamin LaHaise } 257558cff782SGuillaume Nault if (lse_mask->mpls_bos) { 2576a577d8f7SBenjamin LaHaise err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_BOS, 257758cff782SGuillaume Nault lse_key->mpls_bos); 2578a577d8f7SBenjamin LaHaise if (err) 2579a577d8f7SBenjamin LaHaise return err; 2580a577d8f7SBenjamin LaHaise } 2581a577d8f7SBenjamin LaHaise return 0; 2582a577d8f7SBenjamin LaHaise } 2583a577d8f7SBenjamin LaHaise 25840e2c17b6SOr Gerlitz static int fl_dump_key_ip(struct sk_buff *skb, bool encap, 25854d80cc0aSOr Gerlitz struct flow_dissector_key_ip *key, 25864d80cc0aSOr Gerlitz struct flow_dissector_key_ip *mask) 25874d80cc0aSOr Gerlitz { 25880e2c17b6SOr Gerlitz int tos_key = encap ? TCA_FLOWER_KEY_ENC_IP_TOS : TCA_FLOWER_KEY_IP_TOS; 25890e2c17b6SOr Gerlitz int ttl_key = encap ? TCA_FLOWER_KEY_ENC_IP_TTL : TCA_FLOWER_KEY_IP_TTL; 25900e2c17b6SOr Gerlitz int tos_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TOS_MASK : TCA_FLOWER_KEY_IP_TOS_MASK; 25910e2c17b6SOr Gerlitz int ttl_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TTL_MASK : TCA_FLOWER_KEY_IP_TTL_MASK; 25920e2c17b6SOr Gerlitz 25930e2c17b6SOr Gerlitz if (fl_dump_key_val(skb, &key->tos, tos_key, &mask->tos, tos_mask, sizeof(key->tos)) || 25940e2c17b6SOr Gerlitz fl_dump_key_val(skb, &key->ttl, ttl_key, &mask->ttl, ttl_mask, sizeof(key->ttl))) 25954d80cc0aSOr Gerlitz return -1; 25964d80cc0aSOr Gerlitz 25974d80cc0aSOr Gerlitz return 0; 25984d80cc0aSOr Gerlitz } 25994d80cc0aSOr Gerlitz 26009399ae9aSHadar Hen Zion static int fl_dump_key_vlan(struct sk_buff *skb, 2601d64efd09SJianbo Liu int vlan_id_key, int vlan_prio_key, 26029399ae9aSHadar Hen Zion struct flow_dissector_key_vlan *vlan_key, 26039399ae9aSHadar Hen Zion struct flow_dissector_key_vlan *vlan_mask) 26049399ae9aSHadar Hen Zion { 26059399ae9aSHadar Hen Zion int err; 26069399ae9aSHadar Hen Zion 26079399ae9aSHadar Hen Zion if (!memchr_inv(vlan_mask, 0, sizeof(*vlan_mask))) 26089399ae9aSHadar Hen Zion return 0; 26099399ae9aSHadar Hen Zion if (vlan_mask->vlan_id) { 2610d64efd09SJianbo Liu err = nla_put_u16(skb, vlan_id_key, 26119399ae9aSHadar Hen Zion vlan_key->vlan_id); 26129399ae9aSHadar Hen Zion if (err) 26139399ae9aSHadar Hen Zion return err; 26149399ae9aSHadar Hen Zion } 26159399ae9aSHadar Hen Zion if (vlan_mask->vlan_priority) { 2616d64efd09SJianbo Liu err = nla_put_u8(skb, vlan_prio_key, 26179399ae9aSHadar Hen Zion vlan_key->vlan_priority); 26189399ae9aSHadar Hen Zion if (err) 26199399ae9aSHadar Hen Zion return err; 26209399ae9aSHadar Hen Zion } 26219399ae9aSHadar Hen Zion return 0; 26229399ae9aSHadar Hen Zion } 26239399ae9aSHadar Hen Zion 2624faa3ffceSOr Gerlitz static void fl_get_key_flag(u32 dissector_key, u32 dissector_mask, 2625faa3ffceSOr Gerlitz u32 *flower_key, u32 *flower_mask, 2626faa3ffceSOr Gerlitz u32 flower_flag_bit, u32 dissector_flag_bit) 2627faa3ffceSOr Gerlitz { 2628faa3ffceSOr Gerlitz if (dissector_mask & dissector_flag_bit) { 2629faa3ffceSOr Gerlitz *flower_mask |= flower_flag_bit; 2630faa3ffceSOr Gerlitz if (dissector_key & dissector_flag_bit) 2631faa3ffceSOr Gerlitz *flower_key |= flower_flag_bit; 2632faa3ffceSOr Gerlitz } 2633faa3ffceSOr Gerlitz } 2634faa3ffceSOr Gerlitz 2635faa3ffceSOr Gerlitz static int fl_dump_key_flags(struct sk_buff *skb, u32 flags_key, u32 flags_mask) 2636faa3ffceSOr Gerlitz { 2637faa3ffceSOr Gerlitz u32 key, mask; 2638faa3ffceSOr Gerlitz __be32 _key, _mask; 2639faa3ffceSOr Gerlitz int err; 2640faa3ffceSOr Gerlitz 2641faa3ffceSOr Gerlitz if (!memchr_inv(&flags_mask, 0, sizeof(flags_mask))) 2642faa3ffceSOr Gerlitz return 0; 2643faa3ffceSOr Gerlitz 2644faa3ffceSOr Gerlitz key = 0; 2645faa3ffceSOr Gerlitz mask = 0; 2646faa3ffceSOr Gerlitz 2647faa3ffceSOr Gerlitz fl_get_key_flag(flags_key, flags_mask, &key, &mask, 2648faa3ffceSOr Gerlitz TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT); 2649459d153dSPieter Jansen van Vuuren fl_get_key_flag(flags_key, flags_mask, &key, &mask, 2650459d153dSPieter Jansen van Vuuren TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST, 2651459d153dSPieter Jansen van Vuuren FLOW_DIS_FIRST_FRAG); 2652faa3ffceSOr Gerlitz 2653faa3ffceSOr Gerlitz _key = cpu_to_be32(key); 2654faa3ffceSOr Gerlitz _mask = cpu_to_be32(mask); 2655faa3ffceSOr Gerlitz 2656faa3ffceSOr Gerlitz err = nla_put(skb, TCA_FLOWER_KEY_FLAGS, 4, &_key); 2657faa3ffceSOr Gerlitz if (err) 2658faa3ffceSOr Gerlitz return err; 2659faa3ffceSOr Gerlitz 2660faa3ffceSOr Gerlitz return nla_put(skb, TCA_FLOWER_KEY_FLAGS_MASK, 4, &_mask); 2661faa3ffceSOr Gerlitz } 2662faa3ffceSOr Gerlitz 26630a6e7778SPieter Jansen van Vuuren static int fl_dump_key_geneve_opt(struct sk_buff *skb, 26640a6e7778SPieter Jansen van Vuuren struct flow_dissector_key_enc_opts *enc_opts) 26650a6e7778SPieter Jansen van Vuuren { 26660a6e7778SPieter Jansen van Vuuren struct geneve_opt *opt; 26670a6e7778SPieter Jansen van Vuuren struct nlattr *nest; 26680a6e7778SPieter Jansen van Vuuren int opt_off = 0; 26690a6e7778SPieter Jansen van Vuuren 2670ae0be8deSMichal Kubecek nest = nla_nest_start_noflag(skb, TCA_FLOWER_KEY_ENC_OPTS_GENEVE); 26710a6e7778SPieter Jansen van Vuuren if (!nest) 26720a6e7778SPieter Jansen van Vuuren goto nla_put_failure; 26730a6e7778SPieter Jansen van Vuuren 26740a6e7778SPieter Jansen van Vuuren while (enc_opts->len > opt_off) { 26750a6e7778SPieter Jansen van Vuuren opt = (struct geneve_opt *)&enc_opts->data[opt_off]; 26760a6e7778SPieter Jansen van Vuuren 26770a6e7778SPieter Jansen van Vuuren if (nla_put_be16(skb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS, 26780a6e7778SPieter Jansen van Vuuren opt->opt_class)) 26790a6e7778SPieter Jansen van Vuuren goto nla_put_failure; 26800a6e7778SPieter Jansen van Vuuren if (nla_put_u8(skb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE, 26810a6e7778SPieter Jansen van Vuuren opt->type)) 26820a6e7778SPieter Jansen van Vuuren goto nla_put_failure; 26830a6e7778SPieter Jansen van Vuuren if (nla_put(skb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA, 26840a6e7778SPieter Jansen van Vuuren opt->length * 4, opt->opt_data)) 26850a6e7778SPieter Jansen van Vuuren goto nla_put_failure; 26860a6e7778SPieter Jansen van Vuuren 26870a6e7778SPieter Jansen van Vuuren opt_off += sizeof(struct geneve_opt) + opt->length * 4; 26880a6e7778SPieter Jansen van Vuuren } 26890a6e7778SPieter Jansen van Vuuren nla_nest_end(skb, nest); 26900a6e7778SPieter Jansen van Vuuren return 0; 26910a6e7778SPieter Jansen van Vuuren 26920a6e7778SPieter Jansen van Vuuren nla_put_failure: 26930a6e7778SPieter Jansen van Vuuren nla_nest_cancel(skb, nest); 26940a6e7778SPieter Jansen van Vuuren return -EMSGSIZE; 26950a6e7778SPieter Jansen van Vuuren } 26960a6e7778SPieter Jansen van Vuuren 2697d8f9dfaeSXin Long static int fl_dump_key_vxlan_opt(struct sk_buff *skb, 2698d8f9dfaeSXin Long struct flow_dissector_key_enc_opts *enc_opts) 2699d8f9dfaeSXin Long { 2700d8f9dfaeSXin Long struct vxlan_metadata *md; 2701d8f9dfaeSXin Long struct nlattr *nest; 2702d8f9dfaeSXin Long 2703d8f9dfaeSXin Long nest = nla_nest_start_noflag(skb, TCA_FLOWER_KEY_ENC_OPTS_VXLAN); 2704d8f9dfaeSXin Long if (!nest) 2705d8f9dfaeSXin Long goto nla_put_failure; 2706d8f9dfaeSXin Long 2707d8f9dfaeSXin Long md = (struct vxlan_metadata *)&enc_opts->data[0]; 2708d8f9dfaeSXin Long if (nla_put_u32(skb, TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP, md->gbp)) 2709d8f9dfaeSXin Long goto nla_put_failure; 2710d8f9dfaeSXin Long 2711d8f9dfaeSXin Long nla_nest_end(skb, nest); 2712d8f9dfaeSXin Long return 0; 2713d8f9dfaeSXin Long 2714d8f9dfaeSXin Long nla_put_failure: 2715d8f9dfaeSXin Long nla_nest_cancel(skb, nest); 2716d8f9dfaeSXin Long return -EMSGSIZE; 2717d8f9dfaeSXin Long } 2718d8f9dfaeSXin Long 271979b1011cSXin Long static int fl_dump_key_erspan_opt(struct sk_buff *skb, 272079b1011cSXin Long struct flow_dissector_key_enc_opts *enc_opts) 272179b1011cSXin Long { 272279b1011cSXin Long struct erspan_metadata *md; 272379b1011cSXin Long struct nlattr *nest; 272479b1011cSXin Long 272579b1011cSXin Long nest = nla_nest_start_noflag(skb, TCA_FLOWER_KEY_ENC_OPTS_ERSPAN); 272679b1011cSXin Long if (!nest) 272779b1011cSXin Long goto nla_put_failure; 272879b1011cSXin Long 272979b1011cSXin Long md = (struct erspan_metadata *)&enc_opts->data[0]; 273079b1011cSXin Long if (nla_put_u8(skb, TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER, md->version)) 273179b1011cSXin Long goto nla_put_failure; 273279b1011cSXin Long 273379b1011cSXin Long if (md->version == 1 && 273479b1011cSXin Long nla_put_be32(skb, TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX, md->u.index)) 273579b1011cSXin Long goto nla_put_failure; 273679b1011cSXin Long 273779b1011cSXin Long if (md->version == 2 && 273879b1011cSXin Long (nla_put_u8(skb, TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR, 273979b1011cSXin Long md->u.md2.dir) || 274079b1011cSXin Long nla_put_u8(skb, TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID, 274179b1011cSXin Long get_hwid(&md->u.md2)))) 274279b1011cSXin Long goto nla_put_failure; 274379b1011cSXin Long 274479b1011cSXin Long nla_nest_end(skb, nest); 274579b1011cSXin Long return 0; 274679b1011cSXin Long 274779b1011cSXin Long nla_put_failure: 274879b1011cSXin Long nla_nest_cancel(skb, nest); 274979b1011cSXin Long return -EMSGSIZE; 275079b1011cSXin Long } 275179b1011cSXin Long 2752e0ace68aSPaul Blakey static int fl_dump_key_ct(struct sk_buff *skb, 2753e0ace68aSPaul Blakey struct flow_dissector_key_ct *key, 2754e0ace68aSPaul Blakey struct flow_dissector_key_ct *mask) 2755e0ace68aSPaul Blakey { 2756e0ace68aSPaul Blakey if (IS_ENABLED(CONFIG_NF_CONNTRACK) && 2757e0ace68aSPaul Blakey fl_dump_key_val(skb, &key->ct_state, TCA_FLOWER_KEY_CT_STATE, 2758e0ace68aSPaul Blakey &mask->ct_state, TCA_FLOWER_KEY_CT_STATE_MASK, 2759e0ace68aSPaul Blakey sizeof(key->ct_state))) 2760e0ace68aSPaul Blakey goto nla_put_failure; 2761e0ace68aSPaul Blakey 2762e0ace68aSPaul Blakey if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) && 2763e0ace68aSPaul Blakey fl_dump_key_val(skb, &key->ct_zone, TCA_FLOWER_KEY_CT_ZONE, 2764e0ace68aSPaul Blakey &mask->ct_zone, TCA_FLOWER_KEY_CT_ZONE_MASK, 2765e0ace68aSPaul Blakey sizeof(key->ct_zone))) 2766e0ace68aSPaul Blakey goto nla_put_failure; 2767e0ace68aSPaul Blakey 2768e0ace68aSPaul Blakey if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) && 2769e0ace68aSPaul Blakey fl_dump_key_val(skb, &key->ct_mark, TCA_FLOWER_KEY_CT_MARK, 2770e0ace68aSPaul Blakey &mask->ct_mark, TCA_FLOWER_KEY_CT_MARK_MASK, 2771e0ace68aSPaul Blakey sizeof(key->ct_mark))) 2772e0ace68aSPaul Blakey goto nla_put_failure; 2773e0ace68aSPaul Blakey 2774e0ace68aSPaul Blakey if (IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS) && 2775e0ace68aSPaul Blakey fl_dump_key_val(skb, &key->ct_labels, TCA_FLOWER_KEY_CT_LABELS, 2776e0ace68aSPaul Blakey &mask->ct_labels, TCA_FLOWER_KEY_CT_LABELS_MASK, 2777e0ace68aSPaul Blakey sizeof(key->ct_labels))) 2778e0ace68aSPaul Blakey goto nla_put_failure; 2779e0ace68aSPaul Blakey 2780e0ace68aSPaul Blakey return 0; 2781e0ace68aSPaul Blakey 2782e0ace68aSPaul Blakey nla_put_failure: 2783e0ace68aSPaul Blakey return -EMSGSIZE; 2784e0ace68aSPaul Blakey } 2785e0ace68aSPaul Blakey 27860a6e7778SPieter Jansen van Vuuren static int fl_dump_key_options(struct sk_buff *skb, int enc_opt_type, 27870a6e7778SPieter Jansen van Vuuren struct flow_dissector_key_enc_opts *enc_opts) 27880a6e7778SPieter Jansen van Vuuren { 27890a6e7778SPieter Jansen van Vuuren struct nlattr *nest; 27900a6e7778SPieter Jansen van Vuuren int err; 27910a6e7778SPieter Jansen van Vuuren 27920a6e7778SPieter Jansen van Vuuren if (!enc_opts->len) 27930a6e7778SPieter Jansen van Vuuren return 0; 27940a6e7778SPieter Jansen van Vuuren 2795ae0be8deSMichal Kubecek nest = nla_nest_start_noflag(skb, enc_opt_type); 27960a6e7778SPieter Jansen van Vuuren if (!nest) 27970a6e7778SPieter Jansen van Vuuren goto nla_put_failure; 27980a6e7778SPieter Jansen van Vuuren 27990a6e7778SPieter Jansen van Vuuren switch (enc_opts->dst_opt_type) { 28000a6e7778SPieter Jansen van Vuuren case TUNNEL_GENEVE_OPT: 28010a6e7778SPieter Jansen van Vuuren err = fl_dump_key_geneve_opt(skb, enc_opts); 28020a6e7778SPieter Jansen van Vuuren if (err) 28030a6e7778SPieter Jansen van Vuuren goto nla_put_failure; 28040a6e7778SPieter Jansen van Vuuren break; 2805d8f9dfaeSXin Long case TUNNEL_VXLAN_OPT: 2806d8f9dfaeSXin Long err = fl_dump_key_vxlan_opt(skb, enc_opts); 2807d8f9dfaeSXin Long if (err) 2808d8f9dfaeSXin Long goto nla_put_failure; 2809d8f9dfaeSXin Long break; 281079b1011cSXin Long case TUNNEL_ERSPAN_OPT: 281179b1011cSXin Long err = fl_dump_key_erspan_opt(skb, enc_opts); 281279b1011cSXin Long if (err) 281379b1011cSXin Long goto nla_put_failure; 281479b1011cSXin Long break; 28150a6e7778SPieter Jansen van Vuuren default: 28160a6e7778SPieter Jansen van Vuuren goto nla_put_failure; 28170a6e7778SPieter Jansen van Vuuren } 28180a6e7778SPieter Jansen van Vuuren nla_nest_end(skb, nest); 28190a6e7778SPieter Jansen van Vuuren return 0; 28200a6e7778SPieter Jansen van Vuuren 28210a6e7778SPieter Jansen van Vuuren nla_put_failure: 28220a6e7778SPieter Jansen van Vuuren nla_nest_cancel(skb, nest); 28230a6e7778SPieter Jansen van Vuuren return -EMSGSIZE; 28240a6e7778SPieter Jansen van Vuuren } 28250a6e7778SPieter Jansen van Vuuren 28260a6e7778SPieter Jansen van Vuuren static int fl_dump_key_enc_opt(struct sk_buff *skb, 28270a6e7778SPieter Jansen van Vuuren struct flow_dissector_key_enc_opts *key_opts, 28280a6e7778SPieter Jansen van Vuuren struct flow_dissector_key_enc_opts *msk_opts) 28290a6e7778SPieter Jansen van Vuuren { 28300a6e7778SPieter Jansen van Vuuren int err; 28310a6e7778SPieter Jansen van Vuuren 28320a6e7778SPieter Jansen van Vuuren err = fl_dump_key_options(skb, TCA_FLOWER_KEY_ENC_OPTS, key_opts); 28330a6e7778SPieter Jansen van Vuuren if (err) 28340a6e7778SPieter Jansen van Vuuren return err; 28350a6e7778SPieter Jansen van Vuuren 28360a6e7778SPieter Jansen van Vuuren return fl_dump_key_options(skb, TCA_FLOWER_KEY_ENC_OPTS_MASK, msk_opts); 28370a6e7778SPieter Jansen van Vuuren } 28380a6e7778SPieter Jansen van Vuuren 2839f5749081SJiri Pirko static int fl_dump_key(struct sk_buff *skb, struct net *net, 2840f5749081SJiri Pirko struct fl_flow_key *key, struct fl_flow_key *mask) 284177b9900eSJiri Pirko { 28428212ed77SJiri Pirko if (mask->meta.ingress_ifindex) { 284377b9900eSJiri Pirko struct net_device *dev; 284477b9900eSJiri Pirko 28458212ed77SJiri Pirko dev = __dev_get_by_index(net, key->meta.ingress_ifindex); 284677b9900eSJiri Pirko if (dev && nla_put_string(skb, TCA_FLOWER_INDEV, dev->name)) 284777b9900eSJiri Pirko goto nla_put_failure; 284877b9900eSJiri Pirko } 284977b9900eSJiri Pirko 285077b9900eSJiri Pirko if (fl_dump_key_val(skb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST, 285177b9900eSJiri Pirko mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK, 285277b9900eSJiri Pirko sizeof(key->eth.dst)) || 285377b9900eSJiri Pirko fl_dump_key_val(skb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC, 285477b9900eSJiri Pirko mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK, 285577b9900eSJiri Pirko sizeof(key->eth.src)) || 285677b9900eSJiri Pirko fl_dump_key_val(skb, &key->basic.n_proto, TCA_FLOWER_KEY_ETH_TYPE, 285777b9900eSJiri Pirko &mask->basic.n_proto, TCA_FLOWER_UNSPEC, 285877b9900eSJiri Pirko sizeof(key->basic.n_proto))) 285977b9900eSJiri Pirko goto nla_put_failure; 28609399ae9aSHadar Hen Zion 2861a577d8f7SBenjamin LaHaise if (fl_dump_key_mpls(skb, &key->mpls, &mask->mpls)) 2862a577d8f7SBenjamin LaHaise goto nla_put_failure; 2863a577d8f7SBenjamin LaHaise 2864d64efd09SJianbo Liu if (fl_dump_key_vlan(skb, TCA_FLOWER_KEY_VLAN_ID, 2865d64efd09SJianbo Liu TCA_FLOWER_KEY_VLAN_PRIO, &key->vlan, &mask->vlan)) 28669399ae9aSHadar Hen Zion goto nla_put_failure; 28679399ae9aSHadar Hen Zion 2868d64efd09SJianbo Liu if (fl_dump_key_vlan(skb, TCA_FLOWER_KEY_CVLAN_ID, 2869d64efd09SJianbo Liu TCA_FLOWER_KEY_CVLAN_PRIO, 2870d64efd09SJianbo Liu &key->cvlan, &mask->cvlan) || 2871d64efd09SJianbo Liu (mask->cvlan.vlan_tpid && 2872158abbf1SJianbo Liu nla_put_be16(skb, TCA_FLOWER_KEY_VLAN_ETH_TYPE, 2873d64efd09SJianbo Liu key->cvlan.vlan_tpid))) 2874d3069512SJianbo Liu goto nla_put_failure; 2875d3069512SJianbo Liu 28765e9a0fe4SJianbo Liu if (mask->basic.n_proto) { 2877d64efd09SJianbo Liu if (mask->cvlan.vlan_tpid) { 2878d64efd09SJianbo Liu if (nla_put_be16(skb, TCA_FLOWER_KEY_CVLAN_ETH_TYPE, 2879d64efd09SJianbo Liu key->basic.n_proto)) 2880d64efd09SJianbo Liu goto nla_put_failure; 2881d64efd09SJianbo Liu } else if (mask->vlan.vlan_tpid) { 2882d64efd09SJianbo Liu if (nla_put_be16(skb, TCA_FLOWER_KEY_VLAN_ETH_TYPE, 2883d64efd09SJianbo Liu key->basic.n_proto)) 2884d64efd09SJianbo Liu goto nla_put_failure; 2885d64efd09SJianbo Liu } 28865e9a0fe4SJianbo Liu } 2887d64efd09SJianbo Liu 288877b9900eSJiri Pirko if ((key->basic.n_proto == htons(ETH_P_IP) || 288977b9900eSJiri Pirko key->basic.n_proto == htons(ETH_P_IPV6)) && 28904d80cc0aSOr Gerlitz (fl_dump_key_val(skb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO, 289177b9900eSJiri Pirko &mask->basic.ip_proto, TCA_FLOWER_UNSPEC, 28924d80cc0aSOr Gerlitz sizeof(key->basic.ip_proto)) || 28930e2c17b6SOr Gerlitz fl_dump_key_ip(skb, false, &key->ip, &mask->ip))) 289477b9900eSJiri Pirko goto nla_put_failure; 289577b9900eSJiri Pirko 2896c3f83241STom Herbert if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS && 289777b9900eSJiri Pirko (fl_dump_key_val(skb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC, 289877b9900eSJiri Pirko &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK, 289977b9900eSJiri Pirko sizeof(key->ipv4.src)) || 290077b9900eSJiri Pirko fl_dump_key_val(skb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST, 290177b9900eSJiri Pirko &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK, 290277b9900eSJiri Pirko sizeof(key->ipv4.dst)))) 290377b9900eSJiri Pirko goto nla_put_failure; 2904c3f83241STom Herbert else if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS && 290577b9900eSJiri Pirko (fl_dump_key_val(skb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC, 290677b9900eSJiri Pirko &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK, 290777b9900eSJiri Pirko sizeof(key->ipv6.src)) || 290877b9900eSJiri Pirko fl_dump_key_val(skb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST, 290977b9900eSJiri Pirko &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK, 291077b9900eSJiri Pirko sizeof(key->ipv6.dst)))) 291177b9900eSJiri Pirko goto nla_put_failure; 291277b9900eSJiri Pirko 291377b9900eSJiri Pirko if (key->basic.ip_proto == IPPROTO_TCP && 291477b9900eSJiri Pirko (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC, 2915aa72d708SOr Gerlitz &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK, 291677b9900eSJiri Pirko sizeof(key->tp.src)) || 291777b9900eSJiri Pirko fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST, 2918aa72d708SOr Gerlitz &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK, 2919fdfc7dd6SJiri Pirko sizeof(key->tp.dst)) || 2920fdfc7dd6SJiri Pirko fl_dump_key_val(skb, &key->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS, 2921fdfc7dd6SJiri Pirko &mask->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS_MASK, 2922fdfc7dd6SJiri Pirko sizeof(key->tcp.flags)))) 292377b9900eSJiri Pirko goto nla_put_failure; 292477b9900eSJiri Pirko else if (key->basic.ip_proto == IPPROTO_UDP && 292577b9900eSJiri Pirko (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC, 2926aa72d708SOr Gerlitz &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK, 292777b9900eSJiri Pirko sizeof(key->tp.src)) || 292877b9900eSJiri Pirko fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST, 2929aa72d708SOr Gerlitz &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK, 293077b9900eSJiri Pirko sizeof(key->tp.dst)))) 293177b9900eSJiri Pirko goto nla_put_failure; 29325976c5f4SSimon Horman else if (key->basic.ip_proto == IPPROTO_SCTP && 29335976c5f4SSimon Horman (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC, 29345976c5f4SSimon Horman &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK, 29355976c5f4SSimon Horman sizeof(key->tp.src)) || 29365976c5f4SSimon Horman fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST, 29375976c5f4SSimon Horman &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK, 29385976c5f4SSimon Horman sizeof(key->tp.dst)))) 29395976c5f4SSimon Horman goto nla_put_failure; 29407b684884SSimon Horman else if (key->basic.n_proto == htons(ETH_P_IP) && 29417b684884SSimon Horman key->basic.ip_proto == IPPROTO_ICMP && 29427b684884SSimon Horman (fl_dump_key_val(skb, &key->icmp.type, 29437b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_TYPE, &mask->icmp.type, 29447b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_TYPE_MASK, 29457b684884SSimon Horman sizeof(key->icmp.type)) || 29467b684884SSimon Horman fl_dump_key_val(skb, &key->icmp.code, 29477b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_CODE, &mask->icmp.code, 29487b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_CODE_MASK, 29497b684884SSimon Horman sizeof(key->icmp.code)))) 29507b684884SSimon Horman goto nla_put_failure; 29517b684884SSimon Horman else if (key->basic.n_proto == htons(ETH_P_IPV6) && 29527b684884SSimon Horman key->basic.ip_proto == IPPROTO_ICMPV6 && 29537b684884SSimon Horman (fl_dump_key_val(skb, &key->icmp.type, 29547b684884SSimon Horman TCA_FLOWER_KEY_ICMPV6_TYPE, &mask->icmp.type, 29557b684884SSimon Horman TCA_FLOWER_KEY_ICMPV6_TYPE_MASK, 29567b684884SSimon Horman sizeof(key->icmp.type)) || 29577b684884SSimon Horman fl_dump_key_val(skb, &key->icmp.code, 29587b684884SSimon Horman TCA_FLOWER_KEY_ICMPV6_CODE, &mask->icmp.code, 29597b684884SSimon Horman TCA_FLOWER_KEY_ICMPV6_CODE_MASK, 29607b684884SSimon Horman sizeof(key->icmp.code)))) 29617b684884SSimon Horman goto nla_put_failure; 296299d31326SSimon Horman else if ((key->basic.n_proto == htons(ETH_P_ARP) || 296399d31326SSimon Horman key->basic.n_proto == htons(ETH_P_RARP)) && 296499d31326SSimon Horman (fl_dump_key_val(skb, &key->arp.sip, 296599d31326SSimon Horman TCA_FLOWER_KEY_ARP_SIP, &mask->arp.sip, 296699d31326SSimon Horman TCA_FLOWER_KEY_ARP_SIP_MASK, 296799d31326SSimon Horman sizeof(key->arp.sip)) || 296899d31326SSimon Horman fl_dump_key_val(skb, &key->arp.tip, 296999d31326SSimon Horman TCA_FLOWER_KEY_ARP_TIP, &mask->arp.tip, 297099d31326SSimon Horman TCA_FLOWER_KEY_ARP_TIP_MASK, 297199d31326SSimon Horman sizeof(key->arp.tip)) || 297299d31326SSimon Horman fl_dump_key_val(skb, &key->arp.op, 297399d31326SSimon Horman TCA_FLOWER_KEY_ARP_OP, &mask->arp.op, 297499d31326SSimon Horman TCA_FLOWER_KEY_ARP_OP_MASK, 297599d31326SSimon Horman sizeof(key->arp.op)) || 297699d31326SSimon Horman fl_dump_key_val(skb, key->arp.sha, TCA_FLOWER_KEY_ARP_SHA, 297799d31326SSimon Horman mask->arp.sha, TCA_FLOWER_KEY_ARP_SHA_MASK, 297899d31326SSimon Horman sizeof(key->arp.sha)) || 297999d31326SSimon Horman fl_dump_key_val(skb, key->arp.tha, TCA_FLOWER_KEY_ARP_THA, 298099d31326SSimon Horman mask->arp.tha, TCA_FLOWER_KEY_ARP_THA_MASK, 298199d31326SSimon Horman sizeof(key->arp.tha)))) 298299d31326SSimon Horman goto nla_put_failure; 298377b9900eSJiri Pirko 29845c72299fSAmritha Nambiar if ((key->basic.ip_proto == IPPROTO_TCP || 29855c72299fSAmritha Nambiar key->basic.ip_proto == IPPROTO_UDP || 29865c72299fSAmritha Nambiar key->basic.ip_proto == IPPROTO_SCTP) && 29875c72299fSAmritha Nambiar fl_dump_key_port_range(skb, key, mask)) 29885c72299fSAmritha Nambiar goto nla_put_failure; 29895c72299fSAmritha Nambiar 2990bc3103f1SAmir Vadai if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS && 2991bc3103f1SAmir Vadai (fl_dump_key_val(skb, &key->enc_ipv4.src, 2992bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_SRC, &mask->enc_ipv4.src, 2993bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK, 2994bc3103f1SAmir Vadai sizeof(key->enc_ipv4.src)) || 2995bc3103f1SAmir Vadai fl_dump_key_val(skb, &key->enc_ipv4.dst, 2996bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_DST, &mask->enc_ipv4.dst, 2997bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_DST_MASK, 2998bc3103f1SAmir Vadai sizeof(key->enc_ipv4.dst)))) 2999bc3103f1SAmir Vadai goto nla_put_failure; 3000bc3103f1SAmir Vadai else if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS && 3001bc3103f1SAmir Vadai (fl_dump_key_val(skb, &key->enc_ipv6.src, 3002bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_SRC, &mask->enc_ipv6.src, 3003bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK, 3004bc3103f1SAmir Vadai sizeof(key->enc_ipv6.src)) || 3005bc3103f1SAmir Vadai fl_dump_key_val(skb, &key->enc_ipv6.dst, 3006bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_DST, 3007bc3103f1SAmir Vadai &mask->enc_ipv6.dst, 3008bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_DST_MASK, 3009bc3103f1SAmir Vadai sizeof(key->enc_ipv6.dst)))) 3010bc3103f1SAmir Vadai goto nla_put_failure; 3011bc3103f1SAmir Vadai 3012bc3103f1SAmir Vadai if (fl_dump_key_val(skb, &key->enc_key_id, TCA_FLOWER_KEY_ENC_KEY_ID, 3013eb523f42SHadar Hen Zion &mask->enc_key_id, TCA_FLOWER_UNSPEC, 3014f4d997fdSHadar Hen Zion sizeof(key->enc_key_id)) || 3015f4d997fdSHadar Hen Zion fl_dump_key_val(skb, &key->enc_tp.src, 3016f4d997fdSHadar Hen Zion TCA_FLOWER_KEY_ENC_UDP_SRC_PORT, 3017f4d997fdSHadar Hen Zion &mask->enc_tp.src, 3018f4d997fdSHadar Hen Zion TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK, 3019f4d997fdSHadar Hen Zion sizeof(key->enc_tp.src)) || 3020f4d997fdSHadar Hen Zion fl_dump_key_val(skb, &key->enc_tp.dst, 3021f4d997fdSHadar Hen Zion TCA_FLOWER_KEY_ENC_UDP_DST_PORT, 3022f4d997fdSHadar Hen Zion &mask->enc_tp.dst, 3023f4d997fdSHadar Hen Zion TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK, 30240e2c17b6SOr Gerlitz sizeof(key->enc_tp.dst)) || 30250a6e7778SPieter Jansen van Vuuren fl_dump_key_ip(skb, true, &key->enc_ip, &mask->enc_ip) || 30260a6e7778SPieter Jansen van Vuuren fl_dump_key_enc_opt(skb, &key->enc_opts, &mask->enc_opts)) 3027bc3103f1SAmir Vadai goto nla_put_failure; 3028bc3103f1SAmir Vadai 3029e0ace68aSPaul Blakey if (fl_dump_key_ct(skb, &key->ct, &mask->ct)) 3030e0ace68aSPaul Blakey goto nla_put_failure; 3031e0ace68aSPaul Blakey 3032faa3ffceSOr Gerlitz if (fl_dump_key_flags(skb, key->control.flags, mask->control.flags)) 3033faa3ffceSOr Gerlitz goto nla_put_failure; 3034faa3ffceSOr Gerlitz 30355923b8f7SAriel Levkovich if (fl_dump_key_val(skb, &key->hash.hash, TCA_FLOWER_KEY_HASH, 30365923b8f7SAriel Levkovich &mask->hash.hash, TCA_FLOWER_KEY_HASH_MASK, 30375923b8f7SAriel Levkovich sizeof(key->hash.hash))) 30385923b8f7SAriel Levkovich goto nla_put_failure; 30395923b8f7SAriel Levkovich 3040f5749081SJiri Pirko return 0; 3041f5749081SJiri Pirko 3042f5749081SJiri Pirko nla_put_failure: 3043f5749081SJiri Pirko return -EMSGSIZE; 3044f5749081SJiri Pirko } 3045f5749081SJiri Pirko 3046f5749081SJiri Pirko static int fl_dump(struct net *net, struct tcf_proto *tp, void *fh, 304712db03b6SVlad Buslov struct sk_buff *skb, struct tcmsg *t, bool rtnl_held) 3048f5749081SJiri Pirko { 3049f5749081SJiri Pirko struct cls_fl_filter *f = fh; 3050f5749081SJiri Pirko struct nlattr *nest; 3051f5749081SJiri Pirko struct fl_flow_key *key, *mask; 30523d81e711SVlad Buslov bool skip_hw; 3053f5749081SJiri Pirko 3054f5749081SJiri Pirko if (!f) 3055f5749081SJiri Pirko return skb->len; 3056f5749081SJiri Pirko 3057f5749081SJiri Pirko t->tcm_handle = f->handle; 3058f5749081SJiri Pirko 3059ae0be8deSMichal Kubecek nest = nla_nest_start_noflag(skb, TCA_OPTIONS); 3060f5749081SJiri Pirko if (!nest) 3061f5749081SJiri Pirko goto nla_put_failure; 3062f5749081SJiri Pirko 30633d81e711SVlad Buslov spin_lock(&tp->lock); 30643d81e711SVlad Buslov 3065f5749081SJiri Pirko if (f->res.classid && 3066f5749081SJiri Pirko nla_put_u32(skb, TCA_FLOWER_CLASSID, f->res.classid)) 30673d81e711SVlad Buslov goto nla_put_failure_locked; 3068f5749081SJiri Pirko 3069f5749081SJiri Pirko key = &f->key; 3070f5749081SJiri Pirko mask = &f->mask->key; 30713d81e711SVlad Buslov skip_hw = tc_skip_hw(f->flags); 3072f5749081SJiri Pirko 3073f5749081SJiri Pirko if (fl_dump_key(skb, net, key, mask)) 30743d81e711SVlad Buslov goto nla_put_failure_locked; 3075f5749081SJiri Pirko 3076749e6720SOr Gerlitz if (f->flags && nla_put_u32(skb, TCA_FLOWER_FLAGS, f->flags)) 30773d81e711SVlad Buslov goto nla_put_failure_locked; 30783d81e711SVlad Buslov 30793d81e711SVlad Buslov spin_unlock(&tp->lock); 30803d81e711SVlad Buslov 30813d81e711SVlad Buslov if (!skip_hw) 3082c24e43d8SVlad Buslov fl_hw_update_stats(tp, f, rtnl_held); 3083e69985c6SAmir Vadai 308486c55361SVlad Buslov if (nla_put_u32(skb, TCA_FLOWER_IN_HW_COUNT, f->in_hw_count)) 308586c55361SVlad Buslov goto nla_put_failure; 308686c55361SVlad Buslov 308777b9900eSJiri Pirko if (tcf_exts_dump(skb, &f->exts)) 308877b9900eSJiri Pirko goto nla_put_failure; 308977b9900eSJiri Pirko 309077b9900eSJiri Pirko nla_nest_end(skb, nest); 309177b9900eSJiri Pirko 309277b9900eSJiri Pirko if (tcf_exts_dump_stats(skb, &f->exts) < 0) 309377b9900eSJiri Pirko goto nla_put_failure; 309477b9900eSJiri Pirko 309577b9900eSJiri Pirko return skb->len; 309677b9900eSJiri Pirko 30973d81e711SVlad Buslov nla_put_failure_locked: 30983d81e711SVlad Buslov spin_unlock(&tp->lock); 309977b9900eSJiri Pirko nla_put_failure: 310077b9900eSJiri Pirko nla_nest_cancel(skb, nest); 310177b9900eSJiri Pirko return -1; 310277b9900eSJiri Pirko } 310377b9900eSJiri Pirko 31040348451dSVlad Buslov static int fl_terse_dump(struct net *net, struct tcf_proto *tp, void *fh, 31050348451dSVlad Buslov struct sk_buff *skb, struct tcmsg *t, bool rtnl_held) 31060348451dSVlad Buslov { 31070348451dSVlad Buslov struct cls_fl_filter *f = fh; 31080348451dSVlad Buslov struct nlattr *nest; 31090348451dSVlad Buslov bool skip_hw; 31100348451dSVlad Buslov 31110348451dSVlad Buslov if (!f) 31120348451dSVlad Buslov return skb->len; 31130348451dSVlad Buslov 31140348451dSVlad Buslov t->tcm_handle = f->handle; 31150348451dSVlad Buslov 31160348451dSVlad Buslov nest = nla_nest_start_noflag(skb, TCA_OPTIONS); 31170348451dSVlad Buslov if (!nest) 31180348451dSVlad Buslov goto nla_put_failure; 31190348451dSVlad Buslov 31200348451dSVlad Buslov spin_lock(&tp->lock); 31210348451dSVlad Buslov 31220348451dSVlad Buslov skip_hw = tc_skip_hw(f->flags); 31230348451dSVlad Buslov 31240348451dSVlad Buslov if (f->flags && nla_put_u32(skb, TCA_FLOWER_FLAGS, f->flags)) 31250348451dSVlad Buslov goto nla_put_failure_locked; 31260348451dSVlad Buslov 31270348451dSVlad Buslov spin_unlock(&tp->lock); 31280348451dSVlad Buslov 31290348451dSVlad Buslov if (!skip_hw) 31300348451dSVlad Buslov fl_hw_update_stats(tp, f, rtnl_held); 31310348451dSVlad Buslov 31320348451dSVlad Buslov if (tcf_exts_terse_dump(skb, &f->exts)) 31330348451dSVlad Buslov goto nla_put_failure; 31340348451dSVlad Buslov 31350348451dSVlad Buslov nla_nest_end(skb, nest); 31360348451dSVlad Buslov 31370348451dSVlad Buslov return skb->len; 31380348451dSVlad Buslov 31390348451dSVlad Buslov nla_put_failure_locked: 31400348451dSVlad Buslov spin_unlock(&tp->lock); 31410348451dSVlad Buslov nla_put_failure: 31420348451dSVlad Buslov nla_nest_cancel(skb, nest); 31430348451dSVlad Buslov return -1; 31440348451dSVlad Buslov } 31450348451dSVlad Buslov 3146b95ec7ebSJiri Pirko static int fl_tmplt_dump(struct sk_buff *skb, struct net *net, void *tmplt_priv) 3147b95ec7ebSJiri Pirko { 3148b95ec7ebSJiri Pirko struct fl_flow_tmplt *tmplt = tmplt_priv; 3149b95ec7ebSJiri Pirko struct fl_flow_key *key, *mask; 3150b95ec7ebSJiri Pirko struct nlattr *nest; 3151b95ec7ebSJiri Pirko 3152ae0be8deSMichal Kubecek nest = nla_nest_start_noflag(skb, TCA_OPTIONS); 3153b95ec7ebSJiri Pirko if (!nest) 3154b95ec7ebSJiri Pirko goto nla_put_failure; 3155b95ec7ebSJiri Pirko 3156b95ec7ebSJiri Pirko key = &tmplt->dummy_key; 3157b95ec7ebSJiri Pirko mask = &tmplt->mask; 3158b95ec7ebSJiri Pirko 3159b95ec7ebSJiri Pirko if (fl_dump_key(skb, net, key, mask)) 3160b95ec7ebSJiri Pirko goto nla_put_failure; 3161b95ec7ebSJiri Pirko 3162b95ec7ebSJiri Pirko nla_nest_end(skb, nest); 3163b95ec7ebSJiri Pirko 3164b95ec7ebSJiri Pirko return skb->len; 3165b95ec7ebSJiri Pirko 3166b95ec7ebSJiri Pirko nla_put_failure: 3167b95ec7ebSJiri Pirko nla_nest_cancel(skb, nest); 3168b95ec7ebSJiri Pirko return -EMSGSIZE; 3169b95ec7ebSJiri Pirko } 3170b95ec7ebSJiri Pirko 31712e24cd75SCong Wang static void fl_bind_class(void *fh, u32 classid, unsigned long cl, void *q, 31722e24cd75SCong Wang unsigned long base) 317307d79fc7SCong Wang { 317407d79fc7SCong Wang struct cls_fl_filter *f = fh; 317507d79fc7SCong Wang 31762e24cd75SCong Wang if (f && f->res.classid == classid) { 31772e24cd75SCong Wang if (cl) 31782e24cd75SCong Wang __tcf_bind_filter(q, &f->res, base); 31792e24cd75SCong Wang else 31802e24cd75SCong Wang __tcf_unbind_filter(q, &f->res); 31812e24cd75SCong Wang } 318207d79fc7SCong Wang } 318307d79fc7SCong Wang 3184a5b72a08SDavide Caratti static bool fl_delete_empty(struct tcf_proto *tp) 3185a5b72a08SDavide Caratti { 3186a5b72a08SDavide Caratti struct cls_fl_head *head = fl_head_dereference(tp); 3187a5b72a08SDavide Caratti 3188a5b72a08SDavide Caratti spin_lock(&tp->lock); 3189a5b72a08SDavide Caratti tp->deleting = idr_is_empty(&head->handle_idr); 3190a5b72a08SDavide Caratti spin_unlock(&tp->lock); 3191a5b72a08SDavide Caratti 3192a5b72a08SDavide Caratti return tp->deleting; 3193a5b72a08SDavide Caratti } 3194a5b72a08SDavide Caratti 319577b9900eSJiri Pirko static struct tcf_proto_ops cls_fl_ops __read_mostly = { 319677b9900eSJiri Pirko .kind = "flower", 319777b9900eSJiri Pirko .classify = fl_classify, 319877b9900eSJiri Pirko .init = fl_init, 319977b9900eSJiri Pirko .destroy = fl_destroy, 320077b9900eSJiri Pirko .get = fl_get, 320106177558SVlad Buslov .put = fl_put, 320277b9900eSJiri Pirko .change = fl_change, 320377b9900eSJiri Pirko .delete = fl_delete, 3204a5b72a08SDavide Caratti .delete_empty = fl_delete_empty, 320577b9900eSJiri Pirko .walk = fl_walk, 320631533cbaSJohn Hurley .reoffload = fl_reoffload, 3207a449a3e7SVlad Buslov .hw_add = fl_hw_add, 3208a449a3e7SVlad Buslov .hw_del = fl_hw_del, 320977b9900eSJiri Pirko .dump = fl_dump, 32100348451dSVlad Buslov .terse_dump = fl_terse_dump, 321107d79fc7SCong Wang .bind_class = fl_bind_class, 3212b95ec7ebSJiri Pirko .tmplt_create = fl_tmplt_create, 3213b95ec7ebSJiri Pirko .tmplt_destroy = fl_tmplt_destroy, 3214b95ec7ebSJiri Pirko .tmplt_dump = fl_tmplt_dump, 321577b9900eSJiri Pirko .owner = THIS_MODULE, 321692149190SVlad Buslov .flags = TCF_PROTO_OPS_DOIT_UNLOCKED, 321777b9900eSJiri Pirko }; 321877b9900eSJiri Pirko 321977b9900eSJiri Pirko static int __init cls_fl_init(void) 322077b9900eSJiri Pirko { 322177b9900eSJiri Pirko return register_tcf_proto_ops(&cls_fl_ops); 322277b9900eSJiri Pirko } 322377b9900eSJiri Pirko 322477b9900eSJiri Pirko static void __exit cls_fl_exit(void) 322577b9900eSJiri Pirko { 322677b9900eSJiri Pirko unregister_tcf_proto_ops(&cls_fl_ops); 322777b9900eSJiri Pirko } 322877b9900eSJiri Pirko 322977b9900eSJiri Pirko module_init(cls_fl_init); 323077b9900eSJiri Pirko module_exit(cls_fl_exit); 323177b9900eSJiri Pirko 323277b9900eSJiri Pirko MODULE_AUTHOR("Jiri Pirko <jiri@resnulli.us>"); 323377b9900eSJiri Pirko MODULE_DESCRIPTION("Flower classifier"); 323477b9900eSJiri Pirko MODULE_LICENSE("GPL v2"); 3235