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> 21*a577d8f7SBenjamin 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; 51*a577d8f7SBenjamin LaHaise struct flow_dissector_key_mpls mpls; 5277b9900eSJiri Pirko } __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */ 5377b9900eSJiri Pirko 5477b9900eSJiri Pirko struct fl_flow_mask_range { 5577b9900eSJiri Pirko unsigned short int start; 5677b9900eSJiri Pirko unsigned short int end; 5777b9900eSJiri Pirko }; 5877b9900eSJiri Pirko 5977b9900eSJiri Pirko struct fl_flow_mask { 6077b9900eSJiri Pirko struct fl_flow_key key; 6177b9900eSJiri Pirko struct fl_flow_mask_range range; 6277b9900eSJiri Pirko struct rcu_head rcu; 6377b9900eSJiri Pirko }; 6477b9900eSJiri Pirko 6577b9900eSJiri Pirko struct cls_fl_head { 6677b9900eSJiri Pirko struct rhashtable ht; 6777b9900eSJiri Pirko struct fl_flow_mask mask; 6877b9900eSJiri Pirko struct flow_dissector dissector; 6977b9900eSJiri Pirko u32 hgen; 7077b9900eSJiri Pirko bool mask_assigned; 7177b9900eSJiri Pirko struct list_head filters; 7277b9900eSJiri Pirko struct rhashtable_params ht_params; 73d9363774SDaniel Borkmann union { 74d9363774SDaniel Borkmann struct work_struct work; 7577b9900eSJiri Pirko struct rcu_head rcu; 7677b9900eSJiri Pirko }; 77d9363774SDaniel Borkmann }; 7877b9900eSJiri Pirko 7977b9900eSJiri Pirko struct cls_fl_filter { 8077b9900eSJiri Pirko struct rhash_head ht_node; 8177b9900eSJiri Pirko struct fl_flow_key mkey; 8277b9900eSJiri Pirko struct tcf_exts exts; 8377b9900eSJiri Pirko struct tcf_result res; 8477b9900eSJiri Pirko struct fl_flow_key key; 8577b9900eSJiri Pirko struct list_head list; 8677b9900eSJiri Pirko u32 handle; 87e69985c6SAmir Vadai u32 flags; 8877b9900eSJiri Pirko struct rcu_head rcu; 897091d8c7SHadar Hen Zion struct tc_to_netdev tc; 907091d8c7SHadar Hen Zion struct net_device *hw_dev; 9177b9900eSJiri Pirko }; 9277b9900eSJiri Pirko 9377b9900eSJiri Pirko static unsigned short int fl_mask_range(const struct fl_flow_mask *mask) 9477b9900eSJiri Pirko { 9577b9900eSJiri Pirko return mask->range.end - mask->range.start; 9677b9900eSJiri Pirko } 9777b9900eSJiri Pirko 9877b9900eSJiri Pirko static void fl_mask_update_range(struct fl_flow_mask *mask) 9977b9900eSJiri Pirko { 10077b9900eSJiri Pirko const u8 *bytes = (const u8 *) &mask->key; 10177b9900eSJiri Pirko size_t size = sizeof(mask->key); 10277b9900eSJiri Pirko size_t i, first = 0, last = size - 1; 10377b9900eSJiri Pirko 10477b9900eSJiri Pirko for (i = 0; i < sizeof(mask->key); i++) { 10577b9900eSJiri Pirko if (bytes[i]) { 10677b9900eSJiri Pirko if (!first && i) 10777b9900eSJiri Pirko first = i; 10877b9900eSJiri Pirko last = i; 10977b9900eSJiri Pirko } 11077b9900eSJiri Pirko } 11177b9900eSJiri Pirko mask->range.start = rounddown(first, sizeof(long)); 11277b9900eSJiri Pirko mask->range.end = roundup(last + 1, sizeof(long)); 11377b9900eSJiri Pirko } 11477b9900eSJiri Pirko 11577b9900eSJiri Pirko static void *fl_key_get_start(struct fl_flow_key *key, 11677b9900eSJiri Pirko const struct fl_flow_mask *mask) 11777b9900eSJiri Pirko { 11877b9900eSJiri Pirko return (u8 *) key + mask->range.start; 11977b9900eSJiri Pirko } 12077b9900eSJiri Pirko 12177b9900eSJiri Pirko static void fl_set_masked_key(struct fl_flow_key *mkey, struct fl_flow_key *key, 12277b9900eSJiri Pirko struct fl_flow_mask *mask) 12377b9900eSJiri Pirko { 12477b9900eSJiri Pirko const long *lkey = fl_key_get_start(key, mask); 12577b9900eSJiri Pirko const long *lmask = fl_key_get_start(&mask->key, mask); 12677b9900eSJiri Pirko long *lmkey = fl_key_get_start(mkey, mask); 12777b9900eSJiri Pirko int i; 12877b9900eSJiri Pirko 12977b9900eSJiri Pirko for (i = 0; i < fl_mask_range(mask); i += sizeof(long)) 13077b9900eSJiri Pirko *lmkey++ = *lkey++ & *lmask++; 13177b9900eSJiri Pirko } 13277b9900eSJiri Pirko 13377b9900eSJiri Pirko static void fl_clear_masked_range(struct fl_flow_key *key, 13477b9900eSJiri Pirko struct fl_flow_mask *mask) 13577b9900eSJiri Pirko { 13677b9900eSJiri Pirko memset(fl_key_get_start(key, mask), 0, fl_mask_range(mask)); 13777b9900eSJiri Pirko } 13877b9900eSJiri Pirko 139a3308d8fSPaul Blakey static struct cls_fl_filter *fl_lookup(struct cls_fl_head *head, 140a3308d8fSPaul Blakey struct fl_flow_key *mkey) 141a3308d8fSPaul Blakey { 142a3308d8fSPaul Blakey return rhashtable_lookup_fast(&head->ht, 143a3308d8fSPaul Blakey fl_key_get_start(mkey, &head->mask), 144a3308d8fSPaul Blakey head->ht_params); 145a3308d8fSPaul Blakey } 146a3308d8fSPaul Blakey 14777b9900eSJiri Pirko static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp, 14877b9900eSJiri Pirko struct tcf_result *res) 14977b9900eSJiri Pirko { 15077b9900eSJiri Pirko struct cls_fl_head *head = rcu_dereference_bh(tp->root); 15177b9900eSJiri Pirko struct cls_fl_filter *f; 15277b9900eSJiri Pirko struct fl_flow_key skb_key; 15377b9900eSJiri Pirko struct fl_flow_key skb_mkey; 154bc3103f1SAmir Vadai struct ip_tunnel_info *info; 15577b9900eSJiri Pirko 156e69985c6SAmir Vadai if (!atomic_read(&head->ht.nelems)) 157e69985c6SAmir Vadai return -1; 158e69985c6SAmir Vadai 15977b9900eSJiri Pirko fl_clear_masked_range(&skb_key, &head->mask); 160bc3103f1SAmir Vadai 161bc3103f1SAmir Vadai info = skb_tunnel_info(skb); 162bc3103f1SAmir Vadai if (info) { 163bc3103f1SAmir Vadai struct ip_tunnel_key *key = &info->key; 164bc3103f1SAmir Vadai 165bc3103f1SAmir Vadai switch (ip_tunnel_info_af(info)) { 166bc3103f1SAmir Vadai case AF_INET: 1670df0f207SPaul Blakey skb_key.enc_control.addr_type = 1680df0f207SPaul Blakey FLOW_DISSECTOR_KEY_IPV4_ADDRS; 169bc3103f1SAmir Vadai skb_key.enc_ipv4.src = key->u.ipv4.src; 170bc3103f1SAmir Vadai skb_key.enc_ipv4.dst = key->u.ipv4.dst; 171bc3103f1SAmir Vadai break; 172bc3103f1SAmir Vadai case AF_INET6: 1730df0f207SPaul Blakey skb_key.enc_control.addr_type = 1740df0f207SPaul Blakey FLOW_DISSECTOR_KEY_IPV6_ADDRS; 175bc3103f1SAmir Vadai skb_key.enc_ipv6.src = key->u.ipv6.src; 176bc3103f1SAmir Vadai skb_key.enc_ipv6.dst = key->u.ipv6.dst; 177bc3103f1SAmir Vadai break; 178bc3103f1SAmir Vadai } 179bc3103f1SAmir Vadai 180bc3103f1SAmir Vadai skb_key.enc_key_id.keyid = tunnel_id_to_key32(key->tun_id); 181f4d997fdSHadar Hen Zion skb_key.enc_tp.src = key->tp_src; 182f4d997fdSHadar Hen Zion skb_key.enc_tp.dst = key->tp_dst; 183bc3103f1SAmir Vadai } 184bc3103f1SAmir Vadai 18577b9900eSJiri Pirko skb_key.indev_ifindex = skb->skb_iif; 18677b9900eSJiri Pirko /* skb_flow_dissect() does not set n_proto in case an unknown protocol, 18777b9900eSJiri Pirko * so do it rather here. 18877b9900eSJiri Pirko */ 18977b9900eSJiri Pirko skb_key.basic.n_proto = skb->protocol; 190cd79a238STom Herbert skb_flow_dissect(skb, &head->dissector, &skb_key, 0); 19177b9900eSJiri Pirko 19277b9900eSJiri Pirko fl_set_masked_key(&skb_mkey, &skb_key, &head->mask); 19377b9900eSJiri Pirko 194a3308d8fSPaul Blakey f = fl_lookup(head, &skb_mkey); 195e8eb36cdSAmir Vadai if (f && !tc_skip_sw(f->flags)) { 19677b9900eSJiri Pirko *res = f->res; 19777b9900eSJiri Pirko return tcf_exts_exec(skb, &f->exts, res); 19877b9900eSJiri Pirko } 19977b9900eSJiri Pirko return -1; 20077b9900eSJiri Pirko } 20177b9900eSJiri Pirko 20277b9900eSJiri Pirko static int fl_init(struct tcf_proto *tp) 20377b9900eSJiri Pirko { 20477b9900eSJiri Pirko struct cls_fl_head *head; 20577b9900eSJiri Pirko 20677b9900eSJiri Pirko head = kzalloc(sizeof(*head), GFP_KERNEL); 20777b9900eSJiri Pirko if (!head) 20877b9900eSJiri Pirko return -ENOBUFS; 20977b9900eSJiri Pirko 21077b9900eSJiri Pirko INIT_LIST_HEAD_RCU(&head->filters); 21177b9900eSJiri Pirko rcu_assign_pointer(tp->root, head); 21277b9900eSJiri Pirko 21377b9900eSJiri Pirko return 0; 21477b9900eSJiri Pirko } 21577b9900eSJiri Pirko 21677b9900eSJiri Pirko static void fl_destroy_filter(struct rcu_head *head) 21777b9900eSJiri Pirko { 21877b9900eSJiri Pirko struct cls_fl_filter *f = container_of(head, struct cls_fl_filter, rcu); 21977b9900eSJiri Pirko 22077b9900eSJiri Pirko tcf_exts_destroy(&f->exts); 22177b9900eSJiri Pirko kfree(f); 22277b9900eSJiri Pirko } 22377b9900eSJiri Pirko 2243036dab6SHadar Hen Zion static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f) 2255b33f488SAmir Vadai { 2265b33f488SAmir Vadai struct tc_cls_flower_offload offload = {0}; 2277091d8c7SHadar Hen Zion struct net_device *dev = f->hw_dev; 2287091d8c7SHadar Hen Zion struct tc_to_netdev *tc = &f->tc; 2295b33f488SAmir Vadai 23079685219SHadar Hen Zion if (!tc_can_offload(dev, tp)) 2315b33f488SAmir Vadai return; 2325b33f488SAmir Vadai 2335b33f488SAmir Vadai offload.command = TC_CLSFLOWER_DESTROY; 23469ca05ceSJiri Pirko offload.prio = tp->prio; 2353036dab6SHadar Hen Zion offload.cookie = (unsigned long)f; 2365b33f488SAmir Vadai 2377091d8c7SHadar Hen Zion tc->type = TC_SETUP_CLSFLOWER; 2387091d8c7SHadar Hen Zion tc->cls_flower = &offload; 2395b33f488SAmir Vadai 2407091d8c7SHadar Hen Zion dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol, tc); 2415b33f488SAmir Vadai } 2425b33f488SAmir Vadai 243e8eb36cdSAmir Vadai static int fl_hw_replace_filter(struct tcf_proto *tp, 2445b33f488SAmir Vadai struct flow_dissector *dissector, 2455b33f488SAmir Vadai struct fl_flow_key *mask, 2463036dab6SHadar Hen Zion struct cls_fl_filter *f) 2475b33f488SAmir Vadai { 2485b33f488SAmir Vadai struct net_device *dev = tp->q->dev_queue->dev; 2495b33f488SAmir Vadai struct tc_cls_flower_offload offload = {0}; 2507091d8c7SHadar Hen Zion struct tc_to_netdev *tc = &f->tc; 251e8eb36cdSAmir Vadai int err; 2525b33f488SAmir Vadai 2537091d8c7SHadar Hen Zion if (!tc_can_offload(dev, tp)) { 254a6e16931SHadar Hen Zion if (tcf_exts_get_dev(dev, &f->exts, &f->hw_dev) || 255a6e16931SHadar Hen Zion (f->hw_dev && !tc_can_offload(f->hw_dev, tp))) { 256a6e16931SHadar Hen Zion f->hw_dev = dev; 2573036dab6SHadar Hen Zion return tc_skip_sw(f->flags) ? -EINVAL : 0; 258a6e16931SHadar Hen Zion } 2597091d8c7SHadar Hen Zion dev = f->hw_dev; 2607091d8c7SHadar Hen Zion tc->egress_dev = true; 2617091d8c7SHadar Hen Zion } else { 2627091d8c7SHadar Hen Zion f->hw_dev = dev; 2637091d8c7SHadar Hen Zion } 2645b33f488SAmir Vadai 2655b33f488SAmir Vadai offload.command = TC_CLSFLOWER_REPLACE; 26669ca05ceSJiri Pirko offload.prio = tp->prio; 2673036dab6SHadar Hen Zion offload.cookie = (unsigned long)f; 2685b33f488SAmir Vadai offload.dissector = dissector; 2695b33f488SAmir Vadai offload.mask = mask; 270f93bd17bSPaul Blakey offload.key = &f->mkey; 2713036dab6SHadar Hen Zion offload.exts = &f->exts; 2725b33f488SAmir Vadai 2737091d8c7SHadar Hen Zion tc->type = TC_SETUP_CLSFLOWER; 2747091d8c7SHadar Hen Zion tc->cls_flower = &offload; 2755b33f488SAmir Vadai 2765a7a5555SJamal Hadi Salim err = dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol, 2777091d8c7SHadar Hen Zion tc); 27855593960SOr Gerlitz if (!err) 27955593960SOr Gerlitz f->flags |= TCA_CLS_FLAGS_IN_HW; 280e8eb36cdSAmir Vadai 2813036dab6SHadar Hen Zion if (tc_skip_sw(f->flags)) 282e8eb36cdSAmir Vadai return err; 283e8eb36cdSAmir Vadai return 0; 2845b33f488SAmir Vadai } 2855b33f488SAmir Vadai 28610cbc684SAmir Vadai static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f) 28710cbc684SAmir Vadai { 28810cbc684SAmir Vadai struct tc_cls_flower_offload offload = {0}; 2897091d8c7SHadar Hen Zion struct net_device *dev = f->hw_dev; 2907091d8c7SHadar Hen Zion struct tc_to_netdev *tc = &f->tc; 29110cbc684SAmir Vadai 29279685219SHadar Hen Zion if (!tc_can_offload(dev, tp)) 29310cbc684SAmir Vadai return; 29410cbc684SAmir Vadai 29510cbc684SAmir Vadai offload.command = TC_CLSFLOWER_STATS; 29669ca05ceSJiri Pirko offload.prio = tp->prio; 29710cbc684SAmir Vadai offload.cookie = (unsigned long)f; 29810cbc684SAmir Vadai offload.exts = &f->exts; 29910cbc684SAmir Vadai 3007091d8c7SHadar Hen Zion tc->type = TC_SETUP_CLSFLOWER; 3017091d8c7SHadar Hen Zion tc->cls_flower = &offload; 30210cbc684SAmir Vadai 3037091d8c7SHadar Hen Zion dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol, tc); 30410cbc684SAmir Vadai } 30510cbc684SAmir Vadai 30613fa876eSRoi Dayan static void __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f) 30713fa876eSRoi Dayan { 30813fa876eSRoi Dayan list_del_rcu(&f->list); 30979685219SHadar Hen Zion if (!tc_skip_hw(f->flags)) 3103036dab6SHadar Hen Zion fl_hw_destroy_filter(tp, f); 31113fa876eSRoi Dayan tcf_unbind_filter(tp, &f->res); 31213fa876eSRoi Dayan call_rcu(&f->rcu, fl_destroy_filter); 31313fa876eSRoi Dayan } 31413fa876eSRoi Dayan 315d9363774SDaniel Borkmann static void fl_destroy_sleepable(struct work_struct *work) 316d9363774SDaniel Borkmann { 317d9363774SDaniel Borkmann struct cls_fl_head *head = container_of(work, struct cls_fl_head, 318d9363774SDaniel Borkmann work); 319d9363774SDaniel Borkmann if (head->mask_assigned) 320d9363774SDaniel Borkmann rhashtable_destroy(&head->ht); 321d9363774SDaniel Borkmann kfree(head); 322d9363774SDaniel Borkmann module_put(THIS_MODULE); 323d9363774SDaniel Borkmann } 324d9363774SDaniel Borkmann 325d9363774SDaniel Borkmann static void fl_destroy_rcu(struct rcu_head *rcu) 326d9363774SDaniel Borkmann { 327d9363774SDaniel Borkmann struct cls_fl_head *head = container_of(rcu, struct cls_fl_head, rcu); 328d9363774SDaniel Borkmann 329d9363774SDaniel Borkmann INIT_WORK(&head->work, fl_destroy_sleepable); 330d9363774SDaniel Borkmann schedule_work(&head->work); 331d9363774SDaniel Borkmann } 332d9363774SDaniel Borkmann 333763dbf63SWANG Cong static void fl_destroy(struct tcf_proto *tp) 33477b9900eSJiri Pirko { 33577b9900eSJiri Pirko struct cls_fl_head *head = rtnl_dereference(tp->root); 33677b9900eSJiri Pirko struct cls_fl_filter *f, *next; 33777b9900eSJiri Pirko 33813fa876eSRoi Dayan list_for_each_entry_safe(f, next, &head->filters, list) 33913fa876eSRoi Dayan __fl_delete(tp, f); 340d9363774SDaniel Borkmann 341d9363774SDaniel Borkmann __module_get(THIS_MODULE); 342d9363774SDaniel Borkmann call_rcu(&head->rcu, fl_destroy_rcu); 34377b9900eSJiri Pirko } 34477b9900eSJiri Pirko 34577b9900eSJiri Pirko static unsigned long fl_get(struct tcf_proto *tp, u32 handle) 34677b9900eSJiri Pirko { 34777b9900eSJiri Pirko struct cls_fl_head *head = rtnl_dereference(tp->root); 34877b9900eSJiri Pirko struct cls_fl_filter *f; 34977b9900eSJiri Pirko 35077b9900eSJiri Pirko list_for_each_entry(f, &head->filters, list) 35177b9900eSJiri Pirko if (f->handle == handle) 35277b9900eSJiri Pirko return (unsigned long) f; 35377b9900eSJiri Pirko return 0; 35477b9900eSJiri Pirko } 35577b9900eSJiri Pirko 35677b9900eSJiri Pirko static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = { 35777b9900eSJiri Pirko [TCA_FLOWER_UNSPEC] = { .type = NLA_UNSPEC }, 35877b9900eSJiri Pirko [TCA_FLOWER_CLASSID] = { .type = NLA_U32 }, 35977b9900eSJiri Pirko [TCA_FLOWER_INDEV] = { .type = NLA_STRING, 36077b9900eSJiri Pirko .len = IFNAMSIZ }, 36177b9900eSJiri Pirko [TCA_FLOWER_KEY_ETH_DST] = { .len = ETH_ALEN }, 36277b9900eSJiri Pirko [TCA_FLOWER_KEY_ETH_DST_MASK] = { .len = ETH_ALEN }, 36377b9900eSJiri Pirko [TCA_FLOWER_KEY_ETH_SRC] = { .len = ETH_ALEN }, 36477b9900eSJiri Pirko [TCA_FLOWER_KEY_ETH_SRC_MASK] = { .len = ETH_ALEN }, 36577b9900eSJiri Pirko [TCA_FLOWER_KEY_ETH_TYPE] = { .type = NLA_U16 }, 36677b9900eSJiri Pirko [TCA_FLOWER_KEY_IP_PROTO] = { .type = NLA_U8 }, 36777b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV4_SRC] = { .type = NLA_U32 }, 36877b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV4_SRC_MASK] = { .type = NLA_U32 }, 36977b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV4_DST] = { .type = NLA_U32 }, 37077b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV4_DST_MASK] = { .type = NLA_U32 }, 37177b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV6_SRC] = { .len = sizeof(struct in6_addr) }, 37277b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) }, 37377b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV6_DST] = { .len = sizeof(struct in6_addr) }, 37477b9900eSJiri Pirko [TCA_FLOWER_KEY_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) }, 37577b9900eSJiri Pirko [TCA_FLOWER_KEY_TCP_SRC] = { .type = NLA_U16 }, 37677b9900eSJiri Pirko [TCA_FLOWER_KEY_TCP_DST] = { .type = NLA_U16 }, 377b175c3a4SJamal Hadi Salim [TCA_FLOWER_KEY_UDP_SRC] = { .type = NLA_U16 }, 378b175c3a4SJamal Hadi Salim [TCA_FLOWER_KEY_UDP_DST] = { .type = NLA_U16 }, 3799399ae9aSHadar Hen Zion [TCA_FLOWER_KEY_VLAN_ID] = { .type = NLA_U16 }, 3809399ae9aSHadar Hen Zion [TCA_FLOWER_KEY_VLAN_PRIO] = { .type = NLA_U8 }, 3819399ae9aSHadar Hen Zion [TCA_FLOWER_KEY_VLAN_ETH_TYPE] = { .type = NLA_U16 }, 382bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_KEY_ID] = { .type = NLA_U32 }, 383bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV4_SRC] = { .type = NLA_U32 }, 384bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] = { .type = NLA_U32 }, 385bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV4_DST] = { .type = NLA_U32 }, 386bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] = { .type = NLA_U32 }, 387bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV6_SRC] = { .len = sizeof(struct in6_addr) }, 388bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) }, 389bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV6_DST] = { .len = sizeof(struct in6_addr) }, 390bc3103f1SAmir Vadai [TCA_FLOWER_KEY_ENC_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) }, 391aa72d708SOr Gerlitz [TCA_FLOWER_KEY_TCP_SRC_MASK] = { .type = NLA_U16 }, 392aa72d708SOr Gerlitz [TCA_FLOWER_KEY_TCP_DST_MASK] = { .type = NLA_U16 }, 393aa72d708SOr Gerlitz [TCA_FLOWER_KEY_UDP_SRC_MASK] = { .type = NLA_U16 }, 394aa72d708SOr Gerlitz [TCA_FLOWER_KEY_UDP_DST_MASK] = { .type = NLA_U16 }, 3955976c5f4SSimon Horman [TCA_FLOWER_KEY_SCTP_SRC_MASK] = { .type = NLA_U16 }, 3965976c5f4SSimon Horman [TCA_FLOWER_KEY_SCTP_DST_MASK] = { .type = NLA_U16 }, 3975976c5f4SSimon Horman [TCA_FLOWER_KEY_SCTP_SRC] = { .type = NLA_U16 }, 3985976c5f4SSimon Horman [TCA_FLOWER_KEY_SCTP_DST] = { .type = NLA_U16 }, 399f4d997fdSHadar Hen Zion [TCA_FLOWER_KEY_ENC_UDP_SRC_PORT] = { .type = NLA_U16 }, 400f4d997fdSHadar Hen Zion [TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK] = { .type = NLA_U16 }, 401f4d997fdSHadar Hen Zion [TCA_FLOWER_KEY_ENC_UDP_DST_PORT] = { .type = NLA_U16 }, 402f4d997fdSHadar Hen Zion [TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK] = { .type = NLA_U16 }, 403faa3ffceSOr Gerlitz [TCA_FLOWER_KEY_FLAGS] = { .type = NLA_U32 }, 404faa3ffceSOr Gerlitz [TCA_FLOWER_KEY_FLAGS_MASK] = { .type = NLA_U32 }, 4057b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV4_TYPE] = { .type = NLA_U8 }, 4067b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV4_TYPE_MASK] = { .type = NLA_U8 }, 4077b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV4_CODE] = { .type = NLA_U8 }, 4087b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV4_CODE_MASK] = { .type = NLA_U8 }, 4097b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV6_TYPE] = { .type = NLA_U8 }, 4107b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV6_TYPE_MASK] = { .type = NLA_U8 }, 4117b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV6_CODE] = { .type = NLA_U8 }, 4127b684884SSimon Horman [TCA_FLOWER_KEY_ICMPV6_CODE_MASK] = { .type = NLA_U8 }, 41399d31326SSimon Horman [TCA_FLOWER_KEY_ARP_SIP] = { .type = NLA_U32 }, 41499d31326SSimon Horman [TCA_FLOWER_KEY_ARP_SIP_MASK] = { .type = NLA_U32 }, 41599d31326SSimon Horman [TCA_FLOWER_KEY_ARP_TIP] = { .type = NLA_U32 }, 41699d31326SSimon Horman [TCA_FLOWER_KEY_ARP_TIP_MASK] = { .type = NLA_U32 }, 41799d31326SSimon Horman [TCA_FLOWER_KEY_ARP_OP] = { .type = NLA_U8 }, 41899d31326SSimon Horman [TCA_FLOWER_KEY_ARP_OP_MASK] = { .type = NLA_U8 }, 41999d31326SSimon Horman [TCA_FLOWER_KEY_ARP_SHA] = { .len = ETH_ALEN }, 42099d31326SSimon Horman [TCA_FLOWER_KEY_ARP_SHA_MASK] = { .len = ETH_ALEN }, 42199d31326SSimon Horman [TCA_FLOWER_KEY_ARP_THA] = { .len = ETH_ALEN }, 42299d31326SSimon Horman [TCA_FLOWER_KEY_ARP_THA_MASK] = { .len = ETH_ALEN }, 423*a577d8f7SBenjamin LaHaise [TCA_FLOWER_KEY_MPLS_TTL] = { .type = NLA_U8 }, 424*a577d8f7SBenjamin LaHaise [TCA_FLOWER_KEY_MPLS_BOS] = { .type = NLA_U8 }, 425*a577d8f7SBenjamin LaHaise [TCA_FLOWER_KEY_MPLS_TC] = { .type = NLA_U8 }, 426*a577d8f7SBenjamin LaHaise [TCA_FLOWER_KEY_MPLS_LABEL] = { .type = NLA_U32 }, 42777b9900eSJiri Pirko }; 42877b9900eSJiri Pirko 42977b9900eSJiri Pirko static void fl_set_key_val(struct nlattr **tb, 43077b9900eSJiri Pirko void *val, int val_type, 43177b9900eSJiri Pirko void *mask, int mask_type, int len) 43277b9900eSJiri Pirko { 43377b9900eSJiri Pirko if (!tb[val_type]) 43477b9900eSJiri Pirko return; 43577b9900eSJiri Pirko memcpy(val, nla_data(tb[val_type]), len); 43677b9900eSJiri Pirko if (mask_type == TCA_FLOWER_UNSPEC || !tb[mask_type]) 43777b9900eSJiri Pirko memset(mask, 0xff, len); 43877b9900eSJiri Pirko else 43977b9900eSJiri Pirko memcpy(mask, nla_data(tb[mask_type]), len); 44077b9900eSJiri Pirko } 44177b9900eSJiri Pirko 442*a577d8f7SBenjamin LaHaise static void fl_set_key_mpls(struct nlattr **tb, 443*a577d8f7SBenjamin LaHaise struct flow_dissector_key_mpls *key_val, 444*a577d8f7SBenjamin LaHaise struct flow_dissector_key_mpls *key_mask) 445*a577d8f7SBenjamin LaHaise { 446*a577d8f7SBenjamin LaHaise if (tb[TCA_FLOWER_KEY_MPLS_TTL]) { 447*a577d8f7SBenjamin LaHaise key_val->mpls_ttl = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TTL]); 448*a577d8f7SBenjamin LaHaise key_mask->mpls_ttl = MPLS_TTL_MASK; 449*a577d8f7SBenjamin LaHaise } 450*a577d8f7SBenjamin LaHaise if (tb[TCA_FLOWER_KEY_MPLS_BOS]) { 451*a577d8f7SBenjamin LaHaise key_val->mpls_bos = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_BOS]); 452*a577d8f7SBenjamin LaHaise key_mask->mpls_bos = MPLS_BOS_MASK; 453*a577d8f7SBenjamin LaHaise } 454*a577d8f7SBenjamin LaHaise if (tb[TCA_FLOWER_KEY_MPLS_TC]) { 455*a577d8f7SBenjamin LaHaise key_val->mpls_tc = 456*a577d8f7SBenjamin LaHaise nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TC]) & MPLS_TC_MASK; 457*a577d8f7SBenjamin LaHaise key_mask->mpls_tc = MPLS_TC_MASK; 458*a577d8f7SBenjamin LaHaise } 459*a577d8f7SBenjamin LaHaise if (tb[TCA_FLOWER_KEY_MPLS_LABEL]) { 460*a577d8f7SBenjamin LaHaise key_val->mpls_label = 461*a577d8f7SBenjamin LaHaise nla_get_u32(tb[TCA_FLOWER_KEY_MPLS_LABEL]) & 462*a577d8f7SBenjamin LaHaise MPLS_LABEL_MASK; 463*a577d8f7SBenjamin LaHaise key_mask->mpls_label = MPLS_LABEL_MASK; 464*a577d8f7SBenjamin LaHaise } 465*a577d8f7SBenjamin LaHaise } 466*a577d8f7SBenjamin 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 51877b9900eSJiri Pirko static int fl_set_key(struct net *net, struct nlattr **tb, 51977b9900eSJiri Pirko struct fl_flow_key *key, struct fl_flow_key *mask) 52077b9900eSJiri Pirko { 5219399ae9aSHadar Hen Zion __be16 ethertype; 522d9724772SOr Gerlitz int ret = 0; 523dd3aa3b5SBrian Haley #ifdef CONFIG_NET_CLS_IND 52477b9900eSJiri Pirko if (tb[TCA_FLOWER_INDEV]) { 525dd3aa3b5SBrian Haley int err = tcf_change_indev(net, tb[TCA_FLOWER_INDEV]); 52677b9900eSJiri Pirko if (err < 0) 52777b9900eSJiri Pirko return err; 52877b9900eSJiri Pirko key->indev_ifindex = err; 52977b9900eSJiri Pirko mask->indev_ifindex = 0xffffffff; 53077b9900eSJiri Pirko } 531dd3aa3b5SBrian Haley #endif 53277b9900eSJiri Pirko 53377b9900eSJiri Pirko fl_set_key_val(tb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST, 53477b9900eSJiri Pirko mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK, 53577b9900eSJiri Pirko sizeof(key->eth.dst)); 53677b9900eSJiri Pirko fl_set_key_val(tb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC, 53777b9900eSJiri Pirko mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK, 53877b9900eSJiri Pirko sizeof(key->eth.src)); 53966530bdfSJamal Hadi Salim 5400b498a52SArnd Bergmann if (tb[TCA_FLOWER_KEY_ETH_TYPE]) { 5419399ae9aSHadar Hen Zion ethertype = nla_get_be16(tb[TCA_FLOWER_KEY_ETH_TYPE]); 5429399ae9aSHadar Hen Zion 5439399ae9aSHadar Hen Zion if (ethertype == htons(ETH_P_8021Q)) { 5449399ae9aSHadar Hen Zion fl_set_key_vlan(tb, &key->vlan, &mask->vlan); 5459399ae9aSHadar Hen Zion fl_set_key_val(tb, &key->basic.n_proto, 5469399ae9aSHadar Hen Zion TCA_FLOWER_KEY_VLAN_ETH_TYPE, 54777b9900eSJiri Pirko &mask->basic.n_proto, TCA_FLOWER_UNSPEC, 54877b9900eSJiri Pirko sizeof(key->basic.n_proto)); 5499399ae9aSHadar Hen Zion } else { 5509399ae9aSHadar Hen Zion key->basic.n_proto = ethertype; 5519399ae9aSHadar Hen Zion mask->basic.n_proto = cpu_to_be16(~0); 5529399ae9aSHadar Hen Zion } 5530b498a52SArnd Bergmann } 55466530bdfSJamal Hadi Salim 55577b9900eSJiri Pirko if (key->basic.n_proto == htons(ETH_P_IP) || 55677b9900eSJiri Pirko key->basic.n_proto == htons(ETH_P_IPV6)) { 55777b9900eSJiri Pirko fl_set_key_val(tb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO, 55877b9900eSJiri Pirko &mask->basic.ip_proto, TCA_FLOWER_UNSPEC, 55977b9900eSJiri Pirko sizeof(key->basic.ip_proto)); 56077b9900eSJiri Pirko } 56166530bdfSJamal Hadi Salim 56266530bdfSJamal Hadi Salim if (tb[TCA_FLOWER_KEY_IPV4_SRC] || tb[TCA_FLOWER_KEY_IPV4_DST]) { 56366530bdfSJamal Hadi Salim key->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; 564970bfcd0SPaul Blakey mask->control.addr_type = ~0; 56577b9900eSJiri Pirko fl_set_key_val(tb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC, 56677b9900eSJiri Pirko &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK, 56777b9900eSJiri Pirko sizeof(key->ipv4.src)); 56877b9900eSJiri Pirko fl_set_key_val(tb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST, 56977b9900eSJiri Pirko &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK, 57077b9900eSJiri Pirko sizeof(key->ipv4.dst)); 57166530bdfSJamal Hadi Salim } else if (tb[TCA_FLOWER_KEY_IPV6_SRC] || tb[TCA_FLOWER_KEY_IPV6_DST]) { 57266530bdfSJamal Hadi Salim key->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; 573970bfcd0SPaul Blakey mask->control.addr_type = ~0; 57477b9900eSJiri Pirko fl_set_key_val(tb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC, 57577b9900eSJiri Pirko &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK, 57677b9900eSJiri Pirko sizeof(key->ipv6.src)); 57777b9900eSJiri Pirko fl_set_key_val(tb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST, 57877b9900eSJiri Pirko &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK, 57977b9900eSJiri Pirko sizeof(key->ipv6.dst)); 58077b9900eSJiri Pirko } 58166530bdfSJamal Hadi Salim 58277b9900eSJiri Pirko if (key->basic.ip_proto == IPPROTO_TCP) { 58377b9900eSJiri Pirko fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC, 584aa72d708SOr Gerlitz &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK, 58577b9900eSJiri Pirko sizeof(key->tp.src)); 58677b9900eSJiri Pirko fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST, 587aa72d708SOr Gerlitz &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK, 58877b9900eSJiri Pirko sizeof(key->tp.dst)); 58977b9900eSJiri Pirko } else if (key->basic.ip_proto == IPPROTO_UDP) { 59077b9900eSJiri Pirko fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC, 591aa72d708SOr Gerlitz &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK, 59277b9900eSJiri Pirko sizeof(key->tp.src)); 59377b9900eSJiri Pirko fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST, 594aa72d708SOr Gerlitz &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK, 59577b9900eSJiri Pirko sizeof(key->tp.dst)); 5965976c5f4SSimon Horman } else if (key->basic.ip_proto == IPPROTO_SCTP) { 5975976c5f4SSimon Horman fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC, 5985976c5f4SSimon Horman &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK, 5995976c5f4SSimon Horman sizeof(key->tp.src)); 6005976c5f4SSimon Horman fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST, 6015976c5f4SSimon Horman &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK, 6025976c5f4SSimon Horman sizeof(key->tp.dst)); 6037b684884SSimon Horman } else if (key->basic.n_proto == htons(ETH_P_IP) && 6047b684884SSimon Horman key->basic.ip_proto == IPPROTO_ICMP) { 6057b684884SSimon Horman fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV4_TYPE, 6067b684884SSimon Horman &mask->icmp.type, 6077b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_TYPE_MASK, 6087b684884SSimon Horman sizeof(key->icmp.type)); 6097b684884SSimon Horman fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV4_CODE, 6107b684884SSimon Horman &mask->icmp.code, 6117b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_CODE_MASK, 6127b684884SSimon Horman sizeof(key->icmp.code)); 6137b684884SSimon Horman } else if (key->basic.n_proto == htons(ETH_P_IPV6) && 6147b684884SSimon Horman key->basic.ip_proto == IPPROTO_ICMPV6) { 6157b684884SSimon Horman fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV6_TYPE, 6167b684884SSimon Horman &mask->icmp.type, 6177b684884SSimon Horman TCA_FLOWER_KEY_ICMPV6_TYPE_MASK, 6187b684884SSimon Horman sizeof(key->icmp.type)); 619040587afSSimon Horman fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV6_CODE, 6207b684884SSimon Horman &mask->icmp.code, 621040587afSSimon Horman TCA_FLOWER_KEY_ICMPV6_CODE_MASK, 6227b684884SSimon Horman sizeof(key->icmp.code)); 623*a577d8f7SBenjamin LaHaise } else if (key->basic.n_proto == htons(ETH_P_MPLS_UC) || 624*a577d8f7SBenjamin LaHaise key->basic.n_proto == htons(ETH_P_MPLS_MC)) { 625*a577d8f7SBenjamin LaHaise fl_set_key_mpls(tb, &key->mpls, &mask->mpls); 62699d31326SSimon Horman } else if (key->basic.n_proto == htons(ETH_P_ARP) || 62799d31326SSimon Horman key->basic.n_proto == htons(ETH_P_RARP)) { 62899d31326SSimon Horman fl_set_key_val(tb, &key->arp.sip, TCA_FLOWER_KEY_ARP_SIP, 62999d31326SSimon Horman &mask->arp.sip, TCA_FLOWER_KEY_ARP_SIP_MASK, 63099d31326SSimon Horman sizeof(key->arp.sip)); 63199d31326SSimon Horman fl_set_key_val(tb, &key->arp.tip, TCA_FLOWER_KEY_ARP_TIP, 63299d31326SSimon Horman &mask->arp.tip, TCA_FLOWER_KEY_ARP_TIP_MASK, 63399d31326SSimon Horman sizeof(key->arp.tip)); 63499d31326SSimon Horman fl_set_key_val(tb, &key->arp.op, TCA_FLOWER_KEY_ARP_OP, 63599d31326SSimon Horman &mask->arp.op, TCA_FLOWER_KEY_ARP_OP_MASK, 63699d31326SSimon Horman sizeof(key->arp.op)); 63799d31326SSimon Horman fl_set_key_val(tb, key->arp.sha, TCA_FLOWER_KEY_ARP_SHA, 63899d31326SSimon Horman mask->arp.sha, TCA_FLOWER_KEY_ARP_SHA_MASK, 63999d31326SSimon Horman sizeof(key->arp.sha)); 64099d31326SSimon Horman fl_set_key_val(tb, key->arp.tha, TCA_FLOWER_KEY_ARP_THA, 64199d31326SSimon Horman mask->arp.tha, TCA_FLOWER_KEY_ARP_THA_MASK, 64299d31326SSimon Horman sizeof(key->arp.tha)); 64377b9900eSJiri Pirko } 64477b9900eSJiri Pirko 645bc3103f1SAmir Vadai if (tb[TCA_FLOWER_KEY_ENC_IPV4_SRC] || 646bc3103f1SAmir Vadai tb[TCA_FLOWER_KEY_ENC_IPV4_DST]) { 647bc3103f1SAmir Vadai key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; 648970bfcd0SPaul Blakey mask->enc_control.addr_type = ~0; 649bc3103f1SAmir Vadai fl_set_key_val(tb, &key->enc_ipv4.src, 650bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_SRC, 651bc3103f1SAmir Vadai &mask->enc_ipv4.src, 652bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK, 653bc3103f1SAmir Vadai sizeof(key->enc_ipv4.src)); 654bc3103f1SAmir Vadai fl_set_key_val(tb, &key->enc_ipv4.dst, 655bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_DST, 656bc3103f1SAmir Vadai &mask->enc_ipv4.dst, 657bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_DST_MASK, 658bc3103f1SAmir Vadai sizeof(key->enc_ipv4.dst)); 659bc3103f1SAmir Vadai } 660bc3103f1SAmir Vadai 661bc3103f1SAmir Vadai if (tb[TCA_FLOWER_KEY_ENC_IPV6_SRC] || 662bc3103f1SAmir Vadai tb[TCA_FLOWER_KEY_ENC_IPV6_DST]) { 663bc3103f1SAmir Vadai key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; 664970bfcd0SPaul Blakey mask->enc_control.addr_type = ~0; 665bc3103f1SAmir Vadai fl_set_key_val(tb, &key->enc_ipv6.src, 666bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_SRC, 667bc3103f1SAmir Vadai &mask->enc_ipv6.src, 668bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK, 669bc3103f1SAmir Vadai sizeof(key->enc_ipv6.src)); 670bc3103f1SAmir Vadai fl_set_key_val(tb, &key->enc_ipv6.dst, 671bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_DST, 672bc3103f1SAmir Vadai &mask->enc_ipv6.dst, 673bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_DST_MASK, 674bc3103f1SAmir Vadai sizeof(key->enc_ipv6.dst)); 675bc3103f1SAmir Vadai } 676bc3103f1SAmir Vadai 677bc3103f1SAmir Vadai fl_set_key_val(tb, &key->enc_key_id.keyid, TCA_FLOWER_KEY_ENC_KEY_ID, 678eb523f42SHadar Hen Zion &mask->enc_key_id.keyid, TCA_FLOWER_UNSPEC, 679bc3103f1SAmir Vadai sizeof(key->enc_key_id.keyid)); 680bc3103f1SAmir Vadai 681f4d997fdSHadar Hen Zion fl_set_key_val(tb, &key->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT, 682f4d997fdSHadar Hen Zion &mask->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK, 683f4d997fdSHadar Hen Zion sizeof(key->enc_tp.src)); 684f4d997fdSHadar Hen Zion 685f4d997fdSHadar Hen Zion fl_set_key_val(tb, &key->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT, 686f4d997fdSHadar Hen Zion &mask->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK, 687f4d997fdSHadar Hen Zion sizeof(key->enc_tp.dst)); 688f4d997fdSHadar Hen Zion 689d9724772SOr Gerlitz if (tb[TCA_FLOWER_KEY_FLAGS]) 690d9724772SOr Gerlitz ret = fl_set_key_flags(tb, &key->control.flags, &mask->control.flags); 691faa3ffceSOr Gerlitz 692d9724772SOr Gerlitz return ret; 69377b9900eSJiri Pirko } 69477b9900eSJiri Pirko 69577b9900eSJiri Pirko static bool fl_mask_eq(struct fl_flow_mask *mask1, 69677b9900eSJiri Pirko struct fl_flow_mask *mask2) 69777b9900eSJiri Pirko { 69877b9900eSJiri Pirko const long *lmask1 = fl_key_get_start(&mask1->key, mask1); 69977b9900eSJiri Pirko const long *lmask2 = fl_key_get_start(&mask2->key, mask2); 70077b9900eSJiri Pirko 70177b9900eSJiri Pirko return !memcmp(&mask1->range, &mask2->range, sizeof(mask1->range)) && 70277b9900eSJiri Pirko !memcmp(lmask1, lmask2, fl_mask_range(mask1)); 70377b9900eSJiri Pirko } 70477b9900eSJiri Pirko 70577b9900eSJiri Pirko static const struct rhashtable_params fl_ht_params = { 70677b9900eSJiri Pirko .key_offset = offsetof(struct cls_fl_filter, mkey), /* base offset */ 70777b9900eSJiri Pirko .head_offset = offsetof(struct cls_fl_filter, ht_node), 70877b9900eSJiri Pirko .automatic_shrinking = true, 70977b9900eSJiri Pirko }; 71077b9900eSJiri Pirko 71177b9900eSJiri Pirko static int fl_init_hashtable(struct cls_fl_head *head, 71277b9900eSJiri Pirko struct fl_flow_mask *mask) 71377b9900eSJiri Pirko { 71477b9900eSJiri Pirko head->ht_params = fl_ht_params; 71577b9900eSJiri Pirko head->ht_params.key_len = fl_mask_range(mask); 71677b9900eSJiri Pirko head->ht_params.key_offset += mask->range.start; 71777b9900eSJiri Pirko 71877b9900eSJiri Pirko return rhashtable_init(&head->ht, &head->ht_params); 71977b9900eSJiri Pirko } 72077b9900eSJiri Pirko 72177b9900eSJiri Pirko #define FL_KEY_MEMBER_OFFSET(member) offsetof(struct fl_flow_key, member) 72277b9900eSJiri Pirko #define FL_KEY_MEMBER_SIZE(member) (sizeof(((struct fl_flow_key *) 0)->member)) 72377b9900eSJiri Pirko 724339ba878SHadar Hen Zion #define FL_KEY_IS_MASKED(mask, member) \ 725339ba878SHadar Hen Zion memchr_inv(((char *)mask) + FL_KEY_MEMBER_OFFSET(member), \ 726339ba878SHadar Hen Zion 0, FL_KEY_MEMBER_SIZE(member)) \ 72777b9900eSJiri Pirko 72877b9900eSJiri Pirko #define FL_KEY_SET(keys, cnt, id, member) \ 72977b9900eSJiri Pirko do { \ 73077b9900eSJiri Pirko keys[cnt].key_id = id; \ 73177b9900eSJiri Pirko keys[cnt].offset = FL_KEY_MEMBER_OFFSET(member); \ 73277b9900eSJiri Pirko cnt++; \ 73377b9900eSJiri Pirko } while(0); 73477b9900eSJiri Pirko 735339ba878SHadar Hen Zion #define FL_KEY_SET_IF_MASKED(mask, keys, cnt, id, member) \ 73677b9900eSJiri Pirko do { \ 737339ba878SHadar Hen Zion if (FL_KEY_IS_MASKED(mask, member)) \ 73877b9900eSJiri Pirko FL_KEY_SET(keys, cnt, id, member); \ 73977b9900eSJiri Pirko } while(0); 74077b9900eSJiri Pirko 74177b9900eSJiri Pirko static void fl_init_dissector(struct cls_fl_head *head, 74277b9900eSJiri Pirko struct fl_flow_mask *mask) 74377b9900eSJiri Pirko { 74477b9900eSJiri Pirko struct flow_dissector_key keys[FLOW_DISSECTOR_KEY_MAX]; 74577b9900eSJiri Pirko size_t cnt = 0; 74677b9900eSJiri Pirko 74742aecaa9STom Herbert FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_CONTROL, control); 74877b9900eSJiri Pirko FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_BASIC, basic); 749339ba878SHadar Hen Zion FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 75077b9900eSJiri Pirko FLOW_DISSECTOR_KEY_ETH_ADDRS, eth); 751339ba878SHadar Hen Zion FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 75277b9900eSJiri Pirko FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4); 753339ba878SHadar Hen Zion FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 75477b9900eSJiri Pirko FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6); 755339ba878SHadar Hen Zion FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 75677b9900eSJiri Pirko FLOW_DISSECTOR_KEY_PORTS, tp); 7579399ae9aSHadar Hen Zion FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 7587b684884SSimon Horman FLOW_DISSECTOR_KEY_ICMP, icmp); 7597b684884SSimon Horman FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 76099d31326SSimon Horman FLOW_DISSECTOR_KEY_ARP, arp); 76199d31326SSimon Horman FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 762*a577d8f7SBenjamin LaHaise FLOW_DISSECTOR_KEY_MPLS, mpls); 763*a577d8f7SBenjamin LaHaise FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 7649399ae9aSHadar Hen Zion FLOW_DISSECTOR_KEY_VLAN, vlan); 765519d1052SHadar Hen Zion FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 766519d1052SHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_KEYID, enc_key_id); 767519d1052SHadar Hen Zion FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 768519d1052SHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, enc_ipv4); 769519d1052SHadar Hen Zion FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 770519d1052SHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, enc_ipv6); 771519d1052SHadar Hen Zion if (FL_KEY_IS_MASKED(&mask->key, enc_ipv4) || 772519d1052SHadar Hen Zion FL_KEY_IS_MASKED(&mask->key, enc_ipv6)) 773519d1052SHadar Hen Zion FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_ENC_CONTROL, 774519d1052SHadar Hen Zion enc_control); 775f4d997fdSHadar Hen Zion FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt, 776f4d997fdSHadar Hen Zion FLOW_DISSECTOR_KEY_ENC_PORTS, enc_tp); 77777b9900eSJiri Pirko 77877b9900eSJiri Pirko skb_flow_dissector_init(&head->dissector, keys, cnt); 77977b9900eSJiri Pirko } 78077b9900eSJiri Pirko 78177b9900eSJiri Pirko static int fl_check_assign_mask(struct cls_fl_head *head, 78277b9900eSJiri Pirko struct fl_flow_mask *mask) 78377b9900eSJiri Pirko { 78477b9900eSJiri Pirko int err; 78577b9900eSJiri Pirko 78677b9900eSJiri Pirko if (head->mask_assigned) { 78777b9900eSJiri Pirko if (!fl_mask_eq(&head->mask, mask)) 78877b9900eSJiri Pirko return -EINVAL; 78977b9900eSJiri Pirko else 79077b9900eSJiri Pirko return 0; 79177b9900eSJiri Pirko } 79277b9900eSJiri Pirko 79377b9900eSJiri Pirko /* Mask is not assigned yet. So assign it and init hashtable 79477b9900eSJiri Pirko * according to that. 79577b9900eSJiri Pirko */ 79677b9900eSJiri Pirko err = fl_init_hashtable(head, mask); 79777b9900eSJiri Pirko if (err) 79877b9900eSJiri Pirko return err; 79977b9900eSJiri Pirko memcpy(&head->mask, mask, sizeof(head->mask)); 80077b9900eSJiri Pirko head->mask_assigned = true; 80177b9900eSJiri Pirko 80277b9900eSJiri Pirko fl_init_dissector(head, mask); 80377b9900eSJiri Pirko 80477b9900eSJiri Pirko return 0; 80577b9900eSJiri Pirko } 80677b9900eSJiri Pirko 80777b9900eSJiri Pirko static int fl_set_parms(struct net *net, struct tcf_proto *tp, 80877b9900eSJiri Pirko struct cls_fl_filter *f, struct fl_flow_mask *mask, 80977b9900eSJiri Pirko unsigned long base, struct nlattr **tb, 81077b9900eSJiri Pirko struct nlattr *est, bool ovr) 81177b9900eSJiri Pirko { 81277b9900eSJiri Pirko struct tcf_exts e; 81377b9900eSJiri Pirko int err; 81477b9900eSJiri Pirko 815b9a24bb7SWANG Cong err = tcf_exts_init(&e, TCA_FLOWER_ACT, 0); 81677b9900eSJiri Pirko if (err < 0) 81777b9900eSJiri Pirko return err; 818b9a24bb7SWANG Cong err = tcf_exts_validate(net, tp, tb, est, &e, ovr); 819b9a24bb7SWANG Cong if (err < 0) 820b9a24bb7SWANG Cong goto errout; 82177b9900eSJiri Pirko 82277b9900eSJiri Pirko if (tb[TCA_FLOWER_CLASSID]) { 82377b9900eSJiri Pirko f->res.classid = nla_get_u32(tb[TCA_FLOWER_CLASSID]); 82477b9900eSJiri Pirko tcf_bind_filter(tp, &f->res, base); 82577b9900eSJiri Pirko } 82677b9900eSJiri Pirko 82777b9900eSJiri Pirko err = fl_set_key(net, tb, &f->key, &mask->key); 82877b9900eSJiri Pirko if (err) 82977b9900eSJiri Pirko goto errout; 83077b9900eSJiri Pirko 83177b9900eSJiri Pirko fl_mask_update_range(mask); 83277b9900eSJiri Pirko fl_set_masked_key(&f->mkey, &f->key, mask); 83377b9900eSJiri Pirko 83477b9900eSJiri Pirko tcf_exts_change(tp, &f->exts, &e); 83577b9900eSJiri Pirko 83677b9900eSJiri Pirko return 0; 83777b9900eSJiri Pirko errout: 83877b9900eSJiri Pirko tcf_exts_destroy(&e); 83977b9900eSJiri Pirko return err; 84077b9900eSJiri Pirko } 84177b9900eSJiri Pirko 84277b9900eSJiri Pirko static u32 fl_grab_new_handle(struct tcf_proto *tp, 84377b9900eSJiri Pirko struct cls_fl_head *head) 84477b9900eSJiri Pirko { 84577b9900eSJiri Pirko unsigned int i = 0x80000000; 84677b9900eSJiri Pirko u32 handle; 84777b9900eSJiri Pirko 84877b9900eSJiri Pirko do { 84977b9900eSJiri Pirko if (++head->hgen == 0x7FFFFFFF) 85077b9900eSJiri Pirko head->hgen = 1; 85177b9900eSJiri Pirko } while (--i > 0 && fl_get(tp, head->hgen)); 85277b9900eSJiri Pirko 85377b9900eSJiri Pirko if (unlikely(i == 0)) { 85477b9900eSJiri Pirko pr_err("Insufficient number of handles\n"); 85577b9900eSJiri Pirko handle = 0; 85677b9900eSJiri Pirko } else { 85777b9900eSJiri Pirko handle = head->hgen; 85877b9900eSJiri Pirko } 85977b9900eSJiri Pirko 86077b9900eSJiri Pirko return handle; 86177b9900eSJiri Pirko } 86277b9900eSJiri Pirko 86377b9900eSJiri Pirko static int fl_change(struct net *net, struct sk_buff *in_skb, 86477b9900eSJiri Pirko struct tcf_proto *tp, unsigned long base, 86577b9900eSJiri Pirko u32 handle, struct nlattr **tca, 86677b9900eSJiri Pirko unsigned long *arg, bool ovr) 86777b9900eSJiri Pirko { 86877b9900eSJiri Pirko struct cls_fl_head *head = rtnl_dereference(tp->root); 86977b9900eSJiri Pirko struct cls_fl_filter *fold = (struct cls_fl_filter *) *arg; 87077b9900eSJiri Pirko struct cls_fl_filter *fnew; 87139b7b6a6SArnd Bergmann struct nlattr **tb; 87277b9900eSJiri Pirko struct fl_flow_mask mask = {}; 87377b9900eSJiri Pirko int err; 87477b9900eSJiri Pirko 87577b9900eSJiri Pirko if (!tca[TCA_OPTIONS]) 87677b9900eSJiri Pirko return -EINVAL; 87777b9900eSJiri Pirko 87839b7b6a6SArnd Bergmann tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL); 87939b7b6a6SArnd Bergmann if (!tb) 88039b7b6a6SArnd Bergmann return -ENOBUFS; 88139b7b6a6SArnd Bergmann 882fceb6435SJohannes Berg err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS], 883fceb6435SJohannes Berg fl_policy, NULL); 88477b9900eSJiri Pirko if (err < 0) 88539b7b6a6SArnd Bergmann goto errout_tb; 88677b9900eSJiri Pirko 88739b7b6a6SArnd Bergmann if (fold && handle && fold->handle != handle) { 88839b7b6a6SArnd Bergmann err = -EINVAL; 88939b7b6a6SArnd Bergmann goto errout_tb; 89039b7b6a6SArnd Bergmann } 89177b9900eSJiri Pirko 89277b9900eSJiri Pirko fnew = kzalloc(sizeof(*fnew), GFP_KERNEL); 89339b7b6a6SArnd Bergmann if (!fnew) { 89439b7b6a6SArnd Bergmann err = -ENOBUFS; 89539b7b6a6SArnd Bergmann goto errout_tb; 89639b7b6a6SArnd Bergmann } 89777b9900eSJiri Pirko 898b9a24bb7SWANG Cong err = tcf_exts_init(&fnew->exts, TCA_FLOWER_ACT, 0); 899b9a24bb7SWANG Cong if (err < 0) 900b9a24bb7SWANG Cong goto errout; 90177b9900eSJiri Pirko 90277b9900eSJiri Pirko if (!handle) { 90377b9900eSJiri Pirko handle = fl_grab_new_handle(tp, head); 90477b9900eSJiri Pirko if (!handle) { 90577b9900eSJiri Pirko err = -EINVAL; 90677b9900eSJiri Pirko goto errout; 90777b9900eSJiri Pirko } 90877b9900eSJiri Pirko } 90977b9900eSJiri Pirko fnew->handle = handle; 91077b9900eSJiri Pirko 911e69985c6SAmir Vadai if (tb[TCA_FLOWER_FLAGS]) { 912e69985c6SAmir Vadai fnew->flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]); 913e69985c6SAmir Vadai 914e69985c6SAmir Vadai if (!tc_flags_valid(fnew->flags)) { 915e69985c6SAmir Vadai err = -EINVAL; 916e69985c6SAmir Vadai goto errout; 917e69985c6SAmir Vadai } 918e69985c6SAmir Vadai } 9195b33f488SAmir Vadai 92077b9900eSJiri Pirko err = fl_set_parms(net, tp, fnew, &mask, base, tb, tca[TCA_RATE], ovr); 92177b9900eSJiri Pirko if (err) 92277b9900eSJiri Pirko goto errout; 92377b9900eSJiri Pirko 92477b9900eSJiri Pirko err = fl_check_assign_mask(head, &mask); 92577b9900eSJiri Pirko if (err) 92677b9900eSJiri Pirko goto errout; 92777b9900eSJiri Pirko 928e8eb36cdSAmir Vadai if (!tc_skip_sw(fnew->flags)) { 929a3308d8fSPaul Blakey if (!fold && fl_lookup(head, &fnew->mkey)) { 930a3308d8fSPaul Blakey err = -EEXIST; 931a3308d8fSPaul Blakey goto errout; 932a3308d8fSPaul Blakey } 933a3308d8fSPaul Blakey 93477b9900eSJiri Pirko err = rhashtable_insert_fast(&head->ht, &fnew->ht_node, 93577b9900eSJiri Pirko head->ht_params); 93677b9900eSJiri Pirko if (err) 93777b9900eSJiri Pirko goto errout; 938e69985c6SAmir Vadai } 9395b33f488SAmir Vadai 94079685219SHadar Hen Zion if (!tc_skip_hw(fnew->flags)) { 941e8eb36cdSAmir Vadai err = fl_hw_replace_filter(tp, 9425b33f488SAmir Vadai &head->dissector, 9435b33f488SAmir Vadai &mask.key, 9443036dab6SHadar Hen Zion fnew); 945e8eb36cdSAmir Vadai if (err) 946e8eb36cdSAmir Vadai goto errout; 94779685219SHadar Hen Zion } 9485b33f488SAmir Vadai 94955593960SOr Gerlitz if (!tc_in_hw(fnew->flags)) 95055593960SOr Gerlitz fnew->flags |= TCA_CLS_FLAGS_NOT_IN_HW; 95155593960SOr Gerlitz 9525b33f488SAmir Vadai if (fold) { 953725cbb62SJiri Pirko if (!tc_skip_sw(fold->flags)) 95477b9900eSJiri Pirko rhashtable_remove_fast(&head->ht, &fold->ht_node, 95577b9900eSJiri Pirko head->ht_params); 95679685219SHadar Hen Zion if (!tc_skip_hw(fold->flags)) 9573036dab6SHadar Hen Zion fl_hw_destroy_filter(tp, fold); 9585b33f488SAmir Vadai } 95977b9900eSJiri Pirko 96077b9900eSJiri Pirko *arg = (unsigned long) fnew; 96177b9900eSJiri Pirko 96277b9900eSJiri Pirko if (fold) { 963ff3532f2SDaniel Borkmann list_replace_rcu(&fold->list, &fnew->list); 96477b9900eSJiri Pirko tcf_unbind_filter(tp, &fold->res); 96577b9900eSJiri Pirko call_rcu(&fold->rcu, fl_destroy_filter); 96677b9900eSJiri Pirko } else { 96777b9900eSJiri Pirko list_add_tail_rcu(&fnew->list, &head->filters); 96877b9900eSJiri Pirko } 96977b9900eSJiri Pirko 97039b7b6a6SArnd Bergmann kfree(tb); 97177b9900eSJiri Pirko return 0; 97277b9900eSJiri Pirko 97377b9900eSJiri Pirko errout: 974b9a24bb7SWANG Cong tcf_exts_destroy(&fnew->exts); 97577b9900eSJiri Pirko kfree(fnew); 97639b7b6a6SArnd Bergmann errout_tb: 97739b7b6a6SArnd Bergmann kfree(tb); 97877b9900eSJiri Pirko return err; 97977b9900eSJiri Pirko } 98077b9900eSJiri Pirko 981763dbf63SWANG Cong static int fl_delete(struct tcf_proto *tp, unsigned long arg, bool *last) 98277b9900eSJiri Pirko { 98377b9900eSJiri Pirko struct cls_fl_head *head = rtnl_dereference(tp->root); 98477b9900eSJiri Pirko struct cls_fl_filter *f = (struct cls_fl_filter *) arg; 98577b9900eSJiri Pirko 986725cbb62SJiri Pirko if (!tc_skip_sw(f->flags)) 98777b9900eSJiri Pirko rhashtable_remove_fast(&head->ht, &f->ht_node, 98877b9900eSJiri Pirko head->ht_params); 98913fa876eSRoi Dayan __fl_delete(tp, f); 990763dbf63SWANG Cong *last = list_empty(&head->filters); 99177b9900eSJiri Pirko return 0; 99277b9900eSJiri Pirko } 99377b9900eSJiri Pirko 99477b9900eSJiri Pirko static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg) 99577b9900eSJiri Pirko { 99677b9900eSJiri Pirko struct cls_fl_head *head = rtnl_dereference(tp->root); 99777b9900eSJiri Pirko struct cls_fl_filter *f; 99877b9900eSJiri Pirko 99977b9900eSJiri Pirko list_for_each_entry_rcu(f, &head->filters, list) { 100077b9900eSJiri Pirko if (arg->count < arg->skip) 100177b9900eSJiri Pirko goto skip; 100277b9900eSJiri Pirko if (arg->fn(tp, (unsigned long) f, arg) < 0) { 100377b9900eSJiri Pirko arg->stop = 1; 100477b9900eSJiri Pirko break; 100577b9900eSJiri Pirko } 100677b9900eSJiri Pirko skip: 100777b9900eSJiri Pirko arg->count++; 100877b9900eSJiri Pirko } 100977b9900eSJiri Pirko } 101077b9900eSJiri Pirko 101177b9900eSJiri Pirko static int fl_dump_key_val(struct sk_buff *skb, 101277b9900eSJiri Pirko void *val, int val_type, 101377b9900eSJiri Pirko void *mask, int mask_type, int len) 101477b9900eSJiri Pirko { 101577b9900eSJiri Pirko int err; 101677b9900eSJiri Pirko 101777b9900eSJiri Pirko if (!memchr_inv(mask, 0, len)) 101877b9900eSJiri Pirko return 0; 101977b9900eSJiri Pirko err = nla_put(skb, val_type, len, val); 102077b9900eSJiri Pirko if (err) 102177b9900eSJiri Pirko return err; 102277b9900eSJiri Pirko if (mask_type != TCA_FLOWER_UNSPEC) { 102377b9900eSJiri Pirko err = nla_put(skb, mask_type, len, mask); 102477b9900eSJiri Pirko if (err) 102577b9900eSJiri Pirko return err; 102677b9900eSJiri Pirko } 102777b9900eSJiri Pirko return 0; 102877b9900eSJiri Pirko } 102977b9900eSJiri Pirko 1030*a577d8f7SBenjamin LaHaise static int fl_dump_key_mpls(struct sk_buff *skb, 1031*a577d8f7SBenjamin LaHaise struct flow_dissector_key_mpls *mpls_key, 1032*a577d8f7SBenjamin LaHaise struct flow_dissector_key_mpls *mpls_mask) 1033*a577d8f7SBenjamin LaHaise { 1034*a577d8f7SBenjamin LaHaise int err; 1035*a577d8f7SBenjamin LaHaise 1036*a577d8f7SBenjamin LaHaise if (!memchr_inv(mpls_mask, 0, sizeof(*mpls_mask))) 1037*a577d8f7SBenjamin LaHaise return 0; 1038*a577d8f7SBenjamin LaHaise if (mpls_mask->mpls_ttl) { 1039*a577d8f7SBenjamin LaHaise err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TTL, 1040*a577d8f7SBenjamin LaHaise mpls_key->mpls_ttl); 1041*a577d8f7SBenjamin LaHaise if (err) 1042*a577d8f7SBenjamin LaHaise return err; 1043*a577d8f7SBenjamin LaHaise } 1044*a577d8f7SBenjamin LaHaise if (mpls_mask->mpls_tc) { 1045*a577d8f7SBenjamin LaHaise err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TC, 1046*a577d8f7SBenjamin LaHaise mpls_key->mpls_tc); 1047*a577d8f7SBenjamin LaHaise if (err) 1048*a577d8f7SBenjamin LaHaise return err; 1049*a577d8f7SBenjamin LaHaise } 1050*a577d8f7SBenjamin LaHaise if (mpls_mask->mpls_label) { 1051*a577d8f7SBenjamin LaHaise err = nla_put_u32(skb, TCA_FLOWER_KEY_MPLS_LABEL, 1052*a577d8f7SBenjamin LaHaise mpls_key->mpls_label); 1053*a577d8f7SBenjamin LaHaise if (err) 1054*a577d8f7SBenjamin LaHaise return err; 1055*a577d8f7SBenjamin LaHaise } 1056*a577d8f7SBenjamin LaHaise if (mpls_mask->mpls_bos) { 1057*a577d8f7SBenjamin LaHaise err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_BOS, 1058*a577d8f7SBenjamin LaHaise mpls_key->mpls_bos); 1059*a577d8f7SBenjamin LaHaise if (err) 1060*a577d8f7SBenjamin LaHaise return err; 1061*a577d8f7SBenjamin LaHaise } 1062*a577d8f7SBenjamin LaHaise return 0; 1063*a577d8f7SBenjamin LaHaise } 1064*a577d8f7SBenjamin LaHaise 10659399ae9aSHadar Hen Zion static int fl_dump_key_vlan(struct sk_buff *skb, 10669399ae9aSHadar Hen Zion struct flow_dissector_key_vlan *vlan_key, 10679399ae9aSHadar Hen Zion struct flow_dissector_key_vlan *vlan_mask) 10689399ae9aSHadar Hen Zion { 10699399ae9aSHadar Hen Zion int err; 10709399ae9aSHadar Hen Zion 10719399ae9aSHadar Hen Zion if (!memchr_inv(vlan_mask, 0, sizeof(*vlan_mask))) 10729399ae9aSHadar Hen Zion return 0; 10739399ae9aSHadar Hen Zion if (vlan_mask->vlan_id) { 10749399ae9aSHadar Hen Zion err = nla_put_u16(skb, TCA_FLOWER_KEY_VLAN_ID, 10759399ae9aSHadar Hen Zion vlan_key->vlan_id); 10769399ae9aSHadar Hen Zion if (err) 10779399ae9aSHadar Hen Zion return err; 10789399ae9aSHadar Hen Zion } 10799399ae9aSHadar Hen Zion if (vlan_mask->vlan_priority) { 10809399ae9aSHadar Hen Zion err = nla_put_u8(skb, TCA_FLOWER_KEY_VLAN_PRIO, 10819399ae9aSHadar Hen Zion vlan_key->vlan_priority); 10829399ae9aSHadar Hen Zion if (err) 10839399ae9aSHadar Hen Zion return err; 10849399ae9aSHadar Hen Zion } 10859399ae9aSHadar Hen Zion return 0; 10869399ae9aSHadar Hen Zion } 10879399ae9aSHadar Hen Zion 1088faa3ffceSOr Gerlitz static void fl_get_key_flag(u32 dissector_key, u32 dissector_mask, 1089faa3ffceSOr Gerlitz u32 *flower_key, u32 *flower_mask, 1090faa3ffceSOr Gerlitz u32 flower_flag_bit, u32 dissector_flag_bit) 1091faa3ffceSOr Gerlitz { 1092faa3ffceSOr Gerlitz if (dissector_mask & dissector_flag_bit) { 1093faa3ffceSOr Gerlitz *flower_mask |= flower_flag_bit; 1094faa3ffceSOr Gerlitz if (dissector_key & dissector_flag_bit) 1095faa3ffceSOr Gerlitz *flower_key |= flower_flag_bit; 1096faa3ffceSOr Gerlitz } 1097faa3ffceSOr Gerlitz } 1098faa3ffceSOr Gerlitz 1099faa3ffceSOr Gerlitz static int fl_dump_key_flags(struct sk_buff *skb, u32 flags_key, u32 flags_mask) 1100faa3ffceSOr Gerlitz { 1101faa3ffceSOr Gerlitz u32 key, mask; 1102faa3ffceSOr Gerlitz __be32 _key, _mask; 1103faa3ffceSOr Gerlitz int err; 1104faa3ffceSOr Gerlitz 1105faa3ffceSOr Gerlitz if (!memchr_inv(&flags_mask, 0, sizeof(flags_mask))) 1106faa3ffceSOr Gerlitz return 0; 1107faa3ffceSOr Gerlitz 1108faa3ffceSOr Gerlitz key = 0; 1109faa3ffceSOr Gerlitz mask = 0; 1110faa3ffceSOr Gerlitz 1111faa3ffceSOr Gerlitz fl_get_key_flag(flags_key, flags_mask, &key, &mask, 1112faa3ffceSOr Gerlitz TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT); 1113faa3ffceSOr Gerlitz 1114faa3ffceSOr Gerlitz _key = cpu_to_be32(key); 1115faa3ffceSOr Gerlitz _mask = cpu_to_be32(mask); 1116faa3ffceSOr Gerlitz 1117faa3ffceSOr Gerlitz err = nla_put(skb, TCA_FLOWER_KEY_FLAGS, 4, &_key); 1118faa3ffceSOr Gerlitz if (err) 1119faa3ffceSOr Gerlitz return err; 1120faa3ffceSOr Gerlitz 1121faa3ffceSOr Gerlitz return nla_put(skb, TCA_FLOWER_KEY_FLAGS_MASK, 4, &_mask); 1122faa3ffceSOr Gerlitz } 1123faa3ffceSOr Gerlitz 112477b9900eSJiri Pirko static int fl_dump(struct net *net, struct tcf_proto *tp, unsigned long fh, 112577b9900eSJiri Pirko struct sk_buff *skb, struct tcmsg *t) 112677b9900eSJiri Pirko { 112777b9900eSJiri Pirko struct cls_fl_head *head = rtnl_dereference(tp->root); 112877b9900eSJiri Pirko struct cls_fl_filter *f = (struct cls_fl_filter *) fh; 112977b9900eSJiri Pirko struct nlattr *nest; 113077b9900eSJiri Pirko struct fl_flow_key *key, *mask; 113177b9900eSJiri Pirko 113277b9900eSJiri Pirko if (!f) 113377b9900eSJiri Pirko return skb->len; 113477b9900eSJiri Pirko 113577b9900eSJiri Pirko t->tcm_handle = f->handle; 113677b9900eSJiri Pirko 113777b9900eSJiri Pirko nest = nla_nest_start(skb, TCA_OPTIONS); 113877b9900eSJiri Pirko if (!nest) 113977b9900eSJiri Pirko goto nla_put_failure; 114077b9900eSJiri Pirko 114177b9900eSJiri Pirko if (f->res.classid && 114277b9900eSJiri Pirko nla_put_u32(skb, TCA_FLOWER_CLASSID, f->res.classid)) 114377b9900eSJiri Pirko goto nla_put_failure; 114477b9900eSJiri Pirko 114577b9900eSJiri Pirko key = &f->key; 114677b9900eSJiri Pirko mask = &head->mask.key; 114777b9900eSJiri Pirko 114877b9900eSJiri Pirko if (mask->indev_ifindex) { 114977b9900eSJiri Pirko struct net_device *dev; 115077b9900eSJiri Pirko 115177b9900eSJiri Pirko dev = __dev_get_by_index(net, key->indev_ifindex); 115277b9900eSJiri Pirko if (dev && nla_put_string(skb, TCA_FLOWER_INDEV, dev->name)) 115377b9900eSJiri Pirko goto nla_put_failure; 115477b9900eSJiri Pirko } 115577b9900eSJiri Pirko 115679685219SHadar Hen Zion if (!tc_skip_hw(f->flags)) 115710cbc684SAmir Vadai fl_hw_update_stats(tp, f); 115810cbc684SAmir Vadai 115977b9900eSJiri Pirko if (fl_dump_key_val(skb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST, 116077b9900eSJiri Pirko mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK, 116177b9900eSJiri Pirko sizeof(key->eth.dst)) || 116277b9900eSJiri Pirko fl_dump_key_val(skb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC, 116377b9900eSJiri Pirko mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK, 116477b9900eSJiri Pirko sizeof(key->eth.src)) || 116577b9900eSJiri Pirko fl_dump_key_val(skb, &key->basic.n_proto, TCA_FLOWER_KEY_ETH_TYPE, 116677b9900eSJiri Pirko &mask->basic.n_proto, TCA_FLOWER_UNSPEC, 116777b9900eSJiri Pirko sizeof(key->basic.n_proto))) 116877b9900eSJiri Pirko goto nla_put_failure; 11699399ae9aSHadar Hen Zion 1170*a577d8f7SBenjamin LaHaise if (fl_dump_key_mpls(skb, &key->mpls, &mask->mpls)) 1171*a577d8f7SBenjamin LaHaise goto nla_put_failure; 1172*a577d8f7SBenjamin LaHaise 11739399ae9aSHadar Hen Zion if (fl_dump_key_vlan(skb, &key->vlan, &mask->vlan)) 11749399ae9aSHadar Hen Zion goto nla_put_failure; 11759399ae9aSHadar Hen Zion 117677b9900eSJiri Pirko if ((key->basic.n_proto == htons(ETH_P_IP) || 117777b9900eSJiri Pirko key->basic.n_proto == htons(ETH_P_IPV6)) && 117877b9900eSJiri Pirko fl_dump_key_val(skb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO, 117977b9900eSJiri Pirko &mask->basic.ip_proto, TCA_FLOWER_UNSPEC, 118077b9900eSJiri Pirko sizeof(key->basic.ip_proto))) 118177b9900eSJiri Pirko goto nla_put_failure; 118277b9900eSJiri Pirko 1183c3f83241STom Herbert if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS && 118477b9900eSJiri Pirko (fl_dump_key_val(skb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC, 118577b9900eSJiri Pirko &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK, 118677b9900eSJiri Pirko sizeof(key->ipv4.src)) || 118777b9900eSJiri Pirko fl_dump_key_val(skb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST, 118877b9900eSJiri Pirko &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK, 118977b9900eSJiri Pirko sizeof(key->ipv4.dst)))) 119077b9900eSJiri Pirko goto nla_put_failure; 1191c3f83241STom Herbert else if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS && 119277b9900eSJiri Pirko (fl_dump_key_val(skb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC, 119377b9900eSJiri Pirko &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK, 119477b9900eSJiri Pirko sizeof(key->ipv6.src)) || 119577b9900eSJiri Pirko fl_dump_key_val(skb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST, 119677b9900eSJiri Pirko &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK, 119777b9900eSJiri Pirko sizeof(key->ipv6.dst)))) 119877b9900eSJiri Pirko goto nla_put_failure; 119977b9900eSJiri Pirko 120077b9900eSJiri Pirko if (key->basic.ip_proto == IPPROTO_TCP && 120177b9900eSJiri Pirko (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC, 1202aa72d708SOr Gerlitz &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK, 120377b9900eSJiri Pirko sizeof(key->tp.src)) || 120477b9900eSJiri Pirko fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST, 1205aa72d708SOr Gerlitz &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK, 120677b9900eSJiri Pirko sizeof(key->tp.dst)))) 120777b9900eSJiri Pirko goto nla_put_failure; 120877b9900eSJiri Pirko else if (key->basic.ip_proto == IPPROTO_UDP && 120977b9900eSJiri Pirko (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC, 1210aa72d708SOr Gerlitz &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK, 121177b9900eSJiri Pirko sizeof(key->tp.src)) || 121277b9900eSJiri Pirko fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST, 1213aa72d708SOr Gerlitz &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK, 121477b9900eSJiri Pirko sizeof(key->tp.dst)))) 121577b9900eSJiri Pirko goto nla_put_failure; 12165976c5f4SSimon Horman else if (key->basic.ip_proto == IPPROTO_SCTP && 12175976c5f4SSimon Horman (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC, 12185976c5f4SSimon Horman &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK, 12195976c5f4SSimon Horman sizeof(key->tp.src)) || 12205976c5f4SSimon Horman fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST, 12215976c5f4SSimon Horman &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK, 12225976c5f4SSimon Horman sizeof(key->tp.dst)))) 12235976c5f4SSimon Horman goto nla_put_failure; 12247b684884SSimon Horman else if (key->basic.n_proto == htons(ETH_P_IP) && 12257b684884SSimon Horman key->basic.ip_proto == IPPROTO_ICMP && 12267b684884SSimon Horman (fl_dump_key_val(skb, &key->icmp.type, 12277b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_TYPE, &mask->icmp.type, 12287b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_TYPE_MASK, 12297b684884SSimon Horman sizeof(key->icmp.type)) || 12307b684884SSimon Horman fl_dump_key_val(skb, &key->icmp.code, 12317b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_CODE, &mask->icmp.code, 12327b684884SSimon Horman TCA_FLOWER_KEY_ICMPV4_CODE_MASK, 12337b684884SSimon Horman sizeof(key->icmp.code)))) 12347b684884SSimon Horman goto nla_put_failure; 12357b684884SSimon Horman else if (key->basic.n_proto == htons(ETH_P_IPV6) && 12367b684884SSimon Horman key->basic.ip_proto == IPPROTO_ICMPV6 && 12377b684884SSimon Horman (fl_dump_key_val(skb, &key->icmp.type, 12387b684884SSimon Horman TCA_FLOWER_KEY_ICMPV6_TYPE, &mask->icmp.type, 12397b684884SSimon Horman TCA_FLOWER_KEY_ICMPV6_TYPE_MASK, 12407b684884SSimon Horman sizeof(key->icmp.type)) || 12417b684884SSimon Horman fl_dump_key_val(skb, &key->icmp.code, 12427b684884SSimon Horman TCA_FLOWER_KEY_ICMPV6_CODE, &mask->icmp.code, 12437b684884SSimon Horman TCA_FLOWER_KEY_ICMPV6_CODE_MASK, 12447b684884SSimon Horman sizeof(key->icmp.code)))) 12457b684884SSimon Horman goto nla_put_failure; 124699d31326SSimon Horman else if ((key->basic.n_proto == htons(ETH_P_ARP) || 124799d31326SSimon Horman key->basic.n_proto == htons(ETH_P_RARP)) && 124899d31326SSimon Horman (fl_dump_key_val(skb, &key->arp.sip, 124999d31326SSimon Horman TCA_FLOWER_KEY_ARP_SIP, &mask->arp.sip, 125099d31326SSimon Horman TCA_FLOWER_KEY_ARP_SIP_MASK, 125199d31326SSimon Horman sizeof(key->arp.sip)) || 125299d31326SSimon Horman fl_dump_key_val(skb, &key->arp.tip, 125399d31326SSimon Horman TCA_FLOWER_KEY_ARP_TIP, &mask->arp.tip, 125499d31326SSimon Horman TCA_FLOWER_KEY_ARP_TIP_MASK, 125599d31326SSimon Horman sizeof(key->arp.tip)) || 125699d31326SSimon Horman fl_dump_key_val(skb, &key->arp.op, 125799d31326SSimon Horman TCA_FLOWER_KEY_ARP_OP, &mask->arp.op, 125899d31326SSimon Horman TCA_FLOWER_KEY_ARP_OP_MASK, 125999d31326SSimon Horman sizeof(key->arp.op)) || 126099d31326SSimon Horman fl_dump_key_val(skb, key->arp.sha, TCA_FLOWER_KEY_ARP_SHA, 126199d31326SSimon Horman mask->arp.sha, TCA_FLOWER_KEY_ARP_SHA_MASK, 126299d31326SSimon Horman sizeof(key->arp.sha)) || 126399d31326SSimon Horman fl_dump_key_val(skb, key->arp.tha, TCA_FLOWER_KEY_ARP_THA, 126499d31326SSimon Horman mask->arp.tha, TCA_FLOWER_KEY_ARP_THA_MASK, 126599d31326SSimon Horman sizeof(key->arp.tha)))) 126699d31326SSimon Horman goto nla_put_failure; 126777b9900eSJiri Pirko 1268bc3103f1SAmir Vadai if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS && 1269bc3103f1SAmir Vadai (fl_dump_key_val(skb, &key->enc_ipv4.src, 1270bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_SRC, &mask->enc_ipv4.src, 1271bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK, 1272bc3103f1SAmir Vadai sizeof(key->enc_ipv4.src)) || 1273bc3103f1SAmir Vadai fl_dump_key_val(skb, &key->enc_ipv4.dst, 1274bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_DST, &mask->enc_ipv4.dst, 1275bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV4_DST_MASK, 1276bc3103f1SAmir Vadai sizeof(key->enc_ipv4.dst)))) 1277bc3103f1SAmir Vadai goto nla_put_failure; 1278bc3103f1SAmir Vadai else if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS && 1279bc3103f1SAmir Vadai (fl_dump_key_val(skb, &key->enc_ipv6.src, 1280bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_SRC, &mask->enc_ipv6.src, 1281bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK, 1282bc3103f1SAmir Vadai sizeof(key->enc_ipv6.src)) || 1283bc3103f1SAmir Vadai fl_dump_key_val(skb, &key->enc_ipv6.dst, 1284bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_DST, 1285bc3103f1SAmir Vadai &mask->enc_ipv6.dst, 1286bc3103f1SAmir Vadai TCA_FLOWER_KEY_ENC_IPV6_DST_MASK, 1287bc3103f1SAmir Vadai sizeof(key->enc_ipv6.dst)))) 1288bc3103f1SAmir Vadai goto nla_put_failure; 1289bc3103f1SAmir Vadai 1290bc3103f1SAmir Vadai if (fl_dump_key_val(skb, &key->enc_key_id, TCA_FLOWER_KEY_ENC_KEY_ID, 1291eb523f42SHadar Hen Zion &mask->enc_key_id, TCA_FLOWER_UNSPEC, 1292f4d997fdSHadar Hen Zion sizeof(key->enc_key_id)) || 1293f4d997fdSHadar Hen Zion fl_dump_key_val(skb, &key->enc_tp.src, 1294f4d997fdSHadar Hen Zion TCA_FLOWER_KEY_ENC_UDP_SRC_PORT, 1295f4d997fdSHadar Hen Zion &mask->enc_tp.src, 1296f4d997fdSHadar Hen Zion TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK, 1297f4d997fdSHadar Hen Zion sizeof(key->enc_tp.src)) || 1298f4d997fdSHadar Hen Zion fl_dump_key_val(skb, &key->enc_tp.dst, 1299f4d997fdSHadar Hen Zion TCA_FLOWER_KEY_ENC_UDP_DST_PORT, 1300f4d997fdSHadar Hen Zion &mask->enc_tp.dst, 1301f4d997fdSHadar Hen Zion TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK, 1302f4d997fdSHadar Hen Zion sizeof(key->enc_tp.dst))) 1303bc3103f1SAmir Vadai goto nla_put_failure; 1304bc3103f1SAmir Vadai 1305faa3ffceSOr Gerlitz if (fl_dump_key_flags(skb, key->control.flags, mask->control.flags)) 1306faa3ffceSOr Gerlitz goto nla_put_failure; 1307faa3ffceSOr Gerlitz 1308749e6720SOr Gerlitz if (f->flags && nla_put_u32(skb, TCA_FLOWER_FLAGS, f->flags)) 1309749e6720SOr Gerlitz goto nla_put_failure; 1310e69985c6SAmir Vadai 131177b9900eSJiri Pirko if (tcf_exts_dump(skb, &f->exts)) 131277b9900eSJiri Pirko goto nla_put_failure; 131377b9900eSJiri Pirko 131477b9900eSJiri Pirko nla_nest_end(skb, nest); 131577b9900eSJiri Pirko 131677b9900eSJiri Pirko if (tcf_exts_dump_stats(skb, &f->exts) < 0) 131777b9900eSJiri Pirko goto nla_put_failure; 131877b9900eSJiri Pirko 131977b9900eSJiri Pirko return skb->len; 132077b9900eSJiri Pirko 132177b9900eSJiri Pirko nla_put_failure: 132277b9900eSJiri Pirko nla_nest_cancel(skb, nest); 132377b9900eSJiri Pirko return -1; 132477b9900eSJiri Pirko } 132577b9900eSJiri Pirko 132677b9900eSJiri Pirko static struct tcf_proto_ops cls_fl_ops __read_mostly = { 132777b9900eSJiri Pirko .kind = "flower", 132877b9900eSJiri Pirko .classify = fl_classify, 132977b9900eSJiri Pirko .init = fl_init, 133077b9900eSJiri Pirko .destroy = fl_destroy, 133177b9900eSJiri Pirko .get = fl_get, 133277b9900eSJiri Pirko .change = fl_change, 133377b9900eSJiri Pirko .delete = fl_delete, 133477b9900eSJiri Pirko .walk = fl_walk, 133577b9900eSJiri Pirko .dump = fl_dump, 133677b9900eSJiri Pirko .owner = THIS_MODULE, 133777b9900eSJiri Pirko }; 133877b9900eSJiri Pirko 133977b9900eSJiri Pirko static int __init cls_fl_init(void) 134077b9900eSJiri Pirko { 134177b9900eSJiri Pirko return register_tcf_proto_ops(&cls_fl_ops); 134277b9900eSJiri Pirko } 134377b9900eSJiri Pirko 134477b9900eSJiri Pirko static void __exit cls_fl_exit(void) 134577b9900eSJiri Pirko { 134677b9900eSJiri Pirko unregister_tcf_proto_ops(&cls_fl_ops); 134777b9900eSJiri Pirko } 134877b9900eSJiri Pirko 134977b9900eSJiri Pirko module_init(cls_fl_init); 135077b9900eSJiri Pirko module_exit(cls_fl_exit); 135177b9900eSJiri Pirko 135277b9900eSJiri Pirko MODULE_AUTHOR("Jiri Pirko <jiri@resnulli.us>"); 135377b9900eSJiri Pirko MODULE_DESCRIPTION("Flower classifier"); 135477b9900eSJiri Pirko MODULE_LICENSE("GPL v2"); 1355