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