xref: /linux/net/core/netdev-genl.c (revision 753c8608f3e579307493a63b9242667aee35a751)
1 // SPDX-License-Identifier: GPL-2.0-only
2 
3 #include <linux/netdevice.h>
4 #include <linux/notifier.h>
5 #include <linux/rtnetlink.h>
6 #include <net/net_namespace.h>
7 #include <net/sock.h>
8 #include <net/xdp.h>
9 #include <net/xdp_sock.h>
10 
11 #include "netdev-genl-gen.h"
12 
13 static int
14 netdev_nl_dev_fill(struct net_device *netdev, struct sk_buff *rsp,
15 		   const struct genl_info *info)
16 {
17 	u64 xsk_features = 0;
18 	u64 xdp_rx_meta = 0;
19 	void *hdr;
20 
21 	hdr = genlmsg_iput(rsp, info);
22 	if (!hdr)
23 		return -EMSGSIZE;
24 
25 #define XDP_METADATA_KFUNC(_, flag, __, xmo) \
26 	if (netdev->xdp_metadata_ops && netdev->xdp_metadata_ops->xmo) \
27 		xdp_rx_meta |= flag;
28 XDP_METADATA_KFUNC_xxx
29 #undef XDP_METADATA_KFUNC
30 
31 	if (netdev->xsk_tx_metadata_ops) {
32 		if (netdev->xsk_tx_metadata_ops->tmo_fill_timestamp)
33 			xsk_features |= NETDEV_XSK_FLAGS_TX_TIMESTAMP;
34 		if (netdev->xsk_tx_metadata_ops->tmo_request_checksum)
35 			xsk_features |= NETDEV_XSK_FLAGS_TX_CHECKSUM;
36 	}
37 
38 	if (nla_put_u32(rsp, NETDEV_A_DEV_IFINDEX, netdev->ifindex) ||
39 	    nla_put_u64_64bit(rsp, NETDEV_A_DEV_XDP_FEATURES,
40 			      netdev->xdp_features, NETDEV_A_DEV_PAD) ||
41 	    nla_put_u64_64bit(rsp, NETDEV_A_DEV_XDP_RX_METADATA_FEATURES,
42 			      xdp_rx_meta, NETDEV_A_DEV_PAD) ||
43 	    nla_put_u64_64bit(rsp, NETDEV_A_DEV_XSK_FEATURES,
44 			      xsk_features, NETDEV_A_DEV_PAD)) {
45 		genlmsg_cancel(rsp, hdr);
46 		return -EINVAL;
47 	}
48 
49 	if (netdev->xdp_features & NETDEV_XDP_ACT_XSK_ZEROCOPY) {
50 		if (nla_put_u32(rsp, NETDEV_A_DEV_XDP_ZC_MAX_SEGS,
51 				netdev->xdp_zc_max_segs)) {
52 			genlmsg_cancel(rsp, hdr);
53 			return -EINVAL;
54 		}
55 	}
56 
57 	genlmsg_end(rsp, hdr);
58 
59 	return 0;
60 }
61 
62 static void
63 netdev_genl_dev_notify(struct net_device *netdev, int cmd)
64 {
65 	struct genl_info info;
66 	struct sk_buff *ntf;
67 
68 	if (!genl_has_listeners(&netdev_nl_family, dev_net(netdev),
69 				NETDEV_NLGRP_MGMT))
70 		return;
71 
72 	genl_info_init_ntf(&info, &netdev_nl_family, cmd);
73 
74 	ntf = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
75 	if (!ntf)
76 		return;
77 
78 	if (netdev_nl_dev_fill(netdev, ntf, &info)) {
79 		nlmsg_free(ntf);
80 		return;
81 	}
82 
83 	genlmsg_multicast_netns(&netdev_nl_family, dev_net(netdev), ntf,
84 				0, NETDEV_NLGRP_MGMT, GFP_KERNEL);
85 }
86 
87 int netdev_nl_dev_get_doit(struct sk_buff *skb, struct genl_info *info)
88 {
89 	struct net_device *netdev;
90 	struct sk_buff *rsp;
91 	u32 ifindex;
92 	int err;
93 
94 	if (GENL_REQ_ATTR_CHECK(info, NETDEV_A_DEV_IFINDEX))
95 		return -EINVAL;
96 
97 	ifindex = nla_get_u32(info->attrs[NETDEV_A_DEV_IFINDEX]);
98 
99 	rsp = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
100 	if (!rsp)
101 		return -ENOMEM;
102 
103 	rtnl_lock();
104 
105 	netdev = __dev_get_by_index(genl_info_net(info), ifindex);
106 	if (netdev)
107 		err = netdev_nl_dev_fill(netdev, rsp, info);
108 	else
109 		err = -ENODEV;
110 
111 	rtnl_unlock();
112 
113 	if (err)
114 		goto err_free_msg;
115 
116 	return genlmsg_reply(rsp, info);
117 
118 err_free_msg:
119 	nlmsg_free(rsp);
120 	return err;
121 }
122 
123 int netdev_nl_dev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
124 {
125 	struct net *net = sock_net(skb->sk);
126 	struct net_device *netdev;
127 	int err = 0;
128 
129 	rtnl_lock();
130 	for_each_netdev_dump(net, netdev, cb->args[0]) {
131 		err = netdev_nl_dev_fill(netdev, skb, genl_info_dump(cb));
132 		if (err < 0)
133 			break;
134 	}
135 	rtnl_unlock();
136 
137 	if (err != -EMSGSIZE)
138 		return err;
139 
140 	return skb->len;
141 }
142 
143 static int netdev_genl_netdevice_event(struct notifier_block *nb,
144 				       unsigned long event, void *ptr)
145 {
146 	struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
147 
148 	switch (event) {
149 	case NETDEV_REGISTER:
150 		netdev_genl_dev_notify(netdev, NETDEV_CMD_DEV_ADD_NTF);
151 		break;
152 	case NETDEV_UNREGISTER:
153 		netdev_genl_dev_notify(netdev, NETDEV_CMD_DEV_DEL_NTF);
154 		break;
155 	case NETDEV_XDP_FEAT_CHANGE:
156 		netdev_genl_dev_notify(netdev, NETDEV_CMD_DEV_CHANGE_NTF);
157 		break;
158 	}
159 
160 	return NOTIFY_OK;
161 }
162 
163 static struct notifier_block netdev_genl_nb = {
164 	.notifier_call	= netdev_genl_netdevice_event,
165 };
166 
167 static int __init netdev_genl_init(void)
168 {
169 	int err;
170 
171 	err = register_netdevice_notifier(&netdev_genl_nb);
172 	if (err)
173 		return err;
174 
175 	err = genl_register_family(&netdev_nl_family);
176 	if (err)
177 		goto err_unreg_ntf;
178 
179 	return 0;
180 
181 err_unreg_ntf:
182 	unregister_netdevice_notifier(&netdev_genl_nb);
183 	return err;
184 }
185 
186 subsys_initcall(netdev_genl_init);
187