2 * drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c
3 * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
4 * Copyright (c) 2017 Arkadi Sharshevsky <arakdis@mellanox.com>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the names of the copyright holders nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * Alternatively, this software may be distributed under the terms of the
19 * GNU General Public License ("GPL") version 2 as published by the Free
20 * Software Foundation.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
35 #include <linux/kernel.h>
36 #include <net/devlink.h>
39 #include "spectrum_dpipe.h"
40 #include "spectrum_router.h"
42 enum mlxsw_sp_field_metadata_id
{
43 MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT
,
44 MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD
,
45 MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP
,
48 static struct devlink_dpipe_field mlxsw_sp_dpipe_fields_metadata
[] = {
49 { .name
= "erif_port",
50 .id
= MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT
,
52 .mapping_type
= DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX
,
54 { .name
= "l3_forward",
55 .id
= MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD
,
59 .id
= MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP
,
64 enum mlxsw_sp_dpipe_header_id
{
65 MLXSW_SP_DPIPE_HEADER_METADATA
,
68 static struct devlink_dpipe_header mlxsw_sp_dpipe_header_metadata
= {
70 .id
= MLXSW_SP_DPIPE_HEADER_METADATA
,
71 .fields
= mlxsw_sp_dpipe_fields_metadata
,
72 .fields_count
= ARRAY_SIZE(mlxsw_sp_dpipe_fields_metadata
),
75 static struct devlink_dpipe_header
*mlxsw_dpipe_headers
[] = {
76 &mlxsw_sp_dpipe_header_metadata
,
77 &devlink_dpipe_header_ethernet
,
78 &devlink_dpipe_header_ipv4
,
81 static struct devlink_dpipe_headers mlxsw_sp_dpipe_headers
= {
82 .headers
= mlxsw_dpipe_headers
,
83 .headers_count
= ARRAY_SIZE(mlxsw_dpipe_headers
),
86 static int mlxsw_sp_dpipe_table_erif_actions_dump(void *priv
,
89 struct devlink_dpipe_action action
= {0};
92 action
.type
= DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY
;
93 action
.header
= &mlxsw_sp_dpipe_header_metadata
;
94 action
.field_id
= MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD
;
96 err
= devlink_dpipe_action_put(skb
, &action
);
100 action
.type
= DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY
;
101 action
.header
= &mlxsw_sp_dpipe_header_metadata
;
102 action
.field_id
= MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP
;
104 return devlink_dpipe_action_put(skb
, &action
);
107 static int mlxsw_sp_dpipe_table_erif_matches_dump(void *priv
,
110 struct devlink_dpipe_match match
= {0};
112 match
.type
= DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT
;
113 match
.header
= &mlxsw_sp_dpipe_header_metadata
;
114 match
.field_id
= MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT
;
116 return devlink_dpipe_match_put(skb
, &match
);
120 mlxsw_sp_erif_match_action_prepare(struct devlink_dpipe_match
*match
,
121 struct devlink_dpipe_action
*action
)
123 action
->type
= DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY
;
124 action
->header
= &mlxsw_sp_dpipe_header_metadata
;
125 action
->field_id
= MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD
;
127 match
->type
= DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT
;
128 match
->header
= &mlxsw_sp_dpipe_header_metadata
;
129 match
->field_id
= MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT
;
132 static int mlxsw_sp_erif_entry_prepare(struct devlink_dpipe_entry
*entry
,
133 struct devlink_dpipe_value
*match_value
,
134 struct devlink_dpipe_match
*match
,
135 struct devlink_dpipe_value
*action_value
,
136 struct devlink_dpipe_action
*action
)
138 entry
->match_values
= match_value
;
139 entry
->match_values_count
= 1;
141 entry
->action_values
= action_value
;
142 entry
->action_values_count
= 1;
144 match_value
->match
= match
;
145 match_value
->value_size
= sizeof(u32
);
146 match_value
->value
= kmalloc(match_value
->value_size
, GFP_KERNEL
);
147 if (!match_value
->value
)
150 action_value
->action
= action
;
151 action_value
->value_size
= sizeof(u32
);
152 action_value
->value
= kmalloc(action_value
->value_size
, GFP_KERNEL
);
153 if (!action_value
->value
)
154 goto err_action_alloc
;
158 kfree(match_value
->value
);
162 static int mlxsw_sp_erif_entry_get(struct mlxsw_sp
*mlxsw_sp
,
163 struct devlink_dpipe_entry
*entry
,
164 struct mlxsw_sp_rif
*rif
,
165 bool counters_enabled
)
172 /* Set Match RIF index */
173 rif_value
= entry
->match_values
->value
;
174 *rif_value
= mlxsw_sp_rif_index(rif
);
175 entry
->match_values
->mapping_value
= mlxsw_sp_rif_dev_ifindex(rif
);
176 entry
->match_values
->mapping_valid
= true;
178 /* Set Action Forwarding */
179 action_value
= entry
->action_values
->value
;
182 entry
->counter_valid
= false;
184 entry
->index
= mlxsw_sp_rif_index(rif
);
186 if (!counters_enabled
)
189 err
= mlxsw_sp_rif_counter_value_get(mlxsw_sp
, rif
,
190 MLXSW_SP_RIF_COUNTER_EGRESS
,
193 entry
->counter
= cnt
;
194 entry
->counter_valid
= true;
200 mlxsw_sp_dpipe_table_erif_entries_dump(void *priv
, bool counters_enabled
,
201 struct devlink_dpipe_dump_ctx
*dump_ctx
)
203 struct devlink_dpipe_value match_value
, action_value
;
204 struct devlink_dpipe_action action
= {0};
205 struct devlink_dpipe_match match
= {0};
206 struct devlink_dpipe_entry entry
= {0};
207 struct mlxsw_sp
*mlxsw_sp
= priv
;
208 unsigned int rif_count
;
212 memset(&match_value
, 0, sizeof(match_value
));
213 memset(&action_value
, 0, sizeof(action_value
));
215 mlxsw_sp_erif_match_action_prepare(&match
, &action
);
216 err
= mlxsw_sp_erif_entry_prepare(&entry
, &match_value
, &match
,
217 &action_value
, &action
);
221 rif_count
= MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_RIFS
);
225 err
= devlink_dpipe_entry_ctx_prepare(dump_ctx
);
229 for (; i
< rif_count
; i
++) {
230 struct mlxsw_sp_rif
*rif
= mlxsw_sp_rif_by_index(mlxsw_sp
, i
);
234 err
= mlxsw_sp_erif_entry_get(mlxsw_sp
, &entry
, rif
,
238 err
= devlink_dpipe_entry_ctx_append(dump_ctx
, &entry
);
240 if (err
== -EMSGSIZE
) {
242 goto err_entry_append
;
245 goto err_entry_append
;
250 devlink_dpipe_entry_ctx_close(dump_ctx
);
255 devlink_dpipe_entry_clear(&entry
);
260 devlink_dpipe_entry_clear(&entry
);
264 static int mlxsw_sp_dpipe_table_erif_counters_update(void *priv
, bool enable
)
266 struct mlxsw_sp
*mlxsw_sp
= priv
;
270 for (i
= 0; i
< MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_RIFS
); i
++) {
271 struct mlxsw_sp_rif
*rif
= mlxsw_sp_rif_by_index(mlxsw_sp
, i
);
276 mlxsw_sp_rif_counter_alloc(mlxsw_sp
, rif
,
277 MLXSW_SP_RIF_COUNTER_EGRESS
);
279 mlxsw_sp_rif_counter_free(mlxsw_sp
, rif
,
280 MLXSW_SP_RIF_COUNTER_EGRESS
);
286 static u64
mlxsw_sp_dpipe_table_erif_size_get(void *priv
)
288 struct mlxsw_sp
*mlxsw_sp
= priv
;
290 return MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_RIFS
);
293 static struct devlink_dpipe_table_ops mlxsw_sp_erif_ops
= {
294 .matches_dump
= mlxsw_sp_dpipe_table_erif_matches_dump
,
295 .actions_dump
= mlxsw_sp_dpipe_table_erif_actions_dump
,
296 .entries_dump
= mlxsw_sp_dpipe_table_erif_entries_dump
,
297 .counters_set_update
= mlxsw_sp_dpipe_table_erif_counters_update
,
298 .size_get
= mlxsw_sp_dpipe_table_erif_size_get
,
301 static int mlxsw_sp_dpipe_erif_table_init(struct mlxsw_sp
*mlxsw_sp
)
303 struct devlink
*devlink
= priv_to_devlink(mlxsw_sp
->core
);
305 return devlink_dpipe_table_register(devlink
,
306 MLXSW_SP_DPIPE_TABLE_NAME_ERIF
,
311 static void mlxsw_sp_dpipe_erif_table_fini(struct mlxsw_sp
*mlxsw_sp
)
313 struct devlink
*devlink
= priv_to_devlink(mlxsw_sp
->core
);
315 devlink_dpipe_table_unregister(devlink
, MLXSW_SP_DPIPE_TABLE_NAME_ERIF
);
318 static int mlxsw_sp_dpipe_table_host_matches_dump(struct sk_buff
*skb
, int type
)
320 struct devlink_dpipe_match match
= {0};
323 match
.type
= DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT
;
324 match
.header
= &mlxsw_sp_dpipe_header_metadata
;
325 match
.field_id
= MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT
;
327 err
= devlink_dpipe_match_put(skb
, &match
);
331 match
.type
= DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT
;
332 match
.header
= &devlink_dpipe_header_ipv4
;
333 match
.field_id
= DEVLINK_DPIPE_FIELD_IPV4_DST_IP
;
335 return devlink_dpipe_match_put(skb
, &match
);
339 mlxsw_sp_dpipe_table_host4_matches_dump(void *priv
, struct sk_buff
*skb
)
341 return mlxsw_sp_dpipe_table_host_matches_dump(skb
, AF_INET
);
345 mlxsw_sp_dpipe_table_host4_actions_dump(void *priv
, struct sk_buff
*skb
)
347 struct devlink_dpipe_action action
= {0};
349 action
.type
= DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY
;
350 action
.header
= &devlink_dpipe_header_ethernet
;
351 action
.field_id
= DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC
;
353 return devlink_dpipe_action_put(skb
, &action
);
357 mlxsw_sp_dpipe_table_host_size_get(struct mlxsw_sp
*mlxsw_sp
, int type
)
363 for (i
= 0; i
< MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_RIFS
); i
++) {
364 struct mlxsw_sp_rif
*rif
= mlxsw_sp_rif_by_index(mlxsw_sp
, i
);
365 struct mlxsw_sp_neigh_entry
*neigh_entry
;
369 mlxsw_sp_rif_neigh_for_each(neigh_entry
, rif
) {
370 if (mlxsw_sp_neigh_entry_type(neigh_entry
) != type
)
380 static u64
mlxsw_sp_dpipe_table_host4_size_get(void *priv
)
382 struct mlxsw_sp
*mlxsw_sp
= priv
;
384 return mlxsw_sp_dpipe_table_host_size_get(mlxsw_sp
, AF_INET
);
387 static struct devlink_dpipe_table_ops mlxsw_sp_host4_ops
= {
388 .matches_dump
= mlxsw_sp_dpipe_table_host4_matches_dump
,
389 .actions_dump
= mlxsw_sp_dpipe_table_host4_actions_dump
,
390 .size_get
= mlxsw_sp_dpipe_table_host4_size_get
,
393 static int mlxsw_sp_dpipe_host4_table_init(struct mlxsw_sp
*mlxsw_sp
)
395 struct devlink
*devlink
= priv_to_devlink(mlxsw_sp
->core
);
397 return devlink_dpipe_table_register(devlink
,
398 MLXSW_SP_DPIPE_TABLE_NAME_HOST4
,
403 static void mlxsw_sp_dpipe_host4_table_fini(struct mlxsw_sp
*mlxsw_sp
)
405 struct devlink
*devlink
= priv_to_devlink(mlxsw_sp
->core
);
407 devlink_dpipe_table_unregister(devlink
,
408 MLXSW_SP_DPIPE_TABLE_NAME_HOST4
);
411 int mlxsw_sp_dpipe_init(struct mlxsw_sp
*mlxsw_sp
)
413 struct devlink
*devlink
= priv_to_devlink(mlxsw_sp
->core
);
416 err
= devlink_dpipe_headers_register(devlink
,
417 &mlxsw_sp_dpipe_headers
);
420 err
= mlxsw_sp_dpipe_erif_table_init(mlxsw_sp
);
422 goto err_erif_table_init
;
424 err
= mlxsw_sp_dpipe_host4_table_init(mlxsw_sp
);
426 goto err_host4_table_init
;
429 err_host4_table_init
:
430 mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp
);
432 devlink_dpipe_headers_unregister(priv_to_devlink(mlxsw_sp
->core
));
436 void mlxsw_sp_dpipe_fini(struct mlxsw_sp
*mlxsw_sp
)
438 struct devlink
*devlink
= priv_to_devlink(mlxsw_sp
->core
);
440 mlxsw_sp_dpipe_host4_table_fini(mlxsw_sp
);
441 mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp
);
442 devlink_dpipe_headers_unregister(devlink
);