]> granicus.if.org Git - libnl/commitdiff
Export interface to define objects
authorThomas Graf <tgraf@suug.ch>
Sat, 15 Sep 2007 17:55:38 +0000 (19:55 +0200)
committerThomas Graf <tgraf@suug.ch>
Sat, 15 Sep 2007 17:55:38 +0000 (19:55 +0200)
This interface was internal so far which required all code defining
objects to be compiled with the sources available.

This change exposes struct nl_object_ops which seems safe as it
is not supposed to be embedded in other structures.

Patch contains extensive documentation to help with the creation
of own object implementations.

include/netlink-local.h
include/netlink-types.h
include/netlink/object-api.h [new file with mode: 0644]
include/netlink/utils.h
lib/utils.c

index a50745cd5acb58f2eeed44537252a9a81f9f314f..f03b795e2753ef93f3a5480f5800ba23b0a3e12f 100644 (file)
@@ -53,6 +53,7 @@ typedef uint64_t      __u64;
 #include <netlink/handlers.h>
 #include <netlink/cache.h>
 #include <netlink/route/tc.h>
+#include <netlink/object-api.h>
 #include <netlink-types.h>
 
 struct trans_tbl {
@@ -120,6 +121,10 @@ static inline int __assert_error(const char *file, int line, char *func,
 
 #define nl_errno(E)    nl_error(E, NULL)
 
+/* backwards compat */
+#define dp_new_line(params, line)      nl_new_line(params, line)
+#define dp_dump(params, fmt, arg...)   nl_dump(params, fmt, ##arg)
+
 static inline int __trans_list_add(int i, const char *a,
                                   struct nl_list_head *head)
 {
@@ -265,26 +270,6 @@ static inline int __str2flags(const char *buf, struct trans_tbl *tbl,
        return 0;
 }
 
-
-static inline void dp_new_line(struct nl_dump_params *params,
-                              int line_nr)
-{
-       if (params->dp_prefix) {
-               int i;
-               for (i = 0; i < params->dp_prefix; i++) {
-                       if (params->dp_fd)
-                               fprintf(params->dp_fd, " ");
-                       else if (params->dp_buf)
-                               strncat(params->dp_buf, " ",
-                                       params->dp_buflen -
-                                       sizeof(params->dp_buf) - 1);
-               }
-       }
-
-       if (params->dp_nl_cb)
-               params->dp_nl_cb(params, line_nr);
-}
-
 static inline void __dp_dump(struct nl_dump_params *parms, const char *fmt,
                             va_list args)
 {
@@ -302,21 +287,12 @@ static inline void __dp_dump(struct nl_dump_params *parms, const char *fmt,
        }
 }
 
-static inline void dp_dump(struct nl_dump_params *parms, const char *fmt, ...)
-{
-       va_list args;
-
-       va_start(args, fmt);
-       __dp_dump(parms, fmt, args);
-       va_end(args);
-}
-
 static inline void dp_dump_line(struct nl_dump_params *parms, int line,
                                const char *fmt, ...)
 {
        va_list args;
 
-       dp_new_line(parms, line);
+       nl_new_line(parms, line);
 
        va_start(args, fmt);
        __dp_dump(parms, fmt, args);
@@ -424,13 +400,4 @@ static inline char *nl_cache_name(struct nl_cache *cache)
                END_OF_MSGTYPES_LIST, \
        }
 
-#define REQUESTED(LIST, ATTR)  ((LIST) & (ATTR))
-#define AVAILABLE(A, B, ATTR)  (((A)->ce_mask & (B)->ce_mask) & (ATTR))
-#define ATTR_MATCH(A, B, ATTR, EXPR)   (!AVAILABLE(A, B, ATTR) || (EXPR))
-#define ATTR_DIFF(LIST, ATTR, A, B, EXPR) \
-({     int diff = 0; \
-       if (REQUESTED(LIST, ATTR) && ATTR_MATCH(A, B, ATTR, EXPR)) \
-               diff = ATTR; \
-       diff; })
-
 #endif
index 7a06582e75f5176ef6bbfc2105c4f86c9713bfea..8fea34c20791dfe7d819c1af346cf0892676669b 100644 (file)
@@ -127,47 +127,6 @@ struct genl_info
 
 #define LOOSE_FLAG_COMPARISON  1
 
-struct nl_object_ops
-{
-       /* Name of object */
-       char *          oo_name;
-
-       /* Size of object structure */
-       size_t          oo_size;
-
-       /* List of attributes needed to uniquely identify the object */
-       uint32_t        oo_id_attrs;
-
-       /**
-        * Called whenever a new object was allocated
-        */
-       void  (*oo_constructor)(struct nl_object *);
-
-       /**
-        * Called whenever a object in the cache gets destroyed, must
-        * free the type specific memory allocations
-        */
-       void  (*oo_free_data)(struct nl_object *);
-
-       /**
-        * Callened whenever an object needs to be cloned
-        */
-       int  (*oo_clone)(struct nl_object *, struct nl_object *);
-
-       /**
-        * Called whenever a dump of a cache object is requested. Must
-        * dump the specified object to the specified file descriptor
-        */
-       int   (*oo_dump[NL_DUMP_MAX+1])(struct nl_object *,
-                                       struct nl_dump_params *);
-
-       int   (*oo_compare)(struct nl_object *, struct nl_object *,
-                           uint32_t, int);
-
-
-       char *(*oo_attrs2str)(int, char *, size_t);
-};
-
 struct nl_af_group
 {
        int                     ag_family;
@@ -207,15 +166,6 @@ struct nl_cache_ops
 
 #define NL_OBJ_MARK            1
 
-#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;
-
 struct nl_object
 {
        NLHDR_COMMON
diff --git a/include/netlink/object-api.h b/include/netlink/object-api.h
new file mode 100644 (file)
index 0000000..2a32f2c
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * 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);
+ *     int line = 1;   // We will print at least one line for sure
+ *
+ *     // 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, line++);
+ *
+ *     // 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);
+ *
+ *     // Return the number of lines dumped
+ *     return line;
+ * }
+ *
+ * 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 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(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.
+        */
+       int   (*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
index 5b9e8af58f40050230127747a96708bed25229ce..0351d3866cf8f08a94c991890e14de61c75611a3 100644 (file)
@@ -69,6 +69,11 @@ extern int   nl_str2ether_proto(const char *);
 extern char *  nl_ip_proto2str(int, char *, size_t);
 extern int     nl_str2ip_proto(const char *);
 
+/* Dumping helpers */
+extern void    nl_new_line(struct nl_dump_params *, int);
+extern void    nl_dump(struct nl_dump_params *, const char *, ...);
+extern void    nl_dump_line(struct nl_dump_params *, int, const char *, ...);
+
 #ifdef __cplusplus
 }
 #endif
index 8b86921a439c781b4c3ed0a4a834cc16945e758e..b591f721c750a377639a67a66eff30e7e31f002e 100644 (file)
@@ -698,4 +698,58 @@ int nl_str2ip_proto(const char *name)
 
 /** @} */
 
+/**
+ * @name Dumping Helpers
+ * @{
+ */
+
+/**
+ * Handle a new line while dumping
+ * @arg params         Dumping parameters
+ * @arg line           Number of lines dumped already.
+ *
+ * This function must be called before dumping any onto a
+ * new line. It will ensure proper prefixing as specified
+ * by the dumping parameters.
+ *
+ * @note This function will NOT dump any newlines itself
+ */
+void nl_new_line(struct nl_dump_params *params, int line)
+{
+       if (params->dp_prefix) {
+               int i;
+               for (i = 0; i < params->dp_prefix; i++) {
+                       if (params->dp_fd)
+                               fprintf(params->dp_fd, " ");
+                       else if (params->dp_buf)
+                               strncat(params->dp_buf, " ",
+                                       params->dp_buflen -
+                                       sizeof(params->dp_buf) - 1);
+               }
+       }
+
+       if (params->dp_nl_cb)
+               params->dp_nl_cb(params, line);
+}
+
+/**
+ * Dump a formatted character string
+ * @arg params         Dumping parameters
+ * @arg fmt            printf style formatting string
+ * @arg ...            Arguments to formatting string
+ *
+ * Dumps a printf style formatting string to the output device
+ * as specified by the dumping parameters.
+ */
+void nl_dump(struct nl_dump_params *params, const char *fmt, ...)
+{
+       va_list args;
+
+       va_start(args, fmt);
+       __dp_dump(params, fmt, args);
+       va_end(args);
+}
+
+/** @} */
+
 /** @} */