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_hw.h"
0009 #include "prestera_acl.h"
0010 #include "prestera_flow.h"
0011 #include "prestera_span.h"
0012 
0013 struct prestera_span_entry {
0014     struct list_head list;
0015     struct prestera_port *port;
0016     refcount_t ref_count;
0017     u8 id;
0018 };
0019 
0020 struct prestera_span {
0021     struct prestera_switch *sw;
0022     struct list_head entries;
0023 };
0024 
0025 static struct prestera_span_entry *
0026 prestera_span_entry_create(struct prestera_port *port, u8 span_id)
0027 {
0028     struct prestera_span_entry *entry;
0029 
0030     entry = kzalloc(sizeof(*entry), GFP_KERNEL);
0031     if (!entry)
0032         return ERR_PTR(-ENOMEM);
0033 
0034     refcount_set(&entry->ref_count, 1);
0035     entry->port = port;
0036     entry->id = span_id;
0037     list_add_tail(&entry->list, &port->sw->span->entries);
0038 
0039     return entry;
0040 }
0041 
0042 static void prestera_span_entry_del(struct prestera_span_entry *entry)
0043 {
0044     list_del(&entry->list);
0045     kfree(entry);
0046 }
0047 
0048 static struct prestera_span_entry *
0049 prestera_span_entry_find_by_id(struct prestera_span *span, u8 span_id)
0050 {
0051     struct prestera_span_entry *entry;
0052 
0053     list_for_each_entry(entry, &span->entries, list) {
0054         if (entry->id == span_id)
0055             return entry;
0056     }
0057 
0058     return NULL;
0059 }
0060 
0061 static struct prestera_span_entry *
0062 prestera_span_entry_find_by_port(struct prestera_span *span,
0063                  struct prestera_port *port)
0064 {
0065     struct prestera_span_entry *entry;
0066 
0067     list_for_each_entry(entry, &span->entries, list) {
0068         if (entry->port == port)
0069             return entry;
0070     }
0071 
0072     return NULL;
0073 }
0074 
0075 static int prestera_span_get(struct prestera_port *port, u8 *span_id)
0076 {
0077     u8 new_span_id;
0078     struct prestera_switch *sw = port->sw;
0079     struct prestera_span_entry *entry;
0080     int err;
0081 
0082     entry = prestera_span_entry_find_by_port(sw->span, port);
0083     if (entry) {
0084         refcount_inc(&entry->ref_count);
0085         *span_id = entry->id;
0086         return 0;
0087     }
0088 
0089     err = prestera_hw_span_get(port, &new_span_id);
0090     if (err)
0091         return err;
0092 
0093     entry = prestera_span_entry_create(port, new_span_id);
0094     if (IS_ERR(entry)) {
0095         prestera_hw_span_release(sw, new_span_id);
0096         return PTR_ERR(entry);
0097     }
0098 
0099     *span_id = new_span_id;
0100     return 0;
0101 }
0102 
0103 static int prestera_span_put(struct prestera_switch *sw, u8 span_id)
0104 {
0105     struct prestera_span_entry *entry;
0106     int err;
0107 
0108     entry = prestera_span_entry_find_by_id(sw->span, span_id);
0109     if (!entry)
0110         return false;
0111 
0112     if (!refcount_dec_and_test(&entry->ref_count))
0113         return 0;
0114 
0115     err = prestera_hw_span_release(sw, span_id);
0116     if (err)
0117         return err;
0118 
0119     prestera_span_entry_del(entry);
0120     return 0;
0121 }
0122 
0123 static int prestera_span_rule_add(struct prestera_flow_block_binding *binding,
0124                   struct prestera_port *to_port)
0125 {
0126     struct prestera_switch *sw = binding->port->sw;
0127     u8 span_id;
0128     int err;
0129 
0130     if (binding->span_id != PRESTERA_SPAN_INVALID_ID)
0131         /* port already in mirroring */
0132         return -EEXIST;
0133 
0134     err = prestera_span_get(to_port, &span_id);
0135     if (err)
0136         return err;
0137 
0138     err = prestera_hw_span_bind(binding->port, span_id);
0139     if (err) {
0140         prestera_span_put(sw, span_id);
0141         return err;
0142     }
0143 
0144     binding->span_id = span_id;
0145     return 0;
0146 }
0147 
0148 static int prestera_span_rule_del(struct prestera_flow_block_binding *binding)
0149 {
0150     int err;
0151 
0152     err = prestera_hw_span_unbind(binding->port);
0153     if (err)
0154         return err;
0155 
0156     err = prestera_span_put(binding->port->sw, binding->span_id);
0157     if (err)
0158         return err;
0159 
0160     binding->span_id = PRESTERA_SPAN_INVALID_ID;
0161     return 0;
0162 }
0163 
0164 int prestera_span_replace(struct prestera_flow_block *block,
0165               struct tc_cls_matchall_offload *f)
0166 {
0167     struct prestera_flow_block_binding *binding;
0168     __be16 protocol = f->common.protocol;
0169     struct flow_action_entry *act;
0170     struct prestera_port *port;
0171     int err;
0172 
0173     if (!flow_offload_has_one_action(&f->rule->action)) {
0174         NL_SET_ERR_MSG(f->common.extack,
0175                    "Only singular actions are supported");
0176         return -EOPNOTSUPP;
0177     }
0178 
0179     act = &f->rule->action.entries[0];
0180 
0181     if (!prestera_netdev_check(act->dev)) {
0182         NL_SET_ERR_MSG(f->common.extack,
0183                    "Only Marvell Prestera port is supported");
0184         return -EINVAL;
0185     }
0186     if (!tc_cls_can_offload_and_chain0(act->dev, &f->common))
0187         return -EOPNOTSUPP;
0188     if (act->id != FLOW_ACTION_MIRRED)
0189         return -EOPNOTSUPP;
0190     if (protocol != htons(ETH_P_ALL))
0191         return -EOPNOTSUPP;
0192 
0193     port = netdev_priv(act->dev);
0194 
0195     list_for_each_entry(binding, &block->binding_list, list) {
0196         err = prestera_span_rule_add(binding, port);
0197         if (err)
0198             goto rollback;
0199     }
0200 
0201     return 0;
0202 
0203 rollback:
0204     list_for_each_entry_continue_reverse(binding,
0205                          &block->binding_list, list)
0206         prestera_span_rule_del(binding);
0207     return err;
0208 }
0209 
0210 void prestera_span_destroy(struct prestera_flow_block *block)
0211 {
0212     struct prestera_flow_block_binding *binding;
0213 
0214     list_for_each_entry(binding, &block->binding_list, list)
0215         prestera_span_rule_del(binding);
0216 }
0217 
0218 int prestera_span_init(struct prestera_switch *sw)
0219 {
0220     struct prestera_span *span;
0221 
0222     span = kzalloc(sizeof(*span), GFP_KERNEL);
0223     if (!span)
0224         return -ENOMEM;
0225 
0226     INIT_LIST_HEAD(&span->entries);
0227 
0228     sw->span = span;
0229     span->sw = sw;
0230 
0231     return 0;
0232 }
0233 
0234 void prestera_span_fini(struct prestera_switch *sw)
0235 {
0236     struct prestera_span *span = sw->span;
0237 
0238     WARN_ON(!list_empty(&span->entries));
0239     kfree(span);
0240 }