1 /* 2 * lib/route/link/api.c Link Info API 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation version 2.1 7 * of the License. 8 * 9 * Copyright (c) 2003-2008 Thomas Graf <tgraf (at) suug.ch> 10 */ 11 12 /** 13 * @ingroup link 14 * @defgroup link_API Link Modules API 15 * @brief API for modules implementing specific link types/semantics. 16 * 17 * @par 1) Registering/Unregistering a new link info type 18 * @code 19 * static struct rtnl_link_info_ops vlan_info_ops = { 20 * .io_name = "vlan", 21 * .io_alloc = vlan_alloc, 22 * .io_parse = vlan_parse, 23 * .io_dump[NL_DUMP_BRIEF] = vlan_dump_brief, 24 * .io_dump[NL_DUMP_FULL] = vlan_dump_full, 25 * .io_free = vlan_free, 26 * }; 27 * 28 * static void __init vlan_init(void) 29 * { 30 * rtnl_link_register_info(&vlan_info_ops); 31 * } 32 * 33 * static void __exit vlan_exit(void) 34 * { 35 * rtnl_link_unregister_info(&vlan_info_ops); 36 * } 37 * @endcode 38 * 39 * @{ 40 */ 41 42 #include <netlink-private/netlink.h> 43 #include <netlink/netlink.h> 44 #include <netlink/utils.h> 45 #include <netlink/route/link.h> 46 #include <netlink-private/route/link/api.h> 47 48 static NL_LIST_HEAD(info_ops); 49 50 /* lock protecting info_ops and af_ops */ 51 static NL_RW_LOCK(info_lock); 52 53 static struct rtnl_link_info_ops *__rtnl_link_info_ops_lookup(const char *name) 54 { 55 struct rtnl_link_info_ops *ops; 56 57 nl_list_for_each_entry(ops, &info_ops, io_list) 58 if (!strcmp(ops->io_name, name)) 59 return ops; 60 61 return NULL; 62 } 63 64 /** 65 * @name Link Info Modules 66 * @{ 67 */ 68 69 /** 70 * Return operations of a specific link info type 71 * @arg name Name of link info type. 72 * 73 * @note The returned pointer must be given back using rtnl_link_info_ops_put() 74 * 75 * @return Pointer to operations or NULL if unavailable. 76 */ 77 struct rtnl_link_info_ops *rtnl_link_info_ops_lookup(const char *name) 78 { 79 struct rtnl_link_info_ops *ops; 80 81 nl_write_lock(&info_lock); 82 if ((ops = __rtnl_link_info_ops_lookup(name))) 83 ops->io_refcnt++; 84 nl_write_unlock(&info_lock); 85 86 return ops; 87 } 88 89 /** 90 * Give back reference to a set of operations. 91 * @arg ops Link info operations. 92 */ 93 void rtnl_link_info_ops_put(struct rtnl_link_info_ops *ops) 94 { 95 if (ops) 96 ops->io_refcnt--; 97 } 98 99 /** 100 * Register operations for a link info type 101 * @arg ops Link info operations 102 * 103 * This function must be called by modules implementing a specific link 104 * info type. It will make the operations implemented by the module 105 * available for everyone else. 106 * 107 * @return 0 on success or a negative error code. 108 * @return -NLE_INVAL Link info name not specified. 109 * @return -NLE_EXIST Operations for address family already registered. 110 */ 111 int rtnl_link_register_info(struct rtnl_link_info_ops *ops) 112 { 113 int err = 0; 114 115 if (ops->io_name == NULL) 116 return -NLE_INVAL; 117 118 nl_write_lock(&info_lock); 119 if (__rtnl_link_info_ops_lookup(ops->io_name)) { 120 err = -NLE_EXIST; 121 goto errout; 122 } 123 124 NL_DBG(1, "Registered link info operations %s\n", ops->io_name); 125 126 nl_list_add_tail(&ops->io_list, &info_ops); 127 errout: 128 nl_write_unlock(&info_lock); 129 130 return err; 131 } 132 133 /** 134 * Unregister operations for a link info type 135 * @arg ops Link info operations 136 * 137 * This function must be called if a module implementing a specific link 138 * info type is unloaded or becomes unavailable. It must provide a 139 * set of operations which have previously been registered using 140 * rtnl_link_register_info(). 141 * 142 * @return 0 on success or a negative error code 143 * @return _NLE_OPNOTSUPP Link info operations not registered. 144 * @return -NLE_BUSY Link info operations still in use. 145 */ 146 int rtnl_link_unregister_info(struct rtnl_link_info_ops *ops) 147 { 148 struct rtnl_link_info_ops *t; 149 int err = -NLE_OPNOTSUPP; 150 151 nl_write_lock(&info_lock); 152 153 nl_list_for_each_entry(t, &info_ops, io_list) { 154 if (t == ops) { 155 if (t->io_refcnt > 0) { 156 err = -NLE_BUSY; 157 goto errout; 158 } 159 160 nl_list_del(&t->io_list); 161 162 NL_DBG(1, "Unregistered link info operations %s\n", 163 ops->io_name); 164 err = 0; 165 goto errout; 166 } 167 } 168 169 errout: 170 nl_write_unlock(&info_lock); 171 172 return err; 173 } 174 175 /** @} */ 176 177 /** 178 * @name Link Address Family Modules 179 * @{ 180 */ 181 182 static struct rtnl_link_af_ops *af_ops[AF_MAX]; 183 184 /** 185 * Return operations of a specific link address family 186 * @arg family Address family 187 * 188 * @note The returned pointer must be given back using rtnl_link_af_ops_put() 189 * 190 * @return Pointer to operations or NULL if unavailable. 191 */ 192 struct rtnl_link_af_ops *rtnl_link_af_ops_lookup(const unsigned int family) 193 { 194 if (family == AF_UNSPEC || family >= AF_MAX) 195 return NULL; 196 197 nl_write_lock(&info_lock); 198 if (af_ops[family]) 199 af_ops[family]->ao_refcnt++; 200 nl_write_unlock(&info_lock); 201 202 return af_ops[family]; 203 } 204 205 /** 206 * Give back reference to a set of operations. 207 * @arg ops Address family operations. 208 */ 209 void rtnl_link_af_ops_put(struct rtnl_link_af_ops *ops) 210 { 211 if (ops) 212 ops->ao_refcnt--; 213 } 214 215 /** 216 * Allocate and return data buffer for link address family modules 217 * @arg link Link object 218 * @arg ops Address family operations 219 * 220 * This function must be called by link address family modules in all 221 * cases where the API does not provide the data buffer as argument 222 * already. This typically includes set functions the module provides. 223 * Calling this function is strictly required to ensure proper allocation 224 * of the buffer upon first use. Link objects will NOT proactively 225 * allocate a data buffer for each registered link address family. 226 * 227 * @return Pointer to data buffer or NULL on error. 228 */ 229 void *rtnl_link_af_alloc(struct rtnl_link *link, 230 const struct rtnl_link_af_ops *ops) 231 { 232 int family; 233 234 if (!link || !ops) 235 BUG(); 236 237 family = ops->ao_family; 238 239 if (!link->l_af_data[family]) { 240 if (!ops->ao_alloc) 241 BUG(); 242 243 link->l_af_data[family] = ops->ao_alloc(link); 244 if (!link->l_af_data[family]) 245 return NULL; 246 } 247 248 return link->l_af_data[family]; 249 } 250 251 /** 252 * Return data buffer for link address family modules 253 * @arg link Link object 254 * @arg ops Address family operations 255 * 256 * This function returns a pointer to the data buffer for the specified link 257 * address family module or NULL if the buffer was not allocated yet. This 258 * function is typically used by get functions of modules which are not 259 * interested in having the data buffer allocated if no values have been set 260 * yet. 261 * 262 * @return Pointer to data buffer or NULL on error. 263 */ 264 void *rtnl_link_af_data(const struct rtnl_link *link, 265 const struct rtnl_link_af_ops *ops) 266 { 267 if (!link || !ops) 268 BUG(); 269 270 return link->l_af_data[ops->ao_family]; 271 } 272 273 /** 274 * Register operations for a link address family 275 * @arg ops Address family operations 276 * 277 * This function must be called by modules implementing a specific link 278 * address family. It will make the operations implemented by the module 279 * available for everyone else. 280 * 281 * @return 0 on success or a negative error code. 282 * @return -NLE_INVAL Address family is out of range (0..AF_MAX) 283 * @return -NLE_EXIST Operations for address family already registered. 284 */ 285 int rtnl_link_af_register(struct rtnl_link_af_ops *ops) 286 { 287 int err = 0; 288 289 if (ops->ao_family == AF_UNSPEC || ops->ao_family >= AF_MAX) 290 return -NLE_INVAL; 291 292 nl_write_lock(&info_lock); 293 if (af_ops[ops->ao_family]) { 294 err = -NLE_EXIST; 295 goto errout; 296 } 297 298 ops->ao_refcnt = 0; 299 af_ops[ops->ao_family] = ops; 300 301 NL_DBG(1, "Registered link address family operations %u\n", 302 ops->ao_family); 303 304 errout: 305 nl_write_unlock(&info_lock); 306 307 return err; 308 } 309 310 /** 311 * Unregister operations for a link address family 312 * @arg ops Address family operations 313 * 314 * This function must be called if a module implementing a specific link 315 * address family is unloaded or becomes unavailable. It must provide a 316 * set of operations which have previously been registered using 317 * rtnl_link_af_register(). 318 * 319 * @return 0 on success or a negative error code 320 * @return -NLE_INVAL ops is NULL 321 * @return -NLE_OBJ_NOTFOUND Address family operations not registered. 322 * @return -NLE_BUSY Address family operations still in use. 323 */ 324 int rtnl_link_af_unregister(struct rtnl_link_af_ops *ops) 325 { 326 int err = -NLE_INVAL; 327 328 if (!ops) 329 return err; 330 331 nl_write_lock(&info_lock); 332 if (!af_ops[ops->ao_family]) { 333 err = -NLE_OBJ_NOTFOUND; 334 goto errout; 335 } 336 337 if (ops->ao_refcnt > 0) { 338 err = -NLE_BUSY; 339 goto errout; 340 } 341 342 af_ops[ops->ao_family] = NULL; 343 344 NL_DBG(1, "Unregistered link address family operations %u\n", 345 ops->ao_family); 346 347 errout: 348 nl_write_unlock(&info_lock); 349 350 return err; 351 } 352 353 /** 354 * Compare af data for a link address family 355 * @arg a Link object a 356 * @arg b Link object b 357 * @arg family af data family 358 * 359 * This function will compare af_data between two links 360 * a and b of family given by arg family 361 * 362 * @return 0 if address family specific data matches or is not present 363 * or != 0 if it mismatches. 364 */ 365 int rtnl_link_af_data_compare(struct rtnl_link *a, struct rtnl_link *b, 366 int family) 367 { 368 struct rtnl_link_af_ops *af_ops; 369 int ret = 0; 370 371 if (!a->l_af_data[family] && !b->l_af_data[family]) 372 return 0; 373 374 if (!a->l_af_data[family] || !b->l_af_data[family]) 375 return ~0; 376 377 af_ops = rtnl_link_af_ops_lookup(family); 378 if (!af_ops) 379 return ~0; 380 381 if (af_ops->ao_compare == NULL) { 382 ret = ~0; 383 goto out; 384 } 385 386 ret = af_ops->ao_compare(a, b, family, ~0, 0); 387 388 out: 389 rtnl_link_af_ops_put(af_ops); 390 391 return ret; 392 } 393 394 /** @} */ 395 396 /** @} */ 397 398