177b9900eSJiri Pirko /* 277b9900eSJiri Pirko * net/sched/cls_flower.c Flower classifier 377b9900eSJiri Pirko * 477b9900eSJiri Pirko * Copyright (c) 2015 Jiri Pirko <jiri@resnulli.us> 577b9900eSJiri Pirko * 677b9900eSJiri Pirko * This program is free software; you can redistribute it and/or modify 777b9900eSJiri Pirko * it under the terms of the GNU General Public License as published by 877b9900eSJiri Pirko * the Free Software Foundation; either version 2 of the License, or 977b9900eSJiri Pirko * (at your option) any later version. 1077b9900eSJiri Pirko */ 1177b9900eSJiri Pirko 1277b9900eSJiri Pirko #include <linux/kernel.h> 1377b9900eSJiri Pirko #include <linux/init.h> 1477b9900eSJiri Pirko #include <linux/module.h> 1577b9900eSJiri Pirko #include <linux/rhashtable.h> 16d9363774SDaniel Borkmann #include <linux/workqueue.h> 1777b9900eSJiri Pirko 1877b9900eSJiri Pirko #include <linux/if_ether.h> 1977b9900eSJiri Pirko #include <linux/in6.h> 2077b9900eSJiri Pirko #include <linux/ip.h> 21a577d8f7SBenjamin LaHaise #include <linux/mpls.h> 2277b9900eSJiri Pirko 2377b9900eSJiri Pirko #include <net/sch_generic.h> 2477b9900eSJiri Pirko #include <net/pkt_cls.h> 2577b9900eSJiri Pirko #include <net/ip.h> 2677b9900eSJiri Pirko #include <net/flow_dissector.h> 2777b9900eSJiri Pirko 28bc3103f1SAmir Vadai #include <net/dst.h> 29bc3103f1SAmir Vadai #include <net/dst_metadata.h> 30bc3103f1SAmir Vadai 3177b9900eSJiri Pirko struct fl_flow_key { 3277b9900eSJiri Pirko int indev_ifindex; 3342aecaa9STom Herbert struct flow_dissector_key_control control; 34bc3103f1SAmir Vadai struct flow_dissector_key_control enc_control; 3577b9900eSJiri Pirko struct flow_dissector_key_basic basic; 3677b9900eSJiri Pirko struct flow_dissector_key_eth_addrs eth; 379399ae9aSHadar Hen Zion struct flow_dissector_key_vlan vlan; 38d64efd09SJianbo Liu struct flow_dissector_key_vlan cvlan; 3977b9900eSJiri Pirko union { 40c3f83241STom Herbert struct flow_dissector_key_ipv4_addrs ipv4; 4177b9900eSJiri Pirko struct flow_dissector_key_ipv6_addrs ipv6; 4277b9900eSJiri Pirko }; 4377b9900eSJiri Pirko struct flow_dissector_key_ports tp; 447b684884SSimon Horman struct flow_dissector_key_icmp icmp; 4599d31326SSimon Horman struct flow_dissector_key_arp arp; 46bc3103f1SAmir Vadai struct flow_dissector_key_keyid enc_key_id; 47bc3103f1SAmir Vadai union { 48bc3103f1SAmir Vadai struct flow_dissector_key_ipv4_addrs enc_ipv4; 49bc3103f1SAmir Vadai struct flow_dissector_key_ipv6_addrs enc_ipv6; 50bc3103f1SAmir Vadai }; 51f4d997fdSHadar Hen Zion struct flow_dissector_key_ports enc_tp; 52a577d8f7SBenjamin LaHaise struct flow_dissector_key_mpls mpls; 53fdfc7dd6SJiri Pirko struct flow_dissector_key_tcp tcp; 544d80cc0aSOr Gerlitz struct flow_dissector_key_ip ip; 550e2c17b6SOr Gerlitz struct flow_dissector_key_ip enc_ip; 5677b9900eSJiri Pirko } __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */ 5777b9900eSJiri Pirko 5877b9900eSJiri Pirko struct fl_flow_mask_range { 5977b9900eSJiri Pirko unsigned short int start; 6077b9900eSJiri Pirko unsigned short int end; 6177b9900eSJiri Pirko }; 6277b9900eSJiri Pirko 6377b9900eSJiri Pirko struct fl_flow_mask { 6477b9900eSJiri Pirko struct fl_flow_key key; 6577b9900eSJiri Pirko struct fl_flow_mask_range range; 6605cd271fSPaul Blakey struct rhash_head ht_node; 6705cd271fSPaul Blakey struct rhashtable ht; 6805cd271fSPaul Blakey struct rhashtable_params filter_ht_params; 6905cd271fSPaul Blakey struct flow_dissector dissector; 7005cd271fSPaul Blakey struct list_head filters; 7144a5cd43SPaolo Abeni struct rcu_work rwork; 7205cd271fSPaul Blakey struct list_head list; 7377b9900eSJiri Pirko }; 7477b9900eSJiri Pirko 75b95ec7ebSJiri Pirko struct fl_flow_tmplt { 76b95ec7ebSJiri Pirko struct fl_flow_key dummy_key; 77b95ec7ebSJiri Pirko struct fl_flow_key mask; 78b95ec7ebSJiri Pirko struct flow_dissector dissector; 79b95ec7ebSJiri Pirko struct tcf_chain *chain; 80b95ec7ebSJiri Pirko }; 81b95ec7ebSJiri Pirko 8277b9900eSJiri Pirko struct cls_fl_head { 8377b9900eSJiri Pirko struct rhashtable ht; 8405cd271fSPaul Blakey struct list_head masks; 85aaa908ffSCong Wang struct rcu_work rwork; 86c15ab236SChris Mi struct idr handle_idr; 87d9363774SDaniel Borkmann }; 8877b9900eSJiri Pirko 8977b9900eSJiri Pirko struct cls_fl_filter { 9005cd271fSPaul Blakey struct fl_flow_mask *mask; 9177b9900eSJiri Pirko struct rhash_head ht_node; 9277b9900eSJiri Pirko struct fl_flow_key mkey; 9377b9900eSJiri Pirko struct tcf_exts exts; 9477b9900eSJiri Pirko struct tcf_result res; 9577b9900eSJiri Pirko struct fl_flow_key key; 9677b9900eSJiri Pirko struct list_head list; 9777b9900eSJiri Pirko u32 handle; 98e69985c6SAmir Vadai u32 flags; 9931533cbaSJohn Hurley unsigned int in_hw_count; 100aaa908ffSCong Wang struct rcu_work rwork; 1017091d8c7SHadar Hen Zion struct net_device *hw_dev; 10277b9900eSJiri Pirko }; 10377b9900eSJiri Pirko 10405cd271fSPaul Blakey static const struct rhashtable_params mask_ht_params = { 10505cd271fSPaul Blakey .key_offset = offsetof(struct fl_flow_mask, key), 10605cd271fSPaul Blakey .key_len = sizeof(struct fl_flow_key), 10705cd271fSPaul Blakey .head_offset = offsetof(struct fl_flow_mask, ht_node), 10805cd271fSPaul Blakey .automatic_shrinking = true, 10905cd271fSPaul Blakey }; 11005cd271fSPaul Blakey 11177b9900eSJiri Pirko static unsigned short int fl_mask_range(const struct fl_flow_mask *mask) 11277b9900eSJiri Pirko { 11377b9900eSJiri Pirko return mask->range.end - mask->range.start; 11477b9900eSJiri Pirko } 11577b9900eSJiri Pirko 11677b9900eSJiri Pirko static void fl_mask_update_range(struct fl_flow_mask *mask) 11777b9900eSJiri Pirko { 11877b9900eSJiri Pirko const u8 *bytes = (const u8 *) &mask->key; 11977b9900eSJiri Pirko size_t size = sizeof(mask->key); 12005cd271fSPaul Blakey size_t i, first = 0, last; 12177b9900eSJiri Pirko 12205cd271fSPaul Blakey for (i = 0; i < size; i++) { 12377b9900eSJiri Pirko if (bytes[i]) { 12477b9900eSJiri Pirko first = i; 12505cd271fSPaul Blakey break; 12605cd271fSPaul Blakey } 12705cd271fSPaul Blakey } 12805cd271fSPaul Blakey last = first; 12905cd271fSPaul Blakey for (i = size - 1; i != first; i--) { 13005cd271fSPaul Blakey if (bytes[i]) { 13177b9900eSJiri Pirko last = i; 13205cd271fSPaul Blakey break; 13377b9900eSJiri Pirko } 13477b9900eSJiri Pirko } 13577b9900eSJiri Pirko mask->range.start = rounddown(first, sizeof(long)); 13677b9900eSJiri Pirko mask->range.end = roundup(last + 1, sizeof(long)); 13777b9900eSJiri Pirko } 13877b9900eSJiri Pirko 13977b9900eSJiri Pirko static void *fl_key_get_start(struct fl_flow_key *key, 14077b9900eSJiri Pirko const struct fl_flow_mask *mask) 14177b9900eSJiri Pirko { 14277b9900eSJiri Pirko return (u8 *) key + mask->range.start; 14377b9900eSJiri Pirko } 14477b9900eSJiri Pirko 14577b9900eSJiri Pirko static void fl_set_masked_key(struct fl_flow_key *mkey, struct fl_flow_key *key, 14677b9900eSJiri Pirko struct fl_flow_mask *mask) 14777b9900eSJiri Pirko { 14877b9900eSJiri Pirko const long *lkey = fl_key_get_start(key, mask); 14977b9900eSJiri Pirko const long *lmask = fl_key_get_start(&mask->key, mask); 15077b9900eSJiri Pirko long *lmkey = fl_key_get_start(mkey, mask); 15177b9900eSJiri Pirko int i; 15277b9900eSJiri Pirko 15377b9900eSJiri Pirko for (i = 0; i < fl_mask_range(mask); i += sizeof(long)) 15477b9900eSJiri Pirko *lmkey++ = *lkey++ & *lmask++; 15577b9900eSJiri Pirko } 15677b9900eSJiri Pirko 157b95ec7ebSJiri Pirko static bool fl_mask_fits_tmplt(struct fl_flow_tmplt *tmplt, 158b95ec7ebSJiri Pirko struct fl_flow_mask *mask) 159b95ec7ebSJiri Pirko { 160b95ec7ebSJiri Pirko const long *lmask = fl_key_get_start(&mask->key, mask); 161b95ec7ebSJiri Pirko const long *ltmplt; 162b95ec7ebSJiri Pirko int i; 163b95ec7ebSJiri Pirko 164b95ec7ebSJiri Pirko if (!tmplt) 165b95ec7ebSJiri Pirko return true; 166b95ec7ebSJiri Pirko ltmplt = fl_key_get_start(&tmplt->mask, mask); 167b95ec7ebSJiri Pirko for (i = 0; i < fl_mask_range(mask); i += sizeof(long)) { 168b95ec7ebSJiri Pirko if (~*ltmplt++ & *lmask++) 169b95ec7ebSJiri Pirko return false; 170b95ec7ebSJiri Pirko } 171b95ec7ebSJiri Pirko return true; 172b95ec7ebSJiri Pirko } 173b95ec7ebSJiri Pirko 17477b9900eSJiri Pirko static void fl_clear_masked_range(struct fl_flow_key *key, 17577b9900eSJiri Pirko struct fl_flow_mask *mask) 17677b9900eSJiri Pirko { 17777b9900eSJiri Pirko memset(fl_key_get_start(key, mask), 0, fl_mask_range(mask)); 17877b9900eSJiri Pirko } 17977b9900eSJiri Pirko 18005cd271fSPaul Blakey static struct cls_fl_filter *fl_lookup(struct fl_flow_mask *mask, 181a3308d8fSPaul Blakey struct fl_flow_key *mkey) 182a3308d8fSPaul Blakey { 18305cd271fSPaul Blakey return rhashtable_lookup_fast(&mask->ht, fl_key_get_start(mkey, mask), 18405cd271fSPaul Blakey mask->filter_ht_params); 185a3308d8fSPaul Blakey } 186a3308d8fSPaul Blakey 18777b9900eSJiri Pirko static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp, 18877b9900eSJiri Pirko struct tcf_result *res) 18977b9900eSJiri Pirko { 19077b9900eSJiri Pirko struct cls_fl_head *head = rcu_dereference_bh(tp->root); 19177b9900eSJiri Pirko struct cls_fl_filter *f; 19205cd271fSPaul Blakey struct fl_flow_mask *mask; 19377b9900eSJiri Pirko struct fl_flow_key skb_key; 19477b9900eSJiri Pirko struct fl_flow_key skb_mkey; 19577b9900eSJiri Pirko 19605cd271fSPaul Blakey list_for_each_entry_rcu(mask, &head->masks, list) { 19705cd271fSPaul Blakey fl_clear_masked_range(&skb_key, mask); 198bc3103f1SAmir Vadai 19977b9900eSJiri Pirko skb_key.indev_ifindex = skb->skb_iif; 20005cd271fSPaul Blakey /* skb_flow_dissect() does not set n_proto in case an unknown 20105cd271fSPaul Blakey * protocol, so do it rather here. 20277b9900eSJiri Pirko */ 20377b9900eSJiri Pirko skb_key.basic.n_proto = skb->protocol; 20405cd271fSPaul Blakey skb_flow_dissect_tunnel_info(skb, &mask->dissector, &skb_key); 20505cd271fSPaul Blakey skb_flow_dissect(skb, &mask->dissector, &skb_key, 0); 20677b9900eSJiri Pirko 20705cd271fSPaul Blakey fl_set_masked_key(&skb_mkey, &skb_key, mask); 20877b9900eSJiri Pirko 20905cd271fSPaul Blakey f = fl_lookup(mask, &skb_mkey); 210e8eb36cdSAmir Vadai if (f && !tc_skip_sw(f->flags)) { 21177b9900eSJiri Pirko *res = f->res; 21277b9900eSJiri Pirko return tcf_exts_exec(skb, &f->exts, res); 21377b9900eSJiri Pirko } 21405cd271fSPaul Blakey } 21577b9900eSJiri Pirko return -1; 21677b9900eSJiri Pirko } 21777b9900eSJiri Pirko 21877b9900eSJiri Pirko static int fl_init(struct tcf_proto *tp) 21977b9900eSJiri Pirko { 22077b9900eSJiri Pirko struct cls_fl_head *head; 22177b9900eSJiri Pirko 22277b9900eSJiri Pirko head = kzalloc(sizeof(*head), GFP_KERNEL); 22377b9900eSJiri Pirko if (!head) 22477b9900eSJiri Pirko return -ENOBUFS; 22577b9900eSJiri Pirko 22605cd271fSPaul Blakey INIT_LIST_HEAD_RCU(&head->masks); 22777b9900eSJiri Pirko rcu_assign_pointer(tp->root, head); 228c15ab236SChris Mi idr_init(&head->handle_idr); 22977b9900eSJiri Pirko 23005cd271fSPaul Blakey return rhashtable_init(&head->ht, &mask_ht_params); 23105cd271fSPaul Blakey } 23205cd271fSPaul Blakey 23344a5cd43SPaolo Abeni static void fl_mask_free(struct fl_flow_mask *mask) 23444a5cd43SPaolo Abeni { 23544a5cd43SPaolo Abeni rhashtable_destroy(&mask->ht); 23644a5cd43SPaolo Abeni kfree(mask); 23744a5cd43SPaolo Abeni } 23844a5cd43SPaolo Abeni 23944a5cd43SPaolo Abeni static void fl_mask_free_work(struct work_struct *work) 24044a5cd43SPaolo Abeni { 24144a5cd43SPaolo Abeni struct fl_flow_mask *mask = container_of(to_rcu_work(work), 24244a5cd43SPaolo Abeni struct fl_flow_mask, rwork); 24344a5cd43SPaolo Abeni 24444a5cd43SPaolo Abeni fl_mask_free(mask); 24544a5cd43SPaolo Abeni } 24644a5cd43SPaolo Abeni 24705cd271fSPaul Blakey static bool fl_mask_put(struct cls_fl_head *head, struct fl_flow_mask *mask, 24805cd271fSPaul Blakey bool async) 24905cd271fSPaul Blakey { 25005cd271fSPaul Blakey if (!list_empty(&mask->filters)) 25105cd271fSPaul Blakey return false; 25205cd271fSPaul Blakey 25305cd271fSPaul Blakey rhashtable_remove_fast(&head->ht, &mask->ht_node, mask_ht_params); 25405cd271fSPaul Blakey list_del_rcu(&mask->list); 25505cd271fSPaul Blakey if (async) 25644a5cd43SPaolo Abeni tcf_queue_work(&mask->rwork, fl_mask_free_work); 25705cd271fSPaul Blakey else 25844a5cd43SPaolo Abeni fl_mask_free(mask); 25905cd271fSPaul Blakey 26005cd271fSPaul Blakey return true; 26177b9900eSJiri Pirko } 26277b9900eSJiri Pirko 2630dadc117SCong Wang static void __fl_destroy_filter(struct cls_fl_filter *f) 2640dadc117SCong Wang { 2650dadc117SCong Wang tcf_exts_destroy(&f->exts); 2660dadc117SCong Wang tcf_exts_put_net(&f->exts); 2670dadc117SCong Wang kfree(f); 2680dadc117SCong Wang } 2690dadc117SCong Wang 2700552c8afSCong Wang static void fl_destroy_filter_work(struct work_struct *work) 2710552c8afSCong Wang { 272aaa908ffSCong Wang struct cls_fl_filter *f = container_of(to_rcu_work(work), 273aaa908ffSCong Wang struct cls_fl_filter, rwork); 2740552c8afSCong Wang 2750552c8afSCong Wang rtnl_lock(); 2760dadc117SCong Wang __fl_destroy_filter(f); 2770552c8afSCong Wang rtnl_unlock(); 2780552c8afSCong Wang } 2790552c8afSCong Wang 2801b0f8037SJakub Kicinski static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f, 2811b0f8037SJakub Kicinski struct netlink_ext_ack *extack) 2825b33f488SAmir Vadai { 283de4784caSJiri Pirko struct tc_cls_flower_offload cls_flower = {}; 284208c0f4bSJiri Pirko struct tcf_block *block = tp->chain->block; 2855b33f488SAmir Vadai 2861b0f8037SJakub Kicinski tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack); 287de4784caSJiri Pirko cls_flower.command = TC_CLSFLOWER_DESTROY; 288de4784caSJiri Pirko cls_flower.cookie = (unsigned long) f; 2895b33f488SAmir Vadai 290208c0f4bSJiri Pirko tc_setup_cb_call(block, &f->exts, TC_SETUP_CLSFLOWER, 291717503b9SJiri Pirko &cls_flower, false); 292caa72601SJiri Pirko tcf_block_offload_dec(block, &f->flags); 2935b33f488SAmir Vadai } 2945b33f488SAmir Vadai 295e8eb36cdSAmir Vadai static int fl_hw_replace_filter(struct tcf_proto *tp, 29641002038SQuentin Monnet struct cls_fl_filter *f, 29741002038SQuentin Monnet struct netlink_ext_ack *extack) 2985b33f488SAmir Vadai { 299de4784caSJiri Pirko struct tc_cls_flower_offload cls_flower = {}; 300208c0f4bSJiri Pirko struct tcf_block *block = tp->chain->block; 301717503b9SJiri Pirko bool skip_sw = tc_skip_sw(f->flags); 302e8eb36cdSAmir Vadai int err; 3035b33f488SAmir Vadai 304ea205940SJakub Kicinski tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack); 305de4784caSJiri Pirko cls_flower.command = TC_CLSFLOWER_REPLACE; 306de4784caSJiri Pirko cls_flower.cookie = (unsigned long) f; 30705cd271fSPaul Blakey cls_flower.dissector = &f->mask->dissector; 30805cd271fSPaul Blakey cls_flower.mask = &f->mask->key; 309de4784caSJiri Pirko cls_flower.key = &f->mkey; 310de4784caSJiri Pirko cls_flower.exts = &f->exts; 311384c181eSAmritha Nambiar cls_flower.classid = f->res.classid; 3125b33f488SAmir Vadai 313208c0f4bSJiri Pirko err = tc_setup_cb_call(block, &f->exts, TC_SETUP_CLSFLOWER, 314717503b9SJiri Pirko &cls_flower, skip_sw); 315717503b9SJiri Pirko if (err < 0) { 3161b0f8037SJakub Kicinski fl_hw_destroy_filter(tp, f, NULL); 317717503b9SJiri Pirko return err; 318717503b9SJiri Pirko } else if (err > 0) { 31931533cbaSJohn Hurley f->in_hw_count = err; 320caa72601SJiri Pirko tcf_block_offload_inc(block, &f->flags); 321717503b9SJiri Pirko } 322717503b9SJiri Pirko 323717503b9SJiri Pirko if (skip_sw && !(f->flags & TCA_CLS_FLAGS_IN_HW)) 324717503b9SJiri Pirko return -EINVAL; 325717503b9SJiri Pirko 326e8eb36cdSAmir Vadai return 0; 3275b33f488SAmir Vadai } 3285b33f488SAmir Vadai 32910cbc684SAmir Vadai static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f) 33010cbc684SAmir Vadai { 331de4784caSJiri Pirko struct tc_cls_flower_offload cls_flower = {}; 332208c0f4bSJiri Pirko struct tcf_block *block = tp->chain->block; 33310cbc684SAmir Vadai 334ea205940SJakub Kicinski tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, NULL); 335de4784caSJiri Pirko cls_flower.command = TC_CLSFLOWER_STATS; 336de4784caSJiri Pirko cls_flower.cookie = (unsigned long) f; 337de4784caSJiri Pirko cls_flower.exts = &f->exts; 338384c181eSAmritha Nambiar cls_flower.classid = f->res.classid; 33910cbc684SAmir Vadai 340208c0f4bSJiri Pirko tc_setup_cb_call(block, &f->exts, TC_SETUP_CLSFLOWER, 341717503b9SJiri Pirko &cls_flower, false); 34210cbc684SAmir Vadai } 34310cbc684SAmir Vadai 34405cd271fSPaul Blakey static bool __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, 3451b0f8037SJakub Kicinski struct netlink_ext_ack *extack) 34613fa876eSRoi Dayan { 347c15ab236SChris Mi struct cls_fl_head *head = rtnl_dereference(tp->root); 34805cd271fSPaul Blakey bool async = tcf_exts_get_net(&f->exts); 34905cd271fSPaul Blakey bool last; 350c15ab236SChris Mi 3519c160941SMatthew Wilcox idr_remove(&head->handle_idr, f->handle); 35213fa876eSRoi Dayan list_del_rcu(&f->list); 35305cd271fSPaul Blakey last = fl_mask_put(head, f->mask, async); 35479685219SHadar Hen Zion if (!tc_skip_hw(f->flags)) 3551b0f8037SJakub Kicinski fl_hw_destroy_filter(tp, f, extack); 35613fa876eSRoi Dayan tcf_unbind_filter(tp, &f->res); 35705cd271fSPaul Blakey if (async) 358aaa908ffSCong Wang tcf_queue_work(&f->rwork, fl_destroy_filter_work); 3590dadc117SCong Wang else 3600dadc117SCong Wang __fl_destroy_filter(f); 36105cd271fSPaul Blakey 36205cd271fSPaul Blakey return last; 36313fa876eSRoi Dayan } 36413fa876eSRoi Dayan 365d9363774SDaniel Borkmann static void fl_destroy_sleepable(struct work_struct *work) 366d9363774SDaniel Borkmann { 367aaa908ffSCong Wang struct cls_fl_head *head = container_of(to_rcu_work(work), 368aaa908ffSCong Wang struct cls_fl_head, 369aaa908ffSCong Wang rwork); 370de9dc650SPaul Blakey 371de9dc650SPaul Blakey rhashtable_destroy(&head->ht); 372d9363774SDaniel Borkmann kfree(head); 373d9363774SDaniel Borkmann module_put(THIS_MODULE); 374d9363774SDaniel Borkmann } 375d9363774SDaniel Borkmann 376715df5ecSJakub Kicinski static void fl_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack) 37777b9900eSJiri Pirko { 37877b9900eSJiri Pirko struct cls_fl_head *head = rtnl_dereference(tp->root); 37905cd271fSPaul Blakey struct fl_flow_mask *mask, *next_mask; 38077b9900eSJiri Pirko struct cls_fl_filter *f, *next; 38177b9900eSJiri Pirko 38205cd271fSPaul Blakey list_for_each_entry_safe(mask, next_mask, &head->masks, list) { 38305cd271fSPaul Blakey list_for_each_entry_safe(f, next, &mask->filters, list) { 38405cd271fSPaul Blakey if (__fl_delete(tp, f, extack)) 38505cd271fSPaul Blakey break; 38605cd271fSPaul Blakey } 38705cd271fSPaul Blakey } 388c15ab236SChris Mi idr_destroy(&head->handle_idr); 389d9363774SDaniel Borkmann 390d9363774SDaniel Borkmann __module_get(THIS_MODULE); 391aaa908ffSCong Wang tcf_queue_work(&head->rwork, fl_destroy_sleepable); 39277b9900eSJiri Pirko } 39377b9900eSJiri Pirko 3948113c095SWANG Cong static void *fl_get(struct tcf_proto *tp, u32 handle) 39577b9900eSJiri Pirko { 39677b9900eSJiri Pirko struct cls_fl_head *head = rtnl_dereference(tp->root); 39777b9900eSJiri Pirko 398322d884bSMatthew Wilcox return idr_find(&head->handle_idr, handle); 39977b9900eSJiri Pirko } 40077b9900eSJiri Pirko 40177b9900eSJiri Pirko static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = { 40277b9900eSJiri Pirko [TCA_FLOWER_UNSPEC] = { .type = NLA_UNSPEC }, 40377b9900eSJiri Pirko [TCA_FLOWER_CLASSID] = { .type = NLA_U32 }, 40477b9900eSJiri Pirko [TCA_FLOWER_INDEV] = { .type = NLA_STRING, 40577b9900eSJiri Pirko .len = IFNAMSIZ }, 40677b9900eSJiri Pirko [TCA_FLOWER_KEY_ETH_DST] = { .len = ETH_ALEN }, 40777b9900eSJiri Pirko [TCA_FLOWER_KEY_ETH_DST_MASK] = { .len = ETH_ALEN }, 40877b9900eSJiri Pirko [TCA_FLOWER_KEY_ETH_SRC] = { .len = ETH_ALEN }, 40977b9900eSJiri Pirko [TCA_FLOWER_KEY_ETH_SRC_MASK] = { .len = ETH_ALEN }, 41077b9900eSJiri Pirko [TCA_FLOWER_KEY_ETH_TYPE] = { .type = NLA_U16 }, 41177b9900eSJiri Pirko [TCA_FLOWER_KEY_IP_PROTO] = { .type = NLA_U8 }, 41277b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV4_SRC] = { .type = NLA_U32 }, 41377b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV4_SRC_MASK] = { .type = NLA_U32 }, 41477b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV4_DST] = { .type = NLA_U32 }, 41577b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV4_DST_MASK] = { .type = NLA_U32 }, 41677b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV6_SRC] = { .len = sizeof(struct in6_addr) }, 41777b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) }, 41877b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV6_DST] = { .len = sizeof(struct in6_addr) }, 41977b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) }, 42077b9900eSJiri Pirko [TCA_FLOWER_KEY_TCP_SRC] = { .type = NLA_U16 }, 42177b9900eSJiri Pirko [TCA_FLOWER_KEY_TCP_DST] = { .type = NLA_U16 }, 422b175c3a4SJamal Hadi Salim [TCA_FLOWER_KEY_UDP_SRC] = { .type = NLA_U16 }, 423b175c3a4SJamal Hadi Salim [TCA_FLOWER_KEY_UDP_DST] = { .type = NLA_U16 }, 4249399ae9aSHadar Hen Zion [TCA_FLOWER_KEY_VLAN_ID] = { .type = NLA_U16 }, 4259399ae9aSHadar Hen Zion [TCA_FLOWER_KEY_VLAN_PRIO] = { .type = NLA_U8 }, 4269399ae9aSHadar Hen Zion [TCA_FLOWER_KEY_VLAN_ETH_TYPE] = { .type = NLA_U16 }, 427bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_KEY_ID] = { .type = NLA_U32 }, 428bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV4_SRC] = { .type = NLA_U32 }, 429bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] = { .type = NLA_U32 }, 430bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV4_DST] = { .type = NLA_U32 }, 431bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] = { .type = NLA_U32 }, 432bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV6_SRC] = { .len = sizeof(struct in6_addr) }, 433bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) }, 434bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV6_DST] = { .len = sizeof(struct in6_addr) }, 435bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) }, 436aa72d708SOr Gerlitz [TCA_FLOWER_KEY_TCP_SRC_MASK] = { .type = NLA_U16 }, 437aa72d708SOr Gerlitz [TCA_FLOWER_KEY_TCP_DST_MASK] = { .type = NLA_U16 }, 438aa72d708SOr Gerlitz [TCA_FLOWER_KEY_UDP_SRC_MASK] = { .type = NLA_U16 }, 439aa72d708SOr Gerlitz [TCA_FLOWER_KEY_UDP_DST_MASK] = { .type = NLA_U16 }, 4405976c5f4SSimon Horman [TCA_FLOWER_KEY_SCTP_SRC_MASK] = { .type = NLA_U16 }, 4415976c5f4SSimon Horman [TCA_FLOWER_KEY_SCTP_DST_MASK] = { .type = NLA_U16 }, 4425976c5f4SSimon Horman [TCA_FLOWER_KEY_SCTP_SRC] = { .type = NLA_U16 }, 4435976c5f4SSimon Horman [TCA_FLOWER_KEY_SCTP_DST] = { .type = NLA_U16 }, 444f4d997fdSHadar Hen Zion [TCA_FLOWER_KEY_ENC_UDP_SRC_PORT] = { .type = NLA_U16 }, 445f4d997fdSHadar Hen Zion [TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK] = { .type = NLA_U16 }, 446f4d997fdSHadar Hen Zion [TCA_FLOWER_KEY_ENC_UDP_DST_PORT] = { .type = NLA_U16 }, 447f4d997fdSHadar Hen Zion [TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK] = { .type = NLA_U16 }, 448faa3ffceSOr Gerlitz [TCA_FLOWER_KEY_FLAGS] = { .type = NLA_U32 }, 449faa3ffceSOr Gerlitz [TCA_FLOWER_KEY_FLAGS_MASK] = { .type = NLA_U32 }, 4507b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV4_TYPE] = { .type = NLA_U8 }, 4517b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV4_TYPE_MASK] = { .type = NLA_U8 }, 4527b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV4_CODE] = { .type = NLA_U8 }, 4537b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV4_CODE_MASK] = { .type = NLA_U8 }, 4547b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV6_TYPE] = { .type = NLA_U8 }, 4557b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV6_TYPE_MASK] = { .type = NLA_U8 }, 4567b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV6_CODE] = { .type = NLA_U8 }, 4577b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV6_CODE_MASK] = { .type = NLA_U8 }, 45899d31326SSimon Horman [TCA_FLOWER_KEY_ARP_SIP] = { .type = NLA_U32 }, 45999d31326SSimon Horman [TCA_FLOWER_KEY_ARP_SIP_MASK] = { .type = NLA_U32 }, 46099d31326SSimon Horman [TCA_FLOWER_KEY_ARP_TIP] = { .type = NLA_U32 }, 46199d31326SSimon Horman [TCA_FLOWER_KEY_ARP_TIP_MASK] = { .type = NLA_U32 }, 46299d31326SSimon Horman [TCA_FLOWER_KEY_ARP_OP] = { .type = NLA_U8 }, 46399d31326SSimon Horman [TCA_FLOWER_KEY_ARP_OP_MASK] = { .type = NLA_U8 }, 46499d31326SSimon Horman [TCA_FLOWER_KEY_ARP_SHA] = { .len = ETH_ALEN }, 46599d31326SSimon Horman [TCA_FLOWER_KEY_ARP_SHA_MASK] = { .len = ETH_ALEN }, 46699d31326SSimon Horman [TCA_FLOWER_KEY_ARP_THA] = { .len = ETH_ALEN }, 46799d31326SSimon Horman [TCA_FLOWER_KEY_ARP_THA_MASK] = { .len = ETH_ALEN }, 468a577d8f7SBenjamin LaHaise [TCA_FLOWER_KEY_MPLS_TTL] = { .type = NLA_U8 }, 469a577d8f7SBenjamin LaHaise [TCA_FLOWER_KEY_MPLS_BOS] = { .type = NLA_U8 }, 470a577d8f7SBenjamin LaHaise [TCA_FLOWER_KEY_MPLS_TC] = { .type = NLA_U8 }, 471a577d8f7SBenjamin LaHaise [TCA_FLOWER_KEY_MPLS_LABEL] = { .type = NLA_U32 }, 472fdfc7dd6SJiri Pirko [TCA_FLOWER_KEY_TCP_FLAGS] = { .type = NLA_U16 }, 473fdfc7dd6SJiri Pirko [TCA_FLOWER_KEY_TCP_FLAGS_MASK] = { .type = NLA_U16 }, 4744d80cc0aSOr Gerlitz [TCA_FLOWER_KEY_IP_TOS] = { .type = NLA_U8 }, 4754d80cc0aSOr Gerlitz [TCA_FLOWER_KEY_IP_TOS_MASK] = { .type = NLA_U8 }, 4764d80cc0aSOr Gerlitz [TCA_FLOWER_KEY_IP_TTL] = { .type = NLA_U8 }, 4774d80cc0aSOr Gerlitz [TCA_FLOWER_KEY_IP_TTL_MASK] = { .type = NLA_U8 }, 478d64efd09SJianbo Liu [TCA_FLOWER_KEY_CVLAN_ID] = { .type = NLA_U16 }, 479d64efd09SJianbo Liu [TCA_FLOWER_KEY_CVLAN_PRIO] = { .type = NLA_U8 }, 480d64efd09SJianbo Liu [TCA_FLOWER_KEY_CVLAN_ETH_TYPE] = { .type = NLA_U16 }, 4810e2c17b6SOr Gerlitz [TCA_FLOWER_KEY_ENC_IP_TOS] = { .type = NLA_U8 }, 4820e2c17b6SOr Gerlitz [TCA_FLOWER_KEY_ENC_IP_TOS_MASK] = { .type = NLA_U8 }, 4830e2c17b6SOr Gerlitz [TCA_FLOWER_KEY_ENC_IP_TTL] = { .type = NLA_U8 }, 4840e2c17b6SOr Gerlitz [TCA_FLOWER_KEY_ENC_IP_TTL_MASK] = { .type = NLA_U8 }, 48577b9900eSJiri Pirko }; 48677b9900eSJiri Pirko 48777b9900eSJiri Pirko static void fl_set_key_val(struct nlattr **tb, 48877b9900eSJiri Pirko void *val, int val_type, 48977b9900eSJiri Pirko void *mask, int mask_type, int len) 49077b9900eSJiri Pirko { 49177b9900eSJiri Pirko if (!tb[val_type]) 49277b9900eSJiri Pirko return; 49377b9900eSJiri Pirko memcpy(val, nla_data(tb[val_type]), len); 49477b9900eSJiri Pirko if (mask_type == TCA_FLOWER_UNSPEC || !tb[mask_type]) 49577b9900eSJiri Pirko memset(mask, 0xff, len); 49677b9900eSJiri Pirko else 49777b9900eSJiri Pirko memcpy(mask, nla_data(tb[mask_type]), len); 49877b9900eSJiri Pirko } 49977b9900eSJiri Pirko 5001a7fca63SBenjamin LaHaise static int fl_set_key_mpls(struct nlattr **tb, 501a577d8f7SBenjamin LaHaise struct flow_dissector_key_mpls *key_val, 502a577d8f7SBenjamin LaHaise struct flow_dissector_key_mpls *key_mask) 503a577d8f7SBenjamin LaHaise { 504a577d8f7SBenjamin LaHaise if (tb[TCA_FLOWER_KEY_MPLS_TTL]) { 505a577d8f7SBenjamin LaHaise key_val->mpls_ttl = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TTL]); 506a577d8f7SBenjamin LaHaise key_mask->mpls_ttl = MPLS_TTL_MASK; 507a577d8f7SBenjamin LaHaise } 508a577d8f7SBenjamin LaHaise if (tb[TCA_FLOWER_KEY_MPLS_BOS]) { 5091a7fca63SBenjamin LaHaise u8 bos = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_BOS]); 5101a7fca63SBenjamin LaHaise 5111a7fca63SBenjamin LaHaise if (bos & ~MPLS_BOS_MASK) 5121a7fca63SBenjamin LaHaise return -EINVAL; 5131a7fca63SBenjamin LaHaise key_val->mpls_bos = bos; 514a577d8f7SBenjamin LaHaise key_mask->mpls_bos = MPLS_BOS_MASK; 515a577d8f7SBenjamin LaHaise } 516a577d8f7SBenjamin LaHaise if (tb[TCA_FLOWER_KEY_MPLS_TC]) { 5171a7fca63SBenjamin LaHaise u8 tc = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TC]); 5181a7fca63SBenjamin LaHaise 5191a7fca63SBenjamin LaHaise if (tc & ~MPLS_TC_MASK) 5201a7fca63SBenjamin LaHaise return -EINVAL; 5211a7fca63SBenjamin LaHaise key_val->mpls_tc = tc; 522a577d8f7SBenjamin LaHaise key_mask->mpls_tc = MPLS_TC_MASK; 523a577d8f7SBenjamin LaHaise } 524a577d8f7SBenjamin LaHaise if (tb[TCA_FLOWER_KEY_MPLS_LABEL]) { 5251a7fca63SBenjamin LaHaise u32 label = nla_get_u32(tb[TCA_FLOWER_KEY_MPLS_LABEL]); 5261a7fca63SBenjamin LaHaise 5271a7fca63SBenjamin LaHaise if (label & ~MPLS_LABEL_MASK) 5281a7fca63SBenjamin LaHaise return -EINVAL; 5291a7fca63SBenjamin LaHaise key_val->mpls_label = label; 530a577d8f7SBenjamin LaHaise key_mask->mpls_label = MPLS_LABEL_MASK; 531a577d8f7SBenjamin LaHaise } 5321a7fca63SBenjamin LaHaise return 0; 533a577d8f7SBenjamin LaHaise } 534a577d8f7SBenjamin LaHaise 5359399ae9aSHadar Hen Zion static void fl_set_key_vlan(struct nlattr **tb, 536aaab0834SJianbo Liu __be16 ethertype, 537d64efd09SJianbo Liu int vlan_id_key, int vlan_prio_key, 5389399ae9aSHadar Hen Zion struct flow_dissector_key_vlan *key_val, 5399399ae9aSHadar Hen Zion struct flow_dissector_key_vlan *key_mask) 5409399ae9aSHadar Hen Zion { 5419399ae9aSHadar Hen Zion #define VLAN_PRIORITY_MASK 0x7 5429399ae9aSHadar Hen Zion 543d64efd09SJianbo Liu if (tb[vlan_id_key]) { 5449399ae9aSHadar Hen Zion key_val->vlan_id = 545d64efd09SJianbo Liu nla_get_u16(tb[vlan_id_key]) & VLAN_VID_MASK; 5469399ae9aSHadar Hen Zion key_mask->vlan_id = VLAN_VID_MASK; 5479399ae9aSHadar Hen Zion } 548d64efd09SJianbo Liu if (tb[vlan_prio_key]) { 5499399ae9aSHadar Hen Zion key_val->vlan_priority = 550d64efd09SJianbo Liu nla_get_u8(tb[vlan_prio_key]) & 5519399ae9aSHadar Hen Zion VLAN_PRIORITY_MASK; 5529399ae9aSHadar Hen Zion key_mask->vlan_priority = VLAN_PRIORITY_MASK; 5539399ae9aSHadar Hen Zion } 554aaab0834SJianbo Liu key_val->vlan_tpid = ethertype; 555aaab0834SJianbo Liu key_mask->vlan_tpid = cpu_to_be16(~0); 5569399ae9aSHadar Hen Zion } 5579399ae9aSHadar Hen Zion 558faa3ffceSOr Gerlitz static void fl_set_key_flag(u32 flower_key, u32 flower_mask, 559faa3ffceSOr Gerlitz u32 *dissector_key, u32 *dissector_mask, 560faa3ffceSOr Gerlitz u32 flower_flag_bit, u32 dissector_flag_bit) 561faa3ffceSOr Gerlitz { 562faa3ffceSOr Gerlitz if (flower_mask & flower_flag_bit) { 563faa3ffceSOr Gerlitz *dissector_mask |= dissector_flag_bit; 564faa3ffceSOr Gerlitz if (flower_key & flower_flag_bit) 565faa3ffceSOr Gerlitz *dissector_key |= dissector_flag_bit; 566faa3ffceSOr Gerlitz } 567faa3ffceSOr Gerlitz } 568faa3ffceSOr Gerlitz 569d9724772SOr Gerlitz static int fl_set_key_flags(struct nlattr **tb, 570faa3ffceSOr Gerlitz u32 *flags_key, u32 *flags_mask) 571faa3ffceSOr Gerlitz { 572faa3ffceSOr Gerlitz u32 key, mask; 573faa3ffceSOr Gerlitz 574d9724772SOr Gerlitz /* mask is mandatory for flags */ 575d9724772SOr Gerlitz if (!tb[TCA_FLOWER_KEY_FLAGS_MASK]) 576d9724772SOr Gerlitz return -EINVAL; 577faa3ffceSOr Gerlitz 578faa3ffceSOr Gerlitz key = be32_to_cpu(nla_get_u32(tb[TCA_FLOWER_KEY_FLAGS])); 579faa3ffceSOr Gerlitz mask = be32_to_cpu(nla_get_u32(tb[TCA_FLOWER_KEY_FLAGS_MASK])); 580faa3ffceSOr Gerlitz 581faa3ffceSOr Gerlitz *flags_key = 0; 582faa3ffceSOr Gerlitz *flags_mask = 0; 583faa3ffceSOr Gerlitz 584faa3ffceSOr Gerlitz fl_set_key_flag(key, mask, flags_key, flags_mask, 585faa3ffceSOr Gerlitz TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT); 586459d153dSPieter Jansen van Vuuren fl_set_key_flag(key, mask, flags_key, flags_mask, 587459d153dSPieter Jansen van Vuuren TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST, 588459d153dSPieter Jansen van Vuuren FLOW_DIS_FIRST_FRAG); 589d9724772SOr Gerlitz 590d9724772SOr Gerlitz return 0; 591faa3ffceSOr Gerlitz } 592faa3ffceSOr Gerlitz 5930e2c17b6SOr Gerlitz static void fl_set_key_ip(struct nlattr **tb, bool encap, 5944d80cc0aSOr Gerlitz struct flow_dissector_key_ip *key, 5954d80cc0aSOr Gerlitz struct flow_dissector_key_ip *mask) 5964d80cc0aSOr Gerlitz { 5970e2c17b6SOr Gerlitz int tos_key = encap ? TCA_FLOWER_KEY_ENC_IP_TOS : TCA_FLOWER_KEY_IP_TOS; 5980e2c17b6SOr Gerlitz int ttl_key = encap ? TCA_FLOWER_KEY_ENC_IP_TTL : TCA_FLOWER_KEY_IP_TTL; 5990e2c17b6SOr Gerlitz int tos_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TOS_MASK : TCA_FLOWER_KEY_IP_TOS_MASK; 6000e2c17b6SOr Gerlitz int ttl_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TTL_MASK : TCA_FLOWER_KEY_IP_TTL_MASK; 6014d80cc0aSOr Gerlitz 6020e2c17b6SOr Gerlitz fl_set_key_val(tb, &key->tos, tos_key, &mask->tos, tos_mask, sizeof(key->tos)); 6030e2c17b6SOr Gerlitz fl_set_key_val(tb, &key->ttl, ttl_key, &mask->ttl, ttl_mask, sizeof(key->ttl)); 6044d80cc0aSOr Gerlitz } 6054d80cc0aSOr Gerlitz 60677b9900eSJiri Pirko static int fl_set_key(struct net *net, struct nlattr **tb, 6071057c55fSAlexander Aring struct fl_flow_key *key, struct fl_flow_key *mask, 6081057c55fSAlexander Aring struct netlink_ext_ack *extack) 60977b9900eSJiri Pirko { 6109399ae9aSHadar Hen Zion __be16 ethertype; 611d9724772SOr Gerlitz int ret = 0; 612dd3aa3b5SBrian Haley #ifdef CONFIG_NET_CLS_IND 61377b9900eSJiri Pirko if (tb[TCA_FLOWER_INDEV]) { 6141057c55fSAlexander Aring int err = tcf_change_indev(net, tb[TCA_FLOWER_INDEV], extack); 61577b9900eSJiri Pirko if (err < 0) 61677b9900eSJiri Pirko return err; 61777b9900eSJiri Pirko key->indev_ifindex = err; 61877b9900eSJiri Pirko mask->indev_ifindex = 0xffffffff; 61977b9900eSJiri Pirko } 620dd3aa3b5SBrian Haley #endif 62177b9900eSJiri Pirko 62277b9900eSJiri Pirko fl_set_key_val(tb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST, 62377b9900eSJiri Pirko mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK, 62477b9900eSJiri Pirko sizeof(key->eth.dst)); 62577b9900eSJiri Pirko fl_set_key_val(tb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC, 62677b9900eSJiri Pirko mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK, 62777b9900eSJiri Pirko sizeof(key->eth.src)); 62866530bdfSJamal Hadi Salim 6290b498a52SArnd Bergmann if (tb[TCA_FLOWER_KEY_ETH_TYPE]) { 6309399ae9aSHadar Hen Zion ethertype = nla_get_be16(tb[TCA_FLOWER_KEY_ETH_TYPE]); 6319399ae9aSHadar Hen Zion 632aaab0834SJianbo Liu if (eth_type_vlan(ethertype)) { 633d64efd09SJianbo Liu fl_set_key_vlan(tb, ethertype, TCA_FLOWER_KEY_VLAN_ID, 634d64efd09SJianbo Liu TCA_FLOWER_KEY_VLAN_PRIO, &key->vlan, 635d64efd09SJianbo Liu &mask->vlan); 636d64efd09SJianbo Liu 6375e9a0fe4SJianbo Liu if (tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]) { 638d64efd09SJianbo Liu ethertype = nla_get_be16(tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]); 639d64efd09SJianbo Liu if (eth_type_vlan(ethertype)) { 640d64efd09SJianbo Liu fl_set_key_vlan(tb, ethertype, 641d64efd09SJianbo Liu TCA_FLOWER_KEY_CVLAN_ID, 642d64efd09SJianbo Liu TCA_FLOWER_KEY_CVLAN_PRIO, 643d64efd09SJianbo Liu &key->cvlan, &mask->cvlan); 6449399ae9aSHadar Hen Zion fl_set_key_val(tb, &key->basic.n_proto, 645d64efd09SJianbo Liu TCA_FLOWER_KEY_CVLAN_ETH_TYPE, 646d64efd09SJianbo Liu &mask->basic.n_proto, 647d64efd09SJianbo Liu TCA_FLOWER_UNSPEC, 64877b9900eSJiri Pirko sizeof(key->basic.n_proto)); 6499399ae9aSHadar Hen Zion } else { 6509399ae9aSHadar Hen Zion key->basic.n_proto = ethertype; 6519399ae9aSHadar Hen Zion mask->basic.n_proto = cpu_to_be16(~0); 6529399ae9aSHadar Hen Zion } 6535e9a0fe4SJianbo Liu } 654d64efd09SJianbo Liu } else { 655d64efd09SJianbo Liu key->basic.n_proto = ethertype; 656d64efd09SJianbo Liu mask->basic.n_proto = cpu_to_be16(~0); 657d64efd09SJianbo Liu } 6580b498a52SArnd Bergmann } 65966530bdfSJamal Hadi Salim 66077b9900eSJiri Pirko if (key->basic.n_proto == htons(ETH_P_IP) || 66177b9900eSJiri Pirko key->basic.n_proto == htons(ETH_P_IPV6)) { 66277b9900eSJiri Pirko fl_set_key_val(tb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO, 66377b9900eSJiri Pirko &mask->basic.ip_proto, TCA_FLOWER_UNSPEC, 66477b9900eSJiri Pirko sizeof(key->basic.ip_proto)); 6650e2c17b6SOr Gerlitz fl_set_key_ip(tb, false, &key->ip, &mask->ip); 66677b9900eSJiri Pirko } 66766530bdfSJamal Hadi Salim 66866530bdfSJamal Hadi Salim if (tb[TCA_FLOWER_KEY_IPV4_SRC] || tb[TCA_FLOWER_KEY_IPV4_DST]) { 66966530bdfSJamal Hadi Salim key->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; 670970bfcd0SPaul Blakey mask->control.addr_type = ~0; 67177b9900eSJiri Pirko fl_set_key_val(tb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC, 67277b9900eSJiri Pirko &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK, 67377b9900eSJiri Pirko sizeof(key->ipv4.src)); 67477b9900eSJiri Pirko fl_set_key_val(tb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST, 67577b9900eSJiri Pirko &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK, 67677b9900eSJiri Pirko sizeof(key->ipv4.dst)); 67766530bdfSJamal Hadi Salim } else if (tb[TCA_FLOWER_KEY_IPV6_SRC] || tb[TCA_FLOWER_KEY_IPV6_DST]) { 67866530bdfSJamal Hadi Salim key->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; 679970bfcd0SPaul Blakey mask->control.addr_type = ~0; 68077b9900eSJiri Pirko fl_set_key_val(tb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC, 68177b9900eSJiri Pirko &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK, 68277b9900eSJiri Pirko sizeof(key->ipv6.src)); 68377b9900eSJiri Pirko fl_set_key_val(tb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST, 68477b9900eSJiri Pirko &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK, 68577b9900eSJiri Pirko sizeof(key->ipv6.dst)); 68677b9900eSJiri Pirko } 68766530bdfSJamal Hadi Salim 68877b9900eSJiri Pirko if (key->basic.ip_proto == IPPROTO_TCP) { 68977b9900eSJiri Pirko fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC, 690aa72d708SOr Gerlitz &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK, 69177b9900eSJiri Pirko sizeof(key->tp.src)); 69277b9900eSJiri Pirko fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST, 693aa72d708SOr Gerlitz &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK, 69477b9900eSJiri Pirko sizeof(key->tp.dst)); 695fdfc7dd6SJiri Pirko fl_set_key_val(tb, &key->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS, 696fdfc7dd6SJiri Pirko &mask->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS_MASK, 697fdfc7dd6SJiri Pirko sizeof(key->tcp.flags)); 69877b9900eSJiri Pirko } else if (key->basic.ip_proto == IPPROTO_UDP) { 69977b9900eSJiri Pirko fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC, 700aa72d708SOr Gerlitz &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK, 70177b9900eSJiri Pirko sizeof(key->tp.src)); 70277b9900eSJiri Pirko fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST, 703aa72d708SOr Gerlitz &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK, 70477b9900eSJiri Pirko sizeof(key->tp.dst)); 7055976c5f4SSimon Horman } else if (key->basic.ip_proto == IPPROTO_SCTP) { 7065976c5f4SSimon Horman fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC, 7075976c5f4SSimon Horman &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK, 7085976c5f4SSimon Horman sizeof(key->tp.src)); 7095976c5f4SSimon Horman fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST, 7105976c5f4SSimon Horman &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK, 7115976c5f4SSimon Horman sizeof(key->tp.dst)); 7127b684884SSimon Horman } else if (key->basic.n_proto == htons(ETH_P_IP) && 7137b684884SSimon Horman key->basic.ip_proto == IPPROTO_ICMP) { 7147b684884SSimon Horman fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV4_TYPE, 7157b684884SSimon Horman &mask->icmp.type, 7167b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_TYPE_MASK, 7177b684884SSimon Horman sizeof(key->icmp.type)); 7187b684884SSimon Horman fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV4_CODE, 7197b684884SSimon Horman &mask->icmp.code, 7207b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_CODE_MASK, 7217b684884SSimon Horman sizeof(key->icmp.code)); 7227b684884SSimon Horman } else if (key->basic.n_proto == htons(ETH_P_IPV6) && 7237b684884SSimon Horman key->basic.ip_proto == IPPROTO_ICMPV6) { 7247b684884SSimon Horman fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV6_TYPE, 7257b684884SSimon Horman &mask->icmp.type, 7267b684884SSimon Horman TCA_FLOWER_KEY_ICMPV6_TYPE_MASK, 7277b684884SSimon Horman sizeof(key->icmp.type)); 728040587afSSimon Horman fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV6_CODE, 7297b684884SSimon Horman &mask->icmp.code, 730040587afSSimon Horman TCA_FLOWER_KEY_ICMPV6_CODE_MASK, 7317b684884SSimon Horman sizeof(key->icmp.code)); 732a577d8f7SBenjamin LaHaise } else if (key->basic.n_proto == htons(ETH_P_MPLS_UC) || 733a577d8f7SBenjamin LaHaise key->basic.n_proto == htons(ETH_P_MPLS_MC)) { 7341a7fca63SBenjamin LaHaise ret = fl_set_key_mpls(tb, &key->mpls, &mask->mpls); 7351a7fca63SBenjamin LaHaise if (ret) 7361a7fca63SBenjamin LaHaise return ret; 73799d31326SSimon Horman } else if (key->basic.n_proto == htons(ETH_P_ARP) || 73899d31326SSimon Horman key->basic.n_proto == htons(ETH_P_RARP)) { 73999d31326SSimon Horman fl_set_key_val(tb, &key->arp.sip, TCA_FLOWER_KEY_ARP_SIP, 74099d31326SSimon Horman &mask->arp.sip, TCA_FLOWER_KEY_ARP_SIP_MASK, 74199d31326SSimon Horman sizeof(key->arp.sip)); 74299d31326SSimon Horman fl_set_key_val(tb, &key->arp.tip, TCA_FLOWER_KEY_ARP_TIP, 74399d31326SSimon Horman &mask->arp.tip, TCA_FLOWER_KEY_ARP_TIP_MASK, 74499d31326SSimon Horman sizeof(key->arp.tip)); 74599d31326SSimon Horman fl_set_key_val(tb, &key->arp.op, TCA_FLOWER_KEY_ARP_OP, 74699d31326SSimon Horman &mask->arp.op, TCA_FLOWER_KEY_ARP_OP_MASK, 74799d31326SSimon Horman sizeof(key->arp.op)); 74899d31326SSimon Horman fl_set_key_val(tb, key->arp.sha, TCA_FLOWER_KEY_ARP_SHA, 74999d31326SSimon Horman mask->arp.sha, TCA_FLOWER_KEY_ARP_SHA_MASK, 75099d31326SSimon Horman sizeof(key->arp.sha)); 75199d31326SSimon Horman fl_set_key_val(tb, key->arp.tha, TCA_FLOWER_KEY_ARP_THA, 75299d31326SSimon Horman mask->arp.tha, TCA_FLOWER_KEY_ARP_THA_MASK, 75399d31326SSimon Horman sizeof(key->arp.tha)); 75477b9900eSJiri Pirko } 75577b9900eSJiri Pirko 756bc3103f1SAmir Vadai if (tb[TCA_FLOWER_KEY_ENC_IPV4_SRC] || 757bc3103f1SAmir Vadai tb[TCA_FLOWER_KEY_ENC_IPV4_DST]) { 758bc3103f1SAmir Vadai key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; 759970bfcd0SPaul Blakey mask->enc_control.addr_type = ~0; 760bc3103f1SAmir Vadai fl_set_key_val(tb, &key->enc_ipv4.src, 761bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_SRC, 762bc3103f1SAmir Vadai &mask->enc_ipv4.src, 763bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK, 764bc3103f1SAmir Vadai sizeof(key->enc_ipv4.src)); 765bc3103f1SAmir Vadai fl_set_key_val(tb, &key->enc_ipv4.dst, 766bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_DST, 767bc3103f1SAmir Vadai &mask->enc_ipv4.dst, 768bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_DST_MASK, 769bc3103f1SAmir Vadai sizeof(key->enc_ipv4.dst)); 770bc3103f1SAmir Vadai } 771bc3103f1SAmir Vadai 772bc3103f1SAmir Vadai if (tb[TCA_FLOWER_KEY_ENC_IPV6_SRC] || 773bc3103f1SAmir Vadai tb[TCA_FLOWER_KEY_ENC_IPV6_DST]) { 774bc3103f1SAmir Vadai key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; 775970bfcd0SPaul Blakey mask->enc_control.addr_type = ~0; 776bc3103f1SAmir Vadai fl_set_key_val(tb, &key->enc_ipv6.src, 777bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_SRC, 778bc3103f1SAmir Vadai &mask->enc_ipv6.src, 779bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK, 780bc3103f1SAmir Vadai sizeof(key->enc_ipv6.src)); 781bc3103f1SAmir Vadai fl_set_key_val(tb, &key->enc_ipv6.dst, 782bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_DST, 783bc3103f1SAmir Vadai &mask->enc_ipv6.dst, 784bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_DST_MASK, 785bc3103f1SAmir Vadai sizeof(key->enc_ipv6.dst)); 786bc3103f1SAmir Vadai } 787bc3103f1SAmir Vadai 788bc3103f1SAmir Vadai fl_set_key_val(tb, &key->enc_key_id.keyid, TCA_FLOWER_KEY_ENC_KEY_ID, 789eb523f42SHadar Hen Zion &mask->enc_key_id.keyid, TCA_FLOWER_UNSPEC, 790bc3103f1SAmir Vadai sizeof(key->enc_key_id.keyid)); 791bc3103f1SAmir Vadai 792f4d997fdSHadar Hen Zion fl_set_key_val(tb, &key->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT, 793f4d997fdSHadar Hen Zion &mask->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK, 794f4d997fdSHadar Hen Zion sizeof(key->enc_tp.src)); 795f4d997fdSHadar Hen Zion 796f4d997fdSHadar Hen Zion fl_set_key_val(tb, &key->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT, 797f4d997fdSHadar Hen Zion &mask->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK, 798f4d997fdSHadar Hen Zion sizeof(key->enc_tp.dst)); 799f4d997fdSHadar Hen Zion 8000e2c17b6SOr Gerlitz fl_set_key_ip(tb, true, &key->enc_ip, &mask->enc_ip); 8010e2c17b6SOr Gerlitz 802d9724772SOr Gerlitz if (tb[TCA_FLOWER_KEY_FLAGS]) 803d9724772SOr Gerlitz ret = fl_set_key_flags(tb, &key->control.flags, &mask->control.flags); 804faa3ffceSOr Gerlitz 805d9724772SOr Gerlitz return ret; 80677b9900eSJiri Pirko } 80777b9900eSJiri Pirko 80805cd271fSPaul Blakey static void fl_mask_copy(struct fl_flow_mask *dst, 80905cd271fSPaul Blakey struct fl_flow_mask *src) 81077b9900eSJiri Pirko { 81105cd271fSPaul Blakey const void *psrc = fl_key_get_start(&src->key, src); 81205cd271fSPaul Blakey void *pdst = fl_key_get_start(&dst->key, src); 81377b9900eSJiri Pirko 81405cd271fSPaul Blakey memcpy(pdst, psrc, fl_mask_range(src)); 81505cd271fSPaul Blakey dst->range = src->range; 81677b9900eSJiri Pirko } 81777b9900eSJiri Pirko 81877b9900eSJiri Pirko static const struct rhashtable_params fl_ht_params = { 81977b9900eSJiri Pirko .key_offset = offsetof(struct cls_fl_filter, mkey), /* base offset */ 82077b9900eSJiri Pirko .head_offset = offsetof(struct cls_fl_filter, ht_node), 82177b9900eSJiri Pirko .automatic_shrinking = true, 82277b9900eSJiri Pirko }; 82377b9900eSJiri Pirko 82405cd271fSPaul Blakey static int fl_init_mask_hashtable(struct fl_flow_mask *mask) 82577b9900eSJiri Pirko { 82605cd271fSPaul Blakey mask->filter_ht_params = fl_ht_params; 82705cd271fSPaul Blakey mask->filter_ht_params.key_len = fl_mask_range(mask); 82805cd271fSPaul Blakey mask->filter_ht_params.key_offset += mask->range.start; 82977b9900eSJiri Pirko 83005cd271fSPaul Blakey return rhashtable_init(&mask->ht, &mask->filter_ht_params); 83177b9900eSJiri Pirko } 83277b9900eSJiri Pirko 83377b9900eSJiri Pirko #define FL_KEY_MEMBER_OFFSET(member) offsetof(struct fl_flow_key, member) 83477b9900eSJiri Pirko #define FL_KEY_MEMBER_SIZE(member) (sizeof(((struct fl_flow_key *) 0)->member)) 83577b9900eSJiri Pirko 836339ba878SHadar Hen Zion #define FL_KEY_IS_MASKED(mask, member) \ 837339ba878SHadar Hen Zion memchr_inv(((char *)mask) + FL_KEY_MEMBER_OFFSET(member), \ 838339ba878SHadar Hen Zion 0, FL_KEY_MEMBER_SIZE(member)) \ 83977b9900eSJiri Pirko 84077b9900eSJiri Pirko #define FL_KEY_SET(keys, cnt, id, member) \ 84177b9900eSJiri Pirko do { \ 84277b9900eSJiri Pirko keys[cnt].key_id = id; \ 84377b9900eSJiri Pirko keys[cnt].offset = FL_KEY_MEMBER_OFFSET(member); \ 84477b9900eSJiri Pirko cnt++; \ 84577b9900eSJiri Pirko } while(0); 84677b9900eSJiri Pirko 847339ba878SHadar Hen Zion #define FL_KEY_SET_IF_MASKED(mask, keys, cnt, id, member) \ 84877b9900eSJiri Pirko do { \ 849339ba878SHadar Hen Zion if (FL_KEY_IS_MASKED(mask, member)) \ 85077b9900eSJiri Pirko FL_KEY_SET(keys, cnt, id, member); \ 85177b9900eSJiri Pirko } while(0); 85277b9900eSJiri Pirko 85333fb5cbaSJiri Pirko static void fl_init_dissector(struct flow_dissector *dissector, 85433fb5cbaSJiri Pirko struct fl_flow_key *mask) 85577b9900eSJiri Pirko { 85677b9900eSJiri Pirko struct flow_dissector_key keys[FLOW_DISSECTOR_KEY_MAX]; 85777b9900eSJiri Pirko size_t cnt = 0; 85877b9900eSJiri Pirko 85942aecaa9STom Herbert FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_CONTROL, control); 86077b9900eSJiri Pirko FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_BASIC, basic); 86133fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 86277b9900eSJiri Pirko FLOW_DISSECTOR_KEY_ETH_ADDRS, eth); 86333fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 86477b9900eSJiri Pirko FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4); 86533fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 86677b9900eSJiri Pirko FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6); 86733fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 86877b9900eSJiri Pirko FLOW_DISSECTOR_KEY_PORTS, tp); 86933fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 8704d80cc0aSOr Gerlitz FLOW_DISSECTOR_KEY_IP, ip); 87133fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 872fdfc7dd6SJiri Pirko FLOW_DISSECTOR_KEY_TCP, tcp); 87333fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 8747b684884SSimon Horman FLOW_DISSECTOR_KEY_ICMP, icmp); 87533fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 87699d31326SSimon Horman FLOW_DISSECTOR_KEY_ARP, arp); 87733fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 878a577d8f7SBenjamin LaHaise FLOW_DISSECTOR_KEY_MPLS, mpls); 87933fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 8809399ae9aSHadar Hen Zion FLOW_DISSECTOR_KEY_VLAN, vlan); 88133fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 882d64efd09SJianbo Liu FLOW_DISSECTOR_KEY_CVLAN, cvlan); 88333fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 884519d1052SHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_KEYID, enc_key_id); 88533fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 886519d1052SHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, enc_ipv4); 88733fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 888519d1052SHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, enc_ipv6); 88933fb5cbaSJiri Pirko if (FL_KEY_IS_MASKED(mask, enc_ipv4) || 89033fb5cbaSJiri Pirko FL_KEY_IS_MASKED(mask, enc_ipv6)) 891519d1052SHadar Hen Zion FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_ENC_CONTROL, 892519d1052SHadar Hen Zion enc_control); 89333fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 894f4d997fdSHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_PORTS, enc_tp); 89533fb5cbaSJiri Pirko FL_KEY_SET_IF_MASKED(mask, keys, cnt, 8960e2c17b6SOr Gerlitz FLOW_DISSECTOR_KEY_ENC_IP, enc_ip); 89777b9900eSJiri Pirko 89833fb5cbaSJiri Pirko skb_flow_dissector_init(dissector, keys, cnt); 89905cd271fSPaul Blakey } 90005cd271fSPaul Blakey 90105cd271fSPaul Blakey static struct fl_flow_mask *fl_create_new_mask(struct cls_fl_head *head, 90205cd271fSPaul Blakey struct fl_flow_mask *mask) 90305cd271fSPaul Blakey { 90405cd271fSPaul Blakey struct fl_flow_mask *newmask; 90505cd271fSPaul Blakey int err; 90605cd271fSPaul Blakey 90705cd271fSPaul Blakey newmask = kzalloc(sizeof(*newmask), GFP_KERNEL); 90805cd271fSPaul Blakey if (!newmask) 90905cd271fSPaul Blakey return ERR_PTR(-ENOMEM); 91005cd271fSPaul Blakey 91105cd271fSPaul Blakey fl_mask_copy(newmask, mask); 91205cd271fSPaul Blakey 91305cd271fSPaul Blakey err = fl_init_mask_hashtable(newmask); 91405cd271fSPaul Blakey if (err) 91505cd271fSPaul Blakey goto errout_free; 91605cd271fSPaul Blakey 91733fb5cbaSJiri Pirko fl_init_dissector(&newmask->dissector, &newmask->key); 91805cd271fSPaul Blakey 91905cd271fSPaul Blakey INIT_LIST_HEAD_RCU(&newmask->filters); 92005cd271fSPaul Blakey 92105cd271fSPaul Blakey err = rhashtable_insert_fast(&head->ht, &newmask->ht_node, 92205cd271fSPaul Blakey mask_ht_params); 92305cd271fSPaul Blakey if (err) 92405cd271fSPaul Blakey goto errout_destroy; 92505cd271fSPaul Blakey 92605cd271fSPaul Blakey list_add_tail_rcu(&newmask->list, &head->masks); 92705cd271fSPaul Blakey 92805cd271fSPaul Blakey return newmask; 92905cd271fSPaul Blakey 93005cd271fSPaul Blakey errout_destroy: 93105cd271fSPaul Blakey rhashtable_destroy(&newmask->ht); 93205cd271fSPaul Blakey errout_free: 93305cd271fSPaul Blakey kfree(newmask); 93405cd271fSPaul Blakey 93505cd271fSPaul Blakey return ERR_PTR(err); 93677b9900eSJiri Pirko } 93777b9900eSJiri Pirko 93877b9900eSJiri Pirko static int fl_check_assign_mask(struct cls_fl_head *head, 93905cd271fSPaul Blakey struct cls_fl_filter *fnew, 94005cd271fSPaul Blakey struct cls_fl_filter *fold, 94177b9900eSJiri Pirko struct fl_flow_mask *mask) 94277b9900eSJiri Pirko { 94305cd271fSPaul Blakey struct fl_flow_mask *newmask; 94477b9900eSJiri Pirko 94505cd271fSPaul Blakey fnew->mask = rhashtable_lookup_fast(&head->ht, mask, mask_ht_params); 94605cd271fSPaul Blakey if (!fnew->mask) { 94705cd271fSPaul Blakey if (fold) 94877b9900eSJiri Pirko return -EINVAL; 94905cd271fSPaul Blakey 95005cd271fSPaul Blakey newmask = fl_create_new_mask(head, mask); 95105cd271fSPaul Blakey if (IS_ERR(newmask)) 95205cd271fSPaul Blakey return PTR_ERR(newmask); 95305cd271fSPaul Blakey 95405cd271fSPaul Blakey fnew->mask = newmask; 955f6521c58SPaul Blakey } else if (fold && fold->mask != fnew->mask) { 95605cd271fSPaul Blakey return -EINVAL; 95777b9900eSJiri Pirko } 95877b9900eSJiri Pirko 95977b9900eSJiri Pirko return 0; 96077b9900eSJiri Pirko } 96177b9900eSJiri Pirko 96277b9900eSJiri Pirko static int fl_set_parms(struct net *net, struct tcf_proto *tp, 96377b9900eSJiri Pirko struct cls_fl_filter *f, struct fl_flow_mask *mask, 96477b9900eSJiri Pirko unsigned long base, struct nlattr **tb, 96550a56190SAlexander Aring struct nlattr *est, bool ovr, 966b95ec7ebSJiri Pirko struct fl_flow_tmplt *tmplt, 96750a56190SAlexander Aring struct netlink_ext_ack *extack) 96877b9900eSJiri Pirko { 96977b9900eSJiri Pirko int err; 97077b9900eSJiri Pirko 97150a56190SAlexander Aring err = tcf_exts_validate(net, tp, tb, est, &f->exts, ovr, extack); 97277b9900eSJiri Pirko if (err < 0) 97377b9900eSJiri Pirko return err; 97477b9900eSJiri Pirko 97577b9900eSJiri Pirko if (tb[TCA_FLOWER_CLASSID]) { 97677b9900eSJiri Pirko f->res.classid = nla_get_u32(tb[TCA_FLOWER_CLASSID]); 97777b9900eSJiri Pirko tcf_bind_filter(tp, &f->res, base); 97877b9900eSJiri Pirko } 97977b9900eSJiri Pirko 9801057c55fSAlexander Aring err = fl_set_key(net, tb, &f->key, &mask->key, extack); 98177b9900eSJiri Pirko if (err) 98245507529SJiri Pirko return err; 98377b9900eSJiri Pirko 98477b9900eSJiri Pirko fl_mask_update_range(mask); 98577b9900eSJiri Pirko fl_set_masked_key(&f->mkey, &f->key, mask); 98677b9900eSJiri Pirko 987b95ec7ebSJiri Pirko if (!fl_mask_fits_tmplt(tmplt, mask)) { 988b95ec7ebSJiri Pirko NL_SET_ERR_MSG_MOD(extack, "Mask does not fit the template"); 989b95ec7ebSJiri Pirko return -EINVAL; 990b95ec7ebSJiri Pirko } 991b95ec7ebSJiri Pirko 99277b9900eSJiri Pirko return 0; 99377b9900eSJiri Pirko } 99477b9900eSJiri Pirko 99577b9900eSJiri Pirko static int fl_change(struct net *net, struct sk_buff *in_skb, 99677b9900eSJiri Pirko struct tcf_proto *tp, unsigned long base, 99777b9900eSJiri Pirko u32 handle, struct nlattr **tca, 9987306db38SAlexander Aring void **arg, bool ovr, struct netlink_ext_ack *extack) 99977b9900eSJiri Pirko { 100077b9900eSJiri Pirko struct cls_fl_head *head = rtnl_dereference(tp->root); 10018113c095SWANG Cong struct cls_fl_filter *fold = *arg; 100277b9900eSJiri Pirko struct cls_fl_filter *fnew; 100339b7b6a6SArnd Bergmann struct nlattr **tb; 100477b9900eSJiri Pirko struct fl_flow_mask mask = {}; 100577b9900eSJiri Pirko int err; 100677b9900eSJiri Pirko 100777b9900eSJiri Pirko if (!tca[TCA_OPTIONS]) 100877b9900eSJiri Pirko return -EINVAL; 100977b9900eSJiri Pirko 101039b7b6a6SArnd Bergmann tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL); 101139b7b6a6SArnd Bergmann if (!tb) 101239b7b6a6SArnd Bergmann return -ENOBUFS; 101339b7b6a6SArnd Bergmann 1014fceb6435SJohannes Berg err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS], 1015fceb6435SJohannes Berg fl_policy, NULL); 101677b9900eSJiri Pirko if (err < 0) 101739b7b6a6SArnd Bergmann goto errout_tb; 101877b9900eSJiri Pirko 101939b7b6a6SArnd Bergmann if (fold && handle && fold->handle != handle) { 102039b7b6a6SArnd Bergmann err = -EINVAL; 102139b7b6a6SArnd Bergmann goto errout_tb; 102239b7b6a6SArnd Bergmann } 102377b9900eSJiri Pirko 102477b9900eSJiri Pirko fnew = kzalloc(sizeof(*fnew), GFP_KERNEL); 102539b7b6a6SArnd Bergmann if (!fnew) { 102639b7b6a6SArnd Bergmann err = -ENOBUFS; 102739b7b6a6SArnd Bergmann goto errout_tb; 102839b7b6a6SArnd Bergmann } 102977b9900eSJiri Pirko 1030b9a24bb7SWANG Cong err = tcf_exts_init(&fnew->exts, TCA_FLOWER_ACT, 0); 1031b9a24bb7SWANG Cong if (err < 0) 1032b9a24bb7SWANG Cong goto errout; 103377b9900eSJiri Pirko 103477b9900eSJiri Pirko if (!handle) { 103585bd0438SMatthew Wilcox handle = 1; 103685bd0438SMatthew Wilcox err = idr_alloc_u32(&head->handle_idr, fnew, &handle, 103785bd0438SMatthew Wilcox INT_MAX, GFP_KERNEL); 103885bd0438SMatthew Wilcox } else if (!fold) { 1039c15ab236SChris Mi /* user specifies a handle and it doesn't exist */ 104085bd0438SMatthew Wilcox err = idr_alloc_u32(&head->handle_idr, fnew, &handle, 104185bd0438SMatthew Wilcox handle, GFP_KERNEL); 104285bd0438SMatthew Wilcox } 1043c15ab236SChris Mi if (err) 1044c15ab236SChris Mi goto errout; 104585bd0438SMatthew Wilcox fnew->handle = handle; 104677b9900eSJiri Pirko 1047e69985c6SAmir Vadai if (tb[TCA_FLOWER_FLAGS]) { 1048e69985c6SAmir Vadai fnew->flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]); 1049e69985c6SAmir Vadai 1050e69985c6SAmir Vadai if (!tc_flags_valid(fnew->flags)) { 1051e69985c6SAmir Vadai err = -EINVAL; 1052fe2502e4SCong Wang goto errout_idr; 1053e69985c6SAmir Vadai } 1054e69985c6SAmir Vadai } 10555b33f488SAmir Vadai 105650a56190SAlexander Aring err = fl_set_parms(net, tp, fnew, &mask, base, tb, tca[TCA_RATE], ovr, 1057b95ec7ebSJiri Pirko tp->chain->tmplt_priv, extack); 105877b9900eSJiri Pirko if (err) 1059fe2502e4SCong Wang goto errout_idr; 106077b9900eSJiri Pirko 106105cd271fSPaul Blakey err = fl_check_assign_mask(head, fnew, fold, &mask); 106277b9900eSJiri Pirko if (err) 1063fe2502e4SCong Wang goto errout_idr; 106477b9900eSJiri Pirko 1065e8eb36cdSAmir Vadai if (!tc_skip_sw(fnew->flags)) { 106605cd271fSPaul Blakey if (!fold && fl_lookup(fnew->mask, &fnew->mkey)) { 1067a3308d8fSPaul Blakey err = -EEXIST; 106805cd271fSPaul Blakey goto errout_mask; 1069a3308d8fSPaul Blakey } 1070a3308d8fSPaul Blakey 107105cd271fSPaul Blakey err = rhashtable_insert_fast(&fnew->mask->ht, &fnew->ht_node, 107205cd271fSPaul Blakey fnew->mask->filter_ht_params); 107377b9900eSJiri Pirko if (err) 107405cd271fSPaul Blakey goto errout_mask; 1075e69985c6SAmir Vadai } 10765b33f488SAmir Vadai 107779685219SHadar Hen Zion if (!tc_skip_hw(fnew->flags)) { 107805cd271fSPaul Blakey err = fl_hw_replace_filter(tp, fnew, extack); 1079e8eb36cdSAmir Vadai if (err) 108005cd271fSPaul Blakey goto errout_mask; 108179685219SHadar Hen Zion } 10825b33f488SAmir Vadai 108355593960SOr Gerlitz if (!tc_in_hw(fnew->flags)) 108455593960SOr Gerlitz fnew->flags |= TCA_CLS_FLAGS_NOT_IN_HW; 108555593960SOr Gerlitz 10865b33f488SAmir Vadai if (fold) { 1087725cbb62SJiri Pirko if (!tc_skip_sw(fold->flags)) 108805cd271fSPaul Blakey rhashtable_remove_fast(&fold->mask->ht, 108905cd271fSPaul Blakey &fold->ht_node, 109005cd271fSPaul Blakey fold->mask->filter_ht_params); 109179685219SHadar Hen Zion if (!tc_skip_hw(fold->flags)) 10921b0f8037SJakub Kicinski fl_hw_destroy_filter(tp, fold, NULL); 10935b33f488SAmir Vadai } 109477b9900eSJiri Pirko 10958113c095SWANG Cong *arg = fnew; 109677b9900eSJiri Pirko 109777b9900eSJiri Pirko if (fold) { 1098234a4624SMatthew Wilcox idr_replace(&head->handle_idr, fnew, fnew->handle); 1099ff3532f2SDaniel Borkmann list_replace_rcu(&fold->list, &fnew->list); 110077b9900eSJiri Pirko tcf_unbind_filter(tp, &fold->res); 11010dadc117SCong Wang tcf_exts_get_net(&fold->exts); 1102aaa908ffSCong Wang tcf_queue_work(&fold->rwork, fl_destroy_filter_work); 110377b9900eSJiri Pirko } else { 110405cd271fSPaul Blakey list_add_tail_rcu(&fnew->list, &fnew->mask->filters); 110577b9900eSJiri Pirko } 110677b9900eSJiri Pirko 110739b7b6a6SArnd Bergmann kfree(tb); 110877b9900eSJiri Pirko return 0; 110977b9900eSJiri Pirko 111005cd271fSPaul Blakey errout_mask: 111105cd271fSPaul Blakey fl_mask_put(head, fnew->mask, false); 111205cd271fSPaul Blakey 1113fe2502e4SCong Wang errout_idr: 11148258d2daSPaul Blakey if (!fold) 11159c160941SMatthew Wilcox idr_remove(&head->handle_idr, fnew->handle); 111677b9900eSJiri Pirko errout: 1117b9a24bb7SWANG Cong tcf_exts_destroy(&fnew->exts); 111877b9900eSJiri Pirko kfree(fnew); 111939b7b6a6SArnd Bergmann errout_tb: 112039b7b6a6SArnd Bergmann kfree(tb); 112177b9900eSJiri Pirko return err; 112277b9900eSJiri Pirko } 112377b9900eSJiri Pirko 1124571acf21SAlexander Aring static int fl_delete(struct tcf_proto *tp, void *arg, bool *last, 1125571acf21SAlexander Aring struct netlink_ext_ack *extack) 112677b9900eSJiri Pirko { 112777b9900eSJiri Pirko struct cls_fl_head *head = rtnl_dereference(tp->root); 11288113c095SWANG Cong struct cls_fl_filter *f = arg; 112977b9900eSJiri Pirko 1130725cbb62SJiri Pirko if (!tc_skip_sw(f->flags)) 113105cd271fSPaul Blakey rhashtable_remove_fast(&f->mask->ht, &f->ht_node, 113205cd271fSPaul Blakey f->mask->filter_ht_params); 11331b0f8037SJakub Kicinski __fl_delete(tp, f, extack); 113405cd271fSPaul Blakey *last = list_empty(&head->masks); 113577b9900eSJiri Pirko return 0; 113677b9900eSJiri Pirko } 113777b9900eSJiri Pirko 113877b9900eSJiri Pirko static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg) 113977b9900eSJiri Pirko { 114077b9900eSJiri Pirko struct cls_fl_head *head = rtnl_dereference(tp->root); 114177b9900eSJiri Pirko struct cls_fl_filter *f; 114277b9900eSJiri Pirko 114301683a14SVlad Buslov arg->count = arg->skip; 114401683a14SVlad Buslov 114501683a14SVlad Buslov while ((f = idr_get_next_ul(&head->handle_idr, 114601683a14SVlad Buslov &arg->cookie)) != NULL) { 11478113c095SWANG Cong if (arg->fn(tp, f, arg) < 0) { 114877b9900eSJiri Pirko arg->stop = 1; 114977b9900eSJiri Pirko break; 115077b9900eSJiri Pirko } 115101683a14SVlad Buslov arg->cookie = f->handle + 1; 115277b9900eSJiri Pirko arg->count++; 115377b9900eSJiri Pirko } 115477b9900eSJiri Pirko } 115577b9900eSJiri Pirko 115631533cbaSJohn Hurley static int fl_reoffload(struct tcf_proto *tp, bool add, tc_setup_cb_t *cb, 115731533cbaSJohn Hurley void *cb_priv, struct netlink_ext_ack *extack) 115831533cbaSJohn Hurley { 115931533cbaSJohn Hurley struct cls_fl_head *head = rtnl_dereference(tp->root); 116031533cbaSJohn Hurley struct tc_cls_flower_offload cls_flower = {}; 116131533cbaSJohn Hurley struct tcf_block *block = tp->chain->block; 116231533cbaSJohn Hurley struct fl_flow_mask *mask; 116331533cbaSJohn Hurley struct cls_fl_filter *f; 116431533cbaSJohn Hurley int err; 116531533cbaSJohn Hurley 116631533cbaSJohn Hurley list_for_each_entry(mask, &head->masks, list) { 116731533cbaSJohn Hurley list_for_each_entry(f, &mask->filters, list) { 116831533cbaSJohn Hurley if (tc_skip_hw(f->flags)) 116931533cbaSJohn Hurley continue; 117031533cbaSJohn Hurley 117131533cbaSJohn Hurley tc_cls_common_offload_init(&cls_flower.common, tp, 117231533cbaSJohn Hurley f->flags, extack); 117331533cbaSJohn Hurley cls_flower.command = add ? 117431533cbaSJohn Hurley TC_CLSFLOWER_REPLACE : TC_CLSFLOWER_DESTROY; 117531533cbaSJohn Hurley cls_flower.cookie = (unsigned long)f; 117631533cbaSJohn Hurley cls_flower.dissector = &mask->dissector; 117731533cbaSJohn Hurley cls_flower.mask = &f->mkey; 117831533cbaSJohn Hurley cls_flower.key = &f->key; 117931533cbaSJohn Hurley cls_flower.exts = &f->exts; 118031533cbaSJohn Hurley cls_flower.classid = f->res.classid; 118131533cbaSJohn Hurley 118231533cbaSJohn Hurley err = cb(TC_SETUP_CLSFLOWER, &cls_flower, cb_priv); 118331533cbaSJohn Hurley if (err) { 118431533cbaSJohn Hurley if (add && tc_skip_sw(f->flags)) 118531533cbaSJohn Hurley return err; 118631533cbaSJohn Hurley continue; 118731533cbaSJohn Hurley } 118831533cbaSJohn Hurley 118931533cbaSJohn Hurley tc_cls_offload_cnt_update(block, &f->in_hw_count, 119031533cbaSJohn Hurley &f->flags, add); 119131533cbaSJohn Hurley } 119231533cbaSJohn Hurley } 119331533cbaSJohn Hurley 119431533cbaSJohn Hurley return 0; 119531533cbaSJohn Hurley } 119631533cbaSJohn Hurley 119734738452SJiri Pirko static void fl_hw_create_tmplt(struct tcf_chain *chain, 119834738452SJiri Pirko struct fl_flow_tmplt *tmplt) 119934738452SJiri Pirko { 120034738452SJiri Pirko struct tc_cls_flower_offload cls_flower = {}; 120134738452SJiri Pirko struct tcf_block *block = chain->block; 120234738452SJiri Pirko struct tcf_exts dummy_exts = { 0, }; 120334738452SJiri Pirko 120434738452SJiri Pirko cls_flower.common.chain_index = chain->index; 120534738452SJiri Pirko cls_flower.command = TC_CLSFLOWER_TMPLT_CREATE; 120634738452SJiri Pirko cls_flower.cookie = (unsigned long) tmplt; 120734738452SJiri Pirko cls_flower.dissector = &tmplt->dissector; 120834738452SJiri Pirko cls_flower.mask = &tmplt->mask; 120934738452SJiri Pirko cls_flower.key = &tmplt->dummy_key; 121034738452SJiri Pirko cls_flower.exts = &dummy_exts; 121134738452SJiri Pirko 121234738452SJiri Pirko /* We don't care if driver (any of them) fails to handle this 121334738452SJiri Pirko * call. It serves just as a hint for it. 121434738452SJiri Pirko */ 121534738452SJiri Pirko tc_setup_cb_call(block, NULL, TC_SETUP_CLSFLOWER, 121634738452SJiri Pirko &cls_flower, false); 121734738452SJiri Pirko } 121834738452SJiri Pirko 121934738452SJiri Pirko static void fl_hw_destroy_tmplt(struct tcf_chain *chain, 122034738452SJiri Pirko struct fl_flow_tmplt *tmplt) 122134738452SJiri Pirko { 122234738452SJiri Pirko struct tc_cls_flower_offload cls_flower = {}; 122334738452SJiri Pirko struct tcf_block *block = chain->block; 122434738452SJiri Pirko 122534738452SJiri Pirko cls_flower.common.chain_index = chain->index; 122634738452SJiri Pirko cls_flower.command = TC_CLSFLOWER_TMPLT_DESTROY; 122734738452SJiri Pirko cls_flower.cookie = (unsigned long) tmplt; 122834738452SJiri Pirko 122934738452SJiri Pirko tc_setup_cb_call(block, NULL, TC_SETUP_CLSFLOWER, 123034738452SJiri Pirko &cls_flower, false); 123134738452SJiri Pirko } 123234738452SJiri Pirko 1233b95ec7ebSJiri Pirko static void *fl_tmplt_create(struct net *net, struct tcf_chain *chain, 1234b95ec7ebSJiri Pirko struct nlattr **tca, 1235b95ec7ebSJiri Pirko struct netlink_ext_ack *extack) 1236b95ec7ebSJiri Pirko { 1237b95ec7ebSJiri Pirko struct fl_flow_tmplt *tmplt; 1238b95ec7ebSJiri Pirko struct nlattr **tb; 1239b95ec7ebSJiri Pirko int err; 1240b95ec7ebSJiri Pirko 1241b95ec7ebSJiri Pirko if (!tca[TCA_OPTIONS]) 1242b95ec7ebSJiri Pirko return ERR_PTR(-EINVAL); 1243b95ec7ebSJiri Pirko 1244b95ec7ebSJiri Pirko tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL); 1245b95ec7ebSJiri Pirko if (!tb) 1246b95ec7ebSJiri Pirko return ERR_PTR(-ENOBUFS); 1247b95ec7ebSJiri Pirko err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS], 1248b95ec7ebSJiri Pirko fl_policy, NULL); 1249b95ec7ebSJiri Pirko if (err) 1250b95ec7ebSJiri Pirko goto errout_tb; 1251b95ec7ebSJiri Pirko 1252b95ec7ebSJiri Pirko tmplt = kzalloc(sizeof(*tmplt), GFP_KERNEL); 1253*1cbc36a5SDan Carpenter if (!tmplt) { 1254*1cbc36a5SDan Carpenter err = -ENOMEM; 1255b95ec7ebSJiri Pirko goto errout_tb; 1256*1cbc36a5SDan Carpenter } 1257b95ec7ebSJiri Pirko tmplt->chain = chain; 1258b95ec7ebSJiri Pirko err = fl_set_key(net, tb, &tmplt->dummy_key, &tmplt->mask, extack); 1259b95ec7ebSJiri Pirko if (err) 1260b95ec7ebSJiri Pirko goto errout_tmplt; 1261b95ec7ebSJiri Pirko kfree(tb); 1262b95ec7ebSJiri Pirko 1263b95ec7ebSJiri Pirko fl_init_dissector(&tmplt->dissector, &tmplt->mask); 1264b95ec7ebSJiri Pirko 126534738452SJiri Pirko fl_hw_create_tmplt(chain, tmplt); 126634738452SJiri Pirko 1267b95ec7ebSJiri Pirko return tmplt; 1268b95ec7ebSJiri Pirko 1269b95ec7ebSJiri Pirko errout_tmplt: 1270b95ec7ebSJiri Pirko kfree(tmplt); 1271b95ec7ebSJiri Pirko errout_tb: 1272b95ec7ebSJiri Pirko kfree(tb); 1273b95ec7ebSJiri Pirko return ERR_PTR(err); 1274b95ec7ebSJiri Pirko } 1275b95ec7ebSJiri Pirko 1276b95ec7ebSJiri Pirko static void fl_tmplt_destroy(void *tmplt_priv) 1277b95ec7ebSJiri Pirko { 1278b95ec7ebSJiri Pirko struct fl_flow_tmplt *tmplt = tmplt_priv; 1279b95ec7ebSJiri Pirko 128034738452SJiri Pirko fl_hw_destroy_tmplt(tmplt->chain, tmplt); 1281b95ec7ebSJiri Pirko kfree(tmplt); 1282b95ec7ebSJiri Pirko } 1283b95ec7ebSJiri Pirko 128477b9900eSJiri Pirko static int fl_dump_key_val(struct sk_buff *skb, 128577b9900eSJiri Pirko void *val, int val_type, 128677b9900eSJiri Pirko void *mask, int mask_type, int len) 128777b9900eSJiri Pirko { 128877b9900eSJiri Pirko int err; 128977b9900eSJiri Pirko 129077b9900eSJiri Pirko if (!memchr_inv(mask, 0, len)) 129177b9900eSJiri Pirko return 0; 129277b9900eSJiri Pirko err = nla_put(skb, val_type, len, val); 129377b9900eSJiri Pirko if (err) 129477b9900eSJiri Pirko return err; 129577b9900eSJiri Pirko if (mask_type != TCA_FLOWER_UNSPEC) { 129677b9900eSJiri Pirko err = nla_put(skb, mask_type, len, mask); 129777b9900eSJiri Pirko if (err) 129877b9900eSJiri Pirko return err; 129977b9900eSJiri Pirko } 130077b9900eSJiri Pirko return 0; 130177b9900eSJiri Pirko } 130277b9900eSJiri Pirko 1303a577d8f7SBenjamin LaHaise static int fl_dump_key_mpls(struct sk_buff *skb, 1304a577d8f7SBenjamin LaHaise struct flow_dissector_key_mpls *mpls_key, 1305a577d8f7SBenjamin LaHaise struct flow_dissector_key_mpls *mpls_mask) 1306a577d8f7SBenjamin LaHaise { 1307a577d8f7SBenjamin LaHaise int err; 1308a577d8f7SBenjamin LaHaise 1309a577d8f7SBenjamin LaHaise if (!memchr_inv(mpls_mask, 0, sizeof(*mpls_mask))) 1310a577d8f7SBenjamin LaHaise return 0; 1311a577d8f7SBenjamin LaHaise if (mpls_mask->mpls_ttl) { 1312a577d8f7SBenjamin LaHaise err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TTL, 1313a577d8f7SBenjamin LaHaise mpls_key->mpls_ttl); 1314a577d8f7SBenjamin LaHaise if (err) 1315a577d8f7SBenjamin LaHaise return err; 1316a577d8f7SBenjamin LaHaise } 1317a577d8f7SBenjamin LaHaise if (mpls_mask->mpls_tc) { 1318a577d8f7SBenjamin LaHaise err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TC, 1319a577d8f7SBenjamin LaHaise mpls_key->mpls_tc); 1320a577d8f7SBenjamin LaHaise if (err) 1321a577d8f7SBenjamin LaHaise return err; 1322a577d8f7SBenjamin LaHaise } 1323a577d8f7SBenjamin LaHaise if (mpls_mask->mpls_label) { 1324a577d8f7SBenjamin LaHaise err = nla_put_u32(skb, TCA_FLOWER_KEY_MPLS_LABEL, 1325a577d8f7SBenjamin LaHaise mpls_key->mpls_label); 1326a577d8f7SBenjamin LaHaise if (err) 1327a577d8f7SBenjamin LaHaise return err; 1328a577d8f7SBenjamin LaHaise } 1329a577d8f7SBenjamin LaHaise if (mpls_mask->mpls_bos) { 1330a577d8f7SBenjamin LaHaise err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_BOS, 1331a577d8f7SBenjamin LaHaise mpls_key->mpls_bos); 1332a577d8f7SBenjamin LaHaise if (err) 1333a577d8f7SBenjamin LaHaise return err; 1334a577d8f7SBenjamin LaHaise } 1335a577d8f7SBenjamin LaHaise return 0; 1336a577d8f7SBenjamin LaHaise } 1337a577d8f7SBenjamin LaHaise 13380e2c17b6SOr Gerlitz static int fl_dump_key_ip(struct sk_buff *skb, bool encap, 13394d80cc0aSOr Gerlitz struct flow_dissector_key_ip *key, 13404d80cc0aSOr Gerlitz struct flow_dissector_key_ip *mask) 13414d80cc0aSOr Gerlitz { 13420e2c17b6SOr Gerlitz int tos_key = encap ? TCA_FLOWER_KEY_ENC_IP_TOS : TCA_FLOWER_KEY_IP_TOS; 13430e2c17b6SOr Gerlitz int ttl_key = encap ? TCA_FLOWER_KEY_ENC_IP_TTL : TCA_FLOWER_KEY_IP_TTL; 13440e2c17b6SOr Gerlitz int tos_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TOS_MASK : TCA_FLOWER_KEY_IP_TOS_MASK; 13450e2c17b6SOr Gerlitz int ttl_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TTL_MASK : TCA_FLOWER_KEY_IP_TTL_MASK; 13460e2c17b6SOr Gerlitz 13470e2c17b6SOr Gerlitz if (fl_dump_key_val(skb, &key->tos, tos_key, &mask->tos, tos_mask, sizeof(key->tos)) || 13480e2c17b6SOr Gerlitz fl_dump_key_val(skb, &key->ttl, ttl_key, &mask->ttl, ttl_mask, sizeof(key->ttl))) 13494d80cc0aSOr Gerlitz return -1; 13504d80cc0aSOr Gerlitz 13514d80cc0aSOr Gerlitz return 0; 13524d80cc0aSOr Gerlitz } 13534d80cc0aSOr Gerlitz 13549399ae9aSHadar Hen Zion static int fl_dump_key_vlan(struct sk_buff *skb, 1355d64efd09SJianbo Liu int vlan_id_key, int vlan_prio_key, 13569399ae9aSHadar Hen Zion struct flow_dissector_key_vlan *vlan_key, 13579399ae9aSHadar Hen Zion struct flow_dissector_key_vlan *vlan_mask) 13589399ae9aSHadar Hen Zion { 13599399ae9aSHadar Hen Zion int err; 13609399ae9aSHadar Hen Zion 13619399ae9aSHadar Hen Zion if (!memchr_inv(vlan_mask, 0, sizeof(*vlan_mask))) 13629399ae9aSHadar Hen Zion return 0; 13639399ae9aSHadar Hen Zion if (vlan_mask->vlan_id) { 1364d64efd09SJianbo Liu err = nla_put_u16(skb, vlan_id_key, 13659399ae9aSHadar Hen Zion vlan_key->vlan_id); 13669399ae9aSHadar Hen Zion if (err) 13679399ae9aSHadar Hen Zion return err; 13689399ae9aSHadar Hen Zion } 13699399ae9aSHadar Hen Zion if (vlan_mask->vlan_priority) { 1370d64efd09SJianbo Liu err = nla_put_u8(skb, vlan_prio_key, 13719399ae9aSHadar Hen Zion vlan_key->vlan_priority); 13729399ae9aSHadar Hen Zion if (err) 13739399ae9aSHadar Hen Zion return err; 13749399ae9aSHadar Hen Zion } 13759399ae9aSHadar Hen Zion return 0; 13769399ae9aSHadar Hen Zion } 13779399ae9aSHadar Hen Zion 1378faa3ffceSOr Gerlitz static void fl_get_key_flag(u32 dissector_key, u32 dissector_mask, 1379faa3ffceSOr Gerlitz u32 *flower_key, u32 *flower_mask, 1380faa3ffceSOr Gerlitz u32 flower_flag_bit, u32 dissector_flag_bit) 1381faa3ffceSOr Gerlitz { 1382faa3ffceSOr Gerlitz if (dissector_mask & dissector_flag_bit) { 1383faa3ffceSOr Gerlitz *flower_mask |= flower_flag_bit; 1384faa3ffceSOr Gerlitz if (dissector_key & dissector_flag_bit) 1385faa3ffceSOr Gerlitz *flower_key |= flower_flag_bit; 1386faa3ffceSOr Gerlitz } 1387faa3ffceSOr Gerlitz } 1388faa3ffceSOr Gerlitz 1389faa3ffceSOr Gerlitz static int fl_dump_key_flags(struct sk_buff *skb, u32 flags_key, u32 flags_mask) 1390faa3ffceSOr Gerlitz { 1391faa3ffceSOr Gerlitz u32 key, mask; 1392faa3ffceSOr Gerlitz __be32 _key, _mask; 1393faa3ffceSOr Gerlitz int err; 1394faa3ffceSOr Gerlitz 1395faa3ffceSOr Gerlitz if (!memchr_inv(&flags_mask, 0, sizeof(flags_mask))) 1396faa3ffceSOr Gerlitz return 0; 1397faa3ffceSOr Gerlitz 1398faa3ffceSOr Gerlitz key = 0; 1399faa3ffceSOr Gerlitz mask = 0; 1400faa3ffceSOr Gerlitz 1401faa3ffceSOr Gerlitz fl_get_key_flag(flags_key, flags_mask, &key, &mask, 1402faa3ffceSOr Gerlitz TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT); 1403459d153dSPieter Jansen van Vuuren fl_get_key_flag(flags_key, flags_mask, &key, &mask, 1404459d153dSPieter Jansen van Vuuren TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST, 1405459d153dSPieter Jansen van Vuuren FLOW_DIS_FIRST_FRAG); 1406faa3ffceSOr Gerlitz 1407faa3ffceSOr Gerlitz _key = cpu_to_be32(key); 1408faa3ffceSOr Gerlitz _mask = cpu_to_be32(mask); 1409faa3ffceSOr Gerlitz 1410faa3ffceSOr Gerlitz err = nla_put(skb, TCA_FLOWER_KEY_FLAGS, 4, &_key); 1411faa3ffceSOr Gerlitz if (err) 1412faa3ffceSOr Gerlitz return err; 1413faa3ffceSOr Gerlitz 1414faa3ffceSOr Gerlitz return nla_put(skb, TCA_FLOWER_KEY_FLAGS_MASK, 4, &_mask); 1415faa3ffceSOr Gerlitz } 1416faa3ffceSOr Gerlitz 1417f5749081SJiri Pirko static int fl_dump_key(struct sk_buff *skb, struct net *net, 1418f5749081SJiri Pirko struct fl_flow_key *key, struct fl_flow_key *mask) 141977b9900eSJiri Pirko { 142077b9900eSJiri Pirko if (mask->indev_ifindex) { 142177b9900eSJiri Pirko struct net_device *dev; 142277b9900eSJiri Pirko 142377b9900eSJiri Pirko dev = __dev_get_by_index(net, key->indev_ifindex); 142477b9900eSJiri Pirko if (dev && nla_put_string(skb, TCA_FLOWER_INDEV, dev->name)) 142577b9900eSJiri Pirko goto nla_put_failure; 142677b9900eSJiri Pirko } 142777b9900eSJiri Pirko 142877b9900eSJiri Pirko if (fl_dump_key_val(skb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST, 142977b9900eSJiri Pirko mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK, 143077b9900eSJiri Pirko sizeof(key->eth.dst)) || 143177b9900eSJiri Pirko fl_dump_key_val(skb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC, 143277b9900eSJiri Pirko mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK, 143377b9900eSJiri Pirko sizeof(key->eth.src)) || 143477b9900eSJiri Pirko fl_dump_key_val(skb, &key->basic.n_proto, TCA_FLOWER_KEY_ETH_TYPE, 143577b9900eSJiri Pirko &mask->basic.n_proto, TCA_FLOWER_UNSPEC, 143677b9900eSJiri Pirko sizeof(key->basic.n_proto))) 143777b9900eSJiri Pirko goto nla_put_failure; 14389399ae9aSHadar Hen Zion 1439a577d8f7SBenjamin LaHaise if (fl_dump_key_mpls(skb, &key->mpls, &mask->mpls)) 1440a577d8f7SBenjamin LaHaise goto nla_put_failure; 1441a577d8f7SBenjamin LaHaise 1442d64efd09SJianbo Liu if (fl_dump_key_vlan(skb, TCA_FLOWER_KEY_VLAN_ID, 1443d64efd09SJianbo Liu TCA_FLOWER_KEY_VLAN_PRIO, &key->vlan, &mask->vlan)) 14449399ae9aSHadar Hen Zion goto nla_put_failure; 14459399ae9aSHadar Hen Zion 1446d64efd09SJianbo Liu if (fl_dump_key_vlan(skb, TCA_FLOWER_KEY_CVLAN_ID, 1447d64efd09SJianbo Liu TCA_FLOWER_KEY_CVLAN_PRIO, 1448d64efd09SJianbo Liu &key->cvlan, &mask->cvlan) || 1449d64efd09SJianbo Liu (mask->cvlan.vlan_tpid && 1450158abbf1SJianbo Liu nla_put_be16(skb, TCA_FLOWER_KEY_VLAN_ETH_TYPE, 1451d64efd09SJianbo Liu key->cvlan.vlan_tpid))) 1452d3069512SJianbo Liu goto nla_put_failure; 1453d3069512SJianbo Liu 14545e9a0fe4SJianbo Liu if (mask->basic.n_proto) { 1455d64efd09SJianbo Liu if (mask->cvlan.vlan_tpid) { 1456d64efd09SJianbo Liu if (nla_put_be16(skb, TCA_FLOWER_KEY_CVLAN_ETH_TYPE, 1457d64efd09SJianbo Liu key->basic.n_proto)) 1458d64efd09SJianbo Liu goto nla_put_failure; 1459d64efd09SJianbo Liu } else if (mask->vlan.vlan_tpid) { 1460d64efd09SJianbo Liu if (nla_put_be16(skb, TCA_FLOWER_KEY_VLAN_ETH_TYPE, 1461d64efd09SJianbo Liu key->basic.n_proto)) 1462d64efd09SJianbo Liu goto nla_put_failure; 1463d64efd09SJianbo Liu } 14645e9a0fe4SJianbo Liu } 1465d64efd09SJianbo Liu 146677b9900eSJiri Pirko if ((key->basic.n_proto == htons(ETH_P_IP) || 146777b9900eSJiri Pirko key->basic.n_proto == htons(ETH_P_IPV6)) && 14684d80cc0aSOr Gerlitz (fl_dump_key_val(skb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO, 146977b9900eSJiri Pirko &mask->basic.ip_proto, TCA_FLOWER_UNSPEC, 14704d80cc0aSOr Gerlitz sizeof(key->basic.ip_proto)) || 14710e2c17b6SOr Gerlitz fl_dump_key_ip(skb, false, &key->ip, &mask->ip))) 147277b9900eSJiri Pirko goto nla_put_failure; 147377b9900eSJiri Pirko 1474c3f83241STom Herbert if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS && 147577b9900eSJiri Pirko (fl_dump_key_val(skb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC, 147677b9900eSJiri Pirko &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK, 147777b9900eSJiri Pirko sizeof(key->ipv4.src)) || 147877b9900eSJiri Pirko fl_dump_key_val(skb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST, 147977b9900eSJiri Pirko &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK, 148077b9900eSJiri Pirko sizeof(key->ipv4.dst)))) 148177b9900eSJiri Pirko goto nla_put_failure; 1482c3f83241STom Herbert else if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS && 148377b9900eSJiri Pirko (fl_dump_key_val(skb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC, 148477b9900eSJiri Pirko &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK, 148577b9900eSJiri Pirko sizeof(key->ipv6.src)) || 148677b9900eSJiri Pirko fl_dump_key_val(skb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST, 148777b9900eSJiri Pirko &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK, 148877b9900eSJiri Pirko sizeof(key->ipv6.dst)))) 148977b9900eSJiri Pirko goto nla_put_failure; 149077b9900eSJiri Pirko 149177b9900eSJiri Pirko if (key->basic.ip_proto == IPPROTO_TCP && 149277b9900eSJiri Pirko (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC, 1493aa72d708SOr Gerlitz &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK, 149477b9900eSJiri Pirko sizeof(key->tp.src)) || 149577b9900eSJiri Pirko fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST, 1496aa72d708SOr Gerlitz &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK, 1497fdfc7dd6SJiri Pirko sizeof(key->tp.dst)) || 1498fdfc7dd6SJiri Pirko fl_dump_key_val(skb, &key->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS, 1499fdfc7dd6SJiri Pirko &mask->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS_MASK, 1500fdfc7dd6SJiri Pirko sizeof(key->tcp.flags)))) 150177b9900eSJiri Pirko goto nla_put_failure; 150277b9900eSJiri Pirko else if (key->basic.ip_proto == IPPROTO_UDP && 150377b9900eSJiri Pirko (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC, 1504aa72d708SOr Gerlitz &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK, 150577b9900eSJiri Pirko sizeof(key->tp.src)) || 150677b9900eSJiri Pirko fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST, 1507aa72d708SOr Gerlitz &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK, 150877b9900eSJiri Pirko sizeof(key->tp.dst)))) 150977b9900eSJiri Pirko goto nla_put_failure; 15105976c5f4SSimon Horman else if (key->basic.ip_proto == IPPROTO_SCTP && 15115976c5f4SSimon Horman (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC, 15125976c5f4SSimon Horman &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK, 15135976c5f4SSimon Horman sizeof(key->tp.src)) || 15145976c5f4SSimon Horman fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST, 15155976c5f4SSimon Horman &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK, 15165976c5f4SSimon Horman sizeof(key->tp.dst)))) 15175976c5f4SSimon Horman goto nla_put_failure; 15187b684884SSimon Horman else if (key->basic.n_proto == htons(ETH_P_IP) && 15197b684884SSimon Horman key->basic.ip_proto == IPPROTO_ICMP && 15207b684884SSimon Horman (fl_dump_key_val(skb, &key->icmp.type, 15217b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_TYPE, &mask->icmp.type, 15227b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_TYPE_MASK, 15237b684884SSimon Horman sizeof(key->icmp.type)) || 15247b684884SSimon Horman fl_dump_key_val(skb, &key->icmp.code, 15257b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_CODE, &mask->icmp.code, 15267b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_CODE_MASK, 15277b684884SSimon Horman sizeof(key->icmp.code)))) 15287b684884SSimon Horman goto nla_put_failure; 15297b684884SSimon Horman else if (key->basic.n_proto == htons(ETH_P_IPV6) && 15307b684884SSimon Horman key->basic.ip_proto == IPPROTO_ICMPV6 && 15317b684884SSimon Horman (fl_dump_key_val(skb, &key->icmp.type, 15327b684884SSimon Horman TCA_FLOWER_KEY_ICMPV6_TYPE, &mask->icmp.type, 15337b684884SSimon Horman TCA_FLOWER_KEY_ICMPV6_TYPE_MASK, 15347b684884SSimon Horman sizeof(key->icmp.type)) || 15357b684884SSimon Horman fl_dump_key_val(skb, &key->icmp.code, 15367b684884SSimon Horman TCA_FLOWER_KEY_ICMPV6_CODE, &mask->icmp.code, 15377b684884SSimon Horman TCA_FLOWER_KEY_ICMPV6_CODE_MASK, 15387b684884SSimon Horman sizeof(key->icmp.code)))) 15397b684884SSimon Horman goto nla_put_failure; 154099d31326SSimon Horman else if ((key->basic.n_proto == htons(ETH_P_ARP) || 154199d31326SSimon Horman key->basic.n_proto == htons(ETH_P_RARP)) && 154299d31326SSimon Horman (fl_dump_key_val(skb, &key->arp.sip, 154399d31326SSimon Horman TCA_FLOWER_KEY_ARP_SIP, &mask->arp.sip, 154499d31326SSimon Horman TCA_FLOWER_KEY_ARP_SIP_MASK, 154599d31326SSimon Horman sizeof(key->arp.sip)) || 154699d31326SSimon Horman fl_dump_key_val(skb, &key->arp.tip, 154799d31326SSimon Horman TCA_FLOWER_KEY_ARP_TIP, &mask->arp.tip, 154899d31326SSimon Horman TCA_FLOWER_KEY_ARP_TIP_MASK, 154999d31326SSimon Horman sizeof(key->arp.tip)) || 155099d31326SSimon Horman fl_dump_key_val(skb, &key->arp.op, 155199d31326SSimon Horman TCA_FLOWER_KEY_ARP_OP, &mask->arp.op, 155299d31326SSimon Horman TCA_FLOWER_KEY_ARP_OP_MASK, 155399d31326SSimon Horman sizeof(key->arp.op)) || 155499d31326SSimon Horman fl_dump_key_val(skb, key->arp.sha, TCA_FLOWER_KEY_ARP_SHA, 155599d31326SSimon Horman mask->arp.sha, TCA_FLOWER_KEY_ARP_SHA_MASK, 155699d31326SSimon Horman sizeof(key->arp.sha)) || 155799d31326SSimon Horman fl_dump_key_val(skb, key->arp.tha, TCA_FLOWER_KEY_ARP_THA, 155899d31326SSimon Horman mask->arp.tha, TCA_FLOWER_KEY_ARP_THA_MASK, 155999d31326SSimon Horman sizeof(key->arp.tha)))) 156099d31326SSimon Horman goto nla_put_failure; 156177b9900eSJiri Pirko 1562bc3103f1SAmir Vadai if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS && 1563bc3103f1SAmir Vadai (fl_dump_key_val(skb, &key->enc_ipv4.src, 1564bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_SRC, &mask->enc_ipv4.src, 1565bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK, 1566bc3103f1SAmir Vadai sizeof(key->enc_ipv4.src)) || 1567bc3103f1SAmir Vadai fl_dump_key_val(skb, &key->enc_ipv4.dst, 1568bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_DST, &mask->enc_ipv4.dst, 1569bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_DST_MASK, 1570bc3103f1SAmir Vadai sizeof(key->enc_ipv4.dst)))) 1571bc3103f1SAmir Vadai goto nla_put_failure; 1572bc3103f1SAmir Vadai else if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS && 1573bc3103f1SAmir Vadai (fl_dump_key_val(skb, &key->enc_ipv6.src, 1574bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_SRC, &mask->enc_ipv6.src, 1575bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK, 1576bc3103f1SAmir Vadai sizeof(key->enc_ipv6.src)) || 1577bc3103f1SAmir Vadai fl_dump_key_val(skb, &key->enc_ipv6.dst, 1578bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_DST, 1579bc3103f1SAmir Vadai &mask->enc_ipv6.dst, 1580bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_DST_MASK, 1581bc3103f1SAmir Vadai sizeof(key->enc_ipv6.dst)))) 1582bc3103f1SAmir Vadai goto nla_put_failure; 1583bc3103f1SAmir Vadai 1584bc3103f1SAmir Vadai if (fl_dump_key_val(skb, &key->enc_key_id, TCA_FLOWER_KEY_ENC_KEY_ID, 1585eb523f42SHadar Hen Zion &mask->enc_key_id, TCA_FLOWER_UNSPEC, 1586f4d997fdSHadar Hen Zion sizeof(key->enc_key_id)) || 1587f4d997fdSHadar Hen Zion fl_dump_key_val(skb, &key->enc_tp.src, 1588f4d997fdSHadar Hen Zion TCA_FLOWER_KEY_ENC_UDP_SRC_PORT, 1589f4d997fdSHadar Hen Zion &mask->enc_tp.src, 1590f4d997fdSHadar Hen Zion TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK, 1591f4d997fdSHadar Hen Zion sizeof(key->enc_tp.src)) || 1592f4d997fdSHadar Hen Zion fl_dump_key_val(skb, &key->enc_tp.dst, 1593f4d997fdSHadar Hen Zion TCA_FLOWER_KEY_ENC_UDP_DST_PORT, 1594f4d997fdSHadar Hen Zion &mask->enc_tp.dst, 1595f4d997fdSHadar Hen Zion TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK, 15960e2c17b6SOr Gerlitz sizeof(key->enc_tp.dst)) || 15970e2c17b6SOr Gerlitz fl_dump_key_ip(skb, true, &key->enc_ip, &mask->enc_ip)) 1598bc3103f1SAmir Vadai goto nla_put_failure; 1599bc3103f1SAmir Vadai 1600faa3ffceSOr Gerlitz if (fl_dump_key_flags(skb, key->control.flags, mask->control.flags)) 1601faa3ffceSOr Gerlitz goto nla_put_failure; 1602faa3ffceSOr Gerlitz 1603f5749081SJiri Pirko return 0; 1604f5749081SJiri Pirko 1605f5749081SJiri Pirko nla_put_failure: 1606f5749081SJiri Pirko return -EMSGSIZE; 1607f5749081SJiri Pirko } 1608f5749081SJiri Pirko 1609f5749081SJiri Pirko static int fl_dump(struct net *net, struct tcf_proto *tp, void *fh, 1610f5749081SJiri Pirko struct sk_buff *skb, struct tcmsg *t) 1611f5749081SJiri Pirko { 1612f5749081SJiri Pirko struct cls_fl_filter *f = fh; 1613f5749081SJiri Pirko struct nlattr *nest; 1614f5749081SJiri Pirko struct fl_flow_key *key, *mask; 1615f5749081SJiri Pirko 1616f5749081SJiri Pirko if (!f) 1617f5749081SJiri Pirko return skb->len; 1618f5749081SJiri Pirko 1619f5749081SJiri Pirko t->tcm_handle = f->handle; 1620f5749081SJiri Pirko 1621f5749081SJiri Pirko nest = nla_nest_start(skb, TCA_OPTIONS); 1622f5749081SJiri Pirko if (!nest) 1623f5749081SJiri Pirko goto nla_put_failure; 1624f5749081SJiri Pirko 1625f5749081SJiri Pirko if (f->res.classid && 1626f5749081SJiri Pirko nla_put_u32(skb, TCA_FLOWER_CLASSID, f->res.classid)) 1627f5749081SJiri Pirko goto nla_put_failure; 1628f5749081SJiri Pirko 1629f5749081SJiri Pirko key = &f->key; 1630f5749081SJiri Pirko mask = &f->mask->key; 1631f5749081SJiri Pirko 1632f5749081SJiri Pirko if (fl_dump_key(skb, net, key, mask)) 1633f5749081SJiri Pirko goto nla_put_failure; 1634f5749081SJiri Pirko 1635f5749081SJiri Pirko if (!tc_skip_hw(f->flags)) 1636f5749081SJiri Pirko fl_hw_update_stats(tp, f); 1637f5749081SJiri Pirko 1638749e6720SOr Gerlitz if (f->flags && nla_put_u32(skb, TCA_FLOWER_FLAGS, f->flags)) 1639749e6720SOr Gerlitz goto nla_put_failure; 1640e69985c6SAmir Vadai 164177b9900eSJiri Pirko if (tcf_exts_dump(skb, &f->exts)) 164277b9900eSJiri Pirko goto nla_put_failure; 164377b9900eSJiri Pirko 164477b9900eSJiri Pirko nla_nest_end(skb, nest); 164577b9900eSJiri Pirko 164677b9900eSJiri Pirko if (tcf_exts_dump_stats(skb, &f->exts) < 0) 164777b9900eSJiri Pirko goto nla_put_failure; 164877b9900eSJiri Pirko 164977b9900eSJiri Pirko return skb->len; 165077b9900eSJiri Pirko 165177b9900eSJiri Pirko nla_put_failure: 165277b9900eSJiri Pirko nla_nest_cancel(skb, nest); 165377b9900eSJiri Pirko return -1; 165477b9900eSJiri Pirko } 165577b9900eSJiri Pirko 1656b95ec7ebSJiri Pirko static int fl_tmplt_dump(struct sk_buff *skb, struct net *net, void *tmplt_priv) 1657b95ec7ebSJiri Pirko { 1658b95ec7ebSJiri Pirko struct fl_flow_tmplt *tmplt = tmplt_priv; 1659b95ec7ebSJiri Pirko struct fl_flow_key *key, *mask; 1660b95ec7ebSJiri Pirko struct nlattr *nest; 1661b95ec7ebSJiri Pirko 1662b95ec7ebSJiri Pirko nest = nla_nest_start(skb, TCA_OPTIONS); 1663b95ec7ebSJiri Pirko if (!nest) 1664b95ec7ebSJiri Pirko goto nla_put_failure; 1665b95ec7ebSJiri Pirko 1666b95ec7ebSJiri Pirko key = &tmplt->dummy_key; 1667b95ec7ebSJiri Pirko mask = &tmplt->mask; 1668b95ec7ebSJiri Pirko 1669b95ec7ebSJiri Pirko if (fl_dump_key(skb, net, key, mask)) 1670b95ec7ebSJiri Pirko goto nla_put_failure; 1671b95ec7ebSJiri Pirko 1672b95ec7ebSJiri Pirko nla_nest_end(skb, nest); 1673b95ec7ebSJiri Pirko 1674b95ec7ebSJiri Pirko return skb->len; 1675b95ec7ebSJiri Pirko 1676b95ec7ebSJiri Pirko nla_put_failure: 1677b95ec7ebSJiri Pirko nla_nest_cancel(skb, nest); 1678b95ec7ebSJiri Pirko return -EMSGSIZE; 1679b95ec7ebSJiri Pirko } 1680b95ec7ebSJiri Pirko 168107d79fc7SCong Wang static void fl_bind_class(void *fh, u32 classid, unsigned long cl) 168207d79fc7SCong Wang { 168307d79fc7SCong Wang struct cls_fl_filter *f = fh; 168407d79fc7SCong Wang 168507d79fc7SCong Wang if (f && f->res.classid == classid) 168607d79fc7SCong Wang f->res.class = cl; 168707d79fc7SCong Wang } 168807d79fc7SCong Wang 168977b9900eSJiri Pirko static struct tcf_proto_ops cls_fl_ops __read_mostly = { 169077b9900eSJiri Pirko .kind = "flower", 169177b9900eSJiri Pirko .classify = fl_classify, 169277b9900eSJiri Pirko .init = fl_init, 169377b9900eSJiri Pirko .destroy = fl_destroy, 169477b9900eSJiri Pirko .get = fl_get, 169577b9900eSJiri Pirko .change = fl_change, 169677b9900eSJiri Pirko .delete = fl_delete, 169777b9900eSJiri Pirko .walk = fl_walk, 169831533cbaSJohn Hurley .reoffload = fl_reoffload, 169977b9900eSJiri Pirko .dump = fl_dump, 170007d79fc7SCong Wang .bind_class = fl_bind_class, 1701b95ec7ebSJiri Pirko .tmplt_create = fl_tmplt_create, 1702b95ec7ebSJiri Pirko .tmplt_destroy = fl_tmplt_destroy, 1703b95ec7ebSJiri Pirko .tmplt_dump = fl_tmplt_dump, 170477b9900eSJiri Pirko .owner = THIS_MODULE, 170577b9900eSJiri Pirko }; 170677b9900eSJiri Pirko 170777b9900eSJiri Pirko static int __init cls_fl_init(void) 170877b9900eSJiri Pirko { 170977b9900eSJiri Pirko return register_tcf_proto_ops(&cls_fl_ops); 171077b9900eSJiri Pirko } 171177b9900eSJiri Pirko 171277b9900eSJiri Pirko static void __exit cls_fl_exit(void) 171377b9900eSJiri Pirko { 171477b9900eSJiri Pirko unregister_tcf_proto_ops(&cls_fl_ops); 171577b9900eSJiri Pirko } 171677b9900eSJiri Pirko 171777b9900eSJiri Pirko module_init(cls_fl_init); 171877b9900eSJiri Pirko module_exit(cls_fl_exit); 171977b9900eSJiri Pirko 172077b9900eSJiri Pirko MODULE_AUTHOR("Jiri Pirko <jiri@resnulli.us>"); 172177b9900eSJiri Pirko MODULE_DESCRIPTION("Flower classifier"); 172277b9900eSJiri Pirko MODULE_LICENSE("GPL v2"); 1723