lh | 9ed821d | 2023-04-07 01:36:19 -0700 | [diff] [blame] | 1 | /* |
| 2 | * netlink-private/object-api.c Object API |
| 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-2013 Thomas Graf <tgraf@suug.ch> |
| 10 | */ |
| 11 | |
| 12 | #ifndef NETLINK_OBJECT_API_H_ |
| 13 | #define NETLINK_OBJECT_API_H_ |
| 14 | |
| 15 | #include <netlink/netlink.h> |
| 16 | #include <netlink/utils.h> |
| 17 | #include <netlink/object.h> |
| 18 | |
| 19 | #ifdef __cplusplus |
| 20 | extern "C" { |
| 21 | #endif |
| 22 | |
| 23 | /** |
| 24 | * @ingroup object |
| 25 | * @defgroup object_api Object API |
| 26 | * @brief |
| 27 | * |
| 28 | * @par 1) Object Definition |
| 29 | * @code |
| 30 | * // Define your object starting with the common object header |
| 31 | * struct my_obj { |
| 32 | * NLHDR_COMMON |
| 33 | * int my_data; |
| 34 | * }; |
| 35 | * |
| 36 | * // Fill out the object operations structure |
| 37 | * struct nl_object_ops my_ops = { |
| 38 | * .oo_name = "my_obj", |
| 39 | * .oo_size = sizeof(struct my_obj), |
| 40 | * }; |
| 41 | * |
| 42 | * // At this point the object can be allocated, you may want to provide a |
| 43 | * // separate _alloc() function to ease allocting objects of this kind. |
| 44 | * struct nl_object *obj = nl_object_alloc(&my_ops); |
| 45 | * |
| 46 | * // And release it again... |
| 47 | * nl_object_put(obj); |
| 48 | * @endcode |
| 49 | * |
| 50 | * @par 2) Allocating additional data |
| 51 | * @code |
| 52 | * // You may require to allocate additional data and store it inside |
| 53 | * // object, f.e. assuming there is a field `ptr'. |
| 54 | * struct my_obj { |
| 55 | * NLHDR_COMMON |
| 56 | * void * ptr; |
| 57 | * }; |
| 58 | * |
| 59 | * // And at some point you may assign allocated data to this field: |
| 60 | * my_obj->ptr = calloc(1, ...); |
| 61 | * |
| 62 | * // In order to not introduce any memory leaks you have to release |
| 63 | * // this data again when the last reference is given back. |
| 64 | * static void my_obj_free_data(struct nl_object *obj) |
| 65 | * { |
| 66 | * struct my_obj *my_obj = nl_object_priv(obj); |
| 67 | * |
| 68 | * free(my_obj->ptr); |
| 69 | * } |
| 70 | * |
| 71 | * // Also when the object is cloned, you must ensure for your pointer |
| 72 | * // stay valid even if one of the clones is freed by either making |
| 73 | * // a clone as well or increase the reference count. |
| 74 | * static int my_obj_clone(struct nl_object *src, struct nl_object *dst) |
| 75 | * { |
| 76 | * struct my_obj *my_src = nl_object_priv(src); |
| 77 | * struct my_obj *my_dst = nl_object_priv(dst); |
| 78 | * |
| 79 | * if (src->ptr) { |
| 80 | * dst->ptr = calloc(1, ...); |
| 81 | * memcpy(dst->ptr, src->ptr, ...); |
| 82 | * } |
| 83 | * } |
| 84 | * |
| 85 | * struct nl_object_ops my_ops = { |
| 86 | * ... |
| 87 | * .oo_free_data = my_obj_free_data, |
| 88 | * .oo_clone = my_obj_clone, |
| 89 | * }; |
| 90 | * @endcode |
| 91 | * |
| 92 | * @par 3) Object Dumping |
| 93 | * @code |
| 94 | * static int my_obj_dump_detailed(struct nl_object *obj, |
| 95 | * struct nl_dump_params *params) |
| 96 | * { |
| 97 | * struct my_obj *my_obj = nl_object_priv(obj); |
| 98 | * |
| 99 | * // It is absolutely essential to use nl_dump() when printing |
| 100 | * // any text to make sure the dumping parameters are respected. |
| 101 | * nl_dump(params, "Obj Integer: %d\n", my_obj->my_int); |
| 102 | * |
| 103 | * // Before we can dump the next line, make sure to prefix |
| 104 | * // this line correctly. |
| 105 | * nl_new_line(params); |
| 106 | * |
| 107 | * // You may also split a line into multiple nl_dump() calls. |
| 108 | * nl_dump(params, "String: %s ", my_obj->my_string); |
| 109 | * nl_dump(params, "String-2: %s\n", my_obj->another_string); |
| 110 | * } |
| 111 | * |
| 112 | * struct nl_object_ops my_ops = { |
| 113 | * ... |
| 114 | * .oo_dump[NL_DUMP_FULL] = my_obj_dump_detailed, |
| 115 | * }; |
| 116 | * @endcode |
| 117 | * |
| 118 | * @par 4) Object Attributes |
| 119 | * @code |
| 120 | * // The concept of object attributes is optional but can ease the typical |
| 121 | * // case of objects that have optional attributes, e.g. a route may have a |
| 122 | * // nexthop assigned but it is not required to. |
| 123 | * |
| 124 | * // The first step to define your object specific bitmask listing all |
| 125 | * // attributes |
| 126 | * #define MY_ATTR_FOO (1<<0) |
| 127 | * #define MY_ATTR_BAR (1<<1) |
| 128 | * |
| 129 | * // When assigning an optional attribute to the object, make sure |
| 130 | * // to mark its availability. |
| 131 | * my_obj->foo = 123123; |
| 132 | * my_obj->ce_mask |= MY_ATTR_FOO; |
| 133 | * |
| 134 | * // At any time you may use this mask to check for the availability |
| 135 | * // of the attribute, e.g. while dumping |
| 136 | * if (my_obj->ce_mask & MY_ATTR_FOO) |
| 137 | * nl_dump(params, "foo %d ", my_obj->foo); |
| 138 | * |
| 139 | * // One of the big advantages of this concept is that it allows for |
| 140 | * // standardized comparisons which make it trivial for caches to |
| 141 | * // identify unique objects by use of unified comparison functions. |
| 142 | * // In order for it to work, your object implementation must provide |
| 143 | * // a comparison function and define a list of attributes which |
| 144 | * // combined together make an object unique. |
| 145 | * |
| 146 | * static int my_obj_compare(struct nl_object *_a, struct nl_object *_b, |
| 147 | * uint32_t attrs, int flags) |
| 148 | * { |
| 149 | * struct my_obj *a = nl_object_priv(_a): |
| 150 | * struct my_obj *b = nl_object_priv(_b): |
| 151 | * int diff = 0; |
| 152 | * |
| 153 | * // We help ourselves in defining our own DIFF macro which will |
| 154 | * // call ATTR_DIFF() on both objects which will make sure to only |
| 155 | * // compare the attributes if required. |
| 156 | * #define MY_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, MY_ATTR_##ATTR, a, b, EXPR) |
| 157 | * |
| 158 | * // Call our own diff macro for each attribute to build a bitmask |
| 159 | * // representing the attributes which mismatch. |
| 160 | * diff |= MY_DIFF(FOO, a->foo != b->foo) |
| 161 | * diff |= MY_DIFF(BAR, strcmp(a->bar, b->bar)) |
| 162 | * |
| 163 | * return diff; |
| 164 | * } |
| 165 | * |
| 166 | * // In order to identify identical objects with differing attributes |
| 167 | * // you must specify the attributes required to uniquely identify |
| 168 | * // your object. Make sure to not include too many attributes, this |
| 169 | * // list is used when caches look for an old version of an object. |
| 170 | * struct nl_object_ops my_ops = { |
| 171 | * ... |
| 172 | * .oo_id_attrs = MY_ATTR_FOO, |
| 173 | * .oo_compare = my_obj_compare, |
| 174 | * }; |
| 175 | * @endcode |
| 176 | * @{ |
| 177 | */ |
| 178 | |
| 179 | /** |
| 180 | * Common Object Header |
| 181 | * |
| 182 | * This macro must be included as first member in every object |
| 183 | * definition to allow objects to be cached. |
| 184 | */ |
| 185 | #define NLHDR_COMMON \ |
| 186 | int ce_refcnt; \ |
| 187 | struct nl_object_ops * ce_ops; \ |
| 188 | struct nl_cache * ce_cache; \ |
| 189 | struct nl_list_head ce_list; \ |
| 190 | int ce_msgtype; \ |
| 191 | int ce_flags; \ |
| 192 | uint32_t ce_mask; |
| 193 | |
| 194 | struct nl_object |
| 195 | { |
| 196 | NLHDR_COMMON |
| 197 | }; |
| 198 | |
| 199 | |
| 200 | /** |
| 201 | * Return true if attribute is available in both objects |
| 202 | * @arg A an object |
| 203 | * @arg B another object |
| 204 | * @arg ATTR attribute bit |
| 205 | * |
| 206 | * @return True if the attribute is available, otherwise false is returned. |
| 207 | */ |
| 208 | #define AVAILABLE(A, B, ATTR) (((A)->ce_mask & (B)->ce_mask) & (ATTR)) |
| 209 | |
| 210 | /** |
| 211 | * Return true if attribute is available in only one of both objects |
| 212 | * @arg A an object |
| 213 | * @arg B another object |
| 214 | * @arg ATTR attribute bit |
| 215 | * |
| 216 | * @return True if the attribute is available in only one of both objects, |
| 217 | * otherwise false is returned. |
| 218 | */ |
| 219 | #define AVAILABLE_MISMATCH(A, B, ATTR) (((A)->ce_mask ^ (B)->ce_mask) & (ATTR)) |
| 220 | |
| 221 | /** |
| 222 | * Return true if attributes mismatch |
| 223 | * @arg A an object |
| 224 | * @arg B another object |
| 225 | * @arg ATTR attribute bit |
| 226 | * @arg EXPR Comparison expression |
| 227 | * |
| 228 | * This function will check if the attribute in question is available |
| 229 | * in both objects, if not this will count as a mismatch. |
| 230 | * |
| 231 | * If available the function will execute the expression which must |
| 232 | * return true if the attributes mismatch. |
| 233 | * |
| 234 | * @return True if the attribute mismatch, or false if they match. |
| 235 | */ |
| 236 | #define ATTR_MISMATCH(A, B, ATTR, EXPR) (AVAILABLE_MISMATCH(A, B, ATTR) || \ |
| 237 | (AVAILABLE(A, B, ATTR) && (EXPR))) |
| 238 | |
| 239 | /** |
| 240 | * Return attribute bit if attribute does not match |
| 241 | * @arg LIST list of attributes to be compared |
| 242 | * @arg ATTR attribute bit |
| 243 | * @arg A an object |
| 244 | * @arg B another object |
| 245 | * @arg EXPR Comparison expression |
| 246 | * |
| 247 | * This function will check if the attribute in question is available |
| 248 | * in both objects, if not this will count as a mismatch. |
| 249 | * |
| 250 | * If available the function will execute the expression which must |
| 251 | * return true if the attributes mismatch. |
| 252 | * |
| 253 | * In case the attributes mismatch, the attribute is returned, otherwise |
| 254 | * 0 is returned. |
| 255 | * |
| 256 | * @code |
| 257 | * diff |= ATTR_DIFF(attrs, MY_ATTR_FOO, a, b, a->foo != b->foo); |
| 258 | * @endcode |
| 259 | */ |
| 260 | #define ATTR_DIFF(LIST, ATTR, A, B, EXPR) \ |
| 261 | ({ int diff = 0; \ |
| 262 | if (((LIST) & (ATTR)) && ATTR_MISMATCH(A, B, ATTR, EXPR)) \ |
| 263 | diff = ATTR; \ |
| 264 | diff; }) |
| 265 | |
| 266 | /** |
| 267 | * Object Operations |
| 268 | */ |
| 269 | struct nl_object_ops |
| 270 | { |
| 271 | /** |
| 272 | * Unique name of object type |
| 273 | * |
| 274 | * Must be in the form family/name, e.g. "route/addr" |
| 275 | */ |
| 276 | char * oo_name; |
| 277 | |
| 278 | /** Size of object including its header */ |
| 279 | size_t oo_size; |
| 280 | |
| 281 | /* List of attributes needed to uniquely identify the object */ |
| 282 | uint32_t oo_id_attrs; |
| 283 | |
| 284 | /** |
| 285 | * Constructor function |
| 286 | * |
| 287 | * Will be called when a new object of this type is allocated. |
| 288 | * Can be used to initialize members such as lists etc. |
| 289 | */ |
| 290 | void (*oo_constructor)(struct nl_object *); |
| 291 | |
| 292 | /** |
| 293 | * Destructor function |
| 294 | * |
| 295 | * Will be called when an object is freed. Must free all |
| 296 | * resources which may have been allocated as part of this |
| 297 | * object. |
| 298 | */ |
| 299 | void (*oo_free_data)(struct nl_object *); |
| 300 | |
| 301 | /** |
| 302 | * Cloning function |
| 303 | * |
| 304 | * Will be called when an object needs to be cloned. Please |
| 305 | * note that the generic object code will make an exact |
| 306 | * copy of the object first, therefore you only need to take |
| 307 | * care of members which require reference counting etc. |
| 308 | * |
| 309 | * May return a negative error code to abort cloning. |
| 310 | */ |
| 311 | int (*oo_clone)(struct nl_object *, struct nl_object *); |
| 312 | |
| 313 | /** |
| 314 | * Dumping functions |
| 315 | * |
| 316 | * Will be called when an object is dumped. The implementations |
| 317 | * have to use nl_dump(), nl_dump_line(), and nl_new_line() to |
| 318 | * dump objects. |
| 319 | * |
| 320 | * The functions must return the number of lines printed. |
| 321 | */ |
| 322 | void (*oo_dump[NL_DUMP_MAX+1])(struct nl_object *, |
| 323 | struct nl_dump_params *); |
| 324 | |
| 325 | /** |
| 326 | * Comparison function |
| 327 | * |
| 328 | * Will be called when two objects of the same type are |
| 329 | * compared. It takes the two objects in question, an object |
| 330 | * specific bitmask defining which attributes should be |
| 331 | * compared and flags to control the behaviour. |
| 332 | * |
| 333 | * The function must return a bitmask with the relevant bit |
| 334 | * set for each attribute that mismatches. |
| 335 | */ |
| 336 | int (*oo_compare)(struct nl_object *, struct nl_object *, |
| 337 | uint32_t, int); |
| 338 | |
| 339 | |
| 340 | /** |
| 341 | * update function |
| 342 | * |
| 343 | * Will be called when the object given by first argument |
| 344 | * needs to be updated with the contents of the second object |
| 345 | * |
| 346 | * The function must return 0 for success and error for failure |
| 347 | * to update. In case of failure its assumed that the original |
| 348 | * object is not touched |
| 349 | */ |
| 350 | int (*oo_update)(struct nl_object *, struct nl_object *); |
| 351 | |
| 352 | /** |
| 353 | * Hash Key generator function |
| 354 | * |
| 355 | * When called returns a hash key for the object being |
| 356 | * referenced. This key will be used by higher level hash functions |
| 357 | * to build association lists. Each object type gets to specify |
| 358 | * it's own key formulation |
| 359 | */ |
| 360 | void (*oo_keygen)(struct nl_object *, uint32_t *, uint32_t); |
| 361 | |
| 362 | char *(*oo_attrs2str)(int, char *, size_t); |
| 363 | |
| 364 | /** |
| 365 | * Get key attributes by family function |
| 366 | */ |
| 367 | uint32_t (*oo_id_attrs_get)(struct nl_object *); |
| 368 | }; |
| 369 | |
| 370 | /** @} */ |
| 371 | |
| 372 | #ifdef __cplusplus |
| 373 | } |
| 374 | #endif |
| 375 | |
| 376 | #endif |