net/devlink: Add E-Switch mode control
authorOr Gerlitz <ogerlitz@mellanox.com>
Fri, 1 Jul 2016 11:51:01 +0000 (14:51 +0300)
committerDavid S. Miller <davem@davemloft.net>
Sat, 2 Jul 2016 18:40:40 +0000 (14:40 -0400)
Add the commands to set and show the mode of SRIOV E-Switch, two modes
are supported:

* legacy: operating in the "old" L2 based mode (DMAC --> VF vport)

* switchdev: the E-Switch is referred to as whitebox switch configured
using standard tools such as tc, bridge, openvswitch etc. To allow
working with the tools, for each VF, a VF representor netdevice is
created by the E-Switch manager vendor device driver instance (e.g PF).

Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/devlink.h
include/uapi/linux/devlink.h
net/core/devlink.c

index 1d45b61cb320b979bea8acd08cf35783302bfa72..c99ffe8cef3c1a6c7f6ad9db2af7ead71e86dfde 100644 (file)
@@ -90,6 +90,9 @@ struct devlink_ops {
                                       u16 tc_index,
                                       enum devlink_sb_pool_type pool_type,
                                       u32 *p_cur, u32 *p_max);
+
+       int (*eswitch_mode_get)(struct devlink *devlink, u16 *p_mode);
+       int (*eswitch_mode_set)(struct devlink *devlink, u16 mode);
 };
 
 static inline void *devlink_priv(struct devlink *devlink)
index ba0073b26fa66fb185353347231b5fdd37a4e1d8..915bfa74458c147c48a8b12d19221022e0d9e376 100644 (file)
@@ -57,6 +57,8 @@ enum devlink_command {
        DEVLINK_CMD_SB_OCC_SNAPSHOT,
        DEVLINK_CMD_SB_OCC_MAX_CLEAR,
 
+       DEVLINK_CMD_ESWITCH_MODE_GET,
+       DEVLINK_CMD_ESWITCH_MODE_SET,
        /* add new commands above here */
 
        __DEVLINK_CMD_MAX,
@@ -95,6 +97,11 @@ enum devlink_sb_threshold_type {
 
 #define DEVLINK_SB_THRESHOLD_TO_ALPHA_MAX 20
 
+enum devlink_eswitch_mode {
+       DEVLINK_ESWITCH_MODE_LEGACY,
+       DEVLINK_ESWITCH_MODE_SWITCHDEV,
+};
+
 enum devlink_attr {
        /* don't change the order or add anything between, this is ABI! */
        DEVLINK_ATTR_UNSPEC,
@@ -125,6 +132,7 @@ enum devlink_attr {
        DEVLINK_ATTR_SB_TC_INDEX,               /* u16 */
        DEVLINK_ATTR_SB_OCC_CUR,                /* u32 */
        DEVLINK_ATTR_SB_OCC_MAX,                /* u32 */
+       DEVLINK_ATTR_ESWITCH_MODE,              /* u16 */
 
        /* add new attributes above here, update the policy in devlink.c */
 
index 933e8d4d3968a858807616abf68363d4805a455a..b2e592a198c07736cfd03e577b4ff8e85fa3ca61 100644 (file)
@@ -1394,6 +1394,78 @@ static int devlink_nl_cmd_sb_occ_max_clear_doit(struct sk_buff *skb,
        return -EOPNOTSUPP;
 }
 
+static int devlink_eswitch_fill(struct sk_buff *msg, struct devlink *devlink,
+                               enum devlink_command cmd, u32 portid,
+                               u32 seq, int flags, u16 mode)
+{
+       void *hdr;
+
+       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_u16(msg, DEVLINK_ATTR_ESWITCH_MODE, mode))
+               goto nla_put_failure;
+
+       genlmsg_end(msg, hdr);
+       return 0;
+
+nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+       return -EMSGSIZE;
+}
+
+static int devlink_nl_cmd_eswitch_mode_get_doit(struct sk_buff *skb,
+                                               struct genl_info *info)
+{
+       struct devlink *devlink = info->user_ptr[0];
+       const struct devlink_ops *ops = devlink->ops;
+       struct sk_buff *msg;
+       u16 mode;
+       int err;
+
+       if (!ops || !ops->eswitch_mode_get)
+               return -EOPNOTSUPP;
+
+       err = ops->eswitch_mode_get(devlink, &mode);
+       if (err)
+               return err;
+
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       err = devlink_eswitch_fill(msg, devlink, DEVLINK_CMD_ESWITCH_MODE_GET,
+                                  info->snd_portid, info->snd_seq, 0, mode);
+
+       if (err) {
+               nlmsg_free(msg);
+               return err;
+       }
+
+       return genlmsg_reply(msg, info);
+}
+
+static int devlink_nl_cmd_eswitch_mode_set_doit(struct sk_buff *skb,
+                                               struct genl_info *info)
+{
+       struct devlink *devlink = info->user_ptr[0];
+       const struct devlink_ops *ops = devlink->ops;
+       u16 mode;
+
+       if (!info->attrs[DEVLINK_ATTR_ESWITCH_MODE])
+               return -EINVAL;
+
+       mode = nla_get_u16(info->attrs[DEVLINK_ATTR_ESWITCH_MODE]);
+
+       if (ops && ops->eswitch_mode_set)
+               return ops->eswitch_mode_set(devlink, mode);
+       return -EOPNOTSUPP;
+}
+
 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 },
@@ -1407,6 +1479,7 @@ static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
        [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = { .type = NLA_U8 },
        [DEVLINK_ATTR_SB_THRESHOLD] = { .type = NLA_U32 },
        [DEVLINK_ATTR_SB_TC_INDEX] = { .type = NLA_U16 },
+       [DEVLINK_ATTR_ESWITCH_MODE] = { .type = NLA_U16 },
 };
 
 static const struct genl_ops devlink_nl_ops[] = {
@@ -1525,6 +1598,20 @@ static const struct genl_ops devlink_nl_ops[] = {
                                  DEVLINK_NL_FLAG_NEED_SB |
                                  DEVLINK_NL_FLAG_LOCK_PORTS,
        },
+       {
+               .cmd = DEVLINK_CMD_ESWITCH_MODE_GET,
+               .doit = devlink_nl_cmd_eswitch_mode_get_doit,
+               .policy = devlink_nl_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
+       },
+       {
+               .cmd = DEVLINK_CMD_ESWITCH_MODE_SET,
+               .doit = devlink_nl_cmd_eswitch_mode_set_doit,
+               .policy = devlink_nl_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
+       },
 };
 
 /**