dect
/
libnl
Archived
13
0
Fork 0

Export interface to define objects

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.
This commit is contained in:
Thomas Graf 2007-09-15 19:55:38 +02:00
parent 9eb34dc6ca
commit 508685c269
5 changed files with 399 additions and 89 deletions

View 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

View 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

View File

@ -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

View 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

View 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);
}
/** @} */
/** @} */