Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'devlink-instances-relationships'

Jiri Pirko says:

====================
expose devlink instances relationships

From: Jiri Pirko <jiri@nvidia.com>

Currently, the user can instantiate new SF using "devlink port add"
command. That creates an E-switch representor devlink port.

When user activates this SF, there is an auxiliary device created and
probed for it which leads to SF devlink instance creation.

There is 1:1 relationship between E-switch representor devlink port and
the SF auxiliary device devlink instance.

Also, for example in mlx5, one devlink instance is created for
PCI device and one is created for an auxiliary device that represents
the uplink port. The relation between these is invisible to the user.

Patches #1-#3 and #5 are small preparations.

Patch #4 adds netnsid attribute for nested devlink if that in a
different namespace.

Patch #5 is the main one in this set, introduces the relationship
tracking infrastructure later on used to track SFs, linecards and
devlink instance relationships with nested devlink instances.

Expose the relation to the user by introducing new netlink attribute
DEVLINK_PORT_FN_ATTR_DEVLINK which contains the devlink instance related
to devlink port function. This is done by patch #8.
Patch #9 implements this in mlx5 driver.

Patch #10 converts the linecard nested devlink handling to the newly
introduced rel infrastructure.

Patch #11 benefits from the rel infra and introduces possiblitily to
have relation between devlink instances.
Patch #12 implements this in mlx5 driver.

Examples:
$ devlink dev
pci/0000:08:00.0: nested_devlink auxiliary/mlx5_core.eth.0
pci/0000:08:00.1: nested_devlink auxiliary/mlx5_core.eth.1
auxiliary/mlx5_core.eth.1
auxiliary/mlx5_core.eth.0

$ devlink port add pci/0000:08:00.0 flavour pcisf pfnum 0 sfnum 106
pci/0000:08:00.0/32768: type eth netdev eth4 flavour pcisf controller 0 pfnum 0 sfnum 106 splittable false
function:
hw_addr 00:00:00:00:00:00 state inactive opstate detached roce enable
$ devlink port function set pci/0000:08:00.0/32768 state active
$ devlink port show pci/0000:08:00.0/32768
pci/0000:08:00.0/32768: type eth netdev eth4 flavour pcisf controller 0 pfnum 0 sfnum 106 splittable false
function:
hw_addr 00:00:00:00:00:00 state active opstate attached roce enable nested_devlink auxiliary/mlx5_core.sf.2

$ devlink port show pci/0000:08:00.0/32768
pci/0000:08:00.0/32768: type eth netdev eth4 flavour pcisf controller 0 pfnum 0 sfnum 106 splittable false
function:
hw_addr 00:00:00:00:00:00 state active opstate attached roce enable nested_devlink auxiliary/mlx5_core.sf.2 nested_devlink_netns ns1
====================

Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

+509 -60
-11
drivers/net/ethernet/mellanox/mlx5/core/devlink.c
··· 138 138 { 139 139 struct mlx5_core_dev *dev = devlink_priv(devlink); 140 140 struct pci_dev *pdev = dev->pdev; 141 - bool sf_dev_allocated; 142 141 int ret = 0; 143 142 144 143 if (mlx5_dev_is_lightweight(dev)) { ··· 145 146 return -EOPNOTSUPP; 146 147 mlx5_unload_one_light(dev); 147 148 return 0; 148 - } 149 - 150 - sf_dev_allocated = mlx5_sf_dev_allocated(dev); 151 - if (sf_dev_allocated) { 152 - /* Reload results in deleting SF device which further results in 153 - * unregistering devlink instance while holding devlink_mutext. 154 - * Hence, do not support reload. 155 - */ 156 - NL_SET_ERR_MSG_MOD(extack, "reload is unsupported when SFs are allocated"); 157 - return -EOPNOTSUPP; 158 149 } 159 150 160 151 if (mlx5_lag_is_active(dev)) {
+8
drivers/net/ethernet/mellanox/mlx5/core/en/devlink.c
··· 12 12 { 13 13 struct mlx5e_dev *mlx5e_dev; 14 14 struct devlink *devlink; 15 + int err; 15 16 16 17 devlink = devlink_alloc_ns(&mlx5e_devlink_ops, sizeof(*mlx5e_dev), 17 18 devlink_net(priv_to_devlink(mdev)), dev); 18 19 if (!devlink) 19 20 return ERR_PTR(-ENOMEM); 21 + 22 + err = devl_nested_devlink_set(priv_to_devlink(mdev), devlink); 23 + if (err) { 24 + devlink_free(devlink); 25 + return ERR_PTR(err); 26 + } 27 + 20 28 devlink_register(devlink); 21 29 return devlink_priv(devlink); 22 30 }
+1 -1
drivers/net/ethernet/mellanox/mlx5/core/main.c
··· 1405 1405 1406 1406 static void mlx5_unload(struct mlx5_core_dev *dev) 1407 1407 { 1408 + mlx5_eswitch_disable(dev->priv.eswitch); 1408 1409 mlx5_devlink_traps_unregister(priv_to_devlink(dev)); 1409 1410 mlx5_sf_dev_table_destroy(dev); 1410 - mlx5_eswitch_disable(dev->priv.eswitch); 1411 1411 mlx5_sriov_detach(dev); 1412 1412 mlx5_lag_remove_mdev(dev); 1413 1413 mlx5_ec_cleanup(dev);
+6
drivers/net/ethernet/mellanox/mlx5/core/sf/dev/dev.h
··· 19 19 u16 fn_id; 20 20 }; 21 21 22 + struct mlx5_sf_peer_devlink_event_ctx { 23 + u16 fn_id; 24 + struct devlink *devlink; 25 + int err; 26 + }; 27 + 22 28 void mlx5_sf_dev_table_create(struct mlx5_core_dev *dev); 23 29 void mlx5_sf_dev_table_destroy(struct mlx5_core_dev *dev); 24 30
+26
drivers/net/ethernet/mellanox/mlx5/core/sf/dev/driver.c
··· 8 8 #include "dev.h" 9 9 #include "devlink.h" 10 10 11 + static int mlx5_core_peer_devlink_set(struct mlx5_sf_dev *sf_dev, struct devlink *devlink) 12 + { 13 + struct mlx5_sf_peer_devlink_event_ctx event_ctx = { 14 + .fn_id = sf_dev->fn_id, 15 + .devlink = devlink, 16 + }; 17 + int ret; 18 + 19 + ret = mlx5_blocking_notifier_call_chain(sf_dev->parent_mdev, 20 + MLX5_DRIVER_EVENT_SF_PEER_DEVLINK, 21 + &event_ctx); 22 + return ret == NOTIFY_OK ? event_ctx.err : 0; 23 + } 24 + 11 25 static int mlx5_sf_dev_probe(struct auxiliary_device *adev, const struct auxiliary_device_id *id) 12 26 { 13 27 struct mlx5_sf_dev *sf_dev = container_of(adev, struct mlx5_sf_dev, adev); ··· 68 54 mlx5_core_warn(mdev, "mlx5_init_one err=%d\n", err); 69 55 goto init_one_err; 70 56 } 57 + 58 + err = mlx5_core_peer_devlink_set(sf_dev, devlink); 59 + if (err) { 60 + mlx5_core_warn(mdev, "mlx5_core_peer_devlink_set err=%d\n", err); 61 + goto peer_devlink_set_err; 62 + } 63 + 71 64 devlink_register(devlink); 72 65 return 0; 73 66 67 + peer_devlink_set_err: 68 + if (mlx5_dev_is_lightweight(sf_dev->mdev)) 69 + mlx5_uninit_one_light(sf_dev->mdev); 70 + else 71 + mlx5_uninit_one(sf_dev->mdev); 74 72 init_one_err: 75 73 iounmap(mdev->iseg); 76 74 remap_err:
+34
drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c
··· 28 28 struct mutex sf_state_lock; /* Serializes sf state among user cmds & vhca event handler. */ 29 29 struct notifier_block esw_nb; 30 30 struct notifier_block vhca_nb; 31 + struct notifier_block mdev_nb; 31 32 }; 32 33 33 34 static struct mlx5_sf * ··· 512 511 return 0; 513 512 } 514 513 514 + static int mlx5_sf_mdev_event(struct notifier_block *nb, unsigned long event, void *data) 515 + { 516 + struct mlx5_sf_table *table = container_of(nb, struct mlx5_sf_table, mdev_nb); 517 + struct mlx5_sf_peer_devlink_event_ctx *event_ctx = data; 518 + int ret = NOTIFY_DONE; 519 + struct mlx5_sf *sf; 520 + 521 + if (event != MLX5_DRIVER_EVENT_SF_PEER_DEVLINK) 522 + return NOTIFY_DONE; 523 + 524 + table = mlx5_sf_table_try_get(table->dev); 525 + if (!table) 526 + return NOTIFY_DONE; 527 + 528 + mutex_lock(&table->sf_state_lock); 529 + sf = mlx5_sf_lookup_by_function_id(table, event_ctx->fn_id); 530 + if (!sf) 531 + goto out; 532 + 533 + event_ctx->err = devl_port_fn_devlink_set(&sf->dl_port.dl_port, 534 + event_ctx->devlink); 535 + 536 + ret = NOTIFY_OK; 537 + out: 538 + mutex_unlock(&table->sf_state_lock); 539 + mlx5_sf_table_put(table); 540 + return ret; 541 + } 542 + 515 543 static bool mlx5_sf_table_supported(const struct mlx5_core_dev *dev) 516 544 { 517 545 return dev->priv.eswitch && MLX5_ESWITCH_MANAGER(dev) && ··· 574 544 if (err) 575 545 goto vhca_err; 576 546 547 + table->mdev_nb.notifier_call = mlx5_sf_mdev_event; 548 + mlx5_blocking_notifier_register(dev, &table->mdev_nb); 549 + 577 550 return 0; 578 551 579 552 vhca_err: ··· 595 562 if (!table) 596 563 return; 597 564 565 + mlx5_blocking_notifier_unregister(dev, &table->mdev_nb); 598 566 mlx5_vhca_event_notifier_unregister(table->dev, &table->vhca_nb); 599 567 mlx5_esw_event_notifier_unregister(dev->priv.eswitch, &table->esw_nb); 600 568 WARN_ON(refcount_read(&table->refcount));
+6 -3
drivers/net/ethernet/mellanox/mlxsw/core_linecard_dev.c
··· 132 132 struct mlxsw_linecard *linecard = linecard_bdev->linecard; 133 133 struct mlxsw_linecard_dev *linecard_dev; 134 134 struct devlink *devlink; 135 + int err; 135 136 136 137 devlink = devlink_alloc(&mlxsw_linecard_dev_devlink_ops, 137 138 sizeof(*linecard_dev), &adev->dev); ··· 142 141 linecard_dev->linecard = linecard_bdev->linecard; 143 142 linecard_bdev->linecard_dev = linecard_dev; 144 143 144 + err = devlink_linecard_nested_dl_set(linecard->devlink_linecard, devlink); 145 + if (err) { 146 + devlink_free(devlink); 147 + return err; 148 + } 145 149 devlink_register(devlink); 146 - devlink_linecard_nested_dl_set(linecard->devlink_linecard, devlink); 147 150 return 0; 148 151 } 149 152 ··· 156 151 struct mlxsw_linecard_bdev *linecard_bdev = 157 152 container_of(adev, struct mlxsw_linecard_bdev, adev); 158 153 struct devlink *devlink = priv_to_devlink(linecard_bdev->linecard_dev); 159 - struct mlxsw_linecard *linecard = linecard_bdev->linecard; 160 154 161 - devlink_linecard_nested_dl_set(linecard->devlink_linecard, NULL); 162 155 devlink_unregister(devlink); 163 156 devlink_free(devlink); 164 157 }
+1
include/linux/mlx5/device.h
··· 366 366 MLX5_DRIVER_EVENT_UPLINK_NETDEV, 367 367 MLX5_DRIVER_EVENT_MACSEC_SA_ADDED, 368 368 MLX5_DRIVER_EVENT_MACSEC_SA_DELETED, 369 + MLX5_DRIVER_EVENT_SF_PEER_DEVLINK, 369 370 }; 370 371 371 372 enum {
+7 -2
include/net/devlink.h
··· 150 150 151 151 struct devlink_rate *devlink_rate; 152 152 struct devlink_linecard *linecard; 153 + u32 rel_index; 153 154 }; 154 155 155 156 struct devlink_port_new_attrs { ··· 1698 1697 void devlink_port_attrs_pci_sf_set(struct devlink_port *devlink_port, 1699 1698 u32 controller, u16 pf, u32 sf, 1700 1699 bool external); 1700 + int devl_port_fn_devlink_set(struct devlink_port *devlink_port, 1701 + struct devlink *fn_devlink); 1701 1702 struct devlink_rate * 1702 1703 devl_rate_node_create(struct devlink *devlink, void *priv, char *node_name, 1703 1704 struct devlink_rate *parent); ··· 1720 1717 void devlink_linecard_provision_fail(struct devlink_linecard *linecard); 1721 1718 void devlink_linecard_activate(struct devlink_linecard *linecard); 1722 1719 void devlink_linecard_deactivate(struct devlink_linecard *linecard); 1723 - void devlink_linecard_nested_dl_set(struct devlink_linecard *linecard, 1724 - struct devlink *nested_devlink); 1720 + int devlink_linecard_nested_dl_set(struct devlink_linecard *linecard, 1721 + struct devlink *nested_devlink); 1725 1722 int devl_sb_register(struct devlink *devlink, unsigned int sb_index, 1726 1723 u32 size, u16 ingress_pools_count, 1727 1724 u16 egress_pools_count, u16 ingress_tc_count, ··· 1921 1918 void 1922 1919 devlink_health_reporter_recovery_done(struct devlink_health_reporter *reporter); 1923 1920 1921 + int devl_nested_devlink_set(struct devlink *devlink, 1922 + struct devlink *nested_devlink); 1924 1923 bool devlink_is_reload_failed(const struct devlink *devlink); 1925 1924 void devlink_remote_reload_actions_performed(struct devlink *devlink, 1926 1925 enum devlink_reload_limit limit,
+1
include/uapi/linux/devlink.h
··· 680 680 DEVLINK_PORT_FN_ATTR_STATE, /* u8 */ 681 681 DEVLINK_PORT_FN_ATTR_OPSTATE, /* u8 */ 682 682 DEVLINK_PORT_FN_ATTR_CAPS, /* bitfield32 */ 683 + DEVLINK_PORT_FN_ATTR_DEVLINK, /* nested */ 683 684 684 685 __DEVLINK_PORT_FUNCTION_ATTR_MAX, 685 686 DEVLINK_PORT_FUNCTION_ATTR_MAX = __DEVLINK_PORT_FUNCTION_ATTR_MAX - 1
+217
net/devlink/core.c
··· 16 16 17 17 DEFINE_XARRAY_FLAGS(devlinks, XA_FLAGS_ALLOC); 18 18 19 + static struct devlink *devlinks_xa_get(unsigned long index) 20 + { 21 + struct devlink *devlink; 22 + 23 + rcu_read_lock(); 24 + devlink = xa_find(&devlinks, &index, index, DEVLINK_REGISTERED); 25 + if (!devlink || !devlink_try_get(devlink)) 26 + devlink = NULL; 27 + rcu_read_unlock(); 28 + return devlink; 29 + } 30 + 31 + /* devlink_rels xarray contains 1:1 relationships between 32 + * devlink object and related nested devlink instance. 33 + * The xarray index is used to get the nested object from 34 + * the nested-in object code. 35 + */ 36 + static DEFINE_XARRAY_FLAGS(devlink_rels, XA_FLAGS_ALLOC1); 37 + 38 + #define DEVLINK_REL_IN_USE XA_MARK_0 39 + 40 + struct devlink_rel { 41 + u32 index; 42 + refcount_t refcount; 43 + u32 devlink_index; 44 + struct { 45 + u32 devlink_index; 46 + u32 obj_index; 47 + devlink_rel_notify_cb_t *notify_cb; 48 + devlink_rel_cleanup_cb_t *cleanup_cb; 49 + struct work_struct notify_work; 50 + } nested_in; 51 + }; 52 + 53 + static void devlink_rel_free(struct devlink_rel *rel) 54 + { 55 + xa_erase(&devlink_rels, rel->index); 56 + kfree(rel); 57 + } 58 + 59 + static void __devlink_rel_get(struct devlink_rel *rel) 60 + { 61 + refcount_inc(&rel->refcount); 62 + } 63 + 64 + static void __devlink_rel_put(struct devlink_rel *rel) 65 + { 66 + if (refcount_dec_and_test(&rel->refcount)) 67 + devlink_rel_free(rel); 68 + } 69 + 70 + static void devlink_rel_nested_in_notify_work(struct work_struct *work) 71 + { 72 + struct devlink_rel *rel = container_of(work, struct devlink_rel, 73 + nested_in.notify_work); 74 + struct devlink *devlink; 75 + 76 + devlink = devlinks_xa_get(rel->nested_in.devlink_index); 77 + if (!devlink) 78 + goto rel_put; 79 + if (!devl_trylock(devlink)) { 80 + devlink_put(devlink); 81 + goto reschedule_work; 82 + } 83 + if (!devl_is_registered(devlink)) { 84 + devl_unlock(devlink); 85 + devlink_put(devlink); 86 + goto rel_put; 87 + } 88 + if (!xa_get_mark(&devlink_rels, rel->index, DEVLINK_REL_IN_USE)) 89 + rel->nested_in.cleanup_cb(devlink, rel->nested_in.obj_index, rel->index); 90 + rel->nested_in.notify_cb(devlink, rel->nested_in.obj_index); 91 + devl_unlock(devlink); 92 + devlink_put(devlink); 93 + 94 + rel_put: 95 + __devlink_rel_put(rel); 96 + return; 97 + 98 + reschedule_work: 99 + schedule_work(&rel->nested_in.notify_work); 100 + } 101 + 102 + static void devlink_rel_nested_in_notify_work_schedule(struct devlink_rel *rel) 103 + { 104 + __devlink_rel_get(rel); 105 + schedule_work(&rel->nested_in.notify_work); 106 + } 107 + 108 + static struct devlink_rel *devlink_rel_alloc(void) 109 + { 110 + struct devlink_rel *rel; 111 + static u32 next; 112 + int err; 113 + 114 + rel = kzalloc(sizeof(*rel), GFP_KERNEL); 115 + if (!rel) 116 + return ERR_PTR(-ENOMEM); 117 + 118 + err = xa_alloc_cyclic(&devlink_rels, &rel->index, rel, 119 + xa_limit_32b, &next, GFP_KERNEL); 120 + if (err) { 121 + kfree(rel); 122 + return ERR_PTR(err); 123 + } 124 + 125 + refcount_set(&rel->refcount, 1); 126 + INIT_WORK(&rel->nested_in.notify_work, 127 + &devlink_rel_nested_in_notify_work); 128 + return rel; 129 + } 130 + 131 + static void devlink_rel_put(struct devlink *devlink) 132 + { 133 + struct devlink_rel *rel = devlink->rel; 134 + 135 + if (!rel) 136 + return; 137 + xa_clear_mark(&devlink_rels, rel->index, DEVLINK_REL_IN_USE); 138 + devlink_rel_nested_in_notify_work_schedule(rel); 139 + __devlink_rel_put(rel); 140 + devlink->rel = NULL; 141 + } 142 + 143 + void devlink_rel_nested_in_clear(u32 rel_index) 144 + { 145 + xa_clear_mark(&devlink_rels, rel_index, DEVLINK_REL_IN_USE); 146 + } 147 + 148 + int devlink_rel_nested_in_add(u32 *rel_index, u32 devlink_index, 149 + u32 obj_index, devlink_rel_notify_cb_t *notify_cb, 150 + devlink_rel_cleanup_cb_t *cleanup_cb, 151 + struct devlink *devlink) 152 + { 153 + struct devlink_rel *rel = devlink_rel_alloc(); 154 + 155 + ASSERT_DEVLINK_NOT_REGISTERED(devlink); 156 + 157 + if (IS_ERR(rel)) 158 + return PTR_ERR(rel); 159 + 160 + rel->devlink_index = devlink->index; 161 + rel->nested_in.devlink_index = devlink_index; 162 + rel->nested_in.obj_index = obj_index; 163 + rel->nested_in.notify_cb = notify_cb; 164 + rel->nested_in.cleanup_cb = cleanup_cb; 165 + *rel_index = rel->index; 166 + xa_set_mark(&devlink_rels, rel->index, DEVLINK_REL_IN_USE); 167 + devlink->rel = rel; 168 + return 0; 169 + } 170 + 171 + void devlink_rel_nested_in_notify(struct devlink *devlink) 172 + { 173 + struct devlink_rel *rel = devlink->rel; 174 + 175 + if (!rel) 176 + return; 177 + devlink_rel_nested_in_notify_work_schedule(rel); 178 + } 179 + 180 + static struct devlink_rel *devlink_rel_find(unsigned long rel_index) 181 + { 182 + return xa_find(&devlink_rels, &rel_index, rel_index, 183 + DEVLINK_REL_IN_USE); 184 + } 185 + 186 + static struct devlink *devlink_rel_devlink_get_lock(u32 rel_index) 187 + { 188 + struct devlink *devlink; 189 + struct devlink_rel *rel; 190 + u32 devlink_index; 191 + 192 + if (!rel_index) 193 + return NULL; 194 + xa_lock(&devlink_rels); 195 + rel = devlink_rel_find(rel_index); 196 + if (rel) 197 + devlink_index = rel->devlink_index; 198 + xa_unlock(&devlink_rels); 199 + if (!rel) 200 + return NULL; 201 + devlink = devlinks_xa_get(devlink_index); 202 + if (!devlink) 203 + return NULL; 204 + devl_lock(devlink); 205 + if (!devl_is_registered(devlink)) { 206 + devl_unlock(devlink); 207 + devlink_put(devlink); 208 + return NULL; 209 + } 210 + return devlink; 211 + } 212 + 213 + int devlink_rel_devlink_handle_put(struct sk_buff *msg, struct devlink *devlink, 214 + u32 rel_index, int attrtype, 215 + bool *msg_updated) 216 + { 217 + struct net *net = devlink_net(devlink); 218 + struct devlink *rel_devlink; 219 + int err; 220 + 221 + rel_devlink = devlink_rel_devlink_get_lock(rel_index); 222 + if (!rel_devlink) 223 + return 0; 224 + err = devlink_nl_put_nested_handle(msg, net, rel_devlink, attrtype); 225 + devl_unlock(rel_devlink); 226 + devlink_put(rel_devlink); 227 + if (!err && msg_updated) 228 + *msg_updated = true; 229 + return err; 230 + } 231 + 19 232 void *devlink_priv(struct devlink *devlink) 20 233 { 21 234 return &devlink->priv; ··· 355 142 356 143 xa_set_mark(&devlinks, devlink->index, DEVLINK_REGISTERED); 357 144 devlink_notify_register(devlink); 145 + devlink_rel_nested_in_notify(devlink); 358 146 359 147 return 0; 360 148 } ··· 380 166 381 167 devlink_notify_unregister(devlink); 382 168 xa_clear_mark(&devlinks, devlink->index, DEVLINK_REGISTERED); 169 + devlink_rel_put(devlink); 383 170 } 384 171 EXPORT_SYMBOL_GPL(devl_unregister); 385 172 ··· 430 215 xa_init_flags(&devlink->ports, XA_FLAGS_ALLOC); 431 216 xa_init_flags(&devlink->params, XA_FLAGS_ALLOC); 432 217 xa_init_flags(&devlink->snapshot_ids, XA_FLAGS_ALLOC); 218 + xa_init_flags(&devlink->nested_rels, XA_FLAGS_ALLOC); 433 219 write_pnet(&devlink->_net, net); 434 220 INIT_LIST_HEAD(&devlink->rate_list); 435 221 INIT_LIST_HEAD(&devlink->linecard_list); ··· 477 261 WARN_ON(!list_empty(&devlink->linecard_list)); 478 262 WARN_ON(!xa_empty(&devlink->ports)); 479 263 264 + xa_destroy(&devlink->nested_rels); 480 265 xa_destroy(&devlink->snapshot_ids); 481 266 xa_destroy(&devlink->params); 482 267 xa_destroy(&devlink->ports);
+50
net/devlink/dev.c
··· 138 138 return -EMSGSIZE; 139 139 } 140 140 141 + static int devlink_nl_nested_fill(struct sk_buff *msg, struct devlink *devlink) 142 + { 143 + unsigned long rel_index; 144 + void *unused; 145 + int err; 146 + 147 + xa_for_each(&devlink->nested_rels, rel_index, unused) { 148 + err = devlink_rel_devlink_handle_put(msg, devlink, 149 + rel_index, 150 + DEVLINK_ATTR_NESTED_DEVLINK, 151 + NULL); 152 + if (err) 153 + return err; 154 + } 155 + return 0; 156 + } 157 + 141 158 static int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink, 142 159 enum devlink_command cmd, u32 portid, 143 160 u32 seq, int flags) ··· 181 164 goto dev_stats_nest_cancel; 182 165 183 166 nla_nest_end(msg, dev_stats); 167 + 168 + if (devlink_nl_nested_fill(msg, devlink)) 169 + goto nla_put_failure; 170 + 184 171 genlmsg_end(msg, hdr); 185 172 return 0; 186 173 ··· 250 229 { 251 230 return devlink_nl_dumpit(msg, cb, devlink_nl_get_dump_one); 252 231 } 232 + 233 + static void devlink_rel_notify_cb(struct devlink *devlink, u32 obj_index) 234 + { 235 + devlink_notify(devlink, DEVLINK_CMD_NEW); 236 + } 237 + 238 + static void devlink_rel_cleanup_cb(struct devlink *devlink, u32 obj_index, 239 + u32 rel_index) 240 + { 241 + xa_erase(&devlink->nested_rels, rel_index); 242 + } 243 + 244 + int devl_nested_devlink_set(struct devlink *devlink, 245 + struct devlink *nested_devlink) 246 + { 247 + u32 rel_index; 248 + int err; 249 + 250 + err = devlink_rel_nested_in_add(&rel_index, devlink->index, 0, 251 + devlink_rel_notify_cb, 252 + devlink_rel_cleanup_cb, 253 + nested_devlink); 254 + if (err) 255 + return err; 256 + return xa_insert(&devlink->nested_rels, rel_index, 257 + xa_mk_value(0), GFP_KERNEL); 258 + } 259 + EXPORT_SYMBOL_GPL(devl_nested_devlink_set); 253 260 254 261 void devlink_notify_register(struct devlink *devlink) 255 262 { ··· 421 372 devlink_notify_unregister(devlink); 422 373 write_pnet(&devlink->_net, dest_net); 423 374 devlink_notify_register(devlink); 375 + devlink_rel_nested_in_notify(devlink); 424 376 } 425 377 426 378 int devlink_reload(struct devlink *devlink, struct net *dest_net,
+21 -13
net/devlink/devl_internal.h
··· 17 17 18 18 #include "netlink_gen.h" 19 19 20 + struct devlink_rel; 21 + 20 22 #define DEVLINK_REGISTERED XA_MARK_1 21 23 22 24 #define DEVLINK_RELOAD_STATS_ARRAY_SIZE \ ··· 57 55 u8 reload_failed:1; 58 56 refcount_t refcount; 59 57 struct rcu_work rwork; 58 + struct devlink_rel *rel; 59 + struct xarray nested_rels; 60 60 char priv[] __aligned(NETDEV_ALIGN); 61 61 }; 62 62 ··· 95 91 devl_assert_locked(devlink); 96 92 return xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED); 97 93 } 94 + 95 + typedef void devlink_rel_notify_cb_t(struct devlink *devlink, u32 obj_index); 96 + typedef void devlink_rel_cleanup_cb_t(struct devlink *devlink, u32 obj_index, 97 + u32 rel_index); 98 + 99 + void devlink_rel_nested_in_clear(u32 rel_index); 100 + int devlink_rel_nested_in_add(u32 *rel_index, u32 devlink_index, 101 + u32 obj_index, devlink_rel_notify_cb_t *notify_cb, 102 + devlink_rel_cleanup_cb_t *cleanup_cb, 103 + struct devlink *devlink); 104 + void devlink_rel_nested_in_notify(struct devlink *devlink); 105 + int devlink_rel_devlink_handle_put(struct sk_buff *msg, struct devlink *devlink, 106 + u32 rel_index, int attrtype, 107 + bool *msg_updated); 98 108 99 109 /* Netlink */ 100 110 #define DEVLINK_NL_FLAG_NEED_PORT BIT(0) ··· 163 145 return 0; 164 146 } 165 147 148 + int devlink_nl_put_nested_handle(struct sk_buff *msg, struct net *net, 149 + struct devlink *devlink, int attrtype); 166 150 int devlink_nl_msg_reply_and_new(struct sk_buff **msg, struct genl_info *info); 167 151 168 152 /* Notify */ ··· 226 206 struct netlink_ext_ack *extack); 227 207 228 208 /* Linecards */ 229 - struct devlink_linecard { 230 - struct list_head list; 231 - struct devlink *devlink; 232 - unsigned int index; 233 - const struct devlink_linecard_ops *ops; 234 - void *priv; 235 - enum devlink_linecard_state state; 236 - struct mutex state_lock; /* Protects state */ 237 - const char *type; 238 - struct devlink_linecard_type *types; 239 - unsigned int types_count; 240 - struct devlink *nested_devlink; 241 - }; 209 + unsigned int devlink_linecard_index(struct devlink_linecard *linecard); 242 210 243 211 /* Devlink nl cmds */ 244 212 int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info);
+52 -28
net/devlink/linecard.c
··· 6 6 7 7 #include "devl_internal.h" 8 8 9 + struct devlink_linecard { 10 + struct list_head list; 11 + struct devlink *devlink; 12 + unsigned int index; 13 + const struct devlink_linecard_ops *ops; 14 + void *priv; 15 + enum devlink_linecard_state state; 16 + struct mutex state_lock; /* Protects state */ 17 + const char *type; 18 + struct devlink_linecard_type *types; 19 + unsigned int types_count; 20 + u32 rel_index; 21 + }; 22 + 23 + unsigned int devlink_linecard_index(struct devlink_linecard *linecard) 24 + { 25 + return linecard->index; 26 + } 27 + 9 28 static struct devlink_linecard * 10 29 devlink_linecard_get_by_index(struct devlink *devlink, 11 30 unsigned int linecard_index) ··· 63 44 devlink_linecard_get_from_info(struct devlink *devlink, struct genl_info *info) 64 45 { 65 46 return devlink_linecard_get_from_attrs(devlink, info->attrs); 66 - } 67 - 68 - static int devlink_nl_put_nested_handle(struct sk_buff *msg, struct devlink *devlink) 69 - { 70 - struct nlattr *nested_attr; 71 - 72 - nested_attr = nla_nest_start(msg, DEVLINK_ATTR_NESTED_DEVLINK); 73 - if (!nested_attr) 74 - return -EMSGSIZE; 75 - if (devlink_nl_put_handle(msg, devlink)) 76 - goto nla_put_failure; 77 - 78 - nla_nest_end(msg, nested_attr); 79 - return 0; 80 - 81 - nla_put_failure: 82 - nla_nest_cancel(msg, nested_attr); 83 - return -EMSGSIZE; 84 47 } 85 48 86 49 struct devlink_linecard_type { ··· 112 111 nla_nest_end(msg, attr); 113 112 } 114 113 115 - if (linecard->nested_devlink && 116 - devlink_nl_put_nested_handle(msg, linecard->nested_devlink)) 114 + if (devlink_rel_devlink_handle_put(msg, devlink, 115 + linecard->rel_index, 116 + DEVLINK_ATTR_NESTED_DEVLINK, 117 + NULL)) 117 118 goto nla_put_failure; 118 119 119 120 genlmsg_end(msg, hdr); ··· 524 521 void devlink_linecard_provision_clear(struct devlink_linecard *linecard) 525 522 { 526 523 mutex_lock(&linecard->state_lock); 527 - WARN_ON(linecard->nested_devlink); 528 524 linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED; 529 525 linecard->type = NULL; 530 526 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); ··· 542 540 void devlink_linecard_provision_fail(struct devlink_linecard *linecard) 543 541 { 544 542 mutex_lock(&linecard->state_lock); 545 - WARN_ON(linecard->nested_devlink); 546 543 linecard->state = DEVLINK_LINECARD_STATE_PROVISIONING_FAILED; 547 544 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); 548 545 mutex_unlock(&linecard->state_lock); ··· 589 588 } 590 589 EXPORT_SYMBOL_GPL(devlink_linecard_deactivate); 591 590 591 + static void devlink_linecard_rel_notify_cb(struct devlink *devlink, 592 + u32 linecard_index) 593 + { 594 + struct devlink_linecard *linecard; 595 + 596 + linecard = devlink_linecard_get_by_index(devlink, linecard_index); 597 + if (!linecard) 598 + return; 599 + devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); 600 + } 601 + 602 + static void devlink_linecard_rel_cleanup_cb(struct devlink *devlink, 603 + u32 linecard_index, u32 rel_index) 604 + { 605 + struct devlink_linecard *linecard; 606 + 607 + linecard = devlink_linecard_get_by_index(devlink, linecard_index); 608 + if (linecard && linecard->rel_index == rel_index) 609 + linecard->rel_index = 0; 610 + } 611 + 592 612 /** 593 613 * devlink_linecard_nested_dl_set - Attach/detach nested devlink 594 614 * instance to linecard. ··· 617 595 * @linecard: devlink linecard 618 596 * @nested_devlink: devlink instance to attach or NULL to detach 619 597 */ 620 - void devlink_linecard_nested_dl_set(struct devlink_linecard *linecard, 621 - struct devlink *nested_devlink) 598 + int devlink_linecard_nested_dl_set(struct devlink_linecard *linecard, 599 + struct devlink *nested_devlink) 622 600 { 623 - mutex_lock(&linecard->state_lock); 624 - linecard->nested_devlink = nested_devlink; 625 - devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); 626 - mutex_unlock(&linecard->state_lock); 601 + return devlink_rel_nested_in_add(&linecard->rel_index, 602 + linecard->devlink->index, 603 + linecard->index, 604 + devlink_linecard_rel_notify_cb, 605 + devlink_linecard_rel_cleanup_cb, 606 + nested_devlink); 627 607 } 628 608 EXPORT_SYMBOL_GPL(devlink_linecard_nested_dl_set);
+26
net/devlink/netlink.c
··· 82 82 [DEVLINK_ATTR_REGION_DIRECT] = { .type = NLA_FLAG }, 83 83 }; 84 84 85 + int devlink_nl_put_nested_handle(struct sk_buff *msg, struct net *net, 86 + struct devlink *devlink, int attrtype) 87 + { 88 + struct nlattr *nested_attr; 89 + 90 + nested_attr = nla_nest_start(msg, attrtype); 91 + if (!nested_attr) 92 + return -EMSGSIZE; 93 + if (devlink_nl_put_handle(msg, devlink)) 94 + goto nla_put_failure; 95 + if (!net_eq(net, devlink_net(devlink))) { 96 + int id = peernet2id_alloc(net, devlink_net(devlink), 97 + GFP_KERNEL); 98 + 99 + if (nla_put_s32(msg, DEVLINK_ATTR_NETNS_ID, id)) 100 + return -EMSGSIZE; 101 + } 102 + 103 + nla_nest_end(msg, nested_attr); 104 + return 0; 105 + 106 + nla_put_failure: 107 + nla_nest_cancel(msg, nested_attr); 108 + return -EMSGSIZE; 109 + } 110 + 85 111 int devlink_nl_msg_reply_and_new(struct sk_buff **msg, struct genl_info *info) 86 112 { 87 113 int err;
+53 -2
net/devlink/port.c
··· 428 428 if (err) 429 429 goto out; 430 430 err = devlink_port_fn_state_fill(port, msg, extack, &msg_updated); 431 + if (err) 432 + goto out; 433 + err = devlink_rel_devlink_handle_put(msg, port->devlink, 434 + port->rel_index, 435 + DEVLINK_PORT_FN_ATTR_DEVLINK, 436 + &msg_updated); 437 + 431 438 out: 432 439 if (err || !msg_updated) 433 440 nla_nest_cancel(msg, function_attr); ··· 490 483 goto nla_put_failure; 491 484 if (devlink_port->linecard && 492 485 nla_put_u32(msg, DEVLINK_ATTR_LINECARD_INDEX, 493 - devlink_port->linecard->index)) 486 + devlink_linecard_index(devlink_port->linecard))) 494 487 goto nla_put_failure; 495 488 496 489 genlmsg_end(msg, hdr); ··· 1399 1392 } 1400 1393 EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_sf_set); 1401 1394 1395 + static void devlink_port_rel_notify_cb(struct devlink *devlink, u32 port_index) 1396 + { 1397 + struct devlink_port *devlink_port; 1398 + 1399 + devlink_port = devlink_port_get_by_index(devlink, port_index); 1400 + if (!devlink_port) 1401 + return; 1402 + devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW); 1403 + } 1404 + 1405 + static void devlink_port_rel_cleanup_cb(struct devlink *devlink, u32 port_index, 1406 + u32 rel_index) 1407 + { 1408 + struct devlink_port *devlink_port; 1409 + 1410 + devlink_port = devlink_port_get_by_index(devlink, port_index); 1411 + if (devlink_port && devlink_port->rel_index == rel_index) 1412 + devlink_port->rel_index = 0; 1413 + } 1414 + 1415 + /** 1416 + * devl_port_fn_devlink_set - Attach peer devlink 1417 + * instance to port function. 1418 + * @devlink_port: devlink port 1419 + * @fn_devlink: devlink instance to attach 1420 + */ 1421 + int devl_port_fn_devlink_set(struct devlink_port *devlink_port, 1422 + struct devlink *fn_devlink) 1423 + { 1424 + ASSERT_DEVLINK_PORT_REGISTERED(devlink_port); 1425 + 1426 + if (WARN_ON(devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_PCI_SF || 1427 + devlink_port->attrs.pci_sf.external)) 1428 + return -EINVAL; 1429 + 1430 + return devlink_rel_nested_in_add(&devlink_port->rel_index, 1431 + devlink_port->devlink->index, 1432 + devlink_port->index, 1433 + devlink_port_rel_notify_cb, 1434 + devlink_port_rel_cleanup_cb, 1435 + fn_devlink); 1436 + } 1437 + EXPORT_SYMBOL_GPL(devl_port_fn_devlink_set); 1438 + 1402 1439 /** 1403 1440 * devlink_port_linecard_set - Link port with a linecard 1404 1441 * ··· 1471 1420 case DEVLINK_PORT_FLAVOUR_PHYSICAL: 1472 1421 if (devlink_port->linecard) 1473 1422 n = snprintf(name, len, "l%u", 1474 - devlink_port->linecard->index); 1423 + devlink_linecard_index(devlink_port->linecard)); 1475 1424 if (n < len) 1476 1425 n += snprintf(name + n, len - n, "p%u", 1477 1426 attrs->phys.port_number);