devlink: implement line card provisioning
In order to be able to configure all needed stuff on a port/netdevice of a line card without the line card being present, introduce line card provisioning. Basically by setting a type, provisioning process will start and driver is supposed to create a placeholder for instances (ports/netdevices) for a line card type. Allow the user to query the supported line card types over line card get command. Then implement two netlink command SET to allow user to set/unset the card type. On the driver API side, add provision/unprovision ops and supported types array to be advertised. Upon provision op call, the driver should take care of creating the instances for the particular line card type. Introduce provision_set/clear() functions to be called by the driver once the provisioning/unprovisioning is done on its side. These helpers are not to be called directly due to the async nature of provisioning. Example: $ devlink port # No ports are listed $ devlink lc pci/0000:01:00.0: lc 1 state unprovisioned supported_types: 16x100G lc 2 state unprovisioned supported_types: 16x100G lc 3 state unprovisioned supported_types: 16x100G lc 4 state unprovisioned supported_types: 16x100G lc 5 state unprovisioned supported_types: 16x100G lc 6 state unprovisioned supported_types: 16x100G lc 7 state unprovisioned supported_types: 16x100G lc 8 state unprovisioned supported_types: 16x100G $ devlink lc set pci/0000:01:00.0 lc 8 type 16x100G $ devlink lc show pci/0000:01:00.0 lc 8 pci/0000:01:00.0: lc 8 state active type 16x100G supported_types: 16x100G $ devlink port pci/0000:01:00.0/0: type notset flavour cpu port 0 splittable false pci/0000:01:00.0/53: type eth netdev enp1s0nl8p1 flavour physical lc 8 port 1 splittable true lanes 4 pci/0000:01:00.0/54: type eth netdev enp1s0nl8p2 flavour physical lc 8 port 2 splittable true lanes 4 pci/0000:01:00.0/55: type eth netdev enp1s0nl8p3 flavour physical lc 8 port 3 splittable true lanes 4 pci/0000:01:00.0/56: type eth netdev enp1s0nl8p4 flavour physical lc 8 port 4 splittable true lanes 4 pci/0000:01:00.0/57: type eth netdev enp1s0nl8p5 flavour physical lc 8 port 5 splittable true lanes 4 pci/0000:01:00.0/58: type eth netdev enp1s0nl8p6 flavour physical lc 8 port 6 splittable true lanes 4 pci/0000:01:00.0/59: type eth netdev enp1s0nl8p7 flavour physical lc 8 port 7 splittable true lanes 4 pci/0000:01:00.0/60: type eth netdev enp1s0nl8p8 flavour physical lc 8 port 8 splittable true lanes 4 pci/0000:01:00.0/61: type eth netdev enp1s0nl8p9 flavour physical lc 8 port 9 splittable true lanes 4 pci/0000:01:00.0/62: type eth netdev enp1s0nl8p10 flavour physical lc 8 port 10 splittable true lanes 4 pci/0000:01:00.0/63: type eth netdev enp1s0nl8p11 flavour physical lc 8 port 11 splittable true lanes 4 pci/0000:01:00.0/64: type eth netdev enp1s0nl8p12 flavour physical lc 8 port 12 splittable true lanes 4 pci/0000:01:00.0/125: type eth netdev enp1s0nl8p13 flavour physical lc 8 port 13 splittable true lanes 4 pci/0000:01:00.0/126: type eth netdev enp1s0nl8p14 flavour physical lc 8 port 14 splittable true lanes 4 pci/0000:01:00.0/127: type eth netdev enp1s0nl8p15 flavour physical lc 8 port 15 splittable true lanes 4 pci/0000:01:00.0/128: type eth netdev enp1s0nl8p16 flavour physical lc 8 port 16 splittable true lanes 4 $ devlink lc set pci/0000:01:00.0 lc 8 notype Signed-off-by: Jiri Pirko <jiri@nvidia.com> Signed-off-by: Ido Schimmel <idosch@nvidia.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
c246f9b5fd
Коммит
fcdc8ce23a
|
@ -0,0 +1,121 @@
|
||||||
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
=================
|
||||||
|
Devlink Line card
|
||||||
|
=================
|
||||||
|
|
||||||
|
Background
|
||||||
|
==========
|
||||||
|
|
||||||
|
The ``devlink-linecard`` mechanism is targeted for manipulation of
|
||||||
|
line cards that serve as a detachable PHY modules for modular switch
|
||||||
|
system. Following operations are provided:
|
||||||
|
|
||||||
|
* Get a list of supported line card types.
|
||||||
|
* Provision of a slot with specific line card type.
|
||||||
|
* Get and monitor of line card state and its change.
|
||||||
|
|
||||||
|
Line card according to the type may contain one or more gearboxes
|
||||||
|
to mux the lanes with certain speed to multiple ports with lanes
|
||||||
|
of different speed. Line card ensures N:M mapping between
|
||||||
|
the switch ASIC modules and physical front panel ports.
|
||||||
|
|
||||||
|
Overview
|
||||||
|
========
|
||||||
|
|
||||||
|
Each line card devlink object is created by device driver,
|
||||||
|
according to the physical line card slots available on the device.
|
||||||
|
|
||||||
|
Similar to splitter cable, where the device might have no way
|
||||||
|
of detection of the splitter cable geometry, the device
|
||||||
|
might not have a way to detect line card type. For that devices,
|
||||||
|
concept of provisioning is introduced. It allows the user to:
|
||||||
|
|
||||||
|
* Provision a line card slot with certain line card type
|
||||||
|
|
||||||
|
- Device driver would instruct the ASIC to prepare all
|
||||||
|
resources accordingly. The device driver would
|
||||||
|
create all instances, namely devlink port and netdevices
|
||||||
|
that reside on the line card, according to the line card type
|
||||||
|
* Manipulate of line card entities even without line card
|
||||||
|
being physically connected or powered-up
|
||||||
|
* Setup splitter cable on line card ports
|
||||||
|
|
||||||
|
- As on the ordinary ports, user may provision a splitter
|
||||||
|
cable of a certain type, without the need to
|
||||||
|
be physically connected to the port
|
||||||
|
* Configure devlink ports and netdevices
|
||||||
|
|
||||||
|
Netdevice carrier is decided as follows:
|
||||||
|
|
||||||
|
* Line card is not inserted or powered-down
|
||||||
|
|
||||||
|
- The carrier is always down
|
||||||
|
* Line card is inserted and powered up
|
||||||
|
|
||||||
|
- The carrier is decided as for ordinary port netdevice
|
||||||
|
|
||||||
|
Line card state
|
||||||
|
===============
|
||||||
|
|
||||||
|
The ``devlink-linecard`` mechanism supports the following line card states:
|
||||||
|
|
||||||
|
* ``unprovisioned``: Line card is not provisioned on the slot.
|
||||||
|
* ``unprovisioning``: Line card slot is currently being unprovisioned.
|
||||||
|
* ``provisioning``: Line card slot is currently in a process of being provisioned
|
||||||
|
with a line card type.
|
||||||
|
* ``provisioning_failed``: Provisioning was not successful.
|
||||||
|
* ``provisioned``: Line card slot is provisioned with a type.
|
||||||
|
|
||||||
|
The following diagram provides a general overview of ``devlink-linecard``
|
||||||
|
state transitions::
|
||||||
|
|
||||||
|
+-------------------------+
|
||||||
|
| |
|
||||||
|
+----------------------------------> unprovisioned |
|
||||||
|
| | |
|
||||||
|
| +--------|-------^--------+
|
||||||
|
| | |
|
||||||
|
| | |
|
||||||
|
| +--------v-------|--------+
|
||||||
|
| | |
|
||||||
|
| | provisioning |
|
||||||
|
| | |
|
||||||
|
| +------------|------------+
|
||||||
|
| |
|
||||||
|
| +-----------------------------+
|
||||||
|
| | |
|
||||||
|
| +------------v------------+ +------------v------------+
|
||||||
|
| | | | |
|
||||||
|
+----- provisioning_failed | | provisioned |
|
||||||
|
| | | | |
|
||||||
|
| +------------^------------+ +------------|------------+
|
||||||
|
| | |
|
||||||
|
| | |
|
||||||
|
| | +------------v------------+
|
||||||
|
| | | |
|
||||||
|
| | | unprovisioning |
|
||||||
|
| | | |
|
||||||
|
| | +------------|------------+
|
||||||
|
| | |
|
||||||
|
| +-----------------------------+
|
||||||
|
| |
|
||||||
|
+-----------------------------------------------+
|
||||||
|
|
||||||
|
|
||||||
|
Example usage
|
||||||
|
=============
|
||||||
|
|
||||||
|
.. code:: shell
|
||||||
|
|
||||||
|
$ devlink lc show [ DEV [ lc LC_INDEX ] ]
|
||||||
|
$ devlink lc set DEV lc LC_INDEX [ { type LC_TYPE | notype } ]
|
||||||
|
|
||||||
|
# Show current line card configuration and status for all slots:
|
||||||
|
$ devlink lc
|
||||||
|
|
||||||
|
# Set slot 8 to be provisioned with type "16x100G":
|
||||||
|
$ devlink lc set pci/0000:01:00.0 lc 8 type 16x100G
|
||||||
|
|
||||||
|
# Set slot 8 to be unprovisioned:
|
||||||
|
$ devlink lc set pci/0000:01:00.0 lc 8 notype
|
|
@ -39,6 +39,7 @@ general.
|
||||||
devlink-resource
|
devlink-resource
|
||||||
devlink-reload
|
devlink-reload
|
||||||
devlink-trap
|
devlink-trap
|
||||||
|
devlink-linecard
|
||||||
|
|
||||||
Driver-specific documentation
|
Driver-specific documentation
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
|
@ -149,6 +149,40 @@ struct devlink_port_new_attrs {
|
||||||
sfnum_valid:1;
|
sfnum_valid:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct devlink_linecard_ops - Linecard operations
|
||||||
|
* @provision: callback to provision the linecard slot with certain
|
||||||
|
* type of linecard. As a result of this operation,
|
||||||
|
* driver is expected to eventually (could be after
|
||||||
|
* the function call returns) call one of:
|
||||||
|
* devlink_linecard_provision_set()
|
||||||
|
* devlink_linecard_provision_fail()
|
||||||
|
* @unprovision: callback to unprovision the linecard slot. As a result
|
||||||
|
* of this operation, driver is expected to eventually
|
||||||
|
* (could be after the function call returns) call
|
||||||
|
* devlink_linecard_provision_clear()
|
||||||
|
* devlink_linecard_provision_fail()
|
||||||
|
* @same_provision: callback to ask the driver if linecard is already
|
||||||
|
* provisioned in the same way user asks this linecard to be
|
||||||
|
* provisioned.
|
||||||
|
* @types_count: callback to get number of supported types
|
||||||
|
* @types_get: callback to get next type in list
|
||||||
|
*/
|
||||||
|
struct devlink_linecard_ops {
|
||||||
|
int (*provision)(struct devlink_linecard *linecard, void *priv,
|
||||||
|
const char *type, const void *type_priv,
|
||||||
|
struct netlink_ext_ack *extack);
|
||||||
|
int (*unprovision)(struct devlink_linecard *linecard, void *priv,
|
||||||
|
struct netlink_ext_ack *extack);
|
||||||
|
bool (*same_provision)(struct devlink_linecard *linecard, void *priv,
|
||||||
|
const char *type, const void *type_priv);
|
||||||
|
unsigned int (*types_count)(struct devlink_linecard *linecard,
|
||||||
|
void *priv);
|
||||||
|
void (*types_get)(struct devlink_linecard *linecard,
|
||||||
|
void *priv, unsigned int index, const char **type,
|
||||||
|
const void **type_priv);
|
||||||
|
};
|
||||||
|
|
||||||
struct devlink_sb_pool_info {
|
struct devlink_sb_pool_info {
|
||||||
enum devlink_sb_pool_type pool_type;
|
enum devlink_sb_pool_type pool_type;
|
||||||
u32 size;
|
u32 size;
|
||||||
|
@ -1537,9 +1571,14 @@ void devlink_port_attrs_pci_sf_set(struct devlink_port *devlink_port,
|
||||||
int devlink_rate_leaf_create(struct devlink_port *port, void *priv);
|
int devlink_rate_leaf_create(struct devlink_port *port, void *priv);
|
||||||
void devlink_rate_leaf_destroy(struct devlink_port *devlink_port);
|
void devlink_rate_leaf_destroy(struct devlink_port *devlink_port);
|
||||||
void devlink_rate_nodes_destroy(struct devlink *devlink);
|
void devlink_rate_nodes_destroy(struct devlink *devlink);
|
||||||
struct devlink_linecard *devlink_linecard_create(struct devlink *devlink,
|
struct devlink_linecard *
|
||||||
unsigned int linecard_index);
|
devlink_linecard_create(struct devlink *devlink, unsigned int linecard_index,
|
||||||
|
const struct devlink_linecard_ops *ops, void *priv);
|
||||||
void devlink_linecard_destroy(struct devlink_linecard *linecard);
|
void devlink_linecard_destroy(struct devlink_linecard *linecard);
|
||||||
|
void devlink_linecard_provision_set(struct devlink_linecard *linecard,
|
||||||
|
const char *type);
|
||||||
|
void devlink_linecard_provision_clear(struct devlink_linecard *linecard);
|
||||||
|
void devlink_linecard_provision_fail(struct devlink_linecard *linecard);
|
||||||
int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
|
int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
|
||||||
u32 size, u16 ingress_pools_count,
|
u32 size, u16 ingress_pools_count,
|
||||||
u16 egress_pools_count, u16 ingress_tc_count,
|
u16 egress_pools_count, u16 ingress_tc_count,
|
||||||
|
|
|
@ -343,6 +343,18 @@ enum devlink_reload_limit {
|
||||||
|
|
||||||
#define DEVLINK_RELOAD_LIMITS_VALID_MASK (_BITUL(__DEVLINK_RELOAD_LIMIT_MAX) - 1)
|
#define DEVLINK_RELOAD_LIMITS_VALID_MASK (_BITUL(__DEVLINK_RELOAD_LIMIT_MAX) - 1)
|
||||||
|
|
||||||
|
enum devlink_linecard_state {
|
||||||
|
DEVLINK_LINECARD_STATE_UNSPEC,
|
||||||
|
DEVLINK_LINECARD_STATE_UNPROVISIONED,
|
||||||
|
DEVLINK_LINECARD_STATE_UNPROVISIONING,
|
||||||
|
DEVLINK_LINECARD_STATE_PROVISIONING,
|
||||||
|
DEVLINK_LINECARD_STATE_PROVISIONING_FAILED,
|
||||||
|
DEVLINK_LINECARD_STATE_PROVISIONED,
|
||||||
|
|
||||||
|
__DEVLINK_LINECARD_STATE_MAX,
|
||||||
|
DEVLINK_LINECARD_STATE_MAX = __DEVLINK_LINECARD_STATE_MAX - 1
|
||||||
|
};
|
||||||
|
|
||||||
enum devlink_attr {
|
enum devlink_attr {
|
||||||
/* don't change the order or add anything between, this is ABI! */
|
/* don't change the order or add anything between, this is ABI! */
|
||||||
DEVLINK_ATTR_UNSPEC,
|
DEVLINK_ATTR_UNSPEC,
|
||||||
|
@ -559,6 +571,9 @@ enum devlink_attr {
|
||||||
DEVLINK_ATTR_REGION_MAX_SNAPSHOTS, /* u32 */
|
DEVLINK_ATTR_REGION_MAX_SNAPSHOTS, /* u32 */
|
||||||
|
|
||||||
DEVLINK_ATTR_LINECARD_INDEX, /* u32 */
|
DEVLINK_ATTR_LINECARD_INDEX, /* u32 */
|
||||||
|
DEVLINK_ATTR_LINECARD_STATE, /* u8 */
|
||||||
|
DEVLINK_ATTR_LINECARD_TYPE, /* string */
|
||||||
|
DEVLINK_ATTR_LINECARD_SUPPORTED_TYPES, /* nested */
|
||||||
|
|
||||||
/* add new attributes above here, update the policy in devlink.c */
|
/* add new attributes above here, update the policy in devlink.c */
|
||||||
|
|
||||||
|
|
|
@ -72,11 +72,21 @@ struct devlink {
|
||||||
char priv[] __aligned(NETDEV_ALIGN);
|
char priv[] __aligned(NETDEV_ALIGN);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct devlink_linecard_ops;
|
||||||
|
struct devlink_linecard_type;
|
||||||
|
|
||||||
struct devlink_linecard {
|
struct devlink_linecard {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
struct devlink *devlink;
|
struct devlink *devlink;
|
||||||
unsigned int index;
|
unsigned int index;
|
||||||
refcount_t refcount;
|
refcount_t refcount;
|
||||||
|
const struct devlink_linecard_ops *ops;
|
||||||
|
void *priv;
|
||||||
|
enum devlink_linecard_state state;
|
||||||
|
struct mutex state_lock; /* Protects state */
|
||||||
|
const char *type;
|
||||||
|
struct devlink_linecard_type *types;
|
||||||
|
unsigned int types_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -452,8 +462,10 @@ devlink_linecard_get_from_info(struct devlink *devlink, struct genl_info *info)
|
||||||
|
|
||||||
static void devlink_linecard_put(struct devlink_linecard *linecard)
|
static void devlink_linecard_put(struct devlink_linecard *linecard)
|
||||||
{
|
{
|
||||||
if (refcount_dec_and_test(&linecard->refcount))
|
if (refcount_dec_and_test(&linecard->refcount)) {
|
||||||
|
mutex_destroy(&linecard->state_lock);
|
||||||
kfree(linecard);
|
kfree(linecard);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct devlink_sb {
|
struct devlink_sb {
|
||||||
|
@ -2037,6 +2049,11 @@ static int devlink_nl_cmd_rate_del_doit(struct sk_buff *skb,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct devlink_linecard_type {
|
||||||
|
const char *type;
|
||||||
|
const void *priv;
|
||||||
|
};
|
||||||
|
|
||||||
static int devlink_nl_linecard_fill(struct sk_buff *msg,
|
static int devlink_nl_linecard_fill(struct sk_buff *msg,
|
||||||
struct devlink *devlink,
|
struct devlink *devlink,
|
||||||
struct devlink_linecard *linecard,
|
struct devlink_linecard *linecard,
|
||||||
|
@ -2044,7 +2061,10 @@ static int devlink_nl_linecard_fill(struct sk_buff *msg,
|
||||||
u32 seq, int flags,
|
u32 seq, int flags,
|
||||||
struct netlink_ext_ack *extack)
|
struct netlink_ext_ack *extack)
|
||||||
{
|
{
|
||||||
|
struct devlink_linecard_type *linecard_type;
|
||||||
|
struct nlattr *attr;
|
||||||
void *hdr;
|
void *hdr;
|
||||||
|
int i;
|
||||||
|
|
||||||
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
|
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
|
||||||
if (!hdr)
|
if (!hdr)
|
||||||
|
@ -2054,6 +2074,27 @@ static int devlink_nl_linecard_fill(struct sk_buff *msg,
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
if (nla_put_u32(msg, DEVLINK_ATTR_LINECARD_INDEX, linecard->index))
|
if (nla_put_u32(msg, DEVLINK_ATTR_LINECARD_INDEX, linecard->index))
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
|
if (nla_put_u8(msg, DEVLINK_ATTR_LINECARD_STATE, linecard->state))
|
||||||
|
goto nla_put_failure;
|
||||||
|
if (linecard->type &&
|
||||||
|
nla_put_string(msg, DEVLINK_ATTR_LINECARD_TYPE, linecard->type))
|
||||||
|
goto nla_put_failure;
|
||||||
|
|
||||||
|
if (linecard->types_count) {
|
||||||
|
attr = nla_nest_start(msg,
|
||||||
|
DEVLINK_ATTR_LINECARD_SUPPORTED_TYPES);
|
||||||
|
if (!attr)
|
||||||
|
goto nla_put_failure;
|
||||||
|
for (i = 0; i < linecard->types_count; i++) {
|
||||||
|
linecard_type = &linecard->types[i];
|
||||||
|
if (nla_put_string(msg, DEVLINK_ATTR_LINECARD_TYPE,
|
||||||
|
linecard_type->type)) {
|
||||||
|
nla_nest_cancel(msg, attr);
|
||||||
|
goto nla_put_failure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nla_nest_end(msg, attr);
|
||||||
|
}
|
||||||
|
|
||||||
genlmsg_end(msg, hdr);
|
genlmsg_end(msg, hdr);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2103,10 +2144,12 @@ static int devlink_nl_cmd_linecard_get_doit(struct sk_buff *skb,
|
||||||
if (!msg)
|
if (!msg)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
mutex_lock(&linecard->state_lock);
|
||||||
err = devlink_nl_linecard_fill(msg, devlink, linecard,
|
err = devlink_nl_linecard_fill(msg, devlink, linecard,
|
||||||
DEVLINK_CMD_LINECARD_NEW,
|
DEVLINK_CMD_LINECARD_NEW,
|
||||||
info->snd_portid, info->snd_seq, 0,
|
info->snd_portid, info->snd_seq, 0,
|
||||||
info->extack);
|
info->extack);
|
||||||
|
mutex_unlock(&linecard->state_lock);
|
||||||
if (err) {
|
if (err) {
|
||||||
nlmsg_free(msg);
|
nlmsg_free(msg);
|
||||||
return err;
|
return err;
|
||||||
|
@ -2139,12 +2182,14 @@ static int devlink_nl_cmd_linecard_get_dumpit(struct sk_buff *msg,
|
||||||
idx++;
|
idx++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
mutex_lock(&linecard->state_lock);
|
||||||
err = devlink_nl_linecard_fill(msg, devlink, linecard,
|
err = devlink_nl_linecard_fill(msg, devlink, linecard,
|
||||||
DEVLINK_CMD_LINECARD_NEW,
|
DEVLINK_CMD_LINECARD_NEW,
|
||||||
NETLINK_CB(cb->skb).portid,
|
NETLINK_CB(cb->skb).portid,
|
||||||
cb->nlh->nlmsg_seq,
|
cb->nlh->nlmsg_seq,
|
||||||
NLM_F_MULTI,
|
NLM_F_MULTI,
|
||||||
cb->extack);
|
cb->extack);
|
||||||
|
mutex_unlock(&linecard->state_lock);
|
||||||
if (err) {
|
if (err) {
|
||||||
mutex_unlock(&devlink->linecards_lock);
|
mutex_unlock(&devlink->linecards_lock);
|
||||||
devlink_put(devlink);
|
devlink_put(devlink);
|
||||||
|
@ -2163,6 +2208,163 @@ out:
|
||||||
return msg->len;
|
return msg->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct devlink_linecard_type *
|
||||||
|
devlink_linecard_type_lookup(struct devlink_linecard *linecard,
|
||||||
|
const char *type)
|
||||||
|
{
|
||||||
|
struct devlink_linecard_type *linecard_type;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < linecard->types_count; i++) {
|
||||||
|
linecard_type = &linecard->types[i];
|
||||||
|
if (!strcmp(type, linecard_type->type))
|
||||||
|
return linecard_type;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int devlink_linecard_type_set(struct devlink_linecard *linecard,
|
||||||
|
const char *type,
|
||||||
|
struct netlink_ext_ack *extack)
|
||||||
|
{
|
||||||
|
const struct devlink_linecard_ops *ops = linecard->ops;
|
||||||
|
struct devlink_linecard_type *linecard_type;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
mutex_lock(&linecard->state_lock);
|
||||||
|
if (linecard->state == DEVLINK_LINECARD_STATE_PROVISIONING) {
|
||||||
|
NL_SET_ERR_MSG_MOD(extack, "Line card is currently being provisioned");
|
||||||
|
err = -EBUSY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONING) {
|
||||||
|
NL_SET_ERR_MSG_MOD(extack, "Line card is currently being unprovisioned");
|
||||||
|
err = -EBUSY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
linecard_type = devlink_linecard_type_lookup(linecard, type);
|
||||||
|
if (!linecard_type) {
|
||||||
|
NL_SET_ERR_MSG_MOD(extack, "Unsupported line card type provided");
|
||||||
|
err = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (linecard->state != DEVLINK_LINECARD_STATE_UNPROVISIONED &&
|
||||||
|
linecard->state != DEVLINK_LINECARD_STATE_PROVISIONING_FAILED) {
|
||||||
|
NL_SET_ERR_MSG_MOD(extack, "Line card already provisioned");
|
||||||
|
err = -EBUSY;
|
||||||
|
/* Check if the line card is provisioned in the same
|
||||||
|
* way the user asks. In case it is, make the operation
|
||||||
|
* to return success.
|
||||||
|
*/
|
||||||
|
if (ops->same_provision &&
|
||||||
|
ops->same_provision(linecard, linecard->priv,
|
||||||
|
linecard_type->type,
|
||||||
|
linecard_type->priv))
|
||||||
|
err = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
linecard->state = DEVLINK_LINECARD_STATE_PROVISIONING;
|
||||||
|
linecard->type = linecard_type->type;
|
||||||
|
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
|
||||||
|
mutex_unlock(&linecard->state_lock);
|
||||||
|
err = ops->provision(linecard, linecard->priv, linecard_type->type,
|
||||||
|
linecard_type->priv, extack);
|
||||||
|
if (err) {
|
||||||
|
/* Provisioning failed. Assume the linecard is unprovisioned
|
||||||
|
* for future operations.
|
||||||
|
*/
|
||||||
|
mutex_lock(&linecard->state_lock);
|
||||||
|
linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
|
||||||
|
linecard->type = NULL;
|
||||||
|
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
|
||||||
|
mutex_unlock(&linecard->state_lock);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
|
||||||
|
out:
|
||||||
|
mutex_unlock(&linecard->state_lock);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int devlink_linecard_type_unset(struct devlink_linecard *linecard,
|
||||||
|
struct netlink_ext_ack *extack)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
mutex_lock(&linecard->state_lock);
|
||||||
|
if (linecard->state == DEVLINK_LINECARD_STATE_PROVISIONING) {
|
||||||
|
NL_SET_ERR_MSG_MOD(extack, "Line card is currently being provisioned");
|
||||||
|
err = -EBUSY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONING) {
|
||||||
|
NL_SET_ERR_MSG_MOD(extack, "Line card is currently being unprovisioned");
|
||||||
|
err = -EBUSY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (linecard->state == DEVLINK_LINECARD_STATE_PROVISIONING_FAILED) {
|
||||||
|
linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
|
||||||
|
linecard->type = NULL;
|
||||||
|
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
|
||||||
|
err = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONED) {
|
||||||
|
NL_SET_ERR_MSG_MOD(extack, "Line card is not provisioned");
|
||||||
|
err = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONING;
|
||||||
|
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
|
||||||
|
mutex_unlock(&linecard->state_lock);
|
||||||
|
err = linecard->ops->unprovision(linecard, linecard->priv,
|
||||||
|
extack);
|
||||||
|
if (err) {
|
||||||
|
/* Unprovisioning failed. Assume the linecard is unprovisioned
|
||||||
|
* for future operations.
|
||||||
|
*/
|
||||||
|
mutex_lock(&linecard->state_lock);
|
||||||
|
linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
|
||||||
|
linecard->type = NULL;
|
||||||
|
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
|
||||||
|
mutex_unlock(&linecard->state_lock);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
|
||||||
|
out:
|
||||||
|
mutex_unlock(&linecard->state_lock);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int devlink_nl_cmd_linecard_set_doit(struct sk_buff *skb,
|
||||||
|
struct genl_info *info)
|
||||||
|
{
|
||||||
|
struct devlink_linecard *linecard = info->user_ptr[1];
|
||||||
|
struct netlink_ext_ack *extack = info->extack;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (info->attrs[DEVLINK_ATTR_LINECARD_TYPE]) {
|
||||||
|
const char *type;
|
||||||
|
|
||||||
|
type = nla_data(info->attrs[DEVLINK_ATTR_LINECARD_TYPE]);
|
||||||
|
if (strcmp(type, "")) {
|
||||||
|
err = devlink_linecard_type_set(linecard, type, extack);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
} else {
|
||||||
|
err = devlink_linecard_type_unset(linecard, extack);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink,
|
static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink,
|
||||||
struct devlink_sb *devlink_sb,
|
struct devlink_sb *devlink_sb,
|
||||||
enum devlink_command cmd, u32 portid,
|
enum devlink_command cmd, u32 portid,
|
||||||
|
@ -8789,6 +8991,7 @@ static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
|
||||||
[DEVLINK_ATTR_RATE_NODE_NAME] = { .type = NLA_NUL_STRING },
|
[DEVLINK_ATTR_RATE_NODE_NAME] = { .type = NLA_NUL_STRING },
|
||||||
[DEVLINK_ATTR_RATE_PARENT_NODE_NAME] = { .type = NLA_NUL_STRING },
|
[DEVLINK_ATTR_RATE_PARENT_NODE_NAME] = { .type = NLA_NUL_STRING },
|
||||||
[DEVLINK_ATTR_LINECARD_INDEX] = { .type = NLA_U32 },
|
[DEVLINK_ATTR_LINECARD_INDEX] = { .type = NLA_U32 },
|
||||||
|
[DEVLINK_ATTR_LINECARD_TYPE] = { .type = NLA_NUL_STRING },
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct genl_small_ops devlink_nl_ops[] = {
|
static const struct genl_small_ops devlink_nl_ops[] = {
|
||||||
|
@ -8871,6 +9074,12 @@ static const struct genl_small_ops devlink_nl_ops[] = {
|
||||||
.internal_flags = DEVLINK_NL_FLAG_NEED_LINECARD,
|
.internal_flags = DEVLINK_NL_FLAG_NEED_LINECARD,
|
||||||
/* can be retrieved by unprivileged users */
|
/* can be retrieved by unprivileged users */
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.cmd = DEVLINK_CMD_LINECARD_SET,
|
||||||
|
.doit = devlink_nl_cmd_linecard_set_doit,
|
||||||
|
.flags = GENL_ADMIN_PERM,
|
||||||
|
.internal_flags = DEVLINK_NL_FLAG_NEED_LINECARD,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.cmd = DEVLINK_CMD_SB_GET,
|
.cmd = DEVLINK_CMD_SB_GET,
|
||||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||||
|
@ -9962,19 +10171,56 @@ static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int devlink_linecard_types_init(struct devlink_linecard *linecard)
|
||||||
|
{
|
||||||
|
struct devlink_linecard_type *linecard_type;
|
||||||
|
unsigned int count;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
count = linecard->ops->types_count(linecard, linecard->priv);
|
||||||
|
linecard->types = kmalloc_array(count, sizeof(*linecard_type),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!linecard->types)
|
||||||
|
return -ENOMEM;
|
||||||
|
linecard->types_count = count;
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
linecard_type = &linecard->types[i];
|
||||||
|
linecard->ops->types_get(linecard, linecard->priv, i,
|
||||||
|
&linecard_type->type,
|
||||||
|
&linecard_type->priv);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void devlink_linecard_types_fini(struct devlink_linecard *linecard)
|
||||||
|
{
|
||||||
|
kfree(linecard->types);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* devlink_linecard_create - Create devlink linecard
|
* devlink_linecard_create - Create devlink linecard
|
||||||
*
|
*
|
||||||
* @devlink: devlink
|
* @devlink: devlink
|
||||||
* @linecard_index: driver-specific numerical identifier of the linecard
|
* @linecard_index: driver-specific numerical identifier of the linecard
|
||||||
|
* @ops: linecards ops
|
||||||
|
* @priv: user priv pointer
|
||||||
*
|
*
|
||||||
* Create devlink linecard instance with provided linecard index.
|
* Create devlink linecard instance with provided linecard index.
|
||||||
* Caller can use any indexing, even hw-related one.
|
* Caller can use any indexing, even hw-related one.
|
||||||
|
*
|
||||||
|
* Return: Line card structure or an ERR_PTR() encoded error code.
|
||||||
*/
|
*/
|
||||||
struct devlink_linecard *devlink_linecard_create(struct devlink *devlink,
|
struct devlink_linecard *
|
||||||
unsigned int linecard_index)
|
devlink_linecard_create(struct devlink *devlink, unsigned int linecard_index,
|
||||||
|
const struct devlink_linecard_ops *ops, void *priv)
|
||||||
{
|
{
|
||||||
struct devlink_linecard *linecard;
|
struct devlink_linecard *linecard;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (WARN_ON(!ops || !ops->provision || !ops->unprovision ||
|
||||||
|
!ops->types_count || !ops->types_get))
|
||||||
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
mutex_lock(&devlink->linecards_lock);
|
mutex_lock(&devlink->linecards_lock);
|
||||||
if (devlink_linecard_index_exists(devlink, linecard_index)) {
|
if (devlink_linecard_index_exists(devlink, linecard_index)) {
|
||||||
|
@ -9990,6 +10236,19 @@ struct devlink_linecard *devlink_linecard_create(struct devlink *devlink,
|
||||||
|
|
||||||
linecard->devlink = devlink;
|
linecard->devlink = devlink;
|
||||||
linecard->index = linecard_index;
|
linecard->index = linecard_index;
|
||||||
|
linecard->ops = ops;
|
||||||
|
linecard->priv = priv;
|
||||||
|
linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
|
||||||
|
mutex_init(&linecard->state_lock);
|
||||||
|
|
||||||
|
err = devlink_linecard_types_init(linecard);
|
||||||
|
if (err) {
|
||||||
|
mutex_destroy(&linecard->state_lock);
|
||||||
|
kfree(linecard);
|
||||||
|
mutex_unlock(&devlink->linecards_lock);
|
||||||
|
return ERR_PTR(err);
|
||||||
|
}
|
||||||
|
|
||||||
list_add_tail(&linecard->list, &devlink->linecard_list);
|
list_add_tail(&linecard->list, &devlink->linecard_list);
|
||||||
refcount_set(&linecard->refcount, 1);
|
refcount_set(&linecard->refcount, 1);
|
||||||
mutex_unlock(&devlink->linecards_lock);
|
mutex_unlock(&devlink->linecards_lock);
|
||||||
|
@ -10010,11 +10269,68 @@ void devlink_linecard_destroy(struct devlink_linecard *linecard)
|
||||||
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_DEL);
|
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_DEL);
|
||||||
mutex_lock(&devlink->linecards_lock);
|
mutex_lock(&devlink->linecards_lock);
|
||||||
list_del(&linecard->list);
|
list_del(&linecard->list);
|
||||||
|
devlink_linecard_types_fini(linecard);
|
||||||
mutex_unlock(&devlink->linecards_lock);
|
mutex_unlock(&devlink->linecards_lock);
|
||||||
devlink_linecard_put(linecard);
|
devlink_linecard_put(linecard);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(devlink_linecard_destroy);
|
EXPORT_SYMBOL_GPL(devlink_linecard_destroy);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* devlink_linecard_provision_set - Set provisioning on linecard
|
||||||
|
*
|
||||||
|
* @linecard: devlink linecard
|
||||||
|
* @type: linecard type
|
||||||
|
*
|
||||||
|
* This is either called directly from the provision() op call or
|
||||||
|
* as a result of the provision() op call asynchronously.
|
||||||
|
*/
|
||||||
|
void devlink_linecard_provision_set(struct devlink_linecard *linecard,
|
||||||
|
const char *type)
|
||||||
|
{
|
||||||
|
mutex_lock(&linecard->state_lock);
|
||||||
|
WARN_ON(linecard->type && strcmp(linecard->type, type));
|
||||||
|
linecard->state = DEVLINK_LINECARD_STATE_PROVISIONED;
|
||||||
|
linecard->type = type;
|
||||||
|
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
|
||||||
|
mutex_unlock(&linecard->state_lock);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(devlink_linecard_provision_set);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* devlink_linecard_provision_clear - Clear provisioning on linecard
|
||||||
|
*
|
||||||
|
* @linecard: devlink linecard
|
||||||
|
*
|
||||||
|
* This is either called directly from the unprovision() op call or
|
||||||
|
* as a result of the unprovision() op call asynchronously.
|
||||||
|
*/
|
||||||
|
void devlink_linecard_provision_clear(struct devlink_linecard *linecard)
|
||||||
|
{
|
||||||
|
mutex_lock(&linecard->state_lock);
|
||||||
|
linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
|
||||||
|
linecard->type = NULL;
|
||||||
|
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
|
||||||
|
mutex_unlock(&linecard->state_lock);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(devlink_linecard_provision_clear);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* devlink_linecard_provision_fail - Fail provisioning on linecard
|
||||||
|
*
|
||||||
|
* @linecard: devlink linecard
|
||||||
|
*
|
||||||
|
* This is either called directly from the provision() op call or
|
||||||
|
* as a result of the provision() op call asynchronously.
|
||||||
|
*/
|
||||||
|
void devlink_linecard_provision_fail(struct devlink_linecard *linecard)
|
||||||
|
{
|
||||||
|
mutex_lock(&linecard->state_lock);
|
||||||
|
linecard->state = DEVLINK_LINECARD_STATE_PROVISIONING_FAILED;
|
||||||
|
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
|
||||||
|
mutex_unlock(&linecard->state_lock);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(devlink_linecard_provision_fail);
|
||||||
|
|
||||||
int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
|
int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
|
||||||
u32 size, u16 ingress_pools_count,
|
u32 size, u16 ingress_pools_count,
|
||||||
u16 egress_pools_count, u16 ingress_tc_count,
|
u16 egress_pools_count, u16 ingress_tc_count,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче