Home | History | Annotate | Download | only in lib
      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