root/drivers/net/ethernet/netronome/nfp/abm/cls.c

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

DEFINITIONS

This source file includes following definitions.
  1. nfp_abm_u32_check_knode
  2. nfp_abm_find_band_for_prio
  3. nfp_abm_update_band_map
  4. nfp_abm_u32_knode_delete
  5. nfp_abm_u32_knode_replace
  6. nfp_abm_setup_tc_block_cb
  7. nfp_abm_setup_cls_block

   1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
   2 /* Copyright (C) 2018 Netronome Systems, Inc. */
   3 
   4 #include <linux/bitfield.h>
   5 #include <net/pkt_cls.h>
   6 
   7 #include "../nfpcore/nfp_cpp.h"
   8 #include "../nfp_app.h"
   9 #include "../nfp_net_repr.h"
  10 #include "main.h"
  11 
  12 struct nfp_abm_u32_match {
  13         u32 handle;
  14         u32 band;
  15         u8 mask;
  16         u8 val;
  17         struct list_head list;
  18 };
  19 
  20 static bool
  21 nfp_abm_u32_check_knode(struct nfp_abm *abm, struct tc_cls_u32_knode *knode,
  22                         __be16 proto, struct netlink_ext_ack *extack)
  23 {
  24         struct tc_u32_key *k;
  25         unsigned int tos_off;
  26 
  27         if (knode->exts && tcf_exts_has_actions(knode->exts)) {
  28                 NL_SET_ERR_MSG_MOD(extack, "action offload not supported");
  29                 return false;
  30         }
  31         if (knode->link_handle) {
  32                 NL_SET_ERR_MSG_MOD(extack, "linking not supported");
  33                 return false;
  34         }
  35         if (knode->sel->flags != TC_U32_TERMINAL) {
  36                 NL_SET_ERR_MSG_MOD(extack,
  37                                    "flags must be equal to TC_U32_TERMINAL");
  38                 return false;
  39         }
  40         if (knode->sel->off || knode->sel->offshift || knode->sel->offmask ||
  41             knode->sel->offoff || knode->fshift) {
  42                 NL_SET_ERR_MSG_MOD(extack, "variable offsetting not supported");
  43                 return false;
  44         }
  45         if (knode->sel->hoff || knode->sel->hmask) {
  46                 NL_SET_ERR_MSG_MOD(extack, "hashing not supported");
  47                 return false;
  48         }
  49         if (knode->val || knode->mask) {
  50                 NL_SET_ERR_MSG_MOD(extack, "matching on mark not supported");
  51                 return false;
  52         }
  53         if (knode->res && knode->res->class) {
  54                 NL_SET_ERR_MSG_MOD(extack, "setting non-0 class not supported");
  55                 return false;
  56         }
  57         if (knode->res && knode->res->classid >= abm->num_bands) {
  58                 NL_SET_ERR_MSG_MOD(extack,
  59                                    "classid higher than number of bands");
  60                 return false;
  61         }
  62         if (knode->sel->nkeys != 1) {
  63                 NL_SET_ERR_MSG_MOD(extack, "exactly one key required");
  64                 return false;
  65         }
  66 
  67         switch (proto) {
  68         case htons(ETH_P_IP):
  69                 tos_off = 16;
  70                 break;
  71         case htons(ETH_P_IPV6):
  72                 tos_off = 20;
  73                 break;
  74         default:
  75                 NL_SET_ERR_MSG_MOD(extack, "only IP and IPv6 supported as filter protocol");
  76                 return false;
  77         }
  78 
  79         k = &knode->sel->keys[0];
  80         if (k->offmask) {
  81                 NL_SET_ERR_MSG_MOD(extack, "offset mask - variable offsetting not supported");
  82                 return false;
  83         }
  84         if (k->off) {
  85                 NL_SET_ERR_MSG_MOD(extack, "only DSCP fields can be matched");
  86                 return false;
  87         }
  88         if (k->val & ~k->mask) {
  89                 NL_SET_ERR_MSG_MOD(extack, "mask does not cover the key");
  90                 return false;
  91         }
  92         if (be32_to_cpu(k->mask) >> tos_off & ~abm->dscp_mask) {
  93                 NL_SET_ERR_MSG_MOD(extack, "only high DSCP class selector bits can be used");
  94                 nfp_err(abm->app->cpp,
  95                         "u32 offload: requested mask %x FW can support only %x\n",
  96                         be32_to_cpu(k->mask) >> tos_off, abm->dscp_mask);
  97                 return false;
  98         }
  99 
 100         return true;
 101 }
 102 
 103 /* This filter list -> map conversion is O(n * m), we expect single digit or
 104  * low double digit number of prios and likewise for the filters.  Also u32
 105  * doesn't report stats, so it's really only setup time cost.
 106  */
 107 static unsigned int
 108 nfp_abm_find_band_for_prio(struct nfp_abm_link *alink, unsigned int prio)
 109 {
 110         struct nfp_abm_u32_match *iter;
 111 
 112         list_for_each_entry(iter, &alink->dscp_map, list)
 113                 if ((prio & iter->mask) == iter->val)
 114                         return iter->band;
 115 
 116         return alink->def_band;
 117 }
 118 
 119 static int nfp_abm_update_band_map(struct nfp_abm_link *alink)
 120 {
 121         unsigned int i, bits_per_prio, prios_per_word, base_shift;
 122         struct nfp_abm *abm = alink->abm;
 123         u32 field_mask;
 124 
 125         alink->has_prio = !list_empty(&alink->dscp_map);
 126 
 127         bits_per_prio = roundup_pow_of_two(order_base_2(abm->num_bands));
 128         field_mask = (1 << bits_per_prio) - 1;
 129         prios_per_word = sizeof(u32) * BITS_PER_BYTE / bits_per_prio;
 130 
 131         /* FW mask applies from top bits */
 132         base_shift = 8 - order_base_2(abm->num_prios);
 133 
 134         for (i = 0; i < abm->num_prios; i++) {
 135                 unsigned int offset;
 136                 u32 *word;
 137                 u8 band;
 138 
 139                 word = &alink->prio_map[i / prios_per_word];
 140                 offset = (i % prios_per_word) * bits_per_prio;
 141 
 142                 band = nfp_abm_find_band_for_prio(alink, i << base_shift);
 143 
 144                 *word &= ~(field_mask << offset);
 145                 *word |= band << offset;
 146         }
 147 
 148         /* Qdisc offload status may change if has_prio changed */
 149         nfp_abm_qdisc_offload_update(alink);
 150 
 151         return nfp_abm_ctrl_prio_map_update(alink, alink->prio_map);
 152 }
 153 
 154 static void
 155 nfp_abm_u32_knode_delete(struct nfp_abm_link *alink,
 156                          struct tc_cls_u32_knode *knode)
 157 {
 158         struct nfp_abm_u32_match *iter;
 159 
 160         list_for_each_entry(iter, &alink->dscp_map, list)
 161                 if (iter->handle == knode->handle) {
 162                         list_del(&iter->list);
 163                         kfree(iter);
 164                         nfp_abm_update_band_map(alink);
 165                         return;
 166                 }
 167 }
 168 
 169 static int
 170 nfp_abm_u32_knode_replace(struct nfp_abm_link *alink,
 171                           struct tc_cls_u32_knode *knode,
 172                           __be16 proto, struct netlink_ext_ack *extack)
 173 {
 174         struct nfp_abm_u32_match *match = NULL, *iter;
 175         unsigned int tos_off;
 176         u8 mask, val;
 177         int err;
 178 
 179         if (!nfp_abm_u32_check_knode(alink->abm, knode, proto, extack))
 180                 goto err_delete;
 181 
 182         tos_off = proto == htons(ETH_P_IP) ? 16 : 20;
 183 
 184         /* Extract the DSCP Class Selector bits */
 185         val = be32_to_cpu(knode->sel->keys[0].val) >> tos_off & 0xff;
 186         mask = be32_to_cpu(knode->sel->keys[0].mask) >> tos_off & 0xff;
 187 
 188         /* Check if there is no conflicting mapping and find match by handle */
 189         list_for_each_entry(iter, &alink->dscp_map, list) {
 190                 u32 cmask;
 191 
 192                 if (iter->handle == knode->handle) {
 193                         match = iter;
 194                         continue;
 195                 }
 196 
 197                 cmask = iter->mask & mask;
 198                 if ((iter->val & cmask) == (val & cmask) &&
 199                     iter->band != knode->res->classid) {
 200                         NL_SET_ERR_MSG_MOD(extack, "conflict with already offloaded filter");
 201                         goto err_delete;
 202                 }
 203         }
 204 
 205         if (!match) {
 206                 match = kzalloc(sizeof(*match), GFP_KERNEL);
 207                 if (!match)
 208                         return -ENOMEM;
 209                 list_add(&match->list, &alink->dscp_map);
 210         }
 211         match->handle = knode->handle;
 212         match->band = knode->res->classid;
 213         match->mask = mask;
 214         match->val = val;
 215 
 216         err = nfp_abm_update_band_map(alink);
 217         if (err)
 218                 goto err_delete;
 219 
 220         return 0;
 221 
 222 err_delete:
 223         nfp_abm_u32_knode_delete(alink, knode);
 224         return -EOPNOTSUPP;
 225 }
 226 
 227 static int nfp_abm_setup_tc_block_cb(enum tc_setup_type type,
 228                                      void *type_data, void *cb_priv)
 229 {
 230         struct tc_cls_u32_offload *cls_u32 = type_data;
 231         struct nfp_repr *repr = cb_priv;
 232         struct nfp_abm_link *alink;
 233 
 234         alink = repr->app_priv;
 235 
 236         if (type != TC_SETUP_CLSU32) {
 237                 NL_SET_ERR_MSG_MOD(cls_u32->common.extack,
 238                                    "only offload of u32 classifier supported");
 239                 return -EOPNOTSUPP;
 240         }
 241         if (!tc_cls_can_offload_and_chain0(repr->netdev, &cls_u32->common))
 242                 return -EOPNOTSUPP;
 243 
 244         if (cls_u32->common.protocol != htons(ETH_P_IP) &&
 245             cls_u32->common.protocol != htons(ETH_P_IPV6)) {
 246                 NL_SET_ERR_MSG_MOD(cls_u32->common.extack,
 247                                    "only IP and IPv6 supported as filter protocol");
 248                 return -EOPNOTSUPP;
 249         }
 250 
 251         switch (cls_u32->command) {
 252         case TC_CLSU32_NEW_KNODE:
 253         case TC_CLSU32_REPLACE_KNODE:
 254                 return nfp_abm_u32_knode_replace(alink, &cls_u32->knode,
 255                                                  cls_u32->common.protocol,
 256                                                  cls_u32->common.extack);
 257         case TC_CLSU32_DELETE_KNODE:
 258                 nfp_abm_u32_knode_delete(alink, &cls_u32->knode);
 259                 return 0;
 260         default:
 261                 return -EOPNOTSUPP;
 262         }
 263 }
 264 
 265 static LIST_HEAD(nfp_abm_block_cb_list);
 266 
 267 int nfp_abm_setup_cls_block(struct net_device *netdev, struct nfp_repr *repr,
 268                             struct flow_block_offload *f)
 269 {
 270         return flow_block_cb_setup_simple(f, &nfp_abm_block_cb_list,
 271                                           nfp_abm_setup_tc_block_cb,
 272                                           repr, repr, true);
 273 }

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