mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 21:21:41 +00:00
rtnetlink: Add peer_type in struct rtnl_link_ops.
In ops->newlink(), veth, vxcan, and netkit call rtnl_link_get_net() with a net pointer, which is the first argument of ->newlink(). rtnl_link_get_net() could return another netns based on IFLA_NET_NS_PID and IFLA_NET_NS_FD in the peer device's attributes. We want to get it and fill rtnl_nets->nets[] in advance in rtnl_newlink() for per-netns RTNL. All of the three get the peer netns in the same way: 1. Call rtnl_nla_parse_ifinfomsg() 2. Call ops->validate() (vxcan doesn't have) 3. Call rtnl_link_get_net_tb() Let's add a new field peer_type to struct rtnl_link_ops and prefetch netns in the peer ifla to add it to rtnl_nets in rtnl_newlink(). Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com> Reviewed-by: Eric Dumazet <edumazet@google.com> Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org> Link: https://patch.msgid.link/20241108004823.29419-6-kuniyu@amazon.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
cbaaa6326b
commit
28690e5361
@ -75,6 +75,7 @@ static inline int rtnl_msg_family(const struct nlmsghdr *nlh)
|
||||
* @srcu: Used internally
|
||||
* @kind: Identifier
|
||||
* @netns_refund: Physical device, move to init_net on netns exit
|
||||
* @peer_type: Peer device specific netlink attribute number (e.g. VETH_INFO_PEER)
|
||||
* @maxtype: Highest device specific netlink attribute number
|
||||
* @policy: Netlink policy for device specific attribute validation
|
||||
* @validate: Optional validation function for netlink/changelink parameters
|
||||
@ -116,6 +117,7 @@ struct rtnl_link_ops {
|
||||
void (*setup)(struct net_device *dev);
|
||||
|
||||
bool netns_refund;
|
||||
const u16 peer_type;
|
||||
unsigned int maxtype;
|
||||
const struct nla_policy *policy;
|
||||
int (*validate)(struct nlattr *tb[],
|
||||
|
@ -2492,9 +2492,10 @@ int rtnl_nla_parse_ifinfomsg(struct nlattr **tb, const struct nlattr *nla_peer,
|
||||
}
|
||||
EXPORT_SYMBOL(rtnl_nla_parse_ifinfomsg);
|
||||
|
||||
struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[])
|
||||
static struct net *rtnl_link_get_net_ifla(struct nlattr *tb[])
|
||||
{
|
||||
struct net *net;
|
||||
struct net *net = NULL;
|
||||
|
||||
/* Examine the link attributes and figure out which
|
||||
* network namespace we are talking about.
|
||||
*/
|
||||
@ -2502,8 +2503,17 @@ struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[])
|
||||
net = get_net_ns_by_pid(nla_get_u32(tb[IFLA_NET_NS_PID]));
|
||||
else if (tb[IFLA_NET_NS_FD])
|
||||
net = get_net_ns_by_fd(nla_get_u32(tb[IFLA_NET_NS_FD]));
|
||||
else
|
||||
|
||||
return net;
|
||||
}
|
||||
|
||||
struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[])
|
||||
{
|
||||
struct net *net = rtnl_link_get_net_ifla(tb);
|
||||
|
||||
if (!net)
|
||||
net = get_net(src_net);
|
||||
|
||||
return net;
|
||||
}
|
||||
EXPORT_SYMBOL(rtnl_link_get_net);
|
||||
@ -3765,6 +3775,37 @@ out_unregister:
|
||||
goto out;
|
||||
}
|
||||
|
||||
static int rtnl_add_peer_net(struct rtnl_nets *rtnl_nets,
|
||||
const struct rtnl_link_ops *ops,
|
||||
struct nlattr *data[],
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct nlattr *tb[IFLA_MAX + 1];
|
||||
struct net *net;
|
||||
int err;
|
||||
|
||||
if (!data || !data[ops->peer_type])
|
||||
return 0;
|
||||
|
||||
err = rtnl_nla_parse_ifinfomsg(tb, data[ops->peer_type], extack);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (ops->validate) {
|
||||
err = ops->validate(tb, NULL, extack);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
net = rtnl_link_get_net_ifla(tb);
|
||||
if (IS_ERR(net))
|
||||
return PTR_ERR(net);
|
||||
if (net)
|
||||
rtnl_nets_add(rtnl_nets, net);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
const struct rtnl_link_ops *ops,
|
||||
struct net *tgt_net, struct net *link_net,
|
||||
@ -3893,12 +3934,18 @@ static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
if (ret < 0)
|
||||
goto put_ops;
|
||||
}
|
||||
|
||||
if (ops->peer_type) {
|
||||
ret = rtnl_add_peer_net(&rtnl_nets, ops, data, extack);
|
||||
if (ret < 0)
|
||||
goto put_ops;
|
||||
}
|
||||
}
|
||||
|
||||
tgt_net = rtnl_link_get_net_capable(skb, sock_net(skb->sk), tb, CAP_NET_ADMIN);
|
||||
if (IS_ERR(tgt_net)) {
|
||||
ret = PTR_ERR(tgt_net);
|
||||
goto put_ops;
|
||||
goto put_net;
|
||||
}
|
||||
|
||||
rtnl_nets_add(&rtnl_nets, tgt_net);
|
||||
|
Loading…
Reference in New Issue
Block a user