Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 287978
b: refs/heads/master
c: 115c9b8
h: refs/heads/master
v: v3
  • Loading branch information
Greg Rose authored and David S. Miller committed Feb 21, 2012
1 parent 81161af commit a22dabb
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 23 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 84338a6c9dbb6ff3de4749864020f8f25d86fc81
refs/heads/master: 115c9b81928360d769a76c632bae62d15206a94a
1 change: 1 addition & 0 deletions trunk/include/linux/if_link.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ enum {
IFLA_AF_SPEC,
IFLA_GROUP, /* Group the device belongs to */
IFLA_NET_NS_FD,
IFLA_EXT_MASK, /* Extended info mask, VFs, etc */
__IFLA_MAX
};

Expand Down
3 changes: 3 additions & 0 deletions trunk/include/linux/rtnetlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,9 @@ struct tcamsg {
#define TCA_ACT_TAB 1 /* attr type must be >=1 */
#define TCAA_MAX 1

/* New extended info filters for IFLA_EXT_MASK */
#define RTEXT_FILTER_VF (1 << 0)

/* End of information exported to user level */

#ifdef __KERNEL__
Expand Down
2 changes: 1 addition & 1 deletion trunk/include/net/rtnetlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

typedef int (*rtnl_doit_func)(struct sk_buff *, struct nlmsghdr *, void *);
typedef int (*rtnl_dumpit_func)(struct sk_buff *, struct netlink_callback *);
typedef u16 (*rtnl_calcit_func)(struct sk_buff *);
typedef u16 (*rtnl_calcit_func)(struct sk_buff *, struct nlmsghdr *);

extern int __rtnl_register(int protocol, int msgtype,
rtnl_doit_func, rtnl_dumpit_func,
Expand Down
78 changes: 57 additions & 21 deletions trunk/net/core/rtnetlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ struct rtnl_link {
};

static DEFINE_MUTEX(rtnl_mutex);
static u16 min_ifinfo_dump_size;

void rtnl_lock(void)
{
Expand Down Expand Up @@ -724,10 +723,11 @@ static void copy_rtnl_link_stats64(void *v, const struct rtnl_link_stats64 *b)
}

/* All VF info */
static inline int rtnl_vfinfo_size(const struct net_device *dev)
static inline int rtnl_vfinfo_size(const struct net_device *dev,
u32 ext_filter_mask)
{
if (dev->dev.parent && dev_is_pci(dev->dev.parent)) {

if (dev->dev.parent && dev_is_pci(dev->dev.parent) &&
(ext_filter_mask & RTEXT_FILTER_VF)) {
int num_vfs = dev_num_vf(dev->dev.parent);
size_t size = nla_total_size(sizeof(struct nlattr));
size += nla_total_size(num_vfs * sizeof(struct nlattr));
Expand Down Expand Up @@ -766,7 +766,8 @@ static size_t rtnl_port_size(const struct net_device *dev)
return port_self_size;
}

static noinline size_t if_nlmsg_size(const struct net_device *dev)
static noinline size_t if_nlmsg_size(const struct net_device *dev,
u32 ext_filter_mask)
{
return NLMSG_ALIGN(sizeof(struct ifinfomsg))
+ nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */
Expand All @@ -784,8 +785,9 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev)
+ nla_total_size(4) /* IFLA_MASTER */
+ nla_total_size(1) /* IFLA_OPERSTATE */
+ nla_total_size(1) /* IFLA_LINKMODE */
+ nla_total_size(4) /* IFLA_NUM_VF */
+ rtnl_vfinfo_size(dev) /* IFLA_VFINFO_LIST */
+ nla_total_size(ext_filter_mask
& RTEXT_FILTER_VF ? 4 : 0) /* IFLA_NUM_VF */
+ rtnl_vfinfo_size(dev, ext_filter_mask) /* IFLA_VFINFO_LIST */
+ rtnl_port_size(dev) /* IFLA_VF_PORTS + IFLA_PORT_SELF */
+ rtnl_link_get_size(dev) /* IFLA_LINKINFO */
+ rtnl_link_get_af_size(dev); /* IFLA_AF_SPEC */
Expand Down Expand Up @@ -868,7 +870,7 @@ static int rtnl_port_fill(struct sk_buff *skb, struct net_device *dev)

static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
int type, u32 pid, u32 seq, u32 change,
unsigned int flags)
unsigned int flags, u32 ext_filter_mask)
{
struct ifinfomsg *ifm;
struct nlmsghdr *nlh;
Expand Down Expand Up @@ -941,10 +943,11 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
goto nla_put_failure;
copy_rtnl_link_stats64(nla_data(attr), stats);

if (dev->dev.parent)
if (dev->dev.parent && (ext_filter_mask & RTEXT_FILTER_VF))
NLA_PUT_U32(skb, IFLA_NUM_VF, dev_num_vf(dev->dev.parent));

if (dev->netdev_ops->ndo_get_vf_config && dev->dev.parent) {
if (dev->netdev_ops->ndo_get_vf_config && dev->dev.parent
&& (ext_filter_mask & RTEXT_FILTER_VF)) {
int i;

struct nlattr *vfinfo, *vf;
Expand Down Expand Up @@ -1048,13 +1051,21 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
struct net_device *dev;
struct hlist_head *head;
struct hlist_node *node;
struct nlattr *tb[IFLA_MAX+1];
u32 ext_filter_mask = 0;

s_h = cb->args[0];
s_idx = cb->args[1];

rcu_read_lock();
cb->seq = net->dev_base_seq;

nlmsg_parse(cb->nlh, sizeof(struct rtgenmsg), tb, IFLA_MAX,
ifla_policy);

if (tb[IFLA_EXT_MASK])
ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);

for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
idx = 0;
head = &net->dev_index_head[h];
Expand All @@ -1064,7 +1075,8 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK,
NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, 0,
NLM_F_MULTI) <= 0)
NLM_F_MULTI,
ext_filter_mask) <= 0)
goto out;

nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Expand Down Expand Up @@ -1100,6 +1112,7 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = {
[IFLA_VF_PORTS] = { .type = NLA_NESTED },
[IFLA_PORT_SELF] = { .type = NLA_NESTED },
[IFLA_AF_SPEC] = { .type = NLA_NESTED },
[IFLA_EXT_MASK] = { .type = NLA_U32 },
};
EXPORT_SYMBOL(ifla_policy);

Expand Down Expand Up @@ -1509,8 +1522,6 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,

if (send_addr_notify)
call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
min_ifinfo_dump_size = max_t(u16, if_nlmsg_size(dev),
min_ifinfo_dump_size);

return err;
}
Expand Down Expand Up @@ -1842,6 +1853,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
struct net_device *dev = NULL;
struct sk_buff *nskb;
int err;
u32 ext_filter_mask = 0;

err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
if (err < 0)
Expand All @@ -1850,6 +1862,9 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
if (tb[IFLA_IFNAME])
nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);

if (tb[IFLA_EXT_MASK])
ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);

ifm = nlmsg_data(nlh);
if (ifm->ifi_index > 0)
dev = __dev_get_by_index(net, ifm->ifi_index);
Expand All @@ -1861,12 +1876,12 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
if (dev == NULL)
return -ENODEV;

nskb = nlmsg_new(if_nlmsg_size(dev), GFP_KERNEL);
nskb = nlmsg_new(if_nlmsg_size(dev, ext_filter_mask), GFP_KERNEL);
if (nskb == NULL)
return -ENOBUFS;

err = rtnl_fill_ifinfo(nskb, dev, RTM_NEWLINK, NETLINK_CB(skb).pid,
nlh->nlmsg_seq, 0, 0);
nlh->nlmsg_seq, 0, 0, ext_filter_mask);
if (err < 0) {
/* -EMSGSIZE implies BUG in if_nlmsg_size */
WARN_ON(err == -EMSGSIZE);
Expand All @@ -1877,8 +1892,31 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
return err;
}

static u16 rtnl_calcit(struct sk_buff *skb)
static u16 rtnl_calcit(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
struct net_device *dev;
struct nlattr *tb[IFLA_MAX+1];
u32 ext_filter_mask = 0;
u16 min_ifinfo_dump_size = 0;

nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, IFLA_MAX, ifla_policy);

if (tb[IFLA_EXT_MASK])
ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);

if (!ext_filter_mask)
return NLMSG_GOODSIZE;
/*
* traverse the list of net devices and compute the minimum
* buffer size based upon the filter mask.
*/
list_for_each_entry(dev, &net->dev_base_head, dev_list) {
min_ifinfo_dump_size = max_t(u16, min_ifinfo_dump_size,
if_nlmsg_size(dev,
ext_filter_mask));
}

return min_ifinfo_dump_size;
}

Expand Down Expand Up @@ -1913,13 +1951,11 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change)
int err = -ENOBUFS;
size_t if_info_size;

skb = nlmsg_new((if_info_size = if_nlmsg_size(dev)), GFP_KERNEL);
skb = nlmsg_new((if_info_size = if_nlmsg_size(dev, 0)), GFP_KERNEL);
if (skb == NULL)
goto errout;

min_ifinfo_dump_size = max_t(u16, if_info_size, min_ifinfo_dump_size);

err = rtnl_fill_ifinfo(skb, dev, type, 0, 0, change, 0);
err = rtnl_fill_ifinfo(skb, dev, type, 0, 0, change, 0, 0);
if (err < 0) {
/* -EMSGSIZE implies BUG in if_nlmsg_size() */
WARN_ON(err == -EMSGSIZE);
Expand Down Expand Up @@ -1977,7 +2013,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
return -EOPNOTSUPP;
calcit = rtnl_get_calcit(family, type);
if (calcit)
min_dump_alloc = calcit(skb);
min_dump_alloc = calcit(skb, nlh);

__rtnl_unlock();
rtnl = net->rtnl;
Expand Down

0 comments on commit a22dabb

Please sign in to comment.