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-2008 Thomas Graf <tgraf@suug.ch> 10 */ 11 12/** 13 * @ingroup cache 14 * @defgroup object Object 15 * @{ 16 */ 17 18#include <netlink-local.h> 19#include <netlink/netlink.h> 20#include <netlink/cache.h> 21#include <netlink/object.h> 22#include <netlink/utils.h> 23 24static inline struct nl_object_ops *obj_ops(struct nl_object *obj) 25{ 26 if (!obj->ce_ops) 27 BUG(); 28 29 return obj->ce_ops; 30} 31 32/** 33 * @name Object Creation/Deletion 34 * @{ 35 */ 36 37/** 38 * Allocate a new object of kind specified by the operations handle 39 * @arg ops cache operations handle 40 * @return The new object or NULL 41 */ 42struct nl_object *nl_object_alloc(struct nl_object_ops *ops) 43{ 44 struct nl_object *new; 45 46 if (ops->oo_size < sizeof(*new)) 47 BUG(); 48 49 new = calloc(1, ops->oo_size); 50 if (!new) 51 return NULL; 52 53 new->ce_refcnt = 1; 54 nl_init_list_head(&new->ce_list); 55 56 new->ce_ops = ops; 57 if (ops->oo_constructor) 58 ops->oo_constructor(new); 59 60 NL_DBG(4, "Allocated new object %p\n", new); 61 62 return new; 63} 64 65/** 66 * Allocate a new object of kind specified by the name 67 * @arg kind name of object type 68 * @return The new object or nULL 69 */ 70int nl_object_alloc_name(const char *kind, struct nl_object **result) 71{ 72 struct nl_cache_ops *ops; 73 74 ops = nl_cache_ops_lookup(kind); 75 if (!ops) 76 return -NLE_OPNOTSUPP; 77 78 if (!(*result = nl_object_alloc(ops->co_obj_ops))) 79 return -NLE_NOMEM; 80 81 return 0; 82} 83 84struct nl_derived_object { 85 NLHDR_COMMON 86 char data; 87}; 88 89/** 90 * Allocate a new object and copy all data from an existing object 91 * @arg obj object to inherite data from 92 * @return The new object or NULL. 93 */ 94struct nl_object *nl_object_clone(struct nl_object *obj) 95{ 96 struct nl_object *new; 97 struct nl_object_ops *ops = obj_ops(obj); 98 int doff = offsetof(struct nl_derived_object, data); 99 int size; 100 101 new = nl_object_alloc(ops); 102 if (!new) 103 return NULL; 104 105 size = ops->oo_size - doff; 106 if (size < 0) 107 BUG(); 108 109 new->ce_ops = obj->ce_ops; 110 new->ce_msgtype = obj->ce_msgtype; 111 new->ce_mask = obj->ce_mask; 112 113 if (size) 114 memcpy((void *)new + doff, (void *)obj + doff, size); 115 116 if (ops->oo_clone) { 117 if (ops->oo_clone(new, obj) < 0) { 118 nl_object_free(new); 119 return NULL; 120 } 121 } else if (size && ops->oo_free_data) 122 BUG(); 123 124 return new; 125} 126 127/** 128 * Free a cacheable object 129 * @arg obj object to free 130 * 131 * @return 0 or a negative error code. 132 */ 133void nl_object_free(struct nl_object *obj) 134{ 135 struct nl_object_ops *ops = obj_ops(obj); 136 137 if (obj->ce_refcnt > 0) 138 NL_DBG(1, "Warning: Freeing object in use...\n"); 139 140 if (obj->ce_cache) 141 nl_cache_remove(obj); 142 143 if (ops->oo_free_data) 144 ops->oo_free_data(obj); 145 146 free(obj); 147 148 NL_DBG(4, "Freed object %p\n", obj); 149} 150 151/** @} */ 152 153/** 154 * @name Reference Management 155 * @{ 156 */ 157 158/** 159 * Acquire a reference on a object 160 * @arg obj object to acquire reference from 161 */ 162void nl_object_get(struct nl_object *obj) 163{ 164 obj->ce_refcnt++; 165 NL_DBG(4, "New reference to object %p, total %d\n", 166 obj, obj->ce_refcnt); 167} 168 169/** 170 * Release a reference from an object 171 * @arg obj object to release reference from 172 */ 173void nl_object_put(struct nl_object *obj) 174{ 175 if (!obj) 176 return; 177 178 obj->ce_refcnt--; 179 NL_DBG(4, "Returned object reference %p, %d remaining\n", 180 obj, obj->ce_refcnt); 181 182 if (obj->ce_refcnt < 0) 183 BUG(); 184 185 if (obj->ce_refcnt <= 0) 186 nl_object_free(obj); 187} 188 189/** 190 * Check whether this object is used by multiple users 191 * @arg obj object to check 192 * @return true or false 193 */ 194int nl_object_shared(struct nl_object *obj) 195{ 196 return obj->ce_refcnt > 1; 197} 198 199/** @} */ 200 201/** 202 * @name Marks 203 * @{ 204 */ 205 206/** 207 * Add mark to object 208 * @arg obj Object to mark 209 */ 210void nl_object_mark(struct nl_object *obj) 211{ 212 obj->ce_flags |= NL_OBJ_MARK; 213} 214 215/** 216 * Remove mark from object 217 * @arg obj Object to unmark 218 */ 219void nl_object_unmark(struct nl_object *obj) 220{ 221 obj->ce_flags &= ~NL_OBJ_MARK; 222} 223 224/** 225 * Return true if object is marked 226 * @arg obj Object to check 227 * @return true if object is marked, otherwise false 228 */ 229int nl_object_is_marked(struct nl_object *obj) 230{ 231 return (obj->ce_flags & NL_OBJ_MARK); 232} 233 234/** @} */ 235 236/** 237 * @name Utillities 238 * @{ 239 */ 240 241/** 242 * Dump this object according to the specified parameters 243 * @arg obj object to dump 244 * @arg params dumping parameters 245 */ 246void nl_object_dump(struct nl_object *obj, struct nl_dump_params *params) 247{ 248 dump_from_ops(obj, params); 249} 250 251/** 252 * Check if the identifiers of two objects are identical 253 * @arg a an object 254 * @arg b another object of same type 255 * 256 * @return true if both objects have equal identifiers, otherwise false. 257 */ 258int nl_object_identical(struct nl_object *a, struct nl_object *b) 259{ 260 struct nl_object_ops *ops = obj_ops(a); 261 int req_attrs; 262 263 /* Both objects must be of same type */ 264 if (ops != obj_ops(b)) 265 return 0; 266 267 req_attrs = ops->oo_id_attrs; 268 if (req_attrs == ~0) 269 req_attrs = a->ce_mask & b->ce_mask; 270 271 /* Both objects must provide all required attributes to uniquely 272 * identify an object */ 273 if ((a->ce_mask & req_attrs) != req_attrs || 274 (b->ce_mask & req_attrs) != req_attrs) 275 return 0; 276 277 /* Can't judge unless we can compare */ 278 if (ops->oo_compare == NULL) 279 return 0; 280 281 return !(ops->oo_compare(a, b, req_attrs, 0)); 282} 283 284/** 285 * Compute bitmask representing difference in attribute values 286 * @arg a an object 287 * @arg b another object of same type 288 * 289 * The bitmask returned is specific to an object type, each bit set represents 290 * an attribute which mismatches in either of the two objects. Unavailability 291 * of an attribute in one object and presence in the other is regarded a 292 * mismatch as well. 293 * 294 * @return Bitmask describing differences or 0 if they are completely identical. 295 */ 296uint32_t nl_object_diff(struct nl_object *a, struct nl_object *b) 297{ 298 struct nl_object_ops *ops = obj_ops(a); 299 300 if (ops != obj_ops(b) || ops->oo_compare == NULL) 301 return UINT_MAX; 302 303 return ops->oo_compare(a, b, ~0, 0); 304} 305 306/** 307 * Match a filter against an object 308 * @arg obj object to check 309 * @arg filter object of same type acting as filter 310 * 311 * @return 1 if the object matches the filter or 0 312 * if no filter procedure is available or if the 313 * filter does not match. 314 */ 315int nl_object_match_filter(struct nl_object *obj, struct nl_object *filter) 316{ 317 struct nl_object_ops *ops = obj_ops(obj); 318 319 if (ops != obj_ops(filter) || ops->oo_compare == NULL) 320 return 0; 321 322 return !(ops->oo_compare(obj, filter, filter->ce_mask, 323 LOOSE_COMPARISON)); 324} 325 326/** 327 * Convert bitmask of attributes to a character string 328 * @arg obj object of same type as attribute bitmask 329 * @arg attrs bitmask of attribute types 330 * @arg buf destination buffer 331 * @arg len length of destination buffer 332 * 333 * Converts the bitmask of attribute types into a list of attribute 334 * names separated by comas. 335 * 336 * @return destination buffer. 337 */ 338char *nl_object_attrs2str(struct nl_object *obj, uint32_t attrs, 339 char *buf, size_t len) 340{ 341 struct nl_object_ops *ops = obj_ops(obj); 342 343 if (ops->oo_attrs2str != NULL) 344 return ops->oo_attrs2str(attrs, buf, len); 345 else { 346 memset(buf, 0, len); 347 return buf; 348 } 349} 350 351/** 352 * Return list of attributes present in an object 353 * @arg obj an object 354 * @arg buf destination buffer 355 * @arg len length of destination buffer 356 * 357 * @return destination buffer. 358 */ 359char *nl_object_attr_list(struct nl_object *obj, char *buf, size_t len) 360{ 361 return nl_object_attrs2str(obj, obj->ce_mask, buf, len); 362} 363 364/** @} */ 365 366/** 367 * @name Attributes 368 * @{ 369 */ 370 371int nl_object_get_refcnt(struct nl_object *obj) 372{ 373 return obj->ce_refcnt; 374} 375 376struct nl_cache *nl_object_get_cache(struct nl_object *obj) 377{ 378 return obj->ce_cache; 379} 380 381/** @} */ 382 383/** @} */ 384