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