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); 332*6de6e46dSYoshiki Komachi skb_flow_dissect(skb, &mask->dissector, &skb_key, 333*6de6e46dSYoshiki Komachi FLOW_DISSECTOR_F_STOP_BEFORE_ENCAP); 33477b9900eSJiri Pirko 3350af413bdSArnd Bergmann f = fl_mask_lookup(mask, &skb_key); 336e8eb36cdSAmir Vadai if (f && !tc_skip_sw(f->flags)) { 33777b9900eSJiri Pirko *res = f->res; 33877b9900eSJiri Pirko return tcf_exts_exec(skb, &f->exts, res); 33977b9900eSJiri Pirko } 34005cd271fSPaul Blakey } 34177b9900eSJiri Pirko return -1; 34277b9900eSJiri Pirko } 34377b9900eSJiri Pirko 34477b9900eSJiri Pirko static int fl_init(struct tcf_proto *tp) 34577b9900eSJiri Pirko { 34677b9900eSJiri Pirko struct cls_fl_head *head; 34777b9900eSJiri Pirko 34877b9900eSJiri Pirko head = kzalloc(sizeof(*head), GFP_KERNEL); 34977b9900eSJiri Pirko if (!head) 35077b9900eSJiri Pirko return -ENOBUFS; 35177b9900eSJiri Pirko 352259e60f9SVlad Buslov spin_lock_init(&head->masks_lock); 35305cd271fSPaul Blakey INIT_LIST_HEAD_RCU(&head->masks); 354c049d56eSVlad Buslov INIT_LIST_HEAD(&head->hw_filters); 35577b9900eSJiri Pirko rcu_assign_pointer(tp->root, head); 356c15ab236SChris Mi idr_init(&head->handle_idr); 35777b9900eSJiri Pirko 35805cd271fSPaul Blakey return rhashtable_init(&head->ht, &mask_ht_params); 35905cd271fSPaul Blakey } 36005cd271fSPaul Blakey 36199815f50SVlad Buslov static void fl_mask_free(struct fl_flow_mask *mask, bool mask_init_done) 36244a5cd43SPaolo Abeni { 36399815f50SVlad Buslov /* temporary masks don't have their filters list and ht initialized */ 36499815f50SVlad Buslov if (mask_init_done) { 365f48ef4d5SVlad Buslov WARN_ON(!list_empty(&mask->filters)); 36644a5cd43SPaolo Abeni rhashtable_destroy(&mask->ht); 36799815f50SVlad Buslov } 36844a5cd43SPaolo Abeni kfree(mask); 36944a5cd43SPaolo Abeni } 37044a5cd43SPaolo Abeni 37144a5cd43SPaolo Abeni static void fl_mask_free_work(struct work_struct *work) 37244a5cd43SPaolo Abeni { 37344a5cd43SPaolo Abeni struct fl_flow_mask *mask = container_of(to_rcu_work(work), 37444a5cd43SPaolo Abeni struct fl_flow_mask, rwork); 37544a5cd43SPaolo Abeni 37699815f50SVlad Buslov fl_mask_free(mask, true); 37799815f50SVlad Buslov } 37899815f50SVlad Buslov 37999815f50SVlad Buslov static void fl_uninit_mask_free_work(struct work_struct *work) 38099815f50SVlad Buslov { 38199815f50SVlad Buslov struct fl_flow_mask *mask = container_of(to_rcu_work(work), 38299815f50SVlad Buslov struct fl_flow_mask, rwork); 38399815f50SVlad Buslov 38499815f50SVlad Buslov fl_mask_free(mask, false); 38544a5cd43SPaolo Abeni } 38644a5cd43SPaolo Abeni 3879994677cSVlad Buslov static bool fl_mask_put(struct cls_fl_head *head, struct fl_flow_mask *mask) 38805cd271fSPaul Blakey { 389f48ef4d5SVlad Buslov if (!refcount_dec_and_test(&mask->refcnt)) 39005cd271fSPaul Blakey return false; 39105cd271fSPaul Blakey 39205cd271fSPaul Blakey rhashtable_remove_fast(&head->ht, &mask->ht_node, mask_ht_params); 393259e60f9SVlad Buslov 394259e60f9SVlad Buslov spin_lock(&head->masks_lock); 39505cd271fSPaul Blakey list_del_rcu(&mask->list); 396259e60f9SVlad Buslov spin_unlock(&head->masks_lock); 397259e60f9SVlad Buslov 39844a5cd43SPaolo Abeni tcf_queue_work(&mask->rwork, fl_mask_free_work); 39905cd271fSPaul Blakey 40005cd271fSPaul Blakey return true; 40177b9900eSJiri Pirko } 40277b9900eSJiri Pirko 403c049d56eSVlad Buslov static struct cls_fl_head *fl_head_dereference(struct tcf_proto *tp) 404c049d56eSVlad Buslov { 405c049d56eSVlad Buslov /* Flower classifier only changes root pointer during init and destroy. 406c049d56eSVlad Buslov * Users must obtain reference to tcf_proto instance before calling its 407c049d56eSVlad Buslov * API, so tp->root pointer is protected from concurrent call to 408c049d56eSVlad Buslov * fl_destroy() by reference counting. 409c049d56eSVlad Buslov */ 410c049d56eSVlad Buslov return rcu_dereference_raw(tp->root); 411c049d56eSVlad Buslov } 412c049d56eSVlad Buslov 4130dadc117SCong Wang static void __fl_destroy_filter(struct cls_fl_filter *f) 4140dadc117SCong Wang { 4150dadc117SCong Wang tcf_exts_destroy(&f->exts); 4160dadc117SCong Wang tcf_exts_put_net(&f->exts); 4170dadc117SCong Wang kfree(f); 4180dadc117SCong Wang } 4190dadc117SCong Wang 4200552c8afSCong Wang static void fl_destroy_filter_work(struct work_struct *work) 4210552c8afSCong Wang { 422aaa908ffSCong Wang struct cls_fl_filter *f = container_of(to_rcu_work(work), 423aaa908ffSCong Wang struct cls_fl_filter, rwork); 4240552c8afSCong Wang 4250dadc117SCong Wang __fl_destroy_filter(f); 4260552c8afSCong Wang } 4270552c8afSCong Wang 4281b0f8037SJakub Kicinski static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f, 429c24e43d8SVlad Buslov bool rtnl_held, struct netlink_ext_ack *extack) 4305b33f488SAmir Vadai { 431208c0f4bSJiri Pirko struct tcf_block *block = tp->chain->block; 432f9e30088SPablo Neira Ayuso struct flow_cls_offload cls_flower = {}; 4335b33f488SAmir Vadai 434d6787147SPieter Jansen van Vuuren tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack); 435f9e30088SPablo Neira Ayuso cls_flower.command = FLOW_CLS_DESTROY; 436de4784caSJiri Pirko cls_flower.cookie = (unsigned long) f; 4375b33f488SAmir Vadai 43840119211SVlad Buslov tc_setup_cb_destroy(block, tp, TC_SETUP_CLSFLOWER, &cls_flower, false, 439918190f5SVlad Buslov &f->flags, &f->in_hw_count, rtnl_held); 440c24e43d8SVlad Buslov 4415b33f488SAmir Vadai } 4425b33f488SAmir Vadai 443e8eb36cdSAmir Vadai static int fl_hw_replace_filter(struct tcf_proto *tp, 444c24e43d8SVlad Buslov struct cls_fl_filter *f, bool rtnl_held, 44541002038SQuentin Monnet struct netlink_ext_ack *extack) 4465b33f488SAmir Vadai { 447208c0f4bSJiri Pirko struct tcf_block *block = tp->chain->block; 448f9e30088SPablo Neira Ayuso struct flow_cls_offload cls_flower = {}; 449717503b9SJiri Pirko bool skip_sw = tc_skip_sw(f->flags); 450c24e43d8SVlad Buslov int err = 0; 451c24e43d8SVlad Buslov 452e3ab786bSPablo Neira Ayuso cls_flower.rule = flow_rule_alloc(tcf_exts_num_actions(&f->exts)); 453918190f5SVlad Buslov if (!cls_flower.rule) 454918190f5SVlad Buslov return -ENOMEM; 4558f256622SPablo Neira Ayuso 456d6787147SPieter Jansen van Vuuren tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack); 457f9e30088SPablo Neira Ayuso cls_flower.command = FLOW_CLS_REPLACE; 458de4784caSJiri Pirko cls_flower.cookie = (unsigned long) f; 4598f256622SPablo Neira Ayuso cls_flower.rule->match.dissector = &f->mask->dissector; 4608f256622SPablo Neira Ayuso cls_flower.rule->match.mask = &f->mask->key; 4618f256622SPablo Neira Ayuso cls_flower.rule->match.key = &f->mkey; 462384c181eSAmritha Nambiar cls_flower.classid = f->res.classid; 4635b33f488SAmir Vadai 464b15e7a6eSVlad Buslov err = tc_setup_flow_action(&cls_flower.rule->action, &f->exts); 4653a7b6861SPablo Neira Ayuso if (err) { 4663a7b6861SPablo Neira Ayuso kfree(cls_flower.rule); 467918190f5SVlad Buslov if (skip_sw) { 4681f15bb4fSVlad Buslov NL_SET_ERR_MSG_MOD(extack, "Failed to setup flow action"); 469918190f5SVlad Buslov return err; 470918190f5SVlad Buslov } 471918190f5SVlad Buslov return 0; 4721f15bb4fSVlad Buslov } 4733a7b6861SPablo Neira Ayuso 47440119211SVlad Buslov err = tc_setup_cb_add(block, tp, TC_SETUP_CLSFLOWER, &cls_flower, 475918190f5SVlad Buslov skip_sw, &f->flags, &f->in_hw_count, rtnl_held); 4765a6ff4b1SVlad Buslov tc_cleanup_flow_action(&cls_flower.rule->action); 4778f256622SPablo Neira Ayuso kfree(cls_flower.rule); 4788f256622SPablo Neira Ayuso 47940119211SVlad Buslov if (err) { 480918190f5SVlad Buslov fl_hw_destroy_filter(tp, f, rtnl_held, NULL); 481c24e43d8SVlad Buslov return err; 482c24e43d8SVlad Buslov } 483c24e43d8SVlad Buslov 484918190f5SVlad Buslov if (skip_sw && !(f->flags & TCA_CLS_FLAGS_IN_HW)) 485918190f5SVlad Buslov return -EINVAL; 486918190f5SVlad Buslov 487918190f5SVlad Buslov return 0; 488918190f5SVlad Buslov } 489918190f5SVlad Buslov 490c24e43d8SVlad Buslov static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f, 491c24e43d8SVlad Buslov bool rtnl_held) 49210cbc684SAmir Vadai { 493208c0f4bSJiri Pirko struct tcf_block *block = tp->chain->block; 494f9e30088SPablo Neira Ayuso struct flow_cls_offload cls_flower = {}; 49510cbc684SAmir Vadai 496d6787147SPieter Jansen van Vuuren tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, NULL); 497f9e30088SPablo Neira Ayuso cls_flower.command = FLOW_CLS_STATS; 498de4784caSJiri Pirko cls_flower.cookie = (unsigned long) f; 499384c181eSAmritha Nambiar cls_flower.classid = f->res.classid; 50010cbc684SAmir Vadai 501918190f5SVlad Buslov tc_setup_cb_call(block, TC_SETUP_CLSFLOWER, &cls_flower, false, 502918190f5SVlad Buslov rtnl_held); 5033b1903efSPablo Neira Ayuso 5043b1903efSPablo Neira Ayuso tcf_exts_stats_update(&f->exts, cls_flower.stats.bytes, 5053b1903efSPablo Neira Ayuso cls_flower.stats.pkts, 5064b61d3e8SPo Liu cls_flower.stats.drops, 50793a129ebSJiri Pirko cls_flower.stats.lastused, 50893a129ebSJiri Pirko cls_flower.stats.used_hw_stats, 50993a129ebSJiri Pirko cls_flower.stats.used_hw_stats_valid); 51010cbc684SAmir Vadai } 51110cbc684SAmir Vadai 51206177558SVlad Buslov static void __fl_put(struct cls_fl_filter *f) 51306177558SVlad Buslov { 51406177558SVlad Buslov if (!refcount_dec_and_test(&f->refcnt)) 51506177558SVlad Buslov return; 51606177558SVlad Buslov 51706177558SVlad Buslov if (tcf_exts_get_net(&f->exts)) 51806177558SVlad Buslov tcf_queue_work(&f->rwork, fl_destroy_filter_work); 51906177558SVlad Buslov else 52006177558SVlad Buslov __fl_destroy_filter(f); 52106177558SVlad Buslov } 52206177558SVlad Buslov 52306177558SVlad Buslov static struct cls_fl_filter *__fl_get(struct cls_fl_head *head, u32 handle) 52406177558SVlad Buslov { 52506177558SVlad Buslov struct cls_fl_filter *f; 52606177558SVlad Buslov 52706177558SVlad Buslov rcu_read_lock(); 52806177558SVlad Buslov f = idr_find(&head->handle_idr, handle); 52906177558SVlad Buslov if (f && !refcount_inc_not_zero(&f->refcnt)) 53006177558SVlad Buslov f = NULL; 53106177558SVlad Buslov rcu_read_unlock(); 53206177558SVlad Buslov 53306177558SVlad Buslov return f; 53406177558SVlad Buslov } 53506177558SVlad Buslov 536b2552b8cSVlad Buslov static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, 537c24e43d8SVlad Buslov bool *last, bool rtnl_held, 538c24e43d8SVlad Buslov struct netlink_ext_ack *extack) 53913fa876eSRoi Dayan { 540e474619aSVlad Buslov struct cls_fl_head *head = fl_head_dereference(tp); 541c15ab236SChris Mi 542b2552b8cSVlad Buslov *last = false; 543b2552b8cSVlad Buslov 5443d81e711SVlad Buslov spin_lock(&tp->lock); 5453d81e711SVlad Buslov if (f->deleted) { 5463d81e711SVlad Buslov spin_unlock(&tp->lock); 547b2552b8cSVlad Buslov return -ENOENT; 5483d81e711SVlad Buslov } 549b2552b8cSVlad Buslov 550b2552b8cSVlad Buslov f->deleted = true; 551b2552b8cSVlad Buslov rhashtable_remove_fast(&f->mask->ht, &f->ht_node, 552b2552b8cSVlad Buslov f->mask->filter_ht_params); 5539c160941SMatthew Wilcox idr_remove(&head->handle_idr, f->handle); 55413fa876eSRoi Dayan list_del_rcu(&f->list); 5553d81e711SVlad Buslov spin_unlock(&tp->lock); 5563d81e711SVlad Buslov 5579994677cSVlad Buslov *last = fl_mask_put(head, f->mask); 55879685219SHadar Hen Zion if (!tc_skip_hw(f->flags)) 559c24e43d8SVlad Buslov fl_hw_destroy_filter(tp, f, rtnl_held, extack); 56013fa876eSRoi Dayan tcf_unbind_filter(tp, &f->res); 56106177558SVlad Buslov __fl_put(f); 56205cd271fSPaul Blakey 563b2552b8cSVlad Buslov return 0; 56413fa876eSRoi Dayan } 56513fa876eSRoi Dayan 566d9363774SDaniel Borkmann static void fl_destroy_sleepable(struct work_struct *work) 567d9363774SDaniel Borkmann { 568aaa908ffSCong Wang struct cls_fl_head *head = container_of(to_rcu_work(work), 569aaa908ffSCong Wang struct cls_fl_head, 570aaa908ffSCong Wang rwork); 571de9dc650SPaul Blakey 572de9dc650SPaul Blakey rhashtable_destroy(&head->ht); 573d9363774SDaniel Borkmann kfree(head); 574d9363774SDaniel Borkmann module_put(THIS_MODULE); 575d9363774SDaniel Borkmann } 576d9363774SDaniel Borkmann 57712db03b6SVlad Buslov static void fl_destroy(struct tcf_proto *tp, bool rtnl_held, 57812db03b6SVlad Buslov struct netlink_ext_ack *extack) 57977b9900eSJiri Pirko { 580e474619aSVlad Buslov struct cls_fl_head *head = fl_head_dereference(tp); 58105cd271fSPaul Blakey struct fl_flow_mask *mask, *next_mask; 58277b9900eSJiri Pirko struct cls_fl_filter *f, *next; 583b2552b8cSVlad Buslov bool last; 58477b9900eSJiri Pirko 58505cd271fSPaul Blakey list_for_each_entry_safe(mask, next_mask, &head->masks, list) { 58605cd271fSPaul Blakey list_for_each_entry_safe(f, next, &mask->filters, list) { 587c24e43d8SVlad Buslov __fl_delete(tp, f, &last, rtnl_held, extack); 588b2552b8cSVlad Buslov if (last) 58905cd271fSPaul Blakey break; 59005cd271fSPaul Blakey } 59105cd271fSPaul Blakey } 592c15ab236SChris Mi idr_destroy(&head->handle_idr); 593d9363774SDaniel Borkmann 594d9363774SDaniel Borkmann __module_get(THIS_MODULE); 595aaa908ffSCong Wang tcf_queue_work(&head->rwork, fl_destroy_sleepable); 59677b9900eSJiri Pirko } 59777b9900eSJiri Pirko 59806177558SVlad Buslov static void fl_put(struct tcf_proto *tp, void *arg) 59906177558SVlad Buslov { 60006177558SVlad Buslov struct cls_fl_filter *f = arg; 60106177558SVlad Buslov 60206177558SVlad Buslov __fl_put(f); 60306177558SVlad Buslov } 60406177558SVlad Buslov 6058113c095SWANG Cong static void *fl_get(struct tcf_proto *tp, u32 handle) 60677b9900eSJiri Pirko { 607e474619aSVlad Buslov struct cls_fl_head *head = fl_head_dereference(tp); 60877b9900eSJiri Pirko 60906177558SVlad Buslov return __fl_get(head, handle); 61077b9900eSJiri Pirko } 61177b9900eSJiri Pirko 61277b9900eSJiri Pirko static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = { 61377b9900eSJiri Pirko [TCA_FLOWER_UNSPEC] = { .type = NLA_UNSPEC }, 61477b9900eSJiri Pirko [TCA_FLOWER_CLASSID] = { .type = NLA_U32 }, 61577b9900eSJiri Pirko [TCA_FLOWER_INDEV] = { .type = NLA_STRING, 61677b9900eSJiri Pirko .len = IFNAMSIZ }, 61777b9900eSJiri Pirko [TCA_FLOWER_KEY_ETH_DST] = { .len = ETH_ALEN }, 61877b9900eSJiri Pirko [TCA_FLOWER_KEY_ETH_DST_MASK] = { .len = ETH_ALEN }, 61977b9900eSJiri Pirko [TCA_FLOWER_KEY_ETH_SRC] = { .len = ETH_ALEN }, 62077b9900eSJiri Pirko [TCA_FLOWER_KEY_ETH_SRC_MASK] = { .len = ETH_ALEN }, 62177b9900eSJiri Pirko [TCA_FLOWER_KEY_ETH_TYPE] = { .type = NLA_U16 }, 62277b9900eSJiri Pirko [TCA_FLOWER_KEY_IP_PROTO] = { .type = NLA_U8 }, 62377b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV4_SRC] = { .type = NLA_U32 }, 62477b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV4_SRC_MASK] = { .type = NLA_U32 }, 62577b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV4_DST] = { .type = NLA_U32 }, 62677b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV4_DST_MASK] = { .type = NLA_U32 }, 62777b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV6_SRC] = { .len = sizeof(struct in6_addr) }, 62877b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) }, 62977b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV6_DST] = { .len = sizeof(struct in6_addr) }, 63077b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) }, 63177b9900eSJiri Pirko [TCA_FLOWER_KEY_TCP_SRC] = { .type = NLA_U16 }, 63277b9900eSJiri Pirko [TCA_FLOWER_KEY_TCP_DST] = { .type = NLA_U16 }, 633b175c3a4SJamal Hadi Salim [TCA_FLOWER_KEY_UDP_SRC] = { .type = NLA_U16 }, 634b175c3a4SJamal Hadi Salim [TCA_FLOWER_KEY_UDP_DST] = { .type = NLA_U16 }, 6359399ae9aSHadar Hen Zion [TCA_FLOWER_KEY_VLAN_ID] = { .type = NLA_U16 }, 6369399ae9aSHadar Hen Zion [TCA_FLOWER_KEY_VLAN_PRIO] = { .type = NLA_U8 }, 6379399ae9aSHadar Hen Zion [TCA_FLOWER_KEY_VLAN_ETH_TYPE] = { .type = NLA_U16 }, 638bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_KEY_ID] = { .type = NLA_U32 }, 639bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV4_SRC] = { .type = NLA_U32 }, 640bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] = { .type = NLA_U32 }, 641bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV4_DST] = { .type = NLA_U32 }, 642bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] = { .type = NLA_U32 }, 643bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV6_SRC] = { .len = sizeof(struct in6_addr) }, 644bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) }, 645bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV6_DST] = { .len = sizeof(struct in6_addr) }, 646bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) }, 647aa72d708SOr Gerlitz [TCA_FLOWER_KEY_TCP_SRC_MASK] = { .type = NLA_U16 }, 648aa72d708SOr Gerlitz [TCA_FLOWER_KEY_TCP_DST_MASK] = { .type = NLA_U16 }, 649aa72d708SOr Gerlitz [TCA_FLOWER_KEY_UDP_SRC_MASK] = { .type = NLA_U16 }, 650aa72d708SOr Gerlitz [TCA_FLOWER_KEY_UDP_DST_MASK] = { .type = NLA_U16 }, 6515976c5f4SSimon Horman [TCA_FLOWER_KEY_SCTP_SRC_MASK] = { .type = NLA_U16 }, 6525976c5f4SSimon Horman [TCA_FLOWER_KEY_SCTP_DST_MASK] = { .type = NLA_U16 }, 6535976c5f4SSimon Horman [TCA_FLOWER_KEY_SCTP_SRC] = { .type = NLA_U16 }, 6545976c5f4SSimon Horman [TCA_FLOWER_KEY_SCTP_DST] = { .type = NLA_U16 }, 655f4d997fdSHadar Hen Zion [TCA_FLOWER_KEY_ENC_UDP_SRC_PORT] = { .type = NLA_U16 }, 656f4d997fdSHadar Hen Zion [TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK] = { .type = NLA_U16 }, 657f4d997fdSHadar Hen Zion [TCA_FLOWER_KEY_ENC_UDP_DST_PORT] = { .type = NLA_U16 }, 658f4d997fdSHadar Hen Zion [TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK] = { .type = NLA_U16 }, 659faa3ffceSOr Gerlitz [TCA_FLOWER_KEY_FLAGS] = { .type = NLA_U32 }, 660faa3ffceSOr Gerlitz [TCA_FLOWER_KEY_FLAGS_MASK] = { .type = NLA_U32 }, 6617b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV4_TYPE] = { .type = NLA_U8 }, 6627b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV4_TYPE_MASK] = { .type = NLA_U8 }, 6637b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV4_CODE] = { .type = NLA_U8 }, 6647b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV4_CODE_MASK] = { .type = NLA_U8 }, 6657b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV6_TYPE] = { .type = NLA_U8 }, 6667b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV6_TYPE_MASK] = { .type = NLA_U8 }, 6677b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV6_CODE] = { .type = NLA_U8 }, 6687b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV6_CODE_MASK] = { .type = NLA_U8 }, 66999d31326SSimon Horman [TCA_FLOWER_KEY_ARP_SIP] = { .type = NLA_U32 }, 67099d31326SSimon Horman [TCA_FLOWER_KEY_ARP_SIP_MASK] = { .type = NLA_U32 }, 67199d31326SSimon Horman [TCA_FLOWER_KEY_ARP_TIP] = { .type = NLA_U32 }, 67299d31326SSimon Horman [TCA_FLOWER_KEY_ARP_TIP_MASK] = { .type = NLA_U32 }, 67399d31326SSimon Horman [TCA_FLOWER_KEY_ARP_OP] = { .type = NLA_U8 }, 67499d31326SSimon Horman [TCA_FLOWER_KEY_ARP_OP_MASK] = { .type = NLA_U8 }, 67599d31326SSimon Horman [TCA_FLOWER_KEY_ARP_SHA] = { .len = ETH_ALEN }, 67699d31326SSimon Horman [TCA_FLOWER_KEY_ARP_SHA_MASK] = { .len = ETH_ALEN }, 67799d31326SSimon Horman [TCA_FLOWER_KEY_ARP_THA] = { .len = ETH_ALEN }, 67899d31326SSimon Horman [TCA_FLOWER_KEY_ARP_THA_MASK] = { .len = ETH_ALEN }, 679a577d8f7SBenjamin LaHaise [TCA_FLOWER_KEY_MPLS_TTL] = { .type = NLA_U8 }, 680a577d8f7SBenjamin LaHaise [TCA_FLOWER_KEY_MPLS_BOS] = { .type = NLA_U8 }, 681a577d8f7SBenjamin LaHaise [TCA_FLOWER_KEY_MPLS_TC] = { .type = NLA_U8 }, 682a577d8f7SBenjamin LaHaise [TCA_FLOWER_KEY_MPLS_LABEL] = { .type = NLA_U32 }, 68361aec25aSGuillaume Nault [TCA_FLOWER_KEY_MPLS_OPTS] = { .type = NLA_NESTED }, 684fdfc7dd6SJiri Pirko [TCA_FLOWER_KEY_TCP_FLAGS] = { .type = NLA_U16 }, 685fdfc7dd6SJiri Pirko [TCA_FLOWER_KEY_TCP_FLAGS_MASK] = { .type = NLA_U16 }, 6864d80cc0aSOr Gerlitz [TCA_FLOWER_KEY_IP_TOS] = { .type = NLA_U8 }, 6874d80cc0aSOr Gerlitz [TCA_FLOWER_KEY_IP_TOS_MASK] = { .type = NLA_U8 }, 6884d80cc0aSOr Gerlitz [TCA_FLOWER_KEY_IP_TTL] = { .type = NLA_U8 }, 6894d80cc0aSOr Gerlitz [TCA_FLOWER_KEY_IP_TTL_MASK] = { .type = NLA_U8 }, 690d64efd09SJianbo Liu [TCA_FLOWER_KEY_CVLAN_ID] = { .type = NLA_U16 }, 691d64efd09SJianbo Liu [TCA_FLOWER_KEY_CVLAN_PRIO] = { .type = NLA_U8 }, 692d64efd09SJianbo Liu [TCA_FLOWER_KEY_CVLAN_ETH_TYPE] = { .type = NLA_U16 }, 6930e2c17b6SOr Gerlitz [TCA_FLOWER_KEY_ENC_IP_TOS] = { .type = NLA_U8 }, 6940e2c17b6SOr Gerlitz [TCA_FLOWER_KEY_ENC_IP_TOS_MASK] = { .type = NLA_U8 }, 6950e2c17b6SOr Gerlitz [TCA_FLOWER_KEY_ENC_IP_TTL] = { .type = NLA_U8 }, 6960e2c17b6SOr Gerlitz [TCA_FLOWER_KEY_ENC_IP_TTL_MASK] = { .type = NLA_U8 }, 6970a6e7778SPieter Jansen van Vuuren [TCA_FLOWER_KEY_ENC_OPTS] = { .type = NLA_NESTED }, 6980a6e7778SPieter Jansen van Vuuren [TCA_FLOWER_KEY_ENC_OPTS_MASK] = { .type = NLA_NESTED }, 6991bcc51acSwenxu [TCA_FLOWER_KEY_CT_STATE] = 7001bcc51acSwenxu NLA_POLICY_MASK(NLA_U16, TCA_FLOWER_KEY_CT_FLAGS_MASK), 7011bcc51acSwenxu [TCA_FLOWER_KEY_CT_STATE_MASK] = 7021bcc51acSwenxu NLA_POLICY_MASK(NLA_U16, TCA_FLOWER_KEY_CT_FLAGS_MASK), 703e0ace68aSPaul Blakey [TCA_FLOWER_KEY_CT_ZONE] = { .type = NLA_U16 }, 704e0ace68aSPaul Blakey [TCA_FLOWER_KEY_CT_ZONE_MASK] = { .type = NLA_U16 }, 705e0ace68aSPaul Blakey [TCA_FLOWER_KEY_CT_MARK] = { .type = NLA_U32 }, 706e0ace68aSPaul Blakey [TCA_FLOWER_KEY_CT_MARK_MASK] = { .type = NLA_U32 }, 707e0ace68aSPaul Blakey [TCA_FLOWER_KEY_CT_LABELS] = { .type = NLA_BINARY, 708e0ace68aSPaul Blakey .len = 128 / BITS_PER_BYTE }, 709e0ace68aSPaul Blakey [TCA_FLOWER_KEY_CT_LABELS_MASK] = { .type = NLA_BINARY, 710e0ace68aSPaul Blakey .len = 128 / BITS_PER_BYTE }, 711e2debf08SDavide Caratti [TCA_FLOWER_FLAGS] = { .type = NLA_U32 }, 7125923b8f7SAriel Levkovich [TCA_FLOWER_KEY_HASH] = { .type = NLA_U32 }, 7135923b8f7SAriel Levkovich [TCA_FLOWER_KEY_HASH_MASK] = { .type = NLA_U32 }, 7145923b8f7SAriel Levkovich 7150a6e7778SPieter Jansen van Vuuren }; 7160a6e7778SPieter Jansen van Vuuren 7170a6e7778SPieter Jansen van Vuuren static const struct nla_policy 7180a6e7778SPieter Jansen van Vuuren enc_opts_policy[TCA_FLOWER_KEY_ENC_OPTS_MAX + 1] = { 719d8f9dfaeSXin Long [TCA_FLOWER_KEY_ENC_OPTS_UNSPEC] = { 720d8f9dfaeSXin Long .strict_start_type = TCA_FLOWER_KEY_ENC_OPTS_VXLAN }, 7210a6e7778SPieter Jansen van Vuuren [TCA_FLOWER_KEY_ENC_OPTS_GENEVE] = { .type = NLA_NESTED }, 722d8f9dfaeSXin Long [TCA_FLOWER_KEY_ENC_OPTS_VXLAN] = { .type = NLA_NESTED }, 72379b1011cSXin Long [TCA_FLOWER_KEY_ENC_OPTS_ERSPAN] = { .type = NLA_NESTED }, 7240a6e7778SPieter Jansen van Vuuren }; 7250a6e7778SPieter Jansen van Vuuren 7260a6e7778SPieter Jansen van Vuuren static const struct nla_policy 7270a6e7778SPieter Jansen van Vuuren geneve_opt_policy[TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX + 1] = { 7280a6e7778SPieter Jansen van Vuuren [TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS] = { .type = NLA_U16 }, 7290a6e7778SPieter Jansen van Vuuren [TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE] = { .type = NLA_U8 }, 7300a6e7778SPieter Jansen van Vuuren [TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA] = { .type = NLA_BINARY, 7310a6e7778SPieter Jansen van Vuuren .len = 128 }, 73277b9900eSJiri Pirko }; 73377b9900eSJiri Pirko 734d8f9dfaeSXin Long static const struct nla_policy 735d8f9dfaeSXin Long vxlan_opt_policy[TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX + 1] = { 736d8f9dfaeSXin Long [TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP] = { .type = NLA_U32 }, 737d8f9dfaeSXin Long }; 738d8f9dfaeSXin Long 73979b1011cSXin Long static const struct nla_policy 74079b1011cSXin Long erspan_opt_policy[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX + 1] = { 74179b1011cSXin Long [TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER] = { .type = NLA_U8 }, 74279b1011cSXin Long [TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX] = { .type = NLA_U32 }, 74379b1011cSXin Long [TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR] = { .type = NLA_U8 }, 74479b1011cSXin Long [TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID] = { .type = NLA_U8 }, 74579b1011cSXin Long }; 74679b1011cSXin Long 74761aec25aSGuillaume Nault static const struct nla_policy 74861aec25aSGuillaume Nault mpls_stack_entry_policy[TCA_FLOWER_KEY_MPLS_OPT_LSE_MAX + 1] = { 74961aec25aSGuillaume Nault [TCA_FLOWER_KEY_MPLS_OPT_LSE_DEPTH] = { .type = NLA_U8 }, 75061aec25aSGuillaume Nault [TCA_FLOWER_KEY_MPLS_OPT_LSE_TTL] = { .type = NLA_U8 }, 75161aec25aSGuillaume Nault [TCA_FLOWER_KEY_MPLS_OPT_LSE_BOS] = { .type = NLA_U8 }, 75261aec25aSGuillaume Nault [TCA_FLOWER_KEY_MPLS_OPT_LSE_TC] = { .type = NLA_U8 }, 75361aec25aSGuillaume Nault [TCA_FLOWER_KEY_MPLS_OPT_LSE_LABEL] = { .type = NLA_U32 }, 75461aec25aSGuillaume Nault }; 75561aec25aSGuillaume Nault 75677b9900eSJiri Pirko static void fl_set_key_val(struct nlattr **tb, 75777b9900eSJiri Pirko void *val, int val_type, 75877b9900eSJiri Pirko void *mask, int mask_type, int len) 75977b9900eSJiri Pirko { 76077b9900eSJiri Pirko if (!tb[val_type]) 76177b9900eSJiri Pirko return; 762e0ace68aSPaul Blakey nla_memcpy(val, tb[val_type], len); 76377b9900eSJiri Pirko if (mask_type == TCA_FLOWER_UNSPEC || !tb[mask_type]) 76477b9900eSJiri Pirko memset(mask, 0xff, len); 76577b9900eSJiri Pirko else 766e0ace68aSPaul Blakey nla_memcpy(mask, tb[mask_type], len); 76777b9900eSJiri Pirko } 76877b9900eSJiri Pirko 7695c72299fSAmritha Nambiar static int fl_set_key_port_range(struct nlattr **tb, struct fl_flow_key *key, 770bd7d4c12SGuillaume Nault struct fl_flow_key *mask, 771bd7d4c12SGuillaume Nault struct netlink_ext_ack *extack) 7725c72299fSAmritha Nambiar { 7738ffb055bSYoshiki Komachi fl_set_key_val(tb, &key->tp_range.tp_min.dst, 7748ffb055bSYoshiki Komachi TCA_FLOWER_KEY_PORT_DST_MIN, &mask->tp_range.tp_min.dst, 7758ffb055bSYoshiki Komachi TCA_FLOWER_UNSPEC, sizeof(key->tp_range.tp_min.dst)); 7768ffb055bSYoshiki Komachi fl_set_key_val(tb, &key->tp_range.tp_max.dst, 7778ffb055bSYoshiki Komachi TCA_FLOWER_KEY_PORT_DST_MAX, &mask->tp_range.tp_max.dst, 7788ffb055bSYoshiki Komachi TCA_FLOWER_UNSPEC, sizeof(key->tp_range.tp_max.dst)); 7798ffb055bSYoshiki Komachi fl_set_key_val(tb, &key->tp_range.tp_min.src, 7808ffb055bSYoshiki Komachi TCA_FLOWER_KEY_PORT_SRC_MIN, &mask->tp_range.tp_min.src, 7818ffb055bSYoshiki Komachi TCA_FLOWER_UNSPEC, sizeof(key->tp_range.tp_min.src)); 7828ffb055bSYoshiki Komachi fl_set_key_val(tb, &key->tp_range.tp_max.src, 7838ffb055bSYoshiki Komachi TCA_FLOWER_KEY_PORT_SRC_MAX, &mask->tp_range.tp_max.src, 7848ffb055bSYoshiki Komachi TCA_FLOWER_UNSPEC, sizeof(key->tp_range.tp_max.src)); 7855c72299fSAmritha Nambiar 786bd7d4c12SGuillaume Nault if (mask->tp_range.tp_min.dst && mask->tp_range.tp_max.dst && 7876215afcbSVladimir Oltean ntohs(key->tp_range.tp_max.dst) <= 7886215afcbSVladimir Oltean ntohs(key->tp_range.tp_min.dst)) { 789bd7d4c12SGuillaume Nault NL_SET_ERR_MSG_ATTR(extack, 790bd7d4c12SGuillaume Nault tb[TCA_FLOWER_KEY_PORT_DST_MIN], 791bd7d4c12SGuillaume Nault "Invalid destination port range (min must be strictly smaller than max)"); 7925c72299fSAmritha Nambiar return -EINVAL; 793bd7d4c12SGuillaume Nault } 794bd7d4c12SGuillaume Nault if (mask->tp_range.tp_min.src && mask->tp_range.tp_max.src && 7956215afcbSVladimir Oltean ntohs(key->tp_range.tp_max.src) <= 7966215afcbSVladimir Oltean ntohs(key->tp_range.tp_min.src)) { 797bd7d4c12SGuillaume Nault NL_SET_ERR_MSG_ATTR(extack, 798bd7d4c12SGuillaume Nault tb[TCA_FLOWER_KEY_PORT_SRC_MIN], 799bd7d4c12SGuillaume Nault "Invalid source port range (min must be strictly smaller than max)"); 800bd7d4c12SGuillaume Nault return -EINVAL; 801bd7d4c12SGuillaume Nault } 8025c72299fSAmritha Nambiar 8035c72299fSAmritha Nambiar return 0; 8045c72299fSAmritha Nambiar } 8055c72299fSAmritha Nambiar 80661aec25aSGuillaume Nault static int fl_set_key_mpls_lse(const struct nlattr *nla_lse, 80761aec25aSGuillaume Nault struct flow_dissector_key_mpls *key_val, 80861aec25aSGuillaume Nault struct flow_dissector_key_mpls *key_mask, 80961aec25aSGuillaume Nault struct netlink_ext_ack *extack) 81061aec25aSGuillaume Nault { 81161aec25aSGuillaume Nault struct nlattr *tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_MAX + 1]; 81261aec25aSGuillaume Nault struct flow_dissector_mpls_lse *lse_mask; 81361aec25aSGuillaume Nault struct flow_dissector_mpls_lse *lse_val; 81461aec25aSGuillaume Nault u8 lse_index; 81561aec25aSGuillaume Nault u8 depth; 81661aec25aSGuillaume Nault int err; 81761aec25aSGuillaume Nault 81861aec25aSGuillaume Nault err = nla_parse_nested(tb, TCA_FLOWER_KEY_MPLS_OPT_LSE_MAX, nla_lse, 81961aec25aSGuillaume Nault mpls_stack_entry_policy, extack); 82061aec25aSGuillaume Nault if (err < 0) 82161aec25aSGuillaume Nault return err; 82261aec25aSGuillaume Nault 82361aec25aSGuillaume Nault if (!tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_DEPTH]) { 82461aec25aSGuillaume Nault NL_SET_ERR_MSG(extack, "Missing MPLS option \"depth\""); 82561aec25aSGuillaume Nault return -EINVAL; 82661aec25aSGuillaume Nault } 82761aec25aSGuillaume Nault 82861aec25aSGuillaume Nault depth = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_DEPTH]); 82961aec25aSGuillaume Nault 83061aec25aSGuillaume Nault /* LSE depth starts at 1, for consistency with terminology used by 83161aec25aSGuillaume Nault * RFC 3031 (section 3.9), where depth 0 refers to unlabeled packets. 83261aec25aSGuillaume Nault */ 83361aec25aSGuillaume Nault if (depth < 1 || depth > FLOW_DIS_MPLS_MAX) { 83461aec25aSGuillaume Nault NL_SET_ERR_MSG_ATTR(extack, 83561aec25aSGuillaume Nault tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_DEPTH], 83661aec25aSGuillaume Nault "Invalid MPLS depth"); 83761aec25aSGuillaume Nault return -EINVAL; 83861aec25aSGuillaume Nault } 83961aec25aSGuillaume Nault lse_index = depth - 1; 84061aec25aSGuillaume Nault 84161aec25aSGuillaume Nault dissector_set_mpls_lse(key_val, lse_index); 84261aec25aSGuillaume Nault dissector_set_mpls_lse(key_mask, lse_index); 84361aec25aSGuillaume Nault 84461aec25aSGuillaume Nault lse_val = &key_val->ls[lse_index]; 84561aec25aSGuillaume Nault lse_mask = &key_mask->ls[lse_index]; 84661aec25aSGuillaume Nault 84761aec25aSGuillaume Nault if (tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_TTL]) { 84861aec25aSGuillaume Nault lse_val->mpls_ttl = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_TTL]); 84961aec25aSGuillaume Nault lse_mask->mpls_ttl = MPLS_TTL_MASK; 85061aec25aSGuillaume Nault } 85161aec25aSGuillaume Nault if (tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_BOS]) { 85261aec25aSGuillaume Nault u8 bos = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_BOS]); 85361aec25aSGuillaume Nault 85461aec25aSGuillaume Nault if (bos & ~MPLS_BOS_MASK) { 85561aec25aSGuillaume Nault NL_SET_ERR_MSG_ATTR(extack, 85661aec25aSGuillaume Nault tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_BOS], 85761aec25aSGuillaume Nault "Bottom Of Stack (BOS) must be 0 or 1"); 85861aec25aSGuillaume Nault return -EINVAL; 85961aec25aSGuillaume Nault } 86061aec25aSGuillaume Nault lse_val->mpls_bos = bos; 86161aec25aSGuillaume Nault lse_mask->mpls_bos = MPLS_BOS_MASK; 86261aec25aSGuillaume Nault } 86361aec25aSGuillaume Nault if (tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_TC]) { 86461aec25aSGuillaume Nault u8 tc = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_TC]); 86561aec25aSGuillaume Nault 86661aec25aSGuillaume Nault if (tc & ~MPLS_TC_MASK) { 86761aec25aSGuillaume Nault NL_SET_ERR_MSG_ATTR(extack, 86861aec25aSGuillaume Nault tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_TC], 86961aec25aSGuillaume Nault "Traffic Class (TC) must be between 0 and 7"); 87061aec25aSGuillaume Nault return -EINVAL; 87161aec25aSGuillaume Nault } 87261aec25aSGuillaume Nault lse_val->mpls_tc = tc; 87361aec25aSGuillaume Nault lse_mask->mpls_tc = MPLS_TC_MASK; 87461aec25aSGuillaume Nault } 87561aec25aSGuillaume Nault if (tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_LABEL]) { 87661aec25aSGuillaume Nault u32 label = nla_get_u32(tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_LABEL]); 87761aec25aSGuillaume Nault 87861aec25aSGuillaume Nault if (label & ~MPLS_LABEL_MASK) { 87961aec25aSGuillaume Nault NL_SET_ERR_MSG_ATTR(extack, 88061aec25aSGuillaume Nault tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_LABEL], 88161aec25aSGuillaume Nault "Label must be between 0 and 1048575"); 88261aec25aSGuillaume Nault return -EINVAL; 88361aec25aSGuillaume Nault } 88461aec25aSGuillaume Nault lse_val->mpls_label = label; 88561aec25aSGuillaume Nault lse_mask->mpls_label = MPLS_LABEL_MASK; 88661aec25aSGuillaume Nault } 88761aec25aSGuillaume Nault 88861aec25aSGuillaume Nault return 0; 88961aec25aSGuillaume Nault } 89061aec25aSGuillaume Nault 89161aec25aSGuillaume Nault static int fl_set_key_mpls_opts(const struct nlattr *nla_mpls_opts, 89261aec25aSGuillaume Nault struct flow_dissector_key_mpls *key_val, 89361aec25aSGuillaume Nault struct flow_dissector_key_mpls *key_mask, 89461aec25aSGuillaume Nault struct netlink_ext_ack *extack) 89561aec25aSGuillaume Nault { 89661aec25aSGuillaume Nault struct nlattr *nla_lse; 89761aec25aSGuillaume Nault int rem; 89861aec25aSGuillaume Nault int err; 89961aec25aSGuillaume Nault 90061aec25aSGuillaume Nault if (!(nla_mpls_opts->nla_type & NLA_F_NESTED)) { 90161aec25aSGuillaume Nault NL_SET_ERR_MSG_ATTR(extack, nla_mpls_opts, 90261aec25aSGuillaume Nault "NLA_F_NESTED is missing"); 90361aec25aSGuillaume Nault return -EINVAL; 90461aec25aSGuillaume Nault } 90561aec25aSGuillaume Nault 90661aec25aSGuillaume Nault nla_for_each_nested(nla_lse, nla_mpls_opts, rem) { 90761aec25aSGuillaume Nault if (nla_type(nla_lse) != TCA_FLOWER_KEY_MPLS_OPTS_LSE) { 90861aec25aSGuillaume Nault NL_SET_ERR_MSG_ATTR(extack, nla_lse, 90961aec25aSGuillaume Nault "Invalid MPLS option type"); 91061aec25aSGuillaume Nault return -EINVAL; 91161aec25aSGuillaume Nault } 91261aec25aSGuillaume Nault 91361aec25aSGuillaume Nault err = fl_set_key_mpls_lse(nla_lse, key_val, key_mask, extack); 91461aec25aSGuillaume Nault if (err < 0) 91561aec25aSGuillaume Nault return err; 91661aec25aSGuillaume Nault } 91761aec25aSGuillaume Nault if (rem) { 91861aec25aSGuillaume Nault NL_SET_ERR_MSG(extack, 91961aec25aSGuillaume Nault "Bytes leftover after parsing MPLS options"); 92061aec25aSGuillaume Nault return -EINVAL; 92161aec25aSGuillaume Nault } 92261aec25aSGuillaume Nault 92361aec25aSGuillaume Nault return 0; 92461aec25aSGuillaume Nault } 92561aec25aSGuillaume Nault 9261a7fca63SBenjamin LaHaise static int fl_set_key_mpls(struct nlattr **tb, 927a577d8f7SBenjamin LaHaise struct flow_dissector_key_mpls *key_val, 928442f730eSGuillaume Nault struct flow_dissector_key_mpls *key_mask, 929442f730eSGuillaume Nault struct netlink_ext_ack *extack) 930a577d8f7SBenjamin LaHaise { 93158cff782SGuillaume Nault struct flow_dissector_mpls_lse *lse_mask; 93258cff782SGuillaume Nault struct flow_dissector_mpls_lse *lse_val; 93358cff782SGuillaume Nault 93461aec25aSGuillaume Nault if (tb[TCA_FLOWER_KEY_MPLS_OPTS]) { 93561aec25aSGuillaume Nault if (tb[TCA_FLOWER_KEY_MPLS_TTL] || 93661aec25aSGuillaume Nault tb[TCA_FLOWER_KEY_MPLS_BOS] || 93761aec25aSGuillaume Nault tb[TCA_FLOWER_KEY_MPLS_TC] || 93861aec25aSGuillaume Nault tb[TCA_FLOWER_KEY_MPLS_LABEL]) { 93961aec25aSGuillaume Nault NL_SET_ERR_MSG_ATTR(extack, 94061aec25aSGuillaume Nault tb[TCA_FLOWER_KEY_MPLS_OPTS], 94161aec25aSGuillaume Nault "MPLS label, Traffic Class, Bottom Of Stack and Time To Live must be encapsulated in the MPLS options attribute"); 94261aec25aSGuillaume Nault return -EBADMSG; 94361aec25aSGuillaume Nault } 94461aec25aSGuillaume Nault 94561aec25aSGuillaume Nault return fl_set_key_mpls_opts(tb[TCA_FLOWER_KEY_MPLS_OPTS], 94661aec25aSGuillaume Nault key_val, key_mask, extack); 94761aec25aSGuillaume Nault } 94861aec25aSGuillaume Nault 94958cff782SGuillaume Nault lse_val = &key_val->ls[0]; 95058cff782SGuillaume Nault lse_mask = &key_mask->ls[0]; 95158cff782SGuillaume Nault 952a577d8f7SBenjamin LaHaise if (tb[TCA_FLOWER_KEY_MPLS_TTL]) { 95358cff782SGuillaume Nault lse_val->mpls_ttl = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TTL]); 95458cff782SGuillaume Nault lse_mask->mpls_ttl = MPLS_TTL_MASK; 95558cff782SGuillaume Nault dissector_set_mpls_lse(key_val, 0); 95658cff782SGuillaume Nault dissector_set_mpls_lse(key_mask, 0); 957a577d8f7SBenjamin LaHaise } 958a577d8f7SBenjamin LaHaise if (tb[TCA_FLOWER_KEY_MPLS_BOS]) { 9591a7fca63SBenjamin LaHaise u8 bos = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_BOS]); 9601a7fca63SBenjamin LaHaise 961442f730eSGuillaume Nault if (bos & ~MPLS_BOS_MASK) { 962442f730eSGuillaume Nault NL_SET_ERR_MSG_ATTR(extack, 963442f730eSGuillaume Nault tb[TCA_FLOWER_KEY_MPLS_BOS], 964442f730eSGuillaume Nault "Bottom Of Stack (BOS) must be 0 or 1"); 9651a7fca63SBenjamin LaHaise return -EINVAL; 966442f730eSGuillaume Nault } 96758cff782SGuillaume Nault lse_val->mpls_bos = bos; 96858cff782SGuillaume Nault lse_mask->mpls_bos = MPLS_BOS_MASK; 96958cff782SGuillaume Nault dissector_set_mpls_lse(key_val, 0); 97058cff782SGuillaume Nault dissector_set_mpls_lse(key_mask, 0); 971a577d8f7SBenjamin LaHaise } 972a577d8f7SBenjamin LaHaise if (tb[TCA_FLOWER_KEY_MPLS_TC]) { 9731a7fca63SBenjamin LaHaise u8 tc = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TC]); 9741a7fca63SBenjamin LaHaise 975442f730eSGuillaume Nault if (tc & ~MPLS_TC_MASK) { 976442f730eSGuillaume Nault NL_SET_ERR_MSG_ATTR(extack, 977442f730eSGuillaume Nault tb[TCA_FLOWER_KEY_MPLS_TC], 978442f730eSGuillaume Nault "Traffic Class (TC) must be between 0 and 7"); 9791a7fca63SBenjamin LaHaise return -EINVAL; 980442f730eSGuillaume Nault } 98158cff782SGuillaume Nault lse_val->mpls_tc = tc; 98258cff782SGuillaume Nault lse_mask->mpls_tc = MPLS_TC_MASK; 98358cff782SGuillaume Nault dissector_set_mpls_lse(key_val, 0); 98458cff782SGuillaume Nault dissector_set_mpls_lse(key_mask, 0); 985a577d8f7SBenjamin LaHaise } 986a577d8f7SBenjamin LaHaise if (tb[TCA_FLOWER_KEY_MPLS_LABEL]) { 9871a7fca63SBenjamin LaHaise u32 label = nla_get_u32(tb[TCA_FLOWER_KEY_MPLS_LABEL]); 9881a7fca63SBenjamin LaHaise 989442f730eSGuillaume Nault if (label & ~MPLS_LABEL_MASK) { 990442f730eSGuillaume Nault NL_SET_ERR_MSG_ATTR(extack, 991442f730eSGuillaume Nault tb[TCA_FLOWER_KEY_MPLS_LABEL], 992442f730eSGuillaume Nault "Label must be between 0 and 1048575"); 9931a7fca63SBenjamin LaHaise return -EINVAL; 994442f730eSGuillaume Nault } 99558cff782SGuillaume Nault lse_val->mpls_label = label; 99658cff782SGuillaume Nault lse_mask->mpls_label = MPLS_LABEL_MASK; 99758cff782SGuillaume Nault dissector_set_mpls_lse(key_val, 0); 99858cff782SGuillaume Nault dissector_set_mpls_lse(key_mask, 0); 999a577d8f7SBenjamin LaHaise } 10001a7fca63SBenjamin LaHaise return 0; 1001a577d8f7SBenjamin LaHaise } 1002a577d8f7SBenjamin LaHaise 10039399ae9aSHadar Hen Zion static void fl_set_key_vlan(struct nlattr **tb, 1004aaab0834SJianbo Liu __be16 ethertype, 1005d64efd09SJianbo Liu int vlan_id_key, int vlan_prio_key, 10069399ae9aSHadar Hen Zion struct flow_dissector_key_vlan *key_val, 10079399ae9aSHadar Hen Zion struct flow_dissector_key_vlan *key_mask) 10089399ae9aSHadar Hen Zion { 10099399ae9aSHadar Hen Zion #define VLAN_PRIORITY_MASK 0x7 10109399ae9aSHadar Hen Zion 1011d64efd09SJianbo Liu if (tb[vlan_id_key]) { 10129399ae9aSHadar Hen Zion key_val->vlan_id = 1013d64efd09SJianbo Liu nla_get_u16(tb[vlan_id_key]) & VLAN_VID_MASK; 10149399ae9aSHadar Hen Zion key_mask->vlan_id = VLAN_VID_MASK; 10159399ae9aSHadar Hen Zion } 1016d64efd09SJianbo Liu if (tb[vlan_prio_key]) { 10179399ae9aSHadar Hen Zion key_val->vlan_priority = 1018d64efd09SJianbo Liu nla_get_u8(tb[vlan_prio_key]) & 10199399ae9aSHadar Hen Zion VLAN_PRIORITY_MASK; 10209399ae9aSHadar Hen Zion key_mask->vlan_priority = VLAN_PRIORITY_MASK; 10219399ae9aSHadar Hen Zion } 1022aaab0834SJianbo Liu key_val->vlan_tpid = ethertype; 1023aaab0834SJianbo Liu key_mask->vlan_tpid = cpu_to_be16(~0); 10249399ae9aSHadar Hen Zion } 10259399ae9aSHadar Hen Zion 1026faa3ffceSOr Gerlitz static void fl_set_key_flag(u32 flower_key, u32 flower_mask, 1027faa3ffceSOr Gerlitz u32 *dissector_key, u32 *dissector_mask, 1028faa3ffceSOr Gerlitz u32 flower_flag_bit, u32 dissector_flag_bit) 1029faa3ffceSOr Gerlitz { 1030faa3ffceSOr Gerlitz if (flower_mask & flower_flag_bit) { 1031faa3ffceSOr Gerlitz *dissector_mask |= dissector_flag_bit; 1032faa3ffceSOr Gerlitz if (flower_key & flower_flag_bit) 1033faa3ffceSOr Gerlitz *dissector_key |= dissector_flag_bit; 1034faa3ffceSOr Gerlitz } 1035faa3ffceSOr Gerlitz } 1036faa3ffceSOr Gerlitz 1037e304e21aSGuillaume Nault static int fl_set_key_flags(struct nlattr **tb, u32 *flags_key, 1038e304e21aSGuillaume Nault u32 *flags_mask, struct netlink_ext_ack *extack) 1039faa3ffceSOr Gerlitz { 1040faa3ffceSOr Gerlitz u32 key, mask; 1041faa3ffceSOr Gerlitz 1042d9724772SOr Gerlitz /* mask is mandatory for flags */ 1043e304e21aSGuillaume Nault if (!tb[TCA_FLOWER_KEY_FLAGS_MASK]) { 1044e304e21aSGuillaume Nault NL_SET_ERR_MSG(extack, "Missing flags mask"); 1045d9724772SOr Gerlitz return -EINVAL; 1046e304e21aSGuillaume Nault } 1047faa3ffceSOr Gerlitz 1048abee13f5SVladimir Oltean key = be32_to_cpu(nla_get_be32(tb[TCA_FLOWER_KEY_FLAGS])); 1049abee13f5SVladimir Oltean mask = be32_to_cpu(nla_get_be32(tb[TCA_FLOWER_KEY_FLAGS_MASK])); 1050faa3ffceSOr Gerlitz 1051faa3ffceSOr Gerlitz *flags_key = 0; 1052faa3ffceSOr Gerlitz *flags_mask = 0; 1053faa3ffceSOr Gerlitz 1054faa3ffceSOr Gerlitz fl_set_key_flag(key, mask, flags_key, flags_mask, 1055faa3ffceSOr Gerlitz TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT); 1056459d153dSPieter Jansen van Vuuren fl_set_key_flag(key, mask, flags_key, flags_mask, 1057459d153dSPieter Jansen van Vuuren TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST, 1058459d153dSPieter Jansen van Vuuren FLOW_DIS_FIRST_FRAG); 1059d9724772SOr Gerlitz 1060d9724772SOr Gerlitz return 0; 1061faa3ffceSOr Gerlitz } 1062faa3ffceSOr Gerlitz 10630e2c17b6SOr Gerlitz static void fl_set_key_ip(struct nlattr **tb, bool encap, 10644d80cc0aSOr Gerlitz struct flow_dissector_key_ip *key, 10654d80cc0aSOr Gerlitz struct flow_dissector_key_ip *mask) 10664d80cc0aSOr Gerlitz { 10670e2c17b6SOr Gerlitz int tos_key = encap ? TCA_FLOWER_KEY_ENC_IP_TOS : TCA_FLOWER_KEY_IP_TOS; 10680e2c17b6SOr Gerlitz int ttl_key = encap ? TCA_FLOWER_KEY_ENC_IP_TTL : TCA_FLOWER_KEY_IP_TTL; 10690e2c17b6SOr Gerlitz int tos_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TOS_MASK : TCA_FLOWER_KEY_IP_TOS_MASK; 10700e2c17b6SOr Gerlitz int ttl_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TTL_MASK : TCA_FLOWER_KEY_IP_TTL_MASK; 10714d80cc0aSOr Gerlitz 10720e2c17b6SOr Gerlitz fl_set_key_val(tb, &key->tos, tos_key, &mask->tos, tos_mask, sizeof(key->tos)); 10730e2c17b6SOr Gerlitz fl_set_key_val(tb, &key->ttl, ttl_key, &mask->ttl, ttl_mask, sizeof(key->ttl)); 10744d80cc0aSOr Gerlitz } 10754d80cc0aSOr Gerlitz 10760a6e7778SPieter Jansen van Vuuren static int fl_set_geneve_opt(const struct nlattr *nla, struct fl_flow_key *key, 10770a6e7778SPieter Jansen van Vuuren int depth, int option_len, 10780a6e7778SPieter Jansen van Vuuren struct netlink_ext_ack *extack) 10790a6e7778SPieter Jansen van Vuuren { 10800a6e7778SPieter Jansen van Vuuren struct nlattr *tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX + 1]; 10810a6e7778SPieter Jansen van Vuuren struct nlattr *class = NULL, *type = NULL, *data = NULL; 10820a6e7778SPieter Jansen van Vuuren struct geneve_opt *opt; 10830a6e7778SPieter Jansen van Vuuren int err, data_len = 0; 10840a6e7778SPieter Jansen van Vuuren 10850a6e7778SPieter Jansen van Vuuren if (option_len > sizeof(struct geneve_opt)) 10860a6e7778SPieter Jansen van Vuuren data_len = option_len - sizeof(struct geneve_opt); 10870a6e7778SPieter Jansen van Vuuren 10880a6e7778SPieter Jansen van Vuuren opt = (struct geneve_opt *)&key->enc_opts.data[key->enc_opts.len]; 10890a6e7778SPieter Jansen van Vuuren memset(opt, 0xff, option_len); 10900a6e7778SPieter Jansen van Vuuren opt->length = data_len / 4; 10910a6e7778SPieter Jansen van Vuuren opt->r1 = 0; 10920a6e7778SPieter Jansen van Vuuren opt->r2 = 0; 10930a6e7778SPieter Jansen van Vuuren opt->r3 = 0; 10940a6e7778SPieter Jansen van Vuuren 10950a6e7778SPieter Jansen van Vuuren /* If no mask has been prodived we assume an exact match. */ 10960a6e7778SPieter Jansen van Vuuren if (!depth) 10970a6e7778SPieter Jansen van Vuuren return sizeof(struct geneve_opt) + data_len; 10980a6e7778SPieter Jansen van Vuuren 10990a6e7778SPieter Jansen van Vuuren if (nla_type(nla) != TCA_FLOWER_KEY_ENC_OPTS_GENEVE) { 11000a6e7778SPieter Jansen van Vuuren NL_SET_ERR_MSG(extack, "Non-geneve option type for mask"); 11010a6e7778SPieter Jansen van Vuuren return -EINVAL; 11020a6e7778SPieter Jansen van Vuuren } 11030a6e7778SPieter Jansen van Vuuren 11048cb08174SJohannes Berg err = nla_parse_nested_deprecated(tb, 11058cb08174SJohannes Berg TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX, 11060a6e7778SPieter Jansen van Vuuren nla, geneve_opt_policy, extack); 11070a6e7778SPieter Jansen van Vuuren if (err < 0) 11080a6e7778SPieter Jansen van Vuuren return err; 11090a6e7778SPieter Jansen van Vuuren 11100a6e7778SPieter Jansen van Vuuren /* We are not allowed to omit any of CLASS, TYPE or DATA 11110a6e7778SPieter Jansen van Vuuren * fields from the key. 11120a6e7778SPieter Jansen van Vuuren */ 11130a6e7778SPieter Jansen van Vuuren if (!option_len && 11140a6e7778SPieter Jansen van Vuuren (!tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS] || 11150a6e7778SPieter Jansen van Vuuren !tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE] || 11160a6e7778SPieter Jansen van Vuuren !tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA])) { 11170a6e7778SPieter Jansen van Vuuren NL_SET_ERR_MSG(extack, "Missing tunnel key geneve option class, type or data"); 11180a6e7778SPieter Jansen van Vuuren return -EINVAL; 11190a6e7778SPieter Jansen van Vuuren } 11200a6e7778SPieter Jansen van Vuuren 11210a6e7778SPieter Jansen van Vuuren /* Omitting any of CLASS, TYPE or DATA fields is allowed 11220a6e7778SPieter Jansen van Vuuren * for the mask. 11230a6e7778SPieter Jansen van Vuuren */ 11240a6e7778SPieter Jansen van Vuuren if (tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA]) { 11250a6e7778SPieter Jansen van Vuuren int new_len = key->enc_opts.len; 11260a6e7778SPieter Jansen van Vuuren 11270a6e7778SPieter Jansen van Vuuren data = tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA]; 11280a6e7778SPieter Jansen van Vuuren data_len = nla_len(data); 11290a6e7778SPieter Jansen van Vuuren if (data_len < 4) { 11300a6e7778SPieter Jansen van Vuuren NL_SET_ERR_MSG(extack, "Tunnel key geneve option data is less than 4 bytes long"); 11310a6e7778SPieter Jansen van Vuuren return -ERANGE; 11320a6e7778SPieter Jansen van Vuuren } 11330a6e7778SPieter Jansen van Vuuren if (data_len % 4) { 11340a6e7778SPieter Jansen van Vuuren NL_SET_ERR_MSG(extack, "Tunnel key geneve option data is not a multiple of 4 bytes long"); 11350a6e7778SPieter Jansen van Vuuren return -ERANGE; 11360a6e7778SPieter Jansen van Vuuren } 11370a6e7778SPieter Jansen van Vuuren 11380a6e7778SPieter Jansen van Vuuren new_len += sizeof(struct geneve_opt) + data_len; 11390a6e7778SPieter Jansen van Vuuren BUILD_BUG_ON(FLOW_DIS_TUN_OPTS_MAX != IP_TUNNEL_OPTS_MAX); 11400a6e7778SPieter Jansen van Vuuren if (new_len > FLOW_DIS_TUN_OPTS_MAX) { 11410a6e7778SPieter Jansen van Vuuren NL_SET_ERR_MSG(extack, "Tunnel options exceeds max size"); 11420a6e7778SPieter Jansen van Vuuren return -ERANGE; 11430a6e7778SPieter Jansen van Vuuren } 11440a6e7778SPieter Jansen van Vuuren opt->length = data_len / 4; 11450a6e7778SPieter Jansen van Vuuren memcpy(opt->opt_data, nla_data(data), data_len); 11460a6e7778SPieter Jansen van Vuuren } 11470a6e7778SPieter Jansen van Vuuren 11480a6e7778SPieter Jansen van Vuuren if (tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS]) { 11490a6e7778SPieter Jansen van Vuuren class = tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS]; 11500a6e7778SPieter Jansen van Vuuren opt->opt_class = nla_get_be16(class); 11510a6e7778SPieter Jansen van Vuuren } 11520a6e7778SPieter Jansen van Vuuren 11530a6e7778SPieter Jansen van Vuuren if (tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE]) { 11540a6e7778SPieter Jansen van Vuuren type = tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE]; 11550a6e7778SPieter Jansen van Vuuren opt->type = nla_get_u8(type); 11560a6e7778SPieter Jansen van Vuuren } 11570a6e7778SPieter Jansen van Vuuren 11580a6e7778SPieter Jansen van Vuuren return sizeof(struct geneve_opt) + data_len; 11590a6e7778SPieter Jansen van Vuuren } 11600a6e7778SPieter Jansen van Vuuren 1161d8f9dfaeSXin Long static int fl_set_vxlan_opt(const struct nlattr *nla, struct fl_flow_key *key, 1162d8f9dfaeSXin Long int depth, int option_len, 1163d8f9dfaeSXin Long struct netlink_ext_ack *extack) 1164d8f9dfaeSXin Long { 1165d8f9dfaeSXin Long struct nlattr *tb[TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX + 1]; 1166d8f9dfaeSXin Long struct vxlan_metadata *md; 1167d8f9dfaeSXin Long int err; 1168d8f9dfaeSXin Long 1169d8f9dfaeSXin Long md = (struct vxlan_metadata *)&key->enc_opts.data[key->enc_opts.len]; 1170d8f9dfaeSXin Long memset(md, 0xff, sizeof(*md)); 1171d8f9dfaeSXin Long 1172d8f9dfaeSXin Long if (!depth) 1173d8f9dfaeSXin Long return sizeof(*md); 1174d8f9dfaeSXin Long 1175d8f9dfaeSXin Long if (nla_type(nla) != TCA_FLOWER_KEY_ENC_OPTS_VXLAN) { 1176d8f9dfaeSXin Long NL_SET_ERR_MSG(extack, "Non-vxlan option type for mask"); 1177d8f9dfaeSXin Long return -EINVAL; 1178d8f9dfaeSXin Long } 1179d8f9dfaeSXin Long 1180d8f9dfaeSXin Long err = nla_parse_nested(tb, TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX, nla, 1181d8f9dfaeSXin Long vxlan_opt_policy, extack); 1182d8f9dfaeSXin Long if (err < 0) 1183d8f9dfaeSXin Long return err; 1184d8f9dfaeSXin Long 1185d8f9dfaeSXin Long if (!option_len && !tb[TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP]) { 1186d8f9dfaeSXin Long NL_SET_ERR_MSG(extack, "Missing tunnel key vxlan option gbp"); 1187d8f9dfaeSXin Long return -EINVAL; 1188d8f9dfaeSXin Long } 1189d8f9dfaeSXin Long 119013e6ce98SXin Long if (tb[TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP]) { 1191d8f9dfaeSXin Long md->gbp = nla_get_u32(tb[TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP]); 119213e6ce98SXin Long md->gbp &= VXLAN_GBP_MASK; 119313e6ce98SXin Long } 1194d8f9dfaeSXin Long 1195d8f9dfaeSXin Long return sizeof(*md); 1196d8f9dfaeSXin Long } 1197d8f9dfaeSXin Long 119879b1011cSXin Long static int fl_set_erspan_opt(const struct nlattr *nla, struct fl_flow_key *key, 119979b1011cSXin Long int depth, int option_len, 120079b1011cSXin Long struct netlink_ext_ack *extack) 120179b1011cSXin Long { 120279b1011cSXin Long struct nlattr *tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX + 1]; 120379b1011cSXin Long struct erspan_metadata *md; 120479b1011cSXin Long int err; 120579b1011cSXin Long 120679b1011cSXin Long md = (struct erspan_metadata *)&key->enc_opts.data[key->enc_opts.len]; 120779b1011cSXin Long memset(md, 0xff, sizeof(*md)); 120879b1011cSXin Long md->version = 1; 120979b1011cSXin Long 121079b1011cSXin Long if (!depth) 121179b1011cSXin Long return sizeof(*md); 121279b1011cSXin Long 121379b1011cSXin Long if (nla_type(nla) != TCA_FLOWER_KEY_ENC_OPTS_ERSPAN) { 121479b1011cSXin Long NL_SET_ERR_MSG(extack, "Non-erspan option type for mask"); 121579b1011cSXin Long return -EINVAL; 121679b1011cSXin Long } 121779b1011cSXin Long 121879b1011cSXin Long err = nla_parse_nested(tb, TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX, nla, 121979b1011cSXin Long erspan_opt_policy, extack); 122079b1011cSXin Long if (err < 0) 122179b1011cSXin Long return err; 122279b1011cSXin Long 122379b1011cSXin Long if (!option_len && !tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER]) { 122479b1011cSXin Long NL_SET_ERR_MSG(extack, "Missing tunnel key erspan option ver"); 122579b1011cSXin Long return -EINVAL; 122679b1011cSXin Long } 122779b1011cSXin Long 122879b1011cSXin Long if (tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER]) 122979b1011cSXin Long md->version = nla_get_u8(tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER]); 123079b1011cSXin Long 123179b1011cSXin Long if (md->version == 1) { 123279b1011cSXin Long if (!option_len && !tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX]) { 123379b1011cSXin Long NL_SET_ERR_MSG(extack, "Missing tunnel key erspan option index"); 123479b1011cSXin Long return -EINVAL; 123579b1011cSXin Long } 123679b1011cSXin Long if (tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX]) { 123779b1011cSXin Long nla = tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX]; 12388e1b3ac4SXin Long memset(&md->u, 0x00, sizeof(md->u)); 123979b1011cSXin Long md->u.index = nla_get_be32(nla); 124079b1011cSXin Long } 124179b1011cSXin Long } else if (md->version == 2) { 124279b1011cSXin Long if (!option_len && (!tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR] || 124379b1011cSXin Long !tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID])) { 124479b1011cSXin Long NL_SET_ERR_MSG(extack, "Missing tunnel key erspan option dir or hwid"); 124579b1011cSXin Long return -EINVAL; 124679b1011cSXin Long } 124779b1011cSXin Long if (tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR]) { 124879b1011cSXin Long nla = tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR]; 124979b1011cSXin Long md->u.md2.dir = nla_get_u8(nla); 125079b1011cSXin Long } 125179b1011cSXin Long if (tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID]) { 125279b1011cSXin Long nla = tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID]; 125379b1011cSXin Long set_hwid(&md->u.md2, nla_get_u8(nla)); 125479b1011cSXin Long } 125579b1011cSXin Long } else { 125679b1011cSXin Long NL_SET_ERR_MSG(extack, "Tunnel key erspan option ver is incorrect"); 125779b1011cSXin Long return -EINVAL; 125879b1011cSXin Long } 125979b1011cSXin Long 126079b1011cSXin Long return sizeof(*md); 126179b1011cSXin Long } 126279b1011cSXin Long 12630a6e7778SPieter Jansen van Vuuren static int fl_set_enc_opt(struct nlattr **tb, struct fl_flow_key *key, 12640a6e7778SPieter Jansen van Vuuren struct fl_flow_key *mask, 12650a6e7778SPieter Jansen van Vuuren struct netlink_ext_ack *extack) 12660a6e7778SPieter Jansen van Vuuren { 12670a6e7778SPieter Jansen van Vuuren const struct nlattr *nla_enc_key, *nla_opt_key, *nla_opt_msk = NULL; 126863c82997SJakub Kicinski int err, option_len, key_depth, msk_depth = 0; 126963c82997SJakub Kicinski 12708cb08174SJohannes Berg err = nla_validate_nested_deprecated(tb[TCA_FLOWER_KEY_ENC_OPTS], 127163c82997SJakub Kicinski TCA_FLOWER_KEY_ENC_OPTS_MAX, 127263c82997SJakub Kicinski enc_opts_policy, extack); 127363c82997SJakub Kicinski if (err) 127463c82997SJakub Kicinski return err; 12750a6e7778SPieter Jansen van Vuuren 12760a6e7778SPieter Jansen van Vuuren nla_enc_key = nla_data(tb[TCA_FLOWER_KEY_ENC_OPTS]); 12770a6e7778SPieter Jansen van Vuuren 12780a6e7778SPieter Jansen van Vuuren if (tb[TCA_FLOWER_KEY_ENC_OPTS_MASK]) { 12798cb08174SJohannes Berg err = nla_validate_nested_deprecated(tb[TCA_FLOWER_KEY_ENC_OPTS_MASK], 128063c82997SJakub Kicinski TCA_FLOWER_KEY_ENC_OPTS_MAX, 128163c82997SJakub Kicinski enc_opts_policy, extack); 128263c82997SJakub Kicinski if (err) 128363c82997SJakub Kicinski return err; 128463c82997SJakub Kicinski 12850a6e7778SPieter Jansen van Vuuren nla_opt_msk = nla_data(tb[TCA_FLOWER_KEY_ENC_OPTS_MASK]); 12860a6e7778SPieter Jansen van Vuuren msk_depth = nla_len(tb[TCA_FLOWER_KEY_ENC_OPTS_MASK]); 1287c96adff9SCong Wang if (!nla_ok(nla_opt_msk, msk_depth)) { 1288c96adff9SCong Wang NL_SET_ERR_MSG(extack, "Invalid nested attribute for masks"); 1289c96adff9SCong Wang return -EINVAL; 1290c96adff9SCong Wang } 12910a6e7778SPieter Jansen van Vuuren } 12920a6e7778SPieter Jansen van Vuuren 12930a6e7778SPieter Jansen van Vuuren nla_for_each_attr(nla_opt_key, nla_enc_key, 12940a6e7778SPieter Jansen van Vuuren nla_len(tb[TCA_FLOWER_KEY_ENC_OPTS]), key_depth) { 12950a6e7778SPieter Jansen van Vuuren switch (nla_type(nla_opt_key)) { 12960a6e7778SPieter Jansen van Vuuren case TCA_FLOWER_KEY_ENC_OPTS_GENEVE: 1297d8f9dfaeSXin Long if (key->enc_opts.dst_opt_type && 1298d8f9dfaeSXin Long key->enc_opts.dst_opt_type != TUNNEL_GENEVE_OPT) { 1299d8f9dfaeSXin Long NL_SET_ERR_MSG(extack, "Duplicate type for geneve options"); 1300d8f9dfaeSXin Long return -EINVAL; 1301d8f9dfaeSXin Long } 13020a6e7778SPieter Jansen van Vuuren option_len = 0; 13030a6e7778SPieter Jansen van Vuuren key->enc_opts.dst_opt_type = TUNNEL_GENEVE_OPT; 13040a6e7778SPieter Jansen van Vuuren option_len = fl_set_geneve_opt(nla_opt_key, key, 13050a6e7778SPieter Jansen van Vuuren key_depth, option_len, 13060a6e7778SPieter Jansen van Vuuren extack); 13070a6e7778SPieter Jansen van Vuuren if (option_len < 0) 13080a6e7778SPieter Jansen van Vuuren return option_len; 13090a6e7778SPieter Jansen van Vuuren 13100a6e7778SPieter Jansen van Vuuren key->enc_opts.len += option_len; 13110a6e7778SPieter Jansen van Vuuren /* At the same time we need to parse through the mask 13120a6e7778SPieter Jansen van Vuuren * in order to verify exact and mask attribute lengths. 13130a6e7778SPieter Jansen van Vuuren */ 13140a6e7778SPieter Jansen van Vuuren mask->enc_opts.dst_opt_type = TUNNEL_GENEVE_OPT; 13150a6e7778SPieter Jansen van Vuuren option_len = fl_set_geneve_opt(nla_opt_msk, mask, 13160a6e7778SPieter Jansen van Vuuren msk_depth, option_len, 13170a6e7778SPieter Jansen van Vuuren extack); 13180a6e7778SPieter Jansen van Vuuren if (option_len < 0) 13190a6e7778SPieter Jansen van Vuuren return option_len; 13200a6e7778SPieter Jansen van Vuuren 13210a6e7778SPieter Jansen van Vuuren mask->enc_opts.len += option_len; 13220a6e7778SPieter Jansen van Vuuren if (key->enc_opts.len != mask->enc_opts.len) { 13230a6e7778SPieter Jansen van Vuuren NL_SET_ERR_MSG(extack, "Key and mask miss aligned"); 13240a6e7778SPieter Jansen van Vuuren return -EINVAL; 13250a6e7778SPieter Jansen van Vuuren } 13260a6e7778SPieter Jansen van Vuuren break; 1327d8f9dfaeSXin Long case TCA_FLOWER_KEY_ENC_OPTS_VXLAN: 1328d8f9dfaeSXin Long if (key->enc_opts.dst_opt_type) { 1329d8f9dfaeSXin Long NL_SET_ERR_MSG(extack, "Duplicate type for vxlan options"); 1330d8f9dfaeSXin Long return -EINVAL; 1331d8f9dfaeSXin Long } 1332d8f9dfaeSXin Long option_len = 0; 1333d8f9dfaeSXin Long key->enc_opts.dst_opt_type = TUNNEL_VXLAN_OPT; 1334d8f9dfaeSXin Long option_len = fl_set_vxlan_opt(nla_opt_key, key, 1335d8f9dfaeSXin Long key_depth, option_len, 1336d8f9dfaeSXin Long extack); 1337d8f9dfaeSXin Long if (option_len < 0) 1338d8f9dfaeSXin Long return option_len; 1339d8f9dfaeSXin Long 1340d8f9dfaeSXin Long key->enc_opts.len += option_len; 1341d8f9dfaeSXin Long /* At the same time we need to parse through the mask 1342d8f9dfaeSXin Long * in order to verify exact and mask attribute lengths. 1343d8f9dfaeSXin Long */ 1344d8f9dfaeSXin Long mask->enc_opts.dst_opt_type = TUNNEL_VXLAN_OPT; 1345d8f9dfaeSXin Long option_len = fl_set_vxlan_opt(nla_opt_msk, mask, 1346d8f9dfaeSXin Long msk_depth, option_len, 1347d8f9dfaeSXin Long extack); 1348d8f9dfaeSXin Long if (option_len < 0) 1349d8f9dfaeSXin Long return option_len; 1350d8f9dfaeSXin Long 1351d8f9dfaeSXin Long mask->enc_opts.len += option_len; 1352d8f9dfaeSXin Long if (key->enc_opts.len != mask->enc_opts.len) { 1353d8f9dfaeSXin Long NL_SET_ERR_MSG(extack, "Key and mask miss aligned"); 1354d8f9dfaeSXin Long return -EINVAL; 1355d8f9dfaeSXin Long } 1356d8f9dfaeSXin Long break; 135779b1011cSXin Long case TCA_FLOWER_KEY_ENC_OPTS_ERSPAN: 135879b1011cSXin Long if (key->enc_opts.dst_opt_type) { 135979b1011cSXin Long NL_SET_ERR_MSG(extack, "Duplicate type for erspan options"); 136079b1011cSXin Long return -EINVAL; 136179b1011cSXin Long } 136279b1011cSXin Long option_len = 0; 136379b1011cSXin Long key->enc_opts.dst_opt_type = TUNNEL_ERSPAN_OPT; 136479b1011cSXin Long option_len = fl_set_erspan_opt(nla_opt_key, key, 136579b1011cSXin Long key_depth, option_len, 136679b1011cSXin Long extack); 136779b1011cSXin Long if (option_len < 0) 136879b1011cSXin Long return option_len; 136979b1011cSXin Long 137079b1011cSXin Long key->enc_opts.len += option_len; 137179b1011cSXin Long /* At the same time we need to parse through the mask 137279b1011cSXin Long * in order to verify exact and mask attribute lengths. 137379b1011cSXin Long */ 137479b1011cSXin Long mask->enc_opts.dst_opt_type = TUNNEL_ERSPAN_OPT; 137579b1011cSXin Long option_len = fl_set_erspan_opt(nla_opt_msk, mask, 137679b1011cSXin Long msk_depth, option_len, 137779b1011cSXin Long extack); 137879b1011cSXin Long if (option_len < 0) 137979b1011cSXin Long return option_len; 138079b1011cSXin Long 138179b1011cSXin Long mask->enc_opts.len += option_len; 138279b1011cSXin Long if (key->enc_opts.len != mask->enc_opts.len) { 138379b1011cSXin Long NL_SET_ERR_MSG(extack, "Key and mask miss aligned"); 138479b1011cSXin Long return -EINVAL; 138579b1011cSXin Long } 138679b1011cSXin Long break; 13870a6e7778SPieter Jansen van Vuuren default: 13880a6e7778SPieter Jansen van Vuuren NL_SET_ERR_MSG(extack, "Unknown tunnel option type"); 13890a6e7778SPieter Jansen van Vuuren return -EINVAL; 13900a6e7778SPieter Jansen van Vuuren } 1391c96adff9SCong Wang 1392c96adff9SCong Wang if (!msk_depth) 1393c96adff9SCong Wang continue; 1394c96adff9SCong Wang 1395c96adff9SCong Wang if (!nla_ok(nla_opt_msk, msk_depth)) { 1396c96adff9SCong Wang NL_SET_ERR_MSG(extack, "A mask attribute is invalid"); 1397c96adff9SCong Wang return -EINVAL; 1398c96adff9SCong Wang } 1399c96adff9SCong Wang nla_opt_msk = nla_next(nla_opt_msk, &msk_depth); 14000a6e7778SPieter Jansen van Vuuren } 14010a6e7778SPieter Jansen van Vuuren 14020a6e7778SPieter Jansen van Vuuren return 0; 14030a6e7778SPieter Jansen van Vuuren } 14040a6e7778SPieter Jansen van Vuuren 14051bcc51acSwenxu static int fl_validate_ct_state(u16 state, struct nlattr *tb, 14061bcc51acSwenxu struct netlink_ext_ack *extack) 14071bcc51acSwenxu { 14081bcc51acSwenxu if (state && !(state & TCA_FLOWER_KEY_CT_FLAGS_TRACKED)) { 14091bcc51acSwenxu NL_SET_ERR_MSG_ATTR(extack, tb, 14101bcc51acSwenxu "no trk, so no other flag can be set"); 14111bcc51acSwenxu return -EINVAL; 14121bcc51acSwenxu } 14131bcc51acSwenxu 14141bcc51acSwenxu if (state & TCA_FLOWER_KEY_CT_FLAGS_NEW && 14151bcc51acSwenxu state & TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED) { 14161bcc51acSwenxu NL_SET_ERR_MSG_ATTR(extack, tb, 14171bcc51acSwenxu "new and est are mutually exclusive"); 14181bcc51acSwenxu return -EINVAL; 14191bcc51acSwenxu } 14201bcc51acSwenxu 14213aed8b63Swenxu if (state & TCA_FLOWER_KEY_CT_FLAGS_INVALID && 14223aed8b63Swenxu state & ~(TCA_FLOWER_KEY_CT_FLAGS_TRACKED | 14233aed8b63Swenxu TCA_FLOWER_KEY_CT_FLAGS_INVALID)) { 14243aed8b63Swenxu NL_SET_ERR_MSG_ATTR(extack, tb, 14253aed8b63Swenxu "when inv is set, only trk may be set"); 14263aed8b63Swenxu return -EINVAL; 14273aed8b63Swenxu } 14283aed8b63Swenxu 14293aed8b63Swenxu if (state & TCA_FLOWER_KEY_CT_FLAGS_NEW && 14303aed8b63Swenxu state & TCA_FLOWER_KEY_CT_FLAGS_REPLY) { 14313aed8b63Swenxu NL_SET_ERR_MSG_ATTR(extack, tb, 14323aed8b63Swenxu "new and rpl are mutually exclusive"); 14333aed8b63Swenxu return -EINVAL; 14343aed8b63Swenxu } 14353aed8b63Swenxu 14361bcc51acSwenxu return 0; 14371bcc51acSwenxu } 14381bcc51acSwenxu 1439e0ace68aSPaul Blakey static int fl_set_key_ct(struct nlattr **tb, 1440e0ace68aSPaul Blakey struct flow_dissector_key_ct *key, 1441e0ace68aSPaul Blakey struct flow_dissector_key_ct *mask, 1442e0ace68aSPaul Blakey struct netlink_ext_ack *extack) 1443e0ace68aSPaul Blakey { 1444e0ace68aSPaul Blakey if (tb[TCA_FLOWER_KEY_CT_STATE]) { 14451bcc51acSwenxu int err; 14461bcc51acSwenxu 1447e0ace68aSPaul Blakey if (!IS_ENABLED(CONFIG_NF_CONNTRACK)) { 1448e0ace68aSPaul Blakey NL_SET_ERR_MSG(extack, "Conntrack isn't enabled"); 1449e0ace68aSPaul Blakey return -EOPNOTSUPP; 1450e0ace68aSPaul Blakey } 1451e0ace68aSPaul Blakey fl_set_key_val(tb, &key->ct_state, TCA_FLOWER_KEY_CT_STATE, 1452e0ace68aSPaul Blakey &mask->ct_state, TCA_FLOWER_KEY_CT_STATE_MASK, 1453e0ace68aSPaul Blakey sizeof(key->ct_state)); 14541bcc51acSwenxu 1455afa536d8Swenxu err = fl_validate_ct_state(key->ct_state & mask->ct_state, 14561bcc51acSwenxu tb[TCA_FLOWER_KEY_CT_STATE_MASK], 14571bcc51acSwenxu extack); 14581bcc51acSwenxu if (err) 14591bcc51acSwenxu return err; 14601bcc51acSwenxu 1461e0ace68aSPaul Blakey } 1462e0ace68aSPaul Blakey if (tb[TCA_FLOWER_KEY_CT_ZONE]) { 1463e0ace68aSPaul Blakey if (!IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES)) { 1464e0ace68aSPaul Blakey NL_SET_ERR_MSG(extack, "Conntrack zones isn't enabled"); 1465e0ace68aSPaul Blakey return -EOPNOTSUPP; 1466e0ace68aSPaul Blakey } 1467e0ace68aSPaul Blakey fl_set_key_val(tb, &key->ct_zone, TCA_FLOWER_KEY_CT_ZONE, 1468e0ace68aSPaul Blakey &mask->ct_zone, TCA_FLOWER_KEY_CT_ZONE_MASK, 1469e0ace68aSPaul Blakey sizeof(key->ct_zone)); 1470e0ace68aSPaul Blakey } 1471e0ace68aSPaul Blakey if (tb[TCA_FLOWER_KEY_CT_MARK]) { 1472e0ace68aSPaul Blakey if (!IS_ENABLED(CONFIG_NF_CONNTRACK_MARK)) { 1473e0ace68aSPaul Blakey NL_SET_ERR_MSG(extack, "Conntrack mark isn't enabled"); 1474e0ace68aSPaul Blakey return -EOPNOTSUPP; 1475e0ace68aSPaul Blakey } 1476e0ace68aSPaul Blakey fl_set_key_val(tb, &key->ct_mark, TCA_FLOWER_KEY_CT_MARK, 1477e0ace68aSPaul Blakey &mask->ct_mark, TCA_FLOWER_KEY_CT_MARK_MASK, 1478e0ace68aSPaul Blakey sizeof(key->ct_mark)); 1479e0ace68aSPaul Blakey } 1480e0ace68aSPaul Blakey if (tb[TCA_FLOWER_KEY_CT_LABELS]) { 1481e0ace68aSPaul Blakey if (!IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS)) { 1482e0ace68aSPaul Blakey NL_SET_ERR_MSG(extack, "Conntrack labels aren't enabled"); 1483e0ace68aSPaul Blakey return -EOPNOTSUPP; 1484e0ace68aSPaul Blakey } 1485e0ace68aSPaul Blakey fl_set_key_val(tb, key->ct_labels, TCA_FLOWER_KEY_CT_LABELS, 1486e0ace68aSPaul Blakey mask->ct_labels, TCA_FLOWER_KEY_CT_LABELS_MASK, 1487e0ace68aSPaul Blakey sizeof(key->ct_labels)); 1488e0ace68aSPaul Blakey } 1489e0ace68aSPaul Blakey 1490e0ace68aSPaul Blakey return 0; 1491e0ace68aSPaul Blakey } 1492e0ace68aSPaul Blakey 149377b9900eSJiri Pirko static int fl_set_key(struct net *net, struct nlattr **tb, 14941057c55fSAlexander Aring struct fl_flow_key *key, struct fl_flow_key *mask, 14951057c55fSAlexander Aring struct netlink_ext_ack *extack) 149677b9900eSJiri Pirko { 14979399ae9aSHadar Hen Zion __be16 ethertype; 1498d9724772SOr Gerlitz int ret = 0; 1499a5148626SJiri Pirko 150077b9900eSJiri Pirko if (tb[TCA_FLOWER_INDEV]) { 15011057c55fSAlexander Aring int err = tcf_change_indev(net, tb[TCA_FLOWER_INDEV], extack); 150277b9900eSJiri Pirko if (err < 0) 150377b9900eSJiri Pirko return err; 15048212ed77SJiri Pirko key->meta.ingress_ifindex = err; 15058212ed77SJiri Pirko mask->meta.ingress_ifindex = 0xffffffff; 150677b9900eSJiri Pirko } 150777b9900eSJiri Pirko 150877b9900eSJiri Pirko fl_set_key_val(tb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST, 150977b9900eSJiri Pirko mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK, 151077b9900eSJiri Pirko sizeof(key->eth.dst)); 151177b9900eSJiri Pirko fl_set_key_val(tb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC, 151277b9900eSJiri Pirko mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK, 151377b9900eSJiri Pirko sizeof(key->eth.src)); 151466530bdfSJamal Hadi Salim 15150b498a52SArnd Bergmann if (tb[TCA_FLOWER_KEY_ETH_TYPE]) { 15169399ae9aSHadar Hen Zion ethertype = nla_get_be16(tb[TCA_FLOWER_KEY_ETH_TYPE]); 15179399ae9aSHadar Hen Zion 1518aaab0834SJianbo Liu if (eth_type_vlan(ethertype)) { 1519d64efd09SJianbo Liu fl_set_key_vlan(tb, ethertype, TCA_FLOWER_KEY_VLAN_ID, 1520d64efd09SJianbo Liu TCA_FLOWER_KEY_VLAN_PRIO, &key->vlan, 1521d64efd09SJianbo Liu &mask->vlan); 1522d64efd09SJianbo Liu 15235e9a0fe4SJianbo Liu if (tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]) { 1524d64efd09SJianbo Liu ethertype = nla_get_be16(tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]); 1525d64efd09SJianbo Liu if (eth_type_vlan(ethertype)) { 1526d64efd09SJianbo Liu fl_set_key_vlan(tb, ethertype, 1527d64efd09SJianbo Liu TCA_FLOWER_KEY_CVLAN_ID, 1528d64efd09SJianbo Liu TCA_FLOWER_KEY_CVLAN_PRIO, 1529d64efd09SJianbo Liu &key->cvlan, &mask->cvlan); 15309399ae9aSHadar Hen Zion fl_set_key_val(tb, &key->basic.n_proto, 1531d64efd09SJianbo Liu TCA_FLOWER_KEY_CVLAN_ETH_TYPE, 1532d64efd09SJianbo Liu &mask->basic.n_proto, 1533d64efd09SJianbo Liu TCA_FLOWER_UNSPEC, 153477b9900eSJiri Pirko sizeof(key->basic.n_proto)); 15359399ae9aSHadar Hen Zion } else { 15369399ae9aSHadar Hen Zion key->basic.n_proto = ethertype; 15379399ae9aSHadar Hen Zion mask->basic.n_proto = cpu_to_be16(~0); 15389399ae9aSHadar Hen Zion } 15395e9a0fe4SJianbo Liu } 1540d64efd09SJianbo Liu } else { 1541d64efd09SJianbo Liu key->basic.n_proto = ethertype; 1542d64efd09SJianbo Liu mask->basic.n_proto = cpu_to_be16(~0); 1543d64efd09SJianbo Liu } 15440b498a52SArnd Bergmann } 154566530bdfSJamal Hadi Salim 154677b9900eSJiri Pirko if (key->basic.n_proto == htons(ETH_P_IP) || 154777b9900eSJiri Pirko key->basic.n_proto == htons(ETH_P_IPV6)) { 154877b9900eSJiri Pirko fl_set_key_val(tb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO, 154977b9900eSJiri Pirko &mask->basic.ip_proto, TCA_FLOWER_UNSPEC, 155077b9900eSJiri Pirko sizeof(key->basic.ip_proto)); 15510e2c17b6SOr Gerlitz fl_set_key_ip(tb, false, &key->ip, &mask->ip); 155277b9900eSJiri Pirko } 155366530bdfSJamal Hadi Salim 155466530bdfSJamal Hadi Salim if (tb[TCA_FLOWER_KEY_IPV4_SRC] || tb[TCA_FLOWER_KEY_IPV4_DST]) { 155566530bdfSJamal Hadi Salim key->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; 1556970bfcd0SPaul Blakey mask->control.addr_type = ~0; 155777b9900eSJiri Pirko fl_set_key_val(tb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC, 155877b9900eSJiri Pirko &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK, 155977b9900eSJiri Pirko sizeof(key->ipv4.src)); 156077b9900eSJiri Pirko fl_set_key_val(tb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST, 156177b9900eSJiri Pirko &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK, 156277b9900eSJiri Pirko sizeof(key->ipv4.dst)); 156366530bdfSJamal Hadi Salim } else if (tb[TCA_FLOWER_KEY_IPV6_SRC] || tb[TCA_FLOWER_KEY_IPV6_DST]) { 156466530bdfSJamal Hadi Salim key->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; 1565970bfcd0SPaul Blakey mask->control.addr_type = ~0; 156677b9900eSJiri Pirko fl_set_key_val(tb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC, 156777b9900eSJiri Pirko &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK, 156877b9900eSJiri Pirko sizeof(key->ipv6.src)); 156977b9900eSJiri Pirko fl_set_key_val(tb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST, 157077b9900eSJiri Pirko &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK, 157177b9900eSJiri Pirko sizeof(key->ipv6.dst)); 157277b9900eSJiri Pirko } 157366530bdfSJamal Hadi Salim 157477b9900eSJiri Pirko if (key->basic.ip_proto == IPPROTO_TCP) { 157577b9900eSJiri Pirko fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC, 1576aa72d708SOr Gerlitz &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK, 157777b9900eSJiri Pirko sizeof(key->tp.src)); 157877b9900eSJiri Pirko fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST, 1579aa72d708SOr Gerlitz &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK, 158077b9900eSJiri Pirko sizeof(key->tp.dst)); 1581fdfc7dd6SJiri Pirko fl_set_key_val(tb, &key->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS, 1582fdfc7dd6SJiri Pirko &mask->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS_MASK, 1583fdfc7dd6SJiri Pirko sizeof(key->tcp.flags)); 158477b9900eSJiri Pirko } else if (key->basic.ip_proto == IPPROTO_UDP) { 158577b9900eSJiri Pirko fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC, 1586aa72d708SOr Gerlitz &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK, 158777b9900eSJiri Pirko sizeof(key->tp.src)); 158877b9900eSJiri Pirko fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST, 1589aa72d708SOr Gerlitz &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK, 159077b9900eSJiri Pirko sizeof(key->tp.dst)); 15915976c5f4SSimon Horman } else if (key->basic.ip_proto == IPPROTO_SCTP) { 15925976c5f4SSimon Horman fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC, 15935976c5f4SSimon Horman &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK, 15945976c5f4SSimon Horman sizeof(key->tp.src)); 15955976c5f4SSimon Horman fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST, 15965976c5f4SSimon Horman &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK, 15975976c5f4SSimon Horman sizeof(key->tp.dst)); 15987b684884SSimon Horman } else if (key->basic.n_proto == htons(ETH_P_IP) && 15997b684884SSimon Horman key->basic.ip_proto == IPPROTO_ICMP) { 16007b684884SSimon Horman fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV4_TYPE, 16017b684884SSimon Horman &mask->icmp.type, 16027b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_TYPE_MASK, 16037b684884SSimon Horman sizeof(key->icmp.type)); 16047b684884SSimon Horman fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV4_CODE, 16057b684884SSimon Horman &mask->icmp.code, 16067b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_CODE_MASK, 16077b684884SSimon Horman sizeof(key->icmp.code)); 16087b684884SSimon Horman } else if (key->basic.n_proto == htons(ETH_P_IPV6) && 16097b684884SSimon Horman key->basic.ip_proto == IPPROTO_ICMPV6) { 16107b684884SSimon Horman fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV6_TYPE, 16117b684884SSimon Horman &mask->icmp.type, 16127b684884SSimon Horman TCA_FLOWER_KEY_ICMPV6_TYPE_MASK, 16137b684884SSimon Horman sizeof(key->icmp.type)); 1614040587afSSimon Horman fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV6_CODE, 16157b684884SSimon Horman &mask->icmp.code, 1616040587afSSimon Horman TCA_FLOWER_KEY_ICMPV6_CODE_MASK, 16177b684884SSimon Horman sizeof(key->icmp.code)); 1618a577d8f7SBenjamin LaHaise } else if (key->basic.n_proto == htons(ETH_P_MPLS_UC) || 1619a577d8f7SBenjamin LaHaise key->basic.n_proto == htons(ETH_P_MPLS_MC)) { 1620442f730eSGuillaume Nault ret = fl_set_key_mpls(tb, &key->mpls, &mask->mpls, extack); 16211a7fca63SBenjamin LaHaise if (ret) 16221a7fca63SBenjamin LaHaise return ret; 162399d31326SSimon Horman } else if (key->basic.n_proto == htons(ETH_P_ARP) || 162499d31326SSimon Horman key->basic.n_proto == htons(ETH_P_RARP)) { 162599d31326SSimon Horman fl_set_key_val(tb, &key->arp.sip, TCA_FLOWER_KEY_ARP_SIP, 162699d31326SSimon Horman &mask->arp.sip, TCA_FLOWER_KEY_ARP_SIP_MASK, 162799d31326SSimon Horman sizeof(key->arp.sip)); 162899d31326SSimon Horman fl_set_key_val(tb, &key->arp.tip, TCA_FLOWER_KEY_ARP_TIP, 162999d31326SSimon Horman &mask->arp.tip, TCA_FLOWER_KEY_ARP_TIP_MASK, 163099d31326SSimon Horman sizeof(key->arp.tip)); 163199d31326SSimon Horman fl_set_key_val(tb, &key->arp.op, TCA_FLOWER_KEY_ARP_OP, 163299d31326SSimon Horman &mask->arp.op, TCA_FLOWER_KEY_ARP_OP_MASK, 163399d31326SSimon Horman sizeof(key->arp.op)); 163499d31326SSimon Horman fl_set_key_val(tb, key->arp.sha, TCA_FLOWER_KEY_ARP_SHA, 163599d31326SSimon Horman mask->arp.sha, TCA_FLOWER_KEY_ARP_SHA_MASK, 163699d31326SSimon Horman sizeof(key->arp.sha)); 163799d31326SSimon Horman fl_set_key_val(tb, key->arp.tha, TCA_FLOWER_KEY_ARP_THA, 163899d31326SSimon Horman mask->arp.tha, TCA_FLOWER_KEY_ARP_THA_MASK, 163999d31326SSimon Horman sizeof(key->arp.tha)); 164077b9900eSJiri Pirko } 164177b9900eSJiri Pirko 16425c72299fSAmritha Nambiar if (key->basic.ip_proto == IPPROTO_TCP || 16435c72299fSAmritha Nambiar key->basic.ip_proto == IPPROTO_UDP || 16445c72299fSAmritha Nambiar key->basic.ip_proto == IPPROTO_SCTP) { 1645bd7d4c12SGuillaume Nault ret = fl_set_key_port_range(tb, key, mask, extack); 16465c72299fSAmritha Nambiar if (ret) 16475c72299fSAmritha Nambiar return ret; 16485c72299fSAmritha Nambiar } 16495c72299fSAmritha Nambiar 1650bc3103f1SAmir Vadai if (tb[TCA_FLOWER_KEY_ENC_IPV4_SRC] || 1651bc3103f1SAmir Vadai tb[TCA_FLOWER_KEY_ENC_IPV4_DST]) { 1652bc3103f1SAmir Vadai key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; 1653970bfcd0SPaul Blakey mask->enc_control.addr_type = ~0; 1654bc3103f1SAmir Vadai fl_set_key_val(tb, &key->enc_ipv4.src, 1655bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_SRC, 1656bc3103f1SAmir Vadai &mask->enc_ipv4.src, 1657bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK, 1658bc3103f1SAmir Vadai sizeof(key->enc_ipv4.src)); 1659bc3103f1SAmir Vadai fl_set_key_val(tb, &key->enc_ipv4.dst, 1660bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_DST, 1661bc3103f1SAmir Vadai &mask->enc_ipv4.dst, 1662bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_DST_MASK, 1663bc3103f1SAmir Vadai sizeof(key->enc_ipv4.dst)); 1664bc3103f1SAmir Vadai } 1665bc3103f1SAmir Vadai 1666bc3103f1SAmir Vadai if (tb[TCA_FLOWER_KEY_ENC_IPV6_SRC] || 1667bc3103f1SAmir Vadai tb[TCA_FLOWER_KEY_ENC_IPV6_DST]) { 1668bc3103f1SAmir Vadai key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; 1669970bfcd0SPaul Blakey mask->enc_control.addr_type = ~0; 1670bc3103f1SAmir Vadai fl_set_key_val(tb, &key->enc_ipv6.src, 1671bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_SRC, 1672bc3103f1SAmir Vadai &mask->enc_ipv6.src, 1673bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK, 1674bc3103f1SAmir Vadai sizeof(key->enc_ipv6.src)); 1675bc3103f1SAmir Vadai fl_set_key_val(tb, &key->enc_ipv6.dst, 1676bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_DST, 1677bc3103f1SAmir Vadai &mask->enc_ipv6.dst, 1678bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_DST_MASK, 1679bc3103f1SAmir Vadai sizeof(key->enc_ipv6.dst)); 1680bc3103f1SAmir Vadai } 1681bc3103f1SAmir Vadai 1682bc3103f1SAmir Vadai fl_set_key_val(tb, &key->enc_key_id.keyid, TCA_FLOWER_KEY_ENC_KEY_ID, 1683eb523f42SHadar Hen Zion &mask->enc_key_id.keyid, TCA_FLOWER_UNSPEC, 1684bc3103f1SAmir Vadai sizeof(key->enc_key_id.keyid)); 1685bc3103f1SAmir Vadai 1686f4d997fdSHadar Hen Zion fl_set_key_val(tb, &key->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT, 1687f4d997fdSHadar Hen Zion &mask->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK, 1688f4d997fdSHadar Hen Zion sizeof(key->enc_tp.src)); 1689f4d997fdSHadar Hen Zion 1690f4d997fdSHadar Hen Zion fl_set_key_val(tb, &key->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT, 1691f4d997fdSHadar Hen Zion &mask->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK, 1692f4d997fdSHadar Hen Zion sizeof(key->enc_tp.dst)); 1693f4d997fdSHadar Hen Zion 16940e2c17b6SOr Gerlitz fl_set_key_ip(tb, true, &key->enc_ip, &mask->enc_ip); 16950e2c17b6SOr Gerlitz 16965923b8f7SAriel Levkovich fl_set_key_val(tb, &key->hash.hash, TCA_FLOWER_KEY_HASH, 16975923b8f7SAriel Levkovich &mask->hash.hash, TCA_FLOWER_KEY_HASH_MASK, 16985923b8f7SAriel Levkovich sizeof(key->hash.hash)); 16995923b8f7SAriel Levkovich 17000a6e7778SPieter Jansen van Vuuren if (tb[TCA_FLOWER_KEY_ENC_OPTS]) { 17010a6e7778SPieter Jansen van Vuuren ret = fl_set_enc_opt(tb, key, mask, extack); 17020a6e7778SPieter Jansen van Vuuren if (ret) 17030a6e7778SPieter Jansen van Vuuren return ret; 17040a6e7778SPieter Jansen van Vuuren } 17050a6e7778SPieter Jansen van Vuuren 1706e0ace68aSPaul Blakey ret = fl_set_key_ct(tb, &key->ct, &mask->ct, extack); 1707e0ace68aSPaul Blakey if (ret) 1708e0ace68aSPaul Blakey return ret; 1709e0ace68aSPaul Blakey 1710d9724772SOr Gerlitz if (tb[TCA_FLOWER_KEY_FLAGS]) 1711e304e21aSGuillaume Nault ret = fl_set_key_flags(tb, &key->control.flags, 1712e304e21aSGuillaume Nault &mask->control.flags, extack); 1713faa3ffceSOr Gerlitz 1714d9724772SOr Gerlitz return ret; 171577b9900eSJiri Pirko } 171677b9900eSJiri Pirko 171705cd271fSPaul Blakey static void fl_mask_copy(struct fl_flow_mask *dst, 171805cd271fSPaul Blakey struct fl_flow_mask *src) 171977b9900eSJiri Pirko { 172005cd271fSPaul Blakey const void *psrc = fl_key_get_start(&src->key, src); 172105cd271fSPaul Blakey void *pdst = fl_key_get_start(&dst->key, src); 172277b9900eSJiri Pirko 172305cd271fSPaul Blakey memcpy(pdst, psrc, fl_mask_range(src)); 172405cd271fSPaul Blakey dst->range = src->range; 172577b9900eSJiri Pirko } 172677b9900eSJiri Pirko 172777b9900eSJiri Pirko static const struct rhashtable_params fl_ht_params = { 172877b9900eSJiri Pirko .key_offset = offsetof(struct cls_fl_filter, mkey), /* base offset */ 172977b9900eSJiri Pirko .head_offset = offsetof(struct cls_fl_filter, ht_node), 173077b9900eSJiri Pirko .automatic_shrinking = true, 173177b9900eSJiri Pirko }; 173277b9900eSJiri Pirko 173305cd271fSPaul Blakey static int fl_init_mask_hashtable(struct fl_flow_mask *mask) 173477b9900eSJiri Pirko { 173505cd271fSPaul Blakey mask->filter_ht_params = fl_ht_params; 173605cd271fSPaul Blakey mask->filter_ht_params.key_len = fl_mask_range(mask); 173705cd271fSPaul Blakey mask->filter_ht_params.key_offset += mask->range.start; 173877b9900eSJiri Pirko 173905cd271fSPaul Blakey return rhashtable_init(&mask->ht, &mask->filter_ht_params); 174077b9900eSJiri Pirko } 174177b9900eSJiri Pirko 174277b9900eSJiri Pirko #define FL_KEY_MEMBER_OFFSET(member) offsetof(struct fl_flow_key, member) 1743c593642cSPankaj Bharadiya #define FL_KEY_MEMBER_SIZE(member) sizeof_field(struct fl_flow_key, member) 174477b9900eSJiri Pirko 1745339ba878SHadar Hen Zion #define FL_KEY_IS_MASKED(mask, member) \ 1746339ba878SHadar Hen Zion memchr_inv(((char *)mask) + FL_KEY_MEMBER_OFFSET(member), \ 1747339ba878SHadar Hen Zion 0, FL_KEY_MEMBER_SIZE(member)) \ 174877b9900eSJiri Pirko 174977b9900eSJiri Pirko #define FL_KEY_SET(keys, cnt, id, member) \ 175077b9900eSJiri Pirko do { \ 175177b9900eSJiri Pirko keys[cnt].key_id = id; \ 175277b9900eSJiri Pirko keys[cnt].offset = FL_KEY_MEMBER_OFFSET(member); \ 175377b9900eSJiri Pirko cnt++; \ 175477b9900eSJiri Pirko } while(0); 175577b9900eSJiri Pirko 1756339ba878SHadar Hen Zion #define FL_KEY_SET_IF_MASKED(mask, keys, cnt, id, member) \ 175777b9900eSJiri Pirko do { \ 1758339ba878SHadar Hen Zion if (FL_KEY_IS_MASKED(mask, member)) \ 175977b9900eSJiri Pirko FL_KEY_SET(keys, cnt, id, member); \ 176077b9900eSJiri Pirko } while(0); 176177b9900eSJiri Pirko 176233fb5cbaSJiri Pirko static void fl_init_dissector(struct flow_dissector *dissector, 176333fb5cbaSJiri Pirko struct fl_flow_key *mask) 176477b9900eSJiri Pirko { 176577b9900eSJiri Pirko struct flow_dissector_key keys[FLOW_DISSECTOR_KEY_MAX]; 176677b9900eSJiri Pirko size_t cnt = 0; 176777b9900eSJiri Pirko 17688212ed77SJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 17698212ed77SJiri Pirko FLOW_DISSECTOR_KEY_META, meta); 177042aecaa9STom Herbert FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_CONTROL, control); 177177b9900eSJiri Pirko FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_BASIC, basic); 177233fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 177377b9900eSJiri Pirko FLOW_DISSECTOR_KEY_ETH_ADDRS, eth); 177433fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 177577b9900eSJiri Pirko FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4); 177633fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 177777b9900eSJiri Pirko FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6); 17788ffb055bSYoshiki Komachi FL_KEY_SET_IF_MASKED(mask, keys, cnt, 17798ffb055bSYoshiki Komachi FLOW_DISSECTOR_KEY_PORTS, tp); 17808ffb055bSYoshiki Komachi FL_KEY_SET_IF_MASKED(mask, keys, cnt, 17818ffb055bSYoshiki Komachi FLOW_DISSECTOR_KEY_PORTS_RANGE, tp_range); 178233fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 17834d80cc0aSOr Gerlitz FLOW_DISSECTOR_KEY_IP, ip); 178433fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 1785fdfc7dd6SJiri Pirko FLOW_DISSECTOR_KEY_TCP, tcp); 178633fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 17877b684884SSimon Horman FLOW_DISSECTOR_KEY_ICMP, icmp); 178833fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 178999d31326SSimon Horman FLOW_DISSECTOR_KEY_ARP, arp); 179033fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 1791a577d8f7SBenjamin LaHaise FLOW_DISSECTOR_KEY_MPLS, mpls); 179233fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 17939399ae9aSHadar Hen Zion FLOW_DISSECTOR_KEY_VLAN, vlan); 179433fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 1795d64efd09SJianbo Liu FLOW_DISSECTOR_KEY_CVLAN, cvlan); 179633fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 1797519d1052SHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_KEYID, enc_key_id); 179833fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 1799519d1052SHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, enc_ipv4); 180033fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 1801519d1052SHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, enc_ipv6); 180233fb5cbaSJiri Pirko if (FL_KEY_IS_MASKED(mask, enc_ipv4) || 180333fb5cbaSJiri Pirko FL_KEY_IS_MASKED(mask, enc_ipv6)) 1804519d1052SHadar Hen Zion FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_ENC_CONTROL, 1805519d1052SHadar Hen Zion enc_control); 180633fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 1807f4d997fdSHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_PORTS, enc_tp); 180833fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 18090e2c17b6SOr Gerlitz FLOW_DISSECTOR_KEY_ENC_IP, enc_ip); 18100a6e7778SPieter Jansen van Vuuren FL_KEY_SET_IF_MASKED(mask, keys, cnt, 18110a6e7778SPieter Jansen van Vuuren FLOW_DISSECTOR_KEY_ENC_OPTS, enc_opts); 1812e0ace68aSPaul Blakey FL_KEY_SET_IF_MASKED(mask, keys, cnt, 1813e0ace68aSPaul Blakey FLOW_DISSECTOR_KEY_CT, ct); 18145923b8f7SAriel Levkovich FL_KEY_SET_IF_MASKED(mask, keys, cnt, 18155923b8f7SAriel Levkovich FLOW_DISSECTOR_KEY_HASH, hash); 181677b9900eSJiri Pirko 181733fb5cbaSJiri Pirko skb_flow_dissector_init(dissector, keys, cnt); 181805cd271fSPaul Blakey } 181905cd271fSPaul Blakey 182005cd271fSPaul Blakey static struct fl_flow_mask *fl_create_new_mask(struct cls_fl_head *head, 182105cd271fSPaul Blakey struct fl_flow_mask *mask) 182205cd271fSPaul Blakey { 182305cd271fSPaul Blakey struct fl_flow_mask *newmask; 182405cd271fSPaul Blakey int err; 182505cd271fSPaul Blakey 182605cd271fSPaul Blakey newmask = kzalloc(sizeof(*newmask), GFP_KERNEL); 182705cd271fSPaul Blakey if (!newmask) 182805cd271fSPaul Blakey return ERR_PTR(-ENOMEM); 182905cd271fSPaul Blakey 183005cd271fSPaul Blakey fl_mask_copy(newmask, mask); 183105cd271fSPaul Blakey 18328ffb055bSYoshiki Komachi if ((newmask->key.tp_range.tp_min.dst && 18338ffb055bSYoshiki Komachi newmask->key.tp_range.tp_max.dst) || 18348ffb055bSYoshiki Komachi (newmask->key.tp_range.tp_min.src && 18358ffb055bSYoshiki Komachi newmask->key.tp_range.tp_max.src)) 18365c72299fSAmritha Nambiar newmask->flags |= TCA_FLOWER_MASK_FLAGS_RANGE; 18375c72299fSAmritha Nambiar 183805cd271fSPaul Blakey err = fl_init_mask_hashtable(newmask); 183905cd271fSPaul Blakey if (err) 184005cd271fSPaul Blakey goto errout_free; 184105cd271fSPaul Blakey 184233fb5cbaSJiri Pirko fl_init_dissector(&newmask->dissector, &newmask->key); 184305cd271fSPaul Blakey 184405cd271fSPaul Blakey INIT_LIST_HEAD_RCU(&newmask->filters); 184505cd271fSPaul Blakey 1846f48ef4d5SVlad Buslov refcount_set(&newmask->refcnt, 1); 1847195c234dSVlad Buslov err = rhashtable_replace_fast(&head->ht, &mask->ht_node, 1848195c234dSVlad Buslov &newmask->ht_node, mask_ht_params); 184905cd271fSPaul Blakey if (err) 185005cd271fSPaul Blakey goto errout_destroy; 185105cd271fSPaul Blakey 1852259e60f9SVlad Buslov spin_lock(&head->masks_lock); 185305cd271fSPaul Blakey list_add_tail_rcu(&newmask->list, &head->masks); 1854259e60f9SVlad Buslov spin_unlock(&head->masks_lock); 185505cd271fSPaul Blakey 185605cd271fSPaul Blakey return newmask; 185705cd271fSPaul Blakey 185805cd271fSPaul Blakey errout_destroy: 185905cd271fSPaul Blakey rhashtable_destroy(&newmask->ht); 186005cd271fSPaul Blakey errout_free: 186105cd271fSPaul Blakey kfree(newmask); 186205cd271fSPaul Blakey 186305cd271fSPaul Blakey return ERR_PTR(err); 186477b9900eSJiri Pirko } 186577b9900eSJiri Pirko 186677b9900eSJiri Pirko static int fl_check_assign_mask(struct cls_fl_head *head, 186705cd271fSPaul Blakey struct cls_fl_filter *fnew, 186805cd271fSPaul Blakey struct cls_fl_filter *fold, 186977b9900eSJiri Pirko struct fl_flow_mask *mask) 187077b9900eSJiri Pirko { 187105cd271fSPaul Blakey struct fl_flow_mask *newmask; 1872f48ef4d5SVlad Buslov int ret = 0; 187377b9900eSJiri Pirko 1874f48ef4d5SVlad Buslov rcu_read_lock(); 1875195c234dSVlad Buslov 1876195c234dSVlad Buslov /* Insert mask as temporary node to prevent concurrent creation of mask 1877195c234dSVlad Buslov * with same key. Any concurrent lookups with same key will return 187899815f50SVlad Buslov * -EAGAIN because mask's refcnt is zero. 1879195c234dSVlad Buslov */ 1880195c234dSVlad Buslov fnew->mask = rhashtable_lookup_get_insert_fast(&head->ht, 1881195c234dSVlad Buslov &mask->ht_node, 1882195c234dSVlad Buslov mask_ht_params); 188305cd271fSPaul Blakey if (!fnew->mask) { 1884f48ef4d5SVlad Buslov rcu_read_unlock(); 1885f48ef4d5SVlad Buslov 1886195c234dSVlad Buslov if (fold) { 1887195c234dSVlad Buslov ret = -EINVAL; 1888195c234dSVlad Buslov goto errout_cleanup; 1889195c234dSVlad Buslov } 189005cd271fSPaul Blakey 189105cd271fSPaul Blakey newmask = fl_create_new_mask(head, mask); 1892195c234dSVlad Buslov if (IS_ERR(newmask)) { 1893195c234dSVlad Buslov ret = PTR_ERR(newmask); 1894195c234dSVlad Buslov goto errout_cleanup; 1895195c234dSVlad Buslov } 189605cd271fSPaul Blakey 189705cd271fSPaul Blakey fnew->mask = newmask; 189877b9900eSJiri Pirko return 0; 1899195c234dSVlad Buslov } else if (IS_ERR(fnew->mask)) { 1900195c234dSVlad Buslov ret = PTR_ERR(fnew->mask); 1901f48ef4d5SVlad Buslov } else if (fold && fold->mask != fnew->mask) { 1902f48ef4d5SVlad Buslov ret = -EINVAL; 1903f48ef4d5SVlad Buslov } else if (!refcount_inc_not_zero(&fnew->mask->refcnt)) { 1904f48ef4d5SVlad Buslov /* Mask was deleted concurrently, try again */ 1905f48ef4d5SVlad Buslov ret = -EAGAIN; 1906f48ef4d5SVlad Buslov } 1907f48ef4d5SVlad Buslov rcu_read_unlock(); 1908f48ef4d5SVlad Buslov return ret; 1909195c234dSVlad Buslov 1910195c234dSVlad Buslov errout_cleanup: 1911195c234dSVlad Buslov rhashtable_remove_fast(&head->ht, &mask->ht_node, 1912195c234dSVlad Buslov mask_ht_params); 1913195c234dSVlad Buslov return ret; 191477b9900eSJiri Pirko } 191577b9900eSJiri Pirko 191677b9900eSJiri Pirko static int fl_set_parms(struct net *net, struct tcf_proto *tp, 191777b9900eSJiri Pirko struct cls_fl_filter *f, struct fl_flow_mask *mask, 191877b9900eSJiri Pirko unsigned long base, struct nlattr **tb, 1919695176bfSCong Wang struct nlattr *est, 1920695176bfSCong Wang struct fl_flow_tmplt *tmplt, u32 flags, 192150a56190SAlexander Aring struct netlink_ext_ack *extack) 192277b9900eSJiri Pirko { 192377b9900eSJiri Pirko int err; 192477b9900eSJiri Pirko 1925695176bfSCong Wang err = tcf_exts_validate(net, tp, tb, est, &f->exts, flags, 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]); 1931695176bfSCong Wang if (flags & TCA_ACT_FLAGS_NO_RTNL) 1932c24e43d8SVlad Buslov rtnl_lock(); 193377b9900eSJiri Pirko tcf_bind_filter(tp, &f->res, base); 1934695176bfSCong Wang if (flags & TCA_ACT_FLAGS_NO_RTNL) 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, 1978695176bfSCong Wang void **arg, u32 flags, 197912db03b6SVlad Buslov struct netlink_ext_ack *extack) 198077b9900eSJiri Pirko { 1981e474619aSVlad Buslov struct cls_fl_head *head = fl_head_dereference(tp); 1982695176bfSCong Wang bool rtnl_held = !(flags & TCA_ACT_FLAGS_NO_RTNL); 19838113c095SWANG Cong struct cls_fl_filter *fold = *arg; 198477b9900eSJiri Pirko struct cls_fl_filter *fnew; 19852cddd201SIvan Vecera struct fl_flow_mask *mask; 198639b7b6a6SArnd Bergmann struct nlattr **tb; 19871f17f774SVlad Buslov bool in_ht; 198877b9900eSJiri Pirko int err; 198977b9900eSJiri Pirko 199006177558SVlad Buslov if (!tca[TCA_OPTIONS]) { 199106177558SVlad Buslov err = -EINVAL; 199206177558SVlad Buslov goto errout_fold; 199306177558SVlad Buslov } 199477b9900eSJiri Pirko 19952cddd201SIvan Vecera mask = kzalloc(sizeof(struct fl_flow_mask), GFP_KERNEL); 199606177558SVlad Buslov if (!mask) { 199706177558SVlad Buslov err = -ENOBUFS; 199806177558SVlad Buslov goto errout_fold; 199906177558SVlad Buslov } 200039b7b6a6SArnd Bergmann 20012cddd201SIvan Vecera tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL); 20022cddd201SIvan Vecera if (!tb) { 20032cddd201SIvan Vecera err = -ENOBUFS; 20042cddd201SIvan Vecera goto errout_mask_alloc; 20052cddd201SIvan Vecera } 20062cddd201SIvan Vecera 20078cb08174SJohannes Berg err = nla_parse_nested_deprecated(tb, TCA_FLOWER_MAX, 20088cb08174SJohannes Berg tca[TCA_OPTIONS], fl_policy, NULL); 200977b9900eSJiri Pirko if (err < 0) 201039b7b6a6SArnd Bergmann goto errout_tb; 201177b9900eSJiri Pirko 201239b7b6a6SArnd Bergmann if (fold && handle && fold->handle != handle) { 201339b7b6a6SArnd Bergmann err = -EINVAL; 201439b7b6a6SArnd Bergmann goto errout_tb; 201539b7b6a6SArnd Bergmann } 201677b9900eSJiri Pirko 201777b9900eSJiri Pirko fnew = kzalloc(sizeof(*fnew), GFP_KERNEL); 201839b7b6a6SArnd Bergmann if (!fnew) { 201939b7b6a6SArnd Bergmann err = -ENOBUFS; 202039b7b6a6SArnd Bergmann goto errout_tb; 202139b7b6a6SArnd Bergmann } 2022c049d56eSVlad Buslov INIT_LIST_HEAD(&fnew->hw_list); 202306177558SVlad Buslov refcount_set(&fnew->refcnt, 1); 202477b9900eSJiri Pirko 202514215108SCong Wang err = tcf_exts_init(&fnew->exts, net, TCA_FLOWER_ACT, 0); 2026b9a24bb7SWANG Cong if (err < 0) 2027b9a24bb7SWANG Cong goto errout; 202877b9900eSJiri Pirko 2029ecb3dea4SVlad Buslov if (tb[TCA_FLOWER_FLAGS]) { 2030ecb3dea4SVlad Buslov fnew->flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]); 2031ecb3dea4SVlad Buslov 2032ecb3dea4SVlad Buslov if (!tc_flags_valid(fnew->flags)) { 2033ecb3dea4SVlad Buslov err = -EINVAL; 2034ecb3dea4SVlad Buslov goto errout; 2035ecb3dea4SVlad Buslov } 2036ecb3dea4SVlad Buslov } 2037ecb3dea4SVlad Buslov 2038695176bfSCong Wang err = fl_set_parms(net, tp, fnew, mask, base, tb, tca[TCA_RATE], 2039695176bfSCong Wang tp->chain->tmplt_priv, flags, extack); 2040ecb3dea4SVlad Buslov if (err) 2041ecb3dea4SVlad Buslov goto errout; 2042ecb3dea4SVlad Buslov 2043ecb3dea4SVlad Buslov err = fl_check_assign_mask(head, fnew, fold, mask); 2044ecb3dea4SVlad Buslov if (err) 2045ecb3dea4SVlad Buslov goto errout; 2046ecb3dea4SVlad Buslov 20471f17f774SVlad Buslov err = fl_ht_insert_unique(fnew, fold, &in_ht); 20481f17f774SVlad Buslov if (err) 20491f17f774SVlad Buslov goto errout_mask; 20501f17f774SVlad Buslov 205179685219SHadar Hen Zion if (!tc_skip_hw(fnew->flags)) { 2052c24e43d8SVlad Buslov err = fl_hw_replace_filter(tp, fnew, rtnl_held, extack); 2053e8eb36cdSAmir Vadai if (err) 20541f17f774SVlad Buslov goto errout_ht; 205579685219SHadar Hen Zion } 20565b33f488SAmir Vadai 205755593960SOr Gerlitz if (!tc_in_hw(fnew->flags)) 205855593960SOr Gerlitz fnew->flags |= TCA_CLS_FLAGS_NOT_IN_HW; 205955593960SOr Gerlitz 20603d81e711SVlad Buslov spin_lock(&tp->lock); 20613d81e711SVlad Buslov 2062272ffaadSVlad Buslov /* tp was deleted concurrently. -EAGAIN will cause caller to lookup 2063272ffaadSVlad Buslov * proto again or create new one, if necessary. 2064272ffaadSVlad Buslov */ 2065272ffaadSVlad Buslov if (tp->deleting) { 2066272ffaadSVlad Buslov err = -EAGAIN; 2067272ffaadSVlad Buslov goto errout_hw; 2068272ffaadSVlad Buslov } 2069272ffaadSVlad Buslov 20705b33f488SAmir Vadai if (fold) { 2071b2552b8cSVlad Buslov /* Fold filter was deleted concurrently. Retry lookup. */ 2072b2552b8cSVlad Buslov if (fold->deleted) { 2073b2552b8cSVlad Buslov err = -EAGAIN; 2074b2552b8cSVlad Buslov goto errout_hw; 2075b2552b8cSVlad Buslov } 2076b2552b8cSVlad Buslov 2077620da486SVlad Buslov fnew->handle = handle; 2078620da486SVlad Buslov 20791f17f774SVlad Buslov if (!in_ht) { 20801f17f774SVlad Buslov struct rhashtable_params params = 20811f17f774SVlad Buslov fnew->mask->filter_ht_params; 20821f17f774SVlad Buslov 20831f17f774SVlad Buslov err = rhashtable_insert_fast(&fnew->mask->ht, 20841f17f774SVlad Buslov &fnew->ht_node, 20851f17f774SVlad Buslov params); 2086620da486SVlad Buslov if (err) 2087620da486SVlad Buslov goto errout_hw; 20881f17f774SVlad Buslov in_ht = true; 20891f17f774SVlad Buslov } 2090620da486SVlad Buslov 2091c049d56eSVlad Buslov refcount_inc(&fnew->refcnt); 209205cd271fSPaul Blakey rhashtable_remove_fast(&fold->mask->ht, 209305cd271fSPaul Blakey &fold->ht_node, 209405cd271fSPaul Blakey fold->mask->filter_ht_params); 2095234a4624SMatthew Wilcox idr_replace(&head->handle_idr, fnew, fnew->handle); 2096ff3532f2SDaniel Borkmann list_replace_rcu(&fold->list, &fnew->list); 2097b2552b8cSVlad Buslov fold->deleted = true; 2098620da486SVlad Buslov 20993d81e711SVlad Buslov spin_unlock(&tp->lock); 21003d81e711SVlad Buslov 21019994677cSVlad Buslov fl_mask_put(head, fold->mask); 2102620da486SVlad Buslov if (!tc_skip_hw(fold->flags)) 2103c24e43d8SVlad Buslov fl_hw_destroy_filter(tp, fold, rtnl_held, NULL); 210477b9900eSJiri Pirko tcf_unbind_filter(tp, &fold->res); 210506177558SVlad Buslov /* Caller holds reference to fold, so refcnt is always > 0 210606177558SVlad Buslov * after this. 210706177558SVlad Buslov */ 210806177558SVlad Buslov refcount_dec(&fold->refcnt); 210906177558SVlad Buslov __fl_put(fold); 211077b9900eSJiri Pirko } else { 2111620da486SVlad Buslov if (handle) { 2112620da486SVlad Buslov /* user specifies a handle and it doesn't exist */ 2113620da486SVlad Buslov err = idr_alloc_u32(&head->handle_idr, fnew, &handle, 2114620da486SVlad Buslov handle, GFP_ATOMIC); 21159a2d9389SVlad Buslov 21169a2d9389SVlad Buslov /* Filter with specified handle was concurrently 21179a2d9389SVlad Buslov * inserted after initial check in cls_api. This is not 21189a2d9389SVlad Buslov * necessarily an error if NLM_F_EXCL is not set in 21199a2d9389SVlad Buslov * message flags. Returning EAGAIN will cause cls_api to 21209a2d9389SVlad Buslov * try to update concurrently inserted rule. 21219a2d9389SVlad Buslov */ 21229a2d9389SVlad Buslov if (err == -ENOSPC) 21239a2d9389SVlad Buslov err = -EAGAIN; 2124620da486SVlad Buslov } else { 2125620da486SVlad Buslov handle = 1; 2126620da486SVlad Buslov err = idr_alloc_u32(&head->handle_idr, fnew, &handle, 2127620da486SVlad Buslov INT_MAX, GFP_ATOMIC); 2128620da486SVlad Buslov } 2129620da486SVlad Buslov if (err) 2130620da486SVlad Buslov goto errout_hw; 2131620da486SVlad Buslov 2132c049d56eSVlad Buslov refcount_inc(&fnew->refcnt); 2133620da486SVlad Buslov fnew->handle = handle; 213405cd271fSPaul Blakey list_add_tail_rcu(&fnew->list, &fnew->mask->filters); 21353d81e711SVlad Buslov spin_unlock(&tp->lock); 213677b9900eSJiri Pirko } 213777b9900eSJiri Pirko 2138620da486SVlad Buslov *arg = fnew; 2139620da486SVlad Buslov 214039b7b6a6SArnd Bergmann kfree(tb); 214199815f50SVlad Buslov tcf_queue_work(&mask->rwork, fl_uninit_mask_free_work); 214277b9900eSJiri Pirko return 0; 214377b9900eSJiri Pirko 2144c049d56eSVlad Buslov errout_ht: 2145c049d56eSVlad Buslov spin_lock(&tp->lock); 2146620da486SVlad Buslov errout_hw: 2147c049d56eSVlad Buslov fnew->deleted = true; 21483d81e711SVlad Buslov spin_unlock(&tp->lock); 2149620da486SVlad Buslov if (!tc_skip_hw(fnew->flags)) 2150c24e43d8SVlad Buslov fl_hw_destroy_filter(tp, fnew, rtnl_held, NULL); 21511f17f774SVlad Buslov if (in_ht) 21521f17f774SVlad Buslov rhashtable_remove_fast(&fnew->mask->ht, &fnew->ht_node, 21531f17f774SVlad Buslov fnew->mask->filter_ht_params); 2154ecb3dea4SVlad Buslov errout_mask: 21559994677cSVlad Buslov fl_mask_put(head, fnew->mask); 215677b9900eSJiri Pirko errout: 2157c049d56eSVlad Buslov __fl_put(fnew); 215839b7b6a6SArnd Bergmann errout_tb: 215939b7b6a6SArnd Bergmann kfree(tb); 21602cddd201SIvan Vecera errout_mask_alloc: 216199815f50SVlad Buslov tcf_queue_work(&mask->rwork, fl_uninit_mask_free_work); 216206177558SVlad Buslov errout_fold: 216306177558SVlad Buslov if (fold) 216406177558SVlad Buslov __fl_put(fold); 216577b9900eSJiri Pirko return err; 216677b9900eSJiri Pirko } 216777b9900eSJiri Pirko 2168571acf21SAlexander Aring static int fl_delete(struct tcf_proto *tp, void *arg, bool *last, 216912db03b6SVlad Buslov bool rtnl_held, struct netlink_ext_ack *extack) 217077b9900eSJiri Pirko { 2171e474619aSVlad Buslov struct cls_fl_head *head = fl_head_dereference(tp); 21728113c095SWANG Cong struct cls_fl_filter *f = arg; 2173b2552b8cSVlad Buslov bool last_on_mask; 2174b2552b8cSVlad Buslov int err = 0; 217577b9900eSJiri Pirko 2176c24e43d8SVlad Buslov err = __fl_delete(tp, f, &last_on_mask, rtnl_held, extack); 217705cd271fSPaul Blakey *last = list_empty(&head->masks); 217806177558SVlad Buslov __fl_put(f); 217906177558SVlad Buslov 2180b2552b8cSVlad Buslov return err; 218177b9900eSJiri Pirko } 218277b9900eSJiri Pirko 218312db03b6SVlad Buslov static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg, 218412db03b6SVlad Buslov bool rtnl_held) 218577b9900eSJiri Pirko { 2186d39d7149SCong Wang struct cls_fl_head *head = fl_head_dereference(tp); 2187d39d7149SCong Wang unsigned long id = arg->cookie, tmp; 218877b9900eSJiri Pirko struct cls_fl_filter *f; 218977b9900eSJiri Pirko 219001683a14SVlad Buslov arg->count = arg->skip; 219101683a14SVlad Buslov 2192d5ef1906SVlad Buslov rcu_read_lock(); 2193d39d7149SCong Wang idr_for_each_entry_continue_ul(&head->handle_idr, f, tmp, id) { 2194d39d7149SCong Wang /* don't return filters that are being deleted */ 2195d39d7149SCong Wang if (!refcount_inc_not_zero(&f->refcnt)) 2196d39d7149SCong Wang continue; 2197d5ef1906SVlad Buslov rcu_read_unlock(); 2198d5ef1906SVlad Buslov 21998113c095SWANG Cong if (arg->fn(tp, f, arg) < 0) { 220006177558SVlad Buslov __fl_put(f); 220177b9900eSJiri Pirko arg->stop = 1; 2202d5ef1906SVlad Buslov rcu_read_lock(); 220377b9900eSJiri Pirko break; 220477b9900eSJiri Pirko } 220506177558SVlad Buslov __fl_put(f); 220677b9900eSJiri Pirko arg->count++; 2207d5ef1906SVlad Buslov rcu_read_lock(); 220877b9900eSJiri Pirko } 2209d5ef1906SVlad Buslov rcu_read_unlock(); 2210d39d7149SCong Wang arg->cookie = id; 221177b9900eSJiri Pirko } 221277b9900eSJiri Pirko 2213c049d56eSVlad Buslov static struct cls_fl_filter * 2214c049d56eSVlad Buslov fl_get_next_hw_filter(struct tcf_proto *tp, struct cls_fl_filter *f, bool add) 2215c049d56eSVlad Buslov { 2216c049d56eSVlad Buslov struct cls_fl_head *head = fl_head_dereference(tp); 2217c049d56eSVlad Buslov 2218c049d56eSVlad Buslov spin_lock(&tp->lock); 2219c049d56eSVlad Buslov if (list_empty(&head->hw_filters)) { 2220c049d56eSVlad Buslov spin_unlock(&tp->lock); 2221c049d56eSVlad Buslov return NULL; 2222c049d56eSVlad Buslov } 2223c049d56eSVlad Buslov 2224c049d56eSVlad Buslov if (!f) 2225c049d56eSVlad Buslov f = list_entry(&head->hw_filters, struct cls_fl_filter, 2226c049d56eSVlad Buslov hw_list); 2227c049d56eSVlad Buslov list_for_each_entry_continue(f, &head->hw_filters, hw_list) { 2228c049d56eSVlad Buslov if (!(add && f->deleted) && refcount_inc_not_zero(&f->refcnt)) { 2229c049d56eSVlad Buslov spin_unlock(&tp->lock); 2230c049d56eSVlad Buslov return f; 2231c049d56eSVlad Buslov } 2232c049d56eSVlad Buslov } 2233c049d56eSVlad Buslov 2234c049d56eSVlad Buslov spin_unlock(&tp->lock); 2235c049d56eSVlad Buslov return NULL; 2236c049d56eSVlad Buslov } 2237c049d56eSVlad Buslov 2238a7323311SPablo Neira Ayuso static int fl_reoffload(struct tcf_proto *tp, bool add, flow_setup_cb_t *cb, 223931533cbaSJohn Hurley void *cb_priv, struct netlink_ext_ack *extack) 224031533cbaSJohn Hurley { 224131533cbaSJohn Hurley struct tcf_block *block = tp->chain->block; 2242f9e30088SPablo Neira Ayuso struct flow_cls_offload cls_flower = {}; 2243c049d56eSVlad Buslov struct cls_fl_filter *f = NULL; 224431533cbaSJohn Hurley int err; 224531533cbaSJohn Hurley 2246c049d56eSVlad Buslov /* hw_filters list can only be changed by hw offload functions after 2247c049d56eSVlad Buslov * obtaining rtnl lock. Make sure it is not changed while reoffload is 2248c049d56eSVlad Buslov * iterating it. 2249c049d56eSVlad Buslov */ 2250c049d56eSVlad Buslov ASSERT_RTNL(); 225131533cbaSJohn Hurley 2252c049d56eSVlad Buslov while ((f = fl_get_next_hw_filter(tp, f, add))) { 2253e3ab786bSPablo Neira Ayuso cls_flower.rule = 2254e3ab786bSPablo Neira Ayuso flow_rule_alloc(tcf_exts_num_actions(&f->exts)); 225595e27a4dSJohn Hurley if (!cls_flower.rule) { 225695e27a4dSJohn Hurley __fl_put(f); 22578f256622SPablo Neira Ayuso return -ENOMEM; 225895e27a4dSJohn Hurley } 22598f256622SPablo Neira Ayuso 226095e27a4dSJohn Hurley tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, 2261d6787147SPieter Jansen van Vuuren extack); 226231533cbaSJohn Hurley cls_flower.command = add ? 2263f9e30088SPablo Neira Ayuso FLOW_CLS_REPLACE : FLOW_CLS_DESTROY; 226431533cbaSJohn Hurley cls_flower.cookie = (unsigned long)f; 226595e27a4dSJohn Hurley cls_flower.rule->match.dissector = &f->mask->dissector; 226695e27a4dSJohn Hurley cls_flower.rule->match.mask = &f->mask->key; 22678f256622SPablo Neira Ayuso cls_flower.rule->match.key = &f->mkey; 22683a7b6861SPablo Neira Ayuso 2269b15e7a6eSVlad Buslov err = tc_setup_flow_action(&cls_flower.rule->action, &f->exts); 22703a7b6861SPablo Neira Ayuso if (err) { 22713a7b6861SPablo Neira Ayuso kfree(cls_flower.rule); 22721f15bb4fSVlad Buslov if (tc_skip_sw(f->flags)) { 22731f15bb4fSVlad Buslov NL_SET_ERR_MSG_MOD(extack, "Failed to setup flow action"); 227495e27a4dSJohn Hurley __fl_put(f); 22753a7b6861SPablo Neira Ayuso return err; 22763a7b6861SPablo Neira Ayuso } 227795e27a4dSJohn Hurley goto next_flow; 22781f15bb4fSVlad Buslov } 22793a7b6861SPablo Neira Ayuso 228031533cbaSJohn Hurley cls_flower.classid = f->res.classid; 228131533cbaSJohn Hurley 228240119211SVlad Buslov err = tc_setup_cb_reoffload(block, tp, add, cb, 228340119211SVlad Buslov TC_SETUP_CLSFLOWER, &cls_flower, 228440119211SVlad Buslov cb_priv, &f->flags, 228540119211SVlad Buslov &f->in_hw_count); 22865a6ff4b1SVlad Buslov tc_cleanup_flow_action(&cls_flower.rule->action); 22878f256622SPablo Neira Ayuso kfree(cls_flower.rule); 22888f256622SPablo Neira Ayuso 228931533cbaSJohn Hurley if (err) { 229095e27a4dSJohn Hurley __fl_put(f); 229131533cbaSJohn Hurley return err; 229295e27a4dSJohn Hurley } 229395e27a4dSJohn Hurley next_flow: 229495e27a4dSJohn Hurley __fl_put(f); 229531533cbaSJohn Hurley } 229631533cbaSJohn Hurley 229731533cbaSJohn Hurley return 0; 229831533cbaSJohn Hurley } 229931533cbaSJohn Hurley 2300a449a3e7SVlad Buslov static void fl_hw_add(struct tcf_proto *tp, void *type_data) 2301a449a3e7SVlad Buslov { 2302a449a3e7SVlad Buslov struct flow_cls_offload *cls_flower = type_data; 2303a449a3e7SVlad Buslov struct cls_fl_filter *f = 2304a449a3e7SVlad Buslov (struct cls_fl_filter *) cls_flower->cookie; 2305a449a3e7SVlad Buslov struct cls_fl_head *head = fl_head_dereference(tp); 2306a449a3e7SVlad Buslov 2307a449a3e7SVlad Buslov spin_lock(&tp->lock); 2308a449a3e7SVlad Buslov list_add(&f->hw_list, &head->hw_filters); 2309a449a3e7SVlad Buslov spin_unlock(&tp->lock); 2310a449a3e7SVlad Buslov } 2311a449a3e7SVlad Buslov 2312a449a3e7SVlad Buslov static void fl_hw_del(struct tcf_proto *tp, void *type_data) 2313a449a3e7SVlad Buslov { 2314a449a3e7SVlad Buslov struct flow_cls_offload *cls_flower = type_data; 2315a449a3e7SVlad Buslov struct cls_fl_filter *f = 2316a449a3e7SVlad Buslov (struct cls_fl_filter *) cls_flower->cookie; 2317a449a3e7SVlad Buslov 2318a449a3e7SVlad Buslov spin_lock(&tp->lock); 2319a449a3e7SVlad Buslov if (!list_empty(&f->hw_list)) 2320a449a3e7SVlad Buslov list_del_init(&f->hw_list); 2321a449a3e7SVlad Buslov spin_unlock(&tp->lock); 2322a449a3e7SVlad Buslov } 2323a449a3e7SVlad Buslov 23248f256622SPablo Neira Ayuso static int fl_hw_create_tmplt(struct tcf_chain *chain, 232534738452SJiri Pirko struct fl_flow_tmplt *tmplt) 232634738452SJiri Pirko { 2327f9e30088SPablo Neira Ayuso struct flow_cls_offload cls_flower = {}; 232834738452SJiri Pirko struct tcf_block *block = chain->block; 232934738452SJiri Pirko 2330e3ab786bSPablo Neira Ayuso cls_flower.rule = flow_rule_alloc(0); 23318f256622SPablo Neira Ayuso if (!cls_flower.rule) 23328f256622SPablo Neira Ayuso return -ENOMEM; 23338f256622SPablo Neira Ayuso 233434738452SJiri Pirko cls_flower.common.chain_index = chain->index; 2335f9e30088SPablo Neira Ayuso cls_flower.command = FLOW_CLS_TMPLT_CREATE; 233634738452SJiri Pirko cls_flower.cookie = (unsigned long) tmplt; 23378f256622SPablo Neira Ayuso cls_flower.rule->match.dissector = &tmplt->dissector; 23388f256622SPablo Neira Ayuso cls_flower.rule->match.mask = &tmplt->mask; 23398f256622SPablo Neira Ayuso cls_flower.rule->match.key = &tmplt->dummy_key; 234034738452SJiri Pirko 234134738452SJiri Pirko /* We don't care if driver (any of them) fails to handle this 234234738452SJiri Pirko * call. It serves just as a hint for it. 234334738452SJiri Pirko */ 234440119211SVlad Buslov tc_setup_cb_call(block, TC_SETUP_CLSFLOWER, &cls_flower, false, true); 23458f256622SPablo Neira Ayuso kfree(cls_flower.rule); 23468f256622SPablo Neira Ayuso 23478f256622SPablo Neira Ayuso return 0; 234834738452SJiri Pirko } 234934738452SJiri Pirko 235034738452SJiri Pirko static void fl_hw_destroy_tmplt(struct tcf_chain *chain, 235134738452SJiri Pirko struct fl_flow_tmplt *tmplt) 235234738452SJiri Pirko { 2353f9e30088SPablo Neira Ayuso struct flow_cls_offload cls_flower = {}; 235434738452SJiri Pirko struct tcf_block *block = chain->block; 235534738452SJiri Pirko 235634738452SJiri Pirko cls_flower.common.chain_index = chain->index; 2357f9e30088SPablo Neira Ayuso cls_flower.command = FLOW_CLS_TMPLT_DESTROY; 235834738452SJiri Pirko cls_flower.cookie = (unsigned long) tmplt; 235934738452SJiri Pirko 236040119211SVlad Buslov tc_setup_cb_call(block, TC_SETUP_CLSFLOWER, &cls_flower, false, true); 236134738452SJiri Pirko } 236234738452SJiri Pirko 2363b95ec7ebSJiri Pirko static void *fl_tmplt_create(struct net *net, struct tcf_chain *chain, 2364b95ec7ebSJiri Pirko struct nlattr **tca, 2365b95ec7ebSJiri Pirko struct netlink_ext_ack *extack) 2366b95ec7ebSJiri Pirko { 2367b95ec7ebSJiri Pirko struct fl_flow_tmplt *tmplt; 2368b95ec7ebSJiri Pirko struct nlattr **tb; 2369b95ec7ebSJiri Pirko int err; 2370b95ec7ebSJiri Pirko 2371b95ec7ebSJiri Pirko if (!tca[TCA_OPTIONS]) 2372b95ec7ebSJiri Pirko return ERR_PTR(-EINVAL); 2373b95ec7ebSJiri Pirko 2374b95ec7ebSJiri Pirko tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL); 2375b95ec7ebSJiri Pirko if (!tb) 2376b95ec7ebSJiri Pirko return ERR_PTR(-ENOBUFS); 23778cb08174SJohannes Berg err = nla_parse_nested_deprecated(tb, TCA_FLOWER_MAX, 23788cb08174SJohannes Berg tca[TCA_OPTIONS], fl_policy, NULL); 2379b95ec7ebSJiri Pirko if (err) 2380b95ec7ebSJiri Pirko goto errout_tb; 2381b95ec7ebSJiri Pirko 2382b95ec7ebSJiri Pirko tmplt = kzalloc(sizeof(*tmplt), GFP_KERNEL); 23831cbc36a5SDan Carpenter if (!tmplt) { 23841cbc36a5SDan Carpenter err = -ENOMEM; 2385b95ec7ebSJiri Pirko goto errout_tb; 23861cbc36a5SDan Carpenter } 2387b95ec7ebSJiri Pirko tmplt->chain = chain; 2388b95ec7ebSJiri Pirko err = fl_set_key(net, tb, &tmplt->dummy_key, &tmplt->mask, extack); 2389b95ec7ebSJiri Pirko if (err) 2390b95ec7ebSJiri Pirko goto errout_tmplt; 2391b95ec7ebSJiri Pirko 2392b95ec7ebSJiri Pirko fl_init_dissector(&tmplt->dissector, &tmplt->mask); 2393b95ec7ebSJiri Pirko 23948f256622SPablo Neira Ayuso err = fl_hw_create_tmplt(chain, tmplt); 23958f256622SPablo Neira Ayuso if (err) 23968f256622SPablo Neira Ayuso goto errout_tmplt; 239734738452SJiri Pirko 23988f256622SPablo Neira Ayuso kfree(tb); 2399b95ec7ebSJiri Pirko return tmplt; 2400b95ec7ebSJiri Pirko 2401b95ec7ebSJiri Pirko errout_tmplt: 2402b95ec7ebSJiri Pirko kfree(tmplt); 2403b95ec7ebSJiri Pirko errout_tb: 2404b95ec7ebSJiri Pirko kfree(tb); 2405b95ec7ebSJiri Pirko return ERR_PTR(err); 2406b95ec7ebSJiri Pirko } 2407b95ec7ebSJiri Pirko 2408b95ec7ebSJiri Pirko static void fl_tmplt_destroy(void *tmplt_priv) 2409b95ec7ebSJiri Pirko { 2410b95ec7ebSJiri Pirko struct fl_flow_tmplt *tmplt = tmplt_priv; 2411b95ec7ebSJiri Pirko 241295278ddaSCong Wang fl_hw_destroy_tmplt(tmplt->chain, tmplt); 241395278ddaSCong Wang kfree(tmplt); 2414b95ec7ebSJiri Pirko } 2415b95ec7ebSJiri Pirko 241677b9900eSJiri Pirko static int fl_dump_key_val(struct sk_buff *skb, 241777b9900eSJiri Pirko void *val, int val_type, 241877b9900eSJiri Pirko void *mask, int mask_type, int len) 241977b9900eSJiri Pirko { 242077b9900eSJiri Pirko int err; 242177b9900eSJiri Pirko 242277b9900eSJiri Pirko if (!memchr_inv(mask, 0, len)) 242377b9900eSJiri Pirko return 0; 242477b9900eSJiri Pirko err = nla_put(skb, val_type, len, val); 242577b9900eSJiri Pirko if (err) 242677b9900eSJiri Pirko return err; 242777b9900eSJiri Pirko if (mask_type != TCA_FLOWER_UNSPEC) { 242877b9900eSJiri Pirko err = nla_put(skb, mask_type, len, mask); 242977b9900eSJiri Pirko if (err) 243077b9900eSJiri Pirko return err; 243177b9900eSJiri Pirko } 243277b9900eSJiri Pirko return 0; 243377b9900eSJiri Pirko } 243477b9900eSJiri Pirko 24355c72299fSAmritha Nambiar static int fl_dump_key_port_range(struct sk_buff *skb, struct fl_flow_key *key, 24365c72299fSAmritha Nambiar struct fl_flow_key *mask) 24375c72299fSAmritha Nambiar { 24388ffb055bSYoshiki Komachi if (fl_dump_key_val(skb, &key->tp_range.tp_min.dst, 24398ffb055bSYoshiki Komachi TCA_FLOWER_KEY_PORT_DST_MIN, 24408ffb055bSYoshiki Komachi &mask->tp_range.tp_min.dst, TCA_FLOWER_UNSPEC, 24418ffb055bSYoshiki Komachi sizeof(key->tp_range.tp_min.dst)) || 24428ffb055bSYoshiki Komachi fl_dump_key_val(skb, &key->tp_range.tp_max.dst, 24438ffb055bSYoshiki Komachi TCA_FLOWER_KEY_PORT_DST_MAX, 24448ffb055bSYoshiki Komachi &mask->tp_range.tp_max.dst, TCA_FLOWER_UNSPEC, 24458ffb055bSYoshiki Komachi sizeof(key->tp_range.tp_max.dst)) || 24468ffb055bSYoshiki Komachi fl_dump_key_val(skb, &key->tp_range.tp_min.src, 24478ffb055bSYoshiki Komachi TCA_FLOWER_KEY_PORT_SRC_MIN, 24488ffb055bSYoshiki Komachi &mask->tp_range.tp_min.src, TCA_FLOWER_UNSPEC, 24498ffb055bSYoshiki Komachi sizeof(key->tp_range.tp_min.src)) || 24508ffb055bSYoshiki Komachi fl_dump_key_val(skb, &key->tp_range.tp_max.src, 24518ffb055bSYoshiki Komachi TCA_FLOWER_KEY_PORT_SRC_MAX, 24528ffb055bSYoshiki Komachi &mask->tp_range.tp_max.src, TCA_FLOWER_UNSPEC, 24538ffb055bSYoshiki Komachi sizeof(key->tp_range.tp_max.src))) 24545c72299fSAmritha Nambiar return -1; 24555c72299fSAmritha Nambiar 24565c72299fSAmritha Nambiar return 0; 24575c72299fSAmritha Nambiar } 24585c72299fSAmritha Nambiar 245961aec25aSGuillaume Nault static int fl_dump_key_mpls_opt_lse(struct sk_buff *skb, 246061aec25aSGuillaume Nault struct flow_dissector_key_mpls *mpls_key, 246161aec25aSGuillaume Nault struct flow_dissector_key_mpls *mpls_mask, 246261aec25aSGuillaume Nault u8 lse_index) 246361aec25aSGuillaume Nault { 246461aec25aSGuillaume Nault struct flow_dissector_mpls_lse *lse_mask = &mpls_mask->ls[lse_index]; 246561aec25aSGuillaume Nault struct flow_dissector_mpls_lse *lse_key = &mpls_key->ls[lse_index]; 246661aec25aSGuillaume Nault int err; 246761aec25aSGuillaume Nault 246861aec25aSGuillaume Nault err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_OPT_LSE_DEPTH, 246961aec25aSGuillaume Nault lse_index + 1); 247061aec25aSGuillaume Nault if (err) 247161aec25aSGuillaume Nault return err; 247261aec25aSGuillaume Nault 247361aec25aSGuillaume Nault if (lse_mask->mpls_ttl) { 247461aec25aSGuillaume Nault err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_OPT_LSE_TTL, 247561aec25aSGuillaume Nault lse_key->mpls_ttl); 247661aec25aSGuillaume Nault if (err) 247761aec25aSGuillaume Nault return err; 247861aec25aSGuillaume Nault } 247961aec25aSGuillaume Nault if (lse_mask->mpls_bos) { 248061aec25aSGuillaume Nault err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_OPT_LSE_BOS, 248161aec25aSGuillaume Nault lse_key->mpls_bos); 248261aec25aSGuillaume Nault if (err) 248361aec25aSGuillaume Nault return err; 248461aec25aSGuillaume Nault } 248561aec25aSGuillaume Nault if (lse_mask->mpls_tc) { 248661aec25aSGuillaume Nault err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_OPT_LSE_TC, 248761aec25aSGuillaume Nault lse_key->mpls_tc); 248861aec25aSGuillaume Nault if (err) 248961aec25aSGuillaume Nault return err; 249061aec25aSGuillaume Nault } 249161aec25aSGuillaume Nault if (lse_mask->mpls_label) { 24927fdd375eSGuillaume Nault err = nla_put_u32(skb, TCA_FLOWER_KEY_MPLS_OPT_LSE_LABEL, 249361aec25aSGuillaume Nault lse_key->mpls_label); 249461aec25aSGuillaume Nault if (err) 249561aec25aSGuillaume Nault return err; 249661aec25aSGuillaume Nault } 249761aec25aSGuillaume Nault 249861aec25aSGuillaume Nault return 0; 249961aec25aSGuillaume Nault } 250061aec25aSGuillaume Nault 250161aec25aSGuillaume Nault static int fl_dump_key_mpls_opts(struct sk_buff *skb, 250261aec25aSGuillaume Nault struct flow_dissector_key_mpls *mpls_key, 250361aec25aSGuillaume Nault struct flow_dissector_key_mpls *mpls_mask) 250461aec25aSGuillaume Nault { 250561aec25aSGuillaume Nault struct nlattr *opts; 250661aec25aSGuillaume Nault struct nlattr *lse; 250761aec25aSGuillaume Nault u8 lse_index; 250861aec25aSGuillaume Nault int err; 250961aec25aSGuillaume Nault 251061aec25aSGuillaume Nault opts = nla_nest_start(skb, TCA_FLOWER_KEY_MPLS_OPTS); 251161aec25aSGuillaume Nault if (!opts) 251261aec25aSGuillaume Nault return -EMSGSIZE; 251361aec25aSGuillaume Nault 251461aec25aSGuillaume Nault for (lse_index = 0; lse_index < FLOW_DIS_MPLS_MAX; lse_index++) { 251561aec25aSGuillaume Nault if (!(mpls_mask->used_lses & 1 << lse_index)) 251661aec25aSGuillaume Nault continue; 251761aec25aSGuillaume Nault 251861aec25aSGuillaume Nault lse = nla_nest_start(skb, TCA_FLOWER_KEY_MPLS_OPTS_LSE); 251961aec25aSGuillaume Nault if (!lse) { 252061aec25aSGuillaume Nault err = -EMSGSIZE; 252161aec25aSGuillaume Nault goto err_opts; 252261aec25aSGuillaume Nault } 252361aec25aSGuillaume Nault 252461aec25aSGuillaume Nault err = fl_dump_key_mpls_opt_lse(skb, mpls_key, mpls_mask, 252561aec25aSGuillaume Nault lse_index); 252661aec25aSGuillaume Nault if (err) 252761aec25aSGuillaume Nault goto err_opts_lse; 252861aec25aSGuillaume Nault nla_nest_end(skb, lse); 252961aec25aSGuillaume Nault } 253061aec25aSGuillaume Nault nla_nest_end(skb, opts); 253161aec25aSGuillaume Nault 253261aec25aSGuillaume Nault return 0; 253361aec25aSGuillaume Nault 253461aec25aSGuillaume Nault err_opts_lse: 253561aec25aSGuillaume Nault nla_nest_cancel(skb, lse); 253661aec25aSGuillaume Nault err_opts: 253761aec25aSGuillaume Nault nla_nest_cancel(skb, opts); 253861aec25aSGuillaume Nault 253961aec25aSGuillaume Nault return err; 254061aec25aSGuillaume Nault } 254161aec25aSGuillaume Nault 2542a577d8f7SBenjamin LaHaise static int fl_dump_key_mpls(struct sk_buff *skb, 2543a577d8f7SBenjamin LaHaise struct flow_dissector_key_mpls *mpls_key, 2544a577d8f7SBenjamin LaHaise struct flow_dissector_key_mpls *mpls_mask) 2545a577d8f7SBenjamin LaHaise { 254658cff782SGuillaume Nault struct flow_dissector_mpls_lse *lse_mask; 254758cff782SGuillaume Nault struct flow_dissector_mpls_lse *lse_key; 2548a577d8f7SBenjamin LaHaise int err; 2549a577d8f7SBenjamin LaHaise 255061aec25aSGuillaume Nault if (!mpls_mask->used_lses) 2551a577d8f7SBenjamin LaHaise return 0; 255258cff782SGuillaume Nault 255358cff782SGuillaume Nault lse_mask = &mpls_mask->ls[0]; 255458cff782SGuillaume Nault lse_key = &mpls_key->ls[0]; 255558cff782SGuillaume Nault 255661aec25aSGuillaume Nault /* For backward compatibility, don't use the MPLS nested attributes if 255761aec25aSGuillaume Nault * the rule can be expressed using the old attributes. 255861aec25aSGuillaume Nault */ 255961aec25aSGuillaume Nault if (mpls_mask->used_lses & ~1 || 256061aec25aSGuillaume Nault (!lse_mask->mpls_ttl && !lse_mask->mpls_bos && 256161aec25aSGuillaume Nault !lse_mask->mpls_tc && !lse_mask->mpls_label)) 256261aec25aSGuillaume Nault return fl_dump_key_mpls_opts(skb, mpls_key, mpls_mask); 256361aec25aSGuillaume Nault 256458cff782SGuillaume Nault if (lse_mask->mpls_ttl) { 2565a577d8f7SBenjamin LaHaise err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TTL, 256658cff782SGuillaume Nault lse_key->mpls_ttl); 2567a577d8f7SBenjamin LaHaise if (err) 2568a577d8f7SBenjamin LaHaise return err; 2569a577d8f7SBenjamin LaHaise } 257058cff782SGuillaume Nault if (lse_mask->mpls_tc) { 2571a577d8f7SBenjamin LaHaise err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TC, 257258cff782SGuillaume Nault lse_key->mpls_tc); 2573a577d8f7SBenjamin LaHaise if (err) 2574a577d8f7SBenjamin LaHaise return err; 2575a577d8f7SBenjamin LaHaise } 257658cff782SGuillaume Nault if (lse_mask->mpls_label) { 2577a577d8f7SBenjamin LaHaise err = nla_put_u32(skb, TCA_FLOWER_KEY_MPLS_LABEL, 257858cff782SGuillaume Nault lse_key->mpls_label); 2579a577d8f7SBenjamin LaHaise if (err) 2580a577d8f7SBenjamin LaHaise return err; 2581a577d8f7SBenjamin LaHaise } 258258cff782SGuillaume Nault if (lse_mask->mpls_bos) { 2583a577d8f7SBenjamin LaHaise err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_BOS, 258458cff782SGuillaume Nault lse_key->mpls_bos); 2585a577d8f7SBenjamin LaHaise if (err) 2586a577d8f7SBenjamin LaHaise return err; 2587a577d8f7SBenjamin LaHaise } 2588a577d8f7SBenjamin LaHaise return 0; 2589a577d8f7SBenjamin LaHaise } 2590a577d8f7SBenjamin LaHaise 25910e2c17b6SOr Gerlitz static int fl_dump_key_ip(struct sk_buff *skb, bool encap, 25924d80cc0aSOr Gerlitz struct flow_dissector_key_ip *key, 25934d80cc0aSOr Gerlitz struct flow_dissector_key_ip *mask) 25944d80cc0aSOr Gerlitz { 25950e2c17b6SOr Gerlitz int tos_key = encap ? TCA_FLOWER_KEY_ENC_IP_TOS : TCA_FLOWER_KEY_IP_TOS; 25960e2c17b6SOr Gerlitz int ttl_key = encap ? TCA_FLOWER_KEY_ENC_IP_TTL : TCA_FLOWER_KEY_IP_TTL; 25970e2c17b6SOr Gerlitz int tos_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TOS_MASK : TCA_FLOWER_KEY_IP_TOS_MASK; 25980e2c17b6SOr Gerlitz int ttl_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TTL_MASK : TCA_FLOWER_KEY_IP_TTL_MASK; 25990e2c17b6SOr Gerlitz 26000e2c17b6SOr Gerlitz if (fl_dump_key_val(skb, &key->tos, tos_key, &mask->tos, tos_mask, sizeof(key->tos)) || 26010e2c17b6SOr Gerlitz fl_dump_key_val(skb, &key->ttl, ttl_key, &mask->ttl, ttl_mask, sizeof(key->ttl))) 26024d80cc0aSOr Gerlitz return -1; 26034d80cc0aSOr Gerlitz 26044d80cc0aSOr Gerlitz return 0; 26054d80cc0aSOr Gerlitz } 26064d80cc0aSOr Gerlitz 26079399ae9aSHadar Hen Zion static int fl_dump_key_vlan(struct sk_buff *skb, 2608d64efd09SJianbo Liu int vlan_id_key, int vlan_prio_key, 26099399ae9aSHadar Hen Zion struct flow_dissector_key_vlan *vlan_key, 26109399ae9aSHadar Hen Zion struct flow_dissector_key_vlan *vlan_mask) 26119399ae9aSHadar Hen Zion { 26129399ae9aSHadar Hen Zion int err; 26139399ae9aSHadar Hen Zion 26149399ae9aSHadar Hen Zion if (!memchr_inv(vlan_mask, 0, sizeof(*vlan_mask))) 26159399ae9aSHadar Hen Zion return 0; 26169399ae9aSHadar Hen Zion if (vlan_mask->vlan_id) { 2617d64efd09SJianbo Liu err = nla_put_u16(skb, vlan_id_key, 26189399ae9aSHadar Hen Zion vlan_key->vlan_id); 26199399ae9aSHadar Hen Zion if (err) 26209399ae9aSHadar Hen Zion return err; 26219399ae9aSHadar Hen Zion } 26229399ae9aSHadar Hen Zion if (vlan_mask->vlan_priority) { 2623d64efd09SJianbo Liu err = nla_put_u8(skb, vlan_prio_key, 26249399ae9aSHadar Hen Zion vlan_key->vlan_priority); 26259399ae9aSHadar Hen Zion if (err) 26269399ae9aSHadar Hen Zion return err; 26279399ae9aSHadar Hen Zion } 26289399ae9aSHadar Hen Zion return 0; 26299399ae9aSHadar Hen Zion } 26309399ae9aSHadar Hen Zion 2631faa3ffceSOr Gerlitz static void fl_get_key_flag(u32 dissector_key, u32 dissector_mask, 2632faa3ffceSOr Gerlitz u32 *flower_key, u32 *flower_mask, 2633faa3ffceSOr Gerlitz u32 flower_flag_bit, u32 dissector_flag_bit) 2634faa3ffceSOr Gerlitz { 2635faa3ffceSOr Gerlitz if (dissector_mask & dissector_flag_bit) { 2636faa3ffceSOr Gerlitz *flower_mask |= flower_flag_bit; 2637faa3ffceSOr Gerlitz if (dissector_key & dissector_flag_bit) 2638faa3ffceSOr Gerlitz *flower_key |= flower_flag_bit; 2639faa3ffceSOr Gerlitz } 2640faa3ffceSOr Gerlitz } 2641faa3ffceSOr Gerlitz 2642faa3ffceSOr Gerlitz static int fl_dump_key_flags(struct sk_buff *skb, u32 flags_key, u32 flags_mask) 2643faa3ffceSOr Gerlitz { 2644faa3ffceSOr Gerlitz u32 key, mask; 2645faa3ffceSOr Gerlitz __be32 _key, _mask; 2646faa3ffceSOr Gerlitz int err; 2647faa3ffceSOr Gerlitz 2648faa3ffceSOr Gerlitz if (!memchr_inv(&flags_mask, 0, sizeof(flags_mask))) 2649faa3ffceSOr Gerlitz return 0; 2650faa3ffceSOr Gerlitz 2651faa3ffceSOr Gerlitz key = 0; 2652faa3ffceSOr Gerlitz mask = 0; 2653faa3ffceSOr Gerlitz 2654faa3ffceSOr Gerlitz fl_get_key_flag(flags_key, flags_mask, &key, &mask, 2655faa3ffceSOr Gerlitz TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT); 2656459d153dSPieter Jansen van Vuuren fl_get_key_flag(flags_key, flags_mask, &key, &mask, 2657459d153dSPieter Jansen van Vuuren TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST, 2658459d153dSPieter Jansen van Vuuren FLOW_DIS_FIRST_FRAG); 2659faa3ffceSOr Gerlitz 2660faa3ffceSOr Gerlitz _key = cpu_to_be32(key); 2661faa3ffceSOr Gerlitz _mask = cpu_to_be32(mask); 2662faa3ffceSOr Gerlitz 2663faa3ffceSOr Gerlitz err = nla_put(skb, TCA_FLOWER_KEY_FLAGS, 4, &_key); 2664faa3ffceSOr Gerlitz if (err) 2665faa3ffceSOr Gerlitz return err; 2666faa3ffceSOr Gerlitz 2667faa3ffceSOr Gerlitz return nla_put(skb, TCA_FLOWER_KEY_FLAGS_MASK, 4, &_mask); 2668faa3ffceSOr Gerlitz } 2669faa3ffceSOr Gerlitz 26700a6e7778SPieter Jansen van Vuuren static int fl_dump_key_geneve_opt(struct sk_buff *skb, 26710a6e7778SPieter Jansen van Vuuren struct flow_dissector_key_enc_opts *enc_opts) 26720a6e7778SPieter Jansen van Vuuren { 26730a6e7778SPieter Jansen van Vuuren struct geneve_opt *opt; 26740a6e7778SPieter Jansen van Vuuren struct nlattr *nest; 26750a6e7778SPieter Jansen van Vuuren int opt_off = 0; 26760a6e7778SPieter Jansen van Vuuren 2677ae0be8deSMichal Kubecek nest = nla_nest_start_noflag(skb, TCA_FLOWER_KEY_ENC_OPTS_GENEVE); 26780a6e7778SPieter Jansen van Vuuren if (!nest) 26790a6e7778SPieter Jansen van Vuuren goto nla_put_failure; 26800a6e7778SPieter Jansen van Vuuren 26810a6e7778SPieter Jansen van Vuuren while (enc_opts->len > opt_off) { 26820a6e7778SPieter Jansen van Vuuren opt = (struct geneve_opt *)&enc_opts->data[opt_off]; 26830a6e7778SPieter Jansen van Vuuren 26840a6e7778SPieter Jansen van Vuuren if (nla_put_be16(skb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS, 26850a6e7778SPieter Jansen van Vuuren opt->opt_class)) 26860a6e7778SPieter Jansen van Vuuren goto nla_put_failure; 26870a6e7778SPieter Jansen van Vuuren if (nla_put_u8(skb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE, 26880a6e7778SPieter Jansen van Vuuren opt->type)) 26890a6e7778SPieter Jansen van Vuuren goto nla_put_failure; 26900a6e7778SPieter Jansen van Vuuren if (nla_put(skb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA, 26910a6e7778SPieter Jansen van Vuuren opt->length * 4, opt->opt_data)) 26920a6e7778SPieter Jansen van Vuuren goto nla_put_failure; 26930a6e7778SPieter Jansen van Vuuren 26940a6e7778SPieter Jansen van Vuuren opt_off += sizeof(struct geneve_opt) + opt->length * 4; 26950a6e7778SPieter Jansen van Vuuren } 26960a6e7778SPieter Jansen van Vuuren nla_nest_end(skb, nest); 26970a6e7778SPieter Jansen van Vuuren return 0; 26980a6e7778SPieter Jansen van Vuuren 26990a6e7778SPieter Jansen van Vuuren nla_put_failure: 27000a6e7778SPieter Jansen van Vuuren nla_nest_cancel(skb, nest); 27010a6e7778SPieter Jansen van Vuuren return -EMSGSIZE; 27020a6e7778SPieter Jansen van Vuuren } 27030a6e7778SPieter Jansen van Vuuren 2704d8f9dfaeSXin Long static int fl_dump_key_vxlan_opt(struct sk_buff *skb, 2705d8f9dfaeSXin Long struct flow_dissector_key_enc_opts *enc_opts) 2706d8f9dfaeSXin Long { 2707d8f9dfaeSXin Long struct vxlan_metadata *md; 2708d8f9dfaeSXin Long struct nlattr *nest; 2709d8f9dfaeSXin Long 2710d8f9dfaeSXin Long nest = nla_nest_start_noflag(skb, TCA_FLOWER_KEY_ENC_OPTS_VXLAN); 2711d8f9dfaeSXin Long if (!nest) 2712d8f9dfaeSXin Long goto nla_put_failure; 2713d8f9dfaeSXin Long 2714d8f9dfaeSXin Long md = (struct vxlan_metadata *)&enc_opts->data[0]; 2715d8f9dfaeSXin Long if (nla_put_u32(skb, TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP, md->gbp)) 2716d8f9dfaeSXin Long goto nla_put_failure; 2717d8f9dfaeSXin Long 2718d8f9dfaeSXin Long nla_nest_end(skb, nest); 2719d8f9dfaeSXin Long return 0; 2720d8f9dfaeSXin Long 2721d8f9dfaeSXin Long nla_put_failure: 2722d8f9dfaeSXin Long nla_nest_cancel(skb, nest); 2723d8f9dfaeSXin Long return -EMSGSIZE; 2724d8f9dfaeSXin Long } 2725d8f9dfaeSXin Long 272679b1011cSXin Long static int fl_dump_key_erspan_opt(struct sk_buff *skb, 272779b1011cSXin Long struct flow_dissector_key_enc_opts *enc_opts) 272879b1011cSXin Long { 272979b1011cSXin Long struct erspan_metadata *md; 273079b1011cSXin Long struct nlattr *nest; 273179b1011cSXin Long 273279b1011cSXin Long nest = nla_nest_start_noflag(skb, TCA_FLOWER_KEY_ENC_OPTS_ERSPAN); 273379b1011cSXin Long if (!nest) 273479b1011cSXin Long goto nla_put_failure; 273579b1011cSXin Long 273679b1011cSXin Long md = (struct erspan_metadata *)&enc_opts->data[0]; 273779b1011cSXin Long if (nla_put_u8(skb, TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER, md->version)) 273879b1011cSXin Long goto nla_put_failure; 273979b1011cSXin Long 274079b1011cSXin Long if (md->version == 1 && 274179b1011cSXin Long nla_put_be32(skb, TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX, md->u.index)) 274279b1011cSXin Long goto nla_put_failure; 274379b1011cSXin Long 274479b1011cSXin Long if (md->version == 2 && 274579b1011cSXin Long (nla_put_u8(skb, TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR, 274679b1011cSXin Long md->u.md2.dir) || 274779b1011cSXin Long nla_put_u8(skb, TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID, 274879b1011cSXin Long get_hwid(&md->u.md2)))) 274979b1011cSXin Long goto nla_put_failure; 275079b1011cSXin Long 275179b1011cSXin Long nla_nest_end(skb, nest); 275279b1011cSXin Long return 0; 275379b1011cSXin Long 275479b1011cSXin Long nla_put_failure: 275579b1011cSXin Long nla_nest_cancel(skb, nest); 275679b1011cSXin Long return -EMSGSIZE; 275779b1011cSXin Long } 275879b1011cSXin Long 2759e0ace68aSPaul Blakey static int fl_dump_key_ct(struct sk_buff *skb, 2760e0ace68aSPaul Blakey struct flow_dissector_key_ct *key, 2761e0ace68aSPaul Blakey struct flow_dissector_key_ct *mask) 2762e0ace68aSPaul Blakey { 2763e0ace68aSPaul Blakey if (IS_ENABLED(CONFIG_NF_CONNTRACK) && 2764e0ace68aSPaul Blakey fl_dump_key_val(skb, &key->ct_state, TCA_FLOWER_KEY_CT_STATE, 2765e0ace68aSPaul Blakey &mask->ct_state, TCA_FLOWER_KEY_CT_STATE_MASK, 2766e0ace68aSPaul Blakey sizeof(key->ct_state))) 2767e0ace68aSPaul Blakey goto nla_put_failure; 2768e0ace68aSPaul Blakey 2769e0ace68aSPaul Blakey if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) && 2770e0ace68aSPaul Blakey fl_dump_key_val(skb, &key->ct_zone, TCA_FLOWER_KEY_CT_ZONE, 2771e0ace68aSPaul Blakey &mask->ct_zone, TCA_FLOWER_KEY_CT_ZONE_MASK, 2772e0ace68aSPaul Blakey sizeof(key->ct_zone))) 2773e0ace68aSPaul Blakey goto nla_put_failure; 2774e0ace68aSPaul Blakey 2775e0ace68aSPaul Blakey if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) && 2776e0ace68aSPaul Blakey fl_dump_key_val(skb, &key->ct_mark, TCA_FLOWER_KEY_CT_MARK, 2777e0ace68aSPaul Blakey &mask->ct_mark, TCA_FLOWER_KEY_CT_MARK_MASK, 2778e0ace68aSPaul Blakey sizeof(key->ct_mark))) 2779e0ace68aSPaul Blakey goto nla_put_failure; 2780e0ace68aSPaul Blakey 2781e0ace68aSPaul Blakey if (IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS) && 2782e0ace68aSPaul Blakey fl_dump_key_val(skb, &key->ct_labels, TCA_FLOWER_KEY_CT_LABELS, 2783e0ace68aSPaul Blakey &mask->ct_labels, TCA_FLOWER_KEY_CT_LABELS_MASK, 2784e0ace68aSPaul Blakey sizeof(key->ct_labels))) 2785e0ace68aSPaul Blakey goto nla_put_failure; 2786e0ace68aSPaul Blakey 2787e0ace68aSPaul Blakey return 0; 2788e0ace68aSPaul Blakey 2789e0ace68aSPaul Blakey nla_put_failure: 2790e0ace68aSPaul Blakey return -EMSGSIZE; 2791e0ace68aSPaul Blakey } 2792e0ace68aSPaul Blakey 27930a6e7778SPieter Jansen van Vuuren static int fl_dump_key_options(struct sk_buff *skb, int enc_opt_type, 27940a6e7778SPieter Jansen van Vuuren struct flow_dissector_key_enc_opts *enc_opts) 27950a6e7778SPieter Jansen van Vuuren { 27960a6e7778SPieter Jansen van Vuuren struct nlattr *nest; 27970a6e7778SPieter Jansen van Vuuren int err; 27980a6e7778SPieter Jansen van Vuuren 27990a6e7778SPieter Jansen van Vuuren if (!enc_opts->len) 28000a6e7778SPieter Jansen van Vuuren return 0; 28010a6e7778SPieter Jansen van Vuuren 2802ae0be8deSMichal Kubecek nest = nla_nest_start_noflag(skb, enc_opt_type); 28030a6e7778SPieter Jansen van Vuuren if (!nest) 28040a6e7778SPieter Jansen van Vuuren goto nla_put_failure; 28050a6e7778SPieter Jansen van Vuuren 28060a6e7778SPieter Jansen van Vuuren switch (enc_opts->dst_opt_type) { 28070a6e7778SPieter Jansen van Vuuren case TUNNEL_GENEVE_OPT: 28080a6e7778SPieter Jansen van Vuuren err = fl_dump_key_geneve_opt(skb, enc_opts); 28090a6e7778SPieter Jansen van Vuuren if (err) 28100a6e7778SPieter Jansen van Vuuren goto nla_put_failure; 28110a6e7778SPieter Jansen van Vuuren break; 2812d8f9dfaeSXin Long case TUNNEL_VXLAN_OPT: 2813d8f9dfaeSXin Long err = fl_dump_key_vxlan_opt(skb, enc_opts); 2814d8f9dfaeSXin Long if (err) 2815d8f9dfaeSXin Long goto nla_put_failure; 2816d8f9dfaeSXin Long break; 281779b1011cSXin Long case TUNNEL_ERSPAN_OPT: 281879b1011cSXin Long err = fl_dump_key_erspan_opt(skb, enc_opts); 281979b1011cSXin Long if (err) 282079b1011cSXin Long goto nla_put_failure; 282179b1011cSXin Long break; 28220a6e7778SPieter Jansen van Vuuren default: 28230a6e7778SPieter Jansen van Vuuren goto nla_put_failure; 28240a6e7778SPieter Jansen van Vuuren } 28250a6e7778SPieter Jansen van Vuuren nla_nest_end(skb, nest); 28260a6e7778SPieter Jansen van Vuuren return 0; 28270a6e7778SPieter Jansen van Vuuren 28280a6e7778SPieter Jansen van Vuuren nla_put_failure: 28290a6e7778SPieter Jansen van Vuuren nla_nest_cancel(skb, nest); 28300a6e7778SPieter Jansen van Vuuren return -EMSGSIZE; 28310a6e7778SPieter Jansen van Vuuren } 28320a6e7778SPieter Jansen van Vuuren 28330a6e7778SPieter Jansen van Vuuren static int fl_dump_key_enc_opt(struct sk_buff *skb, 28340a6e7778SPieter Jansen van Vuuren struct flow_dissector_key_enc_opts *key_opts, 28350a6e7778SPieter Jansen van Vuuren struct flow_dissector_key_enc_opts *msk_opts) 28360a6e7778SPieter Jansen van Vuuren { 28370a6e7778SPieter Jansen van Vuuren int err; 28380a6e7778SPieter Jansen van Vuuren 28390a6e7778SPieter Jansen van Vuuren err = fl_dump_key_options(skb, TCA_FLOWER_KEY_ENC_OPTS, key_opts); 28400a6e7778SPieter Jansen van Vuuren if (err) 28410a6e7778SPieter Jansen van Vuuren return err; 28420a6e7778SPieter Jansen van Vuuren 28430a6e7778SPieter Jansen van Vuuren return fl_dump_key_options(skb, TCA_FLOWER_KEY_ENC_OPTS_MASK, msk_opts); 28440a6e7778SPieter Jansen van Vuuren } 28450a6e7778SPieter Jansen van Vuuren 2846f5749081SJiri Pirko static int fl_dump_key(struct sk_buff *skb, struct net *net, 2847f5749081SJiri Pirko struct fl_flow_key *key, struct fl_flow_key *mask) 284877b9900eSJiri Pirko { 28498212ed77SJiri Pirko if (mask->meta.ingress_ifindex) { 285077b9900eSJiri Pirko struct net_device *dev; 285177b9900eSJiri Pirko 28528212ed77SJiri Pirko dev = __dev_get_by_index(net, key->meta.ingress_ifindex); 285377b9900eSJiri Pirko if (dev && nla_put_string(skb, TCA_FLOWER_INDEV, dev->name)) 285477b9900eSJiri Pirko goto nla_put_failure; 285577b9900eSJiri Pirko } 285677b9900eSJiri Pirko 285777b9900eSJiri Pirko if (fl_dump_key_val(skb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST, 285877b9900eSJiri Pirko mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK, 285977b9900eSJiri Pirko sizeof(key->eth.dst)) || 286077b9900eSJiri Pirko fl_dump_key_val(skb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC, 286177b9900eSJiri Pirko mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK, 286277b9900eSJiri Pirko sizeof(key->eth.src)) || 286377b9900eSJiri Pirko fl_dump_key_val(skb, &key->basic.n_proto, TCA_FLOWER_KEY_ETH_TYPE, 286477b9900eSJiri Pirko &mask->basic.n_proto, TCA_FLOWER_UNSPEC, 286577b9900eSJiri Pirko sizeof(key->basic.n_proto))) 286677b9900eSJiri Pirko goto nla_put_failure; 28679399ae9aSHadar Hen Zion 2868a577d8f7SBenjamin LaHaise if (fl_dump_key_mpls(skb, &key->mpls, &mask->mpls)) 2869a577d8f7SBenjamin LaHaise goto nla_put_failure; 2870a577d8f7SBenjamin LaHaise 2871d64efd09SJianbo Liu if (fl_dump_key_vlan(skb, TCA_FLOWER_KEY_VLAN_ID, 2872d64efd09SJianbo Liu TCA_FLOWER_KEY_VLAN_PRIO, &key->vlan, &mask->vlan)) 28739399ae9aSHadar Hen Zion goto nla_put_failure; 28749399ae9aSHadar Hen Zion 2875d64efd09SJianbo Liu if (fl_dump_key_vlan(skb, TCA_FLOWER_KEY_CVLAN_ID, 2876d64efd09SJianbo Liu TCA_FLOWER_KEY_CVLAN_PRIO, 2877d64efd09SJianbo Liu &key->cvlan, &mask->cvlan) || 2878d64efd09SJianbo Liu (mask->cvlan.vlan_tpid && 2879158abbf1SJianbo Liu nla_put_be16(skb, TCA_FLOWER_KEY_VLAN_ETH_TYPE, 2880d64efd09SJianbo Liu key->cvlan.vlan_tpid))) 2881d3069512SJianbo Liu goto nla_put_failure; 2882d3069512SJianbo Liu 28835e9a0fe4SJianbo Liu if (mask->basic.n_proto) { 2884d64efd09SJianbo Liu if (mask->cvlan.vlan_tpid) { 2885d64efd09SJianbo Liu if (nla_put_be16(skb, TCA_FLOWER_KEY_CVLAN_ETH_TYPE, 2886d64efd09SJianbo Liu key->basic.n_proto)) 2887d64efd09SJianbo Liu goto nla_put_failure; 2888d64efd09SJianbo Liu } else if (mask->vlan.vlan_tpid) { 2889d64efd09SJianbo Liu if (nla_put_be16(skb, TCA_FLOWER_KEY_VLAN_ETH_TYPE, 2890d64efd09SJianbo Liu key->basic.n_proto)) 2891d64efd09SJianbo Liu goto nla_put_failure; 2892d64efd09SJianbo Liu } 28935e9a0fe4SJianbo Liu } 2894d64efd09SJianbo Liu 289577b9900eSJiri Pirko if ((key->basic.n_proto == htons(ETH_P_IP) || 289677b9900eSJiri Pirko key->basic.n_proto == htons(ETH_P_IPV6)) && 28974d80cc0aSOr Gerlitz (fl_dump_key_val(skb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO, 289877b9900eSJiri Pirko &mask->basic.ip_proto, TCA_FLOWER_UNSPEC, 28994d80cc0aSOr Gerlitz sizeof(key->basic.ip_proto)) || 29000e2c17b6SOr Gerlitz fl_dump_key_ip(skb, false, &key->ip, &mask->ip))) 290177b9900eSJiri Pirko goto nla_put_failure; 290277b9900eSJiri Pirko 2903c3f83241STom Herbert if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS && 290477b9900eSJiri Pirko (fl_dump_key_val(skb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC, 290577b9900eSJiri Pirko &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK, 290677b9900eSJiri Pirko sizeof(key->ipv4.src)) || 290777b9900eSJiri Pirko fl_dump_key_val(skb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST, 290877b9900eSJiri Pirko &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK, 290977b9900eSJiri Pirko sizeof(key->ipv4.dst)))) 291077b9900eSJiri Pirko goto nla_put_failure; 2911c3f83241STom Herbert else if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS && 291277b9900eSJiri Pirko (fl_dump_key_val(skb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC, 291377b9900eSJiri Pirko &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK, 291477b9900eSJiri Pirko sizeof(key->ipv6.src)) || 291577b9900eSJiri Pirko fl_dump_key_val(skb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST, 291677b9900eSJiri Pirko &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK, 291777b9900eSJiri Pirko sizeof(key->ipv6.dst)))) 291877b9900eSJiri Pirko goto nla_put_failure; 291977b9900eSJiri Pirko 292077b9900eSJiri Pirko if (key->basic.ip_proto == IPPROTO_TCP && 292177b9900eSJiri Pirko (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC, 2922aa72d708SOr Gerlitz &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK, 292377b9900eSJiri Pirko sizeof(key->tp.src)) || 292477b9900eSJiri Pirko fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST, 2925aa72d708SOr Gerlitz &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK, 2926fdfc7dd6SJiri Pirko sizeof(key->tp.dst)) || 2927fdfc7dd6SJiri Pirko fl_dump_key_val(skb, &key->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS, 2928fdfc7dd6SJiri Pirko &mask->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS_MASK, 2929fdfc7dd6SJiri Pirko sizeof(key->tcp.flags)))) 293077b9900eSJiri Pirko goto nla_put_failure; 293177b9900eSJiri Pirko else if (key->basic.ip_proto == IPPROTO_UDP && 293277b9900eSJiri Pirko (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC, 2933aa72d708SOr Gerlitz &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK, 293477b9900eSJiri Pirko sizeof(key->tp.src)) || 293577b9900eSJiri Pirko fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST, 2936aa72d708SOr Gerlitz &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK, 293777b9900eSJiri Pirko sizeof(key->tp.dst)))) 293877b9900eSJiri Pirko goto nla_put_failure; 29395976c5f4SSimon Horman else if (key->basic.ip_proto == IPPROTO_SCTP && 29405976c5f4SSimon Horman (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC, 29415976c5f4SSimon Horman &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK, 29425976c5f4SSimon Horman sizeof(key->tp.src)) || 29435976c5f4SSimon Horman fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST, 29445976c5f4SSimon Horman &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK, 29455976c5f4SSimon Horman sizeof(key->tp.dst)))) 29465976c5f4SSimon Horman goto nla_put_failure; 29477b684884SSimon Horman else if (key->basic.n_proto == htons(ETH_P_IP) && 29487b684884SSimon Horman key->basic.ip_proto == IPPROTO_ICMP && 29497b684884SSimon Horman (fl_dump_key_val(skb, &key->icmp.type, 29507b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_TYPE, &mask->icmp.type, 29517b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_TYPE_MASK, 29527b684884SSimon Horman sizeof(key->icmp.type)) || 29537b684884SSimon Horman fl_dump_key_val(skb, &key->icmp.code, 29547b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_CODE, &mask->icmp.code, 29557b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_CODE_MASK, 29567b684884SSimon Horman sizeof(key->icmp.code)))) 29577b684884SSimon Horman goto nla_put_failure; 29587b684884SSimon Horman else if (key->basic.n_proto == htons(ETH_P_IPV6) && 29597b684884SSimon Horman key->basic.ip_proto == IPPROTO_ICMPV6 && 29607b684884SSimon Horman (fl_dump_key_val(skb, &key->icmp.type, 29617b684884SSimon Horman TCA_FLOWER_KEY_ICMPV6_TYPE, &mask->icmp.type, 29627b684884SSimon Horman TCA_FLOWER_KEY_ICMPV6_TYPE_MASK, 29637b684884SSimon Horman sizeof(key->icmp.type)) || 29647b684884SSimon Horman fl_dump_key_val(skb, &key->icmp.code, 29657b684884SSimon Horman TCA_FLOWER_KEY_ICMPV6_CODE, &mask->icmp.code, 29667b684884SSimon Horman TCA_FLOWER_KEY_ICMPV6_CODE_MASK, 29677b684884SSimon Horman sizeof(key->icmp.code)))) 29687b684884SSimon Horman goto nla_put_failure; 296999d31326SSimon Horman else if ((key->basic.n_proto == htons(ETH_P_ARP) || 297099d31326SSimon Horman key->basic.n_proto == htons(ETH_P_RARP)) && 297199d31326SSimon Horman (fl_dump_key_val(skb, &key->arp.sip, 297299d31326SSimon Horman TCA_FLOWER_KEY_ARP_SIP, &mask->arp.sip, 297399d31326SSimon Horman TCA_FLOWER_KEY_ARP_SIP_MASK, 297499d31326SSimon Horman sizeof(key->arp.sip)) || 297599d31326SSimon Horman fl_dump_key_val(skb, &key->arp.tip, 297699d31326SSimon Horman TCA_FLOWER_KEY_ARP_TIP, &mask->arp.tip, 297799d31326SSimon Horman TCA_FLOWER_KEY_ARP_TIP_MASK, 297899d31326SSimon Horman sizeof(key->arp.tip)) || 297999d31326SSimon Horman fl_dump_key_val(skb, &key->arp.op, 298099d31326SSimon Horman TCA_FLOWER_KEY_ARP_OP, &mask->arp.op, 298199d31326SSimon Horman TCA_FLOWER_KEY_ARP_OP_MASK, 298299d31326SSimon Horman sizeof(key->arp.op)) || 298399d31326SSimon Horman fl_dump_key_val(skb, key->arp.sha, TCA_FLOWER_KEY_ARP_SHA, 298499d31326SSimon Horman mask->arp.sha, TCA_FLOWER_KEY_ARP_SHA_MASK, 298599d31326SSimon Horman sizeof(key->arp.sha)) || 298699d31326SSimon Horman fl_dump_key_val(skb, key->arp.tha, TCA_FLOWER_KEY_ARP_THA, 298799d31326SSimon Horman mask->arp.tha, TCA_FLOWER_KEY_ARP_THA_MASK, 298899d31326SSimon Horman sizeof(key->arp.tha)))) 298999d31326SSimon Horman goto nla_put_failure; 299077b9900eSJiri Pirko 29915c72299fSAmritha Nambiar if ((key->basic.ip_proto == IPPROTO_TCP || 29925c72299fSAmritha Nambiar key->basic.ip_proto == IPPROTO_UDP || 29935c72299fSAmritha Nambiar key->basic.ip_proto == IPPROTO_SCTP) && 29945c72299fSAmritha Nambiar fl_dump_key_port_range(skb, key, mask)) 29955c72299fSAmritha Nambiar goto nla_put_failure; 29965c72299fSAmritha Nambiar 2997bc3103f1SAmir Vadai if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS && 2998bc3103f1SAmir Vadai (fl_dump_key_val(skb, &key->enc_ipv4.src, 2999bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_SRC, &mask->enc_ipv4.src, 3000bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK, 3001bc3103f1SAmir Vadai sizeof(key->enc_ipv4.src)) || 3002bc3103f1SAmir Vadai fl_dump_key_val(skb, &key->enc_ipv4.dst, 3003bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_DST, &mask->enc_ipv4.dst, 3004bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_DST_MASK, 3005bc3103f1SAmir Vadai sizeof(key->enc_ipv4.dst)))) 3006bc3103f1SAmir Vadai goto nla_put_failure; 3007bc3103f1SAmir Vadai else if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS && 3008bc3103f1SAmir Vadai (fl_dump_key_val(skb, &key->enc_ipv6.src, 3009bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_SRC, &mask->enc_ipv6.src, 3010bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK, 3011bc3103f1SAmir Vadai sizeof(key->enc_ipv6.src)) || 3012bc3103f1SAmir Vadai fl_dump_key_val(skb, &key->enc_ipv6.dst, 3013bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_DST, 3014bc3103f1SAmir Vadai &mask->enc_ipv6.dst, 3015bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_DST_MASK, 3016bc3103f1SAmir Vadai sizeof(key->enc_ipv6.dst)))) 3017bc3103f1SAmir Vadai goto nla_put_failure; 3018bc3103f1SAmir Vadai 3019bc3103f1SAmir Vadai if (fl_dump_key_val(skb, &key->enc_key_id, TCA_FLOWER_KEY_ENC_KEY_ID, 3020eb523f42SHadar Hen Zion &mask->enc_key_id, TCA_FLOWER_UNSPEC, 3021f4d997fdSHadar Hen Zion sizeof(key->enc_key_id)) || 3022f4d997fdSHadar Hen Zion fl_dump_key_val(skb, &key->enc_tp.src, 3023f4d997fdSHadar Hen Zion TCA_FLOWER_KEY_ENC_UDP_SRC_PORT, 3024f4d997fdSHadar Hen Zion &mask->enc_tp.src, 3025f4d997fdSHadar Hen Zion TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK, 3026f4d997fdSHadar Hen Zion sizeof(key->enc_tp.src)) || 3027f4d997fdSHadar Hen Zion fl_dump_key_val(skb, &key->enc_tp.dst, 3028f4d997fdSHadar Hen Zion TCA_FLOWER_KEY_ENC_UDP_DST_PORT, 3029f4d997fdSHadar Hen Zion &mask->enc_tp.dst, 3030f4d997fdSHadar Hen Zion TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK, 30310e2c17b6SOr Gerlitz sizeof(key->enc_tp.dst)) || 30320a6e7778SPieter Jansen van Vuuren fl_dump_key_ip(skb, true, &key->enc_ip, &mask->enc_ip) || 30330a6e7778SPieter Jansen van Vuuren fl_dump_key_enc_opt(skb, &key->enc_opts, &mask->enc_opts)) 3034bc3103f1SAmir Vadai goto nla_put_failure; 3035bc3103f1SAmir Vadai 3036e0ace68aSPaul Blakey if (fl_dump_key_ct(skb, &key->ct, &mask->ct)) 3037e0ace68aSPaul Blakey goto nla_put_failure; 3038e0ace68aSPaul Blakey 3039faa3ffceSOr Gerlitz if (fl_dump_key_flags(skb, key->control.flags, mask->control.flags)) 3040faa3ffceSOr Gerlitz goto nla_put_failure; 3041faa3ffceSOr Gerlitz 30425923b8f7SAriel Levkovich if (fl_dump_key_val(skb, &key->hash.hash, TCA_FLOWER_KEY_HASH, 30435923b8f7SAriel Levkovich &mask->hash.hash, TCA_FLOWER_KEY_HASH_MASK, 30445923b8f7SAriel Levkovich sizeof(key->hash.hash))) 30455923b8f7SAriel Levkovich goto nla_put_failure; 30465923b8f7SAriel Levkovich 3047f5749081SJiri Pirko return 0; 3048f5749081SJiri Pirko 3049f5749081SJiri Pirko nla_put_failure: 3050f5749081SJiri Pirko return -EMSGSIZE; 3051f5749081SJiri Pirko } 3052f5749081SJiri Pirko 3053f5749081SJiri Pirko static int fl_dump(struct net *net, struct tcf_proto *tp, void *fh, 305412db03b6SVlad Buslov struct sk_buff *skb, struct tcmsg *t, bool rtnl_held) 3055f5749081SJiri Pirko { 3056f5749081SJiri Pirko struct cls_fl_filter *f = fh; 3057f5749081SJiri Pirko struct nlattr *nest; 3058f5749081SJiri Pirko struct fl_flow_key *key, *mask; 30593d81e711SVlad Buslov bool skip_hw; 3060f5749081SJiri Pirko 3061f5749081SJiri Pirko if (!f) 3062f5749081SJiri Pirko return skb->len; 3063f5749081SJiri Pirko 3064f5749081SJiri Pirko t->tcm_handle = f->handle; 3065f5749081SJiri Pirko 3066ae0be8deSMichal Kubecek nest = nla_nest_start_noflag(skb, TCA_OPTIONS); 3067f5749081SJiri Pirko if (!nest) 3068f5749081SJiri Pirko goto nla_put_failure; 3069f5749081SJiri Pirko 30703d81e711SVlad Buslov spin_lock(&tp->lock); 30713d81e711SVlad Buslov 3072f5749081SJiri Pirko if (f->res.classid && 3073f5749081SJiri Pirko nla_put_u32(skb, TCA_FLOWER_CLASSID, f->res.classid)) 30743d81e711SVlad Buslov goto nla_put_failure_locked; 3075f5749081SJiri Pirko 3076f5749081SJiri Pirko key = &f->key; 3077f5749081SJiri Pirko mask = &f->mask->key; 30783d81e711SVlad Buslov skip_hw = tc_skip_hw(f->flags); 3079f5749081SJiri Pirko 3080f5749081SJiri Pirko if (fl_dump_key(skb, net, key, mask)) 30813d81e711SVlad Buslov goto nla_put_failure_locked; 3082f5749081SJiri Pirko 3083749e6720SOr Gerlitz if (f->flags && nla_put_u32(skb, TCA_FLOWER_FLAGS, f->flags)) 30843d81e711SVlad Buslov goto nla_put_failure_locked; 30853d81e711SVlad Buslov 30863d81e711SVlad Buslov spin_unlock(&tp->lock); 30873d81e711SVlad Buslov 30883d81e711SVlad Buslov if (!skip_hw) 3089c24e43d8SVlad Buslov fl_hw_update_stats(tp, f, rtnl_held); 3090e69985c6SAmir Vadai 309186c55361SVlad Buslov if (nla_put_u32(skb, TCA_FLOWER_IN_HW_COUNT, f->in_hw_count)) 309286c55361SVlad Buslov goto nla_put_failure; 309386c55361SVlad Buslov 309477b9900eSJiri Pirko if (tcf_exts_dump(skb, &f->exts)) 309577b9900eSJiri Pirko goto nla_put_failure; 309677b9900eSJiri Pirko 309777b9900eSJiri Pirko nla_nest_end(skb, nest); 309877b9900eSJiri Pirko 309977b9900eSJiri Pirko if (tcf_exts_dump_stats(skb, &f->exts) < 0) 310077b9900eSJiri Pirko goto nla_put_failure; 310177b9900eSJiri Pirko 310277b9900eSJiri Pirko return skb->len; 310377b9900eSJiri Pirko 31043d81e711SVlad Buslov nla_put_failure_locked: 31053d81e711SVlad Buslov spin_unlock(&tp->lock); 310677b9900eSJiri Pirko nla_put_failure: 310777b9900eSJiri Pirko nla_nest_cancel(skb, nest); 310877b9900eSJiri Pirko return -1; 310977b9900eSJiri Pirko } 311077b9900eSJiri Pirko 31110348451dSVlad Buslov static int fl_terse_dump(struct net *net, struct tcf_proto *tp, void *fh, 31120348451dSVlad Buslov struct sk_buff *skb, struct tcmsg *t, bool rtnl_held) 31130348451dSVlad Buslov { 31140348451dSVlad Buslov struct cls_fl_filter *f = fh; 31150348451dSVlad Buslov struct nlattr *nest; 31160348451dSVlad Buslov bool skip_hw; 31170348451dSVlad Buslov 31180348451dSVlad Buslov if (!f) 31190348451dSVlad Buslov return skb->len; 31200348451dSVlad Buslov 31210348451dSVlad Buslov t->tcm_handle = f->handle; 31220348451dSVlad Buslov 31230348451dSVlad Buslov nest = nla_nest_start_noflag(skb, TCA_OPTIONS); 31240348451dSVlad Buslov if (!nest) 31250348451dSVlad Buslov goto nla_put_failure; 31260348451dSVlad Buslov 31270348451dSVlad Buslov spin_lock(&tp->lock); 31280348451dSVlad Buslov 31290348451dSVlad Buslov skip_hw = tc_skip_hw(f->flags); 31300348451dSVlad Buslov 31310348451dSVlad Buslov if (f->flags && nla_put_u32(skb, TCA_FLOWER_FLAGS, f->flags)) 31320348451dSVlad Buslov goto nla_put_failure_locked; 31330348451dSVlad Buslov 31340348451dSVlad Buslov spin_unlock(&tp->lock); 31350348451dSVlad Buslov 31360348451dSVlad Buslov if (!skip_hw) 31370348451dSVlad Buslov fl_hw_update_stats(tp, f, rtnl_held); 31380348451dSVlad Buslov 31390348451dSVlad Buslov if (tcf_exts_terse_dump(skb, &f->exts)) 31400348451dSVlad Buslov goto nla_put_failure; 31410348451dSVlad Buslov 31420348451dSVlad Buslov nla_nest_end(skb, nest); 31430348451dSVlad Buslov 31440348451dSVlad Buslov return skb->len; 31450348451dSVlad Buslov 31460348451dSVlad Buslov nla_put_failure_locked: 31470348451dSVlad Buslov spin_unlock(&tp->lock); 31480348451dSVlad Buslov nla_put_failure: 31490348451dSVlad Buslov nla_nest_cancel(skb, nest); 31500348451dSVlad Buslov return -1; 31510348451dSVlad Buslov } 31520348451dSVlad Buslov 3153b95ec7ebSJiri Pirko static int fl_tmplt_dump(struct sk_buff *skb, struct net *net, void *tmplt_priv) 3154b95ec7ebSJiri Pirko { 3155b95ec7ebSJiri Pirko struct fl_flow_tmplt *tmplt = tmplt_priv; 3156b95ec7ebSJiri Pirko struct fl_flow_key *key, *mask; 3157b95ec7ebSJiri Pirko struct nlattr *nest; 3158b95ec7ebSJiri Pirko 3159ae0be8deSMichal Kubecek nest = nla_nest_start_noflag(skb, TCA_OPTIONS); 3160b95ec7ebSJiri Pirko if (!nest) 3161b95ec7ebSJiri Pirko goto nla_put_failure; 3162b95ec7ebSJiri Pirko 3163b95ec7ebSJiri Pirko key = &tmplt->dummy_key; 3164b95ec7ebSJiri Pirko mask = &tmplt->mask; 3165b95ec7ebSJiri Pirko 3166b95ec7ebSJiri Pirko if (fl_dump_key(skb, net, key, mask)) 3167b95ec7ebSJiri Pirko goto nla_put_failure; 3168b95ec7ebSJiri Pirko 3169b95ec7ebSJiri Pirko nla_nest_end(skb, nest); 3170b95ec7ebSJiri Pirko 3171b95ec7ebSJiri Pirko return skb->len; 3172b95ec7ebSJiri Pirko 3173b95ec7ebSJiri Pirko nla_put_failure: 3174b95ec7ebSJiri Pirko nla_nest_cancel(skb, nest); 3175b95ec7ebSJiri Pirko return -EMSGSIZE; 3176b95ec7ebSJiri Pirko } 3177b95ec7ebSJiri Pirko 31782e24cd75SCong Wang static void fl_bind_class(void *fh, u32 classid, unsigned long cl, void *q, 31792e24cd75SCong Wang unsigned long base) 318007d79fc7SCong Wang { 318107d79fc7SCong Wang struct cls_fl_filter *f = fh; 318207d79fc7SCong Wang 31832e24cd75SCong Wang if (f && f->res.classid == classid) { 31842e24cd75SCong Wang if (cl) 31852e24cd75SCong Wang __tcf_bind_filter(q, &f->res, base); 31862e24cd75SCong Wang else 31872e24cd75SCong Wang __tcf_unbind_filter(q, &f->res); 31882e24cd75SCong Wang } 318907d79fc7SCong Wang } 319007d79fc7SCong Wang 3191a5b72a08SDavide Caratti static bool fl_delete_empty(struct tcf_proto *tp) 3192a5b72a08SDavide Caratti { 3193a5b72a08SDavide Caratti struct cls_fl_head *head = fl_head_dereference(tp); 3194a5b72a08SDavide Caratti 3195a5b72a08SDavide Caratti spin_lock(&tp->lock); 3196a5b72a08SDavide Caratti tp->deleting = idr_is_empty(&head->handle_idr); 3197a5b72a08SDavide Caratti spin_unlock(&tp->lock); 3198a5b72a08SDavide Caratti 3199a5b72a08SDavide Caratti return tp->deleting; 3200a5b72a08SDavide Caratti } 3201a5b72a08SDavide Caratti 320277b9900eSJiri Pirko static struct tcf_proto_ops cls_fl_ops __read_mostly = { 320377b9900eSJiri Pirko .kind = "flower", 320477b9900eSJiri Pirko .classify = fl_classify, 320577b9900eSJiri Pirko .init = fl_init, 320677b9900eSJiri Pirko .destroy = fl_destroy, 320777b9900eSJiri Pirko .get = fl_get, 320806177558SVlad Buslov .put = fl_put, 320977b9900eSJiri Pirko .change = fl_change, 321077b9900eSJiri Pirko .delete = fl_delete, 3211a5b72a08SDavide Caratti .delete_empty = fl_delete_empty, 321277b9900eSJiri Pirko .walk = fl_walk, 321331533cbaSJohn Hurley .reoffload = fl_reoffload, 3214a449a3e7SVlad Buslov .hw_add = fl_hw_add, 3215a449a3e7SVlad Buslov .hw_del = fl_hw_del, 321677b9900eSJiri Pirko .dump = fl_dump, 32170348451dSVlad Buslov .terse_dump = fl_terse_dump, 321807d79fc7SCong Wang .bind_class = fl_bind_class, 3219b95ec7ebSJiri Pirko .tmplt_create = fl_tmplt_create, 3220b95ec7ebSJiri Pirko .tmplt_destroy = fl_tmplt_destroy, 3221b95ec7ebSJiri Pirko .tmplt_dump = fl_tmplt_dump, 322277b9900eSJiri Pirko .owner = THIS_MODULE, 322392149190SVlad Buslov .flags = TCF_PROTO_OPS_DOIT_UNLOCKED, 322477b9900eSJiri Pirko }; 322577b9900eSJiri Pirko 322677b9900eSJiri Pirko static int __init cls_fl_init(void) 322777b9900eSJiri Pirko { 322877b9900eSJiri Pirko return register_tcf_proto_ops(&cls_fl_ops); 322977b9900eSJiri Pirko } 323077b9900eSJiri Pirko 323177b9900eSJiri Pirko static void __exit cls_fl_exit(void) 323277b9900eSJiri Pirko { 323377b9900eSJiri Pirko unregister_tcf_proto_ops(&cls_fl_ops); 323477b9900eSJiri Pirko } 323577b9900eSJiri Pirko 323677b9900eSJiri Pirko module_init(cls_fl_init); 323777b9900eSJiri Pirko module_exit(cls_fl_exit); 323877b9900eSJiri Pirko 323977b9900eSJiri Pirko MODULE_AUTHOR("Jiri Pirko <jiri@resnulli.us>"); 324077b9900eSJiri Pirko MODULE_DESCRIPTION("Flower classifier"); 324177b9900eSJiri Pirko MODULE_LICENSE("GPL v2"); 3242