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; 3877b9900eSJiri Pirko union { 39c3f83241STom Herbert struct flow_dissector_key_ipv4_addrs ipv4; 4077b9900eSJiri Pirko struct flow_dissector_key_ipv6_addrs ipv6; 4177b9900eSJiri Pirko }; 4277b9900eSJiri Pirko struct flow_dissector_key_ports tp; 437b684884SSimon Horman struct flow_dissector_key_icmp icmp; 4499d31326SSimon Horman struct flow_dissector_key_arp arp; 45bc3103f1SAmir Vadai struct flow_dissector_key_keyid enc_key_id; 46bc3103f1SAmir Vadai union { 47bc3103f1SAmir Vadai struct flow_dissector_key_ipv4_addrs enc_ipv4; 48bc3103f1SAmir Vadai struct flow_dissector_key_ipv6_addrs enc_ipv6; 49bc3103f1SAmir Vadai }; 50f4d997fdSHadar Hen Zion struct flow_dissector_key_ports enc_tp; 51a577d8f7SBenjamin LaHaise struct flow_dissector_key_mpls mpls; 52fdfc7dd6SJiri Pirko struct flow_dissector_key_tcp tcp; 534d80cc0aSOr Gerlitz struct flow_dissector_key_ip ip; 5477b9900eSJiri Pirko } __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */ 5577b9900eSJiri Pirko 5677b9900eSJiri Pirko struct fl_flow_mask_range { 5777b9900eSJiri Pirko unsigned short int start; 5877b9900eSJiri Pirko unsigned short int end; 5977b9900eSJiri Pirko }; 6077b9900eSJiri Pirko 6177b9900eSJiri Pirko struct fl_flow_mask { 6277b9900eSJiri Pirko struct fl_flow_key key; 6377b9900eSJiri Pirko struct fl_flow_mask_range range; 6477b9900eSJiri Pirko struct rcu_head rcu; 6577b9900eSJiri Pirko }; 6677b9900eSJiri Pirko 6777b9900eSJiri Pirko struct cls_fl_head { 6877b9900eSJiri Pirko struct rhashtable ht; 6977b9900eSJiri Pirko struct fl_flow_mask mask; 7077b9900eSJiri Pirko struct flow_dissector dissector; 7177b9900eSJiri Pirko bool mask_assigned; 7277b9900eSJiri Pirko struct list_head filters; 7377b9900eSJiri Pirko struct rhashtable_params ht_params; 74d9363774SDaniel Borkmann union { 75d9363774SDaniel Borkmann struct work_struct work; 7677b9900eSJiri Pirko struct rcu_head rcu; 7777b9900eSJiri Pirko }; 78c15ab236SChris Mi struct idr handle_idr; 79d9363774SDaniel Borkmann }; 8077b9900eSJiri Pirko 8177b9900eSJiri Pirko struct cls_fl_filter { 8277b9900eSJiri Pirko struct rhash_head ht_node; 8377b9900eSJiri Pirko struct fl_flow_key mkey; 8477b9900eSJiri Pirko struct tcf_exts exts; 8577b9900eSJiri Pirko struct tcf_result res; 8677b9900eSJiri Pirko struct fl_flow_key key; 8777b9900eSJiri Pirko struct list_head list; 8877b9900eSJiri Pirko u32 handle; 89e69985c6SAmir Vadai u32 flags; 900552c8afSCong Wang union { 910552c8afSCong Wang struct work_struct work; 9277b9900eSJiri Pirko struct rcu_head rcu; 9377b9900eSJiri Pirko }; 9477b9900eSJiri Pirko struct net_device *hw_dev; 9577b9900eSJiri Pirko }; 9677b9900eSJiri Pirko 9777b9900eSJiri Pirko static unsigned short int fl_mask_range(const struct fl_flow_mask *mask) 9877b9900eSJiri Pirko { 9977b9900eSJiri Pirko return mask->range.end - mask->range.start; 10077b9900eSJiri Pirko } 10177b9900eSJiri Pirko 10277b9900eSJiri Pirko static void fl_mask_update_range(struct fl_flow_mask *mask) 10377b9900eSJiri Pirko { 10477b9900eSJiri Pirko const u8 *bytes = (const u8 *) &mask->key; 10577b9900eSJiri Pirko size_t size = sizeof(mask->key); 10677b9900eSJiri Pirko size_t i, first = 0, last = size - 1; 10777b9900eSJiri Pirko 10877b9900eSJiri Pirko for (i = 0; i < sizeof(mask->key); i++) { 10977b9900eSJiri Pirko if (bytes[i]) { 11077b9900eSJiri Pirko if (!first && i) 11177b9900eSJiri Pirko first = i; 11277b9900eSJiri Pirko last = i; 11377b9900eSJiri Pirko } 11477b9900eSJiri Pirko } 11577b9900eSJiri Pirko mask->range.start = rounddown(first, sizeof(long)); 11677b9900eSJiri Pirko mask->range.end = roundup(last + 1, sizeof(long)); 11777b9900eSJiri Pirko } 11877b9900eSJiri Pirko 11977b9900eSJiri Pirko static void *fl_key_get_start(struct fl_flow_key *key, 12077b9900eSJiri Pirko const struct fl_flow_mask *mask) 12177b9900eSJiri Pirko { 12277b9900eSJiri Pirko return (u8 *) key + mask->range.start; 12377b9900eSJiri Pirko } 12477b9900eSJiri Pirko 12577b9900eSJiri Pirko static void fl_set_masked_key(struct fl_flow_key *mkey, struct fl_flow_key *key, 12677b9900eSJiri Pirko struct fl_flow_mask *mask) 12777b9900eSJiri Pirko { 12877b9900eSJiri Pirko const long *lkey = fl_key_get_start(key, mask); 12977b9900eSJiri Pirko const long *lmask = fl_key_get_start(&mask->key, mask); 13077b9900eSJiri Pirko long *lmkey = fl_key_get_start(mkey, mask); 13177b9900eSJiri Pirko int i; 13277b9900eSJiri Pirko 13377b9900eSJiri Pirko for (i = 0; i < fl_mask_range(mask); i += sizeof(long)) 13477b9900eSJiri Pirko *lmkey++ = *lkey++ & *lmask++; 13577b9900eSJiri Pirko } 13677b9900eSJiri Pirko 13777b9900eSJiri Pirko static void fl_clear_masked_range(struct fl_flow_key *key, 13877b9900eSJiri Pirko struct fl_flow_mask *mask) 13977b9900eSJiri Pirko { 14077b9900eSJiri Pirko memset(fl_key_get_start(key, mask), 0, fl_mask_range(mask)); 14177b9900eSJiri Pirko } 14277b9900eSJiri Pirko 143a3308d8fSPaul Blakey static struct cls_fl_filter *fl_lookup(struct cls_fl_head *head, 144a3308d8fSPaul Blakey struct fl_flow_key *mkey) 145a3308d8fSPaul Blakey { 146a3308d8fSPaul Blakey return rhashtable_lookup_fast(&head->ht, 147a3308d8fSPaul Blakey fl_key_get_start(mkey, &head->mask), 148a3308d8fSPaul Blakey head->ht_params); 149a3308d8fSPaul Blakey } 150a3308d8fSPaul Blakey 15177b9900eSJiri Pirko static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp, 15277b9900eSJiri Pirko struct tcf_result *res) 15377b9900eSJiri Pirko { 15477b9900eSJiri Pirko struct cls_fl_head *head = rcu_dereference_bh(tp->root); 15577b9900eSJiri Pirko struct cls_fl_filter *f; 15677b9900eSJiri Pirko struct fl_flow_key skb_key; 15777b9900eSJiri Pirko struct fl_flow_key skb_mkey; 15877b9900eSJiri Pirko 159e69985c6SAmir Vadai if (!atomic_read(&head->ht.nelems)) 160e69985c6SAmir Vadai return -1; 161e69985c6SAmir Vadai 16277b9900eSJiri Pirko fl_clear_masked_range(&skb_key, &head->mask); 163bc3103f1SAmir Vadai 16477b9900eSJiri Pirko skb_key.indev_ifindex = skb->skb_iif; 16577b9900eSJiri Pirko /* skb_flow_dissect() does not set n_proto in case an unknown protocol, 16677b9900eSJiri Pirko * so do it rather here. 16777b9900eSJiri Pirko */ 16877b9900eSJiri Pirko skb_key.basic.n_proto = skb->protocol; 16962b32379SSimon Horman skb_flow_dissect_tunnel_info(skb, &head->dissector, &skb_key); 170cd79a238STom Herbert skb_flow_dissect(skb, &head->dissector, &skb_key, 0); 17177b9900eSJiri Pirko 17277b9900eSJiri Pirko fl_set_masked_key(&skb_mkey, &skb_key, &head->mask); 17377b9900eSJiri Pirko 174a3308d8fSPaul Blakey f = fl_lookup(head, &skb_mkey); 175e8eb36cdSAmir Vadai if (f && !tc_skip_sw(f->flags)) { 17677b9900eSJiri Pirko *res = f->res; 17777b9900eSJiri Pirko return tcf_exts_exec(skb, &f->exts, res); 17877b9900eSJiri Pirko } 17977b9900eSJiri Pirko return -1; 18077b9900eSJiri Pirko } 18177b9900eSJiri Pirko 18277b9900eSJiri Pirko static int fl_init(struct tcf_proto *tp) 18377b9900eSJiri Pirko { 18477b9900eSJiri Pirko struct cls_fl_head *head; 18577b9900eSJiri Pirko 18677b9900eSJiri Pirko head = kzalloc(sizeof(*head), GFP_KERNEL); 18777b9900eSJiri Pirko if (!head) 18877b9900eSJiri Pirko return -ENOBUFS; 18977b9900eSJiri Pirko 19077b9900eSJiri Pirko INIT_LIST_HEAD_RCU(&head->filters); 19177b9900eSJiri Pirko rcu_assign_pointer(tp->root, head); 192c15ab236SChris Mi idr_init(&head->handle_idr); 19377b9900eSJiri Pirko 19477b9900eSJiri Pirko return 0; 19577b9900eSJiri Pirko } 19677b9900eSJiri Pirko 1970dadc117SCong Wang static void __fl_destroy_filter(struct cls_fl_filter *f) 1980dadc117SCong Wang { 1990dadc117SCong Wang tcf_exts_destroy(&f->exts); 2000dadc117SCong Wang tcf_exts_put_net(&f->exts); 2010dadc117SCong Wang kfree(f); 2020dadc117SCong Wang } 2030dadc117SCong Wang 2040552c8afSCong Wang static void fl_destroy_filter_work(struct work_struct *work) 2050552c8afSCong Wang { 2060552c8afSCong Wang struct cls_fl_filter *f = container_of(work, struct cls_fl_filter, work); 2070552c8afSCong Wang 2080552c8afSCong Wang rtnl_lock(); 2090dadc117SCong Wang __fl_destroy_filter(f); 2100552c8afSCong Wang rtnl_unlock(); 2110552c8afSCong Wang } 2120552c8afSCong Wang 21377b9900eSJiri Pirko static void fl_destroy_filter(struct rcu_head *head) 21477b9900eSJiri Pirko { 21577b9900eSJiri Pirko struct cls_fl_filter *f = container_of(head, struct cls_fl_filter, rcu); 21677b9900eSJiri Pirko 2170552c8afSCong Wang INIT_WORK(&f->work, fl_destroy_filter_work); 2180552c8afSCong Wang tcf_queue_work(&f->work); 21977b9900eSJiri Pirko } 22077b9900eSJiri Pirko 2211b0f8037SJakub Kicinski static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f, 2221b0f8037SJakub Kicinski struct netlink_ext_ack *extack) 2235b33f488SAmir Vadai { 224de4784caSJiri Pirko struct tc_cls_flower_offload cls_flower = {}; 225208c0f4bSJiri Pirko struct tcf_block *block = tp->chain->block; 2265b33f488SAmir Vadai 2271b0f8037SJakub Kicinski tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack); 228de4784caSJiri Pirko cls_flower.command = TC_CLSFLOWER_DESTROY; 229de4784caSJiri Pirko cls_flower.cookie = (unsigned long) f; 2305b33f488SAmir Vadai 231208c0f4bSJiri Pirko tc_setup_cb_call(block, &f->exts, TC_SETUP_CLSFLOWER, 232717503b9SJiri Pirko &cls_flower, false); 233caa72601SJiri Pirko tcf_block_offload_dec(block, &f->flags); 2345b33f488SAmir Vadai } 2355b33f488SAmir Vadai 236e8eb36cdSAmir Vadai static int fl_hw_replace_filter(struct tcf_proto *tp, 2375b33f488SAmir Vadai struct flow_dissector *dissector, 2385b33f488SAmir Vadai struct fl_flow_key *mask, 23941002038SQuentin Monnet struct cls_fl_filter *f, 24041002038SQuentin Monnet struct netlink_ext_ack *extack) 2415b33f488SAmir Vadai { 242de4784caSJiri Pirko struct tc_cls_flower_offload cls_flower = {}; 243208c0f4bSJiri Pirko struct tcf_block *block = tp->chain->block; 244717503b9SJiri Pirko bool skip_sw = tc_skip_sw(f->flags); 245e8eb36cdSAmir Vadai int err; 2465b33f488SAmir Vadai 247ea205940SJakub Kicinski tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack); 248de4784caSJiri Pirko cls_flower.command = TC_CLSFLOWER_REPLACE; 249de4784caSJiri Pirko cls_flower.cookie = (unsigned long) f; 250de4784caSJiri Pirko cls_flower.dissector = dissector; 251de4784caSJiri Pirko cls_flower.mask = mask; 252de4784caSJiri Pirko cls_flower.key = &f->mkey; 253de4784caSJiri Pirko cls_flower.exts = &f->exts; 254384c181eSAmritha Nambiar cls_flower.classid = f->res.classid; 2555b33f488SAmir Vadai 256208c0f4bSJiri Pirko err = tc_setup_cb_call(block, &f->exts, TC_SETUP_CLSFLOWER, 257717503b9SJiri Pirko &cls_flower, skip_sw); 258717503b9SJiri Pirko if (err < 0) { 2591b0f8037SJakub Kicinski fl_hw_destroy_filter(tp, f, NULL); 260717503b9SJiri Pirko return err; 261717503b9SJiri Pirko } else if (err > 0) { 262caa72601SJiri Pirko tcf_block_offload_inc(block, &f->flags); 263717503b9SJiri Pirko } 264717503b9SJiri Pirko 265717503b9SJiri Pirko if (skip_sw && !(f->flags & TCA_CLS_FLAGS_IN_HW)) 266717503b9SJiri Pirko return -EINVAL; 267717503b9SJiri Pirko 268e8eb36cdSAmir Vadai return 0; 2695b33f488SAmir Vadai } 2705b33f488SAmir Vadai 27110cbc684SAmir Vadai static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f) 27210cbc684SAmir Vadai { 273de4784caSJiri Pirko struct tc_cls_flower_offload cls_flower = {}; 274208c0f4bSJiri Pirko struct tcf_block *block = tp->chain->block; 27510cbc684SAmir Vadai 276ea205940SJakub Kicinski tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, NULL); 277de4784caSJiri Pirko cls_flower.command = TC_CLSFLOWER_STATS; 278de4784caSJiri Pirko cls_flower.cookie = (unsigned long) f; 279de4784caSJiri Pirko cls_flower.exts = &f->exts; 280384c181eSAmritha Nambiar cls_flower.classid = f->res.classid; 28110cbc684SAmir Vadai 282208c0f4bSJiri Pirko tc_setup_cb_call(block, &f->exts, TC_SETUP_CLSFLOWER, 283717503b9SJiri Pirko &cls_flower, false); 28410cbc684SAmir Vadai } 28510cbc684SAmir Vadai 2861b0f8037SJakub Kicinski static void __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, 2871b0f8037SJakub Kicinski struct netlink_ext_ack *extack) 28813fa876eSRoi Dayan { 289c15ab236SChris Mi struct cls_fl_head *head = rtnl_dereference(tp->root); 290c15ab236SChris Mi 291*9c160941SMatthew Wilcox idr_remove(&head->handle_idr, f->handle); 29213fa876eSRoi Dayan list_del_rcu(&f->list); 29379685219SHadar Hen Zion if (!tc_skip_hw(f->flags)) 2941b0f8037SJakub Kicinski fl_hw_destroy_filter(tp, f, extack); 29513fa876eSRoi Dayan tcf_unbind_filter(tp, &f->res); 2960dadc117SCong Wang if (tcf_exts_get_net(&f->exts)) 29713fa876eSRoi Dayan call_rcu(&f->rcu, fl_destroy_filter); 2980dadc117SCong Wang else 2990dadc117SCong Wang __fl_destroy_filter(f); 30013fa876eSRoi Dayan } 30113fa876eSRoi Dayan 302d9363774SDaniel Borkmann static void fl_destroy_sleepable(struct work_struct *work) 303d9363774SDaniel Borkmann { 304d9363774SDaniel Borkmann struct cls_fl_head *head = container_of(work, struct cls_fl_head, 305d9363774SDaniel Borkmann work); 306d9363774SDaniel Borkmann if (head->mask_assigned) 307d9363774SDaniel Borkmann rhashtable_destroy(&head->ht); 308d9363774SDaniel Borkmann kfree(head); 309d9363774SDaniel Borkmann module_put(THIS_MODULE); 310d9363774SDaniel Borkmann } 311d9363774SDaniel Borkmann 312d9363774SDaniel Borkmann static void fl_destroy_rcu(struct rcu_head *rcu) 313d9363774SDaniel Borkmann { 314d9363774SDaniel Borkmann struct cls_fl_head *head = container_of(rcu, struct cls_fl_head, rcu); 315d9363774SDaniel Borkmann 316d9363774SDaniel Borkmann INIT_WORK(&head->work, fl_destroy_sleepable); 317d9363774SDaniel Borkmann schedule_work(&head->work); 318d9363774SDaniel Borkmann } 319d9363774SDaniel Borkmann 320715df5ecSJakub Kicinski static void fl_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack) 32177b9900eSJiri Pirko { 32277b9900eSJiri Pirko struct cls_fl_head *head = rtnl_dereference(tp->root); 32377b9900eSJiri Pirko struct cls_fl_filter *f, *next; 32477b9900eSJiri Pirko 32513fa876eSRoi Dayan list_for_each_entry_safe(f, next, &head->filters, list) 3261b0f8037SJakub Kicinski __fl_delete(tp, f, extack); 327c15ab236SChris Mi idr_destroy(&head->handle_idr); 328d9363774SDaniel Borkmann 329d9363774SDaniel Borkmann __module_get(THIS_MODULE); 330d9363774SDaniel Borkmann call_rcu(&head->rcu, fl_destroy_rcu); 33177b9900eSJiri Pirko } 33277b9900eSJiri Pirko 3338113c095SWANG Cong static void *fl_get(struct tcf_proto *tp, u32 handle) 33477b9900eSJiri Pirko { 33577b9900eSJiri Pirko struct cls_fl_head *head = rtnl_dereference(tp->root); 33677b9900eSJiri Pirko 337c15ab236SChris Mi return idr_find_ext(&head->handle_idr, handle); 33877b9900eSJiri Pirko } 33977b9900eSJiri Pirko 34077b9900eSJiri Pirko static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = { 34177b9900eSJiri Pirko [TCA_FLOWER_UNSPEC] = { .type = NLA_UNSPEC }, 34277b9900eSJiri Pirko [TCA_FLOWER_CLASSID] = { .type = NLA_U32 }, 34377b9900eSJiri Pirko [TCA_FLOWER_INDEV] = { .type = NLA_STRING, 34477b9900eSJiri Pirko .len = IFNAMSIZ }, 34577b9900eSJiri Pirko [TCA_FLOWER_KEY_ETH_DST] = { .len = ETH_ALEN }, 34677b9900eSJiri Pirko [TCA_FLOWER_KEY_ETH_DST_MASK] = { .len = ETH_ALEN }, 34777b9900eSJiri Pirko [TCA_FLOWER_KEY_ETH_SRC] = { .len = ETH_ALEN }, 34877b9900eSJiri Pirko [TCA_FLOWER_KEY_ETH_SRC_MASK] = { .len = ETH_ALEN }, 34977b9900eSJiri Pirko [TCA_FLOWER_KEY_ETH_TYPE] = { .type = NLA_U16 }, 35077b9900eSJiri Pirko [TCA_FLOWER_KEY_IP_PROTO] = { .type = NLA_U8 }, 35177b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV4_SRC] = { .type = NLA_U32 }, 35277b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV4_SRC_MASK] = { .type = NLA_U32 }, 35377b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV4_DST] = { .type = NLA_U32 }, 35477b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV4_DST_MASK] = { .type = NLA_U32 }, 35577b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV6_SRC] = { .len = sizeof(struct in6_addr) }, 35677b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) }, 35777b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV6_DST] = { .len = sizeof(struct in6_addr) }, 35877b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) }, 35977b9900eSJiri Pirko [TCA_FLOWER_KEY_TCP_SRC] = { .type = NLA_U16 }, 36077b9900eSJiri Pirko [TCA_FLOWER_KEY_TCP_DST] = { .type = NLA_U16 }, 361b175c3a4SJamal Hadi Salim [TCA_FLOWER_KEY_UDP_SRC] = { .type = NLA_U16 }, 362b175c3a4SJamal Hadi Salim [TCA_FLOWER_KEY_UDP_DST] = { .type = NLA_U16 }, 3639399ae9aSHadar Hen Zion [TCA_FLOWER_KEY_VLAN_ID] = { .type = NLA_U16 }, 3649399ae9aSHadar Hen Zion [TCA_FLOWER_KEY_VLAN_PRIO] = { .type = NLA_U8 }, 3659399ae9aSHadar Hen Zion [TCA_FLOWER_KEY_VLAN_ETH_TYPE] = { .type = NLA_U16 }, 366bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_KEY_ID] = { .type = NLA_U32 }, 367bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV4_SRC] = { .type = NLA_U32 }, 368bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] = { .type = NLA_U32 }, 369bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV4_DST] = { .type = NLA_U32 }, 370bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] = { .type = NLA_U32 }, 371bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV6_SRC] = { .len = sizeof(struct in6_addr) }, 372bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) }, 373bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV6_DST] = { .len = sizeof(struct in6_addr) }, 374bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) }, 375aa72d708SOr Gerlitz [TCA_FLOWER_KEY_TCP_SRC_MASK] = { .type = NLA_U16 }, 376aa72d708SOr Gerlitz [TCA_FLOWER_KEY_TCP_DST_MASK] = { .type = NLA_U16 }, 377aa72d708SOr Gerlitz [TCA_FLOWER_KEY_UDP_SRC_MASK] = { .type = NLA_U16 }, 378aa72d708SOr Gerlitz [TCA_FLOWER_KEY_UDP_DST_MASK] = { .type = NLA_U16 }, 3795976c5f4SSimon Horman [TCA_FLOWER_KEY_SCTP_SRC_MASK] = { .type = NLA_U16 }, 3805976c5f4SSimon Horman [TCA_FLOWER_KEY_SCTP_DST_MASK] = { .type = NLA_U16 }, 3815976c5f4SSimon Horman [TCA_FLOWER_KEY_SCTP_SRC] = { .type = NLA_U16 }, 3825976c5f4SSimon Horman [TCA_FLOWER_KEY_SCTP_DST] = { .type = NLA_U16 }, 383f4d997fdSHadar Hen Zion [TCA_FLOWER_KEY_ENC_UDP_SRC_PORT] = { .type = NLA_U16 }, 384f4d997fdSHadar Hen Zion [TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK] = { .type = NLA_U16 }, 385f4d997fdSHadar Hen Zion [TCA_FLOWER_KEY_ENC_UDP_DST_PORT] = { .type = NLA_U16 }, 386f4d997fdSHadar Hen Zion [TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK] = { .type = NLA_U16 }, 387faa3ffceSOr Gerlitz [TCA_FLOWER_KEY_FLAGS] = { .type = NLA_U32 }, 388faa3ffceSOr Gerlitz [TCA_FLOWER_KEY_FLAGS_MASK] = { .type = NLA_U32 }, 3897b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV4_TYPE] = { .type = NLA_U8 }, 3907b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV4_TYPE_MASK] = { .type = NLA_U8 }, 3917b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV4_CODE] = { .type = NLA_U8 }, 3927b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV4_CODE_MASK] = { .type = NLA_U8 }, 3937b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV6_TYPE] = { .type = NLA_U8 }, 3947b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV6_TYPE_MASK] = { .type = NLA_U8 }, 3957b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV6_CODE] = { .type = NLA_U8 }, 3967b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV6_CODE_MASK] = { .type = NLA_U8 }, 39799d31326SSimon Horman [TCA_FLOWER_KEY_ARP_SIP] = { .type = NLA_U32 }, 39899d31326SSimon Horman [TCA_FLOWER_KEY_ARP_SIP_MASK] = { .type = NLA_U32 }, 39999d31326SSimon Horman [TCA_FLOWER_KEY_ARP_TIP] = { .type = NLA_U32 }, 40099d31326SSimon Horman [TCA_FLOWER_KEY_ARP_TIP_MASK] = { .type = NLA_U32 }, 40199d31326SSimon Horman [TCA_FLOWER_KEY_ARP_OP] = { .type = NLA_U8 }, 40299d31326SSimon Horman [TCA_FLOWER_KEY_ARP_OP_MASK] = { .type = NLA_U8 }, 40399d31326SSimon Horman [TCA_FLOWER_KEY_ARP_SHA] = { .len = ETH_ALEN }, 40499d31326SSimon Horman [TCA_FLOWER_KEY_ARP_SHA_MASK] = { .len = ETH_ALEN }, 40599d31326SSimon Horman [TCA_FLOWER_KEY_ARP_THA] = { .len = ETH_ALEN }, 40699d31326SSimon Horman [TCA_FLOWER_KEY_ARP_THA_MASK] = { .len = ETH_ALEN }, 407a577d8f7SBenjamin LaHaise [TCA_FLOWER_KEY_MPLS_TTL] = { .type = NLA_U8 }, 408a577d8f7SBenjamin LaHaise [TCA_FLOWER_KEY_MPLS_BOS] = { .type = NLA_U8 }, 409a577d8f7SBenjamin LaHaise [TCA_FLOWER_KEY_MPLS_TC] = { .type = NLA_U8 }, 410a577d8f7SBenjamin LaHaise [TCA_FLOWER_KEY_MPLS_LABEL] = { .type = NLA_U32 }, 411fdfc7dd6SJiri Pirko [TCA_FLOWER_KEY_TCP_FLAGS] = { .type = NLA_U16 }, 412fdfc7dd6SJiri Pirko [TCA_FLOWER_KEY_TCP_FLAGS_MASK] = { .type = NLA_U16 }, 4134d80cc0aSOr Gerlitz [TCA_FLOWER_KEY_IP_TOS] = { .type = NLA_U8 }, 4144d80cc0aSOr Gerlitz [TCA_FLOWER_KEY_IP_TOS_MASK] = { .type = NLA_U8 }, 4154d80cc0aSOr Gerlitz [TCA_FLOWER_KEY_IP_TTL] = { .type = NLA_U8 }, 4164d80cc0aSOr Gerlitz [TCA_FLOWER_KEY_IP_TTL_MASK] = { .type = NLA_U8 }, 41777b9900eSJiri Pirko }; 41877b9900eSJiri Pirko 41977b9900eSJiri Pirko static void fl_set_key_val(struct nlattr **tb, 42077b9900eSJiri Pirko void *val, int val_type, 42177b9900eSJiri Pirko void *mask, int mask_type, int len) 42277b9900eSJiri Pirko { 42377b9900eSJiri Pirko if (!tb[val_type]) 42477b9900eSJiri Pirko return; 42577b9900eSJiri Pirko memcpy(val, nla_data(tb[val_type]), len); 42677b9900eSJiri Pirko if (mask_type == TCA_FLOWER_UNSPEC || !tb[mask_type]) 42777b9900eSJiri Pirko memset(mask, 0xff, len); 42877b9900eSJiri Pirko else 42977b9900eSJiri Pirko memcpy(mask, nla_data(tb[mask_type]), len); 43077b9900eSJiri Pirko } 43177b9900eSJiri Pirko 4321a7fca63SBenjamin LaHaise static int fl_set_key_mpls(struct nlattr **tb, 433a577d8f7SBenjamin LaHaise struct flow_dissector_key_mpls *key_val, 434a577d8f7SBenjamin LaHaise struct flow_dissector_key_mpls *key_mask) 435a577d8f7SBenjamin LaHaise { 436a577d8f7SBenjamin LaHaise if (tb[TCA_FLOWER_KEY_MPLS_TTL]) { 437a577d8f7SBenjamin LaHaise key_val->mpls_ttl = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TTL]); 438a577d8f7SBenjamin LaHaise key_mask->mpls_ttl = MPLS_TTL_MASK; 439a577d8f7SBenjamin LaHaise } 440a577d8f7SBenjamin LaHaise if (tb[TCA_FLOWER_KEY_MPLS_BOS]) { 4411a7fca63SBenjamin LaHaise u8 bos = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_BOS]); 4421a7fca63SBenjamin LaHaise 4431a7fca63SBenjamin LaHaise if (bos & ~MPLS_BOS_MASK) 4441a7fca63SBenjamin LaHaise return -EINVAL; 4451a7fca63SBenjamin LaHaise key_val->mpls_bos = bos; 446a577d8f7SBenjamin LaHaise key_mask->mpls_bos = MPLS_BOS_MASK; 447a577d8f7SBenjamin LaHaise } 448a577d8f7SBenjamin LaHaise if (tb[TCA_FLOWER_KEY_MPLS_TC]) { 4491a7fca63SBenjamin LaHaise u8 tc = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TC]); 4501a7fca63SBenjamin LaHaise 4511a7fca63SBenjamin LaHaise if (tc & ~MPLS_TC_MASK) 4521a7fca63SBenjamin LaHaise return -EINVAL; 4531a7fca63SBenjamin LaHaise key_val->mpls_tc = tc; 454a577d8f7SBenjamin LaHaise key_mask->mpls_tc = MPLS_TC_MASK; 455a577d8f7SBenjamin LaHaise } 456a577d8f7SBenjamin LaHaise if (tb[TCA_FLOWER_KEY_MPLS_LABEL]) { 4571a7fca63SBenjamin LaHaise u32 label = nla_get_u32(tb[TCA_FLOWER_KEY_MPLS_LABEL]); 4581a7fca63SBenjamin LaHaise 4591a7fca63SBenjamin LaHaise if (label & ~MPLS_LABEL_MASK) 4601a7fca63SBenjamin LaHaise return -EINVAL; 4611a7fca63SBenjamin LaHaise key_val->mpls_label = label; 462a577d8f7SBenjamin LaHaise key_mask->mpls_label = MPLS_LABEL_MASK; 463a577d8f7SBenjamin LaHaise } 4641a7fca63SBenjamin LaHaise return 0; 465a577d8f7SBenjamin LaHaise } 466a577d8f7SBenjamin LaHaise 4679399ae9aSHadar Hen Zion static void fl_set_key_vlan(struct nlattr **tb, 4689399ae9aSHadar Hen Zion struct flow_dissector_key_vlan *key_val, 4699399ae9aSHadar Hen Zion struct flow_dissector_key_vlan *key_mask) 4709399ae9aSHadar Hen Zion { 4719399ae9aSHadar Hen Zion #define VLAN_PRIORITY_MASK 0x7 4729399ae9aSHadar Hen Zion 4739399ae9aSHadar Hen Zion if (tb[TCA_FLOWER_KEY_VLAN_ID]) { 4749399ae9aSHadar Hen Zion key_val->vlan_id = 4759399ae9aSHadar Hen Zion nla_get_u16(tb[TCA_FLOWER_KEY_VLAN_ID]) & VLAN_VID_MASK; 4769399ae9aSHadar Hen Zion key_mask->vlan_id = VLAN_VID_MASK; 4779399ae9aSHadar Hen Zion } 4789399ae9aSHadar Hen Zion if (tb[TCA_FLOWER_KEY_VLAN_PRIO]) { 4799399ae9aSHadar Hen Zion key_val->vlan_priority = 4809399ae9aSHadar Hen Zion nla_get_u8(tb[TCA_FLOWER_KEY_VLAN_PRIO]) & 4819399ae9aSHadar Hen Zion VLAN_PRIORITY_MASK; 4829399ae9aSHadar Hen Zion key_mask->vlan_priority = VLAN_PRIORITY_MASK; 4839399ae9aSHadar Hen Zion } 4849399ae9aSHadar Hen Zion } 4859399ae9aSHadar Hen Zion 486faa3ffceSOr Gerlitz static void fl_set_key_flag(u32 flower_key, u32 flower_mask, 487faa3ffceSOr Gerlitz u32 *dissector_key, u32 *dissector_mask, 488faa3ffceSOr Gerlitz u32 flower_flag_bit, u32 dissector_flag_bit) 489faa3ffceSOr Gerlitz { 490faa3ffceSOr Gerlitz if (flower_mask & flower_flag_bit) { 491faa3ffceSOr Gerlitz *dissector_mask |= dissector_flag_bit; 492faa3ffceSOr Gerlitz if (flower_key & flower_flag_bit) 493faa3ffceSOr Gerlitz *dissector_key |= dissector_flag_bit; 494faa3ffceSOr Gerlitz } 495faa3ffceSOr Gerlitz } 496faa3ffceSOr Gerlitz 497d9724772SOr Gerlitz static int fl_set_key_flags(struct nlattr **tb, 498faa3ffceSOr Gerlitz u32 *flags_key, u32 *flags_mask) 499faa3ffceSOr Gerlitz { 500faa3ffceSOr Gerlitz u32 key, mask; 501faa3ffceSOr Gerlitz 502d9724772SOr Gerlitz /* mask is mandatory for flags */ 503d9724772SOr Gerlitz if (!tb[TCA_FLOWER_KEY_FLAGS_MASK]) 504d9724772SOr Gerlitz return -EINVAL; 505faa3ffceSOr Gerlitz 506faa3ffceSOr Gerlitz key = be32_to_cpu(nla_get_u32(tb[TCA_FLOWER_KEY_FLAGS])); 507faa3ffceSOr Gerlitz mask = be32_to_cpu(nla_get_u32(tb[TCA_FLOWER_KEY_FLAGS_MASK])); 508faa3ffceSOr Gerlitz 509faa3ffceSOr Gerlitz *flags_key = 0; 510faa3ffceSOr Gerlitz *flags_mask = 0; 511faa3ffceSOr Gerlitz 512faa3ffceSOr Gerlitz fl_set_key_flag(key, mask, flags_key, flags_mask, 513faa3ffceSOr Gerlitz TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT); 514d9724772SOr Gerlitz 515d9724772SOr Gerlitz return 0; 516faa3ffceSOr Gerlitz } 517faa3ffceSOr Gerlitz 5184d80cc0aSOr Gerlitz static void fl_set_key_ip(struct nlattr **tb, 5194d80cc0aSOr Gerlitz struct flow_dissector_key_ip *key, 5204d80cc0aSOr Gerlitz struct flow_dissector_key_ip *mask) 5214d80cc0aSOr Gerlitz { 5224d80cc0aSOr Gerlitz fl_set_key_val(tb, &key->tos, TCA_FLOWER_KEY_IP_TOS, 5234d80cc0aSOr Gerlitz &mask->tos, TCA_FLOWER_KEY_IP_TOS_MASK, 5244d80cc0aSOr Gerlitz sizeof(key->tos)); 5254d80cc0aSOr Gerlitz 5264d80cc0aSOr Gerlitz fl_set_key_val(tb, &key->ttl, TCA_FLOWER_KEY_IP_TTL, 5274d80cc0aSOr Gerlitz &mask->ttl, TCA_FLOWER_KEY_IP_TTL_MASK, 5284d80cc0aSOr Gerlitz sizeof(key->ttl)); 5294d80cc0aSOr Gerlitz } 5304d80cc0aSOr Gerlitz 53177b9900eSJiri Pirko static int fl_set_key(struct net *net, struct nlattr **tb, 5321057c55fSAlexander Aring struct fl_flow_key *key, struct fl_flow_key *mask, 5331057c55fSAlexander Aring struct netlink_ext_ack *extack) 53477b9900eSJiri Pirko { 5359399ae9aSHadar Hen Zion __be16 ethertype; 536d9724772SOr Gerlitz int ret = 0; 537dd3aa3b5SBrian Haley #ifdef CONFIG_NET_CLS_IND 53877b9900eSJiri Pirko if (tb[TCA_FLOWER_INDEV]) { 5391057c55fSAlexander Aring int err = tcf_change_indev(net, tb[TCA_FLOWER_INDEV], extack); 54077b9900eSJiri Pirko if (err < 0) 54177b9900eSJiri Pirko return err; 54277b9900eSJiri Pirko key->indev_ifindex = err; 54377b9900eSJiri Pirko mask->indev_ifindex = 0xffffffff; 54477b9900eSJiri Pirko } 545dd3aa3b5SBrian Haley #endif 54677b9900eSJiri Pirko 54777b9900eSJiri Pirko fl_set_key_val(tb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST, 54877b9900eSJiri Pirko mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK, 54977b9900eSJiri Pirko sizeof(key->eth.dst)); 55077b9900eSJiri Pirko fl_set_key_val(tb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC, 55177b9900eSJiri Pirko mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK, 55277b9900eSJiri Pirko sizeof(key->eth.src)); 55366530bdfSJamal Hadi Salim 5540b498a52SArnd Bergmann if (tb[TCA_FLOWER_KEY_ETH_TYPE]) { 5559399ae9aSHadar Hen Zion ethertype = nla_get_be16(tb[TCA_FLOWER_KEY_ETH_TYPE]); 5569399ae9aSHadar Hen Zion 5579399ae9aSHadar Hen Zion if (ethertype == htons(ETH_P_8021Q)) { 5589399ae9aSHadar Hen Zion fl_set_key_vlan(tb, &key->vlan, &mask->vlan); 5599399ae9aSHadar Hen Zion fl_set_key_val(tb, &key->basic.n_proto, 5609399ae9aSHadar Hen Zion TCA_FLOWER_KEY_VLAN_ETH_TYPE, 56177b9900eSJiri Pirko &mask->basic.n_proto, TCA_FLOWER_UNSPEC, 56277b9900eSJiri Pirko sizeof(key->basic.n_proto)); 5639399ae9aSHadar Hen Zion } else { 5649399ae9aSHadar Hen Zion key->basic.n_proto = ethertype; 5659399ae9aSHadar Hen Zion mask->basic.n_proto = cpu_to_be16(~0); 5669399ae9aSHadar Hen Zion } 5670b498a52SArnd Bergmann } 56866530bdfSJamal Hadi Salim 56977b9900eSJiri Pirko if (key->basic.n_proto == htons(ETH_P_IP) || 57077b9900eSJiri Pirko key->basic.n_proto == htons(ETH_P_IPV6)) { 57177b9900eSJiri Pirko fl_set_key_val(tb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO, 57277b9900eSJiri Pirko &mask->basic.ip_proto, TCA_FLOWER_UNSPEC, 57377b9900eSJiri Pirko sizeof(key->basic.ip_proto)); 5744d80cc0aSOr Gerlitz fl_set_key_ip(tb, &key->ip, &mask->ip); 57577b9900eSJiri Pirko } 57666530bdfSJamal Hadi Salim 57766530bdfSJamal Hadi Salim if (tb[TCA_FLOWER_KEY_IPV4_SRC] || tb[TCA_FLOWER_KEY_IPV4_DST]) { 57866530bdfSJamal Hadi Salim key->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; 579970bfcd0SPaul Blakey mask->control.addr_type = ~0; 58077b9900eSJiri Pirko fl_set_key_val(tb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC, 58177b9900eSJiri Pirko &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK, 58277b9900eSJiri Pirko sizeof(key->ipv4.src)); 58377b9900eSJiri Pirko fl_set_key_val(tb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST, 58477b9900eSJiri Pirko &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK, 58577b9900eSJiri Pirko sizeof(key->ipv4.dst)); 58666530bdfSJamal Hadi Salim } else if (tb[TCA_FLOWER_KEY_IPV6_SRC] || tb[TCA_FLOWER_KEY_IPV6_DST]) { 58766530bdfSJamal Hadi Salim key->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; 588970bfcd0SPaul Blakey mask->control.addr_type = ~0; 58977b9900eSJiri Pirko fl_set_key_val(tb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC, 59077b9900eSJiri Pirko &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK, 59177b9900eSJiri Pirko sizeof(key->ipv6.src)); 59277b9900eSJiri Pirko fl_set_key_val(tb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST, 59377b9900eSJiri Pirko &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK, 59477b9900eSJiri Pirko sizeof(key->ipv6.dst)); 59577b9900eSJiri Pirko } 59666530bdfSJamal Hadi Salim 59777b9900eSJiri Pirko if (key->basic.ip_proto == IPPROTO_TCP) { 59877b9900eSJiri Pirko fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC, 599aa72d708SOr Gerlitz &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK, 60077b9900eSJiri Pirko sizeof(key->tp.src)); 60177b9900eSJiri Pirko fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST, 602aa72d708SOr Gerlitz &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK, 60377b9900eSJiri Pirko sizeof(key->tp.dst)); 604fdfc7dd6SJiri Pirko fl_set_key_val(tb, &key->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS, 605fdfc7dd6SJiri Pirko &mask->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS_MASK, 606fdfc7dd6SJiri Pirko sizeof(key->tcp.flags)); 60777b9900eSJiri Pirko } else if (key->basic.ip_proto == IPPROTO_UDP) { 60877b9900eSJiri Pirko fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC, 609aa72d708SOr Gerlitz &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK, 61077b9900eSJiri Pirko sizeof(key->tp.src)); 61177b9900eSJiri Pirko fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST, 612aa72d708SOr Gerlitz &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK, 61377b9900eSJiri Pirko sizeof(key->tp.dst)); 6145976c5f4SSimon Horman } else if (key->basic.ip_proto == IPPROTO_SCTP) { 6155976c5f4SSimon Horman fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC, 6165976c5f4SSimon Horman &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK, 6175976c5f4SSimon Horman sizeof(key->tp.src)); 6185976c5f4SSimon Horman fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST, 6195976c5f4SSimon Horman &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK, 6205976c5f4SSimon Horman sizeof(key->tp.dst)); 6217b684884SSimon Horman } else if (key->basic.n_proto == htons(ETH_P_IP) && 6227b684884SSimon Horman key->basic.ip_proto == IPPROTO_ICMP) { 6237b684884SSimon Horman fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV4_TYPE, 6247b684884SSimon Horman &mask->icmp.type, 6257b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_TYPE_MASK, 6267b684884SSimon Horman sizeof(key->icmp.type)); 6277b684884SSimon Horman fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV4_CODE, 6287b684884SSimon Horman &mask->icmp.code, 6297b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_CODE_MASK, 6307b684884SSimon Horman sizeof(key->icmp.code)); 6317b684884SSimon Horman } else if (key->basic.n_proto == htons(ETH_P_IPV6) && 6327b684884SSimon Horman key->basic.ip_proto == IPPROTO_ICMPV6) { 6337b684884SSimon Horman fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV6_TYPE, 6347b684884SSimon Horman &mask->icmp.type, 6357b684884SSimon Horman TCA_FLOWER_KEY_ICMPV6_TYPE_MASK, 6367b684884SSimon Horman sizeof(key->icmp.type)); 637040587afSSimon Horman fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV6_CODE, 6387b684884SSimon Horman &mask->icmp.code, 639040587afSSimon Horman TCA_FLOWER_KEY_ICMPV6_CODE_MASK, 6407b684884SSimon Horman sizeof(key->icmp.code)); 641a577d8f7SBenjamin LaHaise } else if (key->basic.n_proto == htons(ETH_P_MPLS_UC) || 642a577d8f7SBenjamin LaHaise key->basic.n_proto == htons(ETH_P_MPLS_MC)) { 6431a7fca63SBenjamin LaHaise ret = fl_set_key_mpls(tb, &key->mpls, &mask->mpls); 6441a7fca63SBenjamin LaHaise if (ret) 6451a7fca63SBenjamin LaHaise return ret; 64699d31326SSimon Horman } else if (key->basic.n_proto == htons(ETH_P_ARP) || 64799d31326SSimon Horman key->basic.n_proto == htons(ETH_P_RARP)) { 64899d31326SSimon Horman fl_set_key_val(tb, &key->arp.sip, TCA_FLOWER_KEY_ARP_SIP, 64999d31326SSimon Horman &mask->arp.sip, TCA_FLOWER_KEY_ARP_SIP_MASK, 65099d31326SSimon Horman sizeof(key->arp.sip)); 65199d31326SSimon Horman fl_set_key_val(tb, &key->arp.tip, TCA_FLOWER_KEY_ARP_TIP, 65299d31326SSimon Horman &mask->arp.tip, TCA_FLOWER_KEY_ARP_TIP_MASK, 65399d31326SSimon Horman sizeof(key->arp.tip)); 65499d31326SSimon Horman fl_set_key_val(tb, &key->arp.op, TCA_FLOWER_KEY_ARP_OP, 65599d31326SSimon Horman &mask->arp.op, TCA_FLOWER_KEY_ARP_OP_MASK, 65699d31326SSimon Horman sizeof(key->arp.op)); 65799d31326SSimon Horman fl_set_key_val(tb, key->arp.sha, TCA_FLOWER_KEY_ARP_SHA, 65899d31326SSimon Horman mask->arp.sha, TCA_FLOWER_KEY_ARP_SHA_MASK, 65999d31326SSimon Horman sizeof(key->arp.sha)); 66099d31326SSimon Horman fl_set_key_val(tb, key->arp.tha, TCA_FLOWER_KEY_ARP_THA, 66199d31326SSimon Horman mask->arp.tha, TCA_FLOWER_KEY_ARP_THA_MASK, 66299d31326SSimon Horman sizeof(key->arp.tha)); 66377b9900eSJiri Pirko } 66477b9900eSJiri Pirko 665bc3103f1SAmir Vadai if (tb[TCA_FLOWER_KEY_ENC_IPV4_SRC] || 666bc3103f1SAmir Vadai tb[TCA_FLOWER_KEY_ENC_IPV4_DST]) { 667bc3103f1SAmir Vadai key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; 668970bfcd0SPaul Blakey mask->enc_control.addr_type = ~0; 669bc3103f1SAmir Vadai fl_set_key_val(tb, &key->enc_ipv4.src, 670bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_SRC, 671bc3103f1SAmir Vadai &mask->enc_ipv4.src, 672bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK, 673bc3103f1SAmir Vadai sizeof(key->enc_ipv4.src)); 674bc3103f1SAmir Vadai fl_set_key_val(tb, &key->enc_ipv4.dst, 675bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_DST, 676bc3103f1SAmir Vadai &mask->enc_ipv4.dst, 677bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_DST_MASK, 678bc3103f1SAmir Vadai sizeof(key->enc_ipv4.dst)); 679bc3103f1SAmir Vadai } 680bc3103f1SAmir Vadai 681bc3103f1SAmir Vadai if (tb[TCA_FLOWER_KEY_ENC_IPV6_SRC] || 682bc3103f1SAmir Vadai tb[TCA_FLOWER_KEY_ENC_IPV6_DST]) { 683bc3103f1SAmir Vadai key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; 684970bfcd0SPaul Blakey mask->enc_control.addr_type = ~0; 685bc3103f1SAmir Vadai fl_set_key_val(tb, &key->enc_ipv6.src, 686bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_SRC, 687bc3103f1SAmir Vadai &mask->enc_ipv6.src, 688bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK, 689bc3103f1SAmir Vadai sizeof(key->enc_ipv6.src)); 690bc3103f1SAmir Vadai fl_set_key_val(tb, &key->enc_ipv6.dst, 691bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_DST, 692bc3103f1SAmir Vadai &mask->enc_ipv6.dst, 693bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_DST_MASK, 694bc3103f1SAmir Vadai sizeof(key->enc_ipv6.dst)); 695bc3103f1SAmir Vadai } 696bc3103f1SAmir Vadai 697bc3103f1SAmir Vadai fl_set_key_val(tb, &key->enc_key_id.keyid, TCA_FLOWER_KEY_ENC_KEY_ID, 698eb523f42SHadar Hen Zion &mask->enc_key_id.keyid, TCA_FLOWER_UNSPEC, 699bc3103f1SAmir Vadai sizeof(key->enc_key_id.keyid)); 700bc3103f1SAmir Vadai 701f4d997fdSHadar Hen Zion fl_set_key_val(tb, &key->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT, 702f4d997fdSHadar Hen Zion &mask->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK, 703f4d997fdSHadar Hen Zion sizeof(key->enc_tp.src)); 704f4d997fdSHadar Hen Zion 705f4d997fdSHadar Hen Zion fl_set_key_val(tb, &key->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT, 706f4d997fdSHadar Hen Zion &mask->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK, 707f4d997fdSHadar Hen Zion sizeof(key->enc_tp.dst)); 708f4d997fdSHadar Hen Zion 709d9724772SOr Gerlitz if (tb[TCA_FLOWER_KEY_FLAGS]) 710d9724772SOr Gerlitz ret = fl_set_key_flags(tb, &key->control.flags, &mask->control.flags); 711faa3ffceSOr Gerlitz 712d9724772SOr Gerlitz return ret; 71377b9900eSJiri Pirko } 71477b9900eSJiri Pirko 71577b9900eSJiri Pirko static bool fl_mask_eq(struct fl_flow_mask *mask1, 71677b9900eSJiri Pirko struct fl_flow_mask *mask2) 71777b9900eSJiri Pirko { 71877b9900eSJiri Pirko const long *lmask1 = fl_key_get_start(&mask1->key, mask1); 71977b9900eSJiri Pirko const long *lmask2 = fl_key_get_start(&mask2->key, mask2); 72077b9900eSJiri Pirko 72177b9900eSJiri Pirko return !memcmp(&mask1->range, &mask2->range, sizeof(mask1->range)) && 72277b9900eSJiri Pirko !memcmp(lmask1, lmask2, fl_mask_range(mask1)); 72377b9900eSJiri Pirko } 72477b9900eSJiri Pirko 72577b9900eSJiri Pirko static const struct rhashtable_params fl_ht_params = { 72677b9900eSJiri Pirko .key_offset = offsetof(struct cls_fl_filter, mkey), /* base offset */ 72777b9900eSJiri Pirko .head_offset = offsetof(struct cls_fl_filter, ht_node), 72877b9900eSJiri Pirko .automatic_shrinking = true, 72977b9900eSJiri Pirko }; 73077b9900eSJiri Pirko 73177b9900eSJiri Pirko static int fl_init_hashtable(struct cls_fl_head *head, 73277b9900eSJiri Pirko struct fl_flow_mask *mask) 73377b9900eSJiri Pirko { 73477b9900eSJiri Pirko head->ht_params = fl_ht_params; 73577b9900eSJiri Pirko head->ht_params.key_len = fl_mask_range(mask); 73677b9900eSJiri Pirko head->ht_params.key_offset += mask->range.start; 73777b9900eSJiri Pirko 73877b9900eSJiri Pirko return rhashtable_init(&head->ht, &head->ht_params); 73977b9900eSJiri Pirko } 74077b9900eSJiri Pirko 74177b9900eSJiri Pirko #define FL_KEY_MEMBER_OFFSET(member) offsetof(struct fl_flow_key, member) 74277b9900eSJiri Pirko #define FL_KEY_MEMBER_SIZE(member) (sizeof(((struct fl_flow_key *) 0)->member)) 74377b9900eSJiri Pirko 744339ba878SHadar Hen Zion #define FL_KEY_IS_MASKED(mask, member) \ 745339ba878SHadar Hen Zion memchr_inv(((char *)mask) + FL_KEY_MEMBER_OFFSET(member), \ 746339ba878SHadar Hen Zion 0, FL_KEY_MEMBER_SIZE(member)) \ 74777b9900eSJiri Pirko 74877b9900eSJiri Pirko #define FL_KEY_SET(keys, cnt, id, member) \ 74977b9900eSJiri Pirko do { \ 75077b9900eSJiri Pirko keys[cnt].key_id = id; \ 75177b9900eSJiri Pirko keys[cnt].offset = FL_KEY_MEMBER_OFFSET(member); \ 75277b9900eSJiri Pirko cnt++; \ 75377b9900eSJiri Pirko } while(0); 75477b9900eSJiri Pirko 755339ba878SHadar Hen Zion #define FL_KEY_SET_IF_MASKED(mask, keys, cnt, id, member) \ 75677b9900eSJiri Pirko do { \ 757339ba878SHadar Hen Zion if (FL_KEY_IS_MASKED(mask, member)) \ 75877b9900eSJiri Pirko FL_KEY_SET(keys, cnt, id, member); \ 75977b9900eSJiri Pirko } while(0); 76077b9900eSJiri Pirko 76177b9900eSJiri Pirko static void fl_init_dissector(struct cls_fl_head *head, 76277b9900eSJiri Pirko struct fl_flow_mask *mask) 76377b9900eSJiri Pirko { 76477b9900eSJiri Pirko struct flow_dissector_key keys[FLOW_DISSECTOR_KEY_MAX]; 76577b9900eSJiri Pirko size_t cnt = 0; 76677b9900eSJiri Pirko 76742aecaa9STom Herbert FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_CONTROL, control); 76877b9900eSJiri Pirko FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_BASIC, basic); 769339ba878SHadar Hen Zion FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 77077b9900eSJiri Pirko FLOW_DISSECTOR_KEY_ETH_ADDRS, eth); 771339ba878SHadar Hen Zion FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 77277b9900eSJiri Pirko FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4); 773339ba878SHadar Hen Zion FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 77477b9900eSJiri Pirko FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6); 775339ba878SHadar Hen Zion FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 77677b9900eSJiri Pirko FLOW_DISSECTOR_KEY_PORTS, tp); 7779399ae9aSHadar Hen Zion FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 7784d80cc0aSOr Gerlitz FLOW_DISSECTOR_KEY_IP, ip); 7794d80cc0aSOr Gerlitz FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 780fdfc7dd6SJiri Pirko FLOW_DISSECTOR_KEY_TCP, tcp); 781fdfc7dd6SJiri Pirko FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 7827b684884SSimon Horman FLOW_DISSECTOR_KEY_ICMP, icmp); 7837b684884SSimon Horman FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 78499d31326SSimon Horman FLOW_DISSECTOR_KEY_ARP, arp); 78599d31326SSimon Horman FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 786a577d8f7SBenjamin LaHaise FLOW_DISSECTOR_KEY_MPLS, mpls); 787a577d8f7SBenjamin LaHaise FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 7889399ae9aSHadar Hen Zion FLOW_DISSECTOR_KEY_VLAN, vlan); 789519d1052SHadar Hen Zion FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 790519d1052SHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_KEYID, enc_key_id); 791519d1052SHadar Hen Zion FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 792519d1052SHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, enc_ipv4); 793519d1052SHadar Hen Zion FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 794519d1052SHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, enc_ipv6); 795519d1052SHadar Hen Zion if (FL_KEY_IS_MASKED(&mask->key, enc_ipv4) || 796519d1052SHadar Hen Zion FL_KEY_IS_MASKED(&mask->key, enc_ipv6)) 797519d1052SHadar Hen Zion FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_ENC_CONTROL, 798519d1052SHadar Hen Zion enc_control); 799f4d997fdSHadar Hen Zion FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 800f4d997fdSHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_PORTS, enc_tp); 80177b9900eSJiri Pirko 80277b9900eSJiri Pirko skb_flow_dissector_init(&head->dissector, keys, cnt); 80377b9900eSJiri Pirko } 80477b9900eSJiri Pirko 80577b9900eSJiri Pirko static int fl_check_assign_mask(struct cls_fl_head *head, 80677b9900eSJiri Pirko struct fl_flow_mask *mask) 80777b9900eSJiri Pirko { 80877b9900eSJiri Pirko int err; 80977b9900eSJiri Pirko 81077b9900eSJiri Pirko if (head->mask_assigned) { 81177b9900eSJiri Pirko if (!fl_mask_eq(&head->mask, mask)) 81277b9900eSJiri Pirko return -EINVAL; 81377b9900eSJiri Pirko else 81477b9900eSJiri Pirko return 0; 81577b9900eSJiri Pirko } 81677b9900eSJiri Pirko 81777b9900eSJiri Pirko /* Mask is not assigned yet. So assign it and init hashtable 81877b9900eSJiri Pirko * according to that. 81977b9900eSJiri Pirko */ 82077b9900eSJiri Pirko err = fl_init_hashtable(head, mask); 82177b9900eSJiri Pirko if (err) 82277b9900eSJiri Pirko return err; 82377b9900eSJiri Pirko memcpy(&head->mask, mask, sizeof(head->mask)); 82477b9900eSJiri Pirko head->mask_assigned = true; 82577b9900eSJiri Pirko 82677b9900eSJiri Pirko fl_init_dissector(head, mask); 82777b9900eSJiri Pirko 82877b9900eSJiri Pirko return 0; 82977b9900eSJiri Pirko } 83077b9900eSJiri Pirko 83177b9900eSJiri Pirko static int fl_set_parms(struct net *net, struct tcf_proto *tp, 83277b9900eSJiri Pirko struct cls_fl_filter *f, struct fl_flow_mask *mask, 83377b9900eSJiri Pirko unsigned long base, struct nlattr **tb, 83450a56190SAlexander Aring struct nlattr *est, bool ovr, 83550a56190SAlexander Aring struct netlink_ext_ack *extack) 83677b9900eSJiri Pirko { 83777b9900eSJiri Pirko int err; 83877b9900eSJiri Pirko 83950a56190SAlexander Aring err = tcf_exts_validate(net, tp, tb, est, &f->exts, ovr, extack); 84077b9900eSJiri Pirko if (err < 0) 84177b9900eSJiri Pirko return err; 84277b9900eSJiri Pirko 84377b9900eSJiri Pirko if (tb[TCA_FLOWER_CLASSID]) { 84477b9900eSJiri Pirko f->res.classid = nla_get_u32(tb[TCA_FLOWER_CLASSID]); 84577b9900eSJiri Pirko tcf_bind_filter(tp, &f->res, base); 84677b9900eSJiri Pirko } 84777b9900eSJiri Pirko 8481057c55fSAlexander Aring err = fl_set_key(net, tb, &f->key, &mask->key, extack); 84977b9900eSJiri Pirko if (err) 85045507529SJiri Pirko return err; 85177b9900eSJiri Pirko 85277b9900eSJiri Pirko fl_mask_update_range(mask); 85377b9900eSJiri Pirko fl_set_masked_key(&f->mkey, &f->key, mask); 85477b9900eSJiri Pirko 85577b9900eSJiri Pirko return 0; 85677b9900eSJiri Pirko } 85777b9900eSJiri Pirko 85877b9900eSJiri Pirko static int fl_change(struct net *net, struct sk_buff *in_skb, 85977b9900eSJiri Pirko struct tcf_proto *tp, unsigned long base, 86077b9900eSJiri Pirko u32 handle, struct nlattr **tca, 8617306db38SAlexander Aring void **arg, bool ovr, struct netlink_ext_ack *extack) 86277b9900eSJiri Pirko { 86377b9900eSJiri Pirko struct cls_fl_head *head = rtnl_dereference(tp->root); 8648113c095SWANG Cong struct cls_fl_filter *fold = *arg; 86577b9900eSJiri Pirko struct cls_fl_filter *fnew; 86639b7b6a6SArnd Bergmann struct nlattr **tb; 86777b9900eSJiri Pirko struct fl_flow_mask mask = {}; 868c15ab236SChris Mi unsigned long idr_index; 86977b9900eSJiri Pirko int err; 87077b9900eSJiri Pirko 87177b9900eSJiri Pirko if (!tca[TCA_OPTIONS]) 87277b9900eSJiri Pirko return -EINVAL; 87377b9900eSJiri Pirko 87439b7b6a6SArnd Bergmann tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL); 87539b7b6a6SArnd Bergmann if (!tb) 87639b7b6a6SArnd Bergmann return -ENOBUFS; 87739b7b6a6SArnd Bergmann 878fceb6435SJohannes Berg err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS], 879fceb6435SJohannes Berg fl_policy, NULL); 88077b9900eSJiri Pirko if (err < 0) 88139b7b6a6SArnd Bergmann goto errout_tb; 88277b9900eSJiri Pirko 88339b7b6a6SArnd Bergmann if (fold && handle && fold->handle != handle) { 88439b7b6a6SArnd Bergmann err = -EINVAL; 88539b7b6a6SArnd Bergmann goto errout_tb; 88639b7b6a6SArnd Bergmann } 88777b9900eSJiri Pirko 88877b9900eSJiri Pirko fnew = kzalloc(sizeof(*fnew), GFP_KERNEL); 88939b7b6a6SArnd Bergmann if (!fnew) { 89039b7b6a6SArnd Bergmann err = -ENOBUFS; 89139b7b6a6SArnd Bergmann goto errout_tb; 89239b7b6a6SArnd Bergmann } 89377b9900eSJiri Pirko 894b9a24bb7SWANG Cong err = tcf_exts_init(&fnew->exts, TCA_FLOWER_ACT, 0); 895b9a24bb7SWANG Cong if (err < 0) 896b9a24bb7SWANG Cong goto errout; 89777b9900eSJiri Pirko 89877b9900eSJiri Pirko if (!handle) { 899c15ab236SChris Mi err = idr_alloc_ext(&head->handle_idr, fnew, &idr_index, 900c15ab236SChris Mi 1, 0x80000000, GFP_KERNEL); 901c15ab236SChris Mi if (err) 90277b9900eSJiri Pirko goto errout; 903c15ab236SChris Mi fnew->handle = idr_index; 90477b9900eSJiri Pirko } 905c15ab236SChris Mi 906c15ab236SChris Mi /* user specifies a handle and it doesn't exist */ 907c15ab236SChris Mi if (handle && !fold) { 908c15ab236SChris Mi err = idr_alloc_ext(&head->handle_idr, fnew, &idr_index, 909c15ab236SChris Mi handle, handle + 1, GFP_KERNEL); 910c15ab236SChris Mi if (err) 911c15ab236SChris Mi goto errout; 912c15ab236SChris Mi fnew->handle = idr_index; 91377b9900eSJiri Pirko } 91477b9900eSJiri Pirko 915e69985c6SAmir Vadai if (tb[TCA_FLOWER_FLAGS]) { 916e69985c6SAmir Vadai fnew->flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]); 917e69985c6SAmir Vadai 918e69985c6SAmir Vadai if (!tc_flags_valid(fnew->flags)) { 919e69985c6SAmir Vadai err = -EINVAL; 920fe2502e4SCong Wang goto errout_idr; 921e69985c6SAmir Vadai } 922e69985c6SAmir Vadai } 9235b33f488SAmir Vadai 92450a56190SAlexander Aring err = fl_set_parms(net, tp, fnew, &mask, base, tb, tca[TCA_RATE], ovr, 92550a56190SAlexander Aring extack); 92677b9900eSJiri Pirko if (err) 927fe2502e4SCong Wang goto errout_idr; 92877b9900eSJiri Pirko 92977b9900eSJiri Pirko err = fl_check_assign_mask(head, &mask); 93077b9900eSJiri Pirko if (err) 931fe2502e4SCong Wang goto errout_idr; 93277b9900eSJiri Pirko 933e8eb36cdSAmir Vadai if (!tc_skip_sw(fnew->flags)) { 934a3308d8fSPaul Blakey if (!fold && fl_lookup(head, &fnew->mkey)) { 935a3308d8fSPaul Blakey err = -EEXIST; 936fe2502e4SCong Wang goto errout_idr; 937a3308d8fSPaul Blakey } 938a3308d8fSPaul Blakey 93977b9900eSJiri Pirko err = rhashtable_insert_fast(&head->ht, &fnew->ht_node, 94077b9900eSJiri Pirko head->ht_params); 94177b9900eSJiri Pirko if (err) 942fe2502e4SCong Wang goto errout_idr; 943e69985c6SAmir Vadai } 9445b33f488SAmir Vadai 94579685219SHadar Hen Zion if (!tc_skip_hw(fnew->flags)) { 946e8eb36cdSAmir Vadai err = fl_hw_replace_filter(tp, 9475b33f488SAmir Vadai &head->dissector, 9485b33f488SAmir Vadai &mask.key, 94941002038SQuentin Monnet fnew, 95041002038SQuentin Monnet extack); 951e8eb36cdSAmir Vadai if (err) 952fe2502e4SCong Wang goto errout_idr; 95379685219SHadar Hen Zion } 9545b33f488SAmir Vadai 95555593960SOr Gerlitz if (!tc_in_hw(fnew->flags)) 95655593960SOr Gerlitz fnew->flags |= TCA_CLS_FLAGS_NOT_IN_HW; 95755593960SOr Gerlitz 9585b33f488SAmir Vadai if (fold) { 959725cbb62SJiri Pirko if (!tc_skip_sw(fold->flags)) 96077b9900eSJiri Pirko rhashtable_remove_fast(&head->ht, &fold->ht_node, 96177b9900eSJiri Pirko head->ht_params); 96279685219SHadar Hen Zion if (!tc_skip_hw(fold->flags)) 9631b0f8037SJakub Kicinski fl_hw_destroy_filter(tp, fold, NULL); 9645b33f488SAmir Vadai } 96577b9900eSJiri Pirko 9668113c095SWANG Cong *arg = fnew; 96777b9900eSJiri Pirko 96877b9900eSJiri Pirko if (fold) { 969c15ab236SChris Mi fnew->handle = handle; 970c15ab236SChris Mi idr_replace_ext(&head->handle_idr, fnew, fnew->handle); 971ff3532f2SDaniel Borkmann list_replace_rcu(&fold->list, &fnew->list); 97277b9900eSJiri Pirko tcf_unbind_filter(tp, &fold->res); 9730dadc117SCong Wang tcf_exts_get_net(&fold->exts); 97477b9900eSJiri Pirko call_rcu(&fold->rcu, fl_destroy_filter); 97577b9900eSJiri Pirko } else { 97677b9900eSJiri Pirko list_add_tail_rcu(&fnew->list, &head->filters); 97777b9900eSJiri Pirko } 97877b9900eSJiri Pirko 97939b7b6a6SArnd Bergmann kfree(tb); 98077b9900eSJiri Pirko return 0; 98177b9900eSJiri Pirko 982fe2502e4SCong Wang errout_idr: 983fe2502e4SCong Wang if (fnew->handle) 984*9c160941SMatthew Wilcox idr_remove(&head->handle_idr, fnew->handle); 98577b9900eSJiri Pirko errout: 986b9a24bb7SWANG Cong tcf_exts_destroy(&fnew->exts); 98777b9900eSJiri Pirko kfree(fnew); 98839b7b6a6SArnd Bergmann errout_tb: 98939b7b6a6SArnd Bergmann kfree(tb); 99077b9900eSJiri Pirko return err; 99177b9900eSJiri Pirko } 99277b9900eSJiri Pirko 993571acf21SAlexander Aring static int fl_delete(struct tcf_proto *tp, void *arg, bool *last, 994571acf21SAlexander Aring struct netlink_ext_ack *extack) 99577b9900eSJiri Pirko { 99677b9900eSJiri Pirko struct cls_fl_head *head = rtnl_dereference(tp->root); 9978113c095SWANG Cong struct cls_fl_filter *f = arg; 99877b9900eSJiri Pirko 999725cbb62SJiri Pirko if (!tc_skip_sw(f->flags)) 100077b9900eSJiri Pirko rhashtable_remove_fast(&head->ht, &f->ht_node, 100177b9900eSJiri Pirko head->ht_params); 10021b0f8037SJakub Kicinski __fl_delete(tp, f, extack); 1003763dbf63SWANG Cong *last = list_empty(&head->filters); 100477b9900eSJiri Pirko return 0; 100577b9900eSJiri Pirko } 100677b9900eSJiri Pirko 100777b9900eSJiri Pirko static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg) 100877b9900eSJiri Pirko { 100977b9900eSJiri Pirko struct cls_fl_head *head = rtnl_dereference(tp->root); 101077b9900eSJiri Pirko struct cls_fl_filter *f; 101177b9900eSJiri Pirko 101277b9900eSJiri Pirko list_for_each_entry_rcu(f, &head->filters, list) { 101377b9900eSJiri Pirko if (arg->count < arg->skip) 101477b9900eSJiri Pirko goto skip; 10158113c095SWANG Cong if (arg->fn(tp, f, arg) < 0) { 101677b9900eSJiri Pirko arg->stop = 1; 101777b9900eSJiri Pirko break; 101877b9900eSJiri Pirko } 101977b9900eSJiri Pirko skip: 102077b9900eSJiri Pirko arg->count++; 102177b9900eSJiri Pirko } 102277b9900eSJiri Pirko } 102377b9900eSJiri Pirko 102477b9900eSJiri Pirko static int fl_dump_key_val(struct sk_buff *skb, 102577b9900eSJiri Pirko void *val, int val_type, 102677b9900eSJiri Pirko void *mask, int mask_type, int len) 102777b9900eSJiri Pirko { 102877b9900eSJiri Pirko int err; 102977b9900eSJiri Pirko 103077b9900eSJiri Pirko if (!memchr_inv(mask, 0, len)) 103177b9900eSJiri Pirko return 0; 103277b9900eSJiri Pirko err = nla_put(skb, val_type, len, val); 103377b9900eSJiri Pirko if (err) 103477b9900eSJiri Pirko return err; 103577b9900eSJiri Pirko if (mask_type != TCA_FLOWER_UNSPEC) { 103677b9900eSJiri Pirko err = nla_put(skb, mask_type, len, mask); 103777b9900eSJiri Pirko if (err) 103877b9900eSJiri Pirko return err; 103977b9900eSJiri Pirko } 104077b9900eSJiri Pirko return 0; 104177b9900eSJiri Pirko } 104277b9900eSJiri Pirko 1043a577d8f7SBenjamin LaHaise static int fl_dump_key_mpls(struct sk_buff *skb, 1044a577d8f7SBenjamin LaHaise struct flow_dissector_key_mpls *mpls_key, 1045a577d8f7SBenjamin LaHaise struct flow_dissector_key_mpls *mpls_mask) 1046a577d8f7SBenjamin LaHaise { 1047a577d8f7SBenjamin LaHaise int err; 1048a577d8f7SBenjamin LaHaise 1049a577d8f7SBenjamin LaHaise if (!memchr_inv(mpls_mask, 0, sizeof(*mpls_mask))) 1050a577d8f7SBenjamin LaHaise return 0; 1051a577d8f7SBenjamin LaHaise if (mpls_mask->mpls_ttl) { 1052a577d8f7SBenjamin LaHaise err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TTL, 1053a577d8f7SBenjamin LaHaise mpls_key->mpls_ttl); 1054a577d8f7SBenjamin LaHaise if (err) 1055a577d8f7SBenjamin LaHaise return err; 1056a577d8f7SBenjamin LaHaise } 1057a577d8f7SBenjamin LaHaise if (mpls_mask->mpls_tc) { 1058a577d8f7SBenjamin LaHaise err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TC, 1059a577d8f7SBenjamin LaHaise mpls_key->mpls_tc); 1060a577d8f7SBenjamin LaHaise if (err) 1061a577d8f7SBenjamin LaHaise return err; 1062a577d8f7SBenjamin LaHaise } 1063a577d8f7SBenjamin LaHaise if (mpls_mask->mpls_label) { 1064a577d8f7SBenjamin LaHaise err = nla_put_u32(skb, TCA_FLOWER_KEY_MPLS_LABEL, 1065a577d8f7SBenjamin LaHaise mpls_key->mpls_label); 1066a577d8f7SBenjamin LaHaise if (err) 1067a577d8f7SBenjamin LaHaise return err; 1068a577d8f7SBenjamin LaHaise } 1069a577d8f7SBenjamin LaHaise if (mpls_mask->mpls_bos) { 1070a577d8f7SBenjamin LaHaise err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_BOS, 1071a577d8f7SBenjamin LaHaise mpls_key->mpls_bos); 1072a577d8f7SBenjamin LaHaise if (err) 1073a577d8f7SBenjamin LaHaise return err; 1074a577d8f7SBenjamin LaHaise } 1075a577d8f7SBenjamin LaHaise return 0; 1076a577d8f7SBenjamin LaHaise } 1077a577d8f7SBenjamin LaHaise 10784d80cc0aSOr Gerlitz static int fl_dump_key_ip(struct sk_buff *skb, 10794d80cc0aSOr Gerlitz struct flow_dissector_key_ip *key, 10804d80cc0aSOr Gerlitz struct flow_dissector_key_ip *mask) 10814d80cc0aSOr Gerlitz { 10824d80cc0aSOr Gerlitz if (fl_dump_key_val(skb, &key->tos, TCA_FLOWER_KEY_IP_TOS, &mask->tos, 10834d80cc0aSOr Gerlitz TCA_FLOWER_KEY_IP_TOS_MASK, sizeof(key->tos)) || 10844d80cc0aSOr Gerlitz fl_dump_key_val(skb, &key->ttl, TCA_FLOWER_KEY_IP_TTL, &mask->ttl, 10854d80cc0aSOr Gerlitz TCA_FLOWER_KEY_IP_TTL_MASK, sizeof(key->ttl))) 10864d80cc0aSOr Gerlitz return -1; 10874d80cc0aSOr Gerlitz 10884d80cc0aSOr Gerlitz return 0; 10894d80cc0aSOr Gerlitz } 10904d80cc0aSOr Gerlitz 10919399ae9aSHadar Hen Zion static int fl_dump_key_vlan(struct sk_buff *skb, 10929399ae9aSHadar Hen Zion struct flow_dissector_key_vlan *vlan_key, 10939399ae9aSHadar Hen Zion struct flow_dissector_key_vlan *vlan_mask) 10949399ae9aSHadar Hen Zion { 10959399ae9aSHadar Hen Zion int err; 10969399ae9aSHadar Hen Zion 10979399ae9aSHadar Hen Zion if (!memchr_inv(vlan_mask, 0, sizeof(*vlan_mask))) 10989399ae9aSHadar Hen Zion return 0; 10999399ae9aSHadar Hen Zion if (vlan_mask->vlan_id) { 11009399ae9aSHadar Hen Zion err = nla_put_u16(skb, TCA_FLOWER_KEY_VLAN_ID, 11019399ae9aSHadar Hen Zion vlan_key->vlan_id); 11029399ae9aSHadar Hen Zion if (err) 11039399ae9aSHadar Hen Zion return err; 11049399ae9aSHadar Hen Zion } 11059399ae9aSHadar Hen Zion if (vlan_mask->vlan_priority) { 11069399ae9aSHadar Hen Zion err = nla_put_u8(skb, TCA_FLOWER_KEY_VLAN_PRIO, 11079399ae9aSHadar Hen Zion vlan_key->vlan_priority); 11089399ae9aSHadar Hen Zion if (err) 11099399ae9aSHadar Hen Zion return err; 11109399ae9aSHadar Hen Zion } 11119399ae9aSHadar Hen Zion return 0; 11129399ae9aSHadar Hen Zion } 11139399ae9aSHadar Hen Zion 1114faa3ffceSOr Gerlitz static void fl_get_key_flag(u32 dissector_key, u32 dissector_mask, 1115faa3ffceSOr Gerlitz u32 *flower_key, u32 *flower_mask, 1116faa3ffceSOr Gerlitz u32 flower_flag_bit, u32 dissector_flag_bit) 1117faa3ffceSOr Gerlitz { 1118faa3ffceSOr Gerlitz if (dissector_mask & dissector_flag_bit) { 1119faa3ffceSOr Gerlitz *flower_mask |= flower_flag_bit; 1120faa3ffceSOr Gerlitz if (dissector_key & dissector_flag_bit) 1121faa3ffceSOr Gerlitz *flower_key |= flower_flag_bit; 1122faa3ffceSOr Gerlitz } 1123faa3ffceSOr Gerlitz } 1124faa3ffceSOr Gerlitz 1125faa3ffceSOr Gerlitz static int fl_dump_key_flags(struct sk_buff *skb, u32 flags_key, u32 flags_mask) 1126faa3ffceSOr Gerlitz { 1127faa3ffceSOr Gerlitz u32 key, mask; 1128faa3ffceSOr Gerlitz __be32 _key, _mask; 1129faa3ffceSOr Gerlitz int err; 1130faa3ffceSOr Gerlitz 1131faa3ffceSOr Gerlitz if (!memchr_inv(&flags_mask, 0, sizeof(flags_mask))) 1132faa3ffceSOr Gerlitz return 0; 1133faa3ffceSOr Gerlitz 1134faa3ffceSOr Gerlitz key = 0; 1135faa3ffceSOr Gerlitz mask = 0; 1136faa3ffceSOr Gerlitz 1137faa3ffceSOr Gerlitz fl_get_key_flag(flags_key, flags_mask, &key, &mask, 1138faa3ffceSOr Gerlitz TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT); 1139faa3ffceSOr Gerlitz 1140faa3ffceSOr Gerlitz _key = cpu_to_be32(key); 1141faa3ffceSOr Gerlitz _mask = cpu_to_be32(mask); 1142faa3ffceSOr Gerlitz 1143faa3ffceSOr Gerlitz err = nla_put(skb, TCA_FLOWER_KEY_FLAGS, 4, &_key); 1144faa3ffceSOr Gerlitz if (err) 1145faa3ffceSOr Gerlitz return err; 1146faa3ffceSOr Gerlitz 1147faa3ffceSOr Gerlitz return nla_put(skb, TCA_FLOWER_KEY_FLAGS_MASK, 4, &_mask); 1148faa3ffceSOr Gerlitz } 1149faa3ffceSOr Gerlitz 11508113c095SWANG Cong static int fl_dump(struct net *net, struct tcf_proto *tp, void *fh, 115177b9900eSJiri Pirko struct sk_buff *skb, struct tcmsg *t) 115277b9900eSJiri Pirko { 115377b9900eSJiri Pirko struct cls_fl_head *head = rtnl_dereference(tp->root); 11548113c095SWANG Cong struct cls_fl_filter *f = fh; 115577b9900eSJiri Pirko struct nlattr *nest; 115677b9900eSJiri Pirko struct fl_flow_key *key, *mask; 115777b9900eSJiri Pirko 115877b9900eSJiri Pirko if (!f) 115977b9900eSJiri Pirko return skb->len; 116077b9900eSJiri Pirko 116177b9900eSJiri Pirko t->tcm_handle = f->handle; 116277b9900eSJiri Pirko 116377b9900eSJiri Pirko nest = nla_nest_start(skb, TCA_OPTIONS); 116477b9900eSJiri Pirko if (!nest) 116577b9900eSJiri Pirko goto nla_put_failure; 116677b9900eSJiri Pirko 116777b9900eSJiri Pirko if (f->res.classid && 116877b9900eSJiri Pirko nla_put_u32(skb, TCA_FLOWER_CLASSID, f->res.classid)) 116977b9900eSJiri Pirko goto nla_put_failure; 117077b9900eSJiri Pirko 117177b9900eSJiri Pirko key = &f->key; 117277b9900eSJiri Pirko mask = &head->mask.key; 117377b9900eSJiri Pirko 117477b9900eSJiri Pirko if (mask->indev_ifindex) { 117577b9900eSJiri Pirko struct net_device *dev; 117677b9900eSJiri Pirko 117777b9900eSJiri Pirko dev = __dev_get_by_index(net, key->indev_ifindex); 117877b9900eSJiri Pirko if (dev && nla_put_string(skb, TCA_FLOWER_INDEV, dev->name)) 117977b9900eSJiri Pirko goto nla_put_failure; 118077b9900eSJiri Pirko } 118177b9900eSJiri Pirko 118279685219SHadar Hen Zion if (!tc_skip_hw(f->flags)) 118310cbc684SAmir Vadai fl_hw_update_stats(tp, f); 118410cbc684SAmir Vadai 118577b9900eSJiri Pirko if (fl_dump_key_val(skb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST, 118677b9900eSJiri Pirko mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK, 118777b9900eSJiri Pirko sizeof(key->eth.dst)) || 118877b9900eSJiri Pirko fl_dump_key_val(skb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC, 118977b9900eSJiri Pirko mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK, 119077b9900eSJiri Pirko sizeof(key->eth.src)) || 119177b9900eSJiri Pirko fl_dump_key_val(skb, &key->basic.n_proto, TCA_FLOWER_KEY_ETH_TYPE, 119277b9900eSJiri Pirko &mask->basic.n_proto, TCA_FLOWER_UNSPEC, 119377b9900eSJiri Pirko sizeof(key->basic.n_proto))) 119477b9900eSJiri Pirko goto nla_put_failure; 11959399ae9aSHadar Hen Zion 1196a577d8f7SBenjamin LaHaise if (fl_dump_key_mpls(skb, &key->mpls, &mask->mpls)) 1197a577d8f7SBenjamin LaHaise goto nla_put_failure; 1198a577d8f7SBenjamin LaHaise 11999399ae9aSHadar Hen Zion if (fl_dump_key_vlan(skb, &key->vlan, &mask->vlan)) 12009399ae9aSHadar Hen Zion goto nla_put_failure; 12019399ae9aSHadar Hen Zion 120277b9900eSJiri Pirko if ((key->basic.n_proto == htons(ETH_P_IP) || 120377b9900eSJiri Pirko key->basic.n_proto == htons(ETH_P_IPV6)) && 12044d80cc0aSOr Gerlitz (fl_dump_key_val(skb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO, 120577b9900eSJiri Pirko &mask->basic.ip_proto, TCA_FLOWER_UNSPEC, 12064d80cc0aSOr Gerlitz sizeof(key->basic.ip_proto)) || 12074d80cc0aSOr Gerlitz fl_dump_key_ip(skb, &key->ip, &mask->ip))) 120877b9900eSJiri Pirko goto nla_put_failure; 120977b9900eSJiri Pirko 1210c3f83241STom Herbert if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS && 121177b9900eSJiri Pirko (fl_dump_key_val(skb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC, 121277b9900eSJiri Pirko &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK, 121377b9900eSJiri Pirko sizeof(key->ipv4.src)) || 121477b9900eSJiri Pirko fl_dump_key_val(skb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST, 121577b9900eSJiri Pirko &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK, 121677b9900eSJiri Pirko sizeof(key->ipv4.dst)))) 121777b9900eSJiri Pirko goto nla_put_failure; 1218c3f83241STom Herbert else if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS && 121977b9900eSJiri Pirko (fl_dump_key_val(skb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC, 122077b9900eSJiri Pirko &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK, 122177b9900eSJiri Pirko sizeof(key->ipv6.src)) || 122277b9900eSJiri Pirko fl_dump_key_val(skb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST, 122377b9900eSJiri Pirko &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK, 122477b9900eSJiri Pirko sizeof(key->ipv6.dst)))) 122577b9900eSJiri Pirko goto nla_put_failure; 122677b9900eSJiri Pirko 122777b9900eSJiri Pirko if (key->basic.ip_proto == IPPROTO_TCP && 122877b9900eSJiri Pirko (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC, 1229aa72d708SOr Gerlitz &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK, 123077b9900eSJiri Pirko sizeof(key->tp.src)) || 123177b9900eSJiri Pirko fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST, 1232aa72d708SOr Gerlitz &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK, 1233fdfc7dd6SJiri Pirko sizeof(key->tp.dst)) || 1234fdfc7dd6SJiri Pirko fl_dump_key_val(skb, &key->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS, 1235fdfc7dd6SJiri Pirko &mask->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS_MASK, 1236fdfc7dd6SJiri Pirko sizeof(key->tcp.flags)))) 123777b9900eSJiri Pirko goto nla_put_failure; 123877b9900eSJiri Pirko else if (key->basic.ip_proto == IPPROTO_UDP && 123977b9900eSJiri Pirko (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC, 1240aa72d708SOr Gerlitz &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK, 124177b9900eSJiri Pirko sizeof(key->tp.src)) || 124277b9900eSJiri Pirko fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST, 1243aa72d708SOr Gerlitz &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK, 124477b9900eSJiri Pirko sizeof(key->tp.dst)))) 124577b9900eSJiri Pirko goto nla_put_failure; 12465976c5f4SSimon Horman else if (key->basic.ip_proto == IPPROTO_SCTP && 12475976c5f4SSimon Horman (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC, 12485976c5f4SSimon Horman &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK, 12495976c5f4SSimon Horman sizeof(key->tp.src)) || 12505976c5f4SSimon Horman fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST, 12515976c5f4SSimon Horman &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK, 12525976c5f4SSimon Horman sizeof(key->tp.dst)))) 12535976c5f4SSimon Horman goto nla_put_failure; 12547b684884SSimon Horman else if (key->basic.n_proto == htons(ETH_P_IP) && 12557b684884SSimon Horman key->basic.ip_proto == IPPROTO_ICMP && 12567b684884SSimon Horman (fl_dump_key_val(skb, &key->icmp.type, 12577b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_TYPE, &mask->icmp.type, 12587b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_TYPE_MASK, 12597b684884SSimon Horman sizeof(key->icmp.type)) || 12607b684884SSimon Horman fl_dump_key_val(skb, &key->icmp.code, 12617b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_CODE, &mask->icmp.code, 12627b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_CODE_MASK, 12637b684884SSimon Horman sizeof(key->icmp.code)))) 12647b684884SSimon Horman goto nla_put_failure; 12657b684884SSimon Horman else if (key->basic.n_proto == htons(ETH_P_IPV6) && 12667b684884SSimon Horman key->basic.ip_proto == IPPROTO_ICMPV6 && 12677b684884SSimon Horman (fl_dump_key_val(skb, &key->icmp.type, 12687b684884SSimon Horman TCA_FLOWER_KEY_ICMPV6_TYPE, &mask->icmp.type, 12697b684884SSimon Horman TCA_FLOWER_KEY_ICMPV6_TYPE_MASK, 12707b684884SSimon Horman sizeof(key->icmp.type)) || 12717b684884SSimon Horman fl_dump_key_val(skb, &key->icmp.code, 12727b684884SSimon Horman TCA_FLOWER_KEY_ICMPV6_CODE, &mask->icmp.code, 12737b684884SSimon Horman TCA_FLOWER_KEY_ICMPV6_CODE_MASK, 12747b684884SSimon Horman sizeof(key->icmp.code)))) 12757b684884SSimon Horman goto nla_put_failure; 127699d31326SSimon Horman else if ((key->basic.n_proto == htons(ETH_P_ARP) || 127799d31326SSimon Horman key->basic.n_proto == htons(ETH_P_RARP)) && 127899d31326SSimon Horman (fl_dump_key_val(skb, &key->arp.sip, 127999d31326SSimon Horman TCA_FLOWER_KEY_ARP_SIP, &mask->arp.sip, 128099d31326SSimon Horman TCA_FLOWER_KEY_ARP_SIP_MASK, 128199d31326SSimon Horman sizeof(key->arp.sip)) || 128299d31326SSimon Horman fl_dump_key_val(skb, &key->arp.tip, 128399d31326SSimon Horman TCA_FLOWER_KEY_ARP_TIP, &mask->arp.tip, 128499d31326SSimon Horman TCA_FLOWER_KEY_ARP_TIP_MASK, 128599d31326SSimon Horman sizeof(key->arp.tip)) || 128699d31326SSimon Horman fl_dump_key_val(skb, &key->arp.op, 128799d31326SSimon Horman TCA_FLOWER_KEY_ARP_OP, &mask->arp.op, 128899d31326SSimon Horman TCA_FLOWER_KEY_ARP_OP_MASK, 128999d31326SSimon Horman sizeof(key->arp.op)) || 129099d31326SSimon Horman fl_dump_key_val(skb, key->arp.sha, TCA_FLOWER_KEY_ARP_SHA, 129199d31326SSimon Horman mask->arp.sha, TCA_FLOWER_KEY_ARP_SHA_MASK, 129299d31326SSimon Horman sizeof(key->arp.sha)) || 129399d31326SSimon Horman fl_dump_key_val(skb, key->arp.tha, TCA_FLOWER_KEY_ARP_THA, 129499d31326SSimon Horman mask->arp.tha, TCA_FLOWER_KEY_ARP_THA_MASK, 129599d31326SSimon Horman sizeof(key->arp.tha)))) 129699d31326SSimon Horman goto nla_put_failure; 129777b9900eSJiri Pirko 1298bc3103f1SAmir Vadai if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS && 1299bc3103f1SAmir Vadai (fl_dump_key_val(skb, &key->enc_ipv4.src, 1300bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_SRC, &mask->enc_ipv4.src, 1301bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK, 1302bc3103f1SAmir Vadai sizeof(key->enc_ipv4.src)) || 1303bc3103f1SAmir Vadai fl_dump_key_val(skb, &key->enc_ipv4.dst, 1304bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_DST, &mask->enc_ipv4.dst, 1305bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_DST_MASK, 1306bc3103f1SAmir Vadai sizeof(key->enc_ipv4.dst)))) 1307bc3103f1SAmir Vadai goto nla_put_failure; 1308bc3103f1SAmir Vadai else if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS && 1309bc3103f1SAmir Vadai (fl_dump_key_val(skb, &key->enc_ipv6.src, 1310bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_SRC, &mask->enc_ipv6.src, 1311bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK, 1312bc3103f1SAmir Vadai sizeof(key->enc_ipv6.src)) || 1313bc3103f1SAmir Vadai fl_dump_key_val(skb, &key->enc_ipv6.dst, 1314bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_DST, 1315bc3103f1SAmir Vadai &mask->enc_ipv6.dst, 1316bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_DST_MASK, 1317bc3103f1SAmir Vadai sizeof(key->enc_ipv6.dst)))) 1318bc3103f1SAmir Vadai goto nla_put_failure; 1319bc3103f1SAmir Vadai 1320bc3103f1SAmir Vadai if (fl_dump_key_val(skb, &key->enc_key_id, TCA_FLOWER_KEY_ENC_KEY_ID, 1321eb523f42SHadar Hen Zion &mask->enc_key_id, TCA_FLOWER_UNSPEC, 1322f4d997fdSHadar Hen Zion sizeof(key->enc_key_id)) || 1323f4d997fdSHadar Hen Zion fl_dump_key_val(skb, &key->enc_tp.src, 1324f4d997fdSHadar Hen Zion TCA_FLOWER_KEY_ENC_UDP_SRC_PORT, 1325f4d997fdSHadar Hen Zion &mask->enc_tp.src, 1326f4d997fdSHadar Hen Zion TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK, 1327f4d997fdSHadar Hen Zion sizeof(key->enc_tp.src)) || 1328f4d997fdSHadar Hen Zion fl_dump_key_val(skb, &key->enc_tp.dst, 1329f4d997fdSHadar Hen Zion TCA_FLOWER_KEY_ENC_UDP_DST_PORT, 1330f4d997fdSHadar Hen Zion &mask->enc_tp.dst, 1331f4d997fdSHadar Hen Zion TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK, 1332f4d997fdSHadar Hen Zion sizeof(key->enc_tp.dst))) 1333bc3103f1SAmir Vadai goto nla_put_failure; 1334bc3103f1SAmir Vadai 1335faa3ffceSOr Gerlitz if (fl_dump_key_flags(skb, key->control.flags, mask->control.flags)) 1336faa3ffceSOr Gerlitz goto nla_put_failure; 1337faa3ffceSOr Gerlitz 1338749e6720SOr Gerlitz if (f->flags && nla_put_u32(skb, TCA_FLOWER_FLAGS, f->flags)) 1339749e6720SOr Gerlitz goto nla_put_failure; 1340e69985c6SAmir Vadai 134177b9900eSJiri Pirko if (tcf_exts_dump(skb, &f->exts)) 134277b9900eSJiri Pirko goto nla_put_failure; 134377b9900eSJiri Pirko 134477b9900eSJiri Pirko nla_nest_end(skb, nest); 134577b9900eSJiri Pirko 134677b9900eSJiri Pirko if (tcf_exts_dump_stats(skb, &f->exts) < 0) 134777b9900eSJiri Pirko goto nla_put_failure; 134877b9900eSJiri Pirko 134977b9900eSJiri Pirko return skb->len; 135077b9900eSJiri Pirko 135177b9900eSJiri Pirko nla_put_failure: 135277b9900eSJiri Pirko nla_nest_cancel(skb, nest); 135377b9900eSJiri Pirko return -1; 135477b9900eSJiri Pirko } 135577b9900eSJiri Pirko 135607d79fc7SCong Wang static void fl_bind_class(void *fh, u32 classid, unsigned long cl) 135707d79fc7SCong Wang { 135807d79fc7SCong Wang struct cls_fl_filter *f = fh; 135907d79fc7SCong Wang 136007d79fc7SCong Wang if (f && f->res.classid == classid) 136107d79fc7SCong Wang f->res.class = cl; 136207d79fc7SCong Wang } 136307d79fc7SCong Wang 136477b9900eSJiri Pirko static struct tcf_proto_ops cls_fl_ops __read_mostly = { 136577b9900eSJiri Pirko .kind = "flower", 136677b9900eSJiri Pirko .classify = fl_classify, 136777b9900eSJiri Pirko .init = fl_init, 136877b9900eSJiri Pirko .destroy = fl_destroy, 136977b9900eSJiri Pirko .get = fl_get, 137077b9900eSJiri Pirko .change = fl_change, 137177b9900eSJiri Pirko .delete = fl_delete, 137277b9900eSJiri Pirko .walk = fl_walk, 137377b9900eSJiri Pirko .dump = fl_dump, 137407d79fc7SCong Wang .bind_class = fl_bind_class, 137577b9900eSJiri Pirko .owner = THIS_MODULE, 137677b9900eSJiri Pirko }; 137777b9900eSJiri Pirko 137877b9900eSJiri Pirko static int __init cls_fl_init(void) 137977b9900eSJiri Pirko { 138077b9900eSJiri Pirko return register_tcf_proto_ops(&cls_fl_ops); 138177b9900eSJiri Pirko } 138277b9900eSJiri Pirko 138377b9900eSJiri Pirko static void __exit cls_fl_exit(void) 138477b9900eSJiri Pirko { 138577b9900eSJiri Pirko unregister_tcf_proto_ops(&cls_fl_ops); 138677b9900eSJiri Pirko } 138777b9900eSJiri Pirko 138877b9900eSJiri Pirko module_init(cls_fl_init); 138977b9900eSJiri Pirko module_exit(cls_fl_exit); 139077b9900eSJiri Pirko 139177b9900eSJiri Pirko MODULE_AUTHOR("Jiri Pirko <jiri@resnulli.us>"); 139277b9900eSJiri Pirko MODULE_DESCRIPTION("Flower classifier"); 139377b9900eSJiri Pirko MODULE_LICENSE("GPL v2"); 1394