| /* |
| * netlink/object-api.c Object API |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation version 2.1 |
| * of the License. |
| * |
| * Copyright (c) 2003-2007 Thomas Graf <tgraf@suug.ch> |
| */ |
| |
| #ifndef NETLINK_OBJECT_API_H_ |
| #define NETLINK_OBJECT_API_H_ |
| |
| #include <netlink/netlink.h> |
| #include <netlink/utils.h> |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| /** |
| * @ingroup object |
| * @defgroup object_api Object API |
| * @brief |
| * |
| * @par 1) Object Definition |
| * @code |
| * // Define your object starting with the common object header |
| * struct my_obj { |
| * NLHDR_COMMON |
| * int my_data; |
| * }; |
| * |
| * // Fill out the object operations structure |
| * struct nl_object_ops my_ops = { |
| * .oo_name = "my_obj", |
| * .oo_size = sizeof(struct my_obj), |
| * }; |
| * |
| * // At this point the object can be allocated, you may want to provide a |
| * // separate _alloc() function to ease allocting objects of this kind. |
| * struct nl_object *obj = nl_object_alloc(&my_ops); |
| * |
| * // And release it again... |
| * nl_object_put(obj); |
| * @endcode |
| * |
| * @par 2) Allocating additional data |
| * @code |
| * // You may require to allocate additional data and store it inside |
| * // object, f.e. assuming there is a field `ptr'. |
| * struct my_obj { |
| * NLHDR_COMMON |
| * void * ptr; |
| * }; |
| * |
| * // And at some point you may assign allocated data to this field: |
| * my_obj->ptr = calloc(1, ...); |
| * |
| * // In order to not introduce any memory leaks you have to release |
| * // this data again when the last reference is given back. |
| * static void my_obj_free_data(struct nl_object *obj) |
| * { |
| * struct my_obj *my_obj = nl_object_priv(obj); |
| * |
| * free(my_obj->ptr); |
| * } |
| * |
| * // Also when the object is cloned, you must ensure for your pointer |
| * // stay valid even if one of the clones is freed by either making |
| * // a clone as well or increase the reference count. |
| * static int my_obj_clone(struct nl_object *src, struct nl_object *dst) |
| * { |
| * struct my_obj *my_src = nl_object_priv(src); |
| * struct my_obj *my_dst = nl_object_priv(dst); |
| * |
| * if (src->ptr) { |
| * dst->ptr = calloc(1, ...); |
| * memcpy(dst->ptr, src->ptr, ...); |
| * } |
| * } |
| * |
| * struct nl_object_ops my_ops = { |
| * ... |
| * .oo_free_data = my_obj_free_data, |
| * .oo_clone = my_obj_clone, |
| * }; |
| * @endcode |
| * |
| * @par 3) Object Dumping |
| * @code |
| * static int my_obj_dump_detailed(struct nl_object *obj, |
| * struct nl_dump_params *params) |
| * { |
| * struct my_obj *my_obj = nl_object_priv(obj); |
| * |
| * // It is absolutely essential to use nl_dump() when printing |
| * // any text to make sure the dumping parameters are respected. |
| * nl_dump(params, "Obj Integer: %d\n", my_obj->my_int); |
| * |
| * // Before we can dump the next line, make sure to prefix |
| * // this line correctly. |
| * nl_new_line(params); |
| * |
| * // You may also split a line into multiple nl_dump() calls. |
| * nl_dump(params, "String: %s ", my_obj->my_string); |
| * nl_dump(params, "String-2: %s\n", my_obj->another_string); |
| * } |
| * |
| * struct nl_object_ops my_ops = { |
| * ... |
| * .oo_dump[NL_DUMP_FULL] = my_obj_dump_detailed, |
| * }; |
| * @endcode |
| * |
| * @par 4) Object Attributes |
| * @code |
| * // The concept of object attributes is optional but can ease the typical |
| * // case of objects that have optional attributes, e.g. a route may have a |
| * // nexthop assigned but it is not required to. |
| * |
| * // The first step to define your object specific bitmask listing all |
| * // attributes |
| * #define MY_ATTR_FOO (1<<0) |
| * #define MY_ATTR_BAR (1<<1) |
| * |
| * // When assigning an optional attribute to the object, make sure |
| * // to mark its availability. |
| * my_obj->foo = 123123; |
| * my_obj->ce_mask |= MY_ATTR_FOO; |
| * |
| * // At any time you may use this mask to check for the availability |
| * // of the attribute, e.g. while dumping |
| * if (my_obj->ce_mask & MY_ATTR_FOO) |
| * nl_dump(params, "foo %d ", my_obj->foo); |
| * |
| * // One of the big advantages of this concept is that it allows for |
| * // standardized comparisons which make it trivial for caches to |
| * // identify unique objects by use of unified comparison functions. |
| * // In order for it to work, your object implementation must provide |
| * // a comparison function and define a list of attributes which |
| * // combined together make an object unique. |
| * |
| * static int my_obj_compare(struct nl_object *_a, struct nl_object *_b, |
| * uint32_t attrs, int flags) |
| * { |
| * struct my_obj *a = nl_object_priv(_a): |
| * struct my_obj *b = nl_object_priv(_b): |
| * int diff = 0; |
| * |
| * // We help ourselves in defining our own DIFF macro which will |
| * // call ATTR_DIFF() on both objects which will make sure to only |
| * // compare the attributes if required. |
| * #define MY_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, MY_ATTR_##ATTR, a, b, EXPR) |
| * |
| * // Call our own diff macro for each attribute to build a bitmask |
| * // representing the attributes which mismatch. |
| * diff |= MY_DIFF(FOO, a->foo != b->foo) |
| * diff |= MY_DIFF(BAR, strcmp(a->bar, b->bar)) |
| * |
| * return diff; |
| * } |
| * |
| * // In order to identify identical objects with differing attributes |
| * // you must specify the attributes required to uniquely identify |
| * // your object. Make sure to not include too many attributes, this |
| * // list is used when caches look for an old version of an object. |
| * struct nl_object_ops my_ops = { |
| * ... |
| * .oo_id_attrs = MY_ATTR_FOO, |
| * .oo_compare = my_obj_compare, |
| * }; |
| * @endcode |
| * @{ |
| */ |
| |
| /** |
| * Common Object Header |
| * |
| * This macro must be included as first member in every object |
| * definition to allow objects to be cached. |
| */ |
| #define NLHDR_COMMON \ |
| int ce_refcnt; \ |
| struct nl_object_ops * ce_ops; \ |
| struct nl_cache * ce_cache; \ |
| struct nl_list_head ce_list; \ |
| int ce_msgtype; \ |
| int ce_flags; \ |
| uint32_t ce_mask; |
| |
| /** |
| * Return true if attribute is available in both objects |
| * @arg A an object |
| * @arg B another object |
| * @arg ATTR attribute bit |
| * |
| * @return True if the attribute is available, otherwise false is returned. |
| */ |
| #define AVAILABLE(A, B, ATTR) (((A)->ce_mask & (B)->ce_mask) & (ATTR)) |
| |
| /** |
| * Return true if attribute is available in only one of both objects |
| * @arg A an object |
| * @arg B another object |
| * @arg ATTR attribute bit |
| * |
| * @return True if the attribute is available in only one of both objects, |
| * otherwise false is returned. |
| */ |
| #define AVAILABLE_MISMATCH(A, B, ATTR) (((A)->ce_mask ^ (B)->ce_mask) & (ATTR)) |
| |
| /** |
| * Return true if attributes mismatch |
| * @arg A an object |
| * @arg B another object |
| * @arg ATTR attribute bit |
| * @arg EXPR Comparison expression |
| * |
| * This function will check if the attribute in question is available |
| * in both objects, if not this will count as a mismatch. |
| * |
| * If available the function will execute the expression which must |
| * return true if the attributes mismatch. |
| * |
| * @return True if the attribute mismatch, or false if they match. |
| */ |
| #define ATTR_MISMATCH(A, B, ATTR, EXPR) (AVAILABLE_MISMATCH(A, B, ATTR) || \ |
| (AVAILABLE(A, B, ATTR) && (EXPR))) |
| |
| /** |
| * Return attribute bit if attribute does not match |
| * @arg LIST list of attributes to be compared |
| * @arg ATTR attribute bit |
| * @arg A an object |
| * @arg B another object |
| * @arg EXPR Comparison expression |
| * |
| * This function will check if the attribute in question is available |
| * in both objects, if not this will count as a mismatch. |
| * |
| * If available the function will execute the expression which must |
| * return true if the attributes mismatch. |
| * |
| * In case the attributes mismatch, the attribute is returned, otherwise |
| * 0 is returned. |
| * |
| * @code |
| * diff |= ATTR_DIFF(attrs, MY_ATTR_FOO, a, b, a->foo != b->foo); |
| * @endcode |
| */ |
| #define ATTR_DIFF(LIST, ATTR, A, B, EXPR) \ |
| ({ int diff = 0; \ |
| if (((LIST) & (ATTR)) && ATTR_MISMATCH(A, B, ATTR, EXPR)) \ |
| diff = ATTR; \ |
| diff; }) |
| |
| /** |
| * Object Operations |
| */ |
| struct nl_object_ops |
| { |
| /** |
| * Unique name of object type |
| * |
| * Must be in the form family/name, e.g. "route/addr" |
| */ |
| char * oo_name; |
| |
| /** Size of object including its header */ |
| size_t oo_size; |
| |
| /* List of attributes needed to uniquely identify the object */ |
| uint32_t oo_id_attrs; |
| |
| /** |
| * Constructor function |
| * |
| * Will be called when a new object of this type is allocated. |
| * Can be used to initialize members such as lists etc. |
| */ |
| void (*oo_constructor)(struct nl_object *); |
| |
| /** |
| * Destructor function |
| * |
| * Will be called when an object is freed. Must free all |
| * resources which may have been allocated as part of this |
| * object. |
| */ |
| void (*oo_free_data)(struct nl_object *); |
| |
| /** |
| * Cloning function |
| * |
| * Will be called when an object needs to be cloned. Please |
| * note that the generic object code will make an exact |
| * copy of the object first, therefore you only need to take |
| * care of members which require reference counting etc. |
| * |
| * May return a negative error code to abort cloning. |
| */ |
| int (*oo_clone)(struct nl_object *, struct nl_object *); |
| |
| /** |
| * Dumping functions |
| * |
| * Will be called when an object is dumped. The implementations |
| * have to use nl_dump(), nl_dump_line(), and nl_new_line() to |
| * dump objects. |
| * |
| * The functions must return the number of lines printed. |
| */ |
| void (*oo_dump[NL_DUMP_MAX+1])(struct nl_object *, |
| struct nl_dump_params *); |
| |
| /** |
| * Comparison function |
| * |
| * Will be called when two objects of the same type are |
| * compared. It takes the two objects in question, an object |
| * specific bitmask defining which attributes should be |
| * compared and flags to control the behaviour. |
| * |
| * The function must return a bitmask with the relevant bit |
| * set for each attribute that mismatches. |
| */ |
| int (*oo_compare)(struct nl_object *, struct nl_object *, |
| uint32_t, int); |
| |
| |
| char *(*oo_attrs2str)(int, char *, size_t); |
| }; |
| |
| /** @} */ |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #endif |