diff options
author | David S. Miller <davem@davemloft.net> | 2020-10-02 16:31:56 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2020-10-02 16:31:56 -0700 |
commit | 5a38b4fc010412beda7e6e4284401559356f5827 (patch) | |
tree | d30d2966e4b54167b2100a9cccf8cb670d6a340b | |
parent | 34ad937770d7f17f18f66bdd6b860306a3344d16 (diff) | |
parent | 061d631f7de24cae30a1f931f18df643cba58246 (diff) |
Merge branch 'dpaa2-eth-add-devlink-parser-error-drop-trap-support'
Ioana Ciornei says:
====================
dpaa2-eth: add devlink parser error drop trap support
This patch set adds support in the dpaa2-eth driver for a new group of
devlink drop traps - PARSER_ERROR_DROPS.
The first patch adds a new generic trap group and associated traps,
their definitions in devlink and their corresponding entries in the
Documentation.
Because there might be more devices (besides DPAA2) which do not support
changing the action independently on each trap, a nre devlink callback
is introduced - .trap_group_action_set(). If this callback is populated,
it will take precedence over .trap_action_set() when the user requests
changing the action on all the traps in a group.
The next patches add basic linkage with devlink for the dpaa2-eth driver
and support for the newly added PARSER_ERROR_DROPS. Nothing special
here, just setting up the Rx error queue, interpreting the parse result,
and then reporting any frame received on that queue to devlink.
Changes in v2:
- fix build error in 3/4
Changes in v3:
- removed a commented line in 4/4
- added an extack in 4/4
- fixed up a warning on 32bit in 4/4
- reworded the trap_group_action_set() description in 2/4
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | Documentation/networking/devlink/devlink-trap.rst | 70 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/dpaa2/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-devlink.c | 309 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 114 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h | 81 | ||||
-rw-r--r-- | include/net/devlink.h | 62 | ||||
-rw-r--r-- | net/core/devlink.c | 35 |
7 files changed, 671 insertions, 2 deletions
diff --git a/Documentation/networking/devlink/devlink-trap.rst b/Documentation/networking/devlink/devlink-trap.rst index 7a798352b45d..ef719ceac299 100644 --- a/Documentation/networking/devlink/devlink-trap.rst +++ b/Documentation/networking/devlink/devlink-trap.rst @@ -409,6 +409,73 @@ be added to the following table: - ``drop`` - Traps packets dropped due to the RED (Random Early Detection) algorithm (i.e., early drops) + * - ``vxlan_parsing`` + - ``drop`` + - Traps packets dropped due to an error in the VXLAN header parsing which + might be because of packet truncation or the I flag is not set. + * - ``llc_snap_parsing`` + - ``drop`` + - Traps packets dropped due to an error in the LLC+SNAP header parsing + * - ``vlan_parsing`` + - ``drop`` + - Traps packets dropped due to an error in the VLAN header parsing. Could + include unexpected packet truncation. + * - ``pppoe_ppp_parsing`` + - ``drop`` + - Traps packets dropped due to an error in the PPPoE+PPP header parsing. + This could include finding a session ID of 0xFFFF (which is reserved and + not for use), a PPPoE length which is larger than the frame received or + any common error on this type of header + * - ``mpls_parsing`` + - ``drop`` + - Traps packets dropped due to an error in the MPLS header parsing which + could include unexpected header truncation + * - ``arp_parsing`` + - ``drop`` + - Traps packets dropped due to an error in the ARP header parsing + * - ``ip_1_parsing`` + - ``drop`` + - Traps packets dropped due to an error in the first IP header parsing. + This packet trap could include packets which do not pass an IP checksum + check, a header length check (a minimum of 20 bytes), which might suffer + from packet truncation thus the total length field exceeds the received + packet length etc + * - ``ip_n_parsing`` + - ``drop`` + - Traps packets dropped due to an error in the parsing of the last IP + header (the inner one in case of an IP over IP tunnel). The same common + error checking is performed here as for the ip_1_parsing trap + * - ``gre_parsing`` + - ``drop`` + - Traps packets dropped due to an error in the GRE header parsing + * - ``udp_parsing`` + - ``drop`` + - Traps packets dropped due to an error in the UDP header parsing. + This packet trap could include checksum errorrs, an improper UDP + length detected (smaller than 8 bytes) or detection of header + truncation. + * - ``tcp_parsing`` + - ``drop`` + - Traps packets dropped due to an error in the TCP header parsing. + This could include TCP checksum errors, improper combination of SYN, FIN + and/or RESET etc. + * - ``ipsec_parsing`` + - ``drop`` + - Traps packets dropped due to an error in the IPSEC header parsing + * - ``sctp_parsing`` + - ``drop`` + - Traps packets dropped due to an error in the SCTP header parsing. + This would mean that port number 0 was used or that the header is + truncated. + * - ``dccp_parsing`` + - ``drop`` + - Traps packets dropped due to an error in the DCCP header parsing + * - ``gtp_parsing`` + - ``drop`` + - Traps packets dropped due to an error in the GTP header parsing + * - ``esp_parsing`` + - ``drop`` + - Traps packets dropped due to an error in the ESP header parsing Driver-specific Packet Traps ============================ @@ -509,6 +576,9 @@ narrow. The description of these groups must be added to the following table: * - ``acl_trap`` - Contains packet traps for packets that were trapped (logged) by the device during ACL processing + * - ``parser_error_drops`` + - Contains packet traps for packets that were marked by the device during + parsing as erroneous Packet Trap Policers ==================== diff --git a/drivers/net/ethernet/freescale/dpaa2/Makefile b/drivers/net/ethernet/freescale/dpaa2/Makefile index 6e7f33c956bf..146cb3540e61 100644 --- a/drivers/net/ethernet/freescale/dpaa2/Makefile +++ b/drivers/net/ethernet/freescale/dpaa2/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_FSL_DPAA2_ETH) += fsl-dpaa2-eth.o obj-$(CONFIG_FSL_DPAA2_PTP_CLOCK) += fsl-dpaa2-ptp.o -fsl-dpaa2-eth-objs := dpaa2-eth.o dpaa2-ethtool.o dpni.o dpaa2-mac.o dpmac.o +fsl-dpaa2-eth-objs := dpaa2-eth.o dpaa2-ethtool.o dpni.o dpaa2-mac.o dpmac.o dpaa2-eth-devlink.o fsl-dpaa2-eth-${CONFIG_FSL_DPAA2_ETH_DCB} += dpaa2-eth-dcb.o fsl-dpaa2-eth-${CONFIG_DEBUG_FS} += dpaa2-eth-debugfs.o fsl-dpaa2-ptp-objs := dpaa2-ptp.o dprtc.o diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-devlink.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-devlink.c new file mode 100644 index 000000000000..833696245565 --- /dev/null +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-devlink.c @@ -0,0 +1,309 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +#include "dpaa2-eth.h" +/* Copyright 2020 NXP + */ + +#define DPAA2_ETH_TRAP_DROP(_id, _group_id) \ + DEVLINK_TRAP_GENERIC(DROP, DROP, _id, \ + DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, 0) + +static const struct devlink_trap_group dpaa2_eth_trap_groups_arr[] = { + DEVLINK_TRAP_GROUP_GENERIC(PARSER_ERROR_DROPS, 0), +}; + +static const struct devlink_trap dpaa2_eth_traps_arr[] = { + DPAA2_ETH_TRAP_DROP(VXLAN_PARSING, PARSER_ERROR_DROPS), + DPAA2_ETH_TRAP_DROP(LLC_SNAP_PARSING, PARSER_ERROR_DROPS), + DPAA2_ETH_TRAP_DROP(VLAN_PARSING, PARSER_ERROR_DROPS), + DPAA2_ETH_TRAP_DROP(PPPOE_PPP_PARSING, PARSER_ERROR_DROPS), + DPAA2_ETH_TRAP_DROP(MPLS_PARSING, PARSER_ERROR_DROPS), + DPAA2_ETH_TRAP_DROP(ARP_PARSING, PARSER_ERROR_DROPS), + DPAA2_ETH_TRAP_DROP(IP_1_PARSING, PARSER_ERROR_DROPS), + DPAA2_ETH_TRAP_DROP(IP_N_PARSING, PARSER_ERROR_DROPS), + DPAA2_ETH_TRAP_DROP(GRE_PARSING, PARSER_ERROR_DROPS), + DPAA2_ETH_TRAP_DROP(UDP_PARSING, PARSER_ERROR_DROPS), + DPAA2_ETH_TRAP_DROP(TCP_PARSING, PARSER_ERROR_DROPS), + DPAA2_ETH_TRAP_DROP(IPSEC_PARSING, PARSER_ERROR_DROPS), + DPAA2_ETH_TRAP_DROP(SCTP_PARSING, PARSER_ERROR_DROPS), + DPAA2_ETH_TRAP_DROP(DCCP_PARSING, PARSER_ERROR_DROPS), + DPAA2_ETH_TRAP_DROP(GTP_PARSING, PARSER_ERROR_DROPS), + DPAA2_ETH_TRAP_DROP(ESP_PARSING, PARSER_ERROR_DROPS), +}; + +static int dpaa2_eth_dl_info_get(struct devlink *devlink, + struct devlink_info_req *req, + struct netlink_ext_ack *extack) +{ + struct dpaa2_eth_devlink_priv *dl_priv = devlink_priv(devlink); + struct dpaa2_eth_priv *priv = dl_priv->dpaa2_priv; + char buf[10]; + int err; + + err = devlink_info_driver_name_put(req, KBUILD_MODNAME); + if (err) + return err; + + scnprintf(buf, 10, "%d.%d", priv->dpni_ver_major, priv->dpni_ver_minor); + err = devlink_info_version_running_put(req, "dpni", buf); + if (err) + return err; + + return 0; +} + +static struct dpaa2_eth_trap_item * +dpaa2_eth_dl_trap_item_lookup(struct dpaa2_eth_priv *priv, u16 trap_id) +{ + struct dpaa2_eth_trap_data *dpaa2_eth_trap_data = priv->trap_data; + int i; + + for (i = 0; i < ARRAY_SIZE(dpaa2_eth_traps_arr); i++) { + if (dpaa2_eth_traps_arr[i].id == trap_id) + return &dpaa2_eth_trap_data->trap_items_arr[i]; + } + + return NULL; +} + +struct dpaa2_eth_trap_item *dpaa2_eth_dl_get_trap(struct dpaa2_eth_priv *priv, + struct dpaa2_fapr *fapr) +{ + struct dpaa2_faf_error_bit { + int position; + enum devlink_trap_generic_id trap_id; + } faf_bits[] = { + { .position = 5, .trap_id = DEVLINK_TRAP_GENERIC_ID_VXLAN_PARSING }, + { .position = 20, .trap_id = DEVLINK_TRAP_GENERIC_ID_LLC_SNAP_PARSING }, + { .position = 24, .trap_id = DEVLINK_TRAP_GENERIC_ID_VLAN_PARSING }, + { .position = 26, .trap_id = DEVLINK_TRAP_GENERIC_ID_PPPOE_PPP_PARSING }, + { .position = 29, .trap_id = DEVLINK_TRAP_GENERIC_ID_MPLS_PARSING }, + { .position = 31, .trap_id = DEVLINK_TRAP_GENERIC_ID_ARP_PARSING }, + { .position = 52, .trap_id = DEVLINK_TRAP_GENERIC_ID_IP_1_PARSING }, + { .position = 61, .trap_id = DEVLINK_TRAP_GENERIC_ID_IP_N_PARSING }, + { .position = 67, .trap_id = DEVLINK_TRAP_GENERIC_ID_GRE_PARSING }, + { .position = 71, .trap_id = DEVLINK_TRAP_GENERIC_ID_UDP_PARSING }, + { .position = 76, .trap_id = DEVLINK_TRAP_GENERIC_ID_TCP_PARSING }, + { .position = 80, .trap_id = DEVLINK_TRAP_GENERIC_ID_IPSEC_PARSING }, + { .position = 82, .trap_id = DEVLINK_TRAP_GENERIC_ID_SCTP_PARSING }, + { .position = 84, .trap_id = DEVLINK_TRAP_GENERIC_ID_DCCP_PARSING }, + { .position = 88, .trap_id = DEVLINK_TRAP_GENERIC_ID_GTP_PARSING }, + { .position = 90, .trap_id = DEVLINK_TRAP_GENERIC_ID_ESP_PARSING }, + }; + u64 faf_word; + u64 mask; + int i; + + for (i = 0; i < ARRAY_SIZE(faf_bits); i++) { + if (faf_bits[i].position < 32) { + /* Low part of FAF. + * position ranges from 31 to 0, mask from 0 to 31. + */ + mask = 1ull << (31 - faf_bits[i].position); + faf_word = __le32_to_cpu(fapr->faf_lo); + } else { + /* High part of FAF. + * position ranges from 95 to 32, mask from 0 to 63. + */ + mask = 1ull << (63 - (faf_bits[i].position - 32)); + faf_word = __le64_to_cpu(fapr->faf_hi); + } + if (faf_word & mask) + return dpaa2_eth_dl_trap_item_lookup(priv, faf_bits[i].trap_id); + } + return NULL; +} + +static int dpaa2_eth_dl_trap_init(struct devlink *devlink, + const struct devlink_trap *trap, + void *trap_ctx) +{ + struct dpaa2_eth_devlink_priv *dl_priv = devlink_priv(devlink); + struct dpaa2_eth_priv *priv = dl_priv->dpaa2_priv; + struct dpaa2_eth_trap_item *dpaa2_eth_trap_item; + + dpaa2_eth_trap_item = dpaa2_eth_dl_trap_item_lookup(priv, trap->id); + if (WARN_ON(!dpaa2_eth_trap_item)) + return -ENOENT; + + dpaa2_eth_trap_item->trap_ctx = trap_ctx; + + return 0; +} + +static int dpaa2_eth_dl_trap_action_set(struct devlink *devlink, + const struct devlink_trap *trap, + enum devlink_trap_action action, + struct netlink_ext_ack *extack) +{ + /* No support for changing the action of an independent packet trap, + * only per trap group - parser error drops + */ + NL_SET_ERR_MSG_MOD(extack, + "Cannot change trap action independently of group"); + return -EOPNOTSUPP; +} + +static int dpaa2_eth_dl_trap_group_action_set(struct devlink *devlink, + const struct devlink_trap_group *group, + enum devlink_trap_action action, + struct netlink_ext_ack *extack) +{ + struct dpaa2_eth_devlink_priv *dl_priv = devlink_priv(devlink); + struct dpaa2_eth_priv *priv = dl_priv->dpaa2_priv; + struct net_device *net_dev = priv->net_dev; + struct device *dev = net_dev->dev.parent; + struct dpni_error_cfg err_cfg = {0}; + int err; + + if (group->id != DEVLINK_TRAP_GROUP_GENERIC_ID_PARSER_ERROR_DROPS) + return -EOPNOTSUPP; + + /* Configure handling of frames marked as errors from the parser */ + err_cfg.errors = DPAA2_FAS_RX_ERR_MASK; + err_cfg.set_frame_annotation = 1; + + switch (action) { + case DEVLINK_TRAP_ACTION_DROP: + err_cfg.error_action = DPNI_ERROR_ACTION_DISCARD; + break; + case DEVLINK_TRAP_ACTION_TRAP: + err_cfg.error_action = DPNI_ERROR_ACTION_SEND_TO_ERROR_QUEUE; + break; + default: + return -EOPNOTSUPP; + } + + err = dpni_set_errors_behavior(priv->mc_io, 0, priv->mc_token, &err_cfg); + if (err) { + dev_err(dev, "dpni_set_errors_behavior failed\n"); + return err; + } + + return 0; +} + +static const struct devlink_ops dpaa2_eth_devlink_ops = { + .info_get = dpaa2_eth_dl_info_get, + .trap_init = dpaa2_eth_dl_trap_init, + .trap_action_set = dpaa2_eth_dl_trap_action_set, + .trap_group_action_set = dpaa2_eth_dl_trap_group_action_set, +}; + +int dpaa2_eth_dl_register(struct dpaa2_eth_priv *priv) +{ + struct net_device *net_dev = priv->net_dev; + struct device *dev = net_dev->dev.parent; + struct dpaa2_eth_devlink_priv *dl_priv; + int err; + + priv->devlink = devlink_alloc(&dpaa2_eth_devlink_ops, sizeof(*dl_priv)); + if (!priv->devlink) { + dev_err(dev, "devlink_alloc failed\n"); + return -ENOMEM; + } + dl_priv = devlink_priv(priv->devlink); + dl_priv->dpaa2_priv = priv; + + err = devlink_register(priv->devlink, dev); + if (err) { + dev_err(dev, "devlink_register() = %d\n", err); + goto devlink_free; + } + + return 0; + +devlink_free: + devlink_free(priv->devlink); + + return err; +} + +void dpaa2_eth_dl_unregister(struct dpaa2_eth_priv *priv) +{ + devlink_unregister(priv->devlink); + devlink_free(priv->devlink); +} + +int dpaa2_eth_dl_port_add(struct dpaa2_eth_priv *priv) +{ + struct devlink_port *devlink_port = &priv->devlink_port; + struct devlink_port_attrs attrs = {}; + int err; + + attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL; + devlink_port_attrs_set(devlink_port, &attrs); + + err = devlink_port_register(priv->devlink, devlink_port, 0); + if (err) + return err; + + devlink_port_type_eth_set(devlink_port, priv->net_dev); + + return 0; +} + +void dpaa2_eth_dl_port_del(struct dpaa2_eth_priv *priv) +{ + struct devlink_port *devlink_port = &priv->devlink_port; + + devlink_port_type_clear(devlink_port); + devlink_port_unregister(devlink_port); +} + +int dpaa2_eth_dl_traps_register(struct dpaa2_eth_priv *priv) +{ + struct dpaa2_eth_trap_data *dpaa2_eth_trap_data; + struct net_device *net_dev = priv->net_dev; + struct device *dev = net_dev->dev.parent; + int err; + + dpaa2_eth_trap_data = kzalloc(sizeof(*dpaa2_eth_trap_data), GFP_KERNEL); + if (!dpaa2_eth_trap_data) + return -ENOMEM; + priv->trap_data = dpaa2_eth_trap_data; + + dpaa2_eth_trap_data->trap_items_arr = kcalloc(ARRAY_SIZE(dpaa2_eth_traps_arr), + sizeof(struct dpaa2_eth_trap_item), + GFP_KERNEL); + if (!dpaa2_eth_trap_data->trap_items_arr) { + err = -ENOMEM; + goto trap_data_free; + } + + err = devlink_trap_groups_register(priv->devlink, dpaa2_eth_trap_groups_arr, + ARRAY_SIZE(dpaa2_eth_trap_groups_arr)); + if (err) { + dev_err(dev, "devlink_trap_groups_register() = %d\n", err); + goto trap_items_arr_free; + } + + err = devlink_traps_register(priv->devlink, dpaa2_eth_traps_arr, + ARRAY_SIZE(dpaa2_eth_traps_arr), priv); + if (err) { + dev_err(dev, "devlink_traps_register() = %d\n", err); + goto trap_groups_unregiser; + } + + return 0; + +trap_groups_unregiser: + devlink_trap_groups_unregister(priv->devlink, dpaa2_eth_trap_groups_arr, + ARRAY_SIZE(dpaa2_eth_trap_groups_arr)); +trap_items_arr_free: + kfree(dpaa2_eth_trap_data->trap_items_arr); +trap_data_free: + kfree(dpaa2_eth_trap_data); + priv->trap_data = NULL; + + return err; +} + +void dpaa2_eth_dl_traps_unregister(struct dpaa2_eth_priv *priv) +{ + devlink_traps_unregister(priv->devlink, dpaa2_eth_traps_arr, + ARRAY_SIZE(dpaa2_eth_traps_arr)); + devlink_trap_groups_unregister(priv->devlink, dpaa2_eth_trap_groups_arr, + ARRAY_SIZE(dpaa2_eth_trap_groups_arr)); + kfree(priv->trap_data->trap_items_arr); + kfree(priv->trap_data); +} diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c index fe4caf7aad7c..cf9400a9886d 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c @@ -509,6 +509,58 @@ err_frame_format: percpu_stats->rx_dropped++; } +/* Processing of Rx frames received on the error FQ + * We check and print the error bits and then free the frame + */ +static void dpaa2_eth_rx_err(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_channel *ch, + const struct dpaa2_fd *fd, + struct dpaa2_eth_fq *fq __always_unused) +{ + struct device *dev = priv->net_dev->dev.parent; + dma_addr_t addr = dpaa2_fd_get_addr(fd); + u8 fd_format = dpaa2_fd_get_format(fd); + struct rtnl_link_stats64 *percpu_stats; + struct dpaa2_eth_trap_item *trap_item; + struct dpaa2_fapr *fapr; + struct sk_buff *skb; + void *buf_data; + void *vaddr; + + vaddr = dpaa2_iova_to_virt(priv->iommu_domain, addr); + dma_sync_single_for_cpu(dev, addr, priv->rx_buf_size, + DMA_BIDIRECTIONAL); + + buf_data = vaddr + dpaa2_fd_get_offset(fd); + + if (fd_format == dpaa2_fd_single) { + dma_unmap_page(dev, addr, priv->rx_buf_size, + DMA_BIDIRECTIONAL); + skb = dpaa2_eth_build_linear_skb(ch, fd, vaddr); + } else if (fd_format == dpaa2_fd_sg) { + dma_unmap_page(dev, addr, priv->rx_buf_size, + DMA_BIDIRECTIONAL); + skb = dpaa2_eth_build_frag_skb(priv, ch, buf_data); + free_pages((unsigned long)vaddr, 0); + } else { + /* We don't support any other format */ + dpaa2_eth_free_rx_fd(priv, fd, vaddr); + goto err_frame_format; + } + + fapr = dpaa2_get_fapr(vaddr, false); + trap_item = dpaa2_eth_dl_get_trap(priv, fapr); + if (trap_item) + devlink_trap_report(priv->devlink, skb, trap_item->trap_ctx, + &priv->devlink_port, NULL); + consume_skb(skb); + +err_frame_format: + percpu_stats = this_cpu_ptr(priv->percpu_stats); + percpu_stats->rx_errors++; + ch->buf_count--; +} + /* Consume all frames pull-dequeued into the store. This is the simplest way to * make sure we don't accidentally issue another volatile dequeue which would * overwrite (leak) frames already in the store. @@ -2723,6 +2775,7 @@ static void dpaa2_eth_set_fq_affinity(struct dpaa2_eth_priv *priv) fq = &priv->fq[i]; switch (fq->type) { case DPAA2_RX_FQ: + case DPAA2_RX_ERR_FQ: fq->target_cpu = rx_cpu; rx_cpu = cpumask_next(rx_cpu, &priv->dpio_cpumask); if (rx_cpu >= nr_cpu_ids) @@ -2766,6 +2819,10 @@ static void dpaa2_eth_setup_fqs(struct dpaa2_eth_priv *priv) } } + /* We have exactly one Rx error queue per DPNI */ + priv->fq[priv->num_fqs].type = DPAA2_RX_ERR_FQ; + priv->fq[priv->num_fqs++].consume = dpaa2_eth_rx_err; + /* For each FQ, decide on which core to process incoming frames */ dpaa2_eth_set_fq_affinity(priv); } @@ -3341,6 +3398,38 @@ static int dpaa2_eth_setup_tx_flow(struct dpaa2_eth_priv *priv, return 0; } +static int setup_rx_err_flow(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_fq *fq) +{ + struct device *dev = priv->net_dev->dev.parent; + struct dpni_queue q = { { 0 } }; + struct dpni_queue_id qid; + u8 q_opt = DPNI_QUEUE_OPT_USER_CTX | DPNI_QUEUE_OPT_DEST; + int err; + + err = dpni_get_queue(priv->mc_io, 0, priv->mc_token, + DPNI_QUEUE_RX_ERR, 0, 0, &q, &qid); + if (err) { + dev_err(dev, "dpni_get_queue() failed (%d)\n", err); + return err; + } + + fq->fqid = qid.fqid; + + q.destination.id = fq->channel->dpcon_id; + q.destination.type = DPNI_DEST_DPCON; + q.destination.priority = 1; + q.user_context = (u64)(uintptr_t)fq; + err = dpni_set_queue(priv->mc_io, 0, priv->mc_token, + DPNI_QUEUE_RX_ERR, 0, 0, q_opt, &q); + if (err) { + dev_err(dev, "dpni_set_queue() failed (%d)\n", err); + return err; + } + + return 0; +} + /* Supported header fields for Rx hash distribution key */ static const struct dpaa2_eth_dist_fields dist_fields[] = { { @@ -3739,6 +3828,9 @@ static int dpaa2_eth_bind_dpni(struct dpaa2_eth_priv *priv) case DPAA2_TX_CONF_FQ: err = dpaa2_eth_setup_tx_flow(priv, &priv->fq[i]); break; + case DPAA2_RX_ERR_FQ: + err = setup_rx_err_flow(priv, &priv->fq[i]); + break; default: dev_err(dev, "Invalid FQ type %d\n", priv->fq[i].type); return -EINVAL; @@ -4223,6 +4315,18 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev) if (err) goto err_connect_mac; + err = dpaa2_eth_dl_register(priv); + if (err) + goto err_dl_register; + + err = dpaa2_eth_dl_traps_register(priv); + if (err) + goto err_dl_trap_register; + + err = dpaa2_eth_dl_port_add(priv); + if (err) + goto err_dl_port_add; + err = register_netdev(net_dev); if (err < 0) { dev_err(dev, "register_netdev() failed\n"); @@ -4237,6 +4341,12 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev) return 0; err_netdev_reg: + dpaa2_eth_dl_port_del(priv); +err_dl_port_add: + dpaa2_eth_dl_traps_unregister(priv); +err_dl_trap_register: + dpaa2_eth_dl_unregister(priv); +err_dl_register: dpaa2_eth_disconnect_mac(priv); err_connect_mac: if (priv->do_link_poll) @@ -4291,6 +4401,10 @@ static int dpaa2_eth_remove(struct fsl_mc_device *ls_dev) unregister_netdev(net_dev); + dpaa2_eth_dl_port_del(priv); + dpaa2_eth_dl_traps_unregister(priv); + dpaa2_eth_dl_unregister(priv); + if (priv->do_link_poll) kthread_stop(priv->poll_thread); else diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h index 6436fa3b25cb..d236b8695c39 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h @@ -11,6 +11,7 @@ #include <linux/if_vlan.h> #include <linux/fsl/mc.h> #include <linux/net_tstamp.h> +#include <net/devlink.h> #include <soc/fsl/dpaa2-io.h> #include <soc/fsl/dpaa2-fd.h> @@ -181,6 +182,49 @@ struct dpaa2_fas { */ #define DPAA2_TS_OFFSET 0x8 +/* Frame annotation parse results */ +struct dpaa2_fapr { + /* 64-bit word 1 */ + __le32 faf_lo; + __le16 faf_ext; + __le16 nxt_hdr; + /* 64-bit word 2 */ + __le64 faf_hi; + /* 64-bit word 3 */ + u8 last_ethertype_offset; + u8 vlan_tci_offset_n; + u8 vlan_tci_offset_1; + u8 llc_snap_offset; + u8 eth_offset; + u8 ip1_pid_offset; + u8 shim_offset_2; + u8 shim_offset_1; + /* 64-bit word 4 */ + u8 l5_offset; + u8 l4_offset; + u8 gre_offset; + u8 l3_offset_n; + u8 l3_offset_1; + u8 mpls_offset_n; + u8 mpls_offset_1; + u8 pppoe_offset; + /* 64-bit word 5 */ + __le16 running_sum; + __le16 gross_running_sum; + u8 ipv6_frag_offset; + u8 nxt_hdr_offset; + u8 routing_hdr_offset_2; + u8 routing_hdr_offset_1; + /* 64-bit word 6 */ + u8 reserved[5]; /* Soft-parsing context */ + u8 ip_proto_offset_n; + u8 nxt_hdr_frag_offset; + u8 parse_error_code; +}; + +#define DPAA2_FAPR_OFFSET 0x10 +#define DPAA2_FAPR_SIZE sizeof((struct dpaa2_fapr)) + /* Frame annotation egress action descriptor */ #define DPAA2_FAEAD_OFFSET 0x58 @@ -229,6 +273,11 @@ static inline __le64 *dpaa2_get_ts(void *buf_addr, bool swa) return dpaa2_get_hwa(buf_addr, swa) + DPAA2_TS_OFFSET; } +static inline struct dpaa2_fapr *dpaa2_get_fapr(void *buf_addr, bool swa) +{ + return dpaa2_get_hwa(buf_addr, swa) + DPAA2_FAPR_OFFSET; +} + static inline struct dpaa2_faead *dpaa2_get_faead(void *buf_addr, bool swa) { return dpaa2_get_hwa(buf_addr, swa) + DPAA2_FAEAD_OFFSET; @@ -343,8 +392,10 @@ struct dpaa2_eth_ch_stats { #define DPAA2_ETH_MAX_RX_QUEUES \ (DPAA2_ETH_MAX_RX_QUEUES_PER_TC * DPAA2_ETH_MAX_TCS) #define DPAA2_ETH_MAX_TX_QUEUES 16 +#define DPAA2_ETH_MAX_RX_ERR_QUEUES 1 #define DPAA2_ETH_MAX_QUEUES (DPAA2_ETH_MAX_RX_QUEUES + \ - DPAA2_ETH_MAX_TX_QUEUES) + DPAA2_ETH_MAX_TX_QUEUES + \ + DPAA2_ETH_MAX_RX_ERR_QUEUES) #define DPAA2_ETH_MAX_NETDEV_QUEUES \ (DPAA2_ETH_MAX_TX_QUEUES * DPAA2_ETH_MAX_TCS) @@ -353,6 +404,7 @@ struct dpaa2_eth_ch_stats { enum dpaa2_eth_fq_type { DPAA2_RX_FQ = 0, DPAA2_TX_CONF_FQ, + DPAA2_RX_ERR_FQ }; struct dpaa2_eth_priv; @@ -426,6 +478,15 @@ struct dpaa2_eth_sgt_cache { u16 count; }; +struct dpaa2_eth_trap_item { + void *trap_ctx; +}; + +struct dpaa2_eth_trap_data { + struct dpaa2_eth_trap_item *trap_items_arr; + struct dpaa2_eth_priv *priv; +}; + /* Driver private data */ struct dpaa2_eth_priv { struct net_device *net_dev; @@ -503,6 +564,13 @@ struct dpaa2_eth_priv { * queue before transmit current packet. */ struct mutex onestep_tstamp_lock; + struct devlink *devlink; + struct dpaa2_eth_trap_data *trap_data; + struct devlink_port devlink_port; +}; + +struct dpaa2_eth_devlink_priv { + struct dpaa2_eth_priv *dpaa2_priv; }; #define TX_TSTAMP 0x1 @@ -636,4 +704,15 @@ void dpaa2_eth_set_rx_taildrop(struct dpaa2_eth_priv *priv, extern const struct dcbnl_rtnl_ops dpaa2_eth_dcbnl_ops; +int dpaa2_eth_dl_register(struct dpaa2_eth_priv *priv); +void dpaa2_eth_dl_unregister(struct dpaa2_eth_priv *priv); + +int dpaa2_eth_dl_port_add(struct dpaa2_eth_priv *priv); +void dpaa2_eth_dl_port_del(struct dpaa2_eth_priv *priv); + +int dpaa2_eth_dl_traps_register(struct dpaa2_eth_priv *priv); +void dpaa2_eth_dl_traps_unregister(struct dpaa2_eth_priv *priv); + +struct dpaa2_eth_trap_item *dpaa2_eth_dl_get_trap(struct dpaa2_eth_priv *priv, + struct dpaa2_fapr *fapr); #endif /* __DPAA2_H */ diff --git a/include/net/devlink.h b/include/net/devlink.h index 1c286e9a3590..89ede1ce3a3a 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -784,6 +784,22 @@ enum devlink_trap_generic_id { DEVLINK_TRAP_GENERIC_ID_FLOW_ACTION_SAMPLE, DEVLINK_TRAP_GENERIC_ID_FLOW_ACTION_TRAP, DEVLINK_TRAP_GENERIC_ID_EARLY_DROP, + DEVLINK_TRAP_GENERIC_ID_VXLAN_PARSING, + DEVLINK_TRAP_GENERIC_ID_LLC_SNAP_PARSING, + DEVLINK_TRAP_GENERIC_ID_VLAN_PARSING, + DEVLINK_TRAP_GENERIC_ID_PPPOE_PPP_PARSING, + DEVLINK_TRAP_GENERIC_ID_MPLS_PARSING, + DEVLINK_TRAP_GENERIC_ID_ARP_PARSING, + DEVLINK_TRAP_GENERIC_ID_IP_1_PARSING, + DEVLINK_TRAP_GENERIC_ID_IP_N_PARSING, + DEVLINK_TRAP_GENERIC_ID_GRE_PARSING, + DEVLINK_TRAP_GENERIC_ID_UDP_PARSING, + DEVLINK_TRAP_GENERIC_ID_TCP_PARSING, + DEVLINK_TRAP_GENERIC_ID_IPSEC_PARSING, + DEVLINK_TRAP_GENERIC_ID_SCTP_PARSING, + DEVLINK_TRAP_GENERIC_ID_DCCP_PARSING, + DEVLINK_TRAP_GENERIC_ID_GTP_PARSING, + DEVLINK_TRAP_GENERIC_ID_ESP_PARSING, /* Add new generic trap IDs above */ __DEVLINK_TRAP_GENERIC_ID_MAX, @@ -819,6 +835,7 @@ enum devlink_trap_group_generic_id { DEVLINK_TRAP_GROUP_GENERIC_ID_PTP_GENERAL, DEVLINK_TRAP_GROUP_GENERIC_ID_ACL_SAMPLE, DEVLINK_TRAP_GROUP_GENERIC_ID_ACL_TRAP, + DEVLINK_TRAP_GROUP_GENERIC_ID_PARSER_ERROR_DROPS, /* Add new generic trap group IDs above */ __DEVLINK_TRAP_GROUP_GENERIC_ID_MAX, @@ -974,6 +991,39 @@ enum devlink_trap_group_generic_id { "flow_action_trap" #define DEVLINK_TRAP_GENERIC_NAME_EARLY_DROP \ "early_drop" +#define DEVLINK_TRAP_GENERIC_NAME_VXLAN_PARSING \ + "vxlan_parsing" +#define DEVLINK_TRAP_GENERIC_NAME_LLC_SNAP_PARSING \ + "llc_snap_parsing" +#define DEVLINK_TRAP_GENERIC_NAME_VLAN_PARSING \ + "vlan_parsing" +#define DEVLINK_TRAP_GENERIC_NAME_PPPOE_PPP_PARSING \ + "pppoe_ppp_parsing" +#define DEVLINK_TRAP_GENERIC_NAME_MPLS_PARSING \ + "mpls_parsing" +#define DEVLINK_TRAP_GENERIC_NAME_ARP_PARSING \ + "arp_parsing" +#define DEVLINK_TRAP_GENERIC_NAME_IP_1_PARSING \ + "ip_1_parsing" +#define DEVLINK_TRAP_GENERIC_NAME_IP_N_PARSING \ + "ip_n_parsing" +#define DEVLINK_TRAP_GENERIC_NAME_GRE_PARSING \ + "gre_parsing" +#define DEVLINK_TRAP_GENERIC_NAME_UDP_PARSING \ + "udp_parsing" +#define DEVLINK_TRAP_GENERIC_NAME_TCP_PARSING \ + "tcp_parsing" +#define DEVLINK_TRAP_GENERIC_NAME_IPSEC_PARSING \ + "ipsec_parsing" +#define DEVLINK_TRAP_GENERIC_NAME_SCTP_PARSING \ + "sctp_parsing" +#define DEVLINK_TRAP_GENERIC_NAME_DCCP_PARSING \ + "dccp_parsing" +#define DEVLINK_TRAP_GENERIC_NAME_GTP_PARSING \ + "gtp_parsing" +#define DEVLINK_TRAP_GENERIC_NAME_ESP_PARSING \ + "esp_parsing" + #define DEVLINK_TRAP_GROUP_GENERIC_NAME_L2_DROPS \ "l2_drops" @@ -1025,6 +1075,8 @@ enum devlink_trap_group_generic_id { "acl_sample" #define DEVLINK_TRAP_GROUP_GENERIC_NAME_ACL_TRAP \ "acl_trap" +#define DEVLINK_TRAP_GROUP_GENERIC_NAME_PARSER_ERROR_DROPS \ + "parser_error_drops" #define DEVLINK_TRAP_GENERIC(_type, _init_action, _id, _group_id, \ _metadata_cap) \ @@ -1191,6 +1243,16 @@ struct devlink_ops { const struct devlink_trap_policer *policer, struct netlink_ext_ack *extack); /** + * @trap_group_action_set: Trap group action set function. + * + * If this callback is populated, it will take precedence over looping + * over all traps in a group and calling .trap_action_set(). + */ + int (*trap_group_action_set)(struct devlink *devlink, + const struct devlink_trap_group *group, + enum devlink_trap_action action, + struct netlink_ext_ack *extack); + /** * @trap_policer_init: Trap policer initialization function. * * Should be used by device drivers to initialize the trap policer in diff --git a/net/core/devlink.c b/net/core/devlink.c index 6f2863e717a9..2a95f7f27a54 100644 --- a/net/core/devlink.c +++ b/net/core/devlink.c @@ -6720,6 +6720,24 @@ __devlink_trap_group_action_set(struct devlink *devlink, struct devlink_trap_item *trap_item; int err; + if (devlink->ops->trap_group_action_set) { + err = devlink->ops->trap_group_action_set(devlink, group_item->group, + trap_action, extack); + if (err) + return err; + + list_for_each_entry(trap_item, &devlink->trap_list, list) { + if (strcmp(trap_item->group_item->group->name, group_name)) + continue; + if (trap_item->action != trap_action && + trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP) + continue; + trap_item->action = trap_action; + } + + return 0; + } + list_for_each_entry(trap_item, &devlink->trap_list, list) { if (strcmp(trap_item->group_item->group->name, group_name)) continue; @@ -8925,6 +8943,22 @@ static const struct devlink_trap devlink_trap_generic[] = { DEVLINK_TRAP(FLOW_ACTION_SAMPLE, CONTROL), DEVLINK_TRAP(FLOW_ACTION_TRAP, CONTROL), DEVLINK_TRAP(EARLY_DROP, DROP), + DEVLINK_TRAP(VXLAN_PARSING, DROP), + DEVLINK_TRAP(LLC_SNAP_PARSING, DROP), + DEVLINK_TRAP(VLAN_PARSING, DROP), + DEVLINK_TRAP(PPPOE_PPP_PARSING, DROP), + DEVLINK_TRAP(MPLS_PARSING, DROP), + DEVLINK_TRAP(ARP_PARSING, DROP), + DEVLINK_TRAP(IP_1_PARSING, DROP), + DEVLINK_TRAP(IP_N_PARSING, DROP), + DEVLINK_TRAP(GRE_PARSING, DROP), + DEVLINK_TRAP(UDP_PARSING, DROP), + DEVLINK_TRAP(TCP_PARSING, DROP), + DEVLINK_TRAP(IPSEC_PARSING, DROP), + DEVLINK_TRAP(SCTP_PARSING, DROP), + DEVLINK_TRAP(DCCP_PARSING, DROP), + DEVLINK_TRAP(GTP_PARSING, DROP), + DEVLINK_TRAP(ESP_PARSING, DROP), }; #define DEVLINK_TRAP_GROUP(_id) \ @@ -8959,6 +8993,7 @@ static const struct devlink_trap_group devlink_trap_group_generic[] = { DEVLINK_TRAP_GROUP(PTP_GENERAL), DEVLINK_TRAP_GROUP(ACL_SAMPLE), DEVLINK_TRAP_GROUP(ACL_TRAP), + DEVLINK_TRAP_GROUP(PARSER_ERROR_DROPS), }; static int devlink_trap_generic_verify(const struct devlink_trap *trap) |