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 9 #include "netdev-genl-gen.h" 10 11 static int 12 netdev_nl_dev_fill(struct net_device *netdev, struct sk_buff *rsp, 13 const struct genl_info *info) 14 { 15 void *hdr; 16 17 hdr = genlmsg_iput(rsp, info); 18 if (!hdr) 19 return -EMSGSIZE; 20 21 if (nla_put_u32(rsp, NETDEV_A_DEV_IFINDEX, netdev->ifindex) || 22 nla_put_u64_64bit(rsp, NETDEV_A_DEV_XDP_FEATURES, 23 netdev->xdp_features, NETDEV_A_DEV_PAD)) { 24 genlmsg_cancel(rsp, hdr); 25 return -EINVAL; 26 } 27 28 if (netdev->xdp_features & NETDEV_XDP_ACT_XSK_ZEROCOPY) { 29 if (nla_put_u32(rsp, NETDEV_A_DEV_XDP_ZC_MAX_SEGS, 30 netdev->xdp_zc_max_segs)) { 31 genlmsg_cancel(rsp, hdr); 32 return -EINVAL; 33 } 34 } 35 36 genlmsg_end(rsp, hdr); 37 38 return 0; 39 } 40 41 static void 42 netdev_genl_dev_notify(struct net_device *netdev, int cmd) 43 { 44 struct genl_info info; 45 struct sk_buff *ntf; 46 47 if (!genl_has_listeners(&netdev_nl_family, dev_net(netdev), 48 NETDEV_NLGRP_MGMT)) 49 return; 50 51 genl_info_init_ntf(&info, &netdev_nl_family, cmd); 52 53 ntf = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 54 if (!ntf) 55 return; 56 57 if (netdev_nl_dev_fill(netdev, ntf, &info)) { 58 nlmsg_free(ntf); 59 return; 60 } 61 62 genlmsg_multicast_netns(&netdev_nl_family, dev_net(netdev), ntf, 63 0, NETDEV_NLGRP_MGMT, GFP_KERNEL); 64 } 65 66 int netdev_nl_dev_get_doit(struct sk_buff *skb, struct genl_info *info) 67 { 68 struct net_device *netdev; 69 struct sk_buff *rsp; 70 u32 ifindex; 71 int err; 72 73 if (GENL_REQ_ATTR_CHECK(info, NETDEV_A_DEV_IFINDEX)) 74 return -EINVAL; 75 76 ifindex = nla_get_u32(info->attrs[NETDEV_A_DEV_IFINDEX]); 77 78 rsp = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 79 if (!rsp) 80 return -ENOMEM; 81 82 rtnl_lock(); 83 84 netdev = __dev_get_by_index(genl_info_net(info), ifindex); 85 if (netdev) 86 err = netdev_nl_dev_fill(netdev, rsp, info); 87 else 88 err = -ENODEV; 89 90 rtnl_unlock(); 91 92 if (err) 93 goto err_free_msg; 94 95 return genlmsg_reply(rsp, info); 96 97 err_free_msg: 98 nlmsg_free(rsp); 99 return err; 100 } 101 102 int netdev_nl_dev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) 103 { 104 struct net *net = sock_net(skb->sk); 105 struct net_device *netdev; 106 int err = 0; 107 108 rtnl_lock(); 109 for_each_netdev_dump(net, netdev, cb->args[0]) { 110 err = netdev_nl_dev_fill(netdev, skb, genl_info_dump(cb)); 111 if (err < 0) 112 break; 113 } 114 rtnl_unlock(); 115 116 if (err != -EMSGSIZE) 117 return err; 118 119 return skb->len; 120 } 121 122 static int netdev_genl_netdevice_event(struct notifier_block *nb, 123 unsigned long event, void *ptr) 124 { 125 struct net_device *netdev = netdev_notifier_info_to_dev(ptr); 126 127 switch (event) { 128 case NETDEV_REGISTER: 129 netdev_genl_dev_notify(netdev, NETDEV_CMD_DEV_ADD_NTF); 130 break; 131 case NETDEV_UNREGISTER: 132 netdev_genl_dev_notify(netdev, NETDEV_CMD_DEV_DEL_NTF); 133 break; 134 case NETDEV_XDP_FEAT_CHANGE: 135 netdev_genl_dev_notify(netdev, NETDEV_CMD_DEV_CHANGE_NTF); 136 break; 137 } 138 139 return NOTIFY_OK; 140 } 141 142 static struct notifier_block netdev_genl_nb = { 143 .notifier_call = netdev_genl_netdevice_event, 144 }; 145 146 static int __init netdev_genl_init(void) 147 { 148 int err; 149 150 err = register_netdevice_notifier(&netdev_genl_nb); 151 if (err) 152 return err; 153 154 err = genl_register_family(&netdev_nl_family); 155 if (err) 156 goto err_unreg_ntf; 157 158 return 0; 159 160 err_unreg_ntf: 161 unregister_netdevice_notifier(&netdev_genl_nb); 162 return err; 163 } 164 165 subsys_initcall(netdev_genl_init); 166