root/drivers/net/ethernet/mscc/ocelot_flower.c

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

DEFINITIONS

This source file includes following definitions.
  1. ocelot_flower_parse_action
  2. ocelot_flower_parse
  3. ocelot_ace_rule_create
  4. ocelot_flower_replace
  5. ocelot_flower_destroy
  6. ocelot_flower_stats_update
  7. ocelot_setup_tc_cls_flower
  8. ocelot_setup_tc_block_cb_flower
  9. ocelot_port_block_create
  10. ocelot_port_block_destroy
  11. ocelot_tc_block_unbind
  12. ocelot_setup_tc_block_flower_bind
  13. ocelot_setup_tc_block_flower_unbind

   1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
   2 /* Microsemi Ocelot Switch driver
   3  * Copyright (c) 2019 Microsemi Corporation
   4  */
   5 
   6 #include <net/pkt_cls.h>
   7 #include <net/tc_act/tc_gact.h>
   8 
   9 #include "ocelot_ace.h"
  10 
  11 struct ocelot_port_block {
  12         struct ocelot_acl_block *block;
  13         struct ocelot_port *port;
  14 };
  15 
  16 static int ocelot_flower_parse_action(struct flow_cls_offload *f,
  17                                       struct ocelot_ace_rule *rule)
  18 {
  19         const struct flow_action_entry *a;
  20         int i;
  21 
  22         if (f->rule->action.num_entries != 1)
  23                 return -EOPNOTSUPP;
  24 
  25         flow_action_for_each(i, a, &f->rule->action) {
  26                 switch (a->id) {
  27                 case FLOW_ACTION_DROP:
  28                         rule->action = OCELOT_ACL_ACTION_DROP;
  29                         break;
  30                 case FLOW_ACTION_TRAP:
  31                         rule->action = OCELOT_ACL_ACTION_TRAP;
  32                         break;
  33                 default:
  34                         return -EOPNOTSUPP;
  35                 }
  36         }
  37 
  38         return 0;
  39 }
  40 
  41 static int ocelot_flower_parse(struct flow_cls_offload *f,
  42                                struct ocelot_ace_rule *ocelot_rule)
  43 {
  44         struct flow_rule *rule = flow_cls_offload_flow_rule(f);
  45         struct flow_dissector *dissector = rule->match.dissector;
  46 
  47         if (dissector->used_keys &
  48             ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
  49               BIT(FLOW_DISSECTOR_KEY_BASIC) |
  50               BIT(FLOW_DISSECTOR_KEY_PORTS) |
  51               BIT(FLOW_DISSECTOR_KEY_VLAN) |
  52               BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
  53               BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
  54               BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
  55                 return -EOPNOTSUPP;
  56         }
  57 
  58         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
  59                 struct flow_match_control match;
  60 
  61                 flow_rule_match_control(rule, &match);
  62         }
  63 
  64         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
  65                 struct flow_match_eth_addrs match;
  66                 u16 proto = ntohs(f->common.protocol);
  67 
  68                 /* The hw support mac matches only for MAC_ETYPE key,
  69                  * therefore if other matches(port, tcp flags, etc) are added
  70                  * then just bail out
  71                  */
  72                 if ((dissector->used_keys &
  73                     (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
  74                      BIT(FLOW_DISSECTOR_KEY_BASIC) |
  75                      BIT(FLOW_DISSECTOR_KEY_CONTROL))) !=
  76                     (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
  77                      BIT(FLOW_DISSECTOR_KEY_BASIC) |
  78                      BIT(FLOW_DISSECTOR_KEY_CONTROL)))
  79                         return -EOPNOTSUPP;
  80 
  81                 if (proto == ETH_P_IP ||
  82                     proto == ETH_P_IPV6 ||
  83                     proto == ETH_P_ARP)
  84                         return -EOPNOTSUPP;
  85 
  86                 flow_rule_match_eth_addrs(rule, &match);
  87                 ocelot_rule->type = OCELOT_ACE_TYPE_ETYPE;
  88                 ether_addr_copy(ocelot_rule->frame.etype.dmac.value,
  89                                 match.key->dst);
  90                 ether_addr_copy(ocelot_rule->frame.etype.smac.value,
  91                                 match.key->src);
  92                 ether_addr_copy(ocelot_rule->frame.etype.dmac.mask,
  93                                 match.mask->dst);
  94                 ether_addr_copy(ocelot_rule->frame.etype.smac.mask,
  95                                 match.mask->src);
  96                 goto finished_key_parsing;
  97         }
  98 
  99         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
 100                 struct flow_match_basic match;
 101 
 102                 flow_rule_match_basic(rule, &match);
 103                 if (ntohs(match.key->n_proto) == ETH_P_IP) {
 104                         ocelot_rule->type = OCELOT_ACE_TYPE_IPV4;
 105                         ocelot_rule->frame.ipv4.proto.value[0] =
 106                                 match.key->ip_proto;
 107                         ocelot_rule->frame.ipv4.proto.mask[0] =
 108                                 match.mask->ip_proto;
 109                 }
 110                 if (ntohs(match.key->n_proto) == ETH_P_IPV6) {
 111                         ocelot_rule->type = OCELOT_ACE_TYPE_IPV6;
 112                         ocelot_rule->frame.ipv6.proto.value[0] =
 113                                 match.key->ip_proto;
 114                         ocelot_rule->frame.ipv6.proto.mask[0] =
 115                                 match.mask->ip_proto;
 116                 }
 117         }
 118 
 119         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) &&
 120             ntohs(f->common.protocol) == ETH_P_IP) {
 121                 struct flow_match_ipv4_addrs match;
 122                 u8 *tmp;
 123 
 124                 flow_rule_match_ipv4_addrs(rule, &match);
 125                 tmp = &ocelot_rule->frame.ipv4.sip.value.addr[0];
 126                 memcpy(tmp, &match.key->src, 4);
 127 
 128                 tmp = &ocelot_rule->frame.ipv4.sip.mask.addr[0];
 129                 memcpy(tmp, &match.mask->src, 4);
 130 
 131                 tmp = &ocelot_rule->frame.ipv4.dip.value.addr[0];
 132                 memcpy(tmp, &match.key->dst, 4);
 133 
 134                 tmp = &ocelot_rule->frame.ipv4.dip.mask.addr[0];
 135                 memcpy(tmp, &match.mask->dst, 4);
 136         }
 137 
 138         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) &&
 139             ntohs(f->common.protocol) == ETH_P_IPV6) {
 140                 return -EOPNOTSUPP;
 141         }
 142 
 143         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
 144                 struct flow_match_ports match;
 145 
 146                 flow_rule_match_ports(rule, &match);
 147                 ocelot_rule->frame.ipv4.sport.value = ntohs(match.key->src);
 148                 ocelot_rule->frame.ipv4.sport.mask = ntohs(match.mask->src);
 149                 ocelot_rule->frame.ipv4.dport.value = ntohs(match.key->dst);
 150                 ocelot_rule->frame.ipv4.dport.mask = ntohs(match.mask->dst);
 151         }
 152 
 153         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
 154                 struct flow_match_vlan match;
 155 
 156                 flow_rule_match_vlan(rule, &match);
 157                 ocelot_rule->type = OCELOT_ACE_TYPE_ANY;
 158                 ocelot_rule->vlan.vid.value = match.key->vlan_id;
 159                 ocelot_rule->vlan.vid.mask = match.mask->vlan_id;
 160                 ocelot_rule->vlan.pcp.value[0] = match.key->vlan_priority;
 161                 ocelot_rule->vlan.pcp.mask[0] = match.mask->vlan_priority;
 162         }
 163 
 164 finished_key_parsing:
 165         ocelot_rule->prio = f->common.prio;
 166         ocelot_rule->id = f->cookie;
 167         return ocelot_flower_parse_action(f, ocelot_rule);
 168 }
 169 
 170 static
 171 struct ocelot_ace_rule *ocelot_ace_rule_create(struct flow_cls_offload *f,
 172                                                struct ocelot_port_block *block)
 173 {
 174         struct ocelot_ace_rule *rule;
 175 
 176         rule = kzalloc(sizeof(*rule), GFP_KERNEL);
 177         if (!rule)
 178                 return NULL;
 179 
 180         rule->port = block->port;
 181         rule->chip_port = block->port->chip_port;
 182         return rule;
 183 }
 184 
 185 static int ocelot_flower_replace(struct flow_cls_offload *f,
 186                                  struct ocelot_port_block *port_block)
 187 {
 188         struct ocelot_ace_rule *rule;
 189         int ret;
 190 
 191         rule = ocelot_ace_rule_create(f, port_block);
 192         if (!rule)
 193                 return -ENOMEM;
 194 
 195         ret = ocelot_flower_parse(f, rule);
 196         if (ret) {
 197                 kfree(rule);
 198                 return ret;
 199         }
 200 
 201         ret = ocelot_ace_rule_offload_add(rule);
 202         if (ret)
 203                 return ret;
 204 
 205         port_block->port->tc.offload_cnt++;
 206         return 0;
 207 }
 208 
 209 static int ocelot_flower_destroy(struct flow_cls_offload *f,
 210                                  struct ocelot_port_block *port_block)
 211 {
 212         struct ocelot_ace_rule rule;
 213         int ret;
 214 
 215         rule.prio = f->common.prio;
 216         rule.port = port_block->port;
 217         rule.id = f->cookie;
 218 
 219         ret = ocelot_ace_rule_offload_del(&rule);
 220         if (ret)
 221                 return ret;
 222 
 223         port_block->port->tc.offload_cnt--;
 224         return 0;
 225 }
 226 
 227 static int ocelot_flower_stats_update(struct flow_cls_offload *f,
 228                                       struct ocelot_port_block *port_block)
 229 {
 230         struct ocelot_ace_rule rule;
 231         int ret;
 232 
 233         rule.prio = f->common.prio;
 234         rule.port = port_block->port;
 235         rule.id = f->cookie;
 236         ret = ocelot_ace_rule_stats_update(&rule);
 237         if (ret)
 238                 return ret;
 239 
 240         flow_stats_update(&f->stats, 0x0, rule.stats.pkts, 0x0);
 241         return 0;
 242 }
 243 
 244 static int ocelot_setup_tc_cls_flower(struct flow_cls_offload *f,
 245                                       struct ocelot_port_block *port_block)
 246 {
 247         switch (f->command) {
 248         case FLOW_CLS_REPLACE:
 249                 return ocelot_flower_replace(f, port_block);
 250         case FLOW_CLS_DESTROY:
 251                 return ocelot_flower_destroy(f, port_block);
 252         case FLOW_CLS_STATS:
 253                 return ocelot_flower_stats_update(f, port_block);
 254         default:
 255                 return -EOPNOTSUPP;
 256         }
 257 }
 258 
 259 static int ocelot_setup_tc_block_cb_flower(enum tc_setup_type type,
 260                                            void *type_data, void *cb_priv)
 261 {
 262         struct ocelot_port_block *port_block = cb_priv;
 263 
 264         if (!tc_cls_can_offload_and_chain0(port_block->port->dev, type_data))
 265                 return -EOPNOTSUPP;
 266 
 267         switch (type) {
 268         case TC_SETUP_CLSFLOWER:
 269                 return ocelot_setup_tc_cls_flower(type_data, cb_priv);
 270         case TC_SETUP_CLSMATCHALL:
 271                 return 0;
 272         default:
 273                 return -EOPNOTSUPP;
 274         }
 275 }
 276 
 277 static struct ocelot_port_block*
 278 ocelot_port_block_create(struct ocelot_port *port)
 279 {
 280         struct ocelot_port_block *port_block;
 281 
 282         port_block = kzalloc(sizeof(*port_block), GFP_KERNEL);
 283         if (!port_block)
 284                 return NULL;
 285 
 286         port_block->port = port;
 287 
 288         return port_block;
 289 }
 290 
 291 static void ocelot_port_block_destroy(struct ocelot_port_block *block)
 292 {
 293         kfree(block);
 294 }
 295 
 296 static void ocelot_tc_block_unbind(void *cb_priv)
 297 {
 298         struct ocelot_port_block *port_block = cb_priv;
 299 
 300         ocelot_port_block_destroy(port_block);
 301 }
 302 
 303 int ocelot_setup_tc_block_flower_bind(struct ocelot_port *port,
 304                                       struct flow_block_offload *f)
 305 {
 306         struct ocelot_port_block *port_block;
 307         struct flow_block_cb *block_cb;
 308         int ret;
 309 
 310         if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
 311                 return -EOPNOTSUPP;
 312 
 313         block_cb = flow_block_cb_lookup(f->block,
 314                                         ocelot_setup_tc_block_cb_flower, port);
 315         if (!block_cb) {
 316                 port_block = ocelot_port_block_create(port);
 317                 if (!port_block)
 318                         return -ENOMEM;
 319 
 320                 block_cb = flow_block_cb_alloc(ocelot_setup_tc_block_cb_flower,
 321                                                port, port_block,
 322                                                ocelot_tc_block_unbind);
 323                 if (IS_ERR(block_cb)) {
 324                         ret = PTR_ERR(block_cb);
 325                         goto err_cb_register;
 326                 }
 327                 flow_block_cb_add(block_cb, f);
 328                 list_add_tail(&block_cb->driver_list, f->driver_block_list);
 329         } else {
 330                 port_block = flow_block_cb_priv(block_cb);
 331         }
 332 
 333         flow_block_cb_incref(block_cb);
 334         return 0;
 335 
 336 err_cb_register:
 337         ocelot_port_block_destroy(port_block);
 338 
 339         return ret;
 340 }
 341 
 342 void ocelot_setup_tc_block_flower_unbind(struct ocelot_port *port,
 343                                          struct flow_block_offload *f)
 344 {
 345         struct flow_block_cb *block_cb;
 346 
 347         block_cb = flow_block_cb_lookup(f->block,
 348                                         ocelot_setup_tc_block_cb_flower, port);
 349         if (!block_cb)
 350                 return;
 351 
 352         if (!flow_block_cb_decref(block_cb)) {
 353                 flow_block_cb_remove(block_cb, f);
 354                 list_del(&block_cb->driver_list);
 355         }
 356 }

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