root/drivers/net/ethernet/cisco/enic/enic_clsf.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. enic_addfltr_5t
  2. enic_delfltr
  3. enic_rfs_flw_tbl_init
  4. enic_rfs_flw_tbl_free
  5. htbl_fltr_search
  6. enic_flow_may_expire
  7. htbl_key_search
  8. enic_rx_flow_steer

   1 // SPDX-License-Identifier: GPL-2.0
   2 #include <linux/if.h>
   3 #include <linux/if_ether.h>
   4 #include <linux/if_link.h>
   5 #include <linux/netdevice.h>
   6 #include <linux/in.h>
   7 #include <linux/types.h>
   8 #include <linux/skbuff.h>
   9 #include <net/flow_dissector.h>
  10 #include "enic_res.h"
  11 #include "enic_clsf.h"
  12 
  13 /* enic_addfltr_5t - Add ipv4 5tuple filter
  14  *      @enic: enic struct of vnic
  15  *      @keys: flow_keys of ipv4 5tuple
  16  *      @rq: rq number to steer to
  17  *
  18  * This function returns filter_id(hardware_id) of the filter
  19  * added. In case of error it returns a negative number.
  20  */
  21 int enic_addfltr_5t(struct enic *enic, struct flow_keys *keys, u16 rq)
  22 {
  23         int res;
  24         struct filter data;
  25 
  26         switch (keys->basic.ip_proto) {
  27         case IPPROTO_TCP:
  28                 data.u.ipv4.protocol = PROTO_TCP;
  29                 break;
  30         case IPPROTO_UDP:
  31                 data.u.ipv4.protocol = PROTO_UDP;
  32                 break;
  33         default:
  34                 return -EPROTONOSUPPORT;
  35         }
  36 
  37         data.type = FILTER_IPV4_5TUPLE;
  38         data.u.ipv4.src_addr = ntohl(keys->addrs.v4addrs.src);
  39         data.u.ipv4.dst_addr = ntohl(keys->addrs.v4addrs.dst);
  40         data.u.ipv4.src_port = ntohs(keys->ports.src);
  41         data.u.ipv4.dst_port = ntohs(keys->ports.dst);
  42         data.u.ipv4.flags = FILTER_FIELDS_IPV4_5TUPLE;
  43 
  44         spin_lock_bh(&enic->devcmd_lock);
  45         res = vnic_dev_classifier(enic->vdev, CLSF_ADD, &rq, &data);
  46         spin_unlock_bh(&enic->devcmd_lock);
  47         res = (res == 0) ? rq : res;
  48 
  49         return res;
  50 }
  51 
  52 /* enic_delfltr - Delete clsf filter
  53  *      @enic: enic struct of vnic
  54  *      @filter_id: filter_is(hardware_id) of filter to be deleted
  55  *
  56  * This function returns zero in case of success, negative number incase of
  57  * error.
  58  */
  59 int enic_delfltr(struct enic *enic, u16 filter_id)
  60 {
  61         int ret;
  62 
  63         spin_lock_bh(&enic->devcmd_lock);
  64         ret = vnic_dev_classifier(enic->vdev, CLSF_DEL, &filter_id, NULL);
  65         spin_unlock_bh(&enic->devcmd_lock);
  66 
  67         return ret;
  68 }
  69 
  70 /* enic_rfs_flw_tbl_init - initialize enic->rfs_h members
  71  *      @enic: enic data
  72  */
  73 void enic_rfs_flw_tbl_init(struct enic *enic)
  74 {
  75         int i;
  76 
  77         spin_lock_init(&enic->rfs_h.lock);
  78         for (i = 0; i <= ENIC_RFS_FLW_MASK; i++)
  79                 INIT_HLIST_HEAD(&enic->rfs_h.ht_head[i]);
  80         enic->rfs_h.max = enic->config.num_arfs;
  81         enic->rfs_h.free = enic->rfs_h.max;
  82         enic->rfs_h.toclean = 0;
  83 }
  84 
  85 void enic_rfs_flw_tbl_free(struct enic *enic)
  86 {
  87         int i;
  88 
  89         enic_rfs_timer_stop(enic);
  90         spin_lock_bh(&enic->rfs_h.lock);
  91         for (i = 0; i < (1 << ENIC_RFS_FLW_BITSHIFT); i++) {
  92                 struct hlist_head *hhead;
  93                 struct hlist_node *tmp;
  94                 struct enic_rfs_fltr_node *n;
  95 
  96                 hhead = &enic->rfs_h.ht_head[i];
  97                 hlist_for_each_entry_safe(n, tmp, hhead, node) {
  98                         enic_delfltr(enic, n->fltr_id);
  99                         hlist_del(&n->node);
 100                         kfree(n);
 101                         enic->rfs_h.free++;
 102                 }
 103         }
 104         spin_unlock_bh(&enic->rfs_h.lock);
 105 }
 106 
 107 struct enic_rfs_fltr_node *htbl_fltr_search(struct enic *enic, u16 fltr_id)
 108 {
 109         int i;
 110 
 111         for (i = 0; i < (1 << ENIC_RFS_FLW_BITSHIFT); i++) {
 112                 struct hlist_head *hhead;
 113                 struct hlist_node *tmp;
 114                 struct enic_rfs_fltr_node *n;
 115 
 116                 hhead = &enic->rfs_h.ht_head[i];
 117                 hlist_for_each_entry_safe(n, tmp, hhead, node)
 118                         if (n->fltr_id == fltr_id)
 119                                 return n;
 120         }
 121 
 122         return NULL;
 123 }
 124 
 125 #ifdef CONFIG_RFS_ACCEL
 126 void enic_flow_may_expire(struct timer_list *t)
 127 {
 128         struct enic *enic = from_timer(enic, t, rfs_h.rfs_may_expire);
 129         bool res;
 130         int j;
 131 
 132         spin_lock_bh(&enic->rfs_h.lock);
 133         for (j = 0; j < ENIC_CLSF_EXPIRE_COUNT; j++) {
 134                 struct hlist_head *hhead;
 135                 struct hlist_node *tmp;
 136                 struct enic_rfs_fltr_node *n;
 137 
 138                 hhead = &enic->rfs_h.ht_head[enic->rfs_h.toclean++];
 139                 hlist_for_each_entry_safe(n, tmp, hhead, node) {
 140                         res = rps_may_expire_flow(enic->netdev, n->rq_id,
 141                                                   n->flow_id, n->fltr_id);
 142                         if (res) {
 143                                 res = enic_delfltr(enic, n->fltr_id);
 144                                 if (unlikely(res))
 145                                         continue;
 146                                 hlist_del(&n->node);
 147                                 kfree(n);
 148                                 enic->rfs_h.free++;
 149                         }
 150                 }
 151         }
 152         spin_unlock_bh(&enic->rfs_h.lock);
 153         mod_timer(&enic->rfs_h.rfs_may_expire, jiffies + HZ/4);
 154 }
 155 
 156 static struct enic_rfs_fltr_node *htbl_key_search(struct hlist_head *h,
 157                                                   struct flow_keys *k)
 158 {
 159         struct enic_rfs_fltr_node *tpos;
 160 
 161         hlist_for_each_entry(tpos, h, node)
 162                 if (tpos->keys.addrs.v4addrs.src == k->addrs.v4addrs.src &&
 163                     tpos->keys.addrs.v4addrs.dst == k->addrs.v4addrs.dst &&
 164                     tpos->keys.ports.ports == k->ports.ports &&
 165                     tpos->keys.basic.ip_proto == k->basic.ip_proto &&
 166                     tpos->keys.basic.n_proto == k->basic.n_proto)
 167                         return tpos;
 168         return NULL;
 169 }
 170 
 171 int enic_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
 172                        u16 rxq_index, u32 flow_id)
 173 {
 174         struct flow_keys keys;
 175         struct enic_rfs_fltr_node *n;
 176         struct enic *enic;
 177         u16 tbl_idx;
 178         int res, i;
 179 
 180         enic = netdev_priv(dev);
 181         res = skb_flow_dissect_flow_keys(skb, &keys, 0);
 182         if (!res || keys.basic.n_proto != htons(ETH_P_IP) ||
 183             (keys.basic.ip_proto != IPPROTO_TCP &&
 184              keys.basic.ip_proto != IPPROTO_UDP))
 185                 return -EPROTONOSUPPORT;
 186 
 187         tbl_idx = skb_get_hash_raw(skb) & ENIC_RFS_FLW_MASK;
 188         spin_lock_bh(&enic->rfs_h.lock);
 189         n = htbl_key_search(&enic->rfs_h.ht_head[tbl_idx], &keys);
 190 
 191         if (n) { /* entry already present  */
 192                 if (rxq_index == n->rq_id) {
 193                         res = -EEXIST;
 194                         goto ret_unlock;
 195                 }
 196 
 197                 /* desired rq changed for the flow, we need to delete
 198                  * old fltr and add new one
 199                  *
 200                  * The moment we delete the fltr, the upcoming pkts
 201                  * are put it default rq based on rss. When we add
 202                  * new filter, upcoming pkts are put in desired queue.
 203                  * This could cause ooo pkts.
 204                  *
 205                  * Lets 1st try adding new fltr and then del old one.
 206                  */
 207                 i = --enic->rfs_h.free;
 208                 /* clsf tbl is full, we have to del old fltr first*/
 209                 if (unlikely(i < 0)) {
 210                         enic->rfs_h.free++;
 211                         res = enic_delfltr(enic, n->fltr_id);
 212                         if (unlikely(res < 0))
 213                                 goto ret_unlock;
 214                         res = enic_addfltr_5t(enic, &keys, rxq_index);
 215                         if (res < 0) {
 216                                 hlist_del(&n->node);
 217                                 enic->rfs_h.free++;
 218                                 goto ret_unlock;
 219                         }
 220                 /* add new fltr 1st then del old fltr */
 221                 } else {
 222                         int ret;
 223 
 224                         res = enic_addfltr_5t(enic, &keys, rxq_index);
 225                         if (res < 0) {
 226                                 enic->rfs_h.free++;
 227                                 goto ret_unlock;
 228                         }
 229                         ret = enic_delfltr(enic, n->fltr_id);
 230                         /* deleting old fltr failed. Add old fltr to list.
 231                          * enic_flow_may_expire() will try to delete it later.
 232                          */
 233                         if (unlikely(ret < 0)) {
 234                                 struct enic_rfs_fltr_node *d;
 235                                 struct hlist_head *head;
 236 
 237                                 head = &enic->rfs_h.ht_head[tbl_idx];
 238                                 d = kmalloc(sizeof(*d), GFP_ATOMIC);
 239                                 if (d) {
 240                                         d->fltr_id = n->fltr_id;
 241                                         INIT_HLIST_NODE(&d->node);
 242                                         hlist_add_head(&d->node, head);
 243                                 }
 244                         } else {
 245                                 enic->rfs_h.free++;
 246                         }
 247                 }
 248                 n->rq_id = rxq_index;
 249                 n->fltr_id = res;
 250                 n->flow_id = flow_id;
 251         /* entry not present */
 252         } else {
 253                 i = --enic->rfs_h.free;
 254                 if (i <= 0) {
 255                         enic->rfs_h.free++;
 256                         res = -EBUSY;
 257                         goto ret_unlock;
 258                 }
 259 
 260                 n = kmalloc(sizeof(*n), GFP_ATOMIC);
 261                 if (!n) {
 262                         res = -ENOMEM;
 263                         enic->rfs_h.free++;
 264                         goto ret_unlock;
 265                 }
 266 
 267                 res = enic_addfltr_5t(enic, &keys, rxq_index);
 268                 if (res < 0) {
 269                         kfree(n);
 270                         enic->rfs_h.free++;
 271                         goto ret_unlock;
 272                 }
 273                 n->rq_id = rxq_index;
 274                 n->fltr_id = res;
 275                 n->flow_id = flow_id;
 276                 n->keys = keys;
 277                 INIT_HLIST_NODE(&n->node);
 278                 hlist_add_head(&n->node, &enic->rfs_h.ht_head[tbl_idx]);
 279         }
 280 
 281 ret_unlock:
 282         spin_unlock_bh(&enic->rfs_h.lock);
 283         return res;
 284 }
 285 
 286 #endif /* CONFIG_RFS_ACCEL */

/* [<][>][^][v][top][bottom][index][help] */