1 /* 2 * lib/object.c Generic Cacheable Object 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-2012 Thomas Graf <tgraf (at) suug.ch> 10 */ 11 12 /** 13 * @ingroup core_types 14 * @defgroup object Object (Cacheable) 15 * 16 * Generic object data type, for inheritance purposes to implement cacheable 17 * data types. 18 * 19 * Related sections in the development guide: 20 * 21 * @{ 22 * 23 * Header 24 * ------ 25 * ~~~~{.c} 26 * #include <netlink/object.h> 27 * ~~~~ 28 */ 29 30 #include <netlink-private/netlink.h> 31 #include <netlink/netlink.h> 32 #include <netlink/cache.h> 33 #include <netlink/object.h> 34 #include <netlink/utils.h> 35 36 static inline struct nl_object_ops *obj_ops(struct nl_object *obj) 37 { 38 if (!obj->ce_ops) 39 BUG(); 40 41 return obj->ce_ops; 42 } 43 44 /** 45 * @name Object Creation/Deletion 46 * @{ 47 */ 48 49 /** 50 * Allocate a new object of kind specified by the operations handle 51 * @arg ops cache operations handle 52 * @return The new object or NULL 53 */ 54 struct nl_object *nl_object_alloc(struct nl_object_ops *ops) 55 { 56 struct nl_object *new; 57 58 if (ops->oo_size < sizeof(*new)) 59 BUG(); 60 61 new = calloc(1, ops->oo_size); 62 if (!new) 63 return NULL; 64 65 new->ce_refcnt = 1; 66 nl_init_list_head(&new->ce_list); 67 68 new->ce_ops = ops; 69 if (ops->oo_constructor) 70 ops->oo_constructor(new); 71 72 NL_DBG(4, "Allocated new object %p\n", new); 73 74 return new; 75 } 76 77 /** 78 * Allocate new object of kind specified by the name 79 * @arg kind name of object type 80 * @arg result Result pointer 81 * 82 * @return 0 on success or a negative error code. 83 */ 84 int nl_object_alloc_name(const char *kind, struct nl_object **result) 85 { 86 struct nl_cache_ops *ops; 87 88 ops = nl_cache_ops_lookup_safe(kind); 89 if (!ops) 90 return -NLE_OPNOTSUPP; 91 92 *result = nl_object_alloc(ops->co_obj_ops); 93 nl_cache_ops_put(ops); 94 if (!*result) 95 return -NLE_NOMEM; 96 97 return 0; 98 } 99 100 struct nl_derived_object { 101 NLHDR_COMMON 102 char data; 103 }; 104 105 /** 106 * Allocate a new object and copy all data from an existing object 107 * @arg obj object to inherite data from 108 * @return The new object or NULL. 109 */ 110 struct nl_object *nl_object_clone(struct nl_object *obj) 111 { 112 struct nl_object *new; 113 struct nl_object_ops *ops; 114 int doff = offsetof(struct nl_derived_object, data); 115 int size; 116 117 if (!obj) 118 return NULL; 119 120 ops = obj_ops(obj); 121 new = nl_object_alloc(ops); 122 if (!new) 123 return NULL; 124 125 size = ops->oo_size - doff; 126 if (size < 0) 127 BUG(); 128 129 new->ce_ops = obj->ce_ops; 130 new->ce_msgtype = obj->ce_msgtype; 131 new->ce_mask = obj->ce_mask; 132 133 if (size) 134 memcpy((void *)new + doff, (void *)obj + doff, size); 135 136 if (ops->oo_clone) { 137 if (ops->oo_clone(new, obj) < 0) { 138 nl_object_free(new); 139 return NULL; 140 } 141 } else if (size && ops->oo_free_data) 142 BUG(); 143 144 return new; 145 } 146 147 /** 148 * Merge a cacheable object 149 * @arg dst object to be merged into 150 * @arg src new object to be merged into dst 151 * 152 * @return 0 or a negative error code. 153 */ 154 int nl_object_update(struct nl_object *dst, struct nl_object *src) 155 { 156 struct nl_object_ops *ops = obj_ops(dst); 157 158 if (ops->oo_update) 159 return ops->oo_update(dst, src); 160 161 return -NLE_OPNOTSUPP; 162 } 163 164 /** 165 * Free a cacheable object 166 * @arg obj object to free 167 * 168 * @return 0 or a negative error code. 169 */ 170 void nl_object_free(struct nl_object *obj) 171 { 172 struct nl_object_ops *ops; 173 174 if (!obj) 175 return; 176 177 ops = obj_ops(obj); 178 179 if (obj->ce_refcnt > 0) 180 NL_DBG(1, "Warning: Freeing object in use...\n"); 181 182 if (obj->ce_cache) 183 nl_cache_remove(obj); 184 185 if (ops->oo_free_data) 186 ops->oo_free_data(obj); 187 188 NL_DBG(4, "Freed object %p\n", obj); 189 190 free(obj); 191 } 192 193 /** @} */ 194 195 /** 196 * @name Reference Management 197 * @{ 198 */ 199 200 /** 201 * Acquire a reference on a object 202 * @arg obj object to acquire reference from 203 */ 204 void nl_object_get(struct nl_object *obj) 205 { 206 obj->ce_refcnt++; 207 NL_DBG(4, "New reference to object %p, total %d\n", 208 obj, obj->ce_refcnt); 209 } 210 211 /** 212 * Release a reference from an object 213 * @arg obj object to release reference from 214 */ 215 void nl_object_put(struct nl_object *obj) 216 { 217 if (!obj) 218 return; 219 220 obj->ce_refcnt--; 221 NL_DBG(4, "Returned object reference %p, %d remaining\n", 222 obj, obj->ce_refcnt); 223 224 if (obj->ce_refcnt < 0) 225 BUG(); 226 227 if (obj->ce_refcnt <= 0) 228 nl_object_free(obj); 229 } 230 231 /** 232 * Check whether this object is used by multiple users 233 * @arg obj object to check 234 * @return true or false 235 */ 236 int nl_object_shared(struct nl_object *obj) 237 { 238 return obj->ce_refcnt > 1; 239 } 240 241 /** @} */ 242 243 /** 244 * @name Marks 245 * @{ 246 */ 247 248 /** 249 * Add mark to object 250 * @arg obj Object to mark 251 */ 252 void nl_object_mark(struct nl_object *obj) 253 { 254 obj->ce_flags |= NL_OBJ_MARK; 255 } 256 257 /** 258 * Remove mark from object 259 * @arg obj Object to unmark 260 */ 261 void nl_object_unmark(struct nl_object *obj) 262 { 263 obj->ce_flags &= ~NL_OBJ_MARK; 264 } 265 266 /** 267 * Return true if object is marked 268 * @arg obj Object to check 269 * @return true if object is marked, otherwise false 270 */ 271 int nl_object_is_marked(struct nl_object *obj) 272 { 273 return (obj->ce_flags & NL_OBJ_MARK); 274 } 275 276 /** @} */ 277 278 /** 279 * @name Utillities 280 * @{ 281 */ 282 283 /** 284 * Dump this object according to the specified parameters 285 * @arg obj object to dump 286 * @arg params dumping parameters 287 */ 288 void nl_object_dump(struct nl_object *obj, struct nl_dump_params *params) 289 { 290 if (params->dp_buf) 291 memset(params->dp_buf, 0, params->dp_buflen); 292 293 dump_from_ops(obj, params); 294 } 295 296 void nl_object_dump_buf(struct nl_object *obj, char *buf, size_t len) 297 { 298 struct nl_dump_params dp = { 299 .dp_buf = buf, 300 .dp_buflen = len, 301 }; 302 303 return nl_object_dump(obj, &dp); 304 } 305 306 /** 307 * Check if the identifiers of two objects are identical 308 * @arg a an object 309 * @arg b another object of same type 310 * 311 * @return true if both objects have equal identifiers, otherwise false. 312 */ 313 int nl_object_identical(struct nl_object *a, struct nl_object *b) 314 { 315 struct nl_object_ops *ops = obj_ops(a); 316 uint32_t req_attrs; 317 318 /* Both objects must be of same type */ 319 if (ops != obj_ops(b)) 320 return 0; 321 322 if (ops->oo_id_attrs_get) { 323 int req_attrs_a = ops->oo_id_attrs_get(a); 324 int req_attrs_b = ops->oo_id_attrs_get(b); 325 if (req_attrs_a != req_attrs_b) 326 return 0; 327 req_attrs = req_attrs_a; 328 } else if (ops->oo_id_attrs) { 329 req_attrs = ops->oo_id_attrs; 330 } else { 331 req_attrs = 0xFFFFFFFF; 332 } 333 if (req_attrs == 0xFFFFFFFF) 334 req_attrs = a->ce_mask & b->ce_mask; 335 336 /* Both objects must provide all required attributes to uniquely 337 * identify an object */ 338 if ((a->ce_mask & req_attrs) != req_attrs || 339 (b->ce_mask & req_attrs) != req_attrs) 340 return 0; 341 342 /* Can't judge unless we can compare */ 343 if (ops->oo_compare == NULL) 344 return 0; 345 346 return !(ops->oo_compare(a, b, req_attrs, 0)); 347 } 348 349 /** 350 * Compute bitmask representing difference in attribute values 351 * @arg a an object 352 * @arg b another object of same type 353 * 354 * The bitmask returned is specific to an object type, each bit set represents 355 * an attribute which mismatches in either of the two objects. Unavailability 356 * of an attribute in one object and presence in the other is regarded a 357 * mismatch as well. 358 * 359 * @return Bitmask describing differences or 0 if they are completely identical. 360 */ 361 uint32_t nl_object_diff(struct nl_object *a, struct nl_object *b) 362 { 363 struct nl_object_ops *ops = obj_ops(a); 364 365 if (ops != obj_ops(b) || ops->oo_compare == NULL) 366 return UINT_MAX; 367 368 return ops->oo_compare(a, b, ~0, 0); 369 } 370 371 /** 372 * Match a filter against an object 373 * @arg obj object to check 374 * @arg filter object of same type acting as filter 375 * 376 * @return 1 if the object matches the filter or 0 377 * if no filter procedure is available or if the 378 * filter does not match. 379 */ 380 int nl_object_match_filter(struct nl_object *obj, struct nl_object *filter) 381 { 382 struct nl_object_ops *ops = obj_ops(obj); 383 384 if (ops != obj_ops(filter) || ops->oo_compare == NULL) 385 return 0; 386 387 return !(ops->oo_compare(obj, filter, filter->ce_mask, 388 LOOSE_COMPARISON)); 389 } 390 391 /** 392 * Convert bitmask of attributes to a character string 393 * @arg obj object of same type as attribute bitmask 394 * @arg attrs bitmask of attribute types 395 * @arg buf destination buffer 396 * @arg len length of destination buffer 397 * 398 * Converts the bitmask of attribute types into a list of attribute 399 * names separated by comas. 400 * 401 * @return destination buffer. 402 */ 403 char *nl_object_attrs2str(struct nl_object *obj, uint32_t attrs, 404 char *buf, size_t len) 405 { 406 struct nl_object_ops *ops = obj_ops(obj); 407 408 if (ops->oo_attrs2str != NULL) 409 return ops->oo_attrs2str(attrs, buf, len); 410 else { 411 memset(buf, 0, len); 412 return buf; 413 } 414 } 415 416 /** 417 * Return list of attributes present in an object 418 * @arg obj an object 419 * @arg buf destination buffer 420 * @arg len length of destination buffer 421 * 422 * @return destination buffer. 423 */ 424 char *nl_object_attr_list(struct nl_object *obj, char *buf, size_t len) 425 { 426 return nl_object_attrs2str(obj, obj->ce_mask, buf, len); 427 } 428 429 /** 430 * Generate object hash key 431 * @arg obj the object 432 * @arg hashkey destination buffer to be used for key stream 433 * @arg hashtbl_sz hash table size 434 * 435 * @return hash key in destination buffer 436 */ 437 void nl_object_keygen(struct nl_object *obj, uint32_t *hashkey, 438 uint32_t hashtbl_sz) 439 { 440 struct nl_object_ops *ops = obj_ops(obj); 441 442 if (ops->oo_keygen) 443 ops->oo_keygen(obj, hashkey, hashtbl_sz); 444 else 445 *hashkey = 0; 446 447 return; 448 } 449 450 /** @} */ 451 452 /** 453 * @name Attributes 454 * @{ 455 */ 456 457 /** 458 * Return number of references held 459 * @arg obj object 460 * 461 * @return The number of references held to this object 462 */ 463 int nl_object_get_refcnt(struct nl_object *obj) 464 { 465 return obj->ce_refcnt; 466 } 467 468 /** 469 * Return cache the object is associated with 470 * @arg obj object 471 * 472 * @note The returned pointer is not protected with a reference counter, 473 * it is your responsibility. 474 * 475 * @return Pointer to cache or NULL if not associated with a cache. 476 */ 477 struct nl_cache *nl_object_get_cache(struct nl_object *obj) 478 { 479 return obj->ce_cache; 480 } 481 482 /** 483 * Return the object's type 484 * @arg obj object 485 * 486 * FIXME: link to list of object types 487 * 488 * @return Name of the object type 489 */ 490 const char *nl_object_get_type(const struct nl_object *obj) 491 { 492 if (!obj->ce_ops) 493 BUG(); 494 495 return obj->ce_ops->oo_name; 496 } 497 498 /** 499 * Return the netlink message type the object was derived from 500 * @arg obj object 501 * 502 * @return Netlink message type or 0. 503 */ 504 int nl_object_get_msgtype(const struct nl_object *obj) 505 { 506 return obj->ce_msgtype; 507 } 508 509 /** 510 * Return object operations structure 511 * @arg obj object 512 * 513 * @return Pointer to the object operations structure 514 */ 515 struct nl_object_ops *nl_object_get_ops(const struct nl_object *obj) 516 { 517 return obj->ce_ops; 518 } 519 520 /** 521 * Return object id attribute mask 522 * @arg obj object 523 * 524 * @return object id attribute mask 525 */ 526 uint32_t nl_object_get_id_attrs(struct nl_object *obj) 527 { 528 struct nl_object_ops *ops = obj_ops(obj); 529 uint32_t id_attrs; 530 531 if (!ops) 532 return 0; 533 534 if (ops->oo_id_attrs_get) 535 id_attrs = ops->oo_id_attrs_get(obj); 536 else 537 id_attrs = ops->oo_id_attrs; 538 539 return id_attrs; 540 } 541 542 /** @} */ 543 544 /** @} */ 545