Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /* Copyright (c) 2020 Marvell International Ltd. All rights reserved */
0003 
0004 #include <linux/kernel.h>
0005 #include <linux/list.h>
0006 
0007 #include "prestera.h"
0008 #include "prestera_acl.h"
0009 #include "prestera_flow.h"
0010 #include "prestera_span.h"
0011 #include "prestera_flower.h"
0012 
0013 static LIST_HEAD(prestera_block_cb_list);
0014 
0015 static int prestera_flow_block_mall_cb(struct prestera_flow_block *block,
0016                        struct tc_cls_matchall_offload *f)
0017 {
0018     switch (f->command) {
0019     case TC_CLSMATCHALL_REPLACE:
0020         return prestera_span_replace(block, f);
0021     case TC_CLSMATCHALL_DESTROY:
0022         prestera_span_destroy(block);
0023         return 0;
0024     default:
0025         return -EOPNOTSUPP;
0026     }
0027 }
0028 
0029 static int prestera_flow_block_flower_cb(struct prestera_flow_block *block,
0030                      struct flow_cls_offload *f)
0031 {
0032     switch (f->command) {
0033     case FLOW_CLS_REPLACE:
0034         return prestera_flower_replace(block, f);
0035     case FLOW_CLS_DESTROY:
0036         prestera_flower_destroy(block, f);
0037         return 0;
0038     case FLOW_CLS_STATS:
0039         return prestera_flower_stats(block, f);
0040     case FLOW_CLS_TMPLT_CREATE:
0041         return prestera_flower_tmplt_create(block, f);
0042     case FLOW_CLS_TMPLT_DESTROY:
0043         prestera_flower_tmplt_destroy(block, f);
0044         return 0;
0045     default:
0046         return -EOPNOTSUPP;
0047     }
0048 }
0049 
0050 static int prestera_flow_block_cb(enum tc_setup_type type,
0051                   void *type_data, void *cb_priv)
0052 {
0053     struct prestera_flow_block *block = cb_priv;
0054 
0055     switch (type) {
0056     case TC_SETUP_CLSFLOWER:
0057         return prestera_flow_block_flower_cb(block, type_data);
0058     case TC_SETUP_CLSMATCHALL:
0059         return prestera_flow_block_mall_cb(block, type_data);
0060     default:
0061         return -EOPNOTSUPP;
0062     }
0063 }
0064 
0065 static void prestera_flow_block_destroy(void *cb_priv)
0066 {
0067     struct prestera_flow_block *block = cb_priv;
0068 
0069     prestera_flower_template_cleanup(block);
0070 
0071     WARN_ON(!list_empty(&block->template_list));
0072     WARN_ON(!list_empty(&block->binding_list));
0073 
0074     kfree(block);
0075 }
0076 
0077 static struct prestera_flow_block *
0078 prestera_flow_block_create(struct prestera_switch *sw,
0079                struct net *net,
0080                bool ingress)
0081 {
0082     struct prestera_flow_block *block;
0083 
0084     block = kzalloc(sizeof(*block), GFP_KERNEL);
0085     if (!block)
0086         return NULL;
0087 
0088     INIT_LIST_HEAD(&block->binding_list);
0089     INIT_LIST_HEAD(&block->template_list);
0090     block->net = net;
0091     block->sw = sw;
0092     block->ingress = ingress;
0093 
0094     return block;
0095 }
0096 
0097 static void prestera_flow_block_release(void *cb_priv)
0098 {
0099     struct prestera_flow_block *block = cb_priv;
0100 
0101     prestera_flow_block_destroy(block);
0102 }
0103 
0104 static bool
0105 prestera_flow_block_is_bound(const struct prestera_flow_block *block)
0106 {
0107     return block->ruleset_zero;
0108 }
0109 
0110 static struct prestera_flow_block_binding *
0111 prestera_flow_block_lookup(struct prestera_flow_block *block,
0112                struct prestera_port *port)
0113 {
0114     struct prestera_flow_block_binding *binding;
0115 
0116     list_for_each_entry(binding, &block->binding_list, list)
0117         if (binding->port == port)
0118             return binding;
0119 
0120     return NULL;
0121 }
0122 
0123 static int prestera_flow_block_bind(struct prestera_flow_block *block,
0124                     struct prestera_port *port)
0125 {
0126     struct prestera_flow_block_binding *binding;
0127     int err;
0128 
0129     binding = kzalloc(sizeof(*binding), GFP_KERNEL);
0130     if (!binding)
0131         return -ENOMEM;
0132 
0133     binding->span_id = PRESTERA_SPAN_INVALID_ID;
0134     binding->port = port;
0135 
0136     if (prestera_flow_block_is_bound(block)) {
0137         err = prestera_acl_ruleset_bind(block->ruleset_zero, port);
0138         if (err)
0139             goto err_ruleset_bind;
0140     }
0141 
0142     list_add(&binding->list, &block->binding_list);
0143     return 0;
0144 
0145 err_ruleset_bind:
0146     kfree(binding);
0147     return err;
0148 }
0149 
0150 static int prestera_flow_block_unbind(struct prestera_flow_block *block,
0151                       struct prestera_port *port)
0152 {
0153     struct prestera_flow_block_binding *binding;
0154 
0155     binding = prestera_flow_block_lookup(block, port);
0156     if (!binding)
0157         return -ENOENT;
0158 
0159     list_del(&binding->list);
0160 
0161     if (prestera_flow_block_is_bound(block))
0162         prestera_acl_ruleset_unbind(block->ruleset_zero, port);
0163 
0164     kfree(binding);
0165     return 0;
0166 }
0167 
0168 static struct prestera_flow_block *
0169 prestera_flow_block_get(struct prestera_switch *sw,
0170             struct flow_block_offload *f,
0171             bool *register_block,
0172             bool ingress)
0173 {
0174     struct prestera_flow_block *block;
0175     struct flow_block_cb *block_cb;
0176 
0177     block_cb = flow_block_cb_lookup(f->block,
0178                     prestera_flow_block_cb, sw);
0179     if (!block_cb) {
0180         block = prestera_flow_block_create(sw, f->net, ingress);
0181         if (!block)
0182             return ERR_PTR(-ENOMEM);
0183 
0184         block_cb = flow_block_cb_alloc(prestera_flow_block_cb,
0185                            sw, block,
0186                            prestera_flow_block_release);
0187         if (IS_ERR(block_cb)) {
0188             prestera_flow_block_destroy(block);
0189             return ERR_CAST(block_cb);
0190         }
0191 
0192         block->block_cb = block_cb;
0193         *register_block = true;
0194     } else {
0195         block = flow_block_cb_priv(block_cb);
0196         *register_block = false;
0197     }
0198 
0199     flow_block_cb_incref(block_cb);
0200 
0201     return block;
0202 }
0203 
0204 static void prestera_flow_block_put(struct prestera_flow_block *block)
0205 {
0206     struct flow_block_cb *block_cb = block->block_cb;
0207 
0208     if (flow_block_cb_decref(block_cb))
0209         return;
0210 
0211     flow_block_cb_free(block_cb);
0212     prestera_flow_block_destroy(block);
0213 }
0214 
0215 static int prestera_setup_flow_block_bind(struct prestera_port *port,
0216                       struct flow_block_offload *f, bool ingress)
0217 {
0218     struct prestera_switch *sw = port->sw;
0219     struct prestera_flow_block *block;
0220     struct flow_block_cb *block_cb;
0221     bool register_block;
0222     int err;
0223 
0224     block = prestera_flow_block_get(sw, f, &register_block, ingress);
0225     if (IS_ERR(block))
0226         return PTR_ERR(block);
0227 
0228     block_cb = block->block_cb;
0229 
0230     err = prestera_flow_block_bind(block, port);
0231     if (err)
0232         goto err_block_bind;
0233 
0234     if (register_block) {
0235         flow_block_cb_add(block_cb, f);
0236         list_add_tail(&block_cb->driver_list, &prestera_block_cb_list);
0237     }
0238 
0239     if (ingress)
0240         port->ingress_flow_block = block;
0241     else
0242         port->egress_flow_block = block;
0243 
0244     return 0;
0245 
0246 err_block_bind:
0247     prestera_flow_block_put(block);
0248 
0249     return err;
0250 }
0251 
0252 static void prestera_setup_flow_block_unbind(struct prestera_port *port,
0253                          struct flow_block_offload *f, bool ingress)
0254 {
0255     struct prestera_switch *sw = port->sw;
0256     struct prestera_flow_block *block;
0257     struct flow_block_cb *block_cb;
0258     int err;
0259 
0260     block_cb = flow_block_cb_lookup(f->block, prestera_flow_block_cb, sw);
0261     if (!block_cb)
0262         return;
0263 
0264     block = flow_block_cb_priv(block_cb);
0265 
0266     prestera_span_destroy(block);
0267 
0268     err = prestera_flow_block_unbind(block, port);
0269     if (err)
0270         goto error;
0271 
0272     if (!flow_block_cb_decref(block_cb)) {
0273         flow_block_cb_remove(block_cb, f);
0274         list_del(&block_cb->driver_list);
0275     }
0276 error:
0277     if (ingress)
0278         port->ingress_flow_block = NULL;
0279     else
0280         port->egress_flow_block = NULL;
0281 }
0282 
0283 static int prestera_setup_flow_block_clsact(struct prestera_port *port,
0284                         struct flow_block_offload *f,
0285                         bool ingress)
0286 {
0287     f->driver_block_list = &prestera_block_cb_list;
0288 
0289     switch (f->command) {
0290     case FLOW_BLOCK_BIND:
0291         return prestera_setup_flow_block_bind(port, f, ingress);
0292     case FLOW_BLOCK_UNBIND:
0293         prestera_setup_flow_block_unbind(port, f, ingress);
0294         return 0;
0295     default:
0296         return -EOPNOTSUPP;
0297     }
0298 }
0299 
0300 int prestera_flow_block_setup(struct prestera_port *port,
0301                   struct flow_block_offload *f)
0302 {
0303     switch (f->binder_type) {
0304     case FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS:
0305         return prestera_setup_flow_block_clsact(port, f, true);
0306     case FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS:
0307         return prestera_setup_flow_block_clsact(port, f, false);
0308     default:
0309         return -EOPNOTSUPP;
0310     }
0311 }