[PATCH net-next RFC v1 2/4] devlink: Add devlink traps under devlink_ports context
From: Aya Levin <hidden>
Date: 2020-09-02 15:33:48
Also in:
lkml
Subsystem:
devlink, mellanox ethernet switch drivers, networking drivers, networking [general], the rest · Maintainers:
Jiri Pirko, Ido Schimmel, Petr Machata, Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
There are some cases where we would like to trap dropped packets only for a single port on a device without affecting the others. For that purpose trap_mngr was added to devlink_port and corresponding Trap API with devlink_port were added too. Signed-off-by: Aya Levin <redacted> --- drivers/net/ethernet/mellanox/mlxsw/core.c | 1 + include/net/devlink.h | 25 +++ net/core/devlink.c | 332 ++++++++++++++++++++++++++++- 3 files changed, 353 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c
index 97460f47e537..cb9567a6a90d 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core.c@@ -1178,6 +1178,7 @@ static void mlxsw_devlink_trap_fini(struct devlink *devlink, static int mlxsw_devlink_trap_action_set(struct devlink *devlink, const struct devlink_trap *trap, enum devlink_trap_action action, + void *trap_ctx, struct netlink_ext_ack *extack) { struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
diff --git a/include/net/devlink.h b/include/net/devlink.h
index d387ea5518c3..b4897ee38209 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h@@ -110,6 +110,7 @@ struct devlink_port { struct delayed_work type_warn_dw; struct list_head reporter_list; struct mutex reporters_lock; /* Protects reporter_list */ + struct devlink_trap_mngr trap_mngr; }; struct devlink_sb_pool_info {
@@ -1108,6 +1109,7 @@ struct devlink_trap_ops { int (*trap_action_set)(struct devlink *devlink, const struct devlink_trap *trap, enum devlink_trap_action action, + void *trap_ctx, struct netlink_ext_ack *extack); /** * @trap_group_init: Trap group initialization function.
@@ -1414,6 +1416,29 @@ devlink_trap_policers_unregister(struct devlink *devlink, const struct devlink_trap_policer *policers, size_t policers_count); +void devlink_port_traps_ops(struct devlink_port *devlink_port, + const struct devlink_trap_ops *ops); +int devlink_port_traps_register(struct devlink_port *devlink_port, + const struct devlink_trap *traps, + size_t traps_count, void *priv); +void devlink_port_traps_unregister(struct devlink_port *devlink_port, + const struct devlink_trap *traps, + size_t traps_count); +void devlink_port_trap_report(struct devlink_port *devlink_port, struct sk_buff *skb, + void *trap_ctx, const struct flow_action_cookie *fa_cookie); +int devlink_port_trap_groups_register(struct devlink_port *devlink_port, + const struct devlink_trap_group *groups, + size_t groups_count); +void devlink_port_trap_groups_unregister(struct devlink_port *devlink_port, + const struct devlink_trap_group *groups, + size_t groups_count); +int devlink_port_trap_policers_register(struct devlink_port *devlink_port, + const struct devlink_trap_policer *policers, + size_t policers_count); +void devlink_port_trap_policers_unregister(struct devlink_port *devlink_port, + const struct devlink_trap_policer *policers, + size_t policers_count); + #if IS_ENABLED(CONFIG_NET_DEVLINK) void devlink_compat_running_version(struct net_device *dev,
diff --git a/net/core/devlink.c b/net/core/devlink.c
index a30b5444289b..b13e1b40bf1c 100644
--- a/net/core/devlink.c
+++ b/net/core/devlink.c@@ -6155,7 +6155,13 @@ struct devlink_trap_item { static struct devlink_trap_mngr * devlink_trap_get_trap_mngr_from_info(struct devlink *devlink, struct genl_info *info) { - return &devlink->trap_mngr; + struct devlink_port *devlink_port; + + devlink_port = devlink_port_get_from_attrs(devlink, info->attrs); + if (IS_ERR(devlink_port)) + return &devlink->trap_mngr; + else + return &devlink_port->trap_mngr; } static struct devlink_trap_policer_item *
@@ -6382,6 +6388,7 @@ static int devlink_nl_cmd_trap_get_dumpit(struct sk_buff *msg, { struct devlink_trap_mngr *trap_mngr; struct devlink_trap_item *trap_item; + struct devlink_port *port; struct devlink *devlink; int start = cb->args[0]; int idx = 0;
@@ -6411,6 +6418,30 @@ static int devlink_nl_cmd_trap_get_dumpit(struct sk_buff *msg, } mutex_unlock(&devlink->lock); } + list_for_each_entry(devlink, &devlink_list, list) { + if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) + continue; + list_for_each_entry(port, &devlink->port_list, list) { + trap_mngr = &port->trap_mngr; + mutex_lock(&devlink->lock); + list_for_each_entry(trap_item, &trap_mngr->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) + goto out; + idx++; + } + mutex_unlock(&devlink->lock); + } + } + out: mutex_unlock(&devlink_mutex);
@@ -6433,7 +6464,7 @@ static int __devlink_trap_action_set(struct devlink *devlink, } err = trap_mngr->trap_ops->trap_action_set(devlink, trap_item->trap, - trap_action, extack); + trap_action, trap_item, extack); if (err) return err;
@@ -6481,6 +6512,7 @@ static int devlink_nl_cmd_trap_set_doit(struct sk_buff *skb, NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap"); return -ENOENT; } + return devlink_trap_action_set(devlink, trap_mngr, trap_item, info); err = devlink_trap_action_set(devlink, trap_mngr, trap_item, info); if (err)
@@ -6614,6 +6646,7 @@ static int devlink_nl_cmd_trap_group_get_dumpit(struct sk_buff *msg, struct devlink_trap_group_item *group_item; u32 portid = NETLINK_CB(cb->skb).portid; struct devlink_trap_mngr *trap_mngr; + struct devlink_port *port; struct devlink *devlink; int start = cb->args[0]; int idx = 0;
@@ -6644,6 +6677,30 @@ static int devlink_nl_cmd_trap_group_get_dumpit(struct sk_buff *msg, } mutex_unlock(&devlink->lock); } + list_for_each_entry(devlink, &devlink_list, list) { + if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) + continue; + list_for_each_entry(port, &devlink->port_list, list) { + trap_mngr = &port->trap_mngr; + mutex_lock(&devlink->lock); + list_for_each_entry(group_item, &trap_mngr->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) + goto out; + idx++; + } + mutex_unlock(&devlink->lock); + } + } + out: mutex_unlock(&devlink_mutex);
@@ -6912,6 +6969,7 @@ static int devlink_nl_cmd_trap_policer_get_dumpit(struct sk_buff *msg, struct devlink_trap_policer_item *policer_item; u32 portid = NETLINK_CB(cb->skb).portid; struct devlink_trap_mngr *trap_mngr; + struct devlink_port *port; struct devlink *devlink; int start = cb->args[0]; int idx = 0;
@@ -6943,6 +7001,32 @@ static int devlink_nl_cmd_trap_policer_get_dumpit(struct sk_buff *msg, } mutex_unlock(&devlink->lock); } + list_for_each_entry(devlink, &devlink_list, list) { + if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) + continue; + list_for_each_entry(port, &devlink->port_list, list) { + trap_mngr = &port->trap_mngr; + mutex_lock(&devlink->lock); + list_for_each_entry(policer_item, &trap_mngr->trap_policer_list, + list) { + if (idx < start) { + idx++; + continue; + } + err = devlink_nl_trap_policer_fill(msg, devlink, + policer_item, cmd, + portid, + cb->nlh->nlmsg_seq, + trap_mngr, + NLM_F_MULTI); + if (err) + goto out; + idx++; + } + mutex_unlock(&devlink->lock); + } + } + out: mutex_unlock(&devlink_mutex);
@@ -7348,34 +7432,40 @@ static const struct genl_ops devlink_nl_ops[] = { .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_OR_PORT, /* 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_OR_PORT, }, { .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_OR_PORT, /* 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_OR_PORT, }, { .cmd = DEVLINK_CMD_TRAP_POLICER_GET, .doit = devlink_nl_cmd_trap_policer_get_doit, .dumpit = devlink_nl_cmd_trap_policer_get_dumpit, /* can be retrieved by unprivileged users */ + .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT, }, { .cmd = DEVLINK_CMD_TRAP_POLICER_SET, .doit = devlink_nl_cmd_trap_policer_set_doit, .flags = GENL_ADMIN_PERM, + .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT, }, };
@@ -7593,6 +7683,10 @@ int devlink_port_register(struct devlink *devlink, INIT_DELAYED_WORK(&devlink_port->type_warn_dw, &devlink_port_type_warn); devlink_port_type_warn_schedule(devlink_port); devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW); + INIT_LIST_HEAD(&devlink_port->trap_mngr.trap_list); + INIT_LIST_HEAD(&devlink_port->trap_mngr.trap_group_list); + INIT_LIST_HEAD(&devlink_port->trap_mngr.trap_policer_list); + return 0; } EXPORT_SYMBOL_GPL(devlink_port_register);
@@ -9084,7 +9178,8 @@ static void devlink_trap_disable(struct devlink *devlink, if (WARN_ON_ONCE(!trap_item)) return; - trap_mngr->trap_ops->trap_action_set(devlink, trap, DEVLINK_TRAP_ACTION_DROP, NULL); + trap_mngr->trap_ops->trap_action_set(devlink, trap, DEVLINK_TRAP_ACTION_DROP, + trap_item, NULL); trap_item->action = DEVLINK_TRAP_ACTION_DROP; }
@@ -9532,6 +9627,233 @@ devlink_trap_policers_unregister(struct devlink *devlink, } EXPORT_SYMBOL_GPL(devlink_trap_policers_unregister); +/** + * devlink_port_traps_ops - Register trap callbacks + * @devlink_port: devlink_port. + * @ops: trap ops + */ +void devlink_port_traps_ops(struct devlink_port *devlink_port, + const struct devlink_trap_ops *ops) +{ + devlink_port->trap_mngr.trap_ops = ops; +} +EXPORT_SYMBOL_GPL(devlink_port_traps_ops); + +/** + * devlink_port_traps_register - Register packet traps with devlink + * port. + * @devlink_port: devlink_port. + * @traps: Packet traps. + * @traps_count: Count of provided packet traps. + * @priv: Driver private information. + * + * Return: Non-zero value on failure. + */ +int devlink_port_traps_register(struct devlink_port *devlink_port, + const struct devlink_trap *traps, + size_t traps_count, void *priv) +{ + struct devlink_trap_mngr *trap_mngr = &devlink_port->trap_mngr; + struct devlink *devlink = devlink_port->devlink; + int i, err; + + if (!trap_mngr->trap_ops->trap_init || !trap_mngr->trap_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_mngr, 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, trap_mngr, &traps[i]); + mutex_unlock(&devlink->lock); + return err; +} +EXPORT_SYMBOL_GPL(devlink_port_traps_register); + +/** + * devlink_port_traps_unregister - Unregister packet traps from devlink_port. + * @devlink_port: devlink port. + * @traps: Packet traps. + * @traps_count: Count of provided packet traps. + */ +void devlink_port_traps_unregister(struct devlink_port *devlink_port, + const struct devlink_trap *traps, + size_t traps_count) +{ + struct devlink_trap_mngr *trap_mngr = &devlink_port->trap_mngr; + struct devlink *devlink = devlink_port->devlink; + 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, trap_mngr, &traps[i]); + synchronize_rcu(); + for (i = traps_count - 1; i >= 0; i--) + devlink_trap_unregister(devlink, trap_mngr, &traps[i]); + mutex_unlock(&devlink->lock); +} +EXPORT_SYMBOL_GPL(devlink_port_traps_unregister); + +/** + * devlink_port_trap_report - Report trapped packet to drop monitor. + * @devlink_port: devlink_port. + * @skb: Trapped packet. + * @trap_ctx: Trap context. + * @fa_cookie: Flow action cookie. Could be NULL. + */ +void devlink_port_trap_report(struct devlink_port *devlink_port, struct sk_buff *skb, + void *trap_ctx, const struct flow_action_cookie *fa_cookie) +{ + return devlink_trap_report(devlink_port->devlink, skb, trap_ctx, devlink_port, + fa_cookie); +} +EXPORT_SYMBOL_GPL(devlink_port_trap_report); + +/** + * devlink_port_trap_groups_register - Register packet trap groups with devlink port. + * @devlink_port: devlink_port. + * @groups: Packet trap groups. + * @groups_count: Count of provided packet trap groups. + * + * Return: Non-zero value on failure. + */ +int devlink_port_trap_groups_register(struct devlink_port *devlink_port, + const struct devlink_trap_group *groups, + size_t groups_count) +{ + struct devlink_trap_mngr *trap_mngr = &devlink_port->trap_mngr; + struct devlink *devlink = devlink_port->devlink; + int i, err; + + mutex_lock(&devlink->lock); + for (i = 0; i < groups_count; i++) { + const struct devlink_trap_group *group = &groups[i]; + + err = devlink_trap_group_verify(group); + if (err) + goto err_trap_group_verify; + + err = devlink_trap_group_register(devlink, trap_mngr, group); + if (err) + goto err_trap_group_register; + } + mutex_unlock(&devlink->lock); + + return 0; + +err_trap_group_register: +err_trap_group_verify: + for (i--; i >= 0; i--) + devlink_trap_group_unregister(devlink, trap_mngr, &groups[i]); + mutex_unlock(&devlink->lock); + return err; +} +EXPORT_SYMBOL_GPL(devlink_port_trap_groups_register); + +/** + * devlink_port_trap_groups_unregister - Unregister packet trap groups from devlink port. + * @devlink_port: devlink_port. + * @groups: Packet trap groups. + * @groups_count: Count of provided packet trap groups. + */ +void devlink_port_trap_groups_unregister(struct devlink_port *devlink_port, + const struct devlink_trap_group *groups, + size_t groups_count) +{ + struct devlink_trap_mngr *trap_mngr = &devlink_port->trap_mngr; + struct devlink *devlink = devlink_port->devlink; + int i; + + mutex_lock(&devlink->lock); + for (i = groups_count - 1; i >= 0; i--) + devlink_trap_group_unregister(devlink, trap_mngr, &groups[i]); + mutex_unlock(&devlink->lock); +} +EXPORT_SYMBOL_GPL(devlink_port_trap_groups_unregister); + +/** + * devlink_port_trap_policers_register - Register packet trap policers with devlink port. + * @devlink_port: devlink_port. + * @policers: Packet trap policers. + * @policers_count: Count of provided packet trap policers. + * + * Return: Non-zero value on failure. + */ +int devlink_port_trap_policers_register(struct devlink_port *devlink_port, + const struct devlink_trap_policer *policers, + size_t policers_count) +{ + struct devlink_trap_mngr *trap_mngr = &devlink_port->devlink->trap_mngr; + struct devlink *devlink = devlink_port->devlink; + int i, err; + + mutex_lock(&devlink->lock); + for (i = 0; i < policers_count; i++) { + const struct devlink_trap_policer *policer = &policers[i]; + + if (WARN_ON(policer->id == 0 || + policer->max_rate < policer->min_rate || + policer->max_burst < policer->min_burst)) { + err = -EINVAL; + goto err_trap_policer_verify; + } + + err = devlink_trap_policer_register(devlink, trap_mngr, policer); + if (err) + goto err_trap_policer_register; + } + mutex_unlock(&devlink->lock); + + return 0; + +err_trap_policer_register: +err_trap_policer_verify: + for (i--; i >= 0; i--) + devlink_trap_policer_unregister(devlink, trap_mngr, &policers[i]); + mutex_unlock(&devlink->lock); + return err; +} +EXPORT_SYMBOL_GPL(devlink_port_trap_policers_register); + +/** + * devlink_port_trap_policers_unregister - Unregister packet trap policers from devlink_port + * @devlink_port: devlink_port. + * @policers: Packet trap policers. + * @policers_count: Count of provided packet trap policers. + */ +void devlink_port_trap_policers_unregister(struct devlink_port *devlink_port, + const struct devlink_trap_policer *policers, + size_t policers_count) +{ + struct devlink_trap_mngr *trap_mngr = &devlink_port->devlink->trap_mngr; + struct devlink *devlink = devlink_port->devlink; + int i; + + mutex_lock(&devlink->lock); + for (i = policers_count - 1; i >= 0; i--) + devlink_trap_policer_unregister(devlink, trap_mngr, &policers[i]); + mutex_unlock(&devlink->lock); +} +EXPORT_SYMBOL_GPL(devlink_port_trap_policers_unregister); + static void __devlink_compat_running_version(struct devlink *devlink, char *buf, size_t len) {
--
2.14.1