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-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