* [PATCH net-next 07/11] mlxsw: core: Add API to set trap action
From: Ido Schimmel @ 2019-07-07 7:58 UTC (permalink / raw)
To: netdev
Cc: davem, jiri, mlxsw, dsahern, roopa, nikolay, andy, pablo,
jakub.kicinski, pieter.jansenvanvuuren, andrew, f.fainelli,
vivien.didelot, Ido Schimmel
In-Reply-To: <20190707075828.3315-1-idosch@idosch.org>
From: Ido Schimmel <idosch@mellanox.com>
Up until now the action of a trap was never changed during its lifetime.
This is going to change by subsequent patches that will allow devlink to
control the action of certain traps.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/core.c | 12 ++++++++++++
drivers/net/ethernet/mellanox/mlxsw/core.h | 3 +++
2 files changed, 15 insertions(+)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c
index 17ceac7505e5..6ec07ecfb5f6 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core.c
@@ -1477,6 +1477,18 @@ void mlxsw_core_trap_unregister(struct mlxsw_core *mlxsw_core,
}
EXPORT_SYMBOL(mlxsw_core_trap_unregister);
+int mlxsw_core_trap_action_set(struct mlxsw_core *mlxsw_core,
+ const struct mlxsw_listener *listener,
+ enum mlxsw_reg_hpkt_action action)
+{
+ char hpkt_pl[MLXSW_REG_HPKT_LEN];
+
+ mlxsw_reg_hpkt_pack(hpkt_pl, action, listener->trap_id,
+ listener->trap_group, listener->is_ctrl);
+ return mlxsw_reg_write(mlxsw_core, MLXSW_REG(hpkt), hpkt_pl);
+}
+EXPORT_SYMBOL(mlxsw_core_trap_action_set);
+
static u64 mlxsw_core_tid_get(struct mlxsw_core *mlxsw_core)
{
return atomic64_inc_return(&mlxsw_core->emad.tid);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h
index 8efcff4b59cb..19cea16c30bb 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/core.h
@@ -128,6 +128,9 @@ int mlxsw_core_trap_register(struct mlxsw_core *mlxsw_core,
void mlxsw_core_trap_unregister(struct mlxsw_core *mlxsw_core,
const struct mlxsw_listener *listener,
void *priv);
+int mlxsw_core_trap_action_set(struct mlxsw_core *mlxsw_core,
+ const struct mlxsw_listener *listener,
+ enum mlxsw_reg_hpkt_action action);
typedef void mlxsw_reg_trans_cb_t(struct mlxsw_core *mlxsw_core, char *payload,
size_t payload_len, unsigned long cb_priv);
--
2.20.1
^ permalink raw reply related
* [PATCH net-next 06/11] Documentation: Add description of netdevsim traps
From: Ido Schimmel @ 2019-07-07 7:58 UTC (permalink / raw)
To: netdev
Cc: davem, jiri, mlxsw, dsahern, roopa, nikolay, andy, pablo,
jakub.kicinski, pieter.jansenvanvuuren, andrew, f.fainelli,
vivien.didelot, Ido Schimmel
In-Reply-To: <20190707075828.3315-1-idosch@idosch.org>
From: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
---
.../networking/devlink-trap-netdevsim.rst | 20 +++++++++++++++++++
Documentation/networking/devlink-trap.rst | 11 ++++++++++
Documentation/networking/index.rst | 1 +
drivers/net/netdevsim/dev.c | 3 +++
4 files changed, 35 insertions(+)
create mode 100644 Documentation/networking/devlink-trap-netdevsim.rst
diff --git a/Documentation/networking/devlink-trap-netdevsim.rst b/Documentation/networking/devlink-trap-netdevsim.rst
new file mode 100644
index 000000000000..b721c9415473
--- /dev/null
+++ b/Documentation/networking/devlink-trap-netdevsim.rst
@@ -0,0 +1,20 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+======================
+Devlink Trap netdevsim
+======================
+
+Driver-specific Traps
+=====================
+
+.. list-table:: List of Driver-specific Traps Registered by ``netdevsim``
+ :widths: 5 5 90
+
+ * - Name
+ - Type
+ - Description
+ * - ``fid_miss``
+ - ``exception``
+ - When a packet enters the device it is classified to a filtering
+ indentifier (FID) based on the ingress port and VLAN. This trap is used
+ to trap packets for which a FID could not be found
diff --git a/Documentation/networking/devlink-trap.rst b/Documentation/networking/devlink-trap.rst
index 4a4fd42f5372..906cdeb0d1f3 100644
--- a/Documentation/networking/devlink-trap.rst
+++ b/Documentation/networking/devlink-trap.rst
@@ -153,6 +153,17 @@ be added to the following table:
- Traps packets that the device decided to drop because they could not be
enqueued to a transmission queue which is full
+Driver-specific Packet Traps
+============================
+
+Device drivers can register driver-specific packet traps, but these must be
+clearly documented. Such traps can correspond to device-specific exceptions and
+help debug packet drops caused by these exceptions. The following list includes
+links to the description of driver-specific traps registered by various device
+drivers:
+
+ * :doc:`/devlink-trap-netdevsim`
+
Generic Packet Trap Groups
==========================
diff --git a/Documentation/networking/index.rst b/Documentation/networking/index.rst
index 86a814e4d450..37eabc17894c 100644
--- a/Documentation/networking/index.rst
+++ b/Documentation/networking/index.rst
@@ -15,6 +15,7 @@ Contents:
dsa/index
devlink-info-versions
devlink-trap
+ devlink-trap-netdevsim
ieee802154
kapi
z8530book
diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c
index 2d8c60c3326c..2892b3154940 100644
--- a/drivers/net/netdevsim/dev.c
+++ b/drivers/net/netdevsim/dev.c
@@ -218,6 +218,9 @@ struct nsim_trap_data {
spinlock_t trap_lock; /* Protects trap_items_arr */
};
+/* All driver-specific traps must be documented in
+ * Documentation/networking/devlink-trap-netdevsim.rst
+ */
enum {
NSIM_TRAP_ID_BASE = DEVLINK_TRAP_GENERIC_ID_MAX,
NSIM_TRAP_ID_FID_MISS,
--
2.20.1
^ permalink raw reply related
* [PATCH net-next 05/11] netdevsim: Add devlink-trap support
From: Ido Schimmel @ 2019-07-07 7:58 UTC (permalink / raw)
To: netdev
Cc: davem, jiri, mlxsw, dsahern, roopa, nikolay, andy, pablo,
jakub.kicinski, pieter.jansenvanvuuren, andrew, f.fainelli,
vivien.didelot, Ido Schimmel
In-Reply-To: <20190707075828.3315-1-idosch@idosch.org>
From: Ido Schimmel <idosch@mellanox.com>
Have netdevsim register its trap groups and traps with devlink during
initialization and periodically report trapped packets to devlink core.
Since netdevsim is not a real device, the trapped packets are emulated
using a workqueue that periodically reports a UDP packet with a random
5-tuple from each active packet trap and from each running netdev.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/netdevsim/dev.c | 270 +++++++++++++++++++++++++++++-
drivers/net/netdevsim/netdevsim.h | 1 +
2 files changed, 270 insertions(+), 1 deletion(-)
diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c
index c5c417a3c0ce..2d8c60c3326c 100644
--- a/drivers/net/netdevsim/dev.c
+++ b/drivers/net/netdevsim/dev.c
@@ -17,11 +17,21 @@
#include <linux/debugfs.h>
#include <linux/device.h>
+#include <linux/etherdevice.h>
+#include <linux/inet.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/random.h>
+#include <linux/workqueue.h>
+#include <linux/random.h>
#include <linux/rtnetlink.h>
#include <net/devlink.h>
+#include <net/ip.h>
+#include <uapi/linux/devlink.h>
+#include <uapi/linux/ip.h>
+#include <uapi/linux/udp.h>
#include "netdevsim.h"
@@ -196,6 +206,205 @@ static int nsim_dev_resources_register(struct devlink *devlink)
return err;
}
+struct nsim_trap_item {
+ void *trap_ctx;
+ enum devlink_trap_action action;
+};
+
+struct nsim_trap_data {
+ struct delayed_work trap_report_dw;
+ struct nsim_trap_item *trap_items_arr;
+ struct nsim_dev *nsim_dev;
+ spinlock_t trap_lock; /* Protects trap_items_arr */
+};
+
+enum {
+ NSIM_TRAP_ID_BASE = DEVLINK_TRAP_GENERIC_ID_MAX,
+ NSIM_TRAP_ID_FID_MISS,
+};
+
+#define NSIM_TRAP_NAME_FID_MISS "fid_miss"
+
+#define NSIM_TRAP_METADATA DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT
+
+#define NSIM_TRAP_DROP(_id, _group_id) \
+ DEVLINK_TRAP_GENERIC(DROP, DROP, _id, \
+ DEVLINK_TRAP_GROUP_GENERIC(_group_id), \
+ NSIM_TRAP_METADATA)
+#define NSIM_TRAP_EXCEPTION(_id, _group_id) \
+ DEVLINK_TRAP_GENERIC(EXCEPTION, TRAP, _id, \
+ DEVLINK_TRAP_GROUP_GENERIC(_group_id), \
+ NSIM_TRAP_METADATA)
+#define NSIM_TRAP_DRIVER_EXCEPTION(_id, _group_id) \
+ DEVLINK_TRAP_DRIVER(EXCEPTION, TRAP, NSIM_TRAP_ID_##_id, \
+ NSIM_TRAP_NAME_##_id, \
+ DEVLINK_TRAP_GROUP_GENERIC(_group_id), \
+ NSIM_TRAP_METADATA)
+
+static const struct devlink_trap nsim_traps_arr[] = {
+ NSIM_TRAP_DROP(SMAC_MC, L2_DROPS),
+ NSIM_TRAP_DROP(VLAN_TAG_MISMATCH, L2_DROPS),
+ NSIM_TRAP_DROP(INGRESS_VLAN_FILTER, L2_DROPS),
+ NSIM_TRAP_DROP(INGRESS_STP_FILTER, L2_DROPS),
+ NSIM_TRAP_DROP(EMPTY_TX_LIST, L2_DROPS),
+ NSIM_TRAP_DROP(PORT_LOOPBACK_FILTER, L2_DROPS),
+ NSIM_TRAP_DRIVER_EXCEPTION(FID_MISS, L2_DROPS),
+ NSIM_TRAP_DROP(BLACKHOLE_ROUTE, L3_DROPS),
+ NSIM_TRAP_EXCEPTION(TTL_ERROR, L3_DROPS),
+ NSIM_TRAP_DROP(TAIL_DROP, BUFFER_DROPS),
+};
+
+#define NSIM_TRAP_L4_DATA_LEN 100
+
+static struct sk_buff *nsim_dev_trap_skb_build(void)
+{
+ int tot_len, data_len = NSIM_TRAP_L4_DATA_LEN;
+ struct sk_buff *skb;
+ struct udphdr *udph;
+ struct ethhdr *eth;
+ struct iphdr *iph;
+
+ skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
+ if (!skb)
+ return NULL;
+ tot_len = sizeof(struct iphdr) + sizeof(struct udphdr) + data_len;
+
+ eth = skb_put(skb, sizeof(struct ethhdr));
+ eth_random_addr(eth->h_dest);
+ eth_random_addr(eth->h_source);
+ eth->h_proto = htons(ETH_P_IP);
+ skb->protocol = htons(ETH_P_IP);
+
+ iph = skb_put(skb, sizeof(struct iphdr));
+ iph->protocol = IPPROTO_UDP;
+ iph->saddr = in_aton("192.0.2.1");
+ iph->daddr = in_aton("198.51.100.1");
+ iph->version = 0x4;
+ iph->frag_off = 0;
+ iph->ihl = 0x5;
+ iph->tot_len = htons(tot_len);
+ ip_send_check(iph);
+
+ udph = skb_put_zero(skb, sizeof(struct udphdr) + data_len);
+ get_random_bytes(&udph->source, sizeof(u16));
+ get_random_bytes(&udph->dest, sizeof(u16));
+ udph->len = htons(sizeof(struct udphdr) + data_len);
+
+ return skb;
+}
+
+static void nsim_dev_trap_report(struct nsim_dev_port *nsim_dev_port)
+{
+ struct nsim_dev *nsim_dev = nsim_dev_port->ns->nsim_dev;
+ struct nsim_trap_data *nsim_trap_data = nsim_dev->trap_data;
+ struct devlink *devlink = priv_to_devlink(nsim_dev);
+ int i;
+
+ spin_lock(&nsim_trap_data->trap_lock);
+ for (i = 0; i < ARRAY_SIZE(nsim_traps_arr); i++) {
+ struct nsim_trap_item *nsim_trap_item;
+ struct sk_buff *skb;
+
+ nsim_trap_item = &nsim_trap_data->trap_items_arr[i];
+ if (nsim_trap_item->action == DEVLINK_TRAP_ACTION_DROP)
+ continue;
+
+ skb = nsim_dev_trap_skb_build();
+ if (!skb)
+ continue;
+ skb->dev = nsim_dev_port->ns->netdev;
+
+ devlink_trap_report(devlink, skb, nsim_trap_item->trap_ctx,
+ &nsim_dev_port->devlink_port);
+ consume_skb(skb);
+ }
+ spin_unlock(&nsim_trap_data->trap_lock);
+}
+
+#define NSIM_TRAP_REPORT_INTERVAL_MS 100
+
+static void nsim_dev_trap_report_work(struct work_struct *work)
+{
+ struct nsim_trap_data *nsim_trap_data;
+ struct nsim_dev_port *nsim_dev_port;
+ struct nsim_dev *nsim_dev;
+
+ nsim_trap_data = container_of(work, struct nsim_trap_data,
+ trap_report_dw.work);
+ nsim_dev = nsim_trap_data->nsim_dev;
+
+ /* For each running port and enabled packet trap, generate a UDP
+ * packet with a random 5-tuple and report it.
+ */
+ mutex_lock(&nsim_dev->port_list_lock);
+ list_for_each_entry(nsim_dev_port, &nsim_dev->port_list, list) {
+ if (!netif_running(nsim_dev_port->ns->netdev))
+ continue;
+
+ nsim_dev_trap_report(nsim_dev_port);
+ }
+ mutex_unlock(&nsim_dev->port_list_lock);
+
+ schedule_delayed_work(&nsim_dev->trap_data->trap_report_dw,
+ msecs_to_jiffies(NSIM_TRAP_REPORT_INTERVAL_MS));
+}
+
+static int nsim_dev_traps_init(struct devlink *devlink)
+{
+ struct nsim_dev *nsim_dev = devlink_priv(devlink);
+ struct nsim_trap_data *nsim_trap_data;
+ int err;
+
+ nsim_trap_data = kzalloc(sizeof(*nsim_trap_data), GFP_KERNEL);
+ if (!nsim_trap_data)
+ return -ENOMEM;
+
+ nsim_trap_data->trap_items_arr = kcalloc(ARRAY_SIZE(nsim_traps_arr),
+ sizeof(struct nsim_trap_item),
+ GFP_KERNEL);
+ if (!nsim_trap_data->trap_items_arr) {
+ err = -ENOMEM;
+ goto err_trap_data_free;
+ }
+
+ /* The lock is used to protect the action state of the registered
+ * traps. The value is written by user and read in delayed work when
+ * iterating over all the traps.
+ */
+ spin_lock_init(&nsim_trap_data->trap_lock);
+ nsim_trap_data->nsim_dev = nsim_dev;
+ nsim_dev->trap_data = nsim_trap_data;
+
+ err = devlink_traps_register(devlink, nsim_traps_arr,
+ ARRAY_SIZE(nsim_traps_arr), NULL);
+ if (err)
+ goto err_trap_items_free;
+
+ INIT_DELAYED_WORK(&nsim_dev->trap_data->trap_report_dw,
+ nsim_dev_trap_report_work);
+ schedule_delayed_work(&nsim_dev->trap_data->trap_report_dw,
+ msecs_to_jiffies(NSIM_TRAP_REPORT_INTERVAL_MS));
+
+ return 0;
+
+err_trap_items_free:
+ kfree(nsim_trap_data->trap_items_arr);
+err_trap_data_free:
+ kfree(nsim_trap_data);
+ return err;
+}
+
+static void nsim_dev_traps_exit(struct devlink *devlink)
+{
+ struct nsim_dev *nsim_dev = devlink_priv(devlink);
+
+ cancel_delayed_work_sync(&nsim_dev->trap_data->trap_report_dw);
+ devlink_traps_unregister(devlink, nsim_traps_arr,
+ ARRAY_SIZE(nsim_traps_arr));
+ kfree(nsim_dev->trap_data->trap_items_arr);
+ kfree(nsim_dev->trap_data);
+}
+
static int nsim_dev_reload(struct devlink *devlink,
struct netlink_ext_ack *extack)
{
@@ -262,9 +471,61 @@ static int nsim_dev_flash_update(struct devlink *devlink, const char *file_name,
return 0;
}
+static struct nsim_trap_item *
+nsim_dev_trap_item_lookup(struct nsim_dev *nsim_dev, u16 trap_id)
+{
+ struct nsim_trap_data *nsim_trap_data = nsim_dev->trap_data;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(nsim_traps_arr); i++) {
+ if (nsim_traps_arr[i].id == trap_id)
+ return &nsim_trap_data->trap_items_arr[i];
+ }
+
+ return NULL;
+}
+
+static int nsim_dev_devlink_trap_init(struct devlink *devlink,
+ const struct devlink_trap *trap,
+ void *trap_ctx)
+{
+ struct nsim_dev *nsim_dev = devlink_priv(devlink);
+ struct nsim_trap_item *nsim_trap_item;
+
+ nsim_trap_item = nsim_dev_trap_item_lookup(nsim_dev, trap->id);
+ if (WARN_ON(!nsim_trap_item))
+ return -ENOENT;
+
+ nsim_trap_item->trap_ctx = trap_ctx;
+ nsim_trap_item->action = trap->init_action;
+
+ return 0;
+}
+
+static int
+nsim_dev_devlink_trap_action_set(struct devlink *devlink,
+ const struct devlink_trap *trap,
+ enum devlink_trap_action action)
+{
+ struct nsim_dev *nsim_dev = devlink_priv(devlink);
+ struct nsim_trap_item *nsim_trap_item;
+
+ nsim_trap_item = nsim_dev_trap_item_lookup(nsim_dev, trap->id);
+ if (WARN_ON(!nsim_trap_item))
+ return -ENOENT;
+
+ spin_lock(&nsim_dev->trap_data->trap_lock);
+ nsim_trap_item->action = action;
+ spin_unlock(&nsim_dev->trap_data->trap_lock);
+
+ return 0;
+}
+
static const struct devlink_ops nsim_dev_devlink_ops = {
.reload = nsim_dev_reload,
.flash_update = nsim_dev_flash_update,
+ .trap_init = nsim_dev_devlink_trap_init,
+ .trap_action_set = nsim_dev_devlink_trap_action_set,
};
static struct nsim_dev *
@@ -299,10 +560,14 @@ nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev, unsigned int port_count)
if (err)
goto err_resources_unregister;
- err = nsim_dev_debugfs_init(nsim_dev);
+ err = nsim_dev_traps_init(devlink);
if (err)
goto err_dl_unregister;
+ err = nsim_dev_debugfs_init(nsim_dev);
+ if (err)
+ goto err_traps_exit;
+
err = nsim_bpf_dev_init(nsim_dev);
if (err)
goto err_debugfs_exit;
@@ -311,6 +576,8 @@ nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev, unsigned int port_count)
err_debugfs_exit:
nsim_dev_debugfs_exit(nsim_dev);
+err_traps_exit:
+ nsim_dev_traps_exit(devlink);
err_dl_unregister:
devlink_unregister(devlink);
err_resources_unregister:
@@ -328,6 +595,7 @@ static void nsim_dev_destroy(struct nsim_dev *nsim_dev)
nsim_bpf_dev_exit(nsim_dev);
nsim_dev_debugfs_exit(nsim_dev);
+ nsim_dev_traps_exit(devlink);
devlink_unregister(devlink);
devlink_resources_unregister(devlink, NULL);
nsim_fib_destroy(nsim_dev->fib_data);
diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h
index 79c05af2a7c0..a3dd73ae252e 100644
--- a/drivers/net/netdevsim/netdevsim.h
+++ b/drivers/net/netdevsim/netdevsim.h
@@ -145,6 +145,7 @@ struct nsim_dev_port {
struct nsim_dev {
struct nsim_bus_dev *nsim_bus_dev;
struct nsim_fib_data *fib_data;
+ struct nsim_trap_data *trap_data;
struct dentry *ddir;
struct dentry *ports_ddir;
struct bpf_offload_dev *bpf_dev;
--
2.20.1
^ permalink raw reply related
* [PATCH net-next 04/11] Documentation: Add devlink-trap documentation
From: Ido Schimmel @ 2019-07-07 7:58 UTC (permalink / raw)
To: netdev
Cc: davem, jiri, mlxsw, dsahern, roopa, nikolay, andy, pablo,
jakub.kicinski, pieter.jansenvanvuuren, andrew, f.fainelli,
vivien.didelot, Ido Schimmel
In-Reply-To: <20190707075828.3315-1-idosch@idosch.org>
From: Ido Schimmel <idosch@mellanox.com>
Add initial documentation of the devlink-trap mechanism, explaining the
background, motivation and the semantics of the interface.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
---
Documentation/networking/devlink-trap.rst | 179 ++++++++++++++++++++++
Documentation/networking/index.rst | 1 +
include/net/devlink.h | 6 +
3 files changed, 186 insertions(+)
create mode 100644 Documentation/networking/devlink-trap.rst
diff --git a/Documentation/networking/devlink-trap.rst b/Documentation/networking/devlink-trap.rst
new file mode 100644
index 000000000000..4a4fd42f5372
--- /dev/null
+++ b/Documentation/networking/devlink-trap.rst
@@ -0,0 +1,179 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+============
+Devlink Trap
+============
+
+Background
+==========
+
+Devices capable of offloading the kernel's datapath and perform functions such
+as bridging and routing must also be able to send specific packets to the
+kernel (i.e., the CPU) for processing.
+
+For example, a device acting as a multicast-aware bridge must be able to send
+IGMP membership reports to the kernel for processing by the bridge module.
+Without processing such packets, the bridge module could never populate its
+MDB.
+
+As another example, consider a device acting as router which has received an IP
+packet with a TTL of 1. Upon routing the packet the device must send it to the
+kernel so that it will route it as well and generate an ICMP Time Exceeded
+error datagram. Without letting the kernel route such packets itself, utilities
+such as ``traceroute`` could never work.
+
+The fundamental ability of sending certain packets to the kernel for processing
+is called "packet trapping".
+
+Overview
+========
+
+The ``devlink-trap`` mechanism allows capable device drivers to register their
+supported packet traps with ``devlink`` and report trapped packets to
+``devlink`` for further analysis.
+
+Upon receiving trapped packets, ``devlink`` will perform a per-trap packets and
+bytes accounting and potentially report the packet to user space via a netlink
+event along with all the provided metadata (e.g., trap reason, timestamp, input
+port). This is especially useful for drop traps (see :ref:`Trap-Types`)
+as it allows users to obtain further visibility into packet drops that would
+otherwise be invisible.
+
+The following diagram provides a general overview of ``devlink-trap``::
+
+ Netlink event: Packet w/ metadata
+ ^
+ |
+ Userspace |
+ +---------------------------------------------------+
+ Kernel |
+ |
+ +----+----+
+ | | Kernel's Rx path
+ | devlink | (non-drop traps)
+ | |
+ +----^----+ ^
+ | |
+ +-----------+
+ |
+ +-------+-------+
+ | |
+ | Device driver |
+ | |
+ +-------^-------+
+ Kernel |
+ +---------------------------------------------------+
+ Hardware |
+ | Trapped packet
+ |
+ +--+---+
+ | |
+ | ASIC |
+ | |
+ +------+
+
+.. _Trap-Types:
+
+Trap Types
+==========
+
+The ``devlink-trap`` mechanism supports the following packet trap types:
+
+ * ``drop``: Trapped packets were dropped by the underlying device. Packets
+ are only processed by ``devlink`` and not injected to the kernel's Rx path.
+ The trap action (see :ref:`Trap-Actions`) can be changed.
+ * ``exception``: Trapped packets were not forwarded as intended by the
+ underlying device due to an exception (e.g., TTL error, missing neighbour
+ entry) and trapped to the control plane for resolution. Packets are
+ processed by ``devlink`` and injected to the kernel's Rx path. Changing the
+ action of such traps is not allowed, as it can easily break the control
+ plane.
+
+.. _Trap-Actions:
+
+Trap Actions
+============
+
+The ``devlink-trap`` mechanism supports the following packet trap actions:
+
+ * ``trap``: The sole copy of the packet is sent to the CPU.
+ * ``drop``: The packet is dropped by the underlying device and a copy is not
+ sent to the CPU.
+
+Generic Packet Traps
+====================
+
+Generic packet traps are used to describe traps that trap well-defined packets
+or packets that are trapped due to well-defined conditions (e.g., TTL error).
+Such traps can be shared by multiple device drivers and their description must
+be added to the following table:
+
+.. list-table:: List of Generic Packet Traps
+ :widths: 5 5 90
+
+ * - Name
+ - Type
+ - Description
+ * - ``source_mac_is_multicast``
+ - ``drop``
+ - Traps incoming packets that the device decided to drop because of a
+ multicast source MAC
+ * - ``vlan_tag_mismatch``
+ - ``drop``
+ - Traps incoming packets that the device decided to drop in case of VLAN
+ tag mismatch: The ingress bridge port is not configured with a PVID and
+ the packet is untagged or prio-tagged
+ * - ``ingress_vlan_filter``
+ - ``drop``
+ - Traps incoming packets that the device decided to drop in case they are
+ tagged with a VLAN that is not configured on the ingress bridge port
+ * - ``ingress_spanning_tree_filter``
+ - ``drop``
+ - Traps incoming packets that the device decided to drop in case the STP
+ state of the ingress bridge port is not "forwarding"
+ * - ``port_list_is_empty``
+ - ``drop``
+ - Traps packets that the device decided to drop in case they need to be
+ flooded and the flood list is empty
+ * - ``port_loopback_filter``
+ - ``drop``
+ - Traps packets that the device decided to drop in case after layer 2
+ forwarding the only port from which they should be transmitted through
+ is the port from which they were received
+ * - ``blackhole_route``
+ - ``drop``
+ - Traps packets that the device decided to drop in case they hit a
+ blackhole route
+ * - ``ttl_value_is_too_small``
+ - ``exception``
+ - Traps unicast packets that should be forwarded by the device whose TTL
+ was decremented to 0 or less
+ * - ``tail_drop``
+ - ``drop``
+ - Traps packets that the device decided to drop because they could not be
+ enqueued to a transmission queue which is full
+
+Generic Packet Trap Groups
+==========================
+
+Generic packet trap groups are used to aggregate logically related packet
+traps. These groups allow the user to batch operations such as setting the
+trap action and report state of all member traps. In addition, ``devlink-trap``
+can report aggregated per-group packets and bytes statistics, in case per-trap
+statistics are too narrow. The description of these groups must be added to the
+following table:
+
+.. list-table:: List of Generic Packet Trap Groups
+ :widths: 10 90
+
+ * - Name
+ - Description
+ * - ``l2_drops``
+ - Contains packet traps for packets that were dropped by the device during
+ layer 2 forwarding (i.e., bridge)
+ * - ``l3_drops``
+ - Contains packet traps for packets that were dropped by the device or hit
+ an exception (e.g., TTL error) during layer 3 forwarding
+ * - ``buffer_drops``
+ - Contains packet traps for packets that were dropped by the device due to
+ an enqueue decision
diff --git a/Documentation/networking/index.rst b/Documentation/networking/index.rst
index a46fca264bee..86a814e4d450 100644
--- a/Documentation/networking/index.rst
+++ b/Documentation/networking/index.rst
@@ -14,6 +14,7 @@ Contents:
device_drivers/index
dsa/index
devlink-info-versions
+ devlink-trap
ieee802154
kapi
z8530book
diff --git a/include/net/devlink.h b/include/net/devlink.h
index 9121eb45b1c0..5a578750f6b4 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -520,6 +520,9 @@ struct devlink_trap {
u32 metadata_cap;
};
+/* All traps must be documented in
+ * Documentation/networking/devlink-trap.rst
+ */
enum devlink_trap_generic_id {
DEVLINK_TRAP_GENERIC_ID_SMAC_MC,
DEVLINK_TRAP_GENERIC_ID_VLAN_TAG_MISMATCH,
@@ -536,6 +539,9 @@ enum devlink_trap_generic_id {
DEVLINK_TRAP_GENERIC_ID_MAX = __DEVLINK_TRAP_GENERIC_ID_MAX - 1,
};
+/* All trap groups must be documented in
+ * Documentation/networking/devlink-trap.rst
+ */
enum devlink_trap_group_generic_id {
DEVLINK_TRAP_GROUP_GENERIC_ID_L2_DROPS,
DEVLINK_TRAP_GROUP_GENERIC_ID_L3_DROPS,
--
2.20.1
^ permalink raw reply related
* [PATCH net-next 03/11] devlink: Add generic packet traps and groups
From: Ido Schimmel @ 2019-07-07 7:58 UTC (permalink / raw)
To: netdev
Cc: davem, jiri, mlxsw, dsahern, roopa, nikolay, andy, pablo,
jakub.kicinski, pieter.jansenvanvuuren, andrew, f.fainelli,
vivien.didelot, Ido Schimmel
In-Reply-To: <20190707075828.3315-1-idosch@idosch.org>
From: Ido Schimmel <idosch@mellanox.com>
Add generic packet traps and groups that can report dropped packets as
well as exceptions such as TTL error.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
---
include/net/devlink.h | 40 ++++++++++++++++++++++++++++++++++++++++
net/core/devlink.c | 12 ++++++++++++
2 files changed, 52 insertions(+)
diff --git a/include/net/devlink.h b/include/net/devlink.h
index 22614d3a742a..9121eb45b1c0 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -521,18 +521,58 @@ struct devlink_trap {
};
enum devlink_trap_generic_id {
+ DEVLINK_TRAP_GENERIC_ID_SMAC_MC,
+ DEVLINK_TRAP_GENERIC_ID_VLAN_TAG_MISMATCH,
+ DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER,
+ DEVLINK_TRAP_GENERIC_ID_INGRESS_STP_FILTER,
+ DEVLINK_TRAP_GENERIC_ID_EMPTY_TX_LIST,
+ DEVLINK_TRAP_GENERIC_ID_PORT_LOOPBACK_FILTER,
+ DEVLINK_TRAP_GENERIC_ID_BLACKHOLE_ROUTE,
+ DEVLINK_TRAP_GENERIC_ID_TTL_ERROR,
+ DEVLINK_TRAP_GENERIC_ID_TAIL_DROP,
+
/* Add new generic trap IDs above */
__DEVLINK_TRAP_GENERIC_ID_MAX,
DEVLINK_TRAP_GENERIC_ID_MAX = __DEVLINK_TRAP_GENERIC_ID_MAX - 1,
};
enum devlink_trap_group_generic_id {
+ DEVLINK_TRAP_GROUP_GENERIC_ID_L2_DROPS,
+ DEVLINK_TRAP_GROUP_GENERIC_ID_L3_DROPS,
+ DEVLINK_TRAP_GROUP_GENERIC_ID_BUFFER_DROPS,
+
/* Add new generic trap group IDs above */
__DEVLINK_TRAP_GROUP_GENERIC_ID_MAX,
DEVLINK_TRAP_GROUP_GENERIC_ID_MAX =
__DEVLINK_TRAP_GROUP_GENERIC_ID_MAX - 1,
};
+#define DEVLINK_TRAP_GENERIC_NAME_SMAC_MC \
+ "source_mac_is_multicast"
+#define DEVLINK_TRAP_GENERIC_NAME_VLAN_TAG_MISMATCH \
+ "vlan_tag_mismatch"
+#define DEVLINK_TRAP_GENERIC_NAME_INGRESS_VLAN_FILTER \
+ "ingress_vlan_filter"
+#define DEVLINK_TRAP_GENERIC_NAME_INGRESS_STP_FILTER \
+ "ingress_spanning_tree_filter"
+#define DEVLINK_TRAP_GENERIC_NAME_EMPTY_TX_LIST \
+ "port_list_is_empty"
+#define DEVLINK_TRAP_GENERIC_NAME_PORT_LOOPBACK_FILTER \
+ "port_loopback_filter"
+#define DEVLINK_TRAP_GENERIC_NAME_BLACKHOLE_ROUTE \
+ "blackhole_route"
+#define DEVLINK_TRAP_GENERIC_NAME_TTL_ERROR \
+ "ttl_value_is_too_small"
+#define DEVLINK_TRAP_GENERIC_NAME_TAIL_DROP \
+ "tail_drop"
+
+#define DEVLINK_TRAP_GROUP_GENERIC_NAME_L2_DROPS \
+ "l2_drops"
+#define DEVLINK_TRAP_GROUP_GENERIC_NAME_L3_DROPS \
+ "l3_drops"
+#define DEVLINK_TRAP_GROUP_GENERIC_NAME_BUFFER_DROPS \
+ "buffer_drops"
+
#define DEVLINK_TRAP_GENERIC(_type, _init_action, _id, _group, _metadata_cap) \
{ \
.type = DEVLINK_TRAP_TYPE_##_type, \
diff --git a/net/core/devlink.c b/net/core/devlink.c
index 44a850ec3d5f..172ede6ba1b1 100644
--- a/net/core/devlink.c
+++ b/net/core/devlink.c
@@ -7414,6 +7414,15 @@ EXPORT_SYMBOL_GPL(devlink_region_snapshot_create);
}
static const struct devlink_trap devlink_trap_generic[] = {
+ DEVLINK_TRAP(SMAC_MC, DROP),
+ DEVLINK_TRAP(VLAN_TAG_MISMATCH, DROP),
+ DEVLINK_TRAP(INGRESS_VLAN_FILTER, DROP),
+ DEVLINK_TRAP(INGRESS_STP_FILTER, DROP),
+ DEVLINK_TRAP(EMPTY_TX_LIST, DROP),
+ DEVLINK_TRAP(PORT_LOOPBACK_FILTER, DROP),
+ DEVLINK_TRAP(BLACKHOLE_ROUTE, DROP),
+ DEVLINK_TRAP(TTL_ERROR, EXCEPTION),
+ DEVLINK_TRAP(TAIL_DROP, DROP),
};
#define DEVLINK_TRAP_GROUP(_id) \
@@ -7423,6 +7432,9 @@ static const struct devlink_trap devlink_trap_generic[] = {
}
static const struct devlink_trap_group devlink_trap_group_generic[] = {
+ DEVLINK_TRAP_GROUP(L2_DROPS),
+ DEVLINK_TRAP_GROUP(L3_DROPS),
+ DEVLINK_TRAP_GROUP(BUFFER_DROPS),
};
static int devlink_trap_generic_verify(const struct devlink_trap *trap)
--
2.20.1
^ permalink raw reply related
* [PATCH net-next 02/11] devlink: Add packet trap infrastructure
From: Ido Schimmel @ 2019-07-07 7:58 UTC (permalink / raw)
To: netdev
Cc: davem, jiri, mlxsw, dsahern, roopa, nikolay, andy, pablo,
jakub.kicinski, pieter.jansenvanvuuren, andrew, f.fainelli,
vivien.didelot, Ido Schimmel
In-Reply-To: <20190707075828.3315-1-idosch@idosch.org>
From: Ido Schimmel <idosch@mellanox.com>
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the reporting state as well as the action
of all member traps. In addition, users can retrieve per-group
statistics in case per-trap statistics are too narrow. In the future,
the trap group object can be extended with more attributes, such as
policer settings which will limit the amount of traffic generated by
member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to userspace via a new generic netlink multicast group.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
---
include/net/devlink.h | 129 ++++
include/uapi/linux/devlink.h | 68 ++
net/core/devlink.c | 1251 +++++++++++++++++++++++++++++++++-
3 files changed, 1443 insertions(+), 5 deletions(-)
diff --git a/include/net/devlink.h b/include/net/devlink.h
index 6625ea068d5e..22614d3a742a 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -14,6 +14,7 @@
#include <linux/netdevice.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
+#include <linux/refcount.h>
#include <net/net_namespace.h>
#include <uapi/linux/devlink.h>
@@ -31,6 +32,8 @@ struct devlink {
struct list_head reporter_list;
struct mutex reporters_lock; /* protects reporter_list */
struct devlink_dpipe_headers *dpipe_headers;
+ struct list_head trap_list;
+ struct list_head trap_group_list;
const struct devlink_ops *ops;
struct device *dev;
possible_net_t _net;
@@ -477,6 +480,89 @@ struct devlink_health_reporter_ops {
struct devlink_fmsg *fmsg);
};
+/**
+ * struct devlink_trap_group - Immutable packet trap group attributes.
+ * @name: Trap group name.
+ * @id: Trap group identifier.
+ * @generic: Whether the trap group is generic or not.
+ *
+ * Describes immutable attributes of packet trap groups that drivers register
+ * with devlink.
+ */
+struct devlink_trap_group {
+ const char *name;
+ u16 id;
+ bool generic;
+};
+
+#define DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT BIT(0)
+
+/**
+ * struct devlink_trap - Immutable packet trap attributes.
+ * @type: Trap type.
+ * @init_action: Initial trap action.
+ * @generic: Whether the trap is generic or not.
+ * @id: Trap identifier.
+ * @name: Trap name.
+ * @group: Immutable packet trap group attributes.
+ * @metadata_cap: Metadata types that can be provided by the trap.
+ *
+ * Describes immutable attributes of packet traps that drivers register with
+ * devlink.
+ */
+struct devlink_trap {
+ enum devlink_trap_type type;
+ enum devlink_trap_action init_action;
+ bool generic;
+ u16 id;
+ const char *name;
+ struct devlink_trap_group group;
+ u32 metadata_cap;
+};
+
+enum devlink_trap_generic_id {
+ /* Add new generic trap IDs above */
+ __DEVLINK_TRAP_GENERIC_ID_MAX,
+ DEVLINK_TRAP_GENERIC_ID_MAX = __DEVLINK_TRAP_GENERIC_ID_MAX - 1,
+};
+
+enum devlink_trap_group_generic_id {
+ /* Add new generic trap group IDs above */
+ __DEVLINK_TRAP_GROUP_GENERIC_ID_MAX,
+ DEVLINK_TRAP_GROUP_GENERIC_ID_MAX =
+ __DEVLINK_TRAP_GROUP_GENERIC_ID_MAX - 1,
+};
+
+#define DEVLINK_TRAP_GENERIC(_type, _init_action, _id, _group, _metadata_cap) \
+ { \
+ .type = DEVLINK_TRAP_TYPE_##_type, \
+ .init_action = DEVLINK_TRAP_ACTION_##_init_action, \
+ .generic = true, \
+ .id = DEVLINK_TRAP_GENERIC_ID_##_id, \
+ .name = DEVLINK_TRAP_GENERIC_NAME_##_id, \
+ .group = _group, \
+ .metadata_cap = _metadata_cap, \
+ }
+
+#define DEVLINK_TRAP_DRIVER(_type, _init_action, _id, _name, _group, \
+ _metadata_cap) \
+ { \
+ .type = DEVLINK_TRAP_TYPE_##_type, \
+ .init_action = DEVLINK_TRAP_ACTION_##_init_action, \
+ .generic = false, \
+ .id = _id, \
+ .name = _name, \
+ .group = _group, \
+ .metadata_cap = _metadata_cap, \
+ }
+
+#define DEVLINK_TRAP_GROUP_GENERIC(_id) \
+ { \
+ .name = DEVLINK_TRAP_GROUP_GENERIC_NAME_##_id, \
+ .id = DEVLINK_TRAP_GROUP_GENERIC_ID_##_id, \
+ .generic = true, \
+ }
+
struct devlink_ops {
int (*reload)(struct devlink *devlink, struct netlink_ext_ack *extack);
int (*port_type_set)(struct devlink_port *devlink_port,
@@ -538,6 +624,38 @@ struct devlink_ops {
int (*flash_update)(struct devlink *devlink, const char *file_name,
const char *component,
struct netlink_ext_ack *extack);
+ /**
+ * @trap_init: Trap initialization function.
+ *
+ * Should be used by device drivers to initialize the trap in the
+ * underlying device. Drivers should also store the provided trap
+ * context, so that they could efficiently pass it to
+ * devlink_trap_report() when the trap is triggered.
+ */
+ int (*trap_init)(struct devlink *devlink,
+ const struct devlink_trap *trap, void *trap_ctx);
+ /**
+ * @trap_fini: Trap de-initialization function.
+ *
+ * Should be used by device drivers to de-initialize the trap in the
+ * underlying device.
+ */
+ void (*trap_fini)(struct devlink *devlink,
+ const struct devlink_trap *trap, void *trap_ctx);
+ /**
+ * @trap_action_set: Trap action set function.
+ */
+ int (*trap_action_set)(struct devlink *devlink,
+ const struct devlink_trap *trap,
+ enum devlink_trap_action action);
+ /**
+ * @trap_group_init: Trap group initialization function.
+ *
+ * Should be used by device drivers to initialize the trap group in the
+ * underlying device.
+ */
+ int (*trap_group_init)(struct devlink *devlink,
+ const struct devlink_trap_group *group);
};
static inline void *devlink_priv(struct devlink *devlink)
@@ -747,6 +865,17 @@ void devlink_flash_update_status_notify(struct devlink *devlink,
unsigned long done,
unsigned long total);
+int devlink_traps_register(struct devlink *devlink,
+ const struct devlink_trap *traps,
+ size_t traps_count, void *priv);
+void devlink_traps_unregister(struct devlink *devlink,
+ const struct devlink_trap *traps,
+ size_t traps_count);
+void devlink_trap_report(struct devlink *devlink,
+ struct sk_buff *skb, void *trap_ctx,
+ struct devlink_port *in_devlink_port);
+void *devlink_trap_ctx_priv(void *trap_ctx);
+
#if IS_ENABLED(CONFIG_NET_DEVLINK)
void devlink_compat_running_version(struct net_device *dev,
diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
index 5287b42c181f..c1c0a6e2a71a 100644
--- a/include/uapi/linux/devlink.h
+++ b/include/uapi/linux/devlink.h
@@ -16,6 +16,7 @@
#define DEVLINK_GENL_NAME "devlink"
#define DEVLINK_GENL_VERSION 0x1
#define DEVLINK_GENL_MCGRP_CONFIG_NAME "config"
+#define DEVLINK_GENL_MCGRP_TRAP_NAME "trap"
enum devlink_command {
/* don't change the order or add anything between, this is ABI! */
@@ -107,6 +108,17 @@ enum devlink_command {
DEVLINK_CMD_FLASH_UPDATE_END, /* notification only */
DEVLINK_CMD_FLASH_UPDATE_STATUS, /* notification only */
+ DEVLINK_CMD_TRAP_GET, /* can dump */
+ DEVLINK_CMD_TRAP_SET,
+ DEVLINK_CMD_TRAP_NEW,
+ DEVLINK_CMD_TRAP_DEL,
+ DEVLINK_CMD_TRAP_REPORT,
+
+ DEVLINK_CMD_TRAP_GROUP_GET, /* can dump */
+ DEVLINK_CMD_TRAP_GROUP_SET,
+ DEVLINK_CMD_TRAP_GROUP_NEW,
+ DEVLINK_CMD_TRAP_GROUP_DEL,
+
/* add new commands above here */
__DEVLINK_CMD_MAX,
DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1
@@ -186,6 +198,47 @@ enum devlink_param_fw_load_policy_value {
DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH,
};
+enum {
+ DEVLINK_ATTR_STATS_RX_PACKETS,
+ DEVLINK_ATTR_STATS_RX_BYTES,
+
+ __DEVLINK_ATTR_STATS_MAX,
+ DEVLINK_ATTR_STATS_MAX = __DEVLINK_ATTR_STATS_MAX - 1
+};
+
+/**
+ * enum devlink_trap_action - Packet trap action.
+ * @DEVLINK_TRAP_ACTION_DROP: Packet is dropped by the device and a copy is not
+ * sent to the CPU.
+ * @DEVLINK_TRAP_ACTION_TRAP: The sole copy of the packet is sent to the CPU.
+ */
+enum devlink_trap_action {
+ DEVLINK_TRAP_ACTION_DROP,
+ DEVLINK_TRAP_ACTION_TRAP,
+};
+
+/**
+ * enum devlink_trap_type - Packet trap type.
+ * @DEVLINK_TRAP_TYPE_DROP: Trap reason is a drop. Trapped packets are only
+ * processed by devlink and not injected to the
+ * kernel's Rx path.
+ * @DEVLINK_TRAP_TYPE_EXCEPTION: Trap reason is an exception. Packet was not
+ * forwarded as intended due to an exception
+ * (e.g., missing neighbour entry) and trapped to
+ * control plane for resolution. Trapped packets
+ * are processed by devlink and injected to
+ * the kernel's Rx path.
+ */
+enum devlink_trap_type {
+ DEVLINK_TRAP_TYPE_DROP,
+ DEVLINK_TRAP_TYPE_EXCEPTION,
+};
+
+enum {
+ /* Trap can report input port as metadata */
+ DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT,
+};
+
enum devlink_attr {
/* don't change the order or add anything between, this is ABI! */
DEVLINK_ATTR_UNSPEC,
@@ -337,6 +390,21 @@ enum devlink_attr {
DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE, /* u64 */
DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL, /* u64 */
+ DEVLINK_ATTR_STATS, /* nested */
+
+ DEVLINK_ATTR_TRAP_NAME, /* string */
+ DEVLINK_ATTR_TRAP_REPORT_ENABLED, /* u8 */
+ /* enum devlink_trap_action */
+ DEVLINK_ATTR_TRAP_ACTION, /* u8 */
+ /* enum devlink_trap_type */
+ DEVLINK_ATTR_TRAP_TYPE, /* u8 */
+ DEVLINK_ATTR_TRAP_GENERIC, /* flag */
+ DEVLINK_ATTR_TRAP_METADATA, /* nested */
+ DEVLINK_ATTR_TRAP_TIMESTAMP, /* struct timespec */
+ DEVLINK_ATTR_TRAP_IN_PORT, /* nested */
+ DEVLINK_ATTR_TRAP_PAYLOAD, /* binary */
+ DEVLINK_ATTR_TRAP_GROUP_NAME, /* string */
+
/* add new attributes above here, update the policy in devlink.c */
__DEVLINK_ATTR_MAX,
diff --git a/net/core/devlink.c b/net/core/devlink.c
index 755a9a32015e..44a850ec3d5f 100644
--- a/net/core/devlink.c
+++ b/net/core/devlink.c
@@ -18,6 +18,8 @@
#include <linux/spinlock.h>
#include <linux/refcount.h>
#include <linux/workqueue.h>
+#include <linux/u64_stats_sync.h>
+#include <linux/timekeeping.h>
#include <rdma/ib_verbs.h>
#include <net/netlink.h>
#include <net/genetlink.h>
@@ -449,10 +451,12 @@ static struct genl_family devlink_nl_family;
enum devlink_multicast_groups {
DEVLINK_MCGRP_CONFIG,
+ DEVLINK_MCGRP_TRAP,
};
static const struct genl_multicast_group devlink_nl_mcgrps[] = {
[DEVLINK_MCGRP_CONFIG] = { .name = DEVLINK_GENL_MCGRP_CONFIG_NAME },
+ [DEVLINK_MCGRP_TRAP] = { .name = DEVLINK_GENL_MCGRP_TRAP_NAME },
};
static int devlink_nl_put_handle(struct sk_buff *msg, struct devlink *devlink)
@@ -570,14 +574,14 @@ static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink,
if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
goto nla_put_failure;
- spin_lock(&devlink_port->type_lock);
+ spin_lock_bh(&devlink_port->type_lock);
if (devlink_port->desired_type != DEVLINK_PORT_TYPE_NOTSET &&
nla_put_u16(msg, DEVLINK_ATTR_PORT_DESIRED_TYPE,
devlink_port->desired_type))
goto nla_put_failure_type_locked;
if (devlink_nl_port_type_fill(msg, devlink_port))
goto nla_put_failure_type_locked;
- spin_unlock(&devlink_port->type_lock);
+ spin_unlock_bh(&devlink_port->type_lock);
if (devlink_nl_port_attrs_put(msg, devlink_port))
goto nla_put_failure;
@@ -585,7 +589,7 @@ static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink,
return 0;
nla_put_failure_type_locked:
- spin_unlock(&devlink_port->type_lock);
+ spin_unlock_bh(&devlink_port->type_lock);
nla_put_failure:
genlmsg_cancel(msg, hdr);
return -EMSGSIZE;
@@ -5146,6 +5150,623 @@ devlink_nl_cmd_health_reporter_dump_clear_doit(struct sk_buff *skb,
return 0;
}
+struct devlink_stats {
+ u64 rx_bytes;
+ u64 rx_packets;
+ struct u64_stats_sync syncp;
+};
+
+/**
+ * struct devlink_trap_group_item - Packet trap group attributes.
+ * @group: Immutable packet trap group attributes.
+ * @refcount: Number of trap items using the group.
+ * @list: trap_group_list member.
+ * @stats: Trap group statistics.
+ *
+ * Describes packet trap group attributes. Created by devlink during trap
+ * registration.
+ */
+struct devlink_trap_group_item {
+ const struct devlink_trap_group *group;
+ refcount_t refcount;
+ struct list_head list;
+ struct devlink_stats __percpu *stats;
+};
+
+/**
+ * struct devlink_trap_item - Packet trap attributes.
+ * @trap: Immutable packet trap attributes.
+ * @group_item: Associated group item.
+ * @list: trap_list member.
+ * @report: Whether to report trapped packets or not.
+ * @action: Trap action.
+ * @stats: Trap statistics.
+ * @priv: Driver private information.
+ *
+ * Describes both mutable and immutable packet trap attributes. Created by
+ * devlink during trap registration and used for all trap related operations.
+ */
+struct devlink_trap_item {
+ const struct devlink_trap *trap;
+ struct devlink_trap_group_item *group_item;
+ struct list_head list;
+ bool report;
+ enum devlink_trap_action action;
+ struct devlink_stats __percpu *stats;
+ void *priv;
+};
+
+static struct devlink_trap_item *
+devlink_trap_item_lookup(struct devlink *devlink, const char *name)
+{
+ struct devlink_trap_item *trap_item;
+
+ list_for_each_entry(trap_item, &devlink->trap_list, list) {
+ if (!strcmp(trap_item->trap->name, name))
+ return trap_item;
+ }
+
+ return NULL;
+}
+
+static struct devlink_trap_item *
+devlink_trap_item_get_from_info(struct devlink *devlink,
+ struct genl_info *info)
+{
+ struct nlattr *attr;
+
+ if (!info->attrs[DEVLINK_ATTR_TRAP_NAME])
+ return NULL;
+ attr = info->attrs[DEVLINK_ATTR_TRAP_NAME];
+
+ return devlink_trap_item_lookup(devlink, nla_data(attr));
+}
+
+static int
+devlink_trap_action_get_from_info(struct genl_info *info,
+ enum devlink_trap_action *p_trap_action)
+{
+ u8 val;
+
+ val = nla_get_u8(info->attrs[DEVLINK_ATTR_TRAP_ACTION]);
+ switch (val) {
+ case DEVLINK_TRAP_ACTION_DROP: /* fall-through */
+ case DEVLINK_TRAP_ACTION_TRAP:
+ *p_trap_action = val;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int devlink_trap_metadata_put(struct sk_buff *msg,
+ const struct devlink_trap *trap)
+{
+ struct nlattr *attr;
+
+ attr = nla_nest_start(msg, DEVLINK_ATTR_TRAP_METADATA);
+ if (!attr)
+ return -EMSGSIZE;
+
+ if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT) &&
+ nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT))
+ goto nla_put_failure;
+
+ nla_nest_end(msg, attr);
+
+ return 0;
+
+nla_put_failure:
+ nla_nest_cancel(msg, attr);
+ return -EMSGSIZE;
+}
+
+static void devlink_trap_stats_read(struct devlink_stats __percpu *trap_stats,
+ struct devlink_stats *stats)
+{
+ int i;
+
+ memset(stats, 0, sizeof(*stats));
+ for_each_possible_cpu(i) {
+ struct devlink_stats *cpu_stats;
+ u64 rx_packets, rx_bytes;
+ unsigned int start;
+
+ cpu_stats = per_cpu_ptr(trap_stats, i);
+ do {
+ start = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
+ rx_packets = cpu_stats->rx_packets;
+ rx_bytes = cpu_stats->rx_bytes;
+ } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start));
+
+ stats->rx_packets += rx_packets;
+ stats->rx_bytes += rx_bytes;
+ }
+}
+
+static int devlink_trap_stats_put(struct sk_buff *msg,
+ struct devlink_stats __percpu *trap_stats)
+{
+ struct devlink_stats stats;
+ struct nlattr *attr;
+
+ devlink_trap_stats_read(trap_stats, &stats);
+
+ attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
+ if (!attr)
+ return -EMSGSIZE;
+
+ if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_PACKETS,
+ stats.rx_packets, DEVLINK_ATTR_PAD))
+ goto nla_put_failure;
+
+ if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_BYTES,
+ stats.rx_bytes, DEVLINK_ATTR_PAD))
+ goto nla_put_failure;
+
+ nla_nest_end(msg, attr);
+
+ return 0;
+
+nla_put_failure:
+ nla_nest_cancel(msg, attr);
+ return -EMSGSIZE;
+}
+
+static int devlink_nl_trap_fill(struct sk_buff *msg, struct devlink *devlink,
+ const struct devlink_trap_item *trap_item,
+ enum devlink_command cmd, u32 portid, u32 seq,
+ int flags)
+{
+ struct devlink_trap_group_item *group_item = trap_item->group_item;
+ void *hdr;
+ int err;
+
+ hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
+ if (!hdr)
+ return -EMSGSIZE;
+
+ if (devlink_nl_put_handle(msg, devlink))
+ goto nla_put_failure;
+
+ if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
+ group_item->group->name))
+ goto nla_put_failure;
+
+ if (nla_put_string(msg, DEVLINK_ATTR_TRAP_NAME, trap_item->trap->name))
+ goto nla_put_failure;
+
+ if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_TYPE, trap_item->trap->type))
+ goto nla_put_failure;
+
+ if (trap_item->trap->generic &&
+ nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
+ goto nla_put_failure;
+
+ if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_REPORT_ENABLED,
+ trap_item->report))
+ goto nla_put_failure;
+
+ if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_ACTION, trap_item->action))
+ goto nla_put_failure;
+
+ err = devlink_trap_metadata_put(msg, trap_item->trap);
+ if (err)
+ goto nla_put_failure;
+
+ err = devlink_trap_stats_put(msg, trap_item->stats);
+ if (err)
+ goto nla_put_failure;
+
+ genlmsg_end(msg, hdr);
+
+ return 0;
+
+nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+ return -EMSGSIZE;
+}
+
+static int devlink_nl_cmd_trap_get_doit(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct netlink_ext_ack *extack = info->extack;
+ struct devlink *devlink = info->user_ptr[0];
+ struct devlink_trap_item *trap_item;
+ struct sk_buff *msg;
+ int err;
+
+ if (list_empty(&devlink->trap_list))
+ return -EOPNOTSUPP;
+
+ trap_item = devlink_trap_item_get_from_info(devlink, info);
+ if (!trap_item) {
+ NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap");
+ return -ENOENT;
+ }
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ err = devlink_nl_trap_fill(msg, devlink, trap_item,
+ DEVLINK_CMD_TRAP_NEW, info->snd_portid,
+ info->snd_seq, 0);
+ if (err)
+ goto err_trap_fill;
+
+ return genlmsg_reply(msg, info);
+
+err_trap_fill:
+ nlmsg_free(msg);
+ return err;
+}
+
+static int devlink_nl_cmd_trap_get_dumpit(struct sk_buff *msg,
+ struct netlink_callback *cb)
+{
+ struct devlink_trap_item *trap_item;
+ struct devlink *devlink;
+ int start = cb->args[0];
+ int idx = 0;
+ int err;
+
+ mutex_lock(&devlink_mutex);
+ list_for_each_entry(devlink, &devlink_list, list) {
+ if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
+ continue;
+ mutex_lock(&devlink->lock);
+ list_for_each_entry(trap_item, &devlink->trap_list, list) {
+ if (idx < start) {
+ idx++;
+ continue;
+ }
+ err = devlink_nl_trap_fill(msg, devlink, trap_item,
+ DEVLINK_CMD_TRAP_NEW,
+ NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq,
+ NLM_F_MULTI);
+ if (err) {
+ mutex_unlock(&devlink->lock);
+ goto out;
+ }
+ idx++;
+ }
+ mutex_unlock(&devlink->lock);
+ }
+out:
+ mutex_unlock(&devlink_mutex);
+
+ cb->args[0] = idx;
+ return msg->len;
+}
+
+static int __devlink_trap_action_set(struct devlink *devlink,
+ struct devlink_trap_item *trap_item,
+ enum devlink_trap_action trap_action,
+ struct netlink_ext_ack *extack)
+{
+ int err;
+
+ if (trap_item->action != trap_action &&
+ trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP) {
+ NL_SET_ERR_MSG_MOD(extack, "Cannot change action of non-drop traps. Skipping");
+ return 0;
+ }
+
+ err = devlink->ops->trap_action_set(devlink, trap_item->trap,
+ trap_action);
+ if (err)
+ return err;
+
+ trap_item->action = trap_action;
+
+ return 0;
+}
+
+static int devlink_trap_action_set(struct devlink *devlink,
+ struct devlink_trap_item *trap_item,
+ struct genl_info *info)
+{
+ enum devlink_trap_action trap_action;
+ int err;
+
+ if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
+ return 0;
+
+ err = devlink_trap_action_get_from_info(info, &trap_action);
+ if (err) {
+ NL_SET_ERR_MSG_MOD(info->extack, "Invalid trap action");
+ return -EINVAL;
+ }
+
+ return __devlink_trap_action_set(devlink, trap_item, trap_action,
+ info->extack);
+}
+
+static void devlink_trap_report_set(struct devlink *devlink,
+ struct devlink_trap_item *trap_item,
+ struct genl_info *info)
+{
+ bool report;
+
+ if (!info->attrs[DEVLINK_ATTR_TRAP_REPORT_ENABLED])
+ return;
+
+ report = !!nla_get_u8(info->attrs[DEVLINK_ATTR_TRAP_REPORT_ENABLED]);
+ trap_item->report = report;
+}
+
+static int devlink_nl_cmd_trap_set_doit(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct netlink_ext_ack *extack = info->extack;
+ struct devlink *devlink = info->user_ptr[0];
+ struct devlink_trap_item *trap_item;
+ int err;
+
+ if (list_empty(&devlink->trap_list))
+ return -EOPNOTSUPP;
+
+ trap_item = devlink_trap_item_get_from_info(devlink, info);
+ if (!trap_item) {
+ NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap");
+ return -ENOENT;
+ }
+
+ err = devlink_trap_action_set(devlink, trap_item, info);
+ if (err)
+ return err;
+
+ devlink_trap_report_set(devlink, trap_item, info);
+
+ return 0;
+}
+
+static struct devlink_trap_group_item *
+devlink_trap_group_item_lookup(struct devlink *devlink, const char *name)
+{
+ struct devlink_trap_group_item *group_item;
+
+ list_for_each_entry(group_item, &devlink->trap_group_list, list) {
+ if (!strcmp(group_item->group->name, name))
+ return group_item;
+ }
+
+ return NULL;
+}
+
+static struct devlink_trap_group_item *
+devlink_trap_group_item_get_from_info(struct devlink *devlink,
+ struct genl_info *info)
+{
+ char *name;
+
+ if (!info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME])
+ return NULL;
+ name = nla_data(info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME]);
+
+ return devlink_trap_group_item_lookup(devlink, name);
+}
+
+static int
+devlink_nl_trap_group_fill(struct sk_buff *msg, struct devlink *devlink,
+ const struct devlink_trap_group_item *group_item,
+ enum devlink_command cmd, u32 portid, u32 seq,
+ int flags)
+{
+ void *hdr;
+ int err;
+
+ hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
+ if (!hdr)
+ return -EMSGSIZE;
+
+ if (devlink_nl_put_handle(msg, devlink))
+ goto nla_put_failure;
+
+ if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
+ group_item->group->name))
+ goto nla_put_failure;
+
+ if (group_item->group->generic &&
+ nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
+ goto nla_put_failure;
+
+ err = devlink_trap_stats_put(msg, group_item->stats);
+ if (err)
+ goto nla_put_failure;
+
+ genlmsg_end(msg, hdr);
+
+ return 0;
+
+nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+ return -EMSGSIZE;
+}
+
+static int devlink_nl_cmd_trap_group_get_doit(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct netlink_ext_ack *extack = info->extack;
+ struct devlink *devlink = info->user_ptr[0];
+ struct devlink_trap_group_item *group_item;
+ struct sk_buff *msg;
+ int err;
+
+ if (list_empty(&devlink->trap_group_list))
+ return -EOPNOTSUPP;
+
+ group_item = devlink_trap_group_item_get_from_info(devlink, info);
+ if (!group_item) {
+ NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap group");
+ return -ENOENT;
+ }
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ err = devlink_nl_trap_group_fill(msg, devlink, group_item,
+ DEVLINK_CMD_TRAP_GROUP_NEW,
+ info->snd_portid, info->snd_seq, 0);
+ if (err)
+ goto err_trap_group_fill;
+
+ return genlmsg_reply(msg, info);
+
+err_trap_group_fill:
+ nlmsg_free(msg);
+ return err;
+}
+
+static int devlink_nl_cmd_trap_group_get_dumpit(struct sk_buff *msg,
+ struct netlink_callback *cb)
+{
+ enum devlink_command cmd = DEVLINK_CMD_TRAP_GROUP_NEW;
+ struct devlink_trap_group_item *group_item;
+ u32 portid = NETLINK_CB(cb->skb).portid;
+ struct devlink *devlink;
+ int start = cb->args[0];
+ int idx = 0;
+ int err;
+
+ mutex_lock(&devlink_mutex);
+ list_for_each_entry(devlink, &devlink_list, list) {
+ if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
+ continue;
+ mutex_lock(&devlink->lock);
+ list_for_each_entry(group_item, &devlink->trap_group_list,
+ list) {
+ if (idx < start) {
+ idx++;
+ continue;
+ }
+ err = devlink_nl_trap_group_fill(msg, devlink,
+ group_item, cmd,
+ portid,
+ cb->nlh->nlmsg_seq,
+ NLM_F_MULTI);
+ if (err) {
+ mutex_unlock(&devlink->lock);
+ goto out;
+ }
+ idx++;
+ }
+ mutex_unlock(&devlink->lock);
+ }
+out:
+ mutex_unlock(&devlink_mutex);
+
+ cb->args[0] = idx;
+ return msg->len;
+}
+
+static int
+__devlink_trap_group_action_set(struct devlink *devlink,
+ struct devlink_trap_group_item *group_item,
+ enum devlink_trap_action trap_action,
+ struct netlink_ext_ack *extack)
+{
+ const char *group_name = group_item->group->name;
+ struct devlink_trap_item *trap_item;
+ int err;
+
+ list_for_each_entry(trap_item, &devlink->trap_list, list) {
+ if (strcmp(trap_item->trap->group.name, group_name))
+ continue;
+ err = __devlink_trap_action_set(devlink, trap_item,
+ trap_action, extack);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int
+devlink_trap_group_action_set(struct devlink *devlink,
+ struct devlink_trap_group_item *group_item,
+ struct genl_info *info)
+{
+ enum devlink_trap_action trap_action;
+ int err;
+
+ if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
+ return 0;
+
+ err = devlink_trap_action_get_from_info(info, &trap_action);
+ if (err) {
+ NL_SET_ERR_MSG_MOD(info->extack, "Invalid trap action");
+ return -EINVAL;
+ }
+
+ err = __devlink_trap_group_action_set(devlink, group_item, trap_action,
+ info->extack);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static void
+__devlink_trap_group_report_set(struct devlink *devlink,
+ struct devlink_trap_group_item *group_item,
+ bool report)
+{
+ const char *group_name = group_item->group->name;
+ struct devlink_trap_item *trap_item;
+
+ list_for_each_entry(trap_item, &devlink->trap_list, list) {
+ if (strcmp(trap_item->trap->group.name, group_name))
+ continue;
+ trap_item->report = report;
+ }
+}
+
+static void
+devlink_trap_group_report_set(struct devlink *devlink,
+ struct devlink_trap_group_item *group_item,
+ struct genl_info *info)
+{
+ bool report;
+
+ if (!info->attrs[DEVLINK_ATTR_TRAP_REPORT_ENABLED])
+ return;
+
+ report = !!nla_get_u8(info->attrs[DEVLINK_ATTR_TRAP_REPORT_ENABLED]);
+ __devlink_trap_group_report_set(devlink, group_item, report);
+}
+
+static int devlink_nl_cmd_trap_group_set_doit(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct netlink_ext_ack *extack = info->extack;
+ struct devlink *devlink = info->user_ptr[0];
+ struct devlink_trap_group_item *group_item;
+ int err;
+
+ if (list_empty(&devlink->trap_group_list))
+ return -EOPNOTSUPP;
+
+ group_item = devlink_trap_group_item_get_from_info(devlink, info);
+ if (!group_item) {
+ NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap group");
+ return -ENOENT;
+ }
+
+ err = devlink_trap_group_action_set(devlink, group_item, info);
+ if (err)
+ return err;
+
+ devlink_trap_group_report_set(devlink, group_item, info);
+
+ return 0;
+}
+
static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
[DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
[DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
@@ -5176,6 +5797,10 @@ static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] = { .type = NLA_U8 },
[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME] = { .type = NLA_NUL_STRING },
[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT] = { .type = NLA_NUL_STRING },
+ [DEVLINK_ATTR_TRAP_NAME] = { .type = NLA_NUL_STRING },
+ [DEVLINK_ATTR_TRAP_REPORT_ENABLED] = { .type = NLA_U8 },
+ [DEVLINK_ATTR_TRAP_ACTION] = { .type = NLA_U8 },
+ [DEVLINK_ATTR_TRAP_GROUP_NAME] = { .type = NLA_NUL_STRING },
};
static const struct genl_ops devlink_nl_ops[] = {
@@ -5475,6 +6100,32 @@ static const struct genl_ops devlink_nl_ops[] = {
.flags = GENL_ADMIN_PERM,
.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
},
+ {
+ .cmd = DEVLINK_CMD_TRAP_GET,
+ .doit = devlink_nl_cmd_trap_get_doit,
+ .dumpit = devlink_nl_cmd_trap_get_dumpit,
+ .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
+ /* can be retrieved by unprivileged users */
+ },
+ {
+ .cmd = DEVLINK_CMD_TRAP_SET,
+ .doit = devlink_nl_cmd_trap_set_doit,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
+ },
+ {
+ .cmd = DEVLINK_CMD_TRAP_GROUP_GET,
+ .doit = devlink_nl_cmd_trap_group_get_doit,
+ .dumpit = devlink_nl_cmd_trap_group_get_dumpit,
+ .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
+ /* can be retrieved by unprivileged users */
+ },
+ {
+ .cmd = DEVLINK_CMD_TRAP_GROUP_SET,
+ .doit = devlink_nl_cmd_trap_group_set_doit,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
+ },
};
static struct genl_family devlink_nl_family __ro_after_init = {
@@ -5520,6 +6171,8 @@ struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size)
INIT_LIST_HEAD(&devlink->param_list);
INIT_LIST_HEAD(&devlink->region_list);
INIT_LIST_HEAD(&devlink->reporter_list);
+ INIT_LIST_HEAD(&devlink->trap_list);
+ INIT_LIST_HEAD(&devlink->trap_group_list);
mutex_init(&devlink->lock);
mutex_init(&devlink->reporters_lock);
return devlink;
@@ -5566,6 +6219,8 @@ void devlink_free(struct devlink *devlink)
{
mutex_destroy(&devlink->reporters_lock);
mutex_destroy(&devlink->lock);
+ WARN_ON(!list_empty(&devlink->trap_group_list));
+ WARN_ON(!list_empty(&devlink->trap_list));
WARN_ON(!list_empty(&devlink->reporter_list));
WARN_ON(!list_empty(&devlink->region_list));
WARN_ON(!list_empty(&devlink->param_list));
@@ -5670,10 +6325,10 @@ static void __devlink_port_type_set(struct devlink_port *devlink_port,
if (WARN_ON(!devlink_port->registered))
return;
devlink_port_type_warn_cancel(devlink_port);
- spin_lock(&devlink_port->type_lock);
+ spin_lock_bh(&devlink_port->type_lock);
devlink_port->type = type;
devlink_port->type_dev = type_dev;
- spin_unlock(&devlink_port->type_lock);
+ spin_unlock_bh(&devlink_port->type_lock);
devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
}
@@ -6751,6 +7406,592 @@ int devlink_region_snapshot_create(struct devlink_region *region, u64 data_len,
}
EXPORT_SYMBOL_GPL(devlink_region_snapshot_create);
+#define DEVLINK_TRAP(_id, _type) \
+ { \
+ .type = DEVLINK_TRAP_TYPE_##_type, \
+ .id = DEVLINK_TRAP_GENERIC_ID_##_id, \
+ .name = DEVLINK_TRAP_GENERIC_NAME_##_id, \
+ }
+
+static const struct devlink_trap devlink_trap_generic[] = {
+};
+
+#define DEVLINK_TRAP_GROUP(_id) \
+ { \
+ .id = DEVLINK_TRAP_GROUP_GENERIC_ID_##_id, \
+ .name = DEVLINK_TRAP_GROUP_GENERIC_NAME_##_id, \
+ }
+
+static const struct devlink_trap_group devlink_trap_group_generic[] = {
+};
+
+static int devlink_trap_generic_verify(const struct devlink_trap *trap)
+{
+ if (trap->id > DEVLINK_TRAP_GENERIC_ID_MAX)
+ return -EINVAL;
+
+ if (strcmp(trap->name, devlink_trap_generic[trap->id].name))
+ return -EINVAL;
+
+ if (trap->type != devlink_trap_generic[trap->id].type)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int devlink_trap_driver_verify(const struct devlink_trap *trap)
+{
+ int i;
+
+ if (trap->id <= DEVLINK_TRAP_GENERIC_ID_MAX)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(devlink_trap_generic); i++) {
+ if (!strcmp(trap->name, devlink_trap_generic[i].name))
+ return -EEXIST;
+ }
+
+ return 0;
+}
+
+static int devlink_trap_verify(const struct devlink_trap *trap)
+{
+ if (!trap || !trap->name || !trap->group.name)
+ return -EINVAL;
+
+ if (trap->generic)
+ return devlink_trap_generic_verify(trap);
+ else
+ return devlink_trap_driver_verify(trap);
+}
+
+static int
+devlink_trap_group_generic_verify(const struct devlink_trap_group *group)
+{
+ if (group->id > DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
+ return -EINVAL;
+
+ if (strcmp(group->name, devlink_trap_group_generic[group->id].name))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int
+devlink_trap_group_driver_verify(const struct devlink_trap_group *group)
+{
+ int i;
+
+ if (group->id <= DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(devlink_trap_group_generic); i++) {
+ if (!strcmp(group->name, devlink_trap_group_generic[i].name))
+ return -EEXIST;
+ }
+
+ return 0;
+}
+
+static int devlink_trap_group_verify(const struct devlink_trap_group *group)
+{
+ if (group->generic)
+ return devlink_trap_group_generic_verify(group);
+ else
+ return devlink_trap_group_driver_verify(group);
+}
+
+static void
+devlink_trap_group_notify(struct devlink *devlink,
+ const struct devlink_trap_group_item *group_item,
+ enum devlink_command cmd)
+{
+ struct sk_buff *msg;
+ int err;
+
+ WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_GROUP_NEW &&
+ cmd != DEVLINK_CMD_TRAP_GROUP_DEL);
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!msg)
+ return;
+
+ err = devlink_nl_trap_group_fill(msg, devlink, group_item, cmd, 0, 0,
+ 0);
+ if (err) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
+ msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
+}
+
+static struct devlink_trap_group_item *
+devlink_trap_group_item_create(struct devlink *devlink,
+ const struct devlink_trap_group *group)
+{
+ struct devlink_trap_group_item *group_item;
+ int err;
+
+ err = devlink_trap_group_verify(group);
+ if (err)
+ return ERR_PTR(err);
+
+ group_item = kzalloc(sizeof(*group_item), GFP_KERNEL);
+ if (!group_item)
+ return ERR_PTR(-ENOMEM);
+
+ group_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
+ if (!group_item->stats) {
+ err = -ENOMEM;
+ goto err_stats_alloc;
+ }
+
+ group_item->group = group;
+ refcount_set(&group_item->refcount, 1);
+
+ if (devlink->ops->trap_group_init) {
+ err = devlink->ops->trap_group_init(devlink, group);
+ if (err)
+ goto err_group_init;
+ }
+
+ list_add_tail(&group_item->list, &devlink->trap_group_list);
+ devlink_trap_group_notify(devlink, group_item,
+ DEVLINK_CMD_TRAP_GROUP_NEW);
+
+ return group_item;
+
+err_group_init:
+ free_percpu(group_item->stats);
+err_stats_alloc:
+ kfree(group_item);
+ return ERR_PTR(err);
+}
+
+static void
+devlink_trap_group_item_destroy(struct devlink *devlink,
+ struct devlink_trap_group_item *group_item)
+{
+ devlink_trap_group_notify(devlink, group_item,
+ DEVLINK_CMD_TRAP_GROUP_DEL);
+ list_del(&group_item->list);
+ free_percpu(group_item->stats);
+ kfree(group_item);
+}
+
+static struct devlink_trap_group_item *
+devlink_trap_group_item_get(struct devlink *devlink,
+ const struct devlink_trap_group *group)
+{
+ struct devlink_trap_group_item *group_item;
+
+ group_item = devlink_trap_group_item_lookup(devlink, group->name);
+ if (group_item) {
+ refcount_inc(&group_item->refcount);
+ return group_item;
+ }
+
+ return devlink_trap_group_item_create(devlink, group);
+}
+
+static void
+devlink_trap_group_item_put(struct devlink *devlink,
+ struct devlink_trap_group_item *group_item)
+{
+ if (!refcount_dec_and_test(&group_item->refcount))
+ return;
+
+ devlink_trap_group_item_destroy(devlink, group_item);
+}
+
+static int
+devlink_trap_item_group_link(struct devlink *devlink,
+ struct devlink_trap_item *trap_item)
+{
+ struct devlink_trap_group_item *group_item;
+
+ group_item = devlink_trap_group_item_get(devlink,
+ &trap_item->trap->group);
+ if (IS_ERR(group_item))
+ return PTR_ERR(group_item);
+
+ trap_item->group_item = group_item;
+
+ return 0;
+}
+
+static void
+devlink_trap_item_group_unlink(struct devlink *devlink,
+ struct devlink_trap_item *trap_item)
+{
+ devlink_trap_group_item_put(devlink, trap_item->group_item);
+}
+
+static void devlink_trap_notify(struct devlink *devlink,
+ const struct devlink_trap_item *trap_item,
+ enum devlink_command cmd)
+{
+ struct sk_buff *msg;
+ int err;
+
+ WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_NEW &&
+ cmd != DEVLINK_CMD_TRAP_DEL);
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!msg)
+ return;
+
+ err = devlink_nl_trap_fill(msg, devlink, trap_item, cmd, 0, 0, 0);
+ if (err) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
+ msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
+}
+
+static int
+devlink_trap_register(struct devlink *devlink,
+ const struct devlink_trap *trap, void *priv)
+{
+ struct devlink_trap_item *trap_item;
+ int err;
+
+ if (devlink_trap_item_lookup(devlink, trap->name))
+ return -EEXIST;
+
+ trap_item = kzalloc(sizeof(*trap_item), GFP_KERNEL);
+ if (!trap_item)
+ return -ENOMEM;
+
+ trap_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
+ if (!trap_item->stats) {
+ err = -ENOMEM;
+ goto err_stats_alloc;
+ }
+
+ trap_item->trap = trap;
+ trap_item->report = false;
+ trap_item->action = trap->init_action;
+ trap_item->priv = priv;
+
+ err = devlink_trap_item_group_link(devlink, trap_item);
+ if (err)
+ goto err_group_link;
+
+ err = devlink->ops->trap_init(devlink, trap, trap_item);
+ if (err)
+ goto err_trap_init;
+
+ list_add_tail(&trap_item->list, &devlink->trap_list);
+ devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_NEW);
+
+ return 0;
+
+err_trap_init:
+ devlink_trap_item_group_unlink(devlink, trap_item);
+err_group_link:
+ free_percpu(trap_item->stats);
+err_stats_alloc:
+ kfree(trap_item);
+ return err;
+}
+
+static void devlink_trap_unregister(struct devlink *devlink,
+ const struct devlink_trap *trap)
+{
+ struct devlink_trap_item *trap_item;
+
+ trap_item = devlink_trap_item_lookup(devlink, trap->name);
+ if (WARN_ON_ONCE(!trap_item))
+ return;
+
+ devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_DEL);
+ list_del(&trap_item->list);
+ if (devlink->ops->trap_fini)
+ devlink->ops->trap_fini(devlink, trap, trap_item);
+ devlink_trap_item_group_unlink(devlink, trap_item);
+ free_percpu(trap_item->stats);
+ kfree(trap_item);
+}
+
+static void devlink_trap_disable(struct devlink *devlink,
+ const struct devlink_trap *trap)
+{
+ struct devlink_trap_item *trap_item;
+
+ trap_item = devlink_trap_item_lookup(devlink, trap->name);
+ if (WARN_ON_ONCE(!trap_item))
+ return;
+
+ devlink->ops->trap_action_set(devlink, trap, DEVLINK_TRAP_ACTION_DROP);
+ trap_item->action = DEVLINK_TRAP_ACTION_DROP;
+}
+
+/**
+ * devlink_traps_register - Register packet traps with devlink.
+ * @devlink: devlink.
+ * @traps: Packet traps.
+ * @traps_count: Count of provided packet traps.
+ * @priv: Driver private information.
+ *
+ * Return: Non-zero value on failure.
+ */
+int devlink_traps_register(struct devlink *devlink,
+ const struct devlink_trap *traps,
+ size_t traps_count, void *priv)
+{
+ int i, err;
+
+ if (!devlink->ops->trap_init || !devlink->ops->trap_action_set)
+ return -EINVAL;
+
+ mutex_lock(&devlink->lock);
+ for (i = 0; i < traps_count; i++) {
+ const struct devlink_trap *trap = &traps[i];
+
+ err = devlink_trap_verify(trap);
+ if (err)
+ goto err_trap_verify;
+
+ err = devlink_trap_register(devlink, trap, priv);
+ if (err)
+ goto err_trap_register;
+ }
+ mutex_unlock(&devlink->lock);
+
+ return 0;
+
+err_trap_register:
+err_trap_verify:
+ for (i--; i >= 0; i--)
+ devlink_trap_unregister(devlink, &traps[i]);
+ mutex_unlock(&devlink->lock);
+ return err;
+}
+EXPORT_SYMBOL_GPL(devlink_traps_register);
+
+/**
+ * devlink_traps_unregister - Unregister packet traps from devlink.
+ * @devlink: devlink.
+ * @traps: Packet traps.
+ * @traps_count: Count of provided packet traps.
+ */
+void devlink_traps_unregister(struct devlink *devlink,
+ const struct devlink_trap *traps,
+ size_t traps_count)
+{
+ int i;
+
+ mutex_lock(&devlink->lock);
+ /* Make sure we do not have any packets in-flight while unregistering
+ * traps by disabling all of them and waiting for a grace period.
+ */
+ for (i = traps_count - 1; i >= 0; i--)
+ devlink_trap_disable(devlink, &traps[i]);
+ synchronize_rcu();
+ for (i = traps_count - 1; i >= 0; i--)
+ devlink_trap_unregister(devlink, &traps[i]);
+ mutex_unlock(&devlink->lock);
+}
+EXPORT_SYMBOL_GPL(devlink_traps_unregister);
+
+static void
+devlink_trap_stats_update(struct devlink_stats __percpu *trap_stats,
+ size_t skb_len)
+{
+ struct devlink_stats *stats;
+
+ stats = this_cpu_ptr(trap_stats);
+ u64_stats_update_begin(&stats->syncp);
+ stats->rx_bytes += skb_len;
+ stats->rx_packets++;
+ u64_stats_update_end(&stats->syncp);
+}
+
+static size_t devlink_nl_trap_in_port_size(void)
+{
+ /* DEVLINK_ATTR_TRAP_IN_PORT nest */
+ return nla_total_size(0) +
+ /* DEVLINK_ATTR_PORT_INDEX */
+ nla_total_size(sizeof(u32)) +
+ /* DEVLINK_ATTR_PORT_TYPE */
+ nla_total_size(sizeof(u16)) +
+ /* DEVLINK_ATTR_PORT_NETDEV_IFINDEX */
+ nla_total_size(sizeof(u32)) +
+ /* DEVLINK_ATTR_PORT_{NETDEV, IBDEV}_NAME */
+ nla_total_size(max_t(int, IFNAMSIZ, IB_DEVICE_NAME_MAX) + 1);
+}
+
+static size_t
+devlink_nl_trap_report_size(struct devlink *devlink,
+ const struct devlink_trap_item *trap_item,
+ size_t skb_len)
+{
+ size_t size = nlmsg_msg_size(GENL_HDRLEN + devlink_nl_family.hdrsize);
+ struct devlink_trap_group_item *group_item = trap_item->group_item;
+
+ return NLMSG_ALIGN(size) +
+ /* DEVLINK_ATTR_BUS_NAME */
+ nla_total_size(strlen(devlink->dev->bus->name) + 1) +
+ /* DEVLINK_ATTR_DEV_NAME */
+ nla_total_size(strlen(dev_name(devlink->dev)) + 1) +
+ /* DEVLINK_ATTR_TRAP_GROUP_NAME */
+ nla_total_size(strlen(group_item->group->name) + 1) +
+ /* DEVLINK_ATTR_TRAP_NAME */
+ nla_total_size(strlen(trap_item->trap->name) + 1) +
+ /* DEVLINK_ATTR_TRAP_TYPE */
+ nla_total_size(sizeof(u8)) +
+ /* DEVLINK_ATTR_TRAP_TIMESTAMP */
+ nla_total_size(sizeof(struct timespec)) +
+ /* DEVLINK_ATTR_TRAP_IN_PORT */
+ devlink_nl_trap_in_port_size() +
+ /* DEVLINK_ATTR_TRAP_PAYLOAD */
+ nla_total_size(skb_len);
+}
+
+static int
+devlink_nl_trap_report_in_port_put(struct sk_buff *msg,
+ const struct devlink_trap *trap,
+ struct devlink_port *in_devlink_port)
+{
+ struct nlattr *attr;
+
+ if (!(trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT))
+ return 0;
+
+ attr = nla_nest_start(msg, DEVLINK_ATTR_TRAP_IN_PORT);
+ if (!attr)
+ return -EMSGSIZE;
+
+ if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, in_devlink_port->index))
+ goto nla_put_failure;
+
+ spin_lock(&in_devlink_port->type_lock);
+
+ if (devlink_nl_port_type_fill(msg, in_devlink_port))
+ goto unlock_nla_put_failure;
+
+ spin_unlock(&in_devlink_port->type_lock);
+
+ nla_nest_end(msg, attr);
+
+ return 0;
+
+unlock_nla_put_failure:
+ spin_unlock(&in_devlink_port->type_lock);
+nla_put_failure:
+ nla_nest_cancel(msg, attr);
+ return -EMSGSIZE;
+}
+
+static int
+devlink_nl_trap_report_fill(struct sk_buff *msg, struct devlink *devlink,
+ const struct devlink_trap_item *trap_item,
+ struct sk_buff *skb,
+ struct devlink_port *in_devlink_port)
+{
+ struct devlink_trap_group_item *group_item = trap_item->group_item;
+ struct timespec ts = ktime_to_timespec(ktime_get_real());
+ const struct devlink_trap *trap = trap_item->trap;
+ struct nlattr *attr;
+ void *hdr;
+ int err;
+
+ hdr = genlmsg_put(msg, 0, 0, &devlink_nl_family, 0,
+ DEVLINK_CMD_TRAP_REPORT);
+ if (!hdr)
+ return -EMSGSIZE;
+
+ if (devlink_nl_put_handle(msg, devlink))
+ goto nla_put_failure;
+
+ if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
+ group_item->group->name))
+ goto nla_put_failure;
+
+ if (nla_put_string(msg, DEVLINK_ATTR_TRAP_NAME, trap->name))
+ goto nla_put_failure;
+
+ if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_TYPE, trap->type))
+ goto nla_put_failure;
+
+ if (nla_put(msg, DEVLINK_ATTR_TRAP_TIMESTAMP, sizeof(ts), &ts))
+ goto nla_put_failure;
+
+ err = devlink_nl_trap_report_in_port_put(msg, trap, in_devlink_port);
+ if (err)
+ goto nla_put_failure;
+
+ attr = skb_put(msg, nla_total_size(skb->len));
+ attr->nla_type = DEVLINK_ATTR_TRAP_PAYLOAD;
+ attr->nla_len = nla_attr_size(skb->len);
+ if (skb_copy_bits(skb, 0, nla_data(attr), skb->len))
+ goto nla_put_failure;
+
+ genlmsg_end(msg, hdr);
+
+ return 0;
+
+nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+ return -EMSGSIZE;
+}
+
+/**
+ * devlink_trap_report - Report trapped packet to user space.
+ * @devlink: devlink.
+ * @skb: Trapped packet.
+ * @trap_ctx: Trap context.
+ * @in_devlink_port: Input devlink port.
+ */
+void devlink_trap_report(struct devlink *devlink, struct sk_buff *skb,
+ void *trap_ctx, struct devlink_port *in_devlink_port)
+{
+ struct devlink_trap_item *trap_item = trap_ctx;
+ struct sk_buff *msg;
+ int err;
+
+ devlink_trap_stats_update(trap_item->stats, skb->len);
+ devlink_trap_stats_update(trap_item->group_item->stats, skb->len);
+
+ if (!trap_item->report)
+ return;
+
+ msg = nlmsg_new(devlink_nl_trap_report_size(devlink, trap_item,
+ skb->len), GFP_ATOMIC);
+ if (!msg)
+ return;
+
+ err = devlink_nl_trap_report_fill(msg, devlink, trap_item, skb,
+ in_devlink_port);
+ if (err) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
+ msg, 0, DEVLINK_MCGRP_TRAP, GFP_ATOMIC);
+}
+EXPORT_SYMBOL_GPL(devlink_trap_report);
+
+/**
+ * devlink_trap_ctx_priv - Trap context to driver private information.
+ * @trap_ctx: Trap context.
+ *
+ * Return: Driver private information passed during registration.
+ */
+void *devlink_trap_ctx_priv(void *trap_ctx)
+{
+ struct devlink_trap_item *trap_item = trap_ctx;
+
+ return trap_item->priv;
+}
+EXPORT_SYMBOL_GPL(devlink_trap_ctx_priv);
+
static void __devlink_compat_running_version(struct devlink *devlink,
char *buf, size_t len)
{
--
2.20.1
^ permalink raw reply related
* [PATCH net-next 01/11] devlink: Create helper to fill port type information
From: Ido Schimmel @ 2019-07-07 7:58 UTC (permalink / raw)
To: netdev
Cc: davem, jiri, mlxsw, dsahern, roopa, nikolay, andy, pablo,
jakub.kicinski, pieter.jansenvanvuuren, andrew, f.fainelli,
vivien.didelot, Ido Schimmel
In-Reply-To: <20190707075828.3315-1-idosch@idosch.org>
From: Ido Schimmel <idosch@mellanox.com>
The function that fills port attributes in a netlink message fills the
port type attributes together with other attributes such as the device
handle.
The port type attributes will also need to be filled for trapped packets
by a subsequent patch.
Prevent code duplication and create a helper that can be used from both
places.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
---
net/core/devlink.c | 49 +++++++++++++++++++++++++++-------------------
1 file changed, 29 insertions(+), 20 deletions(-)
diff --git a/net/core/devlink.c b/net/core/devlink.c
index 89c533778135..755a9a32015e 100644
--- a/net/core/devlink.c
+++ b/net/core/devlink.c
@@ -527,6 +527,33 @@ static int devlink_nl_port_attrs_put(struct sk_buff *msg,
return 0;
}
+static int devlink_nl_port_type_fill(struct sk_buff *msg,
+ const struct devlink_port *devlink_port)
+{
+ if (nla_put_u16(msg, DEVLINK_ATTR_PORT_TYPE, devlink_port->type))
+ return -EMSGSIZE;
+
+ if (devlink_port->type == DEVLINK_PORT_TYPE_ETH) {
+ struct net_device *netdev = devlink_port->type_dev;
+
+ if (netdev &&
+ (nla_put_u32(msg, DEVLINK_ATTR_PORT_NETDEV_IFINDEX,
+ netdev->ifindex) ||
+ nla_put_string(msg, DEVLINK_ATTR_PORT_NETDEV_NAME,
+ netdev->name)))
+ return -EMSGSIZE;
+ } else if (devlink_port->type == DEVLINK_PORT_TYPE_IB) {
+ struct ib_device *ibdev = devlink_port->type_dev;
+
+ if (ibdev &&
+ nla_put_string(msg, DEVLINK_ATTR_PORT_IBDEV_NAME,
+ ibdev->name))
+ return -EMSGSIZE;
+ }
+
+ return 0;
+}
+
static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink,
struct devlink_port *devlink_port,
enum devlink_command cmd, u32 portid,
@@ -544,30 +571,12 @@ static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink,
goto nla_put_failure;
spin_lock(&devlink_port->type_lock);
- if (nla_put_u16(msg, DEVLINK_ATTR_PORT_TYPE, devlink_port->type))
- goto nla_put_failure_type_locked;
if (devlink_port->desired_type != DEVLINK_PORT_TYPE_NOTSET &&
nla_put_u16(msg, DEVLINK_ATTR_PORT_DESIRED_TYPE,
devlink_port->desired_type))
goto nla_put_failure_type_locked;
- if (devlink_port->type == DEVLINK_PORT_TYPE_ETH) {
- struct net_device *netdev = devlink_port->type_dev;
-
- if (netdev &&
- (nla_put_u32(msg, DEVLINK_ATTR_PORT_NETDEV_IFINDEX,
- netdev->ifindex) ||
- nla_put_string(msg, DEVLINK_ATTR_PORT_NETDEV_NAME,
- netdev->name)))
- goto nla_put_failure_type_locked;
- }
- if (devlink_port->type == DEVLINK_PORT_TYPE_IB) {
- struct ib_device *ibdev = devlink_port->type_dev;
-
- if (ibdev &&
- nla_put_string(msg, DEVLINK_ATTR_PORT_IBDEV_NAME,
- ibdev->name))
- goto nla_put_failure_type_locked;
- }
+ if (devlink_nl_port_type_fill(msg, devlink_port))
+ goto nla_put_failure_type_locked;
spin_unlock(&devlink_port->type_lock);
if (devlink_nl_port_attrs_put(msg, devlink_port))
goto nla_put_failure;
--
2.20.1
^ permalink raw reply related
* [PATCH net-next 00/11] Add drop monitor for offloaded data paths
From: Ido Schimmel @ 2019-07-07 7:58 UTC (permalink / raw)
To: netdev
Cc: davem, jiri, mlxsw, dsahern, roopa, nikolay, andy, pablo,
jakub.kicinski, pieter.jansenvanvuuren, andrew, f.fainelli,
vivien.didelot, Ido Schimmel
From: Ido Schimmel <idosch@mellanox.com>
Users have several ways to debug the kernel and understand why a packet
was dropped. For example, using "drop monitor" and "perf". Both
utilities trace kfree_skb(), which is the function called when a packet
is freed as part of a failure. The information provided by these tools
is invaluable when trying to understand the cause of a packet loss.
In recent years, large portions of the kernel data path were offloaded
to capable devices. Today, it is possible to perform L2 and L3
forwarding in hardware, as well as tunneling (IP-in-IP and VXLAN).
Different TC classifiers and actions are also offloaded to capable
devices, at both ingress and egress.
However, when the data path is offloaded it is not possible to achieve
the same level of introspection as tools such "perf" and "drop monitor"
become irrelevant.
This patchset aims to solve this by allowing users to monitor packets
that the underlying device decided to drop along with relevant metadata
such as the drop reason and ingress port.
The above is achieved by exposing a fundamental capability of devices
capable of data path offloading - packet trapping. While the common use
case for packet trapping is the trapping of packets required for the
correct functioning of the control plane (e.g., STP, BGP packets),
packets can also be trapped due to other reasons such as exceptions
(e.g., TTL error) and drops (e.g., blackhole route).
Given this ability is not specific to a port, but rather to a device, it
is exposed using devlink. Each capable driver is expected to register
its supported packet traps with devlink and report trapped packets to
devlink as they income. devlink will perform accounting of received
packets and bytes and will potentially generate an event to user space
using a new generic netlink multicast group.
While this patchset is concerned with traps corresponding to dropped
packets, the interface itself is generic and can be used to expose traps
corresponding to control packets in the future. The API is vendor
neutral and similar to the API exposed by SAI which is implemented by
several vendors already.
The implementation in this patchset is on top of both mlxsw and
netdevsim so that people could experiment with the interface and provide
useful feedback.
Patches #1-#4 add the devlink-trap infrastructure.
Patches #5-#6 add an example implementation of netdevsim.
Patches #7-#11 add a real world implementation over mlxsw.
Tests for both the core infrastructure (over netdevsim) and mlxsw will
be sent separately as RFC as they are dependent on the acceptance of the
iproute2 changes.
Example
=======
Instantiate netdevsim
---------------------
# echo "10 1" > /sys/bus/netdevsim/new_device
# ip link set dev eth0 up
List supported traps
--------------------
# devlink trap show
netdevsim/netdevsim10:
name source_mac_is_multicast type drop generic true report false action drop group l2_drops
name vlan_tag_mismatch type drop generic true report false action drop group l2_drops
name ingress_vlan_filter type drop generic true report false action drop group l2_drops
name ingress_spanning_tree_filter type drop generic true report false action drop group l2_drops
name port_list_is_empty type drop generic true report false action drop group l2_drops
name port_loopback_filter type drop generic true report false action drop group l2_drops
name fid_miss type exception generic false report false action trap group l2_drops
name blackhole_route type drop generic true report false action drop group l3_drops
name ttl_value_is_too_small type exception generic true report false action trap group l3_drops
name tail_drop type drop generic true report false action drop group buffer_drops
Enable a trap
-------------
# devlink trap set netdevsim/netdevsim10 trap blackhole_route action trap report true
Query statistics
----------------
# devlink -s trap show netdevsim/netdevsim10 trap blackhole_route
netdevsim/netdevsim10:
name blackhole_route type drop generic true report true action trap group l3_drops
stats:
rx:
bytes 18744 packets 132
Monitor dropped packets
-----------------------
# devlink -v mon trap-report
[trap-report,report] netdevsim/netdevsim10: name blackhole_route type drop group l3_drops length 142 timestamp Sun Jun 30 20:26:12 2019 835605178 nsec
input_port:
netdevsim/netdevsim10/0: type eth netdev eth0
Future plans
============
* Provide more drop reasons as well as more metadata
v1:
* Rename trap names to make them more generic
* Change policer settings in mlxsw
Ido Schimmel (11):
devlink: Create helper to fill port type information
devlink: Add packet trap infrastructure
devlink: Add generic packet traps and groups
Documentation: Add devlink-trap documentation
netdevsim: Add devlink-trap support
Documentation: Add description of netdevsim traps
mlxsw: core: Add API to set trap action
mlxsw: reg: Add new trap action
mlxsw: Add layer 2 discard trap IDs
mlxsw: Add trap group for layer 2 discards
mlxsw: spectrum: Add devlink-trap support
.../networking/devlink-trap-netdevsim.rst | 20 +
Documentation/networking/devlink-trap.rst | 190 +++
Documentation/networking/index.rst | 2 +
drivers/net/ethernet/mellanox/mlxsw/Makefile | 2 +-
drivers/net/ethernet/mellanox/mlxsw/core.c | 64 +
drivers/net/ethernet/mellanox/mlxsw/core.h | 12 +
drivers/net/ethernet/mellanox/mlxsw/reg.h | 10 +
.../net/ethernet/mellanox/mlxsw/spectrum.c | 17 +
.../net/ethernet/mellanox/mlxsw/spectrum.h | 13 +
.../ethernet/mellanox/mlxsw/spectrum_trap.c | 270 ++++
drivers/net/ethernet/mellanox/mlxsw/trap.h | 7 +
drivers/net/netdevsim/dev.c | 273 +++-
drivers/net/netdevsim/netdevsim.h | 1 +
include/net/devlink.h | 175 +++
include/uapi/linux/devlink.h | 68 +
net/core/devlink.c | 1312 ++++++++++++++++-
16 files changed, 2409 insertions(+), 27 deletions(-)
create mode 100644 Documentation/networking/devlink-trap-netdevsim.rst
create mode 100644 Documentation/networking/devlink-trap.rst
create mode 100644 drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c
--
2.20.1
^ permalink raw reply
* Re: [PATCH rdma-next 0/2] DEVX VHCA tunnel support
From: Leon Romanovsky @ 2019-07-07 7:51 UTC (permalink / raw)
To: Jason Gunthorpe
Cc: Doug Ledford, RDMA mailing list, Max Gurtovoy, Yishai Hadas,
Saeed Mahameed, linux-netdev
In-Reply-To: <20190705174007.GA7787@ziepe.ca>
On Fri, Jul 05, 2019 at 02:40:07PM -0300, Jason Gunthorpe wrote:
> On Mon, Jul 01, 2019 at 09:14:00PM +0300, Leon Romanovsky wrote:
> > From: Leon Romanovsky <leonro@mellanox.com>
> >
> > Hi,
> >
> > Those two patches introduce VHCA tunnel mechanism to DEVX interface
> > needed for Bluefield SOC. See extensive commit messages for more
> > information.
> >
> > Thanks
> >
> > Max Gurtovoy (2):
> > net/mlx5: Introduce VHCA tunnel device capability
> > IB/mlx5: Implement VHCA tunnel mechanism in DEVX
> >
> > drivers/infiniband/hw/mlx5/devx.c | 24 ++++++++++++++++++++----
> > include/linux/mlx5/mlx5_ifc.h | 10 ++++++++--
> > 2 files changed, 28 insertions(+), 6 deletions(-)
>
> This looks Ok can you apply the mlx5-next patch please
1dd7382b1bb6 net/mlx5: Introduce VHCA tunnel device capability
Thanks
>
> Thanks,
> Jason
>
^ permalink raw reply
* Re: [PATCH net-next v3 1/4] net/sched: Introduce action ct
From: Paul Blakey @ 2019-07-07 6:54 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Jiri Pirko, Roi Dayan, Yossi Kuperman, Oz Shlomo,
Marcelo Ricardo Leitner, netdev@vger.kernel.org, David Miller,
Aaron Conole, Zhike Wang, Rony Efraim, nst-kernel@redhat.com,
John Hurley, Simon Horman, Justin Pettit
In-Reply-To: <20190704145521.29f67ba4@cakuba.netronome.com>
On 7/5/2019 12:55 AM, Jakub Kicinski wrote:
> On Thu, 4 Jul 2019 14:53:50 +0300, Paul Blakey wrote:
>> +static const struct nla_policy ct_policy[TCA_CT_MAX + 1] = {
>> + [TCA_CT_ACTION] = { .type = NLA_U16 },
> Please use strict checking in all new policies.
>
> attr 0 must have .strict_start_type set.
Thanks, I'll fix it.
^ permalink raw reply
* Re: [PATCH net-next 00/12] mlx5 TLS TX HW offload support
From: Tariq Toukan @ 2019-07-07 6:44 UTC (permalink / raw)
To: David Miller, Tariq Toukan
Cc: netdev@vger.kernel.org, Eran Ben Elisha, Saeed Mahameed,
jakub.kicinski@netronome.com, Moshe Shemesh
In-Reply-To: <20190705.162947.1737460613201841097.davem@davemloft.net>
On 7/6/2019 2:29 AM, David Miller wrote:
> From: Tariq Toukan <tariqt@mellanox.com>
> Date: Fri, 5 Jul 2019 18:30:10 +0300
>
>> This series from Eran and me, adds TLS TX HW offload support to
>> the mlx5 driver.
>
> Series applied, please deal with any further feedback you get from
> Jakub et al.
>
> Thanks.
>
I will followup with patches addressing Jakub's feedback.
Thanks,
Tariq
^ permalink raw reply
* Re: [PATCH 4/4] net: mvmdio: defer probe of orion-mdio if a clock is not ready
From: kbuild test robot @ 2019-07-07 5:21 UTC (permalink / raw)
To: josua; +Cc: kbuild-all, netdev, Josua Mayer, David S. Miller
In-Reply-To: <20190706151900.14355-5-josua@solid-run.com>
[-- Attachment #1: Type: text/plain, Size: 6091 bytes --]
Hi,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on linus/master]
[also build test WARNING on v5.2-rc7 next-20190705]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/josua-solid-run-com/Fix-hang-of-Armada-8040-SoC-in-orion-mdio/20190707-111919
config: arm-allmodconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (GCC) 7.4.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
GCC_VERSION=7.4.0 make.cross ARCH=arm
If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>
All warnings (new ones prefixed by >>):
drivers/net/ethernet/marvell/mvmdio.c: In function 'orion_mdio_probe':
>> drivers/net/ethernet/marvell/mvmdio.c:324:30: warning: passing argument 1 of 'PTR_ERR' makes pointer from integer without a cast [-Wint-conversion]
if (dev->clk[i] == PTR_ERR(-EPROBE_DEFER)) {
^
In file included from include/linux/clk.h:12:0,
from drivers/net/ethernet/marvell/mvmdio.c:20:
include/linux/err.h:29:33: note: expected 'const void *' but argument is of type 'int'
static inline long __must_check PTR_ERR(__force const void *ptr)
^~~~~~~
>> drivers/net/ethernet/marvell/mvmdio.c:324:19: warning: comparison between pointer and integer
if (dev->clk[i] == PTR_ERR(-EPROBE_DEFER)) {
^~
In file included from include/linux/node.h:18:0,
from include/linux/cpu.h:17,
from include/linux/of_device.h:5,
from drivers/net/ethernet/marvell/mvmdio.c:26:
drivers/net/ethernet/marvell/mvmdio.c:334:12: error: passing argument 1 of '_dev_warn' from incompatible pointer type [-Werror=incompatible-pointer-types]
dev_warn(dev, "unsupported number of clocks, limiting to the first "
^
include/linux/device.h:1487:12: note: in definition of macro 'dev_warn'
_dev_warn(dev, dev_fmt(fmt), ##__VA_ARGS__)
^~~
include/linux/device.h:1425:6: note: expected 'const struct device *' but argument is of type 'struct orion_mdio_dev *'
void _dev_warn(const struct device *dev, const char *fmt, ...);
^~~~~~~~~
cc1: some warnings being treated as errors
vim +/PTR_ERR +324 drivers/net/ethernet/marvell/mvmdio.c
275
276 static int orion_mdio_probe(struct platform_device *pdev)
277 {
278 enum orion_mdio_bus_type type;
279 struct resource *r;
280 struct mii_bus *bus;
281 struct orion_mdio_dev *dev;
282 int i, ret;
283
284 type = (enum orion_mdio_bus_type)of_device_get_match_data(&pdev->dev);
285
286 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
287 if (!r) {
288 dev_err(&pdev->dev, "No SMI register address given\n");
289 return -ENODEV;
290 }
291
292 bus = devm_mdiobus_alloc_size(&pdev->dev,
293 sizeof(struct orion_mdio_dev));
294 if (!bus)
295 return -ENOMEM;
296
297 switch (type) {
298 case BUS_TYPE_SMI:
299 bus->read = orion_mdio_smi_read;
300 bus->write = orion_mdio_smi_write;
301 break;
302 case BUS_TYPE_XSMI:
303 bus->read = orion_mdio_xsmi_read;
304 bus->write = orion_mdio_xsmi_write;
305 break;
306 }
307
308 bus->name = "orion_mdio_bus";
309 snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii",
310 dev_name(&pdev->dev));
311 bus->parent = &pdev->dev;
312
313 dev = bus->priv;
314 dev->regs = devm_ioremap(&pdev->dev, r->start, resource_size(r));
315 if (!dev->regs) {
316 dev_err(&pdev->dev, "Unable to remap SMI register\n");
317 return -ENODEV;
318 }
319
320 init_waitqueue_head(&dev->smi_busy_wait);
321
322 for (i = 0; i < ARRAY_SIZE(dev->clk); i++) {
323 dev->clk[i] = of_clk_get(pdev->dev.of_node, i);
> 324 if (dev->clk[i] == PTR_ERR(-EPROBE_DEFER)) {
325 ret = -EPROBE_DEFER;
326 goto out_clk;
327 }
328 if (IS_ERR(dev->clk[i]))
329 break;
330 clk_prepare_enable(dev->clk[i]);
331 }
332
333 if (!IS_ERR(of_clk_get(pdev->dev.of_node, i)))
334 dev_warn(dev, "unsupported number of clocks, limiting to the first "
335 __stringify(ARRAY_SIZE(dev->clk)) "\n");
336
337 dev->err_interrupt = platform_get_irq(pdev, 0);
338 if (dev->err_interrupt > 0 &&
339 resource_size(r) < MVMDIO_ERR_INT_MASK + 4) {
340 dev_err(&pdev->dev,
341 "disabling interrupt, resource size is too small\n");
342 dev->err_interrupt = 0;
343 }
344 if (dev->err_interrupt > 0) {
345 ret = devm_request_irq(&pdev->dev, dev->err_interrupt,
346 orion_mdio_err_irq,
347 IRQF_SHARED, pdev->name, dev);
348 if (ret)
349 goto out_mdio;
350
351 writel(MVMDIO_ERR_INT_SMI_DONE,
352 dev->regs + MVMDIO_ERR_INT_MASK);
353
354 } else if (dev->err_interrupt == -EPROBE_DEFER) {
355 ret = -EPROBE_DEFER;
356 goto out_mdio;
357 }
358
359 ret = of_mdiobus_register(bus, pdev->dev.of_node);
360 if (ret < 0) {
361 dev_err(&pdev->dev, "Cannot register MDIO bus (%d)\n", ret);
362 goto out_mdio;
363 }
364
365 platform_set_drvdata(pdev, bus);
366
367 return 0;
368
369 out_mdio:
370 if (dev->err_interrupt > 0)
371 writel(0, dev->regs + MVMDIO_ERR_INT_MASK);
372
373 out_clk:
374 for (i = 0; i < ARRAY_SIZE(dev->clk); i++) {
375 if (IS_ERR(dev->clk[i]))
376 break;
377 clk_disable_unprepare(dev->clk[i]);
378 clk_put(dev->clk[i]);
379 }
380
381 return ret;
382 }
383
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 70930 bytes --]
^ permalink raw reply
* Re: [PATCH 3/4] net: mvmdio: print warning when orion-mdio has too many clocks
From: kbuild test robot @ 2019-07-07 5:04 UTC (permalink / raw)
To: josua; +Cc: kbuild-all, netdev, Josua Mayer, David S. Miller
In-Reply-To: <20190706151900.14355-4-josua@solid-run.com>
[-- Attachment #1: Type: text/plain, Size: 5216 bytes --]
Hi,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on linus/master]
[also build test ERROR on v5.2-rc7 next-20190705]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/josua-solid-run-com/Fix-hang-of-Armada-8040-SoC-in-orion-mdio/20190707-111919
config: arm-allmodconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (GCC) 7.4.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
GCC_VERSION=7.4.0 make.cross ARCH=arm
If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>
All errors (new ones prefixed by >>):
In file included from include/linux/node.h:18:0,
from include/linux/cpu.h:17,
from include/linux/of_device.h:5,
from drivers/net/ethernet/marvell/mvmdio.c:26:
drivers/net/ethernet/marvell/mvmdio.c: In function 'orion_mdio_probe':
>> drivers/net/ethernet/marvell/mvmdio.c:330:12: error: passing argument 1 of '_dev_warn' from incompatible pointer type [-Werror=incompatible-pointer-types]
dev_warn(dev, "unsupported number of clocks, limiting to the first "
^
include/linux/device.h:1487:12: note: in definition of macro 'dev_warn'
_dev_warn(dev, dev_fmt(fmt), ##__VA_ARGS__)
^~~
include/linux/device.h:1425:6: note: expected 'const struct device *' but argument is of type 'struct orion_mdio_dev *'
void _dev_warn(const struct device *dev, const char *fmt, ...);
^~~~~~~~~
cc1: some warnings being treated as errors
vim +/_dev_warn +330 drivers/net/ethernet/marvell/mvmdio.c
275
276 static int orion_mdio_probe(struct platform_device *pdev)
277 {
278 enum orion_mdio_bus_type type;
279 struct resource *r;
280 struct mii_bus *bus;
281 struct orion_mdio_dev *dev;
282 int i, ret;
283
284 type = (enum orion_mdio_bus_type)of_device_get_match_data(&pdev->dev);
285
286 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
287 if (!r) {
288 dev_err(&pdev->dev, "No SMI register address given\n");
289 return -ENODEV;
290 }
291
292 bus = devm_mdiobus_alloc_size(&pdev->dev,
293 sizeof(struct orion_mdio_dev));
294 if (!bus)
295 return -ENOMEM;
296
297 switch (type) {
298 case BUS_TYPE_SMI:
299 bus->read = orion_mdio_smi_read;
300 bus->write = orion_mdio_smi_write;
301 break;
302 case BUS_TYPE_XSMI:
303 bus->read = orion_mdio_xsmi_read;
304 bus->write = orion_mdio_xsmi_write;
305 break;
306 }
307
308 bus->name = "orion_mdio_bus";
309 snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii",
310 dev_name(&pdev->dev));
311 bus->parent = &pdev->dev;
312
313 dev = bus->priv;
314 dev->regs = devm_ioremap(&pdev->dev, r->start, resource_size(r));
315 if (!dev->regs) {
316 dev_err(&pdev->dev, "Unable to remap SMI register\n");
317 return -ENODEV;
318 }
319
320 init_waitqueue_head(&dev->smi_busy_wait);
321
322 for (i = 0; i < ARRAY_SIZE(dev->clk); i++) {
323 dev->clk[i] = of_clk_get(pdev->dev.of_node, i);
324 if (IS_ERR(dev->clk[i]))
325 break;
326 clk_prepare_enable(dev->clk[i]);
327 }
328
329 if (!IS_ERR(of_clk_get(pdev->dev.of_node, i)))
> 330 dev_warn(dev, "unsupported number of clocks, limiting to the first "
331 __stringify(ARRAY_SIZE(dev->clk)) "\n");
332
333 dev->err_interrupt = platform_get_irq(pdev, 0);
334 if (dev->err_interrupt > 0 &&
335 resource_size(r) < MVMDIO_ERR_INT_MASK + 4) {
336 dev_err(&pdev->dev,
337 "disabling interrupt, resource size is too small\n");
338 dev->err_interrupt = 0;
339 }
340 if (dev->err_interrupt > 0) {
341 ret = devm_request_irq(&pdev->dev, dev->err_interrupt,
342 orion_mdio_err_irq,
343 IRQF_SHARED, pdev->name, dev);
344 if (ret)
345 goto out_mdio;
346
347 writel(MVMDIO_ERR_INT_SMI_DONE,
348 dev->regs + MVMDIO_ERR_INT_MASK);
349
350 } else if (dev->err_interrupt == -EPROBE_DEFER) {
351 ret = -EPROBE_DEFER;
352 goto out_mdio;
353 }
354
355 ret = of_mdiobus_register(bus, pdev->dev.of_node);
356 if (ret < 0) {
357 dev_err(&pdev->dev, "Cannot register MDIO bus (%d)\n", ret);
358 goto out_mdio;
359 }
360
361 platform_set_drvdata(pdev, bus);
362
363 return 0;
364
365 out_mdio:
366 if (dev->err_interrupt > 0)
367 writel(0, dev->regs + MVMDIO_ERR_INT_MASK);
368
369 for (i = 0; i < ARRAY_SIZE(dev->clk); i++) {
370 if (IS_ERR(dev->clk[i]))
371 break;
372 clk_disable_unprepare(dev->clk[i]);
373 clk_put(dev->clk[i]);
374 }
375
376 return ret;
377 }
378
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 70930 bytes --]
^ permalink raw reply
* [PATCH] ipvs: Delete some unused space characters in Kconfig
From: xianfengting221 @ 2019-07-07 4:16 UTC (permalink / raw)
To: wensong, horms, ja, pablo, kadlec, fw, davem
Cc: netdev, lvs-devel, linux-kernel, Hu Haowen
From: Hu Haowen <xianfengting221@163.com>
The space characters at the end of lines are always unused and
not easy to find. This patch deleted some of them I have found
in Kconfig.
Signed-off-by: Hu Haowen <xianfengting221@163.com>
---
This is my first patch to the Linux kernel, so please forgive
me if anything went wrong.
net/netfilter/ipvs/Kconfig | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/net/netfilter/ipvs/Kconfig b/net/netfilter/ipvs/Kconfig
index f6f1a0d..54afad5 100644
--- a/net/netfilter/ipvs/Kconfig
+++ b/net/netfilter/ipvs/Kconfig
@@ -120,7 +120,7 @@ config IP_VS_RR
If you want to compile it in kernel, say Y. To compile it as a
module, choose M here. If unsure, say N.
-
+
config IP_VS_WRR
tristate "weighted round-robin scheduling"
---help---
@@ -138,7 +138,7 @@ config IP_VS_LC
tristate "least-connection scheduling"
---help---
The least-connection scheduling algorithm directs network
- connections to the server with the least number of active
+ connections to the server with the least number of active
connections.
If you want to compile it in kernel, say Y. To compile it as a
@@ -193,7 +193,7 @@ config IP_VS_LBLCR
tristate "locality-based least-connection with replication scheduling"
---help---
The locality-based least-connection with replication scheduling
- algorithm is also for destination IP load balancing. It is
+ algorithm is also for destination IP load balancing. It is
usually used in cache cluster. It differs from the LBLC scheduling
as follows: the load balancer maintains mappings from a target
to a set of server nodes that can serve the target. Requests for
@@ -250,8 +250,8 @@ config IP_VS_SED
tristate "shortest expected delay scheduling"
---help---
The shortest expected delay scheduling algorithm assigns network
- connections to the server with the shortest expected delay. The
- expected delay that the job will experience is (Ci + 1) / Ui if
+ connections to the server with the shortest expected delay. The
+ expected delay that the job will experience is (Ci + 1) / Ui if
sent to the ith server, in which Ci is the number of connections
on the ith server and Ui is the fixed service rate (weight)
of the ith server.
--
2.7.4
^ permalink raw reply related
* [PATCH net] tcp: Reset bytes_acked and bytes_received when disconnecting
From: Christoph Paasch @ 2019-07-06 23:13 UTC (permalink / raw)
To: netdev; +Cc: David Miller, Eric Dumazet
If an app is playing tricks to reuse a socket via tcp_disconnect(),
bytes_acked/received needs to be reset to 0. Otherwise tcp_info will
report the sum of the current and the old connection..
Cc: Eric Dumazet <edumazet@google.com>
Fixes: 0df48c26d841 ("tcp: add tcpi_bytes_acked to tcp_info")
Fixes: bdd1f9edacb5 ("tcp: add tcpi_bytes_received to tcp_info")
Signed-off-by: Christoph Paasch <cpaasch@apple.com>
---
net/ipv4/tcp.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 7dc9ab84bb69..2eebd092c3c1 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2614,6 +2614,8 @@ int tcp_disconnect(struct sock *sk, int flags)
tcp_saved_syn_free(tp);
tp->compressed_ack = 0;
tp->bytes_sent = 0;
+ tp->bytes_acked = 0;
+ tp->bytes_received = 0;
tp->bytes_retrans = 0;
tp->duplicate_sack[0].start_seq = 0;
tp->duplicate_sack[0].end_seq = 0;
--
2.21.0
^ permalink raw reply related
* Re: INFO: rcu detected stall in ext4_write_checks
From: Paul E. McKenney @ 2019-07-07 1:16 UTC (permalink / raw)
To: Theodore Ts'o, Dmitry Vyukov, syzbot, Andreas Dilger,
David Miller, eladr, Ido Schimmel, Jiri Pirko, John Stultz,
linux-ext4, LKML, netdev, syzkaller-bugs, Thomas Gleixner,
Peter Zijlstra, Ingo Molnar
In-Reply-To: <20190706180311.GW26519@linux.ibm.com>
On Sat, Jul 06, 2019 at 11:03:11AM -0700, Paul E. McKenney wrote:
> On Sat, Jul 06, 2019 at 11:02:26AM -0400, Theodore Ts'o wrote:
> > On Fri, Jul 05, 2019 at 11:16:31PM -0700, Paul E. McKenney wrote:
> > > I suppose RCU could take the dueling-banjos approach and use increasingly
> > > aggressive scheduler policies itself, up to and including SCHED_DEADLINE,
> > > until it started getting decent forward progress. However, that
> > > sounds like the something that just might have unintended consequences,
> > > particularly if other kernel subsystems were to also play similar
> > > games of dueling banjos.
> >
> > So long as the RCU threads are well-behaved, using SCHED_DEADLINE
> > shouldn't have much of an impact on the system --- and the scheduling
> > parameters that you can specify on SCHED_DEADLINE allows you to
> > specify the worst-case impact on the system while also guaranteeing
> > that the SCHED_DEADLINE tasks will urn in the first place. After all,
> > that's the whole point of SCHED_DEADLINE.
> >
> > So I wonder if the right approach is during the the first userspace
> > system call to shced_setattr to enable a (any) real-time priority
> > scheduler (SCHED_DEADLINE, SCHED_FIFO or SCHED_RR) on a userspace
> > thread, before that's allowed to proceed, the RCU kernel threads are
> > promoted to be SCHED_DEADLINE with appropriately set deadline
> > parameters. That way, a root user won't be able to shoot the system
> > in the foot, and since the vast majority of the time, there shouldn't
> > be any processes running with real-time priorities, we won't be
> > changing the behavior of a normal server system.
>
> It might well be. However, running the RCU kthreads at real-time
> priority does not come for free. For example, it tends to crank up the
> context-switch rate.
>
> Plus I have taken several runs at computing SCHED_DEADLINE parameters,
> but things like the rcuo callback-offload threads have computational
> requirements that are controlled not by RCU, and not just by the rest of
> the kernel, but also by userspace (keeping in mind the example of opening
> and closing a file in a tight loop, each pass of which queues a callback).
> I suspect that RCU is not the only kernel subsystem whose computational
> requirements are set not by the subsystem, but rather by external code.
>
> OK, OK, I suppose I could just set insanely large SCHED_DEADLINE
> parameters, following syzkaller's example, and then trust my ability to
> keep the RCU code from abusing the resulting awesome power. But wouldn't
> a much nicer approach be to put SCHED_DEADLINE between SCHED_RR/SCHED_FIFO
> priorities 98 and 99 or some such? Then the same (admittedly somewhat
> scary) result could be obtained much more simply via SCHED_FIFO or
> SCHED_RR priority 99.
>
> Some might argue that this is one of those situations where simplicity
> is not necessarily an advantage, but then again, you can find someone
> who will complain about almost anything. ;-)
>
> > (I suspect there might be some audio applications that might try to
> > set real-time priorities, but for desktop systems, it's probably more
> > important that the system not tie its self into knots since the
> > average desktop user isn't going to be well equipped to debug the
> > problem.)
>
> Not only that, but if core counts continue to increase, and if reliance
> on cloud computing continues to grow, there are going to be an increasing
> variety of mixed workloads in increasingly less-controlled environments.
>
> So, yes, it would be good to solve this problem in some reasonable way.
>
> I don't see this as urgent just yet, but I am sure you all will let
> me know if I am mistaken on that point.
>
> > > Alternatively, is it possible to provide stricter admission control?
> >
> > I think that's an orthogonal issue; better admission control would be
> > nice, but it looks to me that it's going to be fundamentally an issue
> > of tweaking hueristics, and a fool-proof solution that will protect
> > against all malicious userspace applications (including syzkaller) is
> > going to require solving the halting problem. So while it would be
> > nice to improve the admission control, I don't think that's a going to
> > be a general solution.
>
> Agreed, and my earlier point about the need to trust the coding abilities
> of those writing ultimate-priority code is all too consistent with your
> point about needing to solve the halting problem. Nevertheless, I believe
> that we could make something that worked reasonably well in practice.
>
> Here are a few components of a possible solution, in practice, but
> of course not in theory:
>
> 1. We set limits to SCHED_DEADLINE parameters, perhaps novel ones.
> For one example, insist on (say) 10 milliseconds of idle time
> every second on each CPU. Yes, you can configure beyond that
> given sufficient permissions, but if you do so, you just voided
> your warranty.
>
> 2. Only allow SCHED_DEADLINE on nohz_full CPUs. (Partial solution,
> given that such a CPU might be running in the kernel or have
> more than one runnable task. Just for fun, I will suggest the
> option of disabling SCHED_DEADLINE during such times.)
>
> 3. RCU detects slowdowns, and does something TBD to increase its
> priority, but only while the slowdown persists. This likely
> relies on scheduling-clock interrupts to detect the slowdowns,
> so there might be additional challenges on a fully nohz_full
> system.
4. SCHED_DEADLINE treats the other three scheduling classes as each
having a period, deadline, and a modest CPU consumption budget
for the members of the class in aggregate. But this has to have
been discussed before. How did that go?
> 5. Your idea here.
Thanx, Paul
^ permalink raw reply
* Re: [PATCH 1/2] proc: revalidate directories created with proc_net_mkdir()
From: Al Viro @ 2019-07-07 1:03 UTC (permalink / raw)
To: Alexey Dobriyan; +Cc: davem, netdev, Per.Hallsmark
In-Reply-To: <20190706165201.GA10550@avx2>
On Sat, Jul 06, 2019 at 07:52:02PM +0300, Alexey Dobriyan wrote:
> +struct proc_dir_entry *_proc_mkdir(const char *name, umode_t mode,
> + struct proc_dir_entry **parent, void *data)
Two underscores, please...
> + parent->nlink++;
> + pde = proc_register(parent, pde);
> + if (!pde)
> + parent->nlink++;
Really?
^ permalink raw reply
* Re: [PATCH][next] 6lowpan: fix off-by-one comparison of index id with LOWPAN_IPHC_CTX_TABLE_SIZE
From: Colin Ian King @ 2019-07-06 23:23 UTC (permalink / raw)
To: Marcel Holtmann
Cc: Alexander Aring, Jukka Rissanen, David S. Miller, linux-bluetooth,
linux-wpan, netdev, kernel-janitors, linux-kernel
In-Reply-To: <B6A1CB42-C239-42CA-B14E-483A02B930EB@holtmann.org>
On 06/07/2019 11:51, Marcel Holtmann wrote:
> Hi Colin,
>
>> The WARN_ON_ONCE check on id is off-by-one, it should be greater or equal
>> to LOWPAN_IPHC_CTX_TABLE_SIZE and not greater than. Fix this.
>>
>> Signed-off-by: Colin Ian King <colin.king@canonical.com>
>> ---
>> net/6lowpan/debugfs.c | 2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/net/6lowpan/debugfs.c b/net/6lowpan/debugfs.c
>> index 1c140af06d52..a510bed8165b 100644
>> --- a/net/6lowpan/debugfs.c
>> +++ b/net/6lowpan/debugfs.c
>> @@ -170,7 +170,7 @@ static void lowpan_dev_debugfs_ctx_init(struct net_device *dev,
>> struct dentry *root;
>> char buf[32];
>>
>> - WARN_ON_ONCE(id > LOWPAN_IPHC_CTX_TABLE_SIZE);
>> + WARN_ON_ONCE(id >= LOWPAN_IPHC_CTX_TABLE_SIZE);
>
> this patch no longer applied cleanly to bluetooth-next. Can you send me an updated version.
I'm confused by this, I just applied it OK on bluetooth-next [1] on the
head 9ce67c3235be71e8cf922a9b3d0b7359ed3f4ce5, am I applying this to the
wrong repo/branch?
[1]
git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git
Colin
>
> Regards
>
> Marcel
>
^ permalink raw reply
* More complex PBR rules
From: Markus Moeller @ 2019-07-06 23:06 UTC (permalink / raw)
To: netdev
Hi Network developers
I am new to this group and wonder if you can advise how I could implement
more complex PBR rules to achieve for example load balancing. The
requirement I have is to route based on e.g. a hash like:
hash(src-ip+dst-ip) mod N routes via gwX 0<X<=N ( load balance over
N gateways )
This would help in situations where I can not use a MAC for identifying a
gateway ( e.g. in cloud environments) .
Could someone point me to the kernel source code where PBR is performed ?
Thank you
Markus
^ permalink raw reply
* Re: [PATCH net-next 0/4] bnxt_en: Add XDP_REDIRECT support.
From: David Miller @ 2019-07-06 22:26 UTC (permalink / raw)
To: michael.chan; +Cc: gospo, netdev, hawk, ast
In-Reply-To: <1562398578-26020-1-git-send-email-michael.chan@broadcom.com>
From: Michael Chan <michael.chan@broadcom.com>
Date: Sat, 6 Jul 2019 03:36:14 -0400
> This patch series adds XDP_REDIRECT support by Andy Gospodarek.
I'll give Jesper et al. a chance to review this.
^ permalink raw reply
* Re: pull-request: wireless-drivers-next 2019-07-06
From: David Miller @ 2019-07-06 22:20 UTC (permalink / raw)
To: kvalo; +Cc: linux-wireless, netdev, linux-kernel
In-Reply-To: <878stbabkb.fsf@kamboji.qca.qualcomm.com>
From: Kalle Valo <kvalo@codeaurora.org>
Date: Sat, 06 Jul 2019 10:04:20 +0300
> here's a pull request to net-next tree for v5.3, more info below. I will
> be offline from Sunday to Thursday, but Johannes should be able to help
> during that time.
Pulled, thanks Kalle.
^ permalink raw reply
* Re: [PATCH net-next] tipc: use rcu dereference functions properly
From: David Miller @ 2019-07-06 22:15 UTC (permalink / raw)
To: lucien.xin; +Cc: netdev, jon.maloy, ying.xue, tipc-discussion
In-Reply-To: <CADvbK_eDnUMSaoT65hco2PF5-f1PO=CKBeMPz3sTRZvg5qKGVA@mail.gmail.com>
From: Xin Long <lucien.xin@gmail.com>
Date: Sat, 6 Jul 2019 14:48:48 +0800
> Hi, David, I saw this patch in "Changes Requested".
I just put it back to Under Review, thanks.
^ permalink raw reply
* [PATCH iproute2-next] ip: bond: add peer notification delay support
From: Vincent Bernat @ 2019-07-06 21:11 UTC (permalink / raw)
To: netdev, Stephen Hemminger; +Cc: Vincent Bernat
Ability to tweak the delay between gratuitous ND/ARP packets has been
added in kernel commit 07a4ddec3ce9 ("bonding: add an option to
specify a delay between peer notifications"), through
IFLA_BOND_PEER_NOTIF_DELAY attribute. Add support to set and show this
value.
Example:
$ ip -d link set bond0 type bond peer_notif_delay 1000
$ ip -d link l dev bond0
2: bond0: <BROADCAST,MULTICAST,MASTER,UP,LOWER_UP> mtu 1500 qdisc noqueue
state UP mode DEFAULT group default qlen 1000
link/ether 50:54:33:00:00:01 brd ff:ff:ff:ff:ff:ff
bond mode active-backup active_slave eth0 miimon 100 updelay 0
downdelay 0 peer_notif_delay 1000 use_carrier 1 arp_interval 0
arp_validate none arp_all_targets any primary eth0
primary_reselect always fail_over_mac active xmit_hash_policy
layer2 resend_igmp 1 num_grat_arp 5 all_slaves_active 0 min_links
0 lp_interval 1 packets_per_slave 1 lacp_rate slow ad_select
stable tlb_dynamic_lb 1 addrgenmode eu
Signed-off-by: Vincent Bernat <vincent@bernat.ch>
---
include/uapi/linux/if_link.h | 1 +
ip/iplink_bond.c | 14 +++++++++++++-
2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index b59554dd55cb..d36919fb4024 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -634,6 +634,7 @@ enum {
IFLA_BOND_AD_USER_PORT_KEY,
IFLA_BOND_AD_ACTOR_SYSTEM,
IFLA_BOND_TLB_DYNAMIC_LB,
+ IFLA_BOND_PEER_NOTIF_DELAY,
__IFLA_BOND_MAX,
};
diff --git a/ip/iplink_bond.c b/ip/iplink_bond.c
index c60f0e8ad0a0..fb62c955631e 100644
--- a/ip/iplink_bond.c
+++ b/ip/iplink_bond.c
@@ -120,6 +120,7 @@ static void print_explain(FILE *f)
"Usage: ... bond [ mode BONDMODE ] [ active_slave SLAVE_DEV ]\n"
" [ clear_active_slave ] [ miimon MIIMON ]\n"
" [ updelay UPDELAY ] [ downdelay DOWNDELAY ]\n"
+ " [ peer_notif_delay DELAY ]\n"
" [ use_carrier USE_CARRIER ]\n"
" [ arp_interval ARP_INTERVAL ]\n"
" [ arp_validate ARP_VALIDATE ]\n"
@@ -165,7 +166,7 @@ static int bond_parse_opt(struct link_util *lu, int argc, char **argv,
__u8 xmit_hash_policy, num_peer_notif, all_slaves_active;
__u8 lacp_rate, ad_select, tlb_dynamic_lb;
__u16 ad_user_port_key, ad_actor_sys_prio;
- __u32 miimon, updelay, downdelay, arp_interval, arp_validate;
+ __u32 miimon, updelay, downdelay, peer_notif_delay, arp_interval, arp_validate;
__u32 arp_all_targets, resend_igmp, min_links, lp_interval;
__u32 packets_per_slave;
unsigned int ifindex;
@@ -200,6 +201,11 @@ static int bond_parse_opt(struct link_util *lu, int argc, char **argv,
if (get_u32(&downdelay, *argv, 0))
invarg("invalid downdelay", *argv);
addattr32(n, 1024, IFLA_BOND_DOWNDELAY, downdelay);
+ } else if (matches(*argv, "peer_notif_delay") == 0) {
+ NEXT_ARG();
+ if (get_u32(&peer_notif_delay, *argv, 0))
+ invarg("invalid peer_notif_delay", *argv);
+ addattr32(n, 1024, IFLA_BOND_PEER_NOTIF_DELAY, peer_notif_delay);
} else if (matches(*argv, "use_carrier") == 0) {
NEXT_ARG();
if (get_u8(&use_carrier, *argv, 0))
@@ -410,6 +416,12 @@ static void bond_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
"downdelay %u ",
rta_getattr_u32(tb[IFLA_BOND_DOWNDELAY]));
+ if (tb[IFLA_BOND_PEER_NOTIF_DELAY])
+ print_uint(PRINT_ANY,
+ "peer_notif_delay",
+ "peer_notif_delay %u ",
+ rta_getattr_u32(tb[IFLA_BOND_PEER_NOTIF_DELAY]));
+
if (tb[IFLA_BOND_USE_CARRIER])
print_uint(PRINT_ANY,
"use_carrier",
--
2.20.1
^ permalink raw reply related
* [net-next] bonding: fix value exported by Netlink for peer_notif_delay
From: Vincent Bernat @ 2019-07-06 21:01 UTC (permalink / raw)
To: Jay Vosburgh, Veaceslav Falico, Andy Gospodarek, David S. Miller,
netdev
Cc: Vincent Bernat
IFLA_BOND_PEER_NOTIF_DELAY was set to the value of downdelay instead
of peer_notif_delay. After this change, the correct value is exported.
Fixes: 07a4ddec3ce9 ("bonding: add an option to specify a delay between peer notifications")
Signed-off-by: Vincent Bernat <vincent@bernat.ch>
---
drivers/net/bonding/bond_netlink.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c
index a259860a7208..b43b51646b11 100644
--- a/drivers/net/bonding/bond_netlink.c
+++ b/drivers/net/bonding/bond_netlink.c
@@ -547,7 +547,7 @@ static int bond_fill_info(struct sk_buff *skb,
goto nla_put_failure;
if (nla_put_u32(skb, IFLA_BOND_PEER_NOTIF_DELAY,
- bond->params.downdelay * bond->params.miimon))
+ bond->params.peer_notif_delay * bond->params.miimon))
goto nla_put_failure;
if (nla_put_u8(skb, IFLA_BOND_USE_CARRIER, bond->params.use_carrier))
--
2.20.1
^ permalink raw reply related
* [PATCH] net, skbuff: Handle devmap managed page when skb->head_frag is true
From: Ujjal Roy @ 2019-07-06 19:57 UTC (permalink / raw)
To: Kernel, David S. Miller
When head_frag is true we have page in the SKB head. So, for devm
managed page we need to inform the device driver through callback.
Signed-off-by: Ujjal Roy <royujjal@gmail.com>
---
net/core/skbuff.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index c8cd99c3603f..0d303e694efa 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -582,10 +582,16 @@ static void skb_free_head(struct sk_buff *skb)
{
unsigned char *head = skb->head;
- if (skb->head_frag)
+ if (skb->head_frag) {
+ struct page *page = virt_to_head_page(head);
+
+ if (put_devmap_managed_page(page))
+ return;
+
skb_free_frag(head);
- else
+ } else {
kfree(head);
+ }
}
static void skb_release_data(struct sk_buff *skb)
--
2.11.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox