Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
0002 /* Microsemi Ocelot Switch driver
0003  * Copyright (c) 2019 Microsemi Corporation
0004  */
0005 
0006 #include <net/pkt_cls.h>
0007 #include <net/tc_act/tc_gact.h>
0008 #include <soc/mscc/ocelot_vcap.h>
0009 #include "ocelot_police.h"
0010 #include "ocelot_vcap.h"
0011 
0012 /* Arbitrarily chosen constants for encoding the VCAP block and lookup number
0013  * into the chain number. This is UAPI.
0014  */
0015 #define VCAP_BLOCK          10000
0016 #define VCAP_LOOKUP         1000
0017 #define VCAP_IS1_NUM_LOOKUPS        3
0018 #define VCAP_IS2_NUM_LOOKUPS        2
0019 #define VCAP_IS2_NUM_PAG        256
0020 #define VCAP_IS1_CHAIN(lookup)      \
0021     (1 * VCAP_BLOCK + (lookup) * VCAP_LOOKUP)
0022 #define VCAP_IS2_CHAIN(lookup, pag) \
0023     (2 * VCAP_BLOCK + (lookup) * VCAP_LOOKUP + (pag))
0024 /* PSFP chain and block ID */
0025 #define PSFP_BLOCK_ID           OCELOT_NUM_VCAP_BLOCKS
0026 #define OCELOT_PSFP_CHAIN       (3 * VCAP_BLOCK)
0027 
0028 static int ocelot_chain_to_block(int chain, bool ingress)
0029 {
0030     int lookup, pag;
0031 
0032     if (!ingress) {
0033         if (chain == 0)
0034             return VCAP_ES0;
0035         return -EOPNOTSUPP;
0036     }
0037 
0038     /* Backwards compatibility with older, single-chain tc-flower
0039      * offload support in Ocelot
0040      */
0041     if (chain == 0)
0042         return VCAP_IS2;
0043 
0044     for (lookup = 0; lookup < VCAP_IS1_NUM_LOOKUPS; lookup++)
0045         if (chain == VCAP_IS1_CHAIN(lookup))
0046             return VCAP_IS1;
0047 
0048     for (lookup = 0; lookup < VCAP_IS2_NUM_LOOKUPS; lookup++)
0049         for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
0050             if (chain == VCAP_IS2_CHAIN(lookup, pag))
0051                 return VCAP_IS2;
0052 
0053     if (chain == OCELOT_PSFP_CHAIN)
0054         return PSFP_BLOCK_ID;
0055 
0056     return -EOPNOTSUPP;
0057 }
0058 
0059 /* Caller must ensure this is a valid IS1 or IS2 chain first,
0060  * by calling ocelot_chain_to_block.
0061  */
0062 static int ocelot_chain_to_lookup(int chain)
0063 {
0064     /* Backwards compatibility with older, single-chain tc-flower
0065      * offload support in Ocelot
0066      */
0067     if (chain == 0)
0068         return 0;
0069 
0070     return (chain / VCAP_LOOKUP) % 10;
0071 }
0072 
0073 /* Caller must ensure this is a valid IS2 chain first,
0074  * by calling ocelot_chain_to_block.
0075  */
0076 static int ocelot_chain_to_pag(int chain)
0077 {
0078     int lookup;
0079 
0080     /* Backwards compatibility with older, single-chain tc-flower
0081      * offload support in Ocelot
0082      */
0083     if (chain == 0)
0084         return 0;
0085 
0086     lookup = ocelot_chain_to_lookup(chain);
0087 
0088     /* calculate PAG value as chain index relative to the first PAG */
0089     return chain - VCAP_IS2_CHAIN(lookup, 0);
0090 }
0091 
0092 static bool ocelot_is_goto_target_valid(int goto_target, int chain,
0093                     bool ingress)
0094 {
0095     int pag;
0096 
0097     /* Can't offload GOTO in VCAP ES0 */
0098     if (!ingress)
0099         return (goto_target < 0);
0100 
0101     /* Non-optional GOTOs */
0102     if (chain == 0)
0103         /* VCAP IS1 can be skipped, either partially or completely */
0104         return (goto_target == VCAP_IS1_CHAIN(0) ||
0105             goto_target == VCAP_IS1_CHAIN(1) ||
0106             goto_target == VCAP_IS1_CHAIN(2) ||
0107             goto_target == VCAP_IS2_CHAIN(0, 0) ||
0108             goto_target == VCAP_IS2_CHAIN(1, 0) ||
0109             goto_target == OCELOT_PSFP_CHAIN);
0110 
0111     if (chain == VCAP_IS1_CHAIN(0))
0112         return (goto_target == VCAP_IS1_CHAIN(1));
0113 
0114     if (chain == VCAP_IS1_CHAIN(1))
0115         return (goto_target == VCAP_IS1_CHAIN(2));
0116 
0117     /* Lookup 2 of VCAP IS1 can really support non-optional GOTOs,
0118      * using a Policy Association Group (PAG) value, which is an 8-bit
0119      * value encoding a VCAP IS2 target chain.
0120      */
0121     if (chain == VCAP_IS1_CHAIN(2)) {
0122         for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
0123             if (goto_target == VCAP_IS2_CHAIN(0, pag))
0124                 return true;
0125 
0126         return false;
0127     }
0128 
0129     /* Non-optional GOTO from VCAP IS2 lookup 0 to lookup 1.
0130      * We cannot change the PAG at this point.
0131      */
0132     for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
0133         if (chain == VCAP_IS2_CHAIN(0, pag))
0134             return (goto_target == VCAP_IS2_CHAIN(1, pag));
0135 
0136     /* VCAP IS2 lookup 1 can goto to PSFP block if hardware support */
0137     for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
0138         if (chain == VCAP_IS2_CHAIN(1, pag))
0139             return (goto_target == OCELOT_PSFP_CHAIN);
0140 
0141     return false;
0142 }
0143 
0144 static struct ocelot_vcap_filter *
0145 ocelot_find_vcap_filter_that_points_at(struct ocelot *ocelot, int chain)
0146 {
0147     struct ocelot_vcap_filter *filter;
0148     struct ocelot_vcap_block *block;
0149     int block_id;
0150 
0151     block_id = ocelot_chain_to_block(chain, true);
0152     if (block_id < 0)
0153         return NULL;
0154 
0155     if (block_id == VCAP_IS2) {
0156         block = &ocelot->block[VCAP_IS1];
0157 
0158         list_for_each_entry(filter, &block->rules, list)
0159             if (filter->type == OCELOT_VCAP_FILTER_PAG &&
0160                 filter->goto_target == chain)
0161                 return filter;
0162     }
0163 
0164     list_for_each_entry(filter, &ocelot->dummy_rules, list)
0165         if (filter->goto_target == chain)
0166             return filter;
0167 
0168     return NULL;
0169 }
0170 
0171 static int
0172 ocelot_flower_parse_ingress_vlan_modify(struct ocelot *ocelot, int port,
0173                     struct ocelot_vcap_filter *filter,
0174                     const struct flow_action_entry *a,
0175                     struct netlink_ext_ack *extack)
0176 {
0177     struct ocelot_port *ocelot_port = ocelot->ports[port];
0178 
0179     if (filter->goto_target != -1) {
0180         NL_SET_ERR_MSG_MOD(extack,
0181                    "Last action must be GOTO");
0182         return -EOPNOTSUPP;
0183     }
0184 
0185     if (!ocelot_port->vlan_aware) {
0186         NL_SET_ERR_MSG_MOD(extack,
0187                    "Can only modify VLAN under VLAN aware bridge");
0188         return -EOPNOTSUPP;
0189     }
0190 
0191     filter->action.vid_replace_ena = true;
0192     filter->action.pcp_dei_ena = true;
0193     filter->action.vid = a->vlan.vid;
0194     filter->action.pcp = a->vlan.prio;
0195     filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
0196 
0197     return 0;
0198 }
0199 
0200 static int
0201 ocelot_flower_parse_egress_vlan_modify(struct ocelot_vcap_filter *filter,
0202                        const struct flow_action_entry *a,
0203                        struct netlink_ext_ack *extack)
0204 {
0205     enum ocelot_tag_tpid_sel tpid;
0206 
0207     switch (ntohs(a->vlan.proto)) {
0208     case ETH_P_8021Q:
0209         tpid = OCELOT_TAG_TPID_SEL_8021Q;
0210         break;
0211     case ETH_P_8021AD:
0212         tpid = OCELOT_TAG_TPID_SEL_8021AD;
0213         break;
0214     default:
0215         NL_SET_ERR_MSG_MOD(extack,
0216                    "Cannot modify custom TPID");
0217         return -EOPNOTSUPP;
0218     }
0219 
0220     filter->action.tag_a_tpid_sel = tpid;
0221     filter->action.push_outer_tag = OCELOT_ES0_TAG;
0222     filter->action.tag_a_vid_sel = OCELOT_ES0_VID_PLUS_CLASSIFIED_VID;
0223     filter->action.vid_a_val = a->vlan.vid;
0224     filter->action.pcp_a_val = a->vlan.prio;
0225     filter->action.tag_a_pcp_sel = OCELOT_ES0_PCP;
0226     filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
0227 
0228     return 0;
0229 }
0230 
0231 static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
0232                       bool ingress, struct flow_cls_offload *f,
0233                       struct ocelot_vcap_filter *filter)
0234 {
0235     const struct flow_action *action = &f->rule->action;
0236     struct netlink_ext_ack *extack = f->common.extack;
0237     bool allow_missing_goto_target = false;
0238     const struct flow_action_entry *a;
0239     enum ocelot_tag_tpid_sel tpid;
0240     int i, chain, egress_port;
0241     u32 pol_ix, pol_max;
0242     u64 rate;
0243     int err;
0244 
0245     if (!flow_action_basic_hw_stats_check(&f->rule->action,
0246                           f->common.extack))
0247         return -EOPNOTSUPP;
0248 
0249     chain = f->common.chain_index;
0250     filter->block_id = ocelot_chain_to_block(chain, ingress);
0251     if (filter->block_id < 0) {
0252         NL_SET_ERR_MSG_MOD(extack, "Cannot offload to this chain");
0253         return -EOPNOTSUPP;
0254     }
0255     if (filter->block_id == VCAP_IS1 || filter->block_id == VCAP_IS2)
0256         filter->lookup = ocelot_chain_to_lookup(chain);
0257     if (filter->block_id == VCAP_IS2)
0258         filter->pag = ocelot_chain_to_pag(chain);
0259 
0260     filter->goto_target = -1;
0261     filter->type = OCELOT_VCAP_FILTER_DUMMY;
0262 
0263     flow_action_for_each(i, a, action) {
0264         switch (a->id) {
0265         case FLOW_ACTION_DROP:
0266             if (filter->block_id != VCAP_IS2) {
0267                 NL_SET_ERR_MSG_MOD(extack,
0268                            "Drop action can only be offloaded to VCAP IS2");
0269                 return -EOPNOTSUPP;
0270             }
0271             if (filter->goto_target != -1) {
0272                 NL_SET_ERR_MSG_MOD(extack,
0273                            "Last action must be GOTO");
0274                 return -EOPNOTSUPP;
0275             }
0276             filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY;
0277             filter->action.port_mask = 0;
0278             filter->action.police_ena = true;
0279             filter->action.pol_ix = OCELOT_POLICER_DISCARD;
0280             filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
0281             break;
0282         case FLOW_ACTION_ACCEPT:
0283             if (filter->block_id != VCAP_ES0 &&
0284                 filter->block_id != VCAP_IS1 &&
0285                 filter->block_id != VCAP_IS2) {
0286                 NL_SET_ERR_MSG_MOD(extack,
0287                            "Accept action can only be offloaded to VCAP chains");
0288                 return -EOPNOTSUPP;
0289             }
0290             if (filter->block_id != VCAP_ES0 &&
0291                 filter->goto_target != -1) {
0292                 NL_SET_ERR_MSG_MOD(extack,
0293                            "Last action must be GOTO");
0294                 return -EOPNOTSUPP;
0295             }
0296             filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
0297             break;
0298         case FLOW_ACTION_TRAP:
0299             if (filter->block_id != VCAP_IS2 ||
0300                 filter->lookup != 0) {
0301                 NL_SET_ERR_MSG_MOD(extack,
0302                            "Trap action can only be offloaded to VCAP IS2 lookup 0");
0303                 return -EOPNOTSUPP;
0304             }
0305             if (filter->goto_target != -1) {
0306                 NL_SET_ERR_MSG_MOD(extack,
0307                            "Last action must be GOTO");
0308                 return -EOPNOTSUPP;
0309             }
0310             filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY;
0311             filter->action.port_mask = 0;
0312             filter->action.cpu_copy_ena = true;
0313             filter->action.cpu_qu_num = 0;
0314             filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
0315             filter->is_trap = true;
0316             break;
0317         case FLOW_ACTION_POLICE:
0318             if (filter->block_id == PSFP_BLOCK_ID) {
0319                 filter->type = OCELOT_PSFP_FILTER_OFFLOAD;
0320                 break;
0321             }
0322             if (filter->block_id != VCAP_IS2 ||
0323                 filter->lookup != 0) {
0324                 NL_SET_ERR_MSG_MOD(extack,
0325                            "Police action can only be offloaded to VCAP IS2 lookup 0 or PSFP");
0326                 return -EOPNOTSUPP;
0327             }
0328             if (filter->goto_target != -1) {
0329                 NL_SET_ERR_MSG_MOD(extack,
0330                            "Last action must be GOTO");
0331                 return -EOPNOTSUPP;
0332             }
0333 
0334             err = ocelot_policer_validate(action, a, extack);
0335             if (err)
0336                 return err;
0337 
0338             filter->action.police_ena = true;
0339 
0340             pol_ix = a->hw_index + ocelot->vcap_pol.base;
0341             pol_max = ocelot->vcap_pol.max;
0342 
0343             if (ocelot->vcap_pol.max2 && pol_ix > pol_max) {
0344                 pol_ix += ocelot->vcap_pol.base2 - pol_max - 1;
0345                 pol_max = ocelot->vcap_pol.max2;
0346             }
0347 
0348             if (pol_ix >= pol_max)
0349                 return -EINVAL;
0350 
0351             filter->action.pol_ix = pol_ix;
0352 
0353             rate = a->police.rate_bytes_ps;
0354             filter->action.pol.rate = div_u64(rate, 1000) * 8;
0355             filter->action.pol.burst = a->police.burst;
0356             filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
0357             break;
0358         case FLOW_ACTION_REDIRECT:
0359             if (filter->block_id != VCAP_IS2) {
0360                 NL_SET_ERR_MSG_MOD(extack,
0361                            "Redirect action can only be offloaded to VCAP IS2");
0362                 return -EOPNOTSUPP;
0363             }
0364             if (filter->goto_target != -1) {
0365                 NL_SET_ERR_MSG_MOD(extack,
0366                            "Last action must be GOTO");
0367                 return -EOPNOTSUPP;
0368             }
0369             egress_port = ocelot->ops->netdev_to_port(a->dev);
0370             if (egress_port < 0) {
0371                 NL_SET_ERR_MSG_MOD(extack,
0372                            "Destination not an ocelot port");
0373                 return -EOPNOTSUPP;
0374             }
0375             filter->action.mask_mode = OCELOT_MASK_MODE_REDIRECT;
0376             filter->action.port_mask = BIT(egress_port);
0377             filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
0378             break;
0379         case FLOW_ACTION_MIRRED:
0380             if (filter->block_id != VCAP_IS2) {
0381                 NL_SET_ERR_MSG_MOD(extack,
0382                            "Mirror action can only be offloaded to VCAP IS2");
0383                 return -EOPNOTSUPP;
0384             }
0385             if (filter->goto_target != -1) {
0386                 NL_SET_ERR_MSG_MOD(extack,
0387                            "Last action must be GOTO");
0388                 return -EOPNOTSUPP;
0389             }
0390             egress_port = ocelot->ops->netdev_to_port(a->dev);
0391             if (egress_port < 0) {
0392                 NL_SET_ERR_MSG_MOD(extack,
0393                            "Destination not an ocelot port");
0394                 return -EOPNOTSUPP;
0395             }
0396             filter->egress_port.value = egress_port;
0397             filter->action.mirror_ena = true;
0398             filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
0399             break;
0400         case FLOW_ACTION_VLAN_POP:
0401             if (filter->block_id != VCAP_IS1) {
0402                 NL_SET_ERR_MSG_MOD(extack,
0403                            "VLAN pop action can only be offloaded to VCAP IS1");
0404                 return -EOPNOTSUPP;
0405             }
0406             if (filter->goto_target != -1) {
0407                 NL_SET_ERR_MSG_MOD(extack,
0408                            "Last action must be GOTO");
0409                 return -EOPNOTSUPP;
0410             }
0411             filter->action.vlan_pop_cnt_ena = true;
0412             filter->action.vlan_pop_cnt++;
0413             if (filter->action.vlan_pop_cnt > 2) {
0414                 NL_SET_ERR_MSG_MOD(extack,
0415                            "Cannot pop more than 2 VLAN headers");
0416                 return -EOPNOTSUPP;
0417             }
0418             filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
0419             break;
0420         case FLOW_ACTION_VLAN_MANGLE:
0421             if (filter->block_id == VCAP_IS1) {
0422                 err = ocelot_flower_parse_ingress_vlan_modify(ocelot, port,
0423                                           filter, a,
0424                                           extack);
0425             } else if (filter->block_id == VCAP_ES0) {
0426                 err = ocelot_flower_parse_egress_vlan_modify(filter, a,
0427                                          extack);
0428             } else {
0429                 NL_SET_ERR_MSG_MOD(extack,
0430                            "VLAN modify action can only be offloaded to VCAP IS1 or ES0");
0431                 err = -EOPNOTSUPP;
0432             }
0433             if (err)
0434                 return err;
0435             break;
0436         case FLOW_ACTION_PRIORITY:
0437             if (filter->block_id != VCAP_IS1) {
0438                 NL_SET_ERR_MSG_MOD(extack,
0439                            "Priority action can only be offloaded to VCAP IS1");
0440                 return -EOPNOTSUPP;
0441             }
0442             if (filter->goto_target != -1) {
0443                 NL_SET_ERR_MSG_MOD(extack,
0444                            "Last action must be GOTO");
0445                 return -EOPNOTSUPP;
0446             }
0447             filter->action.qos_ena = true;
0448             filter->action.qos_val = a->priority;
0449             filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
0450             break;
0451         case FLOW_ACTION_GOTO:
0452             filter->goto_target = a->chain_index;
0453 
0454             if (filter->block_id == VCAP_IS1 && filter->lookup == 2) {
0455                 int pag = ocelot_chain_to_pag(filter->goto_target);
0456 
0457                 filter->action.pag_override_mask = 0xff;
0458                 filter->action.pag_val = pag;
0459                 filter->type = OCELOT_VCAP_FILTER_PAG;
0460             }
0461             break;
0462         case FLOW_ACTION_VLAN_PUSH:
0463             if (filter->block_id != VCAP_ES0) {
0464                 NL_SET_ERR_MSG_MOD(extack,
0465                            "VLAN push action can only be offloaded to VCAP ES0");
0466                 return -EOPNOTSUPP;
0467             }
0468             switch (ntohs(a->vlan.proto)) {
0469             case ETH_P_8021Q:
0470                 tpid = OCELOT_TAG_TPID_SEL_8021Q;
0471                 break;
0472             case ETH_P_8021AD:
0473                 tpid = OCELOT_TAG_TPID_SEL_8021AD;
0474                 break;
0475             default:
0476                 NL_SET_ERR_MSG_MOD(extack,
0477                            "Cannot push custom TPID");
0478                 return -EOPNOTSUPP;
0479             }
0480             filter->action.tag_a_tpid_sel = tpid;
0481             filter->action.push_outer_tag = OCELOT_ES0_TAG;
0482             filter->action.tag_a_vid_sel = OCELOT_ES0_VID;
0483             filter->action.vid_a_val = a->vlan.vid;
0484             filter->action.pcp_a_val = a->vlan.prio;
0485             filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
0486             break;
0487         case FLOW_ACTION_GATE:
0488             if (filter->block_id != PSFP_BLOCK_ID) {
0489                 NL_SET_ERR_MSG_MOD(extack,
0490                            "Gate action can only be offloaded to PSFP chain");
0491                 return -EOPNOTSUPP;
0492             }
0493             filter->type = OCELOT_PSFP_FILTER_OFFLOAD;
0494             break;
0495         default:
0496             NL_SET_ERR_MSG_MOD(extack, "Cannot offload action");
0497             return -EOPNOTSUPP;
0498         }
0499     }
0500 
0501     if (filter->goto_target == -1) {
0502         if ((filter->block_id == VCAP_IS2 && filter->lookup == 1) ||
0503             chain == 0 || filter->block_id == PSFP_BLOCK_ID) {
0504             allow_missing_goto_target = true;
0505         } else {
0506             NL_SET_ERR_MSG_MOD(extack, "Missing GOTO action");
0507             return -EOPNOTSUPP;
0508         }
0509     }
0510 
0511     if (!ocelot_is_goto_target_valid(filter->goto_target, chain, ingress) &&
0512         !allow_missing_goto_target) {
0513         NL_SET_ERR_MSG_MOD(extack, "Cannot offload this GOTO target");
0514         return -EOPNOTSUPP;
0515     }
0516 
0517     return 0;
0518 }
0519 
0520 static int ocelot_flower_parse_indev(struct ocelot *ocelot, int port,
0521                      struct flow_cls_offload *f,
0522                      struct ocelot_vcap_filter *filter)
0523 {
0524     struct flow_rule *rule = flow_cls_offload_flow_rule(f);
0525     const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0];
0526     int key_length = vcap->keys[VCAP_ES0_IGR_PORT].length;
0527     struct netlink_ext_ack *extack = f->common.extack;
0528     struct net_device *dev, *indev;
0529     struct flow_match_meta match;
0530     int ingress_port;
0531 
0532     flow_rule_match_meta(rule, &match);
0533 
0534     if (!match.mask->ingress_ifindex)
0535         return 0;
0536 
0537     if (match.mask->ingress_ifindex != 0xFFFFFFFF) {
0538         NL_SET_ERR_MSG_MOD(extack, "Unsupported ingress ifindex mask");
0539         return -EOPNOTSUPP;
0540     }
0541 
0542     dev = ocelot->ops->port_to_netdev(ocelot, port);
0543     if (!dev)
0544         return -EINVAL;
0545 
0546     indev = __dev_get_by_index(dev_net(dev), match.key->ingress_ifindex);
0547     if (!indev) {
0548         NL_SET_ERR_MSG_MOD(extack,
0549                    "Can't find the ingress port to match on");
0550         return -ENOENT;
0551     }
0552 
0553     ingress_port = ocelot->ops->netdev_to_port(indev);
0554     if (ingress_port < 0) {
0555         NL_SET_ERR_MSG_MOD(extack,
0556                    "Can only offload an ocelot ingress port");
0557         return -EOPNOTSUPP;
0558     }
0559     if (ingress_port == port) {
0560         NL_SET_ERR_MSG_MOD(extack,
0561                    "Ingress port is equal to the egress port");
0562         return -EINVAL;
0563     }
0564 
0565     filter->ingress_port.value = ingress_port;
0566     filter->ingress_port.mask = GENMASK(key_length - 1, 0);
0567 
0568     return 0;
0569 }
0570 
0571 static int
0572 ocelot_flower_parse_key(struct ocelot *ocelot, int port, bool ingress,
0573             struct flow_cls_offload *f,
0574             struct ocelot_vcap_filter *filter)
0575 {
0576     struct flow_rule *rule = flow_cls_offload_flow_rule(f);
0577     struct flow_dissector *dissector = rule->match.dissector;
0578     struct netlink_ext_ack *extack = f->common.extack;
0579     u16 proto = ntohs(f->common.protocol);
0580     bool match_protocol = true;
0581     int ret;
0582 
0583     if (dissector->used_keys &
0584         ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
0585           BIT(FLOW_DISSECTOR_KEY_BASIC) |
0586           BIT(FLOW_DISSECTOR_KEY_META) |
0587           BIT(FLOW_DISSECTOR_KEY_PORTS) |
0588           BIT(FLOW_DISSECTOR_KEY_VLAN) |
0589           BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
0590           BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
0591           BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
0592         return -EOPNOTSUPP;
0593     }
0594 
0595     /* For VCAP ES0 (egress rewriter) we can match on the ingress port */
0596     if (!ingress) {
0597         ret = ocelot_flower_parse_indev(ocelot, port, f, filter);
0598         if (ret)
0599             return ret;
0600     }
0601 
0602     if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
0603         struct flow_match_control match;
0604 
0605         flow_rule_match_control(rule, &match);
0606     }
0607 
0608     if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
0609         struct flow_match_eth_addrs match;
0610 
0611         if (filter->block_id == VCAP_ES0) {
0612             NL_SET_ERR_MSG_MOD(extack,
0613                        "VCAP ES0 cannot match on MAC address");
0614             return -EOPNOTSUPP;
0615         }
0616 
0617         /* The hw support mac matches only for MAC_ETYPE key,
0618          * therefore if other matches(port, tcp flags, etc) are added
0619          * then just bail out
0620          */
0621         if ((dissector->used_keys &
0622             (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
0623              BIT(FLOW_DISSECTOR_KEY_BASIC) |
0624              BIT(FLOW_DISSECTOR_KEY_CONTROL))) !=
0625             (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
0626              BIT(FLOW_DISSECTOR_KEY_BASIC) |
0627              BIT(FLOW_DISSECTOR_KEY_CONTROL)))
0628             return -EOPNOTSUPP;
0629 
0630         flow_rule_match_eth_addrs(rule, &match);
0631 
0632         if (filter->block_id == VCAP_IS1 &&
0633             !is_zero_ether_addr(match.mask->dst)) {
0634             NL_SET_ERR_MSG_MOD(extack,
0635                        "Key type S1_NORMAL cannot match on destination MAC");
0636             return -EOPNOTSUPP;
0637         }
0638 
0639         filter->key_type = OCELOT_VCAP_KEY_ETYPE;
0640         ether_addr_copy(filter->key.etype.dmac.value,
0641                 match.key->dst);
0642         ether_addr_copy(filter->key.etype.smac.value,
0643                 match.key->src);
0644         ether_addr_copy(filter->key.etype.dmac.mask,
0645                 match.mask->dst);
0646         ether_addr_copy(filter->key.etype.smac.mask,
0647                 match.mask->src);
0648         goto finished_key_parsing;
0649     }
0650 
0651     if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
0652         struct flow_match_basic match;
0653 
0654         flow_rule_match_basic(rule, &match);
0655         if (ntohs(match.key->n_proto) == ETH_P_IP) {
0656             if (filter->block_id == VCAP_ES0) {
0657                 NL_SET_ERR_MSG_MOD(extack,
0658                            "VCAP ES0 cannot match on IP protocol");
0659                 return -EOPNOTSUPP;
0660             }
0661 
0662             filter->key_type = OCELOT_VCAP_KEY_IPV4;
0663             filter->key.ipv4.proto.value[0] =
0664                 match.key->ip_proto;
0665             filter->key.ipv4.proto.mask[0] =
0666                 match.mask->ip_proto;
0667             match_protocol = false;
0668         }
0669         if (ntohs(match.key->n_proto) == ETH_P_IPV6) {
0670             if (filter->block_id == VCAP_ES0) {
0671                 NL_SET_ERR_MSG_MOD(extack,
0672                            "VCAP ES0 cannot match on IP protocol");
0673                 return -EOPNOTSUPP;
0674             }
0675 
0676             filter->key_type = OCELOT_VCAP_KEY_IPV6;
0677             filter->key.ipv6.proto.value[0] =
0678                 match.key->ip_proto;
0679             filter->key.ipv6.proto.mask[0] =
0680                 match.mask->ip_proto;
0681             match_protocol = false;
0682         }
0683     }
0684 
0685     if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) &&
0686         proto == ETH_P_IP) {
0687         struct flow_match_ipv4_addrs match;
0688         u8 *tmp;
0689 
0690         if (filter->block_id == VCAP_ES0) {
0691             NL_SET_ERR_MSG_MOD(extack,
0692                        "VCAP ES0 cannot match on IP address");
0693             return -EOPNOTSUPP;
0694         }
0695 
0696         flow_rule_match_ipv4_addrs(rule, &match);
0697 
0698         if (filter->block_id == VCAP_IS1 && *(u32 *)&match.mask->dst) {
0699             NL_SET_ERR_MSG_MOD(extack,
0700                        "Key type S1_NORMAL cannot match on destination IP");
0701             return -EOPNOTSUPP;
0702         }
0703 
0704         tmp = &filter->key.ipv4.sip.value.addr[0];
0705         memcpy(tmp, &match.key->src, 4);
0706 
0707         tmp = &filter->key.ipv4.sip.mask.addr[0];
0708         memcpy(tmp, &match.mask->src, 4);
0709 
0710         tmp = &filter->key.ipv4.dip.value.addr[0];
0711         memcpy(tmp, &match.key->dst, 4);
0712 
0713         tmp = &filter->key.ipv4.dip.mask.addr[0];
0714         memcpy(tmp, &match.mask->dst, 4);
0715         match_protocol = false;
0716     }
0717 
0718     if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) &&
0719         proto == ETH_P_IPV6) {
0720         return -EOPNOTSUPP;
0721     }
0722 
0723     if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
0724         struct flow_match_ports match;
0725 
0726         if (filter->block_id == VCAP_ES0) {
0727             NL_SET_ERR_MSG_MOD(extack,
0728                        "VCAP ES0 cannot match on L4 ports");
0729             return -EOPNOTSUPP;
0730         }
0731 
0732         flow_rule_match_ports(rule, &match);
0733         filter->key.ipv4.sport.value = ntohs(match.key->src);
0734         filter->key.ipv4.sport.mask = ntohs(match.mask->src);
0735         filter->key.ipv4.dport.value = ntohs(match.key->dst);
0736         filter->key.ipv4.dport.mask = ntohs(match.mask->dst);
0737         match_protocol = false;
0738     }
0739 
0740     if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
0741         struct flow_match_vlan match;
0742 
0743         flow_rule_match_vlan(rule, &match);
0744         filter->key_type = OCELOT_VCAP_KEY_ANY;
0745         filter->vlan.vid.value = match.key->vlan_id;
0746         filter->vlan.vid.mask = match.mask->vlan_id;
0747         filter->vlan.pcp.value[0] = match.key->vlan_priority;
0748         filter->vlan.pcp.mask[0] = match.mask->vlan_priority;
0749         match_protocol = false;
0750     }
0751 
0752 finished_key_parsing:
0753     if (match_protocol && proto != ETH_P_ALL) {
0754         if (filter->block_id == VCAP_ES0) {
0755             NL_SET_ERR_MSG_MOD(extack,
0756                        "VCAP ES0 cannot match on L2 proto");
0757             return -EOPNOTSUPP;
0758         }
0759 
0760         /* TODO: support SNAP, LLC etc */
0761         if (proto < ETH_P_802_3_MIN)
0762             return -EOPNOTSUPP;
0763         filter->key_type = OCELOT_VCAP_KEY_ETYPE;
0764         *(__be16 *)filter->key.etype.etype.value = htons(proto);
0765         *(__be16 *)filter->key.etype.etype.mask = htons(0xffff);
0766     }
0767     /* else, a filter of type OCELOT_VCAP_KEY_ANY is implicitly added */
0768 
0769     return 0;
0770 }
0771 
0772 static int ocelot_flower_parse(struct ocelot *ocelot, int port, bool ingress,
0773                    struct flow_cls_offload *f,
0774                    struct ocelot_vcap_filter *filter)
0775 {
0776     int ret;
0777 
0778     filter->prio = f->common.prio;
0779     filter->id.cookie = f->cookie;
0780     filter->id.tc_offload = true;
0781 
0782     ret = ocelot_flower_parse_action(ocelot, port, ingress, f, filter);
0783     if (ret)
0784         return ret;
0785 
0786     /* PSFP filter need to parse key by stream identification function. */
0787     if (filter->type == OCELOT_PSFP_FILTER_OFFLOAD)
0788         return 0;
0789 
0790     return ocelot_flower_parse_key(ocelot, port, ingress, f, filter);
0791 }
0792 
0793 static struct ocelot_vcap_filter
0794 *ocelot_vcap_filter_create(struct ocelot *ocelot, int port, bool ingress,
0795                struct flow_cls_offload *f)
0796 {
0797     struct ocelot_vcap_filter *filter;
0798 
0799     filter = kzalloc(sizeof(*filter), GFP_KERNEL);
0800     if (!filter)
0801         return NULL;
0802 
0803     if (ingress) {
0804         filter->ingress_port_mask = BIT(port);
0805     } else {
0806         const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0];
0807         int key_length = vcap->keys[VCAP_ES0_EGR_PORT].length;
0808 
0809         filter->egress_port.value = port;
0810         filter->egress_port.mask = GENMASK(key_length - 1, 0);
0811     }
0812 
0813     return filter;
0814 }
0815 
0816 static int ocelot_vcap_dummy_filter_add(struct ocelot *ocelot,
0817                     struct ocelot_vcap_filter *filter)
0818 {
0819     list_add(&filter->list, &ocelot->dummy_rules);
0820 
0821     return 0;
0822 }
0823 
0824 static int ocelot_vcap_dummy_filter_del(struct ocelot *ocelot,
0825                     struct ocelot_vcap_filter *filter)
0826 {
0827     list_del(&filter->list);
0828     kfree(filter);
0829 
0830     return 0;
0831 }
0832 
0833 /* If we have an egress VLAN modification rule, we need to actually write the
0834  * delta between the input VLAN (from the key) and the output VLAN (from the
0835  * action), but the action was parsed first. So we need to patch the delta into
0836  * the action here.
0837  */
0838 static int
0839 ocelot_flower_patch_es0_vlan_modify(struct ocelot_vcap_filter *filter,
0840                     struct netlink_ext_ack *extack)
0841 {
0842     if (filter->block_id != VCAP_ES0 ||
0843         filter->action.tag_a_vid_sel != OCELOT_ES0_VID_PLUS_CLASSIFIED_VID)
0844         return 0;
0845 
0846     if (filter->vlan.vid.mask != VLAN_VID_MASK) {
0847         NL_SET_ERR_MSG_MOD(extack,
0848                    "VCAP ES0 VLAN rewriting needs a full VLAN in the key");
0849         return -EOPNOTSUPP;
0850     }
0851 
0852     filter->action.vid_a_val -= filter->vlan.vid.value;
0853     filter->action.vid_a_val &= VLAN_VID_MASK;
0854 
0855     return 0;
0856 }
0857 
0858 int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
0859                   struct flow_cls_offload *f, bool ingress)
0860 {
0861     struct netlink_ext_ack *extack = f->common.extack;
0862     struct ocelot_vcap_filter *filter;
0863     int chain = f->common.chain_index;
0864     int block_id, ret;
0865 
0866     if (chain && !ocelot_find_vcap_filter_that_points_at(ocelot, chain)) {
0867         NL_SET_ERR_MSG_MOD(extack, "No default GOTO action points to this chain");
0868         return -EOPNOTSUPP;
0869     }
0870 
0871     block_id = ocelot_chain_to_block(chain, ingress);
0872     if (block_id < 0) {
0873         NL_SET_ERR_MSG_MOD(extack, "Cannot offload to this chain");
0874         return -EOPNOTSUPP;
0875     }
0876 
0877     filter = ocelot_vcap_block_find_filter_by_id(&ocelot->block[block_id],
0878                              f->cookie, true);
0879     if (filter) {
0880         /* Filter already exists on other ports */
0881         if (!ingress) {
0882             NL_SET_ERR_MSG_MOD(extack, "VCAP ES0 does not support shared filters");
0883             return -EOPNOTSUPP;
0884         }
0885 
0886         filter->ingress_port_mask |= BIT(port);
0887 
0888         return ocelot_vcap_filter_replace(ocelot, filter);
0889     }
0890 
0891     /* Filter didn't exist, create it now */
0892     filter = ocelot_vcap_filter_create(ocelot, port, ingress, f);
0893     if (!filter)
0894         return -ENOMEM;
0895 
0896     ret = ocelot_flower_parse(ocelot, port, ingress, f, filter);
0897     if (ret) {
0898         kfree(filter);
0899         return ret;
0900     }
0901 
0902     ret = ocelot_flower_patch_es0_vlan_modify(filter, extack);
0903     if (ret) {
0904         kfree(filter);
0905         return ret;
0906     }
0907 
0908     /* The non-optional GOTOs for the TCAM skeleton don't need
0909      * to be actually offloaded.
0910      */
0911     if (filter->type == OCELOT_VCAP_FILTER_DUMMY)
0912         return ocelot_vcap_dummy_filter_add(ocelot, filter);
0913 
0914     if (filter->type == OCELOT_PSFP_FILTER_OFFLOAD) {
0915         kfree(filter);
0916         if (ocelot->ops->psfp_filter_add)
0917             return ocelot->ops->psfp_filter_add(ocelot, port, f);
0918 
0919         NL_SET_ERR_MSG_MOD(extack, "PSFP chain is not supported in HW");
0920         return -EOPNOTSUPP;
0921     }
0922 
0923     return ocelot_vcap_filter_add(ocelot, filter, f->common.extack);
0924 }
0925 EXPORT_SYMBOL_GPL(ocelot_cls_flower_replace);
0926 
0927 int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port,
0928                   struct flow_cls_offload *f, bool ingress)
0929 {
0930     struct ocelot_vcap_filter *filter;
0931     struct ocelot_vcap_block *block;
0932     int block_id;
0933 
0934     block_id = ocelot_chain_to_block(f->common.chain_index, ingress);
0935     if (block_id < 0)
0936         return 0;
0937 
0938     if (block_id == PSFP_BLOCK_ID) {
0939         if (ocelot->ops->psfp_filter_del)
0940             return ocelot->ops->psfp_filter_del(ocelot, f);
0941 
0942         return -EOPNOTSUPP;
0943     }
0944 
0945     block = &ocelot->block[block_id];
0946 
0947     filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true);
0948     if (!filter)
0949         return 0;
0950 
0951     if (filter->type == OCELOT_VCAP_FILTER_DUMMY)
0952         return ocelot_vcap_dummy_filter_del(ocelot, filter);
0953 
0954     if (ingress) {
0955         filter->ingress_port_mask &= ~BIT(port);
0956         if (filter->ingress_port_mask)
0957             return ocelot_vcap_filter_replace(ocelot, filter);
0958     }
0959 
0960     return ocelot_vcap_filter_del(ocelot, filter);
0961 }
0962 EXPORT_SYMBOL_GPL(ocelot_cls_flower_destroy);
0963 
0964 int ocelot_cls_flower_stats(struct ocelot *ocelot, int port,
0965                 struct flow_cls_offload *f, bool ingress)
0966 {
0967     struct ocelot_vcap_filter *filter;
0968     struct ocelot_vcap_block *block;
0969     struct flow_stats stats = {0};
0970     int block_id, ret;
0971 
0972     block_id = ocelot_chain_to_block(f->common.chain_index, ingress);
0973     if (block_id < 0)
0974         return 0;
0975 
0976     if (block_id == PSFP_BLOCK_ID) {
0977         if (ocelot->ops->psfp_stats_get) {
0978             ret = ocelot->ops->psfp_stats_get(ocelot, f, &stats);
0979             if (ret)
0980                 return ret;
0981 
0982             goto stats_update;
0983         }
0984 
0985         return -EOPNOTSUPP;
0986     }
0987 
0988     block = &ocelot->block[block_id];
0989 
0990     filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true);
0991     if (!filter || filter->type == OCELOT_VCAP_FILTER_DUMMY)
0992         return 0;
0993 
0994     ret = ocelot_vcap_filter_stats_update(ocelot, filter);
0995     if (ret)
0996         return ret;
0997 
0998     stats.pkts = filter->stats.pkts;
0999 
1000 stats_update:
1001     flow_stats_update(&f->stats, 0x0, stats.pkts, stats.drops, 0x0,
1002               FLOW_ACTION_HW_STATS_IMMEDIATE);
1003     return 0;
1004 }
1005 EXPORT_SYMBOL_GPL(ocelot_cls_flower_stats);