1 /* 2 * net/core/devlink.c - Network physical/parent device Netlink interface 3 * 4 * Heavily inspired by net/wireless/ 5 * Copyright (c) 2016 Mellanox Technologies. All rights reserved. 6 * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 */ 13 14 #include <linux/kernel.h> 15 #include <linux/module.h> 16 #include <linux/types.h> 17 #include <linux/slab.h> 18 #include <linux/gfp.h> 19 #include <linux/device.h> 20 #include <linux/list.h> 21 #include <linux/netdevice.h> 22 #include <rdma/ib_verbs.h> 23 #include <net/netlink.h> 24 #include <net/genetlink.h> 25 #include <net/rtnetlink.h> 26 #include <net/net_namespace.h> 27 #include <net/sock.h> 28 #include <net/devlink.h> 29 #define CREATE_TRACE_POINTS 30 #include <trace/events/devlink.h> 31 32 static struct devlink_dpipe_field devlink_dpipe_fields_ethernet[] = { 33 { 34 .name = "destination mac", 35 .id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC, 36 .bitwidth = 48, 37 }, 38 }; 39 40 struct devlink_dpipe_header devlink_dpipe_header_ethernet = { 41 .name = "ethernet", 42 .id = DEVLINK_DPIPE_HEADER_ETHERNET, 43 .fields = devlink_dpipe_fields_ethernet, 44 .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ethernet), 45 .global = true, 46 }; 47 EXPORT_SYMBOL(devlink_dpipe_header_ethernet); 48 49 static struct devlink_dpipe_field devlink_dpipe_fields_ipv4[] = { 50 { 51 .name = "destination ip", 52 .id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP, 53 .bitwidth = 32, 54 }, 55 }; 56 57 struct devlink_dpipe_header devlink_dpipe_header_ipv4 = { 58 .name = "ipv4", 59 .id = DEVLINK_DPIPE_HEADER_IPV4, 60 .fields = devlink_dpipe_fields_ipv4, 61 .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv4), 62 .global = true, 63 }; 64 EXPORT_SYMBOL(devlink_dpipe_header_ipv4); 65 66 static struct devlink_dpipe_field devlink_dpipe_fields_ipv6[] = { 67 { 68 .name = "destination ip", 69 .id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP, 70 .bitwidth = 128, 71 }, 72 }; 73 74 struct devlink_dpipe_header devlink_dpipe_header_ipv6 = { 75 .name = "ipv6", 76 .id = DEVLINK_DPIPE_HEADER_IPV6, 77 .fields = devlink_dpipe_fields_ipv6, 78 .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv6), 79 .global = true, 80 }; 81 EXPORT_SYMBOL(devlink_dpipe_header_ipv6); 82 83 EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwmsg); 84 85 static LIST_HEAD(devlink_list); 86 87 /* devlink_mutex 88 * 89 * An overall lock guarding every operation coming from userspace. 90 * It also guards devlink devices list and it is taken when 91 * driver registers/unregisters it. 92 */ 93 static DEFINE_MUTEX(devlink_mutex); 94 95 /* devlink_port_mutex 96 * 97 * Shared lock to guard lists of ports in all devlink devices. 98 */ 99 static DEFINE_MUTEX(devlink_port_mutex); 100 101 static struct net *devlink_net(const struct devlink *devlink) 102 { 103 return read_pnet(&devlink->_net); 104 } 105 106 static void devlink_net_set(struct devlink *devlink, struct net *net) 107 { 108 write_pnet(&devlink->_net, net); 109 } 110 111 static struct devlink *devlink_get_from_attrs(struct net *net, 112 struct nlattr **attrs) 113 { 114 struct devlink *devlink; 115 char *busname; 116 char *devname; 117 118 if (!attrs[DEVLINK_ATTR_BUS_NAME] || !attrs[DEVLINK_ATTR_DEV_NAME]) 119 return ERR_PTR(-EINVAL); 120 121 busname = nla_data(attrs[DEVLINK_ATTR_BUS_NAME]); 122 devname = nla_data(attrs[DEVLINK_ATTR_DEV_NAME]); 123 124 list_for_each_entry(devlink, &devlink_list, list) { 125 if (strcmp(devlink->dev->bus->name, busname) == 0 && 126 strcmp(dev_name(devlink->dev), devname) == 0 && 127 net_eq(devlink_net(devlink), net)) 128 return devlink; 129 } 130 131 return ERR_PTR(-ENODEV); 132 } 133 134 static struct devlink *devlink_get_from_info(struct genl_info *info) 135 { 136 return devlink_get_from_attrs(genl_info_net(info), info->attrs); 137 } 138 139 static struct devlink_port *devlink_port_get_by_index(struct devlink *devlink, 140 int port_index) 141 { 142 struct devlink_port *devlink_port; 143 144 list_for_each_entry(devlink_port, &devlink->port_list, list) { 145 if (devlink_port->index == port_index) 146 return devlink_port; 147 } 148 return NULL; 149 } 150 151 static bool devlink_port_index_exists(struct devlink *devlink, int port_index) 152 { 153 return devlink_port_get_by_index(devlink, port_index); 154 } 155 156 static struct devlink_port *devlink_port_get_from_attrs(struct devlink *devlink, 157 struct nlattr **attrs) 158 { 159 if (attrs[DEVLINK_ATTR_PORT_INDEX]) { 160 u32 port_index = nla_get_u32(attrs[DEVLINK_ATTR_PORT_INDEX]); 161 struct devlink_port *devlink_port; 162 163 devlink_port = devlink_port_get_by_index(devlink, port_index); 164 if (!devlink_port) 165 return ERR_PTR(-ENODEV); 166 return devlink_port; 167 } 168 return ERR_PTR(-EINVAL); 169 } 170 171 static struct devlink_port *devlink_port_get_from_info(struct devlink *devlink, 172 struct genl_info *info) 173 { 174 return devlink_port_get_from_attrs(devlink, info->attrs); 175 } 176 177 struct devlink_sb { 178 struct list_head list; 179 unsigned int index; 180 u32 size; 181 u16 ingress_pools_count; 182 u16 egress_pools_count; 183 u16 ingress_tc_count; 184 u16 egress_tc_count; 185 }; 186 187 static u16 devlink_sb_pool_count(struct devlink_sb *devlink_sb) 188 { 189 return devlink_sb->ingress_pools_count + devlink_sb->egress_pools_count; 190 } 191 192 static struct devlink_sb *devlink_sb_get_by_index(struct devlink *devlink, 193 unsigned int sb_index) 194 { 195 struct devlink_sb *devlink_sb; 196 197 list_for_each_entry(devlink_sb, &devlink->sb_list, list) { 198 if (devlink_sb->index == sb_index) 199 return devlink_sb; 200 } 201 return NULL; 202 } 203 204 static bool devlink_sb_index_exists(struct devlink *devlink, 205 unsigned int sb_index) 206 { 207 return devlink_sb_get_by_index(devlink, sb_index); 208 } 209 210 static struct devlink_sb *devlink_sb_get_from_attrs(struct devlink *devlink, 211 struct nlattr **attrs) 212 { 213 if (attrs[DEVLINK_ATTR_SB_INDEX]) { 214 u32 sb_index = nla_get_u32(attrs[DEVLINK_ATTR_SB_INDEX]); 215 struct devlink_sb *devlink_sb; 216 217 devlink_sb = devlink_sb_get_by_index(devlink, sb_index); 218 if (!devlink_sb) 219 return ERR_PTR(-ENODEV); 220 return devlink_sb; 221 } 222 return ERR_PTR(-EINVAL); 223 } 224 225 static struct devlink_sb *devlink_sb_get_from_info(struct devlink *devlink, 226 struct genl_info *info) 227 { 228 return devlink_sb_get_from_attrs(devlink, info->attrs); 229 } 230 231 static int devlink_sb_pool_index_get_from_attrs(struct devlink_sb *devlink_sb, 232 struct nlattr **attrs, 233 u16 *p_pool_index) 234 { 235 u16 val; 236 237 if (!attrs[DEVLINK_ATTR_SB_POOL_INDEX]) 238 return -EINVAL; 239 240 val = nla_get_u16(attrs[DEVLINK_ATTR_SB_POOL_INDEX]); 241 if (val >= devlink_sb_pool_count(devlink_sb)) 242 return -EINVAL; 243 *p_pool_index = val; 244 return 0; 245 } 246 247 static int devlink_sb_pool_index_get_from_info(struct devlink_sb *devlink_sb, 248 struct genl_info *info, 249 u16 *p_pool_index) 250 { 251 return devlink_sb_pool_index_get_from_attrs(devlink_sb, info->attrs, 252 p_pool_index); 253 } 254 255 static int 256 devlink_sb_pool_type_get_from_attrs(struct nlattr **attrs, 257 enum devlink_sb_pool_type *p_pool_type) 258 { 259 u8 val; 260 261 if (!attrs[DEVLINK_ATTR_SB_POOL_TYPE]) 262 return -EINVAL; 263 264 val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_TYPE]); 265 if (val != DEVLINK_SB_POOL_TYPE_INGRESS && 266 val != DEVLINK_SB_POOL_TYPE_EGRESS) 267 return -EINVAL; 268 *p_pool_type = val; 269 return 0; 270 } 271 272 static int 273 devlink_sb_pool_type_get_from_info(struct genl_info *info, 274 enum devlink_sb_pool_type *p_pool_type) 275 { 276 return devlink_sb_pool_type_get_from_attrs(info->attrs, p_pool_type); 277 } 278 279 static int 280 devlink_sb_th_type_get_from_attrs(struct nlattr **attrs, 281 enum devlink_sb_threshold_type *p_th_type) 282 { 283 u8 val; 284 285 if (!attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]) 286 return -EINVAL; 287 288 val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]); 289 if (val != DEVLINK_SB_THRESHOLD_TYPE_STATIC && 290 val != DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC) 291 return -EINVAL; 292 *p_th_type = val; 293 return 0; 294 } 295 296 static int 297 devlink_sb_th_type_get_from_info(struct genl_info *info, 298 enum devlink_sb_threshold_type *p_th_type) 299 { 300 return devlink_sb_th_type_get_from_attrs(info->attrs, p_th_type); 301 } 302 303 static int 304 devlink_sb_tc_index_get_from_attrs(struct devlink_sb *devlink_sb, 305 struct nlattr **attrs, 306 enum devlink_sb_pool_type pool_type, 307 u16 *p_tc_index) 308 { 309 u16 val; 310 311 if (!attrs[DEVLINK_ATTR_SB_TC_INDEX]) 312 return -EINVAL; 313 314 val = nla_get_u16(attrs[DEVLINK_ATTR_SB_TC_INDEX]); 315 if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS && 316 val >= devlink_sb->ingress_tc_count) 317 return -EINVAL; 318 if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS && 319 val >= devlink_sb->egress_tc_count) 320 return -EINVAL; 321 *p_tc_index = val; 322 return 0; 323 } 324 325 static int 326 devlink_sb_tc_index_get_from_info(struct devlink_sb *devlink_sb, 327 struct genl_info *info, 328 enum devlink_sb_pool_type pool_type, 329 u16 *p_tc_index) 330 { 331 return devlink_sb_tc_index_get_from_attrs(devlink_sb, info->attrs, 332 pool_type, p_tc_index); 333 } 334 335 #define DEVLINK_NL_FLAG_NEED_DEVLINK BIT(0) 336 #define DEVLINK_NL_FLAG_NEED_PORT BIT(1) 337 #define DEVLINK_NL_FLAG_NEED_SB BIT(2) 338 #define DEVLINK_NL_FLAG_LOCK_PORTS BIT(3) 339 /* port is not needed but we need to ensure they don't 340 * change in the middle of command 341 */