cregit-Linux how code gets into the kernel

Release 4.8 net/core/devlink.c

Directory: net/core
/*
 * net/core/devlink.c - Network physical/parent device Netlink interface
 *
 * Heavily inspired by net/wireless/
 * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
 * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/gfp.h>
#include <linux/device.h>
#include <linux/list.h>
#include <linux/netdevice.h>
#include <rdma/ib_verbs.h>
#include <net/netlink.h>
#include <net/genetlink.h>
#include <net/rtnetlink.h>
#include <net/net_namespace.h>
#include <net/sock.h>
#include <net/devlink.h>

#define CREATE_TRACE_POINTS
#include <trace/events/devlink.h>


EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwmsg);

static LIST_HEAD(devlink_list);

/* devlink_mutex
 *
 * An overall lock guarding every operation coming from userspace.
 * It also guards devlink devices list and it is taken when
 * driver registers/unregisters it.
 */
static DEFINE_MUTEX(devlink_mutex);

/* devlink_port_mutex
 *
 * Shared lock to guard lists of ports in all devlink devices.
 */
static DEFINE_MUTEX(devlink_port_mutex);


static struct net *devlink_net(const struct devlink *devlink) { return read_pnet(&devlink->_net); }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko23100.00%1100.00%
Total23100.00%1100.00%


static void devlink_net_set(struct devlink *devlink, struct net *net) { write_pnet(&devlink->_net, net); }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko26100.00%1100.00%
Total26100.00%1100.00%


static struct devlink *devlink_get_from_attrs(struct net *net, struct nlattr **attrs) { struct devlink *devlink; char *busname; char *devname; if (!attrs[DEVLINK_ATTR_BUS_NAME] || !attrs[DEVLINK_ATTR_DEV_NAME]) return ERR_PTR(-EINVAL); busname = nla_data(attrs[DEVLINK_ATTR_BUS_NAME]); devname = nla_data(attrs[DEVLINK_ATTR_DEV_NAME]); list_for_each_entry(devlink, &devlink_list, list) { if (strcmp(devlink->dev->bus->name, busname) == 0 && strcmp(dev_name(devlink->dev), devname) == 0 && net_eq(devlink_net(devlink), net)) return devlink; } return ERR_PTR(-ENODEV); }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko134100.00%1100.00%
Total134100.00%1100.00%


static struct devlink *devlink_get_from_info(struct genl_info *info) { return devlink_get_from_attrs(genl_info_net(info), info->attrs); }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko26100.00%1100.00%
Total26100.00%1100.00%


static struct devlink_port *devlink_port_get_by_index(struct devlink *devlink, int port_index) { struct devlink_port *devlink_port; list_for_each_entry(devlink_port, &devlink->port_list, list) { if (devlink_port->index == port_index) return devlink_port; } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko45100.00%1100.00%
Total45100.00%1100.00%


static bool devlink_port_index_exists(struct devlink *devlink, int port_index) { return devlink_port_get_by_index(devlink, port_index); }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko22100.00%1100.00%
Total22100.00%1100.00%


static struct devlink_port *devlink_port_get_from_attrs(struct devlink *devlink, struct nlattr **attrs) { if (attrs[DEVLINK_ATTR_PORT_INDEX]) { u32 port_index = nla_get_u32(attrs[DEVLINK_ATTR_PORT_INDEX]); struct devlink_port *devlink_port; devlink_port = devlink_port_get_by_index(devlink, port_index); if (!devlink_port) return ERR_PTR(-ENODEV); return devlink_port; } return ERR_PTR(-EINVAL); }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko75100.00%1100.00%
Total75100.00%1100.00%


static struct devlink_port *devlink_port_get_from_info(struct devlink *devlink, struct genl_info *info) { return devlink_port_get_from_attrs(devlink, info->attrs); }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko28100.00%1100.00%
Total28100.00%1100.00%

struct devlink_sb { struct list_head list; unsigned int index; u32 size; u16 ingress_pools_count; u16 egress_pools_count; u16 ingress_tc_count; u16 egress_tc_count; };
static u16 devlink_sb_pool_count(struct devlink_sb *devlink_sb) { return devlink_sb->ingress_pools_count + devlink_sb->egress_pools_count; }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko20100.00%2100.00%
Total20100.00%2100.00%


static struct devlink_sb *devlink_sb_get_by_index(struct devlink *devlink, unsigned int sb_index) { struct devlink_sb *devlink_sb; list_for_each_entry(devlink_sb, &devlink->sb_list, list) { if (devlink_sb->index == sb_index) return devlink_sb; } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko46100.00%2100.00%
Total46100.00%2100.00%


static bool devlink_sb_index_exists(struct devlink *devlink, unsigned int sb_index) { return devlink_sb_get_by_index(devlink, sb_index); }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko23100.00%2100.00%
Total23100.00%2100.00%


static struct devlink_sb *devlink_sb_get_from_attrs(struct devlink *devlink, struct nlattr **attrs) { if (attrs[DEVLINK_ATTR_SB_INDEX]) { u32 sb_index = nla_get_u32(attrs[DEVLINK_ATTR_SB_INDEX]); struct devlink_sb *devlink_sb; devlink_sb = devlink_sb_get_by_index(devlink, sb_index); if (!devlink_sb) return ERR_PTR(-ENODEV); return devlink_sb; } return ERR_PTR(-EINVAL); }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko75100.00%3100.00%
Total75100.00%3100.00%


static struct devlink_sb *devlink_sb_get_from_info(struct devlink *devlink, struct genl_info *info) { return devlink_sb_get_from_attrs(devlink, info->attrs); }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko28100.00%2100.00%
Total28100.00%2100.00%


static int devlink_sb_pool_index_get_from_attrs(struct devlink_sb *devlink_sb, struct nlattr **attrs, u16 *p_pool_index) { u16 val; if (!attrs[DEVLINK_ATTR_SB_POOL_INDEX]) return -EINVAL; val = nla_get_u16(attrs[DEVLINK_ATTR_SB_POOL_INDEX]); if (val >= devlink_sb_pool_count(devlink_sb)) return -EINVAL; *p_pool_index = val; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko67100.00%2100.00%
Total67100.00%2100.00%


static int devlink_sb_pool_index_get_from_info(struct devlink_sb *devlink_sb, struct genl_info *info, u16 *p_pool_index) { return devlink_sb_pool_index_get_from_attrs(devlink_sb, info->attrs, p_pool_index); }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko32100.00%1100.00%
Total32100.00%1100.00%


static int devlink_sb_pool_type_get_from_attrs(struct nlattr **attrs, enum devlink_sb_pool_type *p_pool_type) { u8 val; if (!attrs[DEVLINK_ATTR_SB_POOL_TYPE]) return -EINVAL; val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_TYPE]); if (val != DEVLINK_SB_POOL_TYPE_INGRESS && val != DEVLINK_SB_POOL_TYPE_EGRESS) return -EINVAL; *p_pool_type = val; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko64100.00%2100.00%
Total64100.00%2100.00%


static int devlink_sb_pool_type_get_from_info(struct genl_info *info, enum devlink_sb_pool_type *p_pool_type) { return devlink_sb_pool_type_get_from_attrs(info->attrs, p_pool_type); }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko26100.00%1100.00%
Total26100.00%1100.00%


static int devlink_sb_th_type_get_from_attrs(struct nlattr **attrs, enum devlink_sb_threshold_type *p_th_type) { u8 val; if (!attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]) return -EINVAL; val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]); if (val != DEVLINK_SB_THRESHOLD_TYPE_STATIC && val != DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC) return -EINVAL; *p_th_type = val; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko64100.00%2100.00%
Total64100.00%2100.00%


static int devlink_sb_th_type_get_from_info(struct genl_info *info, enum devlink_sb_threshold_type *p_th_type) { return devlink_sb_th_type_get_from_attrs(info->attrs, p_th_type); }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko26100.00%1100.00%
Total26100.00%1100.00%


static int devlink_sb_tc_index_get_from_attrs(struct devlink_sb *devlink_sb, struct nlattr **attrs, enum devlink_sb_pool_type pool_type, u16 *p_tc_index) { u16 val; if (!attrs[DEVLINK_ATTR_SB_TC_INDEX]) return -EINVAL; val = nla_get_u16(attrs[DEVLINK_ATTR_SB_TC_INDEX]); if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS && val >= devlink_sb->ingress_tc_count) return -EINVAL; if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS && val >= devlink_sb->egress_tc_count) return -EINVAL; *p_tc_index = val; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko90100.00%1100.00%
Total90100.00%1100.00%


static int devlink_sb_tc_index_get_from_info(struct devlink_sb *devlink_sb, struct genl_info *info, enum devlink_sb_pool_type pool_type, u16 *p_tc_index) { return devlink_sb_tc_index_get_from_attrs(devlink_sb, info->attrs, pool_type, p_tc_index); }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko38100.00%1100.00%
Total38100.00%1100.00%

#define DEVLINK_NL_FLAG_NEED_DEVLINK BIT(0) #define DEVLINK_NL_FLAG_NEED_PORT BIT(1) #define DEVLINK_NL_FLAG_NEED_SB BIT(2) #define DEVLINK_NL_FLAG_LOCK_PORTS BIT(3) /* port is not needed but we need to ensure they don't * change in the middle of command */
static int devlink_nl_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, struct genl_info *info) { struct devlink *devlink; mutex_lock(&devlink_mutex); devlink = devlink_get_from_info(info); if (IS_ERR(devlink)) { mutex_unlock(&devlink_mutex); return PTR_ERR(devlink); } if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK) { info->user_ptr[0] = devlink; } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) { struct devlink_port *devlink_port; mutex_lock(&devlink_port_mutex); devlink_port = devlink_port_get_from_info(devlink, info); if (IS_ERR(devlink_port)) { mutex_unlock(&devlink_port_mutex); mutex_unlock(&devlink_mutex); return PTR_ERR(devlink_port); } info->user_ptr[0] = devlink_port; } if (ops->internal_flags & DEVLINK_NL_FLAG_LOCK_PORTS) { mutex_lock(&devlink_port_mutex); } if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_SB) { struct devlink_sb *devlink_sb; devlink_sb = devlink_sb_get_from_info(devlink, info); if (IS_ERR(devlink_sb)) { if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) mutex_unlock(&devlink_port_mutex); mutex_unlock(&devlink_mutex); return PTR_ERR(devlink_sb); } info->user_ptr[1] = devlink_sb; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko234100.00%2100.00%
Total234100.00%2100.00%


static void devlink_nl_post_doit(const struct genl_ops *ops, struct sk_buff *skb, struct genl_info *info) { if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT || ops->internal_flags & DEVLINK_NL_FLAG_LOCK_PORTS) mutex_unlock(&devlink_port_mutex); mutex_unlock(&devlink_mutex); }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko48100.00%2100.00%
Total48100.00%2100.00%

static struct genl_family devlink_nl_family = { .id = GENL_ID_GENERATE, .name = DEVLINK_GENL_NAME, .version = DEVLINK_GENL_VERSION, .maxattr = DEVLINK_ATTR_MAX, .netnsok = true, .pre_doit = devlink_nl_pre_doit, .post_doit = devlink_nl_post_doit, }; enum devlink_multicast_groups { DEVLINK_MCGRP_CONFIG, }; static const struct genl_multicast_group devlink_nl_mcgrps[] = { [DEVLINK_MCGRP_CONFIG] = { .name = DEVLINK_GENL_MCGRP_CONFIG_NAME }, };
static int devlink_nl_put_handle(struct sk_buff *msg, struct devlink *devlink) { if (nla_put_string(msg, DEVLINK_ATTR_BUS_NAME, devlink->dev->bus->name)) return -EMSGSIZE; if (nla_put_string(msg, DEVLINK_ATTR_DEV_NAME, dev_name(devlink->dev))) return -EMSGSIZE; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko60100.00%1100.00%
Total60100.00%1100.00%


static int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink, enum devlink_command cmd, u32 portid, u32 seq, int flags) { 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; genlmsg_end(msg, hdr); return 0; nla_put_failure: genlmsg_cancel(msg, hdr); return -EMSGSIZE; }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko95100.00%1100.00%
Total95100.00%1100.00%


static void devlink_notify(struct devlink *devlink, enum devlink_command cmd) { struct sk_buff *msg; int err; WARN_ON(cmd != DEVLINK_CMD_NEW && cmd != DEVLINK_CMD_DEL); msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) return; err = devlink_nl_fill(msg, devlink, 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); }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko97100.00%1100.00%
Total97100.00%1100.00%


static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink, struct devlink_port *devlink_port, enum devlink_command cmd, u32 portid, u32 seq, int flags) { 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_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index)) goto nla_put_failure; if (nla_put_u16(msg, DEVLINK_ATTR_PORT_TYPE, devlink_port->type)) goto nla_put_failure; 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; 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; } 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; } if (devlink_port->split && nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_GROUP, devlink_port->split_group)) goto nla_put_failure; genlmsg_end(msg, hdr); return 0; nla_put_failure: genlmsg_cancel(msg, hdr); return -EMSGSIZE; }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko261100.00%1100.00%
Total261100.00%1100.00%


static void devlink_port_notify(struct devlink_port *devlink_port, enum devlink_command cmd) { struct devlink *devlink = devlink_port->devlink; struct sk_buff *msg; int err; if (!devlink_port->registered) return; WARN_ON(cmd != DEVLINK_CMD_PORT_NEW && cmd != DEVLINK_CMD_PORT_DEL); msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) return; err = devlink_nl_port_fill(msg, devlink, devlink_port, 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); }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko116100.00%1100.00%
Total116100.00%1100.00%


static int devlink_nl_cmd_get_doit(struct sk_buff *skb, struct genl_info *info) { struct devlink *devlink = info->user_ptr[0]; struct sk_buff *msg; int err; msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) return -ENOMEM; err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW, info->snd_portid, info->snd_seq, 0); if (err) { nlmsg_free(msg); return err; } return genlmsg_reply(msg, info); }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko97100.00%1100.00%
Total97100.00%1100.00%


static int devlink_nl_cmd_get_dumpit(struct sk_buff *msg, struct netlink_callback *cb) { 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; if (idx < start) { idx++; continue; } err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, NLM_F_MULTI); if (err) goto out; idx++; } out: mutex_unlock(&devlink_mutex); cb->args[0] = idx; return msg->len; }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko146100.00%1100.00%
Total146100.00%1100.00%


static int devlink_nl_cmd_port_get_doit(struct sk_buff *skb, struct genl_info *info) { struct devlink_port *devlink_port = info->user_ptr[0]; struct devlink *devlink = devlink_port->devlink; struct sk_buff *msg; int err; msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) return -ENOMEM; err = devlink_nl_port_fill(msg, devlink, devlink_port, DEVLINK_CMD_PORT_NEW, info->snd_portid, info->snd_seq, 0); if (err) { nlmsg_free(msg); return err; } return genlmsg_reply(msg, info); }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko108100.00%1100.00%
Total108100.00%1100.00%


static int devlink_nl_cmd_port_get_dumpit(struct sk_buff *msg, struct netlink_callback *cb) { struct devlink *devlink; struct devlink_port *devlink_port; int start = cb->args[0]; int idx = 0; int err; mutex_lock(&devlink_mutex); mutex_lock(&devlink_port_mutex); list_for_each_entry(devlink, &devlink_list, list) { if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) continue; list_for_each_entry(devlink_port, &devlink->port_list, list) { if (idx < start) { idx++; continue; } err = devlink_nl_port_fill(msg, devlink, devlink_port, DEVLINK_CMD_NEW, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, NLM_F_MULTI); if (err) goto out; idx++; } } out: mutex_unlock(&devlink_port_mutex); mutex_unlock(&devlink_mutex); cb->args[0] = idx; return msg->len; }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko175100.00%1100.00%
Total175100.00%1100.00%


static int devlink_port_type_set(struct devlink *devlink, struct devlink_port *devlink_port, enum devlink_port_type port_type) { int err; if (devlink->ops && devlink->ops->port_type_set) { if (port_type == DEVLINK_PORT_TYPE_NOTSET) return -EINVAL; err = devlink->ops->port_type_set(devlink_port, port_type); if (err) return err; devlink_port->desired_type = port_type; devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW); return 0; } return -EOPNOTSUPP; }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko87100.00%1100.00%
Total87100.00%1100.00%


static int devlink_nl_cmd_port_set_doit(struct sk_buff *skb, struct genl_info *info) { struct devlink_port *devlink_port = info->user_ptr[0]; struct devlink *devlink = devlink_port->devlink; int err; if (info->attrs[DEVLINK_ATTR_PORT_TYPE]) { enum devlink_port_type port_type; port_type = nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_TYPE]); err = devlink_port_type_set(devlink, devlink_port, port_type); if (err) return err; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko88100.00%1100.00%
Total88100.00%1100.00%


static int devlink_port_split(struct devlink *devlink, u32 port_index, u32 count) { if (devlink->ops && devlink->ops->port_split) return devlink->ops->port_split(devlink, port_index, count); return -EOPNOTSUPP; }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko47100.00%1100.00%
Total47100.00%1100.00%


static int devlink_nl_cmd_port_split_doit(struct sk_buff *skb, struct genl_info *info) { struct devlink *devlink = info->user_ptr[0]; u32 port_index; u32 count; if (!info->attrs[DEVLINK_ATTR_PORT_INDEX] || !info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT]) return -EINVAL; port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]); count = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT]); return devlink_port_split(devlink, port_index, count); }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko90100.00%1100.00%
Total90100.00%1100.00%


static int devlink_port_unsplit(struct devlink *devlink, u32 port_index) { if (devlink->ops && devlink->ops->port_unsplit) return devlink->ops->port_unsplit(devlink, port_index); return -EOPNOTSUPP; }

Contributors

PersonTokensPropCommitsCommitProp
jiri pirkojiri pirko42100.00%1100.00%
Total42100.00%1100.00%


static int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb, struct genl_info *info) { struct devlink *devlink = info->