Skip to content

Commit

Permalink
[NET]: Make rtnetlink infrastructure network namespace aware (v3)
Browse files Browse the repository at this point in the history
After this patch none of the netlink callback support anything
except the initial network namespace but the rtnetlink infrastructure
now handles multiple network namespaces.

Changes from v2:
- IPv6 addrlabel processing

Changes from v1:
- no need for special rtnl_unlock handling
- fixed IPv6 ndisc

Signed-off-by: Denis V. Lunev <[email protected]>
Signed-off-by: Eric W. Biederman <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
Denis V. Lunev authored and davem330 committed Jan 28, 2008
1 parent b854272 commit 97c53ca
Show file tree
Hide file tree
Showing 21 changed files with 102 additions and 54 deletions.
8 changes: 4 additions & 4 deletions include/linux/rtnetlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -620,11 +620,11 @@ extern int __rtattr_parse_nested_compat(struct rtattr *tb[], int maxattr,
({ data = RTA_PAYLOAD(rta) >= len ? RTA_DATA(rta) : NULL; \
__rtattr_parse_nested_compat(tb, max, rta, len); })

extern int rtnetlink_send(struct sk_buff *skb, u32 pid, u32 group, int echo);
extern int rtnl_unicast(struct sk_buff *skb, u32 pid);
extern int rtnl_notify(struct sk_buff *skb, u32 pid, u32 group,
extern int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, u32 group, int echo);
extern int rtnl_unicast(struct sk_buff *skb, struct net *net, u32 pid);
extern int rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group,
struct nlmsghdr *nlh, gfp_t flags);
extern void rtnl_set_sk_err(u32 group, int error);
extern void rtnl_set_sk_err(struct net *net, u32 group, int error);
extern int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics);
extern int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst,
u32 id, u32 ts, u32 tsage, long expires,
Expand Down
3 changes: 3 additions & 0 deletions include/net/net_namespace.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

struct proc_dir_entry;
struct net_device;
struct sock;
struct net {
atomic_t count; /* To decided when the network
* namespace should be freed.
Expand All @@ -29,6 +30,8 @@ struct net {
struct list_head dev_base_head;
struct hlist_head *dev_name_head;
struct hlist_head *dev_index_head;

struct sock *rtnl; /* rtnetlink socket */
};

#ifdef CONFIG_NET
Expand Down
4 changes: 2 additions & 2 deletions net/bridge/br_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,10 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port)
kfree_skb(skb);
goto errout;
}
err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
err = rtnl_notify(skb, &init_net,0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
errout:
if (err < 0)
rtnl_set_sk_err(RTNLGRP_LINK, err);
rtnl_set_sk_err(&init_net, RTNLGRP_LINK, err);
}

/*
Expand Down
4 changes: 2 additions & 2 deletions net/core/fib_rules.c
Original file line number Diff line number Diff line change
Expand Up @@ -599,10 +599,10 @@ static void notify_rule_change(int event, struct fib_rule *rule,
kfree_skb(skb);
goto errout;
}
err = rtnl_notify(skb, pid, ops->nlgroup, nlh, GFP_KERNEL);
err = rtnl_notify(skb, &init_net, pid, ops->nlgroup, nlh, GFP_KERNEL);
errout:
if (err < 0)
rtnl_set_sk_err(ops->nlgroup, err);
rtnl_set_sk_err(&init_net, ops->nlgroup, err);
}

static void attach_rules(struct list_head *rules, struct net_device *dev)
Expand Down
4 changes: 2 additions & 2 deletions net/core/neighbour.c
Original file line number Diff line number Diff line change
Expand Up @@ -2467,10 +2467,10 @@ static void __neigh_notify(struct neighbour *n, int type, int flags)
kfree_skb(skb);
goto errout;
}
err = rtnl_notify(skb, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
err = rtnl_notify(skb, &init_net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
errout:
if (err < 0)
rtnl_set_sk_err(RTNLGRP_NEIGH, err);
rtnl_set_sk_err(&init_net, RTNLGRP_NEIGH, err);
}

#ifdef CONFIG_ARPD
Expand Down
63 changes: 52 additions & 11 deletions 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 struct sock *rtnl;

void rtnl_lock(void)
{
Expand Down Expand Up @@ -458,8 +457,9 @@ size_t rtattr_strlcpy(char *dest, const struct rtattr *rta, size_t size)
return ret;
}

int rtnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo)
int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned group, int echo)
{
struct sock *rtnl = net->rtnl;
int err = 0;

NETLINK_CB(skb).dst_group = group;
Expand All @@ -471,14 +471,17 @@ int rtnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo)
return err;
}

int rtnl_unicast(struct sk_buff *skb, u32 pid)
int rtnl_unicast(struct sk_buff *skb, struct net *net, u32 pid)
{
struct sock *rtnl = net->rtnl;

return nlmsg_unicast(rtnl, skb, pid);
}

int rtnl_notify(struct sk_buff *skb, u32 pid, u32 group,
int rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group,
struct nlmsghdr *nlh, gfp_t flags)
{
struct sock *rtnl = net->rtnl;
int report = 0;

if (nlh)
Expand All @@ -487,8 +490,10 @@ int rtnl_notify(struct sk_buff *skb, u32 pid, u32 group,
return nlmsg_notify(rtnl, skb, pid, group, report, flags);
}

void rtnl_set_sk_err(u32 group, int error)
void rtnl_set_sk_err(struct net *net, u32 group, int error)
{
struct sock *rtnl = net->rtnl;

netlink_set_err(rtnl, 0, group, error);
}

Expand Down Expand Up @@ -1201,7 +1206,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
kfree_skb(nskb);
goto errout;
}
err = rtnl_unicast(nskb, NETLINK_CB(skb).pid);
err = rtnl_unicast(nskb, net, NETLINK_CB(skb).pid);
errout:
dev_put(dev);

Expand Down Expand Up @@ -1252,10 +1257,10 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change)
kfree_skb(skb);
goto errout;
}
err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
err = rtnl_notify(skb, &init_net, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
errout:
if (err < 0)
rtnl_set_sk_err(RTNLGRP_LINK, err);
rtnl_set_sk_err(&init_net, RTNLGRP_LINK, err);
}

/* Protected by RTNL sempahore. */
Expand All @@ -1266,6 +1271,7 @@ static int rtattr_max;

static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = skb->sk->sk_net;
rtnl_doit_func doit;
int sz_idx, kind;
int min_len;
Expand Down Expand Up @@ -1294,13 +1300,15 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
return -EPERM;

if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) {
struct sock *rtnl;
rtnl_dumpit_func dumpit;

dumpit = rtnl_get_dumpit(family, type);
if (dumpit == NULL)
return -EOPNOTSUPP;

__rtnl_unlock();
rtnl = net->rtnl;
err = netlink_dump_start(rtnl, skb, nlh, dumpit, NULL);
rtnl_lock();
return err;
Expand Down Expand Up @@ -1373,6 +1381,40 @@ static struct notifier_block rtnetlink_dev_notifier = {
.notifier_call = rtnetlink_event,
};


static int rtnetlink_net_init(struct net *net)
{
struct sock *sk;
sk = netlink_kernel_create(net, NETLINK_ROUTE, RTNLGRP_MAX,
rtnetlink_rcv, &rtnl_mutex, THIS_MODULE);
if (!sk)
return -ENOMEM;

/* Don't hold an extra reference on the namespace */
put_net(sk->sk_net);
net->rtnl = sk;
return 0;
}

static void rtnetlink_net_exit(struct net *net)
{
struct sock *sk = net->rtnl;
if (sk) {
/* At the last minute lie and say this is a socket for the
* initial network namespace. So the socket will be safe to
* free.
*/
sk->sk_net = get_net(&init_net);
sock_put(sk);
net->rtnl = NULL;
}
}

static struct pernet_operations rtnetlink_net_ops = {
.init = rtnetlink_net_init,
.exit = rtnetlink_net_exit,
};

void __init rtnetlink_init(void)
{
int i;
Expand All @@ -1385,10 +1427,9 @@ void __init rtnetlink_init(void)
if (!rta_buf)
panic("rtnetlink_init: cannot allocate rta_buf\n");

rtnl = netlink_kernel_create(&init_net, NETLINK_ROUTE, RTNLGRP_MAX,
rtnetlink_rcv, &rtnl_mutex, THIS_MODULE);
if (rtnl == NULL)
if (register_pernet_subsys(&rtnetlink_net_ops))
panic("rtnetlink_init: cannot initialize rtnetlink\n");

netlink_set_nonroot(NETLINK_ROUTE, NL_NONROOT_RECV);
register_netdevice_notifier(&rtnetlink_dev_notifier);

Expand Down
4 changes: 2 additions & 2 deletions net/decnet/dn_dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -793,10 +793,10 @@ static void dn_ifaddr_notify(int event, struct dn_ifaddr *ifa)
kfree_skb(skb);
goto errout;
}
err = rtnl_notify(skb, 0, RTNLGRP_DECnet_IFADDR, NULL, GFP_KERNEL);
err = rtnl_notify(skb, &init_net, 0, RTNLGRP_DECnet_IFADDR, NULL, GFP_KERNEL);
errout:
if (err < 0)
rtnl_set_sk_err(RTNLGRP_DECnet_IFADDR, err);
rtnl_set_sk_err(&init_net, RTNLGRP_DECnet_IFADDR, err);
}

static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
Expand Down
2 changes: 1 addition & 1 deletion net/decnet/dn_route.c
Original file line number Diff line number Diff line change
Expand Up @@ -1587,7 +1587,7 @@ static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void
goto out_free;
}

return rtnl_unicast(skb, NETLINK_CB(in_skb).pid);
return rtnl_unicast(skb, &init_net, NETLINK_CB(in_skb).pid);

out_free:
kfree_skb(skb);
Expand Down
4 changes: 2 additions & 2 deletions net/decnet/dn_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -375,10 +375,10 @@ static void dn_rtmsg_fib(int event, struct dn_fib_node *f, int z, u32 tb_id,
kfree_skb(skb);
goto errout;
}
err = rtnl_notify(skb, pid, RTNLGRP_DECnet_ROUTE, nlh, GFP_KERNEL);
err = rtnl_notify(skb, &init_net, pid, RTNLGRP_DECnet_ROUTE, nlh, GFP_KERNEL);
errout:
if (err < 0)
rtnl_set_sk_err(RTNLGRP_DECnet_ROUTE, err);
rtnl_set_sk_err(&init_net, RTNLGRP_DECnet_ROUTE, err);
}

static __inline__ int dn_hash_dump_bucket(struct sk_buff *skb,
Expand Down
4 changes: 2 additions & 2 deletions net/ipv4/devinet.c
Original file line number Diff line number Diff line change
Expand Up @@ -1240,10 +1240,10 @@ static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh,
kfree_skb(skb);
goto errout;
}
err = rtnl_notify(skb, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
err = rtnl_notify(skb, &init_net, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
errout:
if (err < 0)
rtnl_set_sk_err(RTNLGRP_IPV4_IFADDR, err);
rtnl_set_sk_err(&init_net, RTNLGRP_IPV4_IFADDR, err);
}

#ifdef CONFIG_SYSCTL
Expand Down
4 changes: 2 additions & 2 deletions net/ipv4/fib_semantics.c
Original file line number Diff line number Diff line change
Expand Up @@ -320,11 +320,11 @@ void rtmsg_fib(int event, __be32 key, struct fib_alias *fa,
kfree_skb(skb);
goto errout;
}
err = rtnl_notify(skb, info->pid, RTNLGRP_IPV4_ROUTE,
err = rtnl_notify(skb, &init_net, info->pid, RTNLGRP_IPV4_ROUTE,
info->nlh, GFP_KERNEL);
errout:
if (err < 0)
rtnl_set_sk_err(RTNLGRP_IPV4_ROUTE, err);
rtnl_set_sk_err(&init_net, RTNLGRP_IPV4_ROUTE, err);
}

/* Return the first fib alias matching TOS with
Expand Down
4 changes: 2 additions & 2 deletions net/ipv4/ipmr.c
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ static void ipmr_destroy_unres(struct mfc_cache *c)
e->error = -ETIMEDOUT;
memset(&e->msg, 0, sizeof(e->msg));

rtnl_unicast(skb, NETLINK_CB(skb).pid);
rtnl_unicast(skb, &init_net, NETLINK_CB(skb).pid);
} else
kfree_skb(skb);
}
Expand Down Expand Up @@ -533,7 +533,7 @@ static void ipmr_cache_resolve(struct mfc_cache *uc, struct mfc_cache *c)
memset(&e->msg, 0, sizeof(e->msg));
}

rtnl_unicast(skb, NETLINK_CB(skb).pid);
rtnl_unicast(skb, &init_net, NETLINK_CB(skb).pid);
} else
ip_mr_forward(skb, c, 0);
}
Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/route.c
Original file line number Diff line number Diff line change
Expand Up @@ -2610,7 +2610,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
if (err <= 0)
goto errout_free;

err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid);
err = rtnl_unicast(skb, &init_net, NETLINK_CB(in_skb).pid);
errout:
return err;

Expand Down
14 changes: 7 additions & 7 deletions net/ipv6/addrconf.c
Original file line number Diff line number Diff line change
Expand Up @@ -3397,7 +3397,7 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh,
kfree_skb(skb);
goto errout_ifa;
}
err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid);
err = rtnl_unicast(skb, &init_net, NETLINK_CB(in_skb).pid);
errout_ifa:
in6_ifa_put(ifa);
errout:
Expand All @@ -3420,10 +3420,10 @@ static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa)
kfree_skb(skb);
goto errout;
}
err = rtnl_notify(skb, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
err = rtnl_notify(skb, &init_net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
errout:
if (err < 0)
rtnl_set_sk_err(RTNLGRP_IPV6_IFADDR, err);
rtnl_set_sk_err(&init_net, RTNLGRP_IPV6_IFADDR, err);
}

static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
Expand Down Expand Up @@ -3628,10 +3628,10 @@ void inet6_ifinfo_notify(int event, struct inet6_dev *idev)
kfree_skb(skb);
goto errout;
}
err = rtnl_notify(skb, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
err = rtnl_notify(skb, &init_net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
errout:
if (err < 0)
rtnl_set_sk_err(RTNLGRP_IPV6_IFADDR, err);
rtnl_set_sk_err(&init_net, RTNLGRP_IPV6_IFADDR, err);
}

static inline size_t inet6_prefix_nlmsg_size(void)
Expand Down Expand Up @@ -3697,10 +3697,10 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev,
kfree_skb(skb);
goto errout;
}
err = rtnl_notify(skb, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC);
err = rtnl_notify(skb, &init_net, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC);
errout:
if (err < 0)
rtnl_set_sk_err(RTNLGRP_IPV6_PREFIX, err);
rtnl_set_sk_err(&init_net, RTNLGRP_IPV6_PREFIX, err);
}

static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
Expand Down
2 changes: 1 addition & 1 deletion net/ipv6/addrlabel.c
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,7 @@ static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh,
goto out;
}

err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid);
err = rtnl_unicast(skb, &init_net, NETLINK_CB(in_skb).pid);
out:
return err;
}
Expand Down
5 changes: 3 additions & 2 deletions net/ipv6/ndisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1049,7 +1049,8 @@ static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
&ipv6_hdr(ra)->saddr);
nlmsg_end(skb, nlh);

err = rtnl_notify(skb, 0, RTNLGRP_ND_USEROPT, NULL, GFP_ATOMIC);
err = rtnl_notify(skb, &init_net, 0, RTNLGRP_ND_USEROPT, NULL,
GFP_ATOMIC);
if (err < 0)
goto errout;

Expand All @@ -1059,7 +1060,7 @@ static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
nlmsg_free(skb);
err = -EMSGSIZE;
errout:
rtnl_set_sk_err(RTNLGRP_ND_USEROPT, err);
rtnl_set_sk_err(&init_net, RTNLGRP_ND_USEROPT, err);
}

static void ndisc_router_discovery(struct sk_buff *skb)
Expand Down
Loading

0 comments on commit 97c53ca

Please sign in to comment.