1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2019-2020 Marvell International Ltd. All rights reserved */
4 #include <net/devlink.h>
6 #include "prestera_devlink.h"
7 #include "prestera_hw.h"
9 /* All driver-specific traps must be documented in
10 * Documentation/networking/devlink/prestera.rst
13 DEVLINK_PRESTERA_TRAP_ID_BASE = DEVLINK_TRAP_GENERIC_ID_MAX,
14 DEVLINK_PRESTERA_TRAP_ID_ARP_BC,
15 DEVLINK_PRESTERA_TRAP_ID_IS_IS,
16 DEVLINK_PRESTERA_TRAP_ID_OSPF,
17 DEVLINK_PRESTERA_TRAP_ID_IP_BC_MAC,
18 DEVLINK_PRESTERA_TRAP_ID_ROUTER_MC,
19 DEVLINK_PRESTERA_TRAP_ID_VRRP,
20 DEVLINK_PRESTERA_TRAP_ID_DHCP,
21 DEVLINK_PRESTERA_TRAP_ID_MAC_TO_ME,
22 DEVLINK_PRESTERA_TRAP_ID_IPV4_OPTIONS,
23 DEVLINK_PRESTERA_TRAP_ID_IP_DEFAULT_ROUTE,
24 DEVLINK_PRESTERA_TRAP_ID_IP_TO_ME,
25 DEVLINK_PRESTERA_TRAP_ID_IPV4_ICMP_REDIRECT,
26 DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_0,
27 DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_1,
28 DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_2,
29 DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_3,
30 DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_4,
31 DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_5,
32 DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_6,
33 DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_7,
34 DEVLINK_PRESTERA_TRAP_ID_BGP,
35 DEVLINK_PRESTERA_TRAP_ID_SSH,
36 DEVLINK_PRESTERA_TRAP_ID_TELNET,
37 DEVLINK_PRESTERA_TRAP_ID_ICMP,
38 DEVLINK_PRESTERA_TRAP_ID_MET_RED,
39 DEVLINK_PRESTERA_TRAP_ID_IP_SIP_IS_ZERO,
40 DEVLINK_PRESTERA_TRAP_ID_IP_UC_DIP_DA_MISMATCH,
41 DEVLINK_PRESTERA_TRAP_ID_ILLEGAL_IPV4_HDR,
42 DEVLINK_PRESTERA_TRAP_ID_ILLEGAL_IP_ADDR,
43 DEVLINK_PRESTERA_TRAP_ID_INVALID_SA,
44 DEVLINK_PRESTERA_TRAP_ID_LOCAL_PORT,
45 DEVLINK_PRESTERA_TRAP_ID_PORT_NO_VLAN,
46 DEVLINK_PRESTERA_TRAP_ID_RXDMA_DROP,
49 #define DEVLINK_PRESTERA_TRAP_NAME_ARP_BC \
51 #define DEVLINK_PRESTERA_TRAP_NAME_IS_IS \
53 #define DEVLINK_PRESTERA_TRAP_NAME_OSPF \
55 #define DEVLINK_PRESTERA_TRAP_NAME_IP_BC_MAC \
57 #define DEVLINK_PRESTERA_TRAP_NAME_ROUTER_MC \
59 #define DEVLINK_PRESTERA_TRAP_NAME_VRRP \
61 #define DEVLINK_PRESTERA_TRAP_NAME_DHCP \
63 #define DEVLINK_PRESTERA_TRAP_NAME_MAC_TO_ME \
65 #define DEVLINK_PRESTERA_TRAP_NAME_IPV4_OPTIONS \
67 #define DEVLINK_PRESTERA_TRAP_NAME_IP_DEFAULT_ROUTE \
69 #define DEVLINK_PRESTERA_TRAP_NAME_IP_TO_ME \
71 #define DEVLINK_PRESTERA_TRAP_NAME_IPV4_ICMP_REDIRECT \
73 #define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_0 \
75 #define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_1 \
77 #define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_2 \
79 #define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_3 \
81 #define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_4 \
83 #define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_5 \
85 #define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_6 \
87 #define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_7 \
89 #define DEVLINK_PRESTERA_TRAP_NAME_BGP \
91 #define DEVLINK_PRESTERA_TRAP_NAME_SSH \
93 #define DEVLINK_PRESTERA_TRAP_NAME_TELNET \
95 #define DEVLINK_PRESTERA_TRAP_NAME_ICMP \
97 #define DEVLINK_PRESTERA_TRAP_NAME_RXDMA_DROP \
99 #define DEVLINK_PRESTERA_TRAP_NAME_PORT_NO_VLAN \
101 #define DEVLINK_PRESTERA_TRAP_NAME_LOCAL_PORT \
103 #define DEVLINK_PRESTERA_TRAP_NAME_INVALID_SA \
105 #define DEVLINK_PRESTERA_TRAP_NAME_ILLEGAL_IP_ADDR \
107 #define DEVLINK_PRESTERA_TRAP_NAME_ILLEGAL_IPV4_HDR \
109 #define DEVLINK_PRESTERA_TRAP_NAME_IP_UC_DIP_DA_MISMATCH \
110 "ip_uc_dip_da_mismatch"
111 #define DEVLINK_PRESTERA_TRAP_NAME_IP_SIP_IS_ZERO \
113 #define DEVLINK_PRESTERA_TRAP_NAME_MET_RED \
116 struct prestera_trap {
117 struct devlink_trap trap;
121 struct prestera_trap_item {
122 enum devlink_trap_action action;
126 struct prestera_trap_data {
127 struct prestera_switch *sw;
128 struct prestera_trap_item *trap_items_arr;
132 #define PRESTERA_TRAP_METADATA DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT
134 #define PRESTERA_TRAP_CONTROL(_id, _group_id, _action) \
135 DEVLINK_TRAP_GENERIC(CONTROL, _action, _id, \
136 DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \
137 PRESTERA_TRAP_METADATA)
139 #define PRESTERA_TRAP_DRIVER_CONTROL(_id, _group_id) \
140 DEVLINK_TRAP_DRIVER(CONTROL, TRAP, DEVLINK_PRESTERA_TRAP_ID_##_id, \
141 DEVLINK_PRESTERA_TRAP_NAME_##_id, \
142 DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \
143 PRESTERA_TRAP_METADATA)
145 #define PRESTERA_TRAP_EXCEPTION(_id, _group_id) \
146 DEVLINK_TRAP_GENERIC(EXCEPTION, TRAP, _id, \
147 DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \
148 PRESTERA_TRAP_METADATA)
150 #define PRESTERA_TRAP_DRIVER_EXCEPTION(_id, _group_id) \
151 DEVLINK_TRAP_DRIVER(EXCEPTION, TRAP, DEVLINK_PRESTERA_TRAP_ID_##_id, \
152 DEVLINK_PRESTERA_TRAP_NAME_##_id, \
153 DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \
154 PRESTERA_TRAP_METADATA)
156 #define PRESTERA_TRAP_DRIVER_DROP(_id, _group_id) \
157 DEVLINK_TRAP_DRIVER(DROP, DROP, DEVLINK_PRESTERA_TRAP_ID_##_id, \
158 DEVLINK_PRESTERA_TRAP_NAME_##_id, \
159 DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \
160 PRESTERA_TRAP_METADATA)
162 static const struct devlink_trap_group prestera_trap_groups_arr[] = {
163 /* No policer is associated with following groups (policerid == 0)*/
164 DEVLINK_TRAP_GROUP_GENERIC(L2_DROPS, 0),
165 DEVLINK_TRAP_GROUP_GENERIC(L3_DROPS, 0),
166 DEVLINK_TRAP_GROUP_GENERIC(L3_EXCEPTIONS, 0),
167 DEVLINK_TRAP_GROUP_GENERIC(NEIGH_DISCOVERY, 0),
168 DEVLINK_TRAP_GROUP_GENERIC(ACL_TRAP, 0),
169 DEVLINK_TRAP_GROUP_GENERIC(ACL_DROPS, 0),
170 DEVLINK_TRAP_GROUP_GENERIC(ACL_SAMPLE, 0),
171 DEVLINK_TRAP_GROUP_GENERIC(OSPF, 0),
172 DEVLINK_TRAP_GROUP_GENERIC(STP, 0),
173 DEVLINK_TRAP_GROUP_GENERIC(LACP, 0),
174 DEVLINK_TRAP_GROUP_GENERIC(LLDP, 0),
175 DEVLINK_TRAP_GROUP_GENERIC(VRRP, 0),
176 DEVLINK_TRAP_GROUP_GENERIC(DHCP, 0),
177 DEVLINK_TRAP_GROUP_GENERIC(BGP, 0),
178 DEVLINK_TRAP_GROUP_GENERIC(LOCAL_DELIVERY, 0),
179 DEVLINK_TRAP_GROUP_GENERIC(BUFFER_DROPS, 0),
182 /* Initialize trap list, as well as associate CPU code with them. */
183 static struct prestera_trap prestera_trap_items_arr[] = {
185 .trap = PRESTERA_TRAP_DRIVER_CONTROL(ARP_BC, NEIGH_DISCOVERY),
189 .trap = PRESTERA_TRAP_DRIVER_CONTROL(IS_IS, LOCAL_DELIVERY),
193 .trap = PRESTERA_TRAP_DRIVER_CONTROL(OSPF, OSPF),
197 .trap = PRESTERA_TRAP_DRIVER_CONTROL(IP_BC_MAC, LOCAL_DELIVERY),
201 .trap = PRESTERA_TRAP_CONTROL(STP, STP, TRAP),
205 .trap = PRESTERA_TRAP_CONTROL(LACP, LACP, TRAP),
209 .trap = PRESTERA_TRAP_CONTROL(LLDP, LLDP, TRAP),
213 .trap = PRESTERA_TRAP_DRIVER_CONTROL(ROUTER_MC, LOCAL_DELIVERY),
217 .trap = PRESTERA_TRAP_DRIVER_CONTROL(VRRP, VRRP),
221 .trap = PRESTERA_TRAP_DRIVER_CONTROL(DHCP, DHCP),
225 .trap = PRESTERA_TRAP_EXCEPTION(MTU_ERROR, L3_EXCEPTIONS),
229 .trap = PRESTERA_TRAP_DRIVER_CONTROL(MAC_TO_ME, LOCAL_DELIVERY),
233 .trap = PRESTERA_TRAP_EXCEPTION(TTL_ERROR, L3_EXCEPTIONS),
237 .trap = PRESTERA_TRAP_DRIVER_EXCEPTION(IPV4_OPTIONS,
242 .trap = PRESTERA_TRAP_DRIVER_CONTROL(IP_DEFAULT_ROUTE,
247 .trap = PRESTERA_TRAP_CONTROL(LOCAL_ROUTE, LOCAL_DELIVERY,
252 .trap = PRESTERA_TRAP_DRIVER_EXCEPTION(IPV4_ICMP_REDIRECT,
257 .trap = PRESTERA_TRAP_CONTROL(ARP_RESPONSE, NEIGH_DISCOVERY,
262 .trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_0, ACL_TRAP),
266 .trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_1, ACL_TRAP),
270 .trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_2, ACL_TRAP),
274 .trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_3, ACL_TRAP),
278 .trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_4, ACL_TRAP),
282 .trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_5, ACL_TRAP),
286 .trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_6, ACL_TRAP),
290 .trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_7, ACL_TRAP),
294 .trap = PRESTERA_TRAP_DRIVER_CONTROL(BGP, BGP),
298 .trap = PRESTERA_TRAP_DRIVER_CONTROL(SSH, LOCAL_DELIVERY),
302 .trap = PRESTERA_TRAP_DRIVER_CONTROL(TELNET, LOCAL_DELIVERY),
306 .trap = PRESTERA_TRAP_DRIVER_CONTROL(ICMP, LOCAL_DELIVERY),
310 .trap = PRESTERA_TRAP_DRIVER_DROP(RXDMA_DROP, BUFFER_DROPS),
314 .trap = PRESTERA_TRAP_DRIVER_DROP(PORT_NO_VLAN, L2_DROPS),
318 .trap = PRESTERA_TRAP_DRIVER_DROP(LOCAL_PORT, L2_DROPS),
322 .trap = PRESTERA_TRAP_DRIVER_DROP(INVALID_SA, L2_DROPS),
326 .trap = PRESTERA_TRAP_DRIVER_DROP(ILLEGAL_IP_ADDR, L3_DROPS),
330 .trap = PRESTERA_TRAP_DRIVER_DROP(ILLEGAL_IPV4_HDR, L3_DROPS),
334 .trap = PRESTERA_TRAP_DRIVER_DROP(IP_UC_DIP_DA_MISMATCH,
339 .trap = PRESTERA_TRAP_DRIVER_DROP(IP_SIP_IS_ZERO, L3_DROPS),
343 .trap = PRESTERA_TRAP_DRIVER_DROP(MET_RED, BUFFER_DROPS),
348 static int prestera_drop_counter_get(struct devlink *devlink,
349 const struct devlink_trap *trap,
352 static int prestera_dl_info_get(struct devlink *dl,
353 struct devlink_info_req *req,
354 struct netlink_ext_ack *extack)
356 struct prestera_switch *sw = devlink_priv(dl);
360 err = devlink_info_driver_name_put(req, PRESTERA_DRV_NAME);
364 snprintf(buf, sizeof(buf), "%d.%d.%d",
367 sw->dev->fw_rev.sub);
369 return devlink_info_version_running_put(req,
370 DEVLINK_INFO_VERSION_GENERIC_FW,
374 static int prestera_trap_init(struct devlink *devlink,
375 const struct devlink_trap *trap, void *trap_ctx);
377 static int prestera_trap_action_set(struct devlink *devlink,
378 const struct devlink_trap *trap,
379 enum devlink_trap_action action,
380 struct netlink_ext_ack *extack);
382 static const struct devlink_ops prestera_dl_ops = {
383 .info_get = prestera_dl_info_get,
384 .trap_init = prestera_trap_init,
385 .trap_action_set = prestera_trap_action_set,
386 .trap_drop_counter_get = prestera_drop_counter_get,
389 struct prestera_switch *prestera_devlink_alloc(struct prestera_device *dev)
393 dl = devlink_alloc(&prestera_dl_ops, sizeof(struct prestera_switch),
396 return devlink_priv(dl);
399 void prestera_devlink_free(struct prestera_switch *sw)
401 struct devlink *dl = priv_to_devlink(sw);
406 void prestera_devlink_register(struct prestera_switch *sw)
408 struct devlink *dl = priv_to_devlink(sw);
410 devlink_register(dl);
413 void prestera_devlink_unregister(struct prestera_switch *sw)
415 struct devlink *dl = priv_to_devlink(sw);
417 devlink_unregister(dl);
420 int prestera_devlink_port_register(struct prestera_port *port)
422 struct prestera_switch *sw = port->sw;
423 struct devlink *dl = priv_to_devlink(sw);
424 struct devlink_port_attrs attrs = {};
427 attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
428 attrs.phys.port_number = port->fp_id;
429 attrs.switch_id.id_len = sizeof(sw->id);
430 memcpy(attrs.switch_id.id, &sw->id, attrs.switch_id.id_len);
432 devlink_port_attrs_set(&port->dl_port, &attrs);
434 err = devlink_port_register(dl, &port->dl_port, port->fp_id);
436 dev_err(prestera_dev(sw), "devlink_port_register failed: %d\n", err);
443 void prestera_devlink_port_unregister(struct prestera_port *port)
445 devlink_port_unregister(&port->dl_port);
448 int prestera_devlink_traps_register(struct prestera_switch *sw)
450 const u32 groups_count = ARRAY_SIZE(prestera_trap_groups_arr);
451 const u32 traps_count = ARRAY_SIZE(prestera_trap_items_arr);
452 struct devlink *devlink = priv_to_devlink(sw);
453 struct prestera_trap_data *trap_data;
454 struct prestera_trap *prestera_trap;
457 trap_data = kzalloc(sizeof(*trap_data), GFP_KERNEL);
461 trap_data->trap_items_arr = kcalloc(traps_count,
462 sizeof(struct prestera_trap_item),
464 if (!trap_data->trap_items_arr) {
466 goto err_trap_items_alloc;
470 trap_data->traps_count = traps_count;
471 sw->trap_data = trap_data;
473 err = devlink_trap_groups_register(devlink, prestera_trap_groups_arr,
476 goto err_groups_register;
478 for (i = 0; i < traps_count; i++) {
479 prestera_trap = &prestera_trap_items_arr[i];
480 err = devlink_traps_register(devlink, &prestera_trap->trap, 1,
483 goto err_trap_register;
489 for (i--; i >= 0; i--) {
490 prestera_trap = &prestera_trap_items_arr[i];
491 devlink_traps_unregister(devlink, &prestera_trap->trap, 1);
493 devlink_trap_groups_unregister(devlink, prestera_trap_groups_arr,
496 kfree(trap_data->trap_items_arr);
497 err_trap_items_alloc:
502 static struct prestera_trap_item *
503 prestera_get_trap_item_by_cpu_code(struct prestera_switch *sw, u8 cpu_code)
505 struct prestera_trap_data *trap_data = sw->trap_data;
506 struct prestera_trap *prestera_trap;
509 for (i = 0; i < trap_data->traps_count; i++) {
510 prestera_trap = &prestera_trap_items_arr[i];
511 if (cpu_code == prestera_trap->cpu_code)
512 return &trap_data->trap_items_arr[i];
518 void prestera_devlink_trap_report(struct prestera_port *port,
519 struct sk_buff *skb, u8 cpu_code)
521 struct prestera_trap_item *trap_item;
522 struct devlink *devlink;
524 devlink = port->dl_port.devlink;
526 trap_item = prestera_get_trap_item_by_cpu_code(port->sw, cpu_code);
527 if (unlikely(!trap_item))
530 devlink_trap_report(devlink, skb, trap_item->trap_ctx,
531 &port->dl_port, NULL);
534 static struct prestera_trap_item *
535 prestera_devlink_trap_item_lookup(struct prestera_switch *sw, u16 trap_id)
537 struct prestera_trap_data *trap_data = sw->trap_data;
540 for (i = 0; i < ARRAY_SIZE(prestera_trap_items_arr); i++) {
541 if (prestera_trap_items_arr[i].trap.id == trap_id)
542 return &trap_data->trap_items_arr[i];
548 static int prestera_trap_init(struct devlink *devlink,
549 const struct devlink_trap *trap, void *trap_ctx)
551 struct prestera_switch *sw = devlink_priv(devlink);
552 struct prestera_trap_item *trap_item;
554 trap_item = prestera_devlink_trap_item_lookup(sw, trap->id);
555 if (WARN_ON(!trap_item))
558 trap_item->trap_ctx = trap_ctx;
559 trap_item->action = trap->init_action;
564 static int prestera_trap_action_set(struct devlink *devlink,
565 const struct devlink_trap *trap,
566 enum devlink_trap_action action,
567 struct netlink_ext_ack *extack)
569 /* Currently, driver does not support trap action altering */
573 static int prestera_drop_counter_get(struct devlink *devlink,
574 const struct devlink_trap *trap,
577 struct prestera_switch *sw = devlink_priv(devlink);
578 enum prestera_hw_cpu_code_cnt_t cpu_code_type =
579 PRESTERA_HW_CPU_CODE_CNT_TYPE_DROP;
580 struct prestera_trap *prestera_trap =
581 container_of(trap, struct prestera_trap, trap);
583 return prestera_hw_cpu_code_counters_get(sw, prestera_trap->cpu_code,
584 cpu_code_type, p_drops);
587 void prestera_devlink_traps_unregister(struct prestera_switch *sw)
589 struct prestera_trap_data *trap_data = sw->trap_data;
590 struct devlink *dl = priv_to_devlink(sw);
591 const struct devlink_trap *trap;
594 for (i = 0; i < ARRAY_SIZE(prestera_trap_items_arr); ++i) {
595 trap = &prestera_trap_items_arr[i].trap;
596 devlink_traps_unregister(dl, trap, 1);
599 devlink_trap_groups_unregister(dl, prestera_trap_groups_arr,
600 ARRAY_SIZE(prestera_trap_groups_arr));
601 kfree(trap_data->trap_items_arr);