0001
0002
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
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 }