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