Skip to content

Commit

Permalink
rtnetlink: add new helper rtnl_configure_link_notify()
Browse files Browse the repository at this point in the history
This patch update rtnl_configure_link() to rtnl_configure_link_nlh() by
adding parameter netlink message header and port id so we can notify the
userspace about the new link info if NLM_F_ECHO flag is set.

The rtnl_configure_link() will be a wrapper of the new function. The new
call chain looks like:

- rtnl_configure_link_notify()
  - __dev_notify_flags()
    - rtmsg_ifinfo_nlh()
      - rtmsg_ifinfo_event()
        - rtmsg_ifinfo_build_skb()
        - rtmsg_ifinfo_send()

All the functions in this call chain will add parameter nlh and pid, so
we can use them in the last call rtnl_notify().

Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
  • Loading branch information
liuhangbin authored and intel-lab-lkp committed Sep 30, 2022
1 parent d742ea6 commit 8c50622
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 23 deletions.
2 changes: 1 addition & 1 deletion include/linux/netdevice.h
Expand Up @@ -3856,7 +3856,7 @@ int __dev_change_flags(struct net_device *dev, unsigned int flags,
int dev_change_flags(struct net_device *dev, unsigned int flags,
struct netlink_ext_ack *extack);
void __dev_notify_flags(struct net_device *, unsigned int old_flags,
unsigned int gchanges);
unsigned int gchanges, u32 pid, struct nlmsghdr *nlh);
int dev_set_alias(struct net_device *, const char *, size_t);
int dev_get_alias(const struct net_device *, char *, size_t);
int __dev_change_net_namespace(struct net_device *dev, struct net *net,
Expand Down
6 changes: 4 additions & 2 deletions include/linux/rtnetlink.h
Expand Up @@ -21,12 +21,14 @@ extern int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst,
void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change, gfp_t flags);
void rtmsg_ifinfo_newnet(int type, struct net_device *dev, unsigned int change,
gfp_t flags, int *new_nsid, int new_ifindex);
void rtmsg_ifinfo_nlh(int type, struct net_device *dev, unsigned int change,
gfp_t flags, u32 pid, struct nlmsghdr *nlh);
struct sk_buff *rtmsg_ifinfo_build_skb(int type, struct net_device *dev,
unsigned change, u32 event,
gfp_t flags, int *new_nsid,
int new_ifindex);
int new_ifindex, u32 pid, u32 seq);
void rtmsg_ifinfo_send(struct sk_buff *skb, struct net_device *dev,
gfp_t flags);
gfp_t flags, u32 pid, struct nlmsghdr *nlh);


/* RTNL is used as a global lock for all changes to network configuration */
Expand Down
14 changes: 7 additions & 7 deletions net/core/dev.c
Expand Up @@ -8347,7 +8347,7 @@ static int __dev_set_promiscuity(struct net_device *dev, int inc, bool notify)
dev_change_rx_flags(dev, IFF_PROMISC);
}
if (notify)
__dev_notify_flags(dev, old_flags, IFF_PROMISC);
__dev_notify_flags(dev, old_flags, IFF_PROMISC, 0, NULL);
return 0;
}

Expand Down Expand Up @@ -8402,7 +8402,7 @@ static int __dev_set_allmulti(struct net_device *dev, int inc, bool notify)
dev_set_rx_mode(dev);
if (notify)
__dev_notify_flags(dev, old_flags,
dev->gflags ^ old_gflags);
dev->gflags ^ old_gflags, 0, NULL);
}
return 0;
}
Expand Down Expand Up @@ -8565,12 +8565,12 @@ int __dev_change_flags(struct net_device *dev, unsigned int flags,
}

void __dev_notify_flags(struct net_device *dev, unsigned int old_flags,
unsigned int gchanges)
unsigned int gchanges, u32 pid, struct nlmsghdr *nlh)
{
unsigned int changes = dev->flags ^ old_flags;

if (gchanges)
rtmsg_ifinfo(RTM_NEWLINK, dev, gchanges, GFP_ATOMIC);
rtmsg_ifinfo_nlh(RTM_NEWLINK, dev, gchanges, GFP_ATOMIC, pid, nlh);

if (changes & IFF_UP) {
if (dev->flags & IFF_UP)
Expand Down Expand Up @@ -8612,7 +8612,7 @@ int dev_change_flags(struct net_device *dev, unsigned int flags,
return ret;

changes = (old_flags ^ dev->flags) | (old_gflags ^ dev->gflags);
__dev_notify_flags(dev, old_flags, changes);
__dev_notify_flags(dev, old_flags, changes, 0, NULL);
return ret;
}
EXPORT_SYMBOL(dev_change_flags);
Expand Down Expand Up @@ -10845,7 +10845,7 @@ void unregister_netdevice_many(struct list_head *head)
if (!dev->rtnl_link_ops ||
dev->rtnl_link_state == RTNL_LINK_INITIALIZED)
skb = rtmsg_ifinfo_build_skb(RTM_DELLINK, dev, ~0U, 0,
GFP_KERNEL, NULL, 0);
GFP_KERNEL, NULL, 0, 0, 0);

/*
* Flush the unicast and multicast chains
Expand All @@ -10860,7 +10860,7 @@ void unregister_netdevice_many(struct list_head *head)
dev->netdev_ops->ndo_uninit(dev);

if (skb)
rtmsg_ifinfo_send(skb, dev, GFP_KERNEL);
rtmsg_ifinfo_send(skb, dev, GFP_KERNEL, 0, NULL);

/* Notifier chain MUST detach us all upper devices. */
WARN_ON(netdev_has_any_upper_dev(dev));
Expand Down
41 changes: 28 additions & 13 deletions net/core/rtnetlink.c
Expand Up @@ -3180,7 +3180,8 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh,
return err;
}

int rtnl_configure_link(struct net_device *dev, const struct ifinfomsg *ifm)
int rtnl_configure_link_notify(struct net_device *dev, const struct ifinfomsg *ifm,
struct nlmsghdr *nlh, u32 pid)
{
unsigned int old_flags;
int err;
Expand All @@ -3194,13 +3195,18 @@ int rtnl_configure_link(struct net_device *dev, const struct ifinfomsg *ifm)
}

if (dev->rtnl_link_state == RTNL_LINK_INITIALIZED) {
__dev_notify_flags(dev, old_flags, (old_flags ^ dev->flags));
__dev_notify_flags(dev, old_flags, (old_flags ^ dev->flags), pid, nlh);
} else {
dev->rtnl_link_state = RTNL_LINK_INITIALIZED;
__dev_notify_flags(dev, old_flags, ~0U);
__dev_notify_flags(dev, old_flags, ~0U, pid, nlh);
}
return 0;
}

int rtnl_configure_link(struct net_device *dev, const struct ifinfomsg *ifm)
{
return rtnl_configure_link_notify(dev, ifm, NULL, 0);
}
EXPORT_SYMBOL(rtnl_configure_link);

struct net_device *rtnl_create_link(struct net *net, const char *ifname,
Expand Down Expand Up @@ -3896,7 +3902,7 @@ static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
struct sk_buff *rtmsg_ifinfo_build_skb(int type, struct net_device *dev,
unsigned int change,
u32 event, gfp_t flags, int *new_nsid,
int new_ifindex)
int new_ifindex, u32 pid, u32 seq)
{
struct net *net = dev_net(dev);
struct sk_buff *skb;
Expand All @@ -3907,7 +3913,7 @@ struct sk_buff *rtmsg_ifinfo_build_skb(int type, struct net_device *dev,
goto errout;

err = rtnl_fill_ifinfo(skb, dev, dev_net(dev),
type, 0, 0, change, 0, 0, event,
type, pid, seq, change, 0, 0, event,
new_nsid, new_ifindex, -1, flags);
if (err < 0) {
/* -EMSGSIZE implies BUG in if_nlmsg_size() */
Expand All @@ -3922,40 +3928,49 @@ struct sk_buff *rtmsg_ifinfo_build_skb(int type, struct net_device *dev,
return NULL;
}

void rtmsg_ifinfo_send(struct sk_buff *skb, struct net_device *dev, gfp_t flags)
void rtmsg_ifinfo_send(struct sk_buff *skb, struct net_device *dev, gfp_t flags,
u32 pid, struct nlmsghdr *nlh)
{
struct net *net = dev_net(dev);

rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, flags);
rtnl_notify(skb, net, pid, RTNLGRP_LINK, nlh, flags);
}

static void rtmsg_ifinfo_event(int type, struct net_device *dev,
unsigned int change, u32 event,
gfp_t flags, int *new_nsid, int new_ifindex)
gfp_t flags, int *new_nsid, int new_ifindex,
u32 pid, struct nlmsghdr *nlh)
{
struct sk_buff *skb;

if (dev->reg_state != NETREG_REGISTERED)
return;

skb = rtmsg_ifinfo_build_skb(type, dev, change, event, flags, new_nsid,
new_ifindex);
new_ifindex, pid, nlh ? nlh->nlmsg_seq : 0);
if (skb)
rtmsg_ifinfo_send(skb, dev, flags);
rtmsg_ifinfo_send(skb, dev, flags, pid, nlh);
}

void rtmsg_ifinfo(int type, struct net_device *dev, unsigned int change,
gfp_t flags)
{
rtmsg_ifinfo_event(type, dev, change, rtnl_get_event(0), flags,
NULL, 0);
NULL, 0, 0, NULL);
}

void rtmsg_ifinfo_newnet(int type, struct net_device *dev, unsigned int change,
gfp_t flags, int *new_nsid, int new_ifindex)
{
rtmsg_ifinfo_event(type, dev, change, rtnl_get_event(0), flags,
new_nsid, new_ifindex);
new_nsid, new_ifindex, 0, NULL);
}

void rtmsg_ifinfo_nlh(int type, struct net_device *dev, unsigned int change,
gfp_t flags, u32 pid, struct nlmsghdr *nlh)
{
rtmsg_ifinfo_event(type, dev, change, rtnl_get_event(0), flags,
NULL, 0, pid, nlh);
}

static int nlmsg_populate_fdb_fill(struct sk_buff *skb,
Expand Down Expand Up @@ -6140,7 +6155,7 @@ static int rtnetlink_event(struct notifier_block *this, unsigned long event, voi
case NETDEV_CHANGELOWERSTATE:
case NETDEV_CHANGE_TX_QUEUE_LEN:
rtmsg_ifinfo_event(RTM_NEWLINK, dev, 0, rtnl_get_event(event),
GFP_KERNEL, NULL, 0);
GFP_KERNEL, NULL, 0, 0, NULL);
break;
default:
break;
Expand Down

0 comments on commit 8c50622

Please sign in to comment.