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 (at) 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 24 static 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 */ 42 struct 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 */ 70 int 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 84 struct 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 */ 94 struct 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 */ 133 void 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 */ 162 void 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 */ 173 void 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 */ 194 int 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 */ 210 void 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 */ 219 void 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 */ 229 int 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 */ 246 void 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 */ 258 int 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 */ 296 uint32_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 */ 315 int 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 */ 338 char *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 */ 359 char *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 371 int nl_object_get_refcnt(struct nl_object *obj) 372 { 373 return obj->ce_refcnt; 374 } 375 376 struct nl_cache *nl_object_get_cache(struct nl_object *obj) 377 { 378 return obj->ce_cache; 379 } 380 381 /** @} */ 382 383 /** @} */ 384