1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3 * Copyright (c) 2003-2012 Thomas Graf <[email protected]>
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
obj_ops(struct nl_object * obj)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 */
nl_object_alloc(struct nl_object_ops * ops)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 */
nl_object_alloc_name(const char * kind,struct nl_object ** result)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
101 struct nl_derived_object {
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 */
nl_object_clone(struct nl_object * obj)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 /* 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 */
nl_object_update(struct nl_object * dst,struct nl_object * src)160 int 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 */
nl_object_free(struct nl_object * obj)176 void 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 */
nl_object_get(struct nl_object * obj)210 void 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 */
nl_object_put(struct nl_object * obj)221 void 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 */
nl_object_shared(struct nl_object * obj)242 int 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 */
nl_object_mark(struct nl_object * obj)258 void 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 */
nl_object_unmark(struct nl_object * obj)267 void 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 */
nl_object_is_marked(struct nl_object * obj)277 int 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 */
nl_object_dump(struct nl_object * obj,struct nl_dump_params * params)294 void 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
nl_object_dump_buf(struct nl_object * obj,char * buf,size_t len)302 void 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 */
nl_object_identical(struct nl_object * a,struct nl_object * b)319 int 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 */
nl_object_diff64(struct nl_object * a,struct nl_object * b)371 uint64_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 */
nl_object_diff(struct nl_object * a,struct nl_object * b)395 uint32_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 */
nl_object_match_filter(struct nl_object * obj,struct nl_object * filter)415 int 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 */
nl_object_attrs2str(struct nl_object * obj,uint32_t attrs,char * buf,size_t len)438 char *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 */
nl_object_attr_list(struct nl_object * obj,char * buf,size_t len)459 char *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 */
nl_object_keygen(struct nl_object * obj,uint32_t * hashkey,uint32_t hashtbl_sz)472 void 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 */
nl_object_get_refcnt(struct nl_object * obj)498 int 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 */
nl_object_get_cache(struct nl_object * obj)512 struct 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 */
nl_object_get_type(const struct nl_object * obj)525 const 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 */
nl_object_get_msgtype(const struct nl_object * obj)539 int 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 */
nl_object_get_ops(const struct nl_object * obj)550 struct 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 */
nl_object_get_id_attrs(struct nl_object * obj)561 uint32_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 /** @} */
580