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> 2177b9900eSJiri Pirko 2277b9900eSJiri Pirko #include <net/sch_generic.h> 2377b9900eSJiri Pirko #include <net/pkt_cls.h> 2477b9900eSJiri Pirko #include <net/ip.h> 2577b9900eSJiri Pirko #include <net/flow_dissector.h> 2677b9900eSJiri Pirko 27bc3103f1SAmir Vadai #include <net/dst.h> 28bc3103f1SAmir Vadai #include <net/dst_metadata.h> 29bc3103f1SAmir Vadai 3077b9900eSJiri Pirko struct fl_flow_key { 3177b9900eSJiri Pirko int indev_ifindex; 3242aecaa9STom Herbert struct flow_dissector_key_control control; 33bc3103f1SAmir Vadai struct flow_dissector_key_control enc_control; 3477b9900eSJiri Pirko struct flow_dissector_key_basic basic; 3577b9900eSJiri Pirko struct flow_dissector_key_eth_addrs eth; 369399ae9aSHadar Hen Zion struct flow_dissector_key_vlan vlan; 3777b9900eSJiri Pirko union { 38c3f83241STom Herbert struct flow_dissector_key_ipv4_addrs ipv4; 3977b9900eSJiri Pirko struct flow_dissector_key_ipv6_addrs ipv6; 4077b9900eSJiri Pirko }; 4177b9900eSJiri Pirko struct flow_dissector_key_ports tp; 427b684884SSimon Horman struct flow_dissector_key_icmp icmp; 43bc3103f1SAmir Vadai struct flow_dissector_key_keyid enc_key_id; 44bc3103f1SAmir Vadai union { 45bc3103f1SAmir Vadai struct flow_dissector_key_ipv4_addrs enc_ipv4; 46bc3103f1SAmir Vadai struct flow_dissector_key_ipv6_addrs enc_ipv6; 47bc3103f1SAmir Vadai }; 48f4d997fdSHadar Hen Zion struct flow_dissector_key_ports enc_tp; 4977b9900eSJiri Pirko } __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */ 5077b9900eSJiri Pirko 5177b9900eSJiri Pirko struct fl_flow_mask_range { 5277b9900eSJiri Pirko unsigned short int start; 5377b9900eSJiri Pirko unsigned short int end; 5477b9900eSJiri Pirko }; 5577b9900eSJiri Pirko 5677b9900eSJiri Pirko struct fl_flow_mask { 5777b9900eSJiri Pirko struct fl_flow_key key; 5877b9900eSJiri Pirko struct fl_flow_mask_range range; 5977b9900eSJiri Pirko struct rcu_head rcu; 6077b9900eSJiri Pirko }; 6177b9900eSJiri Pirko 6277b9900eSJiri Pirko struct cls_fl_head { 6377b9900eSJiri Pirko struct rhashtable ht; 6477b9900eSJiri Pirko struct fl_flow_mask mask; 6577b9900eSJiri Pirko struct flow_dissector dissector; 6677b9900eSJiri Pirko u32 hgen; 6777b9900eSJiri Pirko bool mask_assigned; 6877b9900eSJiri Pirko struct list_head filters; 6977b9900eSJiri Pirko struct rhashtable_params ht_params; 70d9363774SDaniel Borkmann union { 71d9363774SDaniel Borkmann struct work_struct work; 7277b9900eSJiri Pirko struct rcu_head rcu; 7377b9900eSJiri Pirko }; 74d9363774SDaniel Borkmann }; 7577b9900eSJiri Pirko 7677b9900eSJiri Pirko struct cls_fl_filter { 7777b9900eSJiri Pirko struct rhash_head ht_node; 7877b9900eSJiri Pirko struct fl_flow_key mkey; 7977b9900eSJiri Pirko struct tcf_exts exts; 8077b9900eSJiri Pirko struct tcf_result res; 8177b9900eSJiri Pirko struct fl_flow_key key; 8277b9900eSJiri Pirko struct list_head list; 8377b9900eSJiri Pirko u32 handle; 84e69985c6SAmir Vadai u32 flags; 8577b9900eSJiri Pirko struct rcu_head rcu; 867091d8c7SHadar Hen Zion struct tc_to_netdev tc; 877091d8c7SHadar Hen Zion struct net_device *hw_dev; 8877b9900eSJiri Pirko }; 8977b9900eSJiri Pirko 9077b9900eSJiri Pirko static unsigned short int fl_mask_range(const struct fl_flow_mask *mask) 9177b9900eSJiri Pirko { 9277b9900eSJiri Pirko return mask->range.end - mask->range.start; 9377b9900eSJiri Pirko } 9477b9900eSJiri Pirko 9577b9900eSJiri Pirko static void fl_mask_update_range(struct fl_flow_mask *mask) 9677b9900eSJiri Pirko { 9777b9900eSJiri Pirko const u8 *bytes = (const u8 *) &mask->key; 9877b9900eSJiri Pirko size_t size = sizeof(mask->key); 9977b9900eSJiri Pirko size_t i, first = 0, last = size - 1; 10077b9900eSJiri Pirko 10177b9900eSJiri Pirko for (i = 0; i < sizeof(mask->key); i++) { 10277b9900eSJiri Pirko if (bytes[i]) { 10377b9900eSJiri Pirko if (!first && i) 10477b9900eSJiri Pirko first = i; 10577b9900eSJiri Pirko last = i; 10677b9900eSJiri Pirko } 10777b9900eSJiri Pirko } 10877b9900eSJiri Pirko mask->range.start = rounddown(first, sizeof(long)); 10977b9900eSJiri Pirko mask->range.end = roundup(last + 1, sizeof(long)); 11077b9900eSJiri Pirko } 11177b9900eSJiri Pirko 11277b9900eSJiri Pirko static void *fl_key_get_start(struct fl_flow_key *key, 11377b9900eSJiri Pirko const struct fl_flow_mask *mask) 11477b9900eSJiri Pirko { 11577b9900eSJiri Pirko return (u8 *) key + mask->range.start; 11677b9900eSJiri Pirko } 11777b9900eSJiri Pirko 11877b9900eSJiri Pirko static void fl_set_masked_key(struct fl_flow_key *mkey, struct fl_flow_key *key, 11977b9900eSJiri Pirko struct fl_flow_mask *mask) 12077b9900eSJiri Pirko { 12177b9900eSJiri Pirko const long *lkey = fl_key_get_start(key, mask); 12277b9900eSJiri Pirko const long *lmask = fl_key_get_start(&mask->key, mask); 12377b9900eSJiri Pirko long *lmkey = fl_key_get_start(mkey, mask); 12477b9900eSJiri Pirko int i; 12577b9900eSJiri Pirko 12677b9900eSJiri Pirko for (i = 0; i < fl_mask_range(mask); i += sizeof(long)) 12777b9900eSJiri Pirko *lmkey++ = *lkey++ & *lmask++; 12877b9900eSJiri Pirko } 12977b9900eSJiri Pirko 13077b9900eSJiri Pirko static void fl_clear_masked_range(struct fl_flow_key *key, 13177b9900eSJiri Pirko struct fl_flow_mask *mask) 13277b9900eSJiri Pirko { 13377b9900eSJiri Pirko memset(fl_key_get_start(key, mask), 0, fl_mask_range(mask)); 13477b9900eSJiri Pirko } 13577b9900eSJiri Pirko 13677b9900eSJiri Pirko static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp, 13777b9900eSJiri Pirko struct tcf_result *res) 13877b9900eSJiri Pirko { 13977b9900eSJiri Pirko struct cls_fl_head *head = rcu_dereference_bh(tp->root); 14077b9900eSJiri Pirko struct cls_fl_filter *f; 14177b9900eSJiri Pirko struct fl_flow_key skb_key; 14277b9900eSJiri Pirko struct fl_flow_key skb_mkey; 143bc3103f1SAmir Vadai struct ip_tunnel_info *info; 14477b9900eSJiri Pirko 145e69985c6SAmir Vadai if (!atomic_read(&head->ht.nelems)) 146e69985c6SAmir Vadai return -1; 147e69985c6SAmir Vadai 14877b9900eSJiri Pirko fl_clear_masked_range(&skb_key, &head->mask); 149bc3103f1SAmir Vadai 150bc3103f1SAmir Vadai info = skb_tunnel_info(skb); 151bc3103f1SAmir Vadai if (info) { 152bc3103f1SAmir Vadai struct ip_tunnel_key *key = &info->key; 153bc3103f1SAmir Vadai 154bc3103f1SAmir Vadai switch (ip_tunnel_info_af(info)) { 155bc3103f1SAmir Vadai case AF_INET: 156bc3103f1SAmir Vadai skb_key.enc_ipv4.src = key->u.ipv4.src; 157bc3103f1SAmir Vadai skb_key.enc_ipv4.dst = key->u.ipv4.dst; 158bc3103f1SAmir Vadai break; 159bc3103f1SAmir Vadai case AF_INET6: 160bc3103f1SAmir Vadai skb_key.enc_ipv6.src = key->u.ipv6.src; 161bc3103f1SAmir Vadai skb_key.enc_ipv6.dst = key->u.ipv6.dst; 162bc3103f1SAmir Vadai break; 163bc3103f1SAmir Vadai } 164bc3103f1SAmir Vadai 165bc3103f1SAmir Vadai skb_key.enc_key_id.keyid = tunnel_id_to_key32(key->tun_id); 166f4d997fdSHadar Hen Zion skb_key.enc_tp.src = key->tp_src; 167f4d997fdSHadar Hen Zion skb_key.enc_tp.dst = key->tp_dst; 168bc3103f1SAmir Vadai } 169bc3103f1SAmir Vadai 17077b9900eSJiri Pirko skb_key.indev_ifindex = skb->skb_iif; 17177b9900eSJiri Pirko /* skb_flow_dissect() does not set n_proto in case an unknown protocol, 17277b9900eSJiri Pirko * so do it rather here. 17377b9900eSJiri Pirko */ 17477b9900eSJiri Pirko skb_key.basic.n_proto = skb->protocol; 175cd79a238STom Herbert skb_flow_dissect(skb, &head->dissector, &skb_key, 0); 17677b9900eSJiri Pirko 17777b9900eSJiri Pirko fl_set_masked_key(&skb_mkey, &skb_key, &head->mask); 17877b9900eSJiri Pirko 17977b9900eSJiri Pirko f = rhashtable_lookup_fast(&head->ht, 18077b9900eSJiri Pirko fl_key_get_start(&skb_mkey, &head->mask), 18177b9900eSJiri Pirko head->ht_params); 182e8eb36cdSAmir Vadai if (f && !tc_skip_sw(f->flags)) { 18377b9900eSJiri Pirko *res = f->res; 18477b9900eSJiri Pirko return tcf_exts_exec(skb, &f->exts, res); 18577b9900eSJiri Pirko } 18677b9900eSJiri Pirko return -1; 18777b9900eSJiri Pirko } 18877b9900eSJiri Pirko 18977b9900eSJiri Pirko static int fl_init(struct tcf_proto *tp) 19077b9900eSJiri Pirko { 19177b9900eSJiri Pirko struct cls_fl_head *head; 19277b9900eSJiri Pirko 19377b9900eSJiri Pirko head = kzalloc(sizeof(*head), GFP_KERNEL); 19477b9900eSJiri Pirko if (!head) 19577b9900eSJiri Pirko return -ENOBUFS; 19677b9900eSJiri Pirko 19777b9900eSJiri Pirko INIT_LIST_HEAD_RCU(&head->filters); 19877b9900eSJiri Pirko rcu_assign_pointer(tp->root, head); 19977b9900eSJiri Pirko 20077b9900eSJiri Pirko return 0; 20177b9900eSJiri Pirko } 20277b9900eSJiri Pirko 20377b9900eSJiri Pirko static void fl_destroy_filter(struct rcu_head *head) 20477b9900eSJiri Pirko { 20577b9900eSJiri Pirko struct cls_fl_filter *f = container_of(head, struct cls_fl_filter, rcu); 20677b9900eSJiri Pirko 20777b9900eSJiri Pirko tcf_exts_destroy(&f->exts); 20877b9900eSJiri Pirko kfree(f); 20977b9900eSJiri Pirko } 21077b9900eSJiri Pirko 2113036dab6SHadar Hen Zion static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f) 2125b33f488SAmir Vadai { 2135b33f488SAmir Vadai struct tc_cls_flower_offload offload = {0}; 2147091d8c7SHadar Hen Zion struct net_device *dev = f->hw_dev; 2157091d8c7SHadar Hen Zion struct tc_to_netdev *tc = &f->tc; 2165b33f488SAmir Vadai 21779685219SHadar Hen Zion if (!tc_can_offload(dev, tp)) 2185b33f488SAmir Vadai return; 2195b33f488SAmir Vadai 2205b33f488SAmir Vadai offload.command = TC_CLSFLOWER_DESTROY; 2213036dab6SHadar Hen Zion offload.cookie = (unsigned long)f; 2225b33f488SAmir Vadai 2237091d8c7SHadar Hen Zion tc->type = TC_SETUP_CLSFLOWER; 2247091d8c7SHadar Hen Zion tc->cls_flower = &offload; 2255b33f488SAmir Vadai 2267091d8c7SHadar Hen Zion dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol, tc); 2275b33f488SAmir Vadai } 2285b33f488SAmir Vadai 229e8eb36cdSAmir Vadai static int fl_hw_replace_filter(struct tcf_proto *tp, 2305b33f488SAmir Vadai struct flow_dissector *dissector, 2315b33f488SAmir Vadai struct fl_flow_key *mask, 2323036dab6SHadar Hen Zion struct cls_fl_filter *f) 2335b33f488SAmir Vadai { 2345b33f488SAmir Vadai struct net_device *dev = tp->q->dev_queue->dev; 2355b33f488SAmir Vadai struct tc_cls_flower_offload offload = {0}; 2367091d8c7SHadar Hen Zion struct tc_to_netdev *tc = &f->tc; 237e8eb36cdSAmir Vadai int err; 2385b33f488SAmir Vadai 2397091d8c7SHadar Hen Zion if (!tc_can_offload(dev, tp)) { 240a6e16931SHadar Hen Zion if (tcf_exts_get_dev(dev, &f->exts, &f->hw_dev) || 241a6e16931SHadar Hen Zion (f->hw_dev && !tc_can_offload(f->hw_dev, tp))) { 242a6e16931SHadar Hen Zion f->hw_dev = dev; 2433036dab6SHadar Hen Zion return tc_skip_sw(f->flags) ? -EINVAL : 0; 244a6e16931SHadar Hen Zion } 2457091d8c7SHadar Hen Zion dev = f->hw_dev; 2467091d8c7SHadar Hen Zion tc->egress_dev = true; 2477091d8c7SHadar Hen Zion } else { 2487091d8c7SHadar Hen Zion f->hw_dev = dev; 2497091d8c7SHadar Hen Zion } 2505b33f488SAmir Vadai 2515b33f488SAmir Vadai offload.command = TC_CLSFLOWER_REPLACE; 2523036dab6SHadar Hen Zion offload.cookie = (unsigned long)f; 2535b33f488SAmir Vadai offload.dissector = dissector; 2545b33f488SAmir Vadai offload.mask = mask; 255*f93bd17bSPaul Blakey offload.key = &f->mkey; 2563036dab6SHadar Hen Zion offload.exts = &f->exts; 2575b33f488SAmir Vadai 2587091d8c7SHadar Hen Zion tc->type = TC_SETUP_CLSFLOWER; 2597091d8c7SHadar Hen Zion tc->cls_flower = &offload; 2605b33f488SAmir Vadai 2615a7a5555SJamal Hadi Salim err = dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol, 2627091d8c7SHadar Hen Zion tc); 263e8eb36cdSAmir Vadai 2643036dab6SHadar Hen Zion if (tc_skip_sw(f->flags)) 265e8eb36cdSAmir Vadai return err; 266e8eb36cdSAmir Vadai return 0; 2675b33f488SAmir Vadai } 2685b33f488SAmir Vadai 26910cbc684SAmir Vadai static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f) 27010cbc684SAmir Vadai { 27110cbc684SAmir Vadai struct tc_cls_flower_offload offload = {0}; 2727091d8c7SHadar Hen Zion struct net_device *dev = f->hw_dev; 2737091d8c7SHadar Hen Zion struct tc_to_netdev *tc = &f->tc; 27410cbc684SAmir Vadai 27579685219SHadar Hen Zion if (!tc_can_offload(dev, tp)) 27610cbc684SAmir Vadai return; 27710cbc684SAmir Vadai 27810cbc684SAmir Vadai offload.command = TC_CLSFLOWER_STATS; 27910cbc684SAmir Vadai offload.cookie = (unsigned long)f; 28010cbc684SAmir Vadai offload.exts = &f->exts; 28110cbc684SAmir Vadai 2827091d8c7SHadar Hen Zion tc->type = TC_SETUP_CLSFLOWER; 2837091d8c7SHadar Hen Zion tc->cls_flower = &offload; 28410cbc684SAmir Vadai 2857091d8c7SHadar Hen Zion dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol, tc); 28610cbc684SAmir Vadai } 28710cbc684SAmir Vadai 28813fa876eSRoi Dayan static void __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f) 28913fa876eSRoi Dayan { 29013fa876eSRoi Dayan list_del_rcu(&f->list); 29179685219SHadar Hen Zion if (!tc_skip_hw(f->flags)) 2923036dab6SHadar Hen Zion fl_hw_destroy_filter(tp, f); 29313fa876eSRoi Dayan tcf_unbind_filter(tp, &f->res); 29413fa876eSRoi Dayan call_rcu(&f->rcu, fl_destroy_filter); 29513fa876eSRoi Dayan } 29613fa876eSRoi Dayan 297d9363774SDaniel Borkmann static void fl_destroy_sleepable(struct work_struct *work) 298d9363774SDaniel Borkmann { 299d9363774SDaniel Borkmann struct cls_fl_head *head = container_of(work, struct cls_fl_head, 300d9363774SDaniel Borkmann work); 301d9363774SDaniel Borkmann if (head->mask_assigned) 302d9363774SDaniel Borkmann rhashtable_destroy(&head->ht); 303d9363774SDaniel Borkmann kfree(head); 304d9363774SDaniel Borkmann module_put(THIS_MODULE); 305d9363774SDaniel Borkmann } 306d9363774SDaniel Borkmann 307d9363774SDaniel Borkmann static void fl_destroy_rcu(struct rcu_head *rcu) 308d9363774SDaniel Borkmann { 309d9363774SDaniel Borkmann struct cls_fl_head *head = container_of(rcu, struct cls_fl_head, rcu); 310d9363774SDaniel Borkmann 311d9363774SDaniel Borkmann INIT_WORK(&head->work, fl_destroy_sleepable); 312d9363774SDaniel Borkmann schedule_work(&head->work); 313d9363774SDaniel Borkmann } 314d9363774SDaniel Borkmann 31577b9900eSJiri Pirko static bool fl_destroy(struct tcf_proto *tp, bool force) 31677b9900eSJiri Pirko { 31777b9900eSJiri Pirko struct cls_fl_head *head = rtnl_dereference(tp->root); 31877b9900eSJiri Pirko struct cls_fl_filter *f, *next; 31977b9900eSJiri Pirko 32077b9900eSJiri Pirko if (!force && !list_empty(&head->filters)) 32177b9900eSJiri Pirko return false; 32277b9900eSJiri Pirko 32313fa876eSRoi Dayan list_for_each_entry_safe(f, next, &head->filters, list) 32413fa876eSRoi Dayan __fl_delete(tp, f); 325d9363774SDaniel Borkmann 326d9363774SDaniel Borkmann __module_get(THIS_MODULE); 327d9363774SDaniel Borkmann call_rcu(&head->rcu, fl_destroy_rcu); 3282745529aSDavid S. Miller 32977b9900eSJiri Pirko return true; 33077b9900eSJiri Pirko } 33177b9900eSJiri Pirko 33277b9900eSJiri Pirko static unsigned long fl_get(struct tcf_proto *tp, u32 handle) 33377b9900eSJiri Pirko { 33477b9900eSJiri Pirko struct cls_fl_head *head = rtnl_dereference(tp->root); 33577b9900eSJiri Pirko struct cls_fl_filter *f; 33677b9900eSJiri Pirko 33777b9900eSJiri Pirko list_for_each_entry(f, &head->filters, list) 33877b9900eSJiri Pirko if (f->handle == handle) 33977b9900eSJiri Pirko return (unsigned long) f; 34077b9900eSJiri Pirko return 0; 34177b9900eSJiri Pirko } 34277b9900eSJiri Pirko 34377b9900eSJiri Pirko static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = { 34477b9900eSJiri Pirko [TCA_FLOWER_UNSPEC] = { .type = NLA_UNSPEC }, 34577b9900eSJiri Pirko [TCA_FLOWER_CLASSID] = { .type = NLA_U32 }, 34677b9900eSJiri Pirko [TCA_FLOWER_INDEV] = { .type = NLA_STRING, 34777b9900eSJiri Pirko .len = IFNAMSIZ }, 34877b9900eSJiri Pirko [TCA_FLOWER_KEY_ETH_DST] = { .len = ETH_ALEN }, 34977b9900eSJiri Pirko [TCA_FLOWER_KEY_ETH_DST_MASK] = { .len = ETH_ALEN }, 35077b9900eSJiri Pirko [TCA_FLOWER_KEY_ETH_SRC] = { .len = ETH_ALEN }, 35177b9900eSJiri Pirko [TCA_FLOWER_KEY_ETH_SRC_MASK] = { .len = ETH_ALEN }, 35277b9900eSJiri Pirko [TCA_FLOWER_KEY_ETH_TYPE] = { .type = NLA_U16 }, 35377b9900eSJiri Pirko [TCA_FLOWER_KEY_IP_PROTO] = { .type = NLA_U8 }, 35477b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV4_SRC] = { .type = NLA_U32 }, 35577b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV4_SRC_MASK] = { .type = NLA_U32 }, 35677b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV4_DST] = { .type = NLA_U32 }, 35777b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV4_DST_MASK] = { .type = NLA_U32 }, 35877b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV6_SRC] = { .len = sizeof(struct in6_addr) }, 35977b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) }, 36077b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV6_DST] = { .len = sizeof(struct in6_addr) }, 36177b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) }, 36277b9900eSJiri Pirko [TCA_FLOWER_KEY_TCP_SRC] = { .type = NLA_U16 }, 36377b9900eSJiri Pirko [TCA_FLOWER_KEY_TCP_DST] = { .type = NLA_U16 }, 364b175c3a4SJamal Hadi Salim [TCA_FLOWER_KEY_UDP_SRC] = { .type = NLA_U16 }, 365b175c3a4SJamal Hadi Salim [TCA_FLOWER_KEY_UDP_DST] = { .type = NLA_U16 }, 3669399ae9aSHadar Hen Zion [TCA_FLOWER_KEY_VLAN_ID] = { .type = NLA_U16 }, 3679399ae9aSHadar Hen Zion [TCA_FLOWER_KEY_VLAN_PRIO] = { .type = NLA_U8 }, 3689399ae9aSHadar Hen Zion [TCA_FLOWER_KEY_VLAN_ETH_TYPE] = { .type = NLA_U16 }, 369bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_KEY_ID] = { .type = NLA_U32 }, 370bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV4_SRC] = { .type = NLA_U32 }, 371bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] = { .type = NLA_U32 }, 372bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV4_DST] = { .type = NLA_U32 }, 373bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] = { .type = NLA_U32 }, 374bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV6_SRC] = { .len = sizeof(struct in6_addr) }, 375bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) }, 376bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV6_DST] = { .len = sizeof(struct in6_addr) }, 377bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) }, 378aa72d708SOr Gerlitz [TCA_FLOWER_KEY_TCP_SRC_MASK] = { .type = NLA_U16 }, 379aa72d708SOr Gerlitz [TCA_FLOWER_KEY_TCP_DST_MASK] = { .type = NLA_U16 }, 380aa72d708SOr Gerlitz [TCA_FLOWER_KEY_UDP_SRC_MASK] = { .type = NLA_U16 }, 381aa72d708SOr Gerlitz [TCA_FLOWER_KEY_UDP_DST_MASK] = { .type = NLA_U16 }, 3825976c5f4SSimon Horman [TCA_FLOWER_KEY_SCTP_SRC_MASK] = { .type = NLA_U16 }, 3835976c5f4SSimon Horman [TCA_FLOWER_KEY_SCTP_DST_MASK] = { .type = NLA_U16 }, 3845976c5f4SSimon Horman [TCA_FLOWER_KEY_SCTP_SRC] = { .type = NLA_U16 }, 3855976c5f4SSimon Horman [TCA_FLOWER_KEY_SCTP_DST] = { .type = NLA_U16 }, 386f4d997fdSHadar Hen Zion [TCA_FLOWER_KEY_ENC_UDP_SRC_PORT] = { .type = NLA_U16 }, 387f4d997fdSHadar Hen Zion [TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK] = { .type = NLA_U16 }, 388f4d997fdSHadar Hen Zion [TCA_FLOWER_KEY_ENC_UDP_DST_PORT] = { .type = NLA_U16 }, 389f4d997fdSHadar Hen Zion [TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK] = { .type = NLA_U16 }, 390faa3ffceSOr Gerlitz [TCA_FLOWER_KEY_FLAGS] = { .type = NLA_U32 }, 391faa3ffceSOr Gerlitz [TCA_FLOWER_KEY_FLAGS_MASK] = { .type = NLA_U32 }, 3927b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV4_TYPE] = { .type = NLA_U8 }, 3937b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV4_TYPE_MASK] = { .type = NLA_U8 }, 3947b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV4_CODE] = { .type = NLA_U8 }, 3957b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV4_CODE_MASK] = { .type = NLA_U8 }, 3967b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV6_TYPE] = { .type = NLA_U8 }, 3977b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV6_TYPE_MASK] = { .type = NLA_U8 }, 3987b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV6_CODE] = { .type = NLA_U8 }, 3997b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV6_CODE_MASK] = { .type = NLA_U8 }, 40077b9900eSJiri Pirko }; 40177b9900eSJiri Pirko 40277b9900eSJiri Pirko static void fl_set_key_val(struct nlattr **tb, 40377b9900eSJiri Pirko void *val, int val_type, 40477b9900eSJiri Pirko void *mask, int mask_type, int len) 40577b9900eSJiri Pirko { 40677b9900eSJiri Pirko if (!tb[val_type]) 40777b9900eSJiri Pirko return; 40877b9900eSJiri Pirko memcpy(val, nla_data(tb[val_type]), len); 40977b9900eSJiri Pirko if (mask_type == TCA_FLOWER_UNSPEC || !tb[mask_type]) 41077b9900eSJiri Pirko memset(mask, 0xff, len); 41177b9900eSJiri Pirko else 41277b9900eSJiri Pirko memcpy(mask, nla_data(tb[mask_type]), len); 41377b9900eSJiri Pirko } 41477b9900eSJiri Pirko 4159399ae9aSHadar Hen Zion static void fl_set_key_vlan(struct nlattr **tb, 4169399ae9aSHadar Hen Zion struct flow_dissector_key_vlan *key_val, 4179399ae9aSHadar Hen Zion struct flow_dissector_key_vlan *key_mask) 4189399ae9aSHadar Hen Zion { 4199399ae9aSHadar Hen Zion #define VLAN_PRIORITY_MASK 0x7 4209399ae9aSHadar Hen Zion 4219399ae9aSHadar Hen Zion if (tb[TCA_FLOWER_KEY_VLAN_ID]) { 4229399ae9aSHadar Hen Zion key_val->vlan_id = 4239399ae9aSHadar Hen Zion nla_get_u16(tb[TCA_FLOWER_KEY_VLAN_ID]) & VLAN_VID_MASK; 4249399ae9aSHadar Hen Zion key_mask->vlan_id = VLAN_VID_MASK; 4259399ae9aSHadar Hen Zion } 4269399ae9aSHadar Hen Zion if (tb[TCA_FLOWER_KEY_VLAN_PRIO]) { 4279399ae9aSHadar Hen Zion key_val->vlan_priority = 4289399ae9aSHadar Hen Zion nla_get_u8(tb[TCA_FLOWER_KEY_VLAN_PRIO]) & 4299399ae9aSHadar Hen Zion VLAN_PRIORITY_MASK; 4309399ae9aSHadar Hen Zion key_mask->vlan_priority = VLAN_PRIORITY_MASK; 4319399ae9aSHadar Hen Zion } 4329399ae9aSHadar Hen Zion } 4339399ae9aSHadar Hen Zion 434faa3ffceSOr Gerlitz static void fl_set_key_flag(u32 flower_key, u32 flower_mask, 435faa3ffceSOr Gerlitz u32 *dissector_key, u32 *dissector_mask, 436faa3ffceSOr Gerlitz u32 flower_flag_bit, u32 dissector_flag_bit) 437faa3ffceSOr Gerlitz { 438faa3ffceSOr Gerlitz if (flower_mask & flower_flag_bit) { 439faa3ffceSOr Gerlitz *dissector_mask |= dissector_flag_bit; 440faa3ffceSOr Gerlitz if (flower_key & flower_flag_bit) 441faa3ffceSOr Gerlitz *dissector_key |= dissector_flag_bit; 442faa3ffceSOr Gerlitz } 443faa3ffceSOr Gerlitz } 444faa3ffceSOr Gerlitz 445faa3ffceSOr Gerlitz static void fl_set_key_flags(struct nlattr **tb, 446faa3ffceSOr Gerlitz u32 *flags_key, u32 *flags_mask) 447faa3ffceSOr Gerlitz { 448faa3ffceSOr Gerlitz u32 key, mask; 449faa3ffceSOr Gerlitz 450faa3ffceSOr Gerlitz if (!tb[TCA_FLOWER_KEY_FLAGS]) 451faa3ffceSOr Gerlitz return; 452faa3ffceSOr Gerlitz 453faa3ffceSOr Gerlitz key = be32_to_cpu(nla_get_u32(tb[TCA_FLOWER_KEY_FLAGS])); 454faa3ffceSOr Gerlitz 455faa3ffceSOr Gerlitz if (!tb[TCA_FLOWER_KEY_FLAGS_MASK]) 456faa3ffceSOr Gerlitz mask = ~0; 457faa3ffceSOr Gerlitz else 458faa3ffceSOr Gerlitz mask = be32_to_cpu(nla_get_u32(tb[TCA_FLOWER_KEY_FLAGS_MASK])); 459faa3ffceSOr Gerlitz 460faa3ffceSOr Gerlitz *flags_key = 0; 461faa3ffceSOr Gerlitz *flags_mask = 0; 462faa3ffceSOr Gerlitz 463faa3ffceSOr Gerlitz fl_set_key_flag(key, mask, flags_key, flags_mask, 464faa3ffceSOr Gerlitz TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT); 465faa3ffceSOr Gerlitz } 466faa3ffceSOr Gerlitz 46777b9900eSJiri Pirko static int fl_set_key(struct net *net, struct nlattr **tb, 46877b9900eSJiri Pirko struct fl_flow_key *key, struct fl_flow_key *mask) 46977b9900eSJiri Pirko { 4709399ae9aSHadar Hen Zion __be16 ethertype; 471dd3aa3b5SBrian Haley #ifdef CONFIG_NET_CLS_IND 47277b9900eSJiri Pirko if (tb[TCA_FLOWER_INDEV]) { 473dd3aa3b5SBrian Haley int err = tcf_change_indev(net, tb[TCA_FLOWER_INDEV]); 47477b9900eSJiri Pirko if (err < 0) 47577b9900eSJiri Pirko return err; 47677b9900eSJiri Pirko key->indev_ifindex = err; 47777b9900eSJiri Pirko mask->indev_ifindex = 0xffffffff; 47877b9900eSJiri Pirko } 479dd3aa3b5SBrian Haley #endif 48077b9900eSJiri Pirko 48177b9900eSJiri Pirko fl_set_key_val(tb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST, 48277b9900eSJiri Pirko mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK, 48377b9900eSJiri Pirko sizeof(key->eth.dst)); 48477b9900eSJiri Pirko fl_set_key_val(tb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC, 48577b9900eSJiri Pirko mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK, 48677b9900eSJiri Pirko sizeof(key->eth.src)); 48766530bdfSJamal Hadi Salim 4880b498a52SArnd Bergmann if (tb[TCA_FLOWER_KEY_ETH_TYPE]) { 4899399ae9aSHadar Hen Zion ethertype = nla_get_be16(tb[TCA_FLOWER_KEY_ETH_TYPE]); 4909399ae9aSHadar Hen Zion 4919399ae9aSHadar Hen Zion if (ethertype == htons(ETH_P_8021Q)) { 4929399ae9aSHadar Hen Zion fl_set_key_vlan(tb, &key->vlan, &mask->vlan); 4939399ae9aSHadar Hen Zion fl_set_key_val(tb, &key->basic.n_proto, 4949399ae9aSHadar Hen Zion TCA_FLOWER_KEY_VLAN_ETH_TYPE, 49577b9900eSJiri Pirko &mask->basic.n_proto, TCA_FLOWER_UNSPEC, 49677b9900eSJiri Pirko sizeof(key->basic.n_proto)); 4979399ae9aSHadar Hen Zion } else { 4989399ae9aSHadar Hen Zion key->basic.n_proto = ethertype; 4999399ae9aSHadar Hen Zion mask->basic.n_proto = cpu_to_be16(~0); 5009399ae9aSHadar Hen Zion } 5010b498a52SArnd Bergmann } 50266530bdfSJamal Hadi Salim 50377b9900eSJiri Pirko if (key->basic.n_proto == htons(ETH_P_IP) || 50477b9900eSJiri Pirko key->basic.n_proto == htons(ETH_P_IPV6)) { 50577b9900eSJiri Pirko fl_set_key_val(tb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO, 50677b9900eSJiri Pirko &mask->basic.ip_proto, TCA_FLOWER_UNSPEC, 50777b9900eSJiri Pirko sizeof(key->basic.ip_proto)); 50877b9900eSJiri Pirko } 50966530bdfSJamal Hadi Salim 51066530bdfSJamal Hadi Salim if (tb[TCA_FLOWER_KEY_IPV4_SRC] || tb[TCA_FLOWER_KEY_IPV4_DST]) { 51166530bdfSJamal Hadi Salim key->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; 512970bfcd0SPaul Blakey mask->control.addr_type = ~0; 51377b9900eSJiri Pirko fl_set_key_val(tb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC, 51477b9900eSJiri Pirko &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK, 51577b9900eSJiri Pirko sizeof(key->ipv4.src)); 51677b9900eSJiri Pirko fl_set_key_val(tb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST, 51777b9900eSJiri Pirko &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK, 51877b9900eSJiri Pirko sizeof(key->ipv4.dst)); 51966530bdfSJamal Hadi Salim } else if (tb[TCA_FLOWER_KEY_IPV6_SRC] || tb[TCA_FLOWER_KEY_IPV6_DST]) { 52066530bdfSJamal Hadi Salim key->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; 521970bfcd0SPaul Blakey mask->control.addr_type = ~0; 52277b9900eSJiri Pirko fl_set_key_val(tb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC, 52377b9900eSJiri Pirko &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK, 52477b9900eSJiri Pirko sizeof(key->ipv6.src)); 52577b9900eSJiri Pirko fl_set_key_val(tb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST, 52677b9900eSJiri Pirko &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK, 52777b9900eSJiri Pirko sizeof(key->ipv6.dst)); 52877b9900eSJiri Pirko } 52966530bdfSJamal Hadi Salim 53077b9900eSJiri Pirko if (key->basic.ip_proto == IPPROTO_TCP) { 53177b9900eSJiri Pirko fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC, 532aa72d708SOr Gerlitz &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK, 53377b9900eSJiri Pirko sizeof(key->tp.src)); 53477b9900eSJiri Pirko fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST, 535aa72d708SOr Gerlitz &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK, 53677b9900eSJiri Pirko sizeof(key->tp.dst)); 53777b9900eSJiri Pirko } else if (key->basic.ip_proto == IPPROTO_UDP) { 53877b9900eSJiri Pirko fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC, 539aa72d708SOr Gerlitz &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK, 54077b9900eSJiri Pirko sizeof(key->tp.src)); 54177b9900eSJiri Pirko fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST, 542aa72d708SOr Gerlitz &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK, 54377b9900eSJiri Pirko sizeof(key->tp.dst)); 5445976c5f4SSimon Horman } else if (key->basic.ip_proto == IPPROTO_SCTP) { 5455976c5f4SSimon Horman fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC, 5465976c5f4SSimon Horman &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK, 5475976c5f4SSimon Horman sizeof(key->tp.src)); 5485976c5f4SSimon Horman fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST, 5495976c5f4SSimon Horman &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK, 5505976c5f4SSimon Horman sizeof(key->tp.dst)); 5517b684884SSimon Horman } else if (key->basic.n_proto == htons(ETH_P_IP) && 5527b684884SSimon Horman key->basic.ip_proto == IPPROTO_ICMP) { 5537b684884SSimon Horman fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV4_TYPE, 5547b684884SSimon Horman &mask->icmp.type, 5557b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_TYPE_MASK, 5567b684884SSimon Horman sizeof(key->icmp.type)); 5577b684884SSimon Horman fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV4_CODE, 5587b684884SSimon Horman &mask->icmp.code, 5597b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_CODE_MASK, 5607b684884SSimon Horman sizeof(key->icmp.code)); 5617b684884SSimon Horman } else if (key->basic.n_proto == htons(ETH_P_IPV6) && 5627b684884SSimon Horman key->basic.ip_proto == IPPROTO_ICMPV6) { 5637b684884SSimon Horman fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV6_TYPE, 5647b684884SSimon Horman &mask->icmp.type, 5657b684884SSimon Horman TCA_FLOWER_KEY_ICMPV6_TYPE_MASK, 5667b684884SSimon Horman sizeof(key->icmp.type)); 5677b684884SSimon Horman fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV4_CODE, 5687b684884SSimon Horman &mask->icmp.code, 5697b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_CODE_MASK, 5707b684884SSimon Horman sizeof(key->icmp.code)); 57177b9900eSJiri Pirko } 57277b9900eSJiri Pirko 573bc3103f1SAmir Vadai if (tb[TCA_FLOWER_KEY_ENC_IPV4_SRC] || 574bc3103f1SAmir Vadai tb[TCA_FLOWER_KEY_ENC_IPV4_DST]) { 575bc3103f1SAmir Vadai key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; 576970bfcd0SPaul Blakey mask->enc_control.addr_type = ~0; 577bc3103f1SAmir Vadai fl_set_key_val(tb, &key->enc_ipv4.src, 578bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_SRC, 579bc3103f1SAmir Vadai &mask->enc_ipv4.src, 580bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK, 581bc3103f1SAmir Vadai sizeof(key->enc_ipv4.src)); 582bc3103f1SAmir Vadai fl_set_key_val(tb, &key->enc_ipv4.dst, 583bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_DST, 584bc3103f1SAmir Vadai &mask->enc_ipv4.dst, 585bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_DST_MASK, 586bc3103f1SAmir Vadai sizeof(key->enc_ipv4.dst)); 587bc3103f1SAmir Vadai } 588bc3103f1SAmir Vadai 589bc3103f1SAmir Vadai if (tb[TCA_FLOWER_KEY_ENC_IPV6_SRC] || 590bc3103f1SAmir Vadai tb[TCA_FLOWER_KEY_ENC_IPV6_DST]) { 591bc3103f1SAmir Vadai key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; 592970bfcd0SPaul Blakey mask->enc_control.addr_type = ~0; 593bc3103f1SAmir Vadai fl_set_key_val(tb, &key->enc_ipv6.src, 594bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_SRC, 595bc3103f1SAmir Vadai &mask->enc_ipv6.src, 596bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK, 597bc3103f1SAmir Vadai sizeof(key->enc_ipv6.src)); 598bc3103f1SAmir Vadai fl_set_key_val(tb, &key->enc_ipv6.dst, 599bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_DST, 600bc3103f1SAmir Vadai &mask->enc_ipv6.dst, 601bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_DST_MASK, 602bc3103f1SAmir Vadai sizeof(key->enc_ipv6.dst)); 603bc3103f1SAmir Vadai } 604bc3103f1SAmir Vadai 605bc3103f1SAmir Vadai fl_set_key_val(tb, &key->enc_key_id.keyid, TCA_FLOWER_KEY_ENC_KEY_ID, 606eb523f42SHadar Hen Zion &mask->enc_key_id.keyid, TCA_FLOWER_UNSPEC, 607bc3103f1SAmir Vadai sizeof(key->enc_key_id.keyid)); 608bc3103f1SAmir Vadai 609f4d997fdSHadar Hen Zion fl_set_key_val(tb, &key->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT, 610f4d997fdSHadar Hen Zion &mask->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK, 611f4d997fdSHadar Hen Zion sizeof(key->enc_tp.src)); 612f4d997fdSHadar Hen Zion 613f4d997fdSHadar Hen Zion fl_set_key_val(tb, &key->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT, 614f4d997fdSHadar Hen Zion &mask->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK, 615f4d997fdSHadar Hen Zion sizeof(key->enc_tp.dst)); 616f4d997fdSHadar Hen Zion 617faa3ffceSOr Gerlitz fl_set_key_flags(tb, &key->control.flags, &mask->control.flags); 618faa3ffceSOr Gerlitz 61977b9900eSJiri Pirko return 0; 62077b9900eSJiri Pirko } 62177b9900eSJiri Pirko 62277b9900eSJiri Pirko static bool fl_mask_eq(struct fl_flow_mask *mask1, 62377b9900eSJiri Pirko struct fl_flow_mask *mask2) 62477b9900eSJiri Pirko { 62577b9900eSJiri Pirko const long *lmask1 = fl_key_get_start(&mask1->key, mask1); 62677b9900eSJiri Pirko const long *lmask2 = fl_key_get_start(&mask2->key, mask2); 62777b9900eSJiri Pirko 62877b9900eSJiri Pirko return !memcmp(&mask1->range, &mask2->range, sizeof(mask1->range)) && 62977b9900eSJiri Pirko !memcmp(lmask1, lmask2, fl_mask_range(mask1)); 63077b9900eSJiri Pirko } 63177b9900eSJiri Pirko 63277b9900eSJiri Pirko static const struct rhashtable_params fl_ht_params = { 63377b9900eSJiri Pirko .key_offset = offsetof(struct cls_fl_filter, mkey), /* base offset */ 63477b9900eSJiri Pirko .head_offset = offsetof(struct cls_fl_filter, ht_node), 63577b9900eSJiri Pirko .automatic_shrinking = true, 63677b9900eSJiri Pirko }; 63777b9900eSJiri Pirko 63877b9900eSJiri Pirko static int fl_init_hashtable(struct cls_fl_head *head, 63977b9900eSJiri Pirko struct fl_flow_mask *mask) 64077b9900eSJiri Pirko { 64177b9900eSJiri Pirko head->ht_params = fl_ht_params; 64277b9900eSJiri Pirko head->ht_params.key_len = fl_mask_range(mask); 64377b9900eSJiri Pirko head->ht_params.key_offset += mask->range.start; 64477b9900eSJiri Pirko 64577b9900eSJiri Pirko return rhashtable_init(&head->ht, &head->ht_params); 64677b9900eSJiri Pirko } 64777b9900eSJiri Pirko 64877b9900eSJiri Pirko #define FL_KEY_MEMBER_OFFSET(member) offsetof(struct fl_flow_key, member) 64977b9900eSJiri Pirko #define FL_KEY_MEMBER_SIZE(member) (sizeof(((struct fl_flow_key *) 0)->member)) 65077b9900eSJiri Pirko 651339ba878SHadar Hen Zion #define FL_KEY_IS_MASKED(mask, member) \ 652339ba878SHadar Hen Zion memchr_inv(((char *)mask) + FL_KEY_MEMBER_OFFSET(member), \ 653339ba878SHadar Hen Zion 0, FL_KEY_MEMBER_SIZE(member)) \ 65477b9900eSJiri Pirko 65577b9900eSJiri Pirko #define FL_KEY_SET(keys, cnt, id, member) \ 65677b9900eSJiri Pirko do { \ 65777b9900eSJiri Pirko keys[cnt].key_id = id; \ 65877b9900eSJiri Pirko keys[cnt].offset = FL_KEY_MEMBER_OFFSET(member); \ 65977b9900eSJiri Pirko cnt++; \ 66077b9900eSJiri Pirko } while(0); 66177b9900eSJiri Pirko 662339ba878SHadar Hen Zion #define FL_KEY_SET_IF_MASKED(mask, keys, cnt, id, member) \ 66377b9900eSJiri Pirko do { \ 664339ba878SHadar Hen Zion if (FL_KEY_IS_MASKED(mask, member)) \ 66577b9900eSJiri Pirko FL_KEY_SET(keys, cnt, id, member); \ 66677b9900eSJiri Pirko } while(0); 66777b9900eSJiri Pirko 66877b9900eSJiri Pirko static void fl_init_dissector(struct cls_fl_head *head, 66977b9900eSJiri Pirko struct fl_flow_mask *mask) 67077b9900eSJiri Pirko { 67177b9900eSJiri Pirko struct flow_dissector_key keys[FLOW_DISSECTOR_KEY_MAX]; 67277b9900eSJiri Pirko size_t cnt = 0; 67377b9900eSJiri Pirko 67442aecaa9STom Herbert FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_CONTROL, control); 67577b9900eSJiri Pirko FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_BASIC, basic); 676339ba878SHadar Hen Zion FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 67777b9900eSJiri Pirko FLOW_DISSECTOR_KEY_ETH_ADDRS, eth); 678339ba878SHadar Hen Zion FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 67977b9900eSJiri Pirko FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4); 680339ba878SHadar Hen Zion FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 68177b9900eSJiri Pirko FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6); 682339ba878SHadar Hen Zion FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 68377b9900eSJiri Pirko FLOW_DISSECTOR_KEY_PORTS, tp); 6849399ae9aSHadar Hen Zion FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 6857b684884SSimon Horman FLOW_DISSECTOR_KEY_ICMP, icmp); 6867b684884SSimon Horman FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 6879399ae9aSHadar Hen Zion FLOW_DISSECTOR_KEY_VLAN, vlan); 688519d1052SHadar Hen Zion FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 689519d1052SHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_KEYID, enc_key_id); 690519d1052SHadar Hen Zion FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 691519d1052SHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, enc_ipv4); 692519d1052SHadar Hen Zion FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 693519d1052SHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, enc_ipv6); 694519d1052SHadar Hen Zion if (FL_KEY_IS_MASKED(&mask->key, enc_ipv4) || 695519d1052SHadar Hen Zion FL_KEY_IS_MASKED(&mask->key, enc_ipv6)) 696519d1052SHadar Hen Zion FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_ENC_CONTROL, 697519d1052SHadar Hen Zion enc_control); 698f4d997fdSHadar Hen Zion FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 699f4d997fdSHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_PORTS, enc_tp); 70077b9900eSJiri Pirko 70177b9900eSJiri Pirko skb_flow_dissector_init(&head->dissector, keys, cnt); 70277b9900eSJiri Pirko } 70377b9900eSJiri Pirko 70477b9900eSJiri Pirko static int fl_check_assign_mask(struct cls_fl_head *head, 70577b9900eSJiri Pirko struct fl_flow_mask *mask) 70677b9900eSJiri Pirko { 70777b9900eSJiri Pirko int err; 70877b9900eSJiri Pirko 70977b9900eSJiri Pirko if (head->mask_assigned) { 71077b9900eSJiri Pirko if (!fl_mask_eq(&head->mask, mask)) 71177b9900eSJiri Pirko return -EINVAL; 71277b9900eSJiri Pirko else 71377b9900eSJiri Pirko return 0; 71477b9900eSJiri Pirko } 71577b9900eSJiri Pirko 71677b9900eSJiri Pirko /* Mask is not assigned yet. So assign it and init hashtable 71777b9900eSJiri Pirko * according to that. 71877b9900eSJiri Pirko */ 71977b9900eSJiri Pirko err = fl_init_hashtable(head, mask); 72077b9900eSJiri Pirko if (err) 72177b9900eSJiri Pirko return err; 72277b9900eSJiri Pirko memcpy(&head->mask, mask, sizeof(head->mask)); 72377b9900eSJiri Pirko head->mask_assigned = true; 72477b9900eSJiri Pirko 72577b9900eSJiri Pirko fl_init_dissector(head, mask); 72677b9900eSJiri Pirko 72777b9900eSJiri Pirko return 0; 72877b9900eSJiri Pirko } 72977b9900eSJiri Pirko 73077b9900eSJiri Pirko static int fl_set_parms(struct net *net, struct tcf_proto *tp, 73177b9900eSJiri Pirko struct cls_fl_filter *f, struct fl_flow_mask *mask, 73277b9900eSJiri Pirko unsigned long base, struct nlattr **tb, 73377b9900eSJiri Pirko struct nlattr *est, bool ovr) 73477b9900eSJiri Pirko { 73577b9900eSJiri Pirko struct tcf_exts e; 73677b9900eSJiri Pirko int err; 73777b9900eSJiri Pirko 738b9a24bb7SWANG Cong err = tcf_exts_init(&e, TCA_FLOWER_ACT, 0); 73977b9900eSJiri Pirko if (err < 0) 74077b9900eSJiri Pirko return err; 741b9a24bb7SWANG Cong err = tcf_exts_validate(net, tp, tb, est, &e, ovr); 742b9a24bb7SWANG Cong if (err < 0) 743b9a24bb7SWANG Cong goto errout; 74477b9900eSJiri Pirko 74577b9900eSJiri Pirko if (tb[TCA_FLOWER_CLASSID]) { 74677b9900eSJiri Pirko f->res.classid = nla_get_u32(tb[TCA_FLOWER_CLASSID]); 74777b9900eSJiri Pirko tcf_bind_filter(tp, &f->res, base); 74877b9900eSJiri Pirko } 74977b9900eSJiri Pirko 75077b9900eSJiri Pirko err = fl_set_key(net, tb, &f->key, &mask->key); 75177b9900eSJiri Pirko if (err) 75277b9900eSJiri Pirko goto errout; 75377b9900eSJiri Pirko 75477b9900eSJiri Pirko fl_mask_update_range(mask); 75577b9900eSJiri Pirko fl_set_masked_key(&f->mkey, &f->key, mask); 75677b9900eSJiri Pirko 75777b9900eSJiri Pirko tcf_exts_change(tp, &f->exts, &e); 75877b9900eSJiri Pirko 75977b9900eSJiri Pirko return 0; 76077b9900eSJiri Pirko errout: 76177b9900eSJiri Pirko tcf_exts_destroy(&e); 76277b9900eSJiri Pirko return err; 76377b9900eSJiri Pirko } 76477b9900eSJiri Pirko 76577b9900eSJiri Pirko static u32 fl_grab_new_handle(struct tcf_proto *tp, 76677b9900eSJiri Pirko struct cls_fl_head *head) 76777b9900eSJiri Pirko { 76877b9900eSJiri Pirko unsigned int i = 0x80000000; 76977b9900eSJiri Pirko u32 handle; 77077b9900eSJiri Pirko 77177b9900eSJiri Pirko do { 77277b9900eSJiri Pirko if (++head->hgen == 0x7FFFFFFF) 77377b9900eSJiri Pirko head->hgen = 1; 77477b9900eSJiri Pirko } while (--i > 0 && fl_get(tp, head->hgen)); 77577b9900eSJiri Pirko 77677b9900eSJiri Pirko if (unlikely(i == 0)) { 77777b9900eSJiri Pirko pr_err("Insufficient number of handles\n"); 77877b9900eSJiri Pirko handle = 0; 77977b9900eSJiri Pirko } else { 78077b9900eSJiri Pirko handle = head->hgen; 78177b9900eSJiri Pirko } 78277b9900eSJiri Pirko 78377b9900eSJiri Pirko return handle; 78477b9900eSJiri Pirko } 78577b9900eSJiri Pirko 78677b9900eSJiri Pirko static int fl_change(struct net *net, struct sk_buff *in_skb, 78777b9900eSJiri Pirko struct tcf_proto *tp, unsigned long base, 78877b9900eSJiri Pirko u32 handle, struct nlattr **tca, 78977b9900eSJiri Pirko unsigned long *arg, bool ovr) 79077b9900eSJiri Pirko { 79177b9900eSJiri Pirko struct cls_fl_head *head = rtnl_dereference(tp->root); 79277b9900eSJiri Pirko struct cls_fl_filter *fold = (struct cls_fl_filter *) *arg; 79377b9900eSJiri Pirko struct cls_fl_filter *fnew; 79477b9900eSJiri Pirko struct nlattr *tb[TCA_FLOWER_MAX + 1]; 79577b9900eSJiri Pirko struct fl_flow_mask mask = {}; 79677b9900eSJiri Pirko int err; 79777b9900eSJiri Pirko 79877b9900eSJiri Pirko if (!tca[TCA_OPTIONS]) 79977b9900eSJiri Pirko return -EINVAL; 80077b9900eSJiri Pirko 80177b9900eSJiri Pirko err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS], fl_policy); 80277b9900eSJiri Pirko if (err < 0) 80377b9900eSJiri Pirko return err; 80477b9900eSJiri Pirko 80577b9900eSJiri Pirko if (fold && handle && fold->handle != handle) 80677b9900eSJiri Pirko return -EINVAL; 80777b9900eSJiri Pirko 80877b9900eSJiri Pirko fnew = kzalloc(sizeof(*fnew), GFP_KERNEL); 80977b9900eSJiri Pirko if (!fnew) 81077b9900eSJiri Pirko return -ENOBUFS; 81177b9900eSJiri Pirko 812b9a24bb7SWANG Cong err = tcf_exts_init(&fnew->exts, TCA_FLOWER_ACT, 0); 813b9a24bb7SWANG Cong if (err < 0) 814b9a24bb7SWANG Cong goto errout; 81577b9900eSJiri Pirko 81677b9900eSJiri Pirko if (!handle) { 81777b9900eSJiri Pirko handle = fl_grab_new_handle(tp, head); 81877b9900eSJiri Pirko if (!handle) { 81977b9900eSJiri Pirko err = -EINVAL; 82077b9900eSJiri Pirko goto errout; 82177b9900eSJiri Pirko } 82277b9900eSJiri Pirko } 82377b9900eSJiri Pirko fnew->handle = handle; 82477b9900eSJiri Pirko 825e69985c6SAmir Vadai if (tb[TCA_FLOWER_FLAGS]) { 826e69985c6SAmir Vadai fnew->flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]); 827e69985c6SAmir Vadai 828e69985c6SAmir Vadai if (!tc_flags_valid(fnew->flags)) { 829e69985c6SAmir Vadai err = -EINVAL; 830e69985c6SAmir Vadai goto errout; 831e69985c6SAmir Vadai } 832e69985c6SAmir Vadai } 8335b33f488SAmir Vadai 83477b9900eSJiri Pirko err = fl_set_parms(net, tp, fnew, &mask, base, tb, tca[TCA_RATE], ovr); 83577b9900eSJiri Pirko if (err) 83677b9900eSJiri Pirko goto errout; 83777b9900eSJiri Pirko 83877b9900eSJiri Pirko err = fl_check_assign_mask(head, &mask); 83977b9900eSJiri Pirko if (err) 84077b9900eSJiri Pirko goto errout; 84177b9900eSJiri Pirko 842e8eb36cdSAmir Vadai if (!tc_skip_sw(fnew->flags)) { 84377b9900eSJiri Pirko err = rhashtable_insert_fast(&head->ht, &fnew->ht_node, 84477b9900eSJiri Pirko head->ht_params); 84577b9900eSJiri Pirko if (err) 84677b9900eSJiri Pirko goto errout; 847e69985c6SAmir Vadai } 8485b33f488SAmir Vadai 84979685219SHadar Hen Zion if (!tc_skip_hw(fnew->flags)) { 850e8eb36cdSAmir Vadai err = fl_hw_replace_filter(tp, 8515b33f488SAmir Vadai &head->dissector, 8525b33f488SAmir Vadai &mask.key, 8533036dab6SHadar Hen Zion fnew); 854e8eb36cdSAmir Vadai if (err) 855e8eb36cdSAmir Vadai goto errout; 85679685219SHadar Hen Zion } 8575b33f488SAmir Vadai 8585b33f488SAmir Vadai if (fold) { 859725cbb62SJiri Pirko if (!tc_skip_sw(fold->flags)) 86077b9900eSJiri Pirko rhashtable_remove_fast(&head->ht, &fold->ht_node, 86177b9900eSJiri Pirko head->ht_params); 86279685219SHadar Hen Zion if (!tc_skip_hw(fold->flags)) 8633036dab6SHadar Hen Zion fl_hw_destroy_filter(tp, fold); 8645b33f488SAmir Vadai } 86577b9900eSJiri Pirko 86677b9900eSJiri Pirko *arg = (unsigned long) fnew; 86777b9900eSJiri Pirko 86877b9900eSJiri Pirko if (fold) { 869ff3532f2SDaniel Borkmann list_replace_rcu(&fold->list, &fnew->list); 87077b9900eSJiri Pirko tcf_unbind_filter(tp, &fold->res); 87177b9900eSJiri Pirko call_rcu(&fold->rcu, fl_destroy_filter); 87277b9900eSJiri Pirko } else { 87377b9900eSJiri Pirko list_add_tail_rcu(&fnew->list, &head->filters); 87477b9900eSJiri Pirko } 87577b9900eSJiri Pirko 87677b9900eSJiri Pirko return 0; 87777b9900eSJiri Pirko 87877b9900eSJiri Pirko errout: 879b9a24bb7SWANG Cong tcf_exts_destroy(&fnew->exts); 88077b9900eSJiri Pirko kfree(fnew); 88177b9900eSJiri Pirko return err; 88277b9900eSJiri Pirko } 88377b9900eSJiri Pirko 88477b9900eSJiri Pirko static int fl_delete(struct tcf_proto *tp, unsigned long arg) 88577b9900eSJiri Pirko { 88677b9900eSJiri Pirko struct cls_fl_head *head = rtnl_dereference(tp->root); 88777b9900eSJiri Pirko struct cls_fl_filter *f = (struct cls_fl_filter *) arg; 88877b9900eSJiri Pirko 889725cbb62SJiri Pirko if (!tc_skip_sw(f->flags)) 89077b9900eSJiri Pirko rhashtable_remove_fast(&head->ht, &f->ht_node, 89177b9900eSJiri Pirko head->ht_params); 89213fa876eSRoi Dayan __fl_delete(tp, f); 89377b9900eSJiri Pirko return 0; 89477b9900eSJiri Pirko } 89577b9900eSJiri Pirko 89677b9900eSJiri Pirko static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg) 89777b9900eSJiri Pirko { 89877b9900eSJiri Pirko struct cls_fl_head *head = rtnl_dereference(tp->root); 89977b9900eSJiri Pirko struct cls_fl_filter *f; 90077b9900eSJiri Pirko 90177b9900eSJiri Pirko list_for_each_entry_rcu(f, &head->filters, list) { 90277b9900eSJiri Pirko if (arg->count < arg->skip) 90377b9900eSJiri Pirko goto skip; 90477b9900eSJiri Pirko if (arg->fn(tp, (unsigned long) f, arg) < 0) { 90577b9900eSJiri Pirko arg->stop = 1; 90677b9900eSJiri Pirko break; 90777b9900eSJiri Pirko } 90877b9900eSJiri Pirko skip: 90977b9900eSJiri Pirko arg->count++; 91077b9900eSJiri Pirko } 91177b9900eSJiri Pirko } 91277b9900eSJiri Pirko 91377b9900eSJiri Pirko static int fl_dump_key_val(struct sk_buff *skb, 91477b9900eSJiri Pirko void *val, int val_type, 91577b9900eSJiri Pirko void *mask, int mask_type, int len) 91677b9900eSJiri Pirko { 91777b9900eSJiri Pirko int err; 91877b9900eSJiri Pirko 91977b9900eSJiri Pirko if (!memchr_inv(mask, 0, len)) 92077b9900eSJiri Pirko return 0; 92177b9900eSJiri Pirko err = nla_put(skb, val_type, len, val); 92277b9900eSJiri Pirko if (err) 92377b9900eSJiri Pirko return err; 92477b9900eSJiri Pirko if (mask_type != TCA_FLOWER_UNSPEC) { 92577b9900eSJiri Pirko err = nla_put(skb, mask_type, len, mask); 92677b9900eSJiri Pirko if (err) 92777b9900eSJiri Pirko return err; 92877b9900eSJiri Pirko } 92977b9900eSJiri Pirko return 0; 93077b9900eSJiri Pirko } 93177b9900eSJiri Pirko 9329399ae9aSHadar Hen Zion static int fl_dump_key_vlan(struct sk_buff *skb, 9339399ae9aSHadar Hen Zion struct flow_dissector_key_vlan *vlan_key, 9349399ae9aSHadar Hen Zion struct flow_dissector_key_vlan *vlan_mask) 9359399ae9aSHadar Hen Zion { 9369399ae9aSHadar Hen Zion int err; 9379399ae9aSHadar Hen Zion 9389399ae9aSHadar Hen Zion if (!memchr_inv(vlan_mask, 0, sizeof(*vlan_mask))) 9399399ae9aSHadar Hen Zion return 0; 9409399ae9aSHadar Hen Zion if (vlan_mask->vlan_id) { 9419399ae9aSHadar Hen Zion err = nla_put_u16(skb, TCA_FLOWER_KEY_VLAN_ID, 9429399ae9aSHadar Hen Zion vlan_key->vlan_id); 9439399ae9aSHadar Hen Zion if (err) 9449399ae9aSHadar Hen Zion return err; 9459399ae9aSHadar Hen Zion } 9469399ae9aSHadar Hen Zion if (vlan_mask->vlan_priority) { 9479399ae9aSHadar Hen Zion err = nla_put_u8(skb, TCA_FLOWER_KEY_VLAN_PRIO, 9489399ae9aSHadar Hen Zion vlan_key->vlan_priority); 9499399ae9aSHadar Hen Zion if (err) 9509399ae9aSHadar Hen Zion return err; 9519399ae9aSHadar Hen Zion } 9529399ae9aSHadar Hen Zion return 0; 9539399ae9aSHadar Hen Zion } 9549399ae9aSHadar Hen Zion 955faa3ffceSOr Gerlitz static void fl_get_key_flag(u32 dissector_key, u32 dissector_mask, 956faa3ffceSOr Gerlitz u32 *flower_key, u32 *flower_mask, 957faa3ffceSOr Gerlitz u32 flower_flag_bit, u32 dissector_flag_bit) 958faa3ffceSOr Gerlitz { 959faa3ffceSOr Gerlitz if (dissector_mask & dissector_flag_bit) { 960faa3ffceSOr Gerlitz *flower_mask |= flower_flag_bit; 961faa3ffceSOr Gerlitz if (dissector_key & dissector_flag_bit) 962faa3ffceSOr Gerlitz *flower_key |= flower_flag_bit; 963faa3ffceSOr Gerlitz } 964faa3ffceSOr Gerlitz } 965faa3ffceSOr Gerlitz 966faa3ffceSOr Gerlitz static int fl_dump_key_flags(struct sk_buff *skb, u32 flags_key, u32 flags_mask) 967faa3ffceSOr Gerlitz { 968faa3ffceSOr Gerlitz u32 key, mask; 969faa3ffceSOr Gerlitz __be32 _key, _mask; 970faa3ffceSOr Gerlitz int err; 971faa3ffceSOr Gerlitz 972faa3ffceSOr Gerlitz if (!memchr_inv(&flags_mask, 0, sizeof(flags_mask))) 973faa3ffceSOr Gerlitz return 0; 974faa3ffceSOr Gerlitz 975faa3ffceSOr Gerlitz key = 0; 976faa3ffceSOr Gerlitz mask = 0; 977faa3ffceSOr Gerlitz 978faa3ffceSOr Gerlitz fl_get_key_flag(flags_key, flags_mask, &key, &mask, 979faa3ffceSOr Gerlitz TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT); 980faa3ffceSOr Gerlitz 981faa3ffceSOr Gerlitz _key = cpu_to_be32(key); 982faa3ffceSOr Gerlitz _mask = cpu_to_be32(mask); 983faa3ffceSOr Gerlitz 984faa3ffceSOr Gerlitz err = nla_put(skb, TCA_FLOWER_KEY_FLAGS, 4, &_key); 985faa3ffceSOr Gerlitz if (err) 986faa3ffceSOr Gerlitz return err; 987faa3ffceSOr Gerlitz 988faa3ffceSOr Gerlitz return nla_put(skb, TCA_FLOWER_KEY_FLAGS_MASK, 4, &_mask); 989faa3ffceSOr Gerlitz } 990faa3ffceSOr Gerlitz 99177b9900eSJiri Pirko static int fl_dump(struct net *net, struct tcf_proto *tp, unsigned long fh, 99277b9900eSJiri Pirko struct sk_buff *skb, struct tcmsg *t) 99377b9900eSJiri Pirko { 99477b9900eSJiri Pirko struct cls_fl_head *head = rtnl_dereference(tp->root); 99577b9900eSJiri Pirko struct cls_fl_filter *f = (struct cls_fl_filter *) fh; 99677b9900eSJiri Pirko struct nlattr *nest; 99777b9900eSJiri Pirko struct fl_flow_key *key, *mask; 99877b9900eSJiri Pirko 99977b9900eSJiri Pirko if (!f) 100077b9900eSJiri Pirko return skb->len; 100177b9900eSJiri Pirko 100277b9900eSJiri Pirko t->tcm_handle = f->handle; 100377b9900eSJiri Pirko 100477b9900eSJiri Pirko nest = nla_nest_start(skb, TCA_OPTIONS); 100577b9900eSJiri Pirko if (!nest) 100677b9900eSJiri Pirko goto nla_put_failure; 100777b9900eSJiri Pirko 100877b9900eSJiri Pirko if (f->res.classid && 100977b9900eSJiri Pirko nla_put_u32(skb, TCA_FLOWER_CLASSID, f->res.classid)) 101077b9900eSJiri Pirko goto nla_put_failure; 101177b9900eSJiri Pirko 101277b9900eSJiri Pirko key = &f->key; 101377b9900eSJiri Pirko mask = &head->mask.key; 101477b9900eSJiri Pirko 101577b9900eSJiri Pirko if (mask->indev_ifindex) { 101677b9900eSJiri Pirko struct net_device *dev; 101777b9900eSJiri Pirko 101877b9900eSJiri Pirko dev = __dev_get_by_index(net, key->indev_ifindex); 101977b9900eSJiri Pirko if (dev && nla_put_string(skb, TCA_FLOWER_INDEV, dev->name)) 102077b9900eSJiri Pirko goto nla_put_failure; 102177b9900eSJiri Pirko } 102277b9900eSJiri Pirko 102379685219SHadar Hen Zion if (!tc_skip_hw(f->flags)) 102410cbc684SAmir Vadai fl_hw_update_stats(tp, f); 102510cbc684SAmir Vadai 102677b9900eSJiri Pirko if (fl_dump_key_val(skb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST, 102777b9900eSJiri Pirko mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK, 102877b9900eSJiri Pirko sizeof(key->eth.dst)) || 102977b9900eSJiri Pirko fl_dump_key_val(skb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC, 103077b9900eSJiri Pirko mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK, 103177b9900eSJiri Pirko sizeof(key->eth.src)) || 103277b9900eSJiri Pirko fl_dump_key_val(skb, &key->basic.n_proto, TCA_FLOWER_KEY_ETH_TYPE, 103377b9900eSJiri Pirko &mask->basic.n_proto, TCA_FLOWER_UNSPEC, 103477b9900eSJiri Pirko sizeof(key->basic.n_proto))) 103577b9900eSJiri Pirko goto nla_put_failure; 10369399ae9aSHadar Hen Zion 10379399ae9aSHadar Hen Zion if (fl_dump_key_vlan(skb, &key->vlan, &mask->vlan)) 10389399ae9aSHadar Hen Zion goto nla_put_failure; 10399399ae9aSHadar Hen Zion 104077b9900eSJiri Pirko if ((key->basic.n_proto == htons(ETH_P_IP) || 104177b9900eSJiri Pirko key->basic.n_proto == htons(ETH_P_IPV6)) && 104277b9900eSJiri Pirko fl_dump_key_val(skb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO, 104377b9900eSJiri Pirko &mask->basic.ip_proto, TCA_FLOWER_UNSPEC, 104477b9900eSJiri Pirko sizeof(key->basic.ip_proto))) 104577b9900eSJiri Pirko goto nla_put_failure; 104677b9900eSJiri Pirko 1047c3f83241STom Herbert if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS && 104877b9900eSJiri Pirko (fl_dump_key_val(skb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC, 104977b9900eSJiri Pirko &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK, 105077b9900eSJiri Pirko sizeof(key->ipv4.src)) || 105177b9900eSJiri Pirko fl_dump_key_val(skb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST, 105277b9900eSJiri Pirko &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK, 105377b9900eSJiri Pirko sizeof(key->ipv4.dst)))) 105477b9900eSJiri Pirko goto nla_put_failure; 1055c3f83241STom Herbert else if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS && 105677b9900eSJiri Pirko (fl_dump_key_val(skb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC, 105777b9900eSJiri Pirko &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK, 105877b9900eSJiri Pirko sizeof(key->ipv6.src)) || 105977b9900eSJiri Pirko fl_dump_key_val(skb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST, 106077b9900eSJiri Pirko &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK, 106177b9900eSJiri Pirko sizeof(key->ipv6.dst)))) 106277b9900eSJiri Pirko goto nla_put_failure; 106377b9900eSJiri Pirko 106477b9900eSJiri Pirko if (key->basic.ip_proto == IPPROTO_TCP && 106577b9900eSJiri Pirko (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC, 1066aa72d708SOr Gerlitz &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK, 106777b9900eSJiri Pirko sizeof(key->tp.src)) || 106877b9900eSJiri Pirko fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST, 1069aa72d708SOr Gerlitz &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK, 107077b9900eSJiri Pirko sizeof(key->tp.dst)))) 107177b9900eSJiri Pirko goto nla_put_failure; 107277b9900eSJiri Pirko else if (key->basic.ip_proto == IPPROTO_UDP && 107377b9900eSJiri Pirko (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC, 1074aa72d708SOr Gerlitz &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK, 107577b9900eSJiri Pirko sizeof(key->tp.src)) || 107677b9900eSJiri Pirko fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST, 1077aa72d708SOr Gerlitz &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK, 107877b9900eSJiri Pirko sizeof(key->tp.dst)))) 107977b9900eSJiri Pirko goto nla_put_failure; 10805976c5f4SSimon Horman else if (key->basic.ip_proto == IPPROTO_SCTP && 10815976c5f4SSimon Horman (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC, 10825976c5f4SSimon Horman &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK, 10835976c5f4SSimon Horman sizeof(key->tp.src)) || 10845976c5f4SSimon Horman fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST, 10855976c5f4SSimon Horman &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK, 10865976c5f4SSimon Horman sizeof(key->tp.dst)))) 10875976c5f4SSimon Horman goto nla_put_failure; 10887b684884SSimon Horman else if (key->basic.n_proto == htons(ETH_P_IP) && 10897b684884SSimon Horman key->basic.ip_proto == IPPROTO_ICMP && 10907b684884SSimon Horman (fl_dump_key_val(skb, &key->icmp.type, 10917b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_TYPE, &mask->icmp.type, 10927b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_TYPE_MASK, 10937b684884SSimon Horman sizeof(key->icmp.type)) || 10947b684884SSimon Horman fl_dump_key_val(skb, &key->icmp.code, 10957b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_CODE, &mask->icmp.code, 10967b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_CODE_MASK, 10977b684884SSimon Horman sizeof(key->icmp.code)))) 10987b684884SSimon Horman goto nla_put_failure; 10997b684884SSimon Horman else if (key->basic.n_proto == htons(ETH_P_IPV6) && 11007b684884SSimon Horman key->basic.ip_proto == IPPROTO_ICMPV6 && 11017b684884SSimon Horman (fl_dump_key_val(skb, &key->icmp.type, 11027b684884SSimon Horman TCA_FLOWER_KEY_ICMPV6_TYPE, &mask->icmp.type, 11037b684884SSimon Horman TCA_FLOWER_KEY_ICMPV6_TYPE_MASK, 11047b684884SSimon Horman sizeof(key->icmp.type)) || 11057b684884SSimon Horman fl_dump_key_val(skb, &key->icmp.code, 11067b684884SSimon Horman TCA_FLOWER_KEY_ICMPV6_CODE, &mask->icmp.code, 11077b684884SSimon Horman TCA_FLOWER_KEY_ICMPV6_CODE_MASK, 11087b684884SSimon Horman sizeof(key->icmp.code)))) 11097b684884SSimon Horman goto nla_put_failure; 111077b9900eSJiri Pirko 1111bc3103f1SAmir Vadai if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS && 1112bc3103f1SAmir Vadai (fl_dump_key_val(skb, &key->enc_ipv4.src, 1113bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_SRC, &mask->enc_ipv4.src, 1114bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK, 1115bc3103f1SAmir Vadai sizeof(key->enc_ipv4.src)) || 1116bc3103f1SAmir Vadai fl_dump_key_val(skb, &key->enc_ipv4.dst, 1117bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_DST, &mask->enc_ipv4.dst, 1118bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_DST_MASK, 1119bc3103f1SAmir Vadai sizeof(key->enc_ipv4.dst)))) 1120bc3103f1SAmir Vadai goto nla_put_failure; 1121bc3103f1SAmir Vadai else if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS && 1122bc3103f1SAmir Vadai (fl_dump_key_val(skb, &key->enc_ipv6.src, 1123bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_SRC, &mask->enc_ipv6.src, 1124bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK, 1125bc3103f1SAmir Vadai sizeof(key->enc_ipv6.src)) || 1126bc3103f1SAmir Vadai fl_dump_key_val(skb, &key->enc_ipv6.dst, 1127bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_DST, 1128bc3103f1SAmir Vadai &mask->enc_ipv6.dst, 1129bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_DST_MASK, 1130bc3103f1SAmir Vadai sizeof(key->enc_ipv6.dst)))) 1131bc3103f1SAmir Vadai goto nla_put_failure; 1132bc3103f1SAmir Vadai 1133bc3103f1SAmir Vadai if (fl_dump_key_val(skb, &key->enc_key_id, TCA_FLOWER_KEY_ENC_KEY_ID, 1134eb523f42SHadar Hen Zion &mask->enc_key_id, TCA_FLOWER_UNSPEC, 1135f4d997fdSHadar Hen Zion sizeof(key->enc_key_id)) || 1136f4d997fdSHadar Hen Zion fl_dump_key_val(skb, &key->enc_tp.src, 1137f4d997fdSHadar Hen Zion TCA_FLOWER_KEY_ENC_UDP_SRC_PORT, 1138f4d997fdSHadar Hen Zion &mask->enc_tp.src, 1139f4d997fdSHadar Hen Zion TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK, 1140f4d997fdSHadar Hen Zion sizeof(key->enc_tp.src)) || 1141f4d997fdSHadar Hen Zion fl_dump_key_val(skb, &key->enc_tp.dst, 1142f4d997fdSHadar Hen Zion TCA_FLOWER_KEY_ENC_UDP_DST_PORT, 1143f4d997fdSHadar Hen Zion &mask->enc_tp.dst, 1144f4d997fdSHadar Hen Zion TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK, 1145f4d997fdSHadar Hen Zion sizeof(key->enc_tp.dst))) 1146bc3103f1SAmir Vadai goto nla_put_failure; 1147bc3103f1SAmir Vadai 1148faa3ffceSOr Gerlitz if (fl_dump_key_flags(skb, key->control.flags, mask->control.flags)) 1149faa3ffceSOr Gerlitz goto nla_put_failure; 1150faa3ffceSOr Gerlitz 1151e69985c6SAmir Vadai nla_put_u32(skb, TCA_FLOWER_FLAGS, f->flags); 1152e69985c6SAmir Vadai 115377b9900eSJiri Pirko if (tcf_exts_dump(skb, &f->exts)) 115477b9900eSJiri Pirko goto nla_put_failure; 115577b9900eSJiri Pirko 115677b9900eSJiri Pirko nla_nest_end(skb, nest); 115777b9900eSJiri Pirko 115877b9900eSJiri Pirko if (tcf_exts_dump_stats(skb, &f->exts) < 0) 115977b9900eSJiri Pirko goto nla_put_failure; 116077b9900eSJiri Pirko 116177b9900eSJiri Pirko return skb->len; 116277b9900eSJiri Pirko 116377b9900eSJiri Pirko nla_put_failure: 116477b9900eSJiri Pirko nla_nest_cancel(skb, nest); 116577b9900eSJiri Pirko return -1; 116677b9900eSJiri Pirko } 116777b9900eSJiri Pirko 116877b9900eSJiri Pirko static struct tcf_proto_ops cls_fl_ops __read_mostly = { 116977b9900eSJiri Pirko .kind = "flower", 117077b9900eSJiri Pirko .classify = fl_classify, 117177b9900eSJiri Pirko .init = fl_init, 117277b9900eSJiri Pirko .destroy = fl_destroy, 117377b9900eSJiri Pirko .get = fl_get, 117477b9900eSJiri Pirko .change = fl_change, 117577b9900eSJiri Pirko .delete = fl_delete, 117677b9900eSJiri Pirko .walk = fl_walk, 117777b9900eSJiri Pirko .dump = fl_dump, 117877b9900eSJiri Pirko .owner = THIS_MODULE, 117977b9900eSJiri Pirko }; 118077b9900eSJiri Pirko 118177b9900eSJiri Pirko static int __init cls_fl_init(void) 118277b9900eSJiri Pirko { 118377b9900eSJiri Pirko return register_tcf_proto_ops(&cls_fl_ops); 118477b9900eSJiri Pirko } 118577b9900eSJiri Pirko 118677b9900eSJiri Pirko static void __exit cls_fl_exit(void) 118777b9900eSJiri Pirko { 118877b9900eSJiri Pirko unregister_tcf_proto_ops(&cls_fl_ops); 118977b9900eSJiri Pirko } 119077b9900eSJiri Pirko 119177b9900eSJiri Pirko module_init(cls_fl_init); 119277b9900eSJiri Pirko module_exit(cls_fl_exit); 119377b9900eSJiri Pirko 119477b9900eSJiri Pirko MODULE_AUTHOR("Jiri Pirko <jiri@resnulli.us>"); 119577b9900eSJiri Pirko MODULE_DESCRIPTION("Flower classifier"); 119677b9900eSJiri Pirko MODULE_LICENSE("GPL v2"); 1197