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