diff options
author | Petr Machata <petrm@mellanox.com> | 2018-02-27 08:53:45 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-02-27 14:46:27 -0500 |
commit | 169b5d95c15e01e08e1665bd8ceaff9bf8331c33 (patch) | |
tree | 7f3d639812d0cb52aed9143e2e3069633dd76614 | |
parent | 079c9f393b8d467995516c4716557373edefaa89 (diff) |
mlxsw: spectrum_span: Generalize SPAN support
To support mirroring to different device types, the functions that
partake in configuring the port analyzer need to be extended to admit
non-trivial SPAN types.
Create a structure where all details of SPAN configuration are kept,
struct mlxsw_sp_span_parms. Also create struct mlxsw_sp_span_entry_ops
to keep per-SPAN-type operations.
Instantiate the latter once for MLXSW_REG_MPAT_SPAN_TYPE_LOCAL_ETH, and
once for a suite of NOP callbacks used for invalidated SPAN entry. Put
the formet as a sole member of a new array mlxsw_sp_span_entry_types,
where all known SPAN types are kept. Introduce a new function,
mlxsw_sp_span_entry_ops(), to look up the right ops suite given a
netdevice.
Change mlxsw_sp_span_mirror_add() to use both parms and ops structures.
Change mlxsw_sp_span_entry_get() and mlxsw_sp_span_entry_create() to
take these as arguments. Modify mlxsw_sp_span_entry_configure() and
mlxsw_sp_span_entry_deconfigure() to dispatch to ops.
Signed-off-by: Petr Machata <petrm@mellanox.com>
Reviewed-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 5 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c | 155 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h | 17 |
4 files changed, 147 insertions, 33 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 86991db3478c..b070cad8dba7 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c | |||
@@ -1266,11 +1266,6 @@ mlxsw_sp_port_add_cls_matchall_mirror(struct mlxsw_sp_port *mlxsw_sp_port, | |||
1266 | return -EINVAL; | 1266 | return -EINVAL; |
1267 | } | 1267 | } |
1268 | 1268 | ||
1269 | if (!mlxsw_sp_port_dev_check(to_dev)) { | ||
1270 | netdev_err(mlxsw_sp_port->dev, "Cannot mirror to a non-spectrum port"); | ||
1271 | return -EOPNOTSUPP; | ||
1272 | } | ||
1273 | |||
1274 | mirror->ingress = ingress; | 1269 | mirror->ingress = ingress; |
1275 | span_type = ingress ? MLXSW_SP_SPAN_INGRESS : MLXSW_SP_SPAN_EGRESS; | 1270 | span_type = ingress ? MLXSW_SP_SPAN_INGRESS : MLXSW_SP_SPAN_EGRESS; |
1276 | return mlxsw_sp_span_mirror_add(mlxsw_sp_port, to_dev, span_type, | 1271 | return mlxsw_sp_span_mirror_add(mlxsw_sp_port, to_dev, span_type, |
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c index 50f5eacdfa24..9d7197b9abb1 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c | |||
@@ -581,9 +581,6 @@ int mlxsw_sp_acl_rulei_act_mirror(struct mlxsw_sp *mlxsw_sp, | |||
581 | binding = list_first_entry(&block->binding_list, | 581 | binding = list_first_entry(&block->binding_list, |
582 | struct mlxsw_sp_acl_block_binding, list); | 582 | struct mlxsw_sp_acl_block_binding, list); |
583 | in_port = binding->mlxsw_sp_port; | 583 | in_port = binding->mlxsw_sp_port; |
584 | if (!mlxsw_sp_port_dev_check(out_dev)) | ||
585 | return -EINVAL; | ||
586 | |||
587 | out_port = netdev_priv(out_dev); | 584 | out_port = netdev_priv(out_dev); |
588 | if (out_port->mlxsw_sp != mlxsw_sp) | 585 | if (out_port->mlxsw_sp != mlxsw_sp) |
589 | return -EINVAL; | 586 | return -EINVAL; |
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c index 9819cdcf9e5c..c0e0e9af2da7 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c | |||
@@ -74,40 +74,120 @@ void mlxsw_sp_span_fini(struct mlxsw_sp *mlxsw_sp) | |||
74 | } | 74 | } |
75 | 75 | ||
76 | static int | 76 | static int |
77 | mlxsw_sp_span_entry_configure(struct mlxsw_sp *mlxsw_sp, | 77 | mlxsw_sp_span_entry_phys_parms(const struct net_device *to_dev, |
78 | struct mlxsw_sp_span_entry *span_entry, | 78 | struct mlxsw_sp_span_parms *sparmsp) |
79 | u8 local_port) | 79 | { |
80 | sparmsp->dest_port = netdev_priv(to_dev); | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static int | ||
85 | mlxsw_sp_span_entry_phys_configure(struct mlxsw_sp_span_entry *span_entry, | ||
86 | struct mlxsw_sp_span_parms sparms) | ||
80 | { | 87 | { |
88 | struct mlxsw_sp_port *dest_port = sparms.dest_port; | ||
89 | struct mlxsw_sp *mlxsw_sp = dest_port->mlxsw_sp; | ||
90 | u8 local_port = dest_port->local_port; | ||
81 | char mpat_pl[MLXSW_REG_MPAT_LEN]; | 91 | char mpat_pl[MLXSW_REG_MPAT_LEN]; |
82 | int pa_id = span_entry->id; | 92 | int pa_id = span_entry->id; |
83 | 93 | ||
84 | /* Create a new port analayzer entry for local_port. */ | 94 | /* Create a new port analayzer entry for local_port. */ |
85 | mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, true, | 95 | mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, true, |
86 | MLXSW_REG_MPAT_SPAN_TYPE_LOCAL_ETH); | 96 | MLXSW_REG_MPAT_SPAN_TYPE_LOCAL_ETH); |
97 | |||
87 | return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl); | 98 | return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl); |
88 | } | 99 | } |
89 | 100 | ||
90 | static void | 101 | static void |
91 | mlxsw_sp_span_entry_deconfigure(struct mlxsw_sp *mlxsw_sp, | 102 | mlxsw_sp_span_entry_deconfigure_common(struct mlxsw_sp_span_entry *span_entry, |
92 | struct mlxsw_sp_span_entry *span_entry) | 103 | enum mlxsw_reg_mpat_span_type span_type) |
93 | { | 104 | { |
94 | struct mlxsw_sp_port *to_port = netdev_priv(span_entry->to_dev); | 105 | struct mlxsw_sp_port *dest_port = span_entry->parms.dest_port; |
95 | u8 local_port = to_port->local_port; | 106 | struct mlxsw_sp *mlxsw_sp = dest_port->mlxsw_sp; |
107 | u8 local_port = dest_port->local_port; | ||
96 | char mpat_pl[MLXSW_REG_MPAT_LEN]; | 108 | char mpat_pl[MLXSW_REG_MPAT_LEN]; |
97 | int pa_id = span_entry->id; | 109 | int pa_id = span_entry->id; |
98 | 110 | ||
99 | mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, false, | 111 | mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, false, span_type); |
100 | MLXSW_REG_MPAT_SPAN_TYPE_LOCAL_ETH); | ||
101 | mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl); | 112 | mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl); |
102 | } | 113 | } |
103 | 114 | ||
115 | static void | ||
116 | mlxsw_sp_span_entry_phys_deconfigure(struct mlxsw_sp_span_entry *span_entry) | ||
117 | { | ||
118 | mlxsw_sp_span_entry_deconfigure_common(span_entry, | ||
119 | MLXSW_REG_MPAT_SPAN_TYPE_LOCAL_ETH); | ||
120 | } | ||
121 | |||
122 | static const | ||
123 | struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_phys = { | ||
124 | .can_handle = mlxsw_sp_port_dev_check, | ||
125 | .parms = mlxsw_sp_span_entry_phys_parms, | ||
126 | .configure = mlxsw_sp_span_entry_phys_configure, | ||
127 | .deconfigure = mlxsw_sp_span_entry_phys_deconfigure, | ||
128 | }; | ||
129 | |||
130 | static const | ||
131 | struct mlxsw_sp_span_entry_ops *const mlxsw_sp_span_entry_types[] = { | ||
132 | &mlxsw_sp_span_entry_ops_phys, | ||
133 | }; | ||
134 | |||
135 | static int | ||
136 | mlxsw_sp_span_entry_nop_parms(const struct net_device *to_dev, | ||
137 | struct mlxsw_sp_span_parms *sparmsp) | ||
138 | { | ||
139 | sparmsp->dest_port = NULL; | ||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static int | ||
144 | mlxsw_sp_span_entry_nop_configure(struct mlxsw_sp_span_entry *span_entry, | ||
145 | struct mlxsw_sp_span_parms sparms) | ||
146 | { | ||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | static void | ||
151 | mlxsw_sp_span_entry_nop_deconfigure(struct mlxsw_sp_span_entry *span_entry) | ||
152 | { | ||
153 | } | ||
154 | |||
155 | static const struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_nop = { | ||
156 | .parms = mlxsw_sp_span_entry_nop_parms, | ||
157 | .configure = mlxsw_sp_span_entry_nop_configure, | ||
158 | .deconfigure = mlxsw_sp_span_entry_nop_deconfigure, | ||
159 | }; | ||
160 | |||
161 | static void | ||
162 | mlxsw_sp_span_entry_configure(struct mlxsw_sp *mlxsw_sp, | ||
163 | struct mlxsw_sp_span_entry *span_entry, | ||
164 | struct mlxsw_sp_span_parms sparms) | ||
165 | { | ||
166 | if (sparms.dest_port) { | ||
167 | if (span_entry->ops->configure(span_entry, sparms)) { | ||
168 | netdev_err(span_entry->to_dev, "Failed to offload mirror to %s", | ||
169 | sparms.dest_port->dev->name); | ||
170 | sparms.dest_port = NULL; | ||
171 | } | ||
172 | } | ||
173 | |||
174 | span_entry->parms = sparms; | ||
175 | } | ||
176 | |||
177 | static void | ||
178 | mlxsw_sp_span_entry_deconfigure(struct mlxsw_sp_span_entry *span_entry) | ||
179 | { | ||
180 | if (span_entry->parms.dest_port) | ||
181 | span_entry->ops->deconfigure(span_entry); | ||
182 | } | ||
183 | |||
104 | static struct mlxsw_sp_span_entry * | 184 | static struct mlxsw_sp_span_entry * |
105 | mlxsw_sp_span_entry_create(struct mlxsw_sp *mlxsw_sp, | 185 | mlxsw_sp_span_entry_create(struct mlxsw_sp *mlxsw_sp, |
106 | const struct net_device *to_dev) | 186 | const struct net_device *to_dev, |
187 | const struct mlxsw_sp_span_entry_ops *ops, | ||
188 | struct mlxsw_sp_span_parms sparms) | ||
107 | { | 189 | { |
108 | struct mlxsw_sp_port *to_port = netdev_priv(to_dev); | ||
109 | struct mlxsw_sp_span_entry *span_entry = NULL; | 190 | struct mlxsw_sp_span_entry *span_entry = NULL; |
110 | u8 local_port = to_port->local_port; | ||
111 | int i; | 191 | int i; |
112 | 192 | ||
113 | /* find a free entry to use */ | 193 | /* find a free entry to use */ |
@@ -120,19 +200,17 @@ mlxsw_sp_span_entry_create(struct mlxsw_sp *mlxsw_sp, | |||
120 | if (!span_entry) | 200 | if (!span_entry) |
121 | return NULL; | 201 | return NULL; |
122 | 202 | ||
123 | if (mlxsw_sp_span_entry_configure(mlxsw_sp, span_entry, local_port)) | 203 | span_entry->ops = ops; |
124 | return NULL; | ||
125 | |||
126 | span_entry->ref_count = 1; | 204 | span_entry->ref_count = 1; |
127 | span_entry->to_dev = to_dev; | 205 | span_entry->to_dev = to_dev; |
206 | mlxsw_sp_span_entry_configure(mlxsw_sp, span_entry, sparms); | ||
207 | |||
128 | return span_entry; | 208 | return span_entry; |
129 | } | 209 | } |
130 | 210 | ||
131 | static void mlxsw_sp_span_entry_destroy(struct mlxsw_sp *mlxsw_sp, | 211 | static void mlxsw_sp_span_entry_destroy(struct mlxsw_sp_span_entry *span_entry) |
132 | struct mlxsw_sp_span_entry *span_entry) | ||
133 | { | 212 | { |
134 | if (span_entry->to_dev) | 213 | mlxsw_sp_span_entry_deconfigure(span_entry); |
135 | mlxsw_sp_span_entry_deconfigure(mlxsw_sp, span_entry); | ||
136 | } | 214 | } |
137 | 215 | ||
138 | struct mlxsw_sp_span_entry * | 216 | struct mlxsw_sp_span_entry * |
@@ -153,8 +231,8 @@ mlxsw_sp_span_entry_find_by_port(struct mlxsw_sp *mlxsw_sp, | |||
153 | void mlxsw_sp_span_entry_invalidate(struct mlxsw_sp *mlxsw_sp, | 231 | void mlxsw_sp_span_entry_invalidate(struct mlxsw_sp *mlxsw_sp, |
154 | struct mlxsw_sp_span_entry *span_entry) | 232 | struct mlxsw_sp_span_entry *span_entry) |
155 | { | 233 | { |
156 | mlxsw_sp_span_entry_deconfigure(mlxsw_sp, span_entry); | 234 | mlxsw_sp_span_entry_deconfigure(span_entry); |
157 | span_entry->to_dev = NULL; | 235 | span_entry->ops = &mlxsw_sp_span_entry_ops_nop; |
158 | } | 236 | } |
159 | 237 | ||
160 | static struct mlxsw_sp_span_entry * | 238 | static struct mlxsw_sp_span_entry * |
@@ -173,7 +251,9 @@ mlxsw_sp_span_entry_find_by_id(struct mlxsw_sp *mlxsw_sp, int span_id) | |||
173 | 251 | ||
174 | static struct mlxsw_sp_span_entry * | 252 | static struct mlxsw_sp_span_entry * |
175 | mlxsw_sp_span_entry_get(struct mlxsw_sp *mlxsw_sp, | 253 | mlxsw_sp_span_entry_get(struct mlxsw_sp *mlxsw_sp, |
176 | const struct net_device *to_dev) | 254 | const struct net_device *to_dev, |
255 | const struct mlxsw_sp_span_entry_ops *ops, | ||
256 | struct mlxsw_sp_span_parms sparms) | ||
177 | { | 257 | { |
178 | struct mlxsw_sp_span_entry *span_entry; | 258 | struct mlxsw_sp_span_entry *span_entry; |
179 | 259 | ||
@@ -184,7 +264,7 @@ mlxsw_sp_span_entry_get(struct mlxsw_sp *mlxsw_sp, | |||
184 | return span_entry; | 264 | return span_entry; |
185 | } | 265 | } |
186 | 266 | ||
187 | return mlxsw_sp_span_entry_create(mlxsw_sp, to_dev); | 267 | return mlxsw_sp_span_entry_create(mlxsw_sp, to_dev, ops, sparms); |
188 | } | 268 | } |
189 | 269 | ||
190 | static int mlxsw_sp_span_entry_put(struct mlxsw_sp *mlxsw_sp, | 270 | static int mlxsw_sp_span_entry_put(struct mlxsw_sp *mlxsw_sp, |
@@ -192,7 +272,7 @@ static int mlxsw_sp_span_entry_put(struct mlxsw_sp *mlxsw_sp, | |||
192 | { | 272 | { |
193 | WARN_ON(!span_entry->ref_count); | 273 | WARN_ON(!span_entry->ref_count); |
194 | if (--span_entry->ref_count == 0) | 274 | if (--span_entry->ref_count == 0) |
195 | mlxsw_sp_span_entry_destroy(mlxsw_sp, span_entry); | 275 | mlxsw_sp_span_entry_destroy(span_entry); |
196 | return 0; | 276 | return 0; |
197 | } | 277 | } |
198 | 278 | ||
@@ -354,16 +434,41 @@ mlxsw_sp_span_inspected_port_del(struct mlxsw_sp_port *port, | |||
354 | kfree(inspected_port); | 434 | kfree(inspected_port); |
355 | } | 435 | } |
356 | 436 | ||
437 | static const struct mlxsw_sp_span_entry_ops * | ||
438 | mlxsw_sp_span_entry_ops(struct mlxsw_sp *mlxsw_sp, | ||
439 | const struct net_device *to_dev) | ||
440 | { | ||
441 | size_t i; | ||
442 | |||
443 | for (i = 0; i < ARRAY_SIZE(mlxsw_sp_span_entry_types); ++i) | ||
444 | if (mlxsw_sp_span_entry_types[i]->can_handle(to_dev)) | ||
445 | return mlxsw_sp_span_entry_types[i]; | ||
446 | |||
447 | return NULL; | ||
448 | } | ||
449 | |||
357 | int mlxsw_sp_span_mirror_add(struct mlxsw_sp_port *from, | 450 | int mlxsw_sp_span_mirror_add(struct mlxsw_sp_port *from, |
358 | const struct net_device *to_dev, | 451 | const struct net_device *to_dev, |
359 | enum mlxsw_sp_span_type type, bool bind, | 452 | enum mlxsw_sp_span_type type, bool bind, |
360 | int *p_span_id) | 453 | int *p_span_id) |
361 | { | 454 | { |
362 | struct mlxsw_sp *mlxsw_sp = from->mlxsw_sp; | 455 | struct mlxsw_sp *mlxsw_sp = from->mlxsw_sp; |
456 | const struct mlxsw_sp_span_entry_ops *ops; | ||
457 | struct mlxsw_sp_span_parms sparms = {0}; | ||
363 | struct mlxsw_sp_span_entry *span_entry; | 458 | struct mlxsw_sp_span_entry *span_entry; |
364 | int err; | 459 | int err; |
365 | 460 | ||
366 | span_entry = mlxsw_sp_span_entry_get(mlxsw_sp, to_dev); | 461 | ops = mlxsw_sp_span_entry_ops(mlxsw_sp, to_dev); |
462 | if (!ops) { | ||
463 | netdev_err(to_dev, "Cannot mirror to %s", to_dev->name); | ||
464 | return -EOPNOTSUPP; | ||
465 | } | ||
466 | |||
467 | err = ops->parms(to_dev, &sparms); | ||
468 | if (err) | ||
469 | return err; | ||
470 | |||
471 | span_entry = mlxsw_sp_span_entry_get(mlxsw_sp, to_dev, ops, sparms); | ||
367 | if (!span_entry) | 472 | if (!span_entry) |
368 | return -ENOENT; | 473 | return -ENOENT; |
369 | 474 | ||
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h index 44b307c59d0e..9390b05a7919 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h | |||
@@ -50,13 +50,30 @@ struct mlxsw_sp_span_inspected_port { | |||
50 | u8 local_port; | 50 | u8 local_port; |
51 | }; | 51 | }; |
52 | 52 | ||
53 | struct mlxsw_sp_span_parms { | ||
54 | struct mlxsw_sp_port *dest_port; /* NULL for unoffloaded SPAN. */ | ||
55 | }; | ||
56 | |||
57 | struct mlxsw_sp_span_entry_ops; | ||
58 | |||
53 | struct mlxsw_sp_span_entry { | 59 | struct mlxsw_sp_span_entry { |
54 | const struct net_device *to_dev; | 60 | const struct net_device *to_dev; |
61 | const struct mlxsw_sp_span_entry_ops *ops; | ||
62 | struct mlxsw_sp_span_parms parms; | ||
55 | struct list_head bound_ports_list; | 63 | struct list_head bound_ports_list; |
56 | int ref_count; | 64 | int ref_count; |
57 | int id; | 65 | int id; |
58 | }; | 66 | }; |
59 | 67 | ||
68 | struct mlxsw_sp_span_entry_ops { | ||
69 | bool (*can_handle)(const struct net_device *to_dev); | ||
70 | int (*parms)(const struct net_device *to_dev, | ||
71 | struct mlxsw_sp_span_parms *sparmsp); | ||
72 | int (*configure)(struct mlxsw_sp_span_entry *span_entry, | ||
73 | struct mlxsw_sp_span_parms sparms); | ||
74 | void (*deconfigure)(struct mlxsw_sp_span_entry *span_entry); | ||
75 | }; | ||
76 | |||
60 | int mlxsw_sp_span_init(struct mlxsw_sp *mlxsw_sp); | 77 | int mlxsw_sp_span_init(struct mlxsw_sp *mlxsw_sp); |
61 | void mlxsw_sp_span_fini(struct mlxsw_sp *mlxsw_sp); | 78 | void mlxsw_sp_span_fini(struct mlxsw_sp *mlxsw_sp); |
62 | 79 | ||