libnl  3.6.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 <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 
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  */
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  */
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 
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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 
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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 /** @} */
struct nl_cache_ops * nl_cache_ops_lookup_safe(const char *name)
Lookup cache operations by name.
Definition: cache_mngt.c:93
void nl_cache_ops_put(struct nl_cache_ops *ops)
Decrement reference counter.
Definition: cache_mngt.c:59
void nl_cache_remove(struct nl_object *obj)
Remove object from cache.
Definition: cache.c:546
int nl_object_alloc_name(const char *kind, struct nl_object **result)
Allocate new object of kind specified by the name.
Definition: object.c:78
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:388
struct nl_object_ops * nl_object_get_ops(const struct nl_object *obj)
Return object operations structure.
Definition: object.c:543
void nl_object_dump(struct nl_object *obj, struct nl_dump_params *params)
Dump this object according to the specified parameters.
Definition: object.c:287
int nl_object_update(struct nl_object *dst, struct nl_object *src)
Merge a cacheable object.
Definition: object.c:153
int nl_object_get_msgtype(const struct nl_object *obj)
Return the netlink message type the object was derived from.
Definition: object.c:532
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:452
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:431
uint64_t nl_object_diff64(struct nl_object *a, struct nl_object *b)
Compute bitmask representing difference in attribute values.
Definition: object.c:364
uint32_t nl_object_get_id_attrs(struct nl_object *obj)
Return object id attribute mask.
Definition: object.c:554
int nl_object_get_refcnt(struct nl_object *obj)
Return number of references held.
Definition: object.c:491
int nl_object_shared(struct nl_object *obj)
Check whether this object is used by multiple users.
Definition: object.c:235
void nl_object_unmark(struct nl_object *obj)
Remove mark from object.
Definition: object.c:260
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:104
void nl_object_put(struct nl_object *obj)
Release a reference from an object.
Definition: object.c:214
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:48
int nl_object_identical(struct nl_object *a, struct nl_object *b)
Check if the identifiers of two objects are identical.
Definition: object.c:312
void nl_object_get(struct nl_object *obj)
Acquire a reference on a object.
Definition: object.c:203
void nl_object_free(struct nl_object *obj)
Free a cacheable object.
Definition: object.c:169
struct nl_cache * nl_object_get_cache(struct nl_object *obj)
Return cache the object is associated with.
Definition: object.c:505
int nl_object_match_filter(struct nl_object *obj, struct nl_object *filter)
Match a filter against an object.
Definition: object.c:408
int nl_object_is_marked(struct nl_object *obj)
Return true if object is marked.
Definition: object.c:270
const char * nl_object_get_type(const struct nl_object *obj)
Return the object's type.
Definition: object.c:518
void nl_object_mark(struct nl_object *obj)
Add mark to object.
Definition: object.c:251
void nl_object_keygen(struct nl_object *obj, uint32_t *hashkey, uint32_t hashtbl_sz)
Generate object hash key.
Definition: object.c:465
Dumping parameters.
Definition: types.h:28
size_t dp_buflen
Length of the buffer dp_buf.
Definition: types.h:87
char * dp_buf
Alternatively the output may be redirected into a buffer.
Definition: types.h:82