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