summaryrefslogtreecommitdiffstats
path: root/sys/netgraph/netgraph.h
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netgraph/netgraph.h')
-rw-r--r--sys/netgraph/netgraph.h440
1 files changed, 373 insertions, 67 deletions
diff --git a/sys/netgraph/netgraph.h b/sys/netgraph/netgraph.h
index 56cf7d6f..323aacc 100644
--- a/sys/netgraph/netgraph.h
+++ b/sys/netgraph/netgraph.h
@@ -51,11 +51,24 @@
#error "This file should not be included in user level programs"
#endif
+#include <sys/mutex.h>
+
+/* The structure for queueing across ISR switches */
+struct ng_item ; /* forward reference */
+typedef struct ng_item *item_p;
+struct ng_queue {
+ u_long q_flags;
+ struct mtx q_mtx;
+ item_p queue;
+ item_p *last;
+ struct ng_node *q_node; /* find the front of the node.. */
+};
+
/*
* Structure of a hook
*/
struct ng_hook {
- char *name; /* what this node knows this link as */
+ char name[NG_HOOKLEN+1];/* what this node knows this link as */
void *private; /* node dependant ID for this hook */
int flags; /* info about this hook/link */
int refs; /* dont actually free this till 0 */
@@ -68,30 +81,32 @@ typedef struct ng_hook *hook_p;
/* Flags for a hook */
#define HK_INVALID 0x0001 /* don't trust it! */
#define HK_QUEUE 0x0002 /* queue for later delivery */
+#define HK_FORCE_WRITER 0x0004 /* Incoming data queued as a writer */
/*
* Structure of a node
*/
struct ng_node {
- char *name; /* optional globally unique name */
+ char name[NG_NODELEN+1]; /* optional globally unique name */
struct ng_type *type; /* the installed 'type' */
int flags; /* see below for bit definitions */
- int sleepers; /* #procs sleeping on this node */
int refs; /* number of references to this node */
int numhooks; /* number of hooks */
- int colour; /* for graph colouring algorithms */
void *private; /* node type dependant node ID */
ng_ID_t ID; /* Unique per node */
LIST_HEAD(hooks, ng_hook) hooks; /* linked list of node hooks */
LIST_ENTRY(ng_node) nodes; /* linked list of all nodes */
LIST_ENTRY(ng_node) idnodes; /* ID hash collision list */
+ TAILQ_ENTRY(ng_node) work; /* nodes with work to do */
+ struct ng_queue input_queue; /* input queue for locking */
};
typedef struct ng_node *node_p;
/* Flags for a node */
-#define NG_INVALID 0x001 /* free when all sleepers and refs go to 0 */
-#define NG_BUSY 0x002 /* callers should sleep or wait */
-#define NG_TOUCHED 0x004 /* to avoid cycles when 'flooding' */
+#define NG_INVALID 0x00000001 /* free when refs go to 0 */
+#define NG_WORKQ 0x00000002 /* node is on the work queue */
+#define NG_FORCE_WRITER 0x00000004 /* Never multithread this node */
+#define NG_CLOSING 0x00000008 /* ng_rmnode() at work */
#define NGF_TYPE1 0x10000000 /* reserved for type specific storage */
#define NGF_TYPE2 0x20000000 /* reserved for type specific storage */
#define NGF_TYPE3 0x40000000 /* reserved for type specific storage */
@@ -131,18 +146,15 @@ typedef struct ng_meta *meta_p;
#define NGMF_TRACE 0x02 /* trace when handing this data to a node */
/* node method definitions */
-typedef int ng_constructor_t(node_p *node);
-typedef int ng_rcvmsg_t(node_p node, struct ng_mesg *msg,
- const char *retaddr, struct ng_mesg **resp,
- hook_p lasthook);
+typedef int ng_constructor_t(node_p node);
+typedef int ng_rcvmsg_t(node_p node, item_p item, hook_p lasthook);
typedef int ng_shutdown_t(node_p node);
typedef int ng_newhook_t(node_p node, hook_p hook, const char *name);
typedef hook_p ng_findhook_t(node_p node, const char *name);
typedef int ng_connect_t(hook_p hook);
-typedef int ng_rcvdata_t(hook_p hook, struct mbuf *m, meta_p meta,
- struct mbuf **ret_m, meta_p *ret_meta, struct ng_mesg **resp);
+typedef int ng_rcvdata_t(hook_p hook, item_p item);
typedef int ng_disconnect_t(hook_p hook);
-
+typedef int ng_rcvitem (node_p node, hook_p hook, item_p item);
/*
* Command list -- each node type specifies the command that it knows
* how to convert between ASCII and binary using an array of these.
@@ -191,73 +203,371 @@ struct ng_type {
int refs; /* number of instances */
};
+struct ng_item {
+ u_long el_flags;
+ item_p el_next;
+ node_p el_dest; /* The node it will be applied against (or NULL) */
+ hook_p el_hook; /* Entering hook. Optional in Control messages */
+ union {
+ struct {
+ struct mbuf *da_m;
+ meta_p da_meta;
+ } data;
+ struct {
+ struct ng_mesg *msg_msg;
+ ng_ID_t msg_retaddr;
+ } msg;
+ } body;
+#define ITEM_DEBUG
+#ifdef ITEM_DEBUG
+ char *lastfile;
+ int lastline;
+ TAILQ_ENTRY(ng_item) all; /* all existing items */
+#endif /* ITEM_DEBUG */
+};
+#define NGQF_D_M 0x01 /* MASK of data/message */
+#define NGQF_DATA 0x01 /* the queue element is data */
+#define NGQF_MESG 0x00 /* the queue element is a message */
+#define NGQF_TYPE 0x02 /* MASK for queue entry type */
+#define NGQF_READER 0x02 /* queued as a reader */
+#define NGQF_WRITER 0x00 /* queued as a writer */
+#define NGQF_FREE 0x04
+
/*
* This defines the in-kernel binary interface version.
* It is possible to change this but leave the external message
* API the same. Each type also has it's own cookies for versioning as well.
+ * Change it for ITEM_DEBUG version so we cannot mix debug and non debug
+ * modules.
*/
-#define NG_ABI_VERSION 5
+#define _NG_ABI_VERSION 5
+#ifdef ITEM_DEBUG
+#define NG_ABI_VERSION (_NG_ABI_VERSION + 0x10000)
+#else /* ITEM_DEBUG */
+#define NG_ABI_VERSION _NG_ABI_VERSION
+#endif /* ITEM_DEBUG */
+
+/**********************************************************************
+* Queue item macros. Peek and extract values.
+**********************************************************************/
+/*
+ * Get the mbuf (etc) out of an item.
+ * Sets the value in the item to NULL in case we need to call NG_FREE_ITEM()
+ * with it, (to avoid freeing the things twice).
+ * If you don't want to zero out the item then realise that the
+ * item still owns it.
+ * Retaddr is different. There are no references on that. It's just a number.
+ * The debug versions must be either all used everywhere or not at all.
+ */
+
+#define _NGI_M(i) ((i)->body.data.da_m)
+#define _NGI_META(i) ((i)->body.data.da_meta)
+#define _NGI_MSG(i) ((i)->body.msg.msg_msg)
+#define _NGI_RETADDR(i) ((i)->body.msg.msg_retaddr)
+
+#ifdef ITEM_DEBUG
+void dumpitem(item_p item, char *file, int line);
+static __inline void _ngi_check(item_p item, char *file, int line) ;
+static __inline struct mbuf ** _ngi_m(item_p item, char *file, int line) ;
+static __inline meta_p * _ngi_meta(item_p item, char *file, int line) ;
+static __inline struct ng_mesg ** _ngi_msg(item_p item, char *file, int line) ;
+static __inline ng_ID_t * _ngi_retaddr(item_p item, char *file, int line) ;
+
+static __inline void
+_ngi_check(item_p item, char *file, int line)
+{
+ if (item->el_flags & NGQF_FREE) {
+ dumpitem(item, file, line);
+ panic ("free item!");
+ }
+ (item)->lastline = line;
+ (item)->lastfile = file;
+}
+
+static __inline struct mbuf **
+_ngi_m(item_p item, char *file, int line)
+{
+ _ngi_check(item, file, line);
+ return (&_NGI_M(item));
+}
+
+static __inline meta_p *
+_ngi_meta(item_p item, char *file, int line)
+{
+ _ngi_check(item, file, line);
+ return (&_NGI_META(item));
+}
+
+static __inline struct ng_mesg **
+_ngi_msg(item_p item, char *file, int line)
+{
+ _ngi_check(item, file, line);
+ return (&_NGI_MSG(item));
+}
+
+static __inline ng_ID_t *
+_ngi_retaddr(item_p item, char *file, int line)
+{
+ _ngi_check(item, file, line);
+ return (&_NGI_RETADDR(item));
+}
+
+#define NGI_M(i) (*_ngi_m(i, __FILE__, __LINE__))
+
+#define NGI_META(i) (*_ngi_meta(i, __FILE__, __LINE__))
+
+#define NGI_MSG(i) (*_ngi_msg(i, __FILE__, __LINE__))
+
+#define NGI_RETADDR(i) (*_ngi_retaddr(i, __FILE__, __LINE__))
+
+#define NGI_GET_M(i,m) \
+ do { \
+ m = NGI_M(i); \
+ _NGI_M(i) = NULL; \
+ } while (0)
+
+#define NGI_GET_META(i,m) \
+ do { \
+ m = NGI_META(i); \
+ _NGI_META(i) = NULL; \
+ } while (0)
+
+#define NGI_GET_MSG(i,m) \
+ do { \
+ m = NGI_MSG(i); \
+ _NGI_MSG(i) = NULL; \
+ } while (0)
+
+#define NG_FREE_ITEM(item) \
+ do { \
+ _ngi_check(item, __FILE__, __LINE__); \
+ ng_free_item((item)); \
+ } while (0)
-/* Send data packet with meta-data */
-#define NG_SEND_DATA(err, hook, m, meta) \
+#define SAVE_LINE(item) \
do { \
- (err) = ng_send_data((hook), (m), (meta), \
- NULL, NULL, NULL); \
+ (item)->lastline = __LINE__; \
+ (item)->lastfile = __FILE__; \
+ } while (0)
+
+#else /* ITEM_DEBUG */
+
+
+#define NGI_M(i) _NGI_M(i)
+#define NGI_META(i) _NGI_META(i)
+#define NGI_MSG(i) _NGI_MSG(i)
+#define NGI_RETADDR(i) _NGI_RETADDR(i)
+
+#define NGI_GET_M(i,m) do {m = NGI_M(i); NGI_M(i) = NULL; } while (0)
+#define NGI_GET_META(i,m) do {m = NGI_META(i); NGI_META(i) = NULL;} while (0)
+#define NGI_GET_MSG(i,m) do {m = NGI_MSG(i); NGI_MSG(i) = NULL; } while (0)
+
+#define NG_FREE_ITEM(item) ng_free_item((item))
+#define SAVE_LINE(item)
+
+#endif /* ITEM_DEBUG */
+
+/**********************************************************************
+* Data macros. Send, manipulate and free.
+**********************************************************************/
+/* Send data packet including a possible sync response pointer */
+#define NG_SEND_DATA(error, hook, m, meta) \
+ do { \
+ item_p item; \
+ if ((item = ng_package_data((m), (meta)))) { \
+ if (!((error) = ng_address_hook(NULL, item, \
+ hook, NULL))) { \
+ SAVE_LINE(item); \
+ (error) = ng_snd_item((item), 0); \
+ } \
+ } else { \
+ (error) = ENOMEM; \
+ } \
(m) = NULL; \
(meta) = NULL; \
} while (0)
-/* Send data packet with no meta-data */
-#define NG_SEND_DATA_ONLY(err, hook, m) \
+#define NG_SEND_DATA_ONLY(error, hook, m) \
do { \
- (err) = ng_send_data((hook), (m), NULL, \
- NULL, NULL, NULL); \
+ item_p item; \
+ if ((item = ng_package_data((m), NULL))) { \
+ if (!((error) = ng_address_hook(NULL, item, \
+ hook, NULL))) { \
+ SAVE_LINE(item); \
+ (error) = ng_snd_item((item), 0); \
+ } \
+ } else { \
+ (error) = ENOMEM; \
+ } \
(m) = NULL; \
} while (0)
-/* Send data packet including a possible sync response pointer */
-#define NG_SEND_DATA_RESP(err, hook, m, meta, rmsg) \
+/*
+ * Forward a data packet with no new meta-data.
+ * old metadata is passed along without change.
+ * Mbuf pointer is updated to new value.
+ */
+#define NG_FWD_NEW_DATA(error, item, hook, m) \
do { \
- (err) = ng_send_data((hook), (m), (meta), \
- NULL, NULL, rmsg); \
+ NGI_M(item) = m; \
+ if (!((error) = ng_address_hook(NULL, (item), \
+ (hook), NULL))) { \
+ SAVE_LINE(item); \
+ (error) = ng_snd_item((item), 0); \
+ } \
+ (item) = NULL; \
(m) = NULL; \
- (meta) = NULL; \
} while (0)
/*
- * Send data packet including a possible sync response pointer
- * Allow the callee to replace the data and pass it back
- * or to simply 'reject it' or 'keep it'
+ * Assuming the data is already ok, just set the new address and send
*/
-#define NG_SEND_DATA_RET(err, hook, m, meta, rmsg) \
+#define NG_FWD_DATA(error, item, hook) \
do { \
- struct mbuf *rm = NULL; \
- meta_p rmeta = NULL; \
- (err) = ng_send_data((hook), (m), (meta), \
- &rm, &rmeta, (rmsg)); \
- (m) = rm; \
- (meta) = rmeta; \
+ if (!((error) = ng_address_hook(NULL, (item), \
+ (hook), NULL))) { \
+ SAVE_LINE(item); \
+ (error) = ng_snd_item((item), 0); \
+ } else { \
+ (error) = ENXIO; \
+ } \
+ (item) = NULL; \
} while (0)
-/* Free metadata */
+/* Note that messages can be static (e.g. in ng_rmnode_self()) */
+/* XXX flag should not be user visible */
+#define NG_FREE_MSG(msg) \
+ do { \
+ if ((msg)) { \
+ if ((msg->header.flags & NGF_STATIC) == 0) { \
+ FREE((msg), M_NETGRAPH_MSG); \
+ } \
+ (msg) = NULL; \
+ } \
+ } while (0)
+
#define NG_FREE_META(meta) \
do { \
if ((meta)) { \
- FREE((meta), M_NETGRAPH); \
- meta = NULL; \
- } \
+ FREE((meta), M_NETGRAPH_META); \
+ (meta) = NULL; \
+ } \
} while (0)
-/* Free any data packet and/or meta-data */
-#define NG_FREE_DATA(m, meta) \
+#define NG_FREE_M(m) \
do { \
if ((m)) { \
m_freem((m)); \
- m = NULL; \
+ (m) = NULL; \
} \
+ } while (0)
+/* Free any data packet and/or meta-data */
+#define NG_FREE_DATAX(m, meta) \
+ do { \
+ NG_FREE_M((m)); \
NG_FREE_META((meta)); \
} while (0)
+/*****************************************
+* Message macros
+*****************************************/
+
+#define NG_SEND_MSG_HOOK(error, here, msg, hook, retaddr) \
+ do { \
+ item_p item; \
+ if ((item = ng_package_msg(msg)) \
+ && (ng_address_hook((here), (item), \
+ (hook), (retaddr)) == 0)) { \
+ SAVE_LINE(item); \
+ (error) = ng_snd_item((item), 0); \
+ } else { \
+ (error) = EINVAL; \
+ } \
+ (msg) = NULL; \
+ } while (0)
+
+#define NG_SEND_MSG_PATH(error, here, msg, path, retaddr) \
+ do { \
+ item_p item; \
+ if ((item = ng_package_msg(msg)) \
+ && (ng_address_path((here), (item), \
+ (path), (retaddr)) == 0)) { \
+ SAVE_LINE(item); \
+ (error) = ng_snd_item((item), 0); \
+ } else { \
+ (error) = EINVAL; \
+ } \
+ (msg) = NULL; \
+ } while (0)
+
+#define NG_SEND_MSG_ID(error, here, msg, ID, retaddr) \
+ do { \
+ item_p item; \
+ if ((item = ng_package_msg(msg)) \
+ && (ng_address_ID((here), (item), \
+ (ID), (retaddr)) == 0)) { \
+ SAVE_LINE(item); \
+ (error) = ng_snd_item((item), 0); \
+ } else { \
+ (error) = EINVAL; \
+ } \
+ (msg) = NULL; \
+ } while (0)
+
+#define NG_QUEUE_MSG(error, here, msg, path, retaddr) \
+ do { \
+ item_p item; \
+ if ((item = ng_package_msg(msg)) \
+ && (ng_address_path((here), (item), \
+ (path), (retaddr)) == 0)) { \
+ SAVE_LINE(item); \
+ (error) = ng_snd_item((item), 0); \
+ } else { \
+ (error) = EINVAL; \
+ } \
+ (msg) = NULL; \
+ } while (0)
+
+/*
+ * Redirect the message to the next hop using the given hook.
+ * ng_retarget_msg() frees the item if there is an error
+ * and returns an error code. It returns 0 on success.
+ */
+#define NG_FWD_MSG_HOOK(error, here, item, hook, retaddr) \
+ do { \
+ if ((ng_address_hook((here), (item), \
+ (hook), (retaddr))) == 0) { \
+ SAVE_LINE(item); \
+ (error) = ng_snd_item((item), 0); \
+ } else { \
+ (error) = EINVAL; \
+ } \
+ (item) = NULL; \
+ } while (0)
+
+/*
+ * Send a queue item back to it's originator with a response message.
+ * Assume original message was removed and freed separatly.
+ */
+#define NG_RESPOND_MSG(error, here, item, resp) \
+ do { \
+ if (resp) { \
+ ng_ID_t dest = NGI_RETADDR(item); \
+ NGI_RETADDR(item) = NULL; \
+ NGI_MSG(item) = resp; \
+ if ((ng_address_ID((here), (item), \
+ dest, NULL )) == 0) { \
+ SAVE_LINE(item); \
+ (error) = ng_snd_item((item), 1); \
+ } else { \
+ (error) = EINVAL; \
+ } \
+ } else { \
+ NG_FREE_ITEM(item); \
+ } \
+ (item) = NULL; \
+ } while (0)
+
/*
* Use the NETGRAPH_INIT() macro to link a node type into the
@@ -284,39 +594,35 @@ MODULE_DEPEND(ng_##typename, netgraph, 1, 1, 1)
NETGRAPH_INIT_ORDERED(tn, tp, SI_SUB_PSEUDO, SI_ORDER_ANY)
/* Special malloc() type for netgraph structs and ctrl messages */
+/* Only these two types should be visible to nodes */
MALLOC_DECLARE(M_NETGRAPH);
+MALLOC_DECLARE(M_NETGRAPH_MSG);
+MALLOC_DECLARE(M_NETGRAPH_META);
+
+
-int ng_bypass(hook_p hook1, hook_p hook2);
-void ng_cutlinks(node_p node);
-int ng_con_nodes(node_p node,
- const char *name, node_p node2, const char *name2);
+/* Methods that should go away (or become private)*/
+/* Methods that should exist */
+int ng_address_ID(node_p here, item_p item, ng_ID_t ID, ng_ID_t retaddr);
+int ng_address_hook(node_p here, item_p item, hook_p hook, ng_ID_t retaddr);
+int ng_address_path(node_p here, item_p item,
+ char *address, ng_ID_t retaddr);
meta_p ng_copy_meta(meta_p meta);
-void ng_destroy_hook(hook_p hook);
hook_p ng_findhook(node_p node, const char *name);
-node_p ng_findname(node_p node, const char *name);
-struct ng_type *ng_findtype(const char *type);
-int ng_make_node(const char *type, node_p *nodepp);
+void ng_free_item(item_p item);
int ng_make_node_common(struct ng_type *typep, node_p *nodep);
-int ng_mkpeer(node_p node, const char *name, const char *name2, char *type);
int ng_mod_event(module_t mod, int what, void *arg);
int ng_name_node(node_p node, const char *name);
int ng_newtype(struct ng_type *tp);
ng_ID_t ng_node2ID(node_p node);
-int ng_path2node(node_p here, const char *path,
- node_p *dest, hook_p *lasthook);
-int ng_path_parse(char *addr, char **node, char **path, char **hook);
-int ng_queue_data(hook_p hook, struct mbuf *m, meta_p meta);
-int ng_queue_msg(node_p here, struct ng_mesg *msg, const char *address,
- hook_p hook, char *retaddr);
-void ng_release_node(node_p node);
-void ng_rmnode(node_p node);
-int ng_send_data(hook_p hook, struct mbuf *m, meta_p meta,
- struct mbuf **ret_m, meta_p *ret_meta, struct ng_mesg **resp);
-int ng_send_msg(node_p here, struct ng_mesg *msg, const char *address,
- hook_p hook, char *retaddr, struct ng_mesg **resp);
+item_p ng_package_data(struct mbuf *m, meta_p meta);
+item_p ng_package_msg(struct ng_mesg *msg);
+item_p ng_package_msg_self(node_p here, hook_p hook, struct ng_mesg *msg);
+void ng_replace_retaddr(node_p here, item_p item, ng_ID_t retaddr);
+int ng_rmnode_self(node_p here);
+int ng_snd_item(item_p item, int queue);
void ng_unname(node_p node);
void ng_unref(node_p node);
-int ng_wait_node(node_p node, char *msg);
#endif /* _NETGRAPH_NETGRAPH_H_ */
OpenPOWER on IntegriCloud