libnl  3.2.24-rc1
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 = obj_ops(obj);
114  int doff = offsetof(struct nl_derived_object, data);
115  int size;
116 
117  if (!obj)
118  return NULL;
119 
120  new = nl_object_alloc(ops);
121  if (!new)
122  return NULL;
123 
124  size = ops->oo_size - doff;
125  if (size < 0)
126  BUG();
127 
128  new->ce_ops = obj->ce_ops;
129  new->ce_msgtype = obj->ce_msgtype;
130  new->ce_mask = obj->ce_mask;
131 
132  if (size)
133  memcpy((void *)new + doff, (void *)obj + doff, size);
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  free(obj);
188 
189  NL_DBG(4, "Freed object %p\n", 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  return 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 = obj_ops(a);
315  uint32_t req_attrs;
316 
317  /* Both objects must be of same type */
318  if (ops != obj_ops(b))
319  return 0;
320 
321  if (ops->oo_id_attrs_get) {
322  int req_attrs_a = ops->oo_id_attrs_get(a);
323  int req_attrs_b = ops->oo_id_attrs_get(b);
324  if (req_attrs_a != req_attrs_b)
325  return 0;
326  req_attrs = req_attrs_a;
327  } else if (ops->oo_id_attrs) {
328  req_attrs = ops->oo_id_attrs;
329  } else {
330  req_attrs = 0xFFFFFFFF;
331  }
332  if (req_attrs == 0xFFFFFFFF)
333  req_attrs = a->ce_mask & b->ce_mask;
334 
335  /* Both objects must provide all required attributes to uniquely
336  * identify an object */
337  if ((a->ce_mask & req_attrs) != req_attrs ||
338  (b->ce_mask & req_attrs) != req_attrs)
339  return 0;
340 
341  /* Can't judge unless we can compare */
342  if (ops->oo_compare == NULL)
343  return 0;
344 
345  return !(ops->oo_compare(a, b, req_attrs, 0));
346 }
347 
348 /**
349  * Compute bitmask representing difference in attribute values
350  * @arg a an object
351  * @arg b another object of same type
352  *
353  * The bitmask returned is specific to an object type, each bit set represents
354  * an attribute which mismatches in either of the two objects. Unavailability
355  * of an attribute in one object and presence in the other is regarded a
356  * mismatch as well.
357  *
358  * @return Bitmask describing differences or 0 if they are completely identical.
359  */
360 uint32_t nl_object_diff(struct nl_object *a, struct nl_object *b)
361 {
362  struct nl_object_ops *ops = obj_ops(a);
363 
364  if (ops != obj_ops(b) || ops->oo_compare == NULL)
365  return UINT_MAX;
366 
367  return ops->oo_compare(a, b, ~0, 0);
368 }
369 
370 /**
371  * Match a filter against an object
372  * @arg obj object to check
373  * @arg filter object of same type acting as filter
374  *
375  * @return 1 if the object matches the filter or 0
376  * if no filter procedure is available or if the
377  * filter does not match.
378  */
379 int nl_object_match_filter(struct nl_object *obj, struct nl_object *filter)
380 {
381  struct nl_object_ops *ops = obj_ops(obj);
382 
383  if (ops != obj_ops(filter) || ops->oo_compare == NULL)
384  return 0;
385 
386  return !(ops->oo_compare(obj, filter, filter->ce_mask,
387  LOOSE_COMPARISON));
388 }
389 
390 /**
391  * Convert bitmask of attributes to a character string
392  * @arg obj object of same type as attribute bitmask
393  * @arg attrs bitmask of attribute types
394  * @arg buf destination buffer
395  * @arg len length of destination buffer
396  *
397  * Converts the bitmask of attribute types into a list of attribute
398  * names separated by comas.
399  *
400  * @return destination buffer.
401  */
402 char *nl_object_attrs2str(struct nl_object *obj, uint32_t attrs,
403  char *buf, size_t len)
404 {
405  struct nl_object_ops *ops = obj_ops(obj);
406 
407  if (ops->oo_attrs2str != NULL)
408  return ops->oo_attrs2str(attrs, buf, len);
409  else {
410  memset(buf, 0, len);
411  return buf;
412  }
413 }
414 
415 /**
416  * Return list of attributes present in an object
417  * @arg obj an object
418  * @arg buf destination buffer
419  * @arg len length of destination buffer
420  *
421  * @return destination buffer.
422  */
423 char *nl_object_attr_list(struct nl_object *obj, char *buf, size_t len)
424 {
425  return nl_object_attrs2str(obj, obj->ce_mask, buf, len);
426 }
427 
428 /**
429  * Generate object hash key
430  * @arg obj the object
431  * @arg hashkey destination buffer to be used for key stream
432  * @arg hashtbl_sz hash table size
433  *
434  * @return hash key in destination buffer
435  */
436 void nl_object_keygen(struct nl_object *obj, uint32_t *hashkey,
437  uint32_t hashtbl_sz)
438 {
439  struct nl_object_ops *ops = obj_ops(obj);
440 
441  if (ops->oo_keygen)
442  ops->oo_keygen(obj, hashkey, hashtbl_sz);
443  else
444  *hashkey = 0;
445 
446  return;
447 }
448 
449 /** @} */
450 
451 /**
452  * @name Attributes
453  * @{
454  */
455 
456 /**
457  * Return number of references held
458  * @arg obj object
459  *
460  * @return The number of references held to this object
461  */
462 int nl_object_get_refcnt(struct nl_object *obj)
463 {
464  return obj->ce_refcnt;
465 }
466 
467 /**
468  * Return cache the object is associated with
469  * @arg obj object
470  *
471  * @note The returned pointer is not protected with a reference counter,
472  * it is your responsibility.
473  *
474  * @return Pointer to cache or NULL if not associated with a cache.
475  */
476 struct nl_cache *nl_object_get_cache(struct nl_object *obj)
477 {
478  return obj->ce_cache;
479 }
480 
481 /**
482  * Return the object's type
483  * @arg obj object
484  *
485  * FIXME: link to list of object types
486  *
487  * @return Name of the object type
488  */
489 const char *nl_object_get_type(const struct nl_object *obj)
490 {
491  if (!obj->ce_ops)
492  BUG();
493 
494  return obj->ce_ops->oo_name;
495 }
496 
497 /**
498  * Return the netlink message type the object was derived from
499  * @arg obj object
500  *
501  * @return Netlink message type or 0.
502  */
503 int nl_object_get_msgtype(const struct nl_object *obj)
504 {
505  return obj->ce_msgtype;
506 }
507 
508 /**
509  * Return object operations structure
510  * @arg obj object
511  *
512  * @return Pointer to the object operations structure
513  */
514 struct nl_object_ops *nl_object_get_ops(const struct nl_object *obj)
515 {
516  return obj->ce_ops;
517 }
518 
519 /**
520  * Return object id attribute mask
521  * @arg obj object
522  *
523  * @return object id attribute mask
524  */
525 uint32_t nl_object_get_id_attrs(struct nl_object *obj)
526 {
527  struct nl_object_ops *ops = obj_ops(obj);
528  uint32_t id_attrs;
529 
530  if (!ops)
531  return 0;
532 
533  if (ops->oo_id_attrs_get)
534  id_attrs = ops->oo_id_attrs_get(obj);
535  else
536  id_attrs = ops->oo_id_attrs;
537 
538  return id_attrs;
539 }
540 
541 /** @} */
542 
543 /** @} */