linux/drivers/net/ethernet/cisco/enic/enic_clsf.c
<<
>>
Prefs
   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 */
  21int 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        data.type = FILTER_IPV4_5TUPLE;
  37        data.u.ipv4.src_addr = ntohl(keys->addrs.v4addrs.src);
  38        data.u.ipv4.dst_addr = ntohl(keys->addrs.v4addrs.dst);
  39        data.u.ipv4.src_port = ntohs(keys->ports.src);
  40        data.u.ipv4.dst_port = ntohs(keys->ports.dst);
  41        data.u.ipv4.flags = FILTER_FIELDS_IPV4_5TUPLE;
  42
  43        spin_lock_bh(&enic->devcmd_lock);
  44        res = vnic_dev_classifier(enic->vdev, CLSF_ADD, &rq, &data);
  45        spin_unlock_bh(&enic->devcmd_lock);
  46        res = (res == 0) ? rq : res;
  47
  48        return res;
  49}
  50
  51/* enic_delfltr - Delete clsf filter
  52 *      @enic: enic struct of vnic
  53 *      @filter_id: filter_is(hardware_id) of filter to be deleted
  54 *
  55 * This function returns zero in case of success, negative number incase of
  56 * error.
  57 */
  58int enic_delfltr(struct enic *enic, u16 filter_id)
  59{
  60        int ret;
  61
  62        spin_lock_bh(&enic->devcmd_lock);
  63        ret = vnic_dev_classifier(enic->vdev, CLSF_DEL, &filter_id, NULL);
  64        spin_unlock_bh(&enic->devcmd_lock);
  65
  66        return ret;
  67}
  68
  69/* enic_rfs_flw_tbl_init - initialize enic->rfs_h members
  70 *      @enic: enic data
  71 */
  72void enic_rfs_flw_tbl_init(struct enic *enic)
  73{
  74        int i;
  75
  76        spin_lock_init(&enic->rfs_h.lock);
  77        for (i = 0; i <= ENIC_RFS_FLW_MASK; i++)
  78                INIT_HLIST_HEAD(&enic->rfs_h.ht_head[i]);
  79        enic->rfs_h.max = enic->config.num_arfs;
  80        enic->rfs_h.free = enic->rfs_h.max;
  81        enic->rfs_h.toclean = 0;
  82        enic_rfs_timer_start(enic);
  83}
  84
  85void 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        enic->rfs_h.free = 0;
  92        for (i = 0; i < (1 << ENIC_RFS_FLW_BITSHIFT); i++) {
  93                struct hlist_head *hhead;
  94                struct hlist_node *tmp;
  95                struct enic_rfs_fltr_node *n;
  96
  97                hhead = &enic->rfs_h.ht_head[i];
  98                hlist_for_each_entry_safe(n, tmp, hhead, node) {
  99                        enic_delfltr(enic, n->fltr_id);
 100                        hlist_del(&n->node);
 101                        kfree(n);
 102                }
 103        }
 104        spin_unlock_bh(&enic->rfs_h.lock);
 105}
 106
 107struct 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
 126void 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
 156static 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
 171int 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
 281ret_unlock:
 282        spin_unlock_bh(&enic->rfs_h.lock);
 283        return res;
 284}
 285
 286#endif /* CONFIG_RFS_ACCEL */
 287