The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netgraph/ng_tag.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2006 Vadim Goncharov <vadimnuclight@tpu.ru>
    3  * All rights reserved.
    4  * 
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice unmodified, this list of conditions, and the following
   10  *    disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  *
   27  * Portions Copyright (c) 1999 Whistle Communications, Inc.
   28  * (ng_bpf by Archie Cobbs <archie@freebsd.org>)
   29  *
   30  * $FreeBSD: releng/8.0/sys/netgraph/ng_tag.c 184205 2008-10-23 15:53:51Z des $
   31  */
   32 
   33 /*
   34  * TAG NETGRAPH NODE TYPE
   35  *
   36  * This node type accepts an arbitrary number of hooks. Each hook can be
   37  * configured for an mbuf_tags(9) definition and two hook names: a hook
   38  * for matched packets, and a hook for packets, that didn't match. Incoming
   39  * packets are examined for configured tag, matched packets are delivered
   40  * out via first hook, and not matched out via second. If corresponding hook
   41  * is not configured, packets are dropped.
   42  *
   43  * A hook can also have an outgoing tag definition configured, so that
   44  * all packets leaving the hook will be unconditionally appended with newly
   45  * allocated tag.
   46  *
   47  * Both hooks can be set to null tag definitions (that is, with zeroed
   48  * fields), so that packet tags are unmodified on output or all packets
   49  * are unconditionally forwarded to non-matching hook on input.  There is
   50  * also a possibility to replace tags by specifying strip flag on input
   51  * and replacing tag on corresponding output tag (or simply remove tag if
   52  * no tag specified on output).
   53  *
   54  * If compiled with NG_TAG_DEBUG, each hook also keeps statistics about
   55  * how many packets have matched, etc.
   56  */
   57 
   58 #include <sys/param.h>
   59 #include <sys/systm.h>
   60 #include <sys/errno.h>
   61 #include <sys/kernel.h>
   62 #include <sys/malloc.h>
   63 #include <sys/mbuf.h>
   64 #include <sys/stddef.h>
   65 
   66 #include <netgraph/ng_message.h>
   67 #include <netgraph/netgraph.h>
   68 #include <netgraph/ng_parse.h>
   69 #include <netgraph/ng_tag.h>
   70 
   71 #ifdef NG_SEPARATE_MALLOC
   72 MALLOC_DEFINE(M_NETGRAPH_TAG, "netgraph_tag", "netgraph tag node ");
   73 #else
   74 #define M_NETGRAPH_TAG M_NETGRAPH
   75 #endif
   76 
   77 #define ERROUT(x)       do { error = (x); goto done; } while (0)
   78 
   79 /*
   80  * Per hook private info.
   81  *
   82  * We've separated API and ABI here, to make easier changes in this node,
   83  * if needed. If you want to change representation, please do not break API.
   84  * We still keep API structures in memory to simplify access to them for
   85  * GET* messages, but most of data is accessed in internal representation
   86  * only.  The reason for this is to speed things up - if data will be
   87  * accessed from API structures, there would be double pointer dereferencing
   88  * in the code, which almost necessarily leads to CPU cache misses and
   89  * reloads.
   90  *
   91  * We also do another optimization by using resolved pointers to
   92  * destination hooks instead of expensive ng_findhook().
   93  */
   94 struct ng_tag_hookinfo {
   95         hook_p                  hi_match;       /* matching hook pointer */
   96         hook_p                  hi_nonmatch;    /* non-matching hook pointer */
   97         uint32_t                in_tag_cookie;
   98         uint32_t                out_tag_cookie;
   99         uint16_t                in_tag_id;
  100         uint16_t                in_tag_len;
  101         uint16_t                out_tag_id;
  102         uint16_t                out_tag_len;
  103         uint8_t                 strip;
  104         void                    *in_tag_data;
  105         void                    *out_tag_data;
  106         struct ng_tag_hookin    *in;
  107         struct ng_tag_hookout   *out;
  108 #ifdef NG_TAG_DEBUG
  109         struct ng_tag_hookstat  stats;
  110 #endif
  111 };
  112 typedef struct ng_tag_hookinfo *hinfo_p;
  113 
  114 /* Netgraph methods. */
  115 static ng_constructor_t ng_tag_constructor;
  116 static ng_rcvmsg_t      ng_tag_rcvmsg;
  117 static ng_shutdown_t    ng_tag_shutdown;
  118 static ng_newhook_t     ng_tag_newhook;
  119 static ng_rcvdata_t     ng_tag_rcvdata;
  120 static ng_disconnect_t  ng_tag_disconnect;
  121 
  122 /* Internal helper functions. */
  123 static int      ng_tag_setdata_in(hook_p hook, const struct ng_tag_hookin *hp);
  124 static int      ng_tag_setdata_out(hook_p hook, const struct ng_tag_hookout *hp);
  125 
  126 /* Parse types for the field 'tag_data' in structs ng_tag_hookin and out. */
  127 static int
  128 ng_tag_hookinary_getLength(const struct ng_parse_type *type,
  129         const u_char *start, const u_char *buf)
  130 {
  131         const struct ng_tag_hookin *hp;
  132 
  133         hp = (const struct ng_tag_hookin *)
  134             (buf - offsetof(struct ng_tag_hookin, tag_data));
  135         return (hp->tag_len);
  136 }
  137 
  138 static int
  139 ng_tag_hookoutary_getLength(const struct ng_parse_type *type,
  140         const u_char *start, const u_char *buf)
  141 {
  142         const struct ng_tag_hookout *hp;
  143 
  144         hp = (const struct ng_tag_hookout *)
  145             (buf - offsetof(struct ng_tag_hookout, tag_data));
  146         return (hp->tag_len);
  147 }
  148 
  149 static const struct ng_parse_type ng_tag_hookinary_type = {
  150         &ng_parse_bytearray_type,
  151         &ng_tag_hookinary_getLength
  152 };
  153 
  154 static const struct ng_parse_type ng_tag_hookoutary_type = {
  155         &ng_parse_bytearray_type,
  156         &ng_tag_hookoutary_getLength
  157 };
  158 
  159 /* Parse type for struct ng_tag_hookin. */
  160 static const struct ng_parse_struct_field ng_tag_hookin_type_fields[]
  161         = NG_TAG_HOOKIN_TYPE_INFO(&ng_tag_hookinary_type);
  162 static const struct ng_parse_type ng_tag_hookin_type = {
  163         &ng_parse_struct_type,
  164         &ng_tag_hookin_type_fields
  165 };
  166 
  167 /* Parse type for struct ng_tag_hookout. */
  168 static const struct ng_parse_struct_field ng_tag_hookout_type_fields[]
  169         = NG_TAG_HOOKOUT_TYPE_INFO(&ng_tag_hookoutary_type);
  170 static const struct ng_parse_type ng_tag_hookout_type = {
  171         &ng_parse_struct_type,
  172         &ng_tag_hookout_type_fields
  173 };
  174 
  175 #ifdef NG_TAG_DEBUG
  176 /* Parse type for struct ng_tag_hookstat. */
  177 static const struct ng_parse_struct_field ng_tag_hookstat_type_fields[]
  178         = NG_TAG_HOOKSTAT_TYPE_INFO;
  179 static const struct ng_parse_type ng_tag_hookstat_type = {
  180         &ng_parse_struct_type,
  181         &ng_tag_hookstat_type_fields
  182 };
  183 #endif
  184 
  185 /* List of commands and how to convert arguments to/from ASCII. */
  186 static const struct ng_cmdlist ng_tag_cmdlist[] = {
  187         {
  188           NGM_TAG_COOKIE,
  189           NGM_TAG_SET_HOOKIN,
  190           "sethookin",
  191           &ng_tag_hookin_type,
  192           NULL
  193         },
  194         {
  195           NGM_TAG_COOKIE,
  196           NGM_TAG_GET_HOOKIN,
  197           "gethookin",
  198           &ng_parse_hookbuf_type,
  199           &ng_tag_hookin_type
  200         },
  201         {
  202           NGM_TAG_COOKIE,
  203           NGM_TAG_SET_HOOKOUT,
  204           "sethookout",
  205           &ng_tag_hookout_type,
  206           NULL
  207         },
  208         {
  209           NGM_TAG_COOKIE,
  210           NGM_TAG_GET_HOOKOUT,
  211           "gethookout",
  212           &ng_parse_hookbuf_type,
  213           &ng_tag_hookout_type
  214         },
  215 #ifdef NG_TAG_DEBUG
  216         {
  217           NGM_TAG_COOKIE,
  218           NGM_TAG_GET_STATS,
  219           "getstats",
  220           &ng_parse_hookbuf_type,
  221           &ng_tag_hookstat_type
  222         },
  223         {
  224           NGM_TAG_COOKIE,
  225           NGM_TAG_CLR_STATS,
  226           "clrstats",
  227           &ng_parse_hookbuf_type,
  228           NULL
  229         },
  230         {
  231           NGM_TAG_COOKIE,
  232           NGM_TAG_GETCLR_STATS,
  233           "getclrstats",
  234           &ng_parse_hookbuf_type,
  235           &ng_tag_hookstat_type
  236         },
  237 #endif
  238         { 0 }
  239 };
  240 
  241 /* Netgraph type descriptor. */
  242 static struct ng_type typestruct = {
  243         .version =      NG_ABI_VERSION,
  244         .name =         NG_TAG_NODE_TYPE,
  245         .constructor =  ng_tag_constructor,
  246         .rcvmsg =       ng_tag_rcvmsg,
  247         .shutdown =     ng_tag_shutdown,
  248         .newhook =      ng_tag_newhook,
  249         .rcvdata =      ng_tag_rcvdata,
  250         .disconnect =   ng_tag_disconnect,
  251         .cmdlist =      ng_tag_cmdlist,
  252 };
  253 NETGRAPH_INIT(tag, &typestruct);
  254 
  255 /*
  256  * This are default API structures (initialized to zeroes) which are
  257  * returned in response to GET* messages when no configuration was made.
  258  * One could ask why to have this structures at all when we have
  259  * ng_tag_hookinfo initialized to zero and don't need in and out structures
  260  * at all to operate.  Unfortunatelly, we have to return thisHook field
  261  * in response to messages so the fastest and simpliest way is to have
  262  * this default structures and initialize thisHook once at hook creation
  263  * rather than to do it on every response.
  264  */
  265 
  266 /* Default tag values for a hook that matches nothing. */
  267 static const struct ng_tag_hookin ng_tag_default_in = {
  268         { '\0' },               /* to be filled in at hook creation time */
  269         { '\0' },
  270         { '\0' },
  271         0,
  272         0,
  273         0,
  274         0
  275 };
  276 
  277 /* Default tag values for a hook that adds nothing */
  278 static const struct ng_tag_hookout ng_tag_default_out = {
  279         { '\0' },               /* to be filled in at hook creation time */
  280         0,
  281         0,
  282         0
  283 };
  284 
  285 /*
  286  * Node constructor.
  287  *
  288  * We don't keep any per-node private data - we do it on per-hook basis.
  289  */
  290 static int
  291 ng_tag_constructor(node_p node)
  292 {
  293         return (0);
  294 }
  295 
  296 /*
  297  * Add a hook.
  298  */
  299 static int
  300 ng_tag_newhook(node_p node, hook_p hook, const char *name)
  301 {
  302         hinfo_p hip;
  303         int error;
  304 
  305         /* Create hook private structure. */
  306         hip = malloc(sizeof(*hip), M_NETGRAPH_TAG, M_WAITOK | M_ZERO);
  307         /* M_WAITOK can't return NULL. */
  308         NG_HOOK_SET_PRIVATE(hook, hip);
  309 
  310         /*
  311          * After M_ZERO both in and out hook pointers are set to NULL,
  312          * as well as all members and pointers to in and out API
  313          * structures, so we need to set explicitly only thisHook field
  314          * in that structures (after allocating them, of course).
  315          */
  316 
  317         /* Attach the default IN data. */
  318         if ((error = ng_tag_setdata_in(hook, &ng_tag_default_in)) != 0) {
  319                 free(hip, M_NETGRAPH_TAG);
  320                 return (error);
  321         }
  322 
  323         /* Attach the default OUT data. */
  324         if ((error = ng_tag_setdata_out(hook, &ng_tag_default_out)) != 0) {
  325                 free(hip, M_NETGRAPH_TAG);
  326                 return (error);
  327         }
  328 
  329         /*
  330          * Set hook name.  This is done only once at hook creation time
  331          * since hook name can't change, rather than to do it on every
  332          * response to messages requesting API structures with data who
  333          * we are etc.
  334          */
  335         strncpy(hip->in->thisHook, name, sizeof(hip->in->thisHook) - 1);
  336         hip->in->thisHook[sizeof(hip->in->thisHook) - 1] = '\0';
  337         strncpy(hip->out->thisHook, name, sizeof(hip->out->thisHook) - 1);
  338         hip->out->thisHook[sizeof(hip->out->thisHook) - 1] = '\0';
  339         return (0);
  340 }
  341 
  342 /*
  343  * Receive a control message.
  344  */
  345 static int
  346 ng_tag_rcvmsg(node_p node, item_p item, hook_p lasthook)
  347 {
  348         struct ng_mesg *msg;
  349         struct ng_mesg *resp = NULL;
  350         int error = 0;
  351 
  352         NGI_GET_MSG(item, msg);
  353         switch (msg->header.typecookie) {
  354         case NGM_TAG_COOKIE:
  355                 switch (msg->header.cmd) {
  356                 case NGM_TAG_SET_HOOKIN:
  357                     {
  358                         struct ng_tag_hookin *const
  359                             hp = (struct ng_tag_hookin *)msg->data;
  360                         hook_p hook;
  361 
  362                         /* Sanity check. */
  363                         if (msg->header.arglen < sizeof(*hp)
  364                             || msg->header.arglen !=
  365                             NG_TAG_HOOKIN_SIZE(hp->tag_len))
  366                                 ERROUT(EINVAL);
  367 
  368                         /* Find hook. */
  369                         if ((hook = ng_findhook(node, hp->thisHook)) == NULL)
  370                                 ERROUT(ENOENT);
  371 
  372                         /* Set new tag values. */
  373                         if ((error = ng_tag_setdata_in(hook, hp)) != 0)
  374                                 ERROUT(error);
  375                         break;
  376                     }
  377 
  378                 case NGM_TAG_SET_HOOKOUT:
  379                     {
  380                         struct ng_tag_hookout *const
  381                             hp = (struct ng_tag_hookout *)msg->data;
  382                         hook_p hook;
  383 
  384                         /* Sanity check. */
  385                         if (msg->header.arglen < sizeof(*hp)
  386                             || msg->header.arglen !=
  387                             NG_TAG_HOOKOUT_SIZE(hp->tag_len))
  388                                 ERROUT(EINVAL);
  389 
  390                         /* Find hook. */
  391                         if ((hook = ng_findhook(node, hp->thisHook)) == NULL)
  392                                 ERROUT(ENOENT);
  393 
  394                         /* Set new tag values. */
  395                         if ((error = ng_tag_setdata_out(hook, hp)) != 0)
  396                                 ERROUT(error);
  397                         break;
  398                     }
  399 
  400                 case NGM_TAG_GET_HOOKIN:
  401                     {
  402                         struct ng_tag_hookin *hp;
  403                         hook_p hook;
  404 
  405                         /* Sanity check. */
  406                         if (msg->header.arglen == 0)
  407                                 ERROUT(EINVAL);
  408                         msg->data[msg->header.arglen - 1] = '\0';
  409 
  410                         /* Find hook. */
  411                         if ((hook = ng_findhook(node, msg->data)) == NULL)
  412                                 ERROUT(ENOENT);
  413 
  414                         /* Build response. */
  415                         hp = ((hinfo_p)NG_HOOK_PRIVATE(hook))->in;
  416                         NG_MKRESPONSE(resp, msg,
  417                             NG_TAG_HOOKIN_SIZE(hp->tag_len), M_WAITOK);
  418                         /* M_WAITOK can't return NULL. */
  419                         bcopy(hp, resp->data,
  420                            NG_TAG_HOOKIN_SIZE(hp->tag_len));
  421                         break;
  422                     }
  423 
  424                 case NGM_TAG_GET_HOOKOUT:
  425                     {
  426                         struct ng_tag_hookout *hp;
  427                         hook_p hook;
  428 
  429                         /* Sanity check. */
  430                         if (msg->header.arglen == 0)
  431                                 ERROUT(EINVAL);
  432                         msg->data[msg->header.arglen - 1] = '\0';
  433 
  434                         /* Find hook. */
  435                         if ((hook = ng_findhook(node, msg->data)) == NULL)
  436                                 ERROUT(ENOENT);
  437 
  438                         /* Build response. */
  439                         hp = ((hinfo_p)NG_HOOK_PRIVATE(hook))->out;
  440                         NG_MKRESPONSE(resp, msg,
  441                             NG_TAG_HOOKOUT_SIZE(hp->tag_len), M_WAITOK);
  442                         /* M_WAITOK can't return NULL. */
  443                         bcopy(hp, resp->data,
  444                            NG_TAG_HOOKOUT_SIZE(hp->tag_len));
  445                         break;
  446                     }
  447 
  448 #ifdef NG_TAG_DEBUG
  449                 case NGM_TAG_GET_STATS:
  450                 case NGM_TAG_CLR_STATS:
  451                 case NGM_TAG_GETCLR_STATS:
  452                     {
  453                         struct ng_tag_hookstat *stats;
  454                         hook_p hook;
  455 
  456                         /* Sanity check. */
  457                         if (msg->header.arglen == 0)
  458                                 ERROUT(EINVAL);
  459                         msg->data[msg->header.arglen - 1] = '\0';
  460 
  461                         /* Find hook. */
  462                         if ((hook = ng_findhook(node, msg->data)) == NULL)
  463                                 ERROUT(ENOENT);
  464                         stats = &((hinfo_p)NG_HOOK_PRIVATE(hook))->stats;
  465 
  466                         /* Build response (if desired). */
  467                         if (msg->header.cmd != NGM_TAG_CLR_STATS) {
  468                                 NG_MKRESPONSE(resp,
  469                                     msg, sizeof(*stats), M_WAITOK);
  470                                 /* M_WAITOK can't return NULL. */
  471                                 bcopy(stats, resp->data, sizeof(*stats));
  472                         }
  473 
  474                         /* Clear stats (if desired). */
  475                         if (msg->header.cmd != NGM_TAG_GET_STATS)
  476                                 bzero(stats, sizeof(*stats));
  477                         break;
  478                     }
  479 #endif /* NG_TAG_DEBUG */
  480 
  481                 default:
  482                         error = EINVAL;
  483                         break;
  484                 }
  485                 break;
  486         default:
  487                 error = EINVAL;
  488                 break;
  489         }
  490 done:
  491         NG_RESPOND_MSG(error, node, item, resp);
  492         NG_FREE_MSG(msg);
  493         return (error);
  494 }
  495 
  496 /*
  497  * Receive data on a hook.
  498  *
  499  * Apply the filter, and then drop or forward packet as appropriate.
  500  */
  501 static int
  502 ng_tag_rcvdata(hook_p hook, item_p item)
  503 {
  504         struct mbuf *m;
  505         struct m_tag *tag = NULL;
  506         const hinfo_p hip = NG_HOOK_PRIVATE(hook);
  507         uint16_t type, tag_len;
  508         uint32_t cookie;
  509         hinfo_p dhip;
  510         hook_p dest;
  511         int totlen;
  512         int found = 0, error = 0;
  513 
  514         m = NGI_M(item);        /* 'item' still owns it.. we are peeking */
  515         totlen = m->m_pkthdr.len;
  516 
  517 #ifdef NG_TAG_DEBUG
  518         hip->stats.recvFrames++;
  519         hip->stats.recvOctets += totlen;
  520 #endif
  521 
  522         /* Looking up incoming tag. */
  523         cookie = hip->in_tag_cookie;
  524         type = hip->in_tag_id;
  525         tag_len = hip->in_tag_len;
  526 
  527         /*
  528          * We treat case of all zeroes specially (that is, cookie and
  529          * type are equal to zero), as we assume that such tag
  530          * can never occur in the wild.  So we don't waste time trying
  531          * to find such tag (for example, these are zeroes after hook
  532          * creation in default structures).
  533          */
  534         if ((cookie != 0) || (type != 0)) {
  535                 tag = m_tag_locate(m, cookie, type, NULL);
  536                 while (tag != NULL) {
  537                         if (memcmp((void *)(tag + 1),
  538                             hip->in_tag_data, tag_len) == 0) {
  539                                 found = 1;
  540                                 break;
  541                         }
  542                         tag = m_tag_locate(m, cookie, type, tag);
  543                 }
  544         }
  545         
  546         /* See if we got a match and find destination hook. */
  547         if (found) {
  548 #ifdef NG_TAG_DEBUG
  549                 hip->stats.recvMatchFrames++;
  550                 hip->stats.recvMatchOctets += totlen;
  551 #endif
  552                 if (hip->strip)
  553                         m_tag_delete(m, tag);
  554                 dest = hip->hi_match;
  555         } else
  556                 dest = hip->hi_nonmatch;
  557         if (dest == NULL) {
  558                 NG_FREE_ITEM(item);
  559                 return (0);
  560         }
  561 
  562         /* Deliver frame out destination hook. */
  563         dhip = NG_HOOK_PRIVATE(dest);
  564 
  565 #ifdef NG_TAG_DEBUG
  566         dhip->stats.xmitOctets += totlen;
  567         dhip->stats.xmitFrames++;
  568 #endif
  569         
  570         cookie = dhip->out_tag_cookie;
  571         type = dhip->out_tag_id;
  572         tag_len = dhip->out_tag_len;
  573         
  574         if ((cookie != 0) || (type != 0)) {
  575                 tag = m_tag_alloc(cookie, type, tag_len, M_NOWAIT);
  576                 /* XXX may be free the mbuf if tag allocation failed? */
  577                 if (tag != NULL) {
  578                         if (tag_len != 0) {
  579                                 /* copy tag data to its place */
  580                                 memcpy((void *)(tag + 1),
  581                                     dhip->out_tag_data, tag_len);
  582                         }
  583                         m_tag_prepend(m, tag);
  584                 }
  585         }
  586         
  587         NG_FWD_ITEM_HOOK(error, item, dest);
  588         return (error);
  589 }
  590 
  591 /*
  592  * Shutdown processing.
  593  */
  594 static int
  595 ng_tag_shutdown(node_p node)
  596 {
  597         NG_NODE_UNREF(node);
  598         return (0);
  599 }
  600 
  601 /*
  602  * Hook disconnection.
  603  *
  604  * We must check all hooks, since they may reference this one.
  605  */
  606 static int
  607 ng_tag_disconnect(hook_p hook)
  608 {
  609         const hinfo_p hip = NG_HOOK_PRIVATE(hook);
  610         node_p node = NG_HOOK_NODE(hook);
  611         hook_p hook2;
  612 
  613         KASSERT(hip != NULL, ("%s: null info", __func__));
  614 
  615         LIST_FOREACH(hook2, &node->nd_hooks, hk_hooks) {
  616                 hinfo_p priv = NG_HOOK_PRIVATE(hook2);
  617 
  618                 if (priv->hi_match == hook)
  619                         priv->hi_match = NULL;
  620                 if (priv->hi_nonmatch == hook)
  621                         priv->hi_nonmatch = NULL;
  622         }
  623 
  624         free(hip->in, M_NETGRAPH_TAG);
  625         free(hip->out, M_NETGRAPH_TAG);
  626         free(hip, M_NETGRAPH_TAG);
  627         NG_HOOK_SET_PRIVATE(hook, NULL);                        /* for good measure */
  628         if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) &&
  629             (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) {
  630                 ng_rmnode_self(NG_HOOK_NODE(hook));
  631         }
  632         return (0);
  633 }
  634 
  635 /************************************************************************
  636                         HELPER STUFF
  637  ************************************************************************/
  638 
  639 /*
  640  * Set the IN tag values associated with a hook.
  641  */
  642 static int
  643 ng_tag_setdata_in(hook_p hook, const struct ng_tag_hookin *hp0)
  644 {
  645         const hinfo_p hip = NG_HOOK_PRIVATE(hook);
  646         struct ng_tag_hookin *hp;
  647         int size;
  648 
  649         /* Make a copy of the tag values and data. */
  650         size = NG_TAG_HOOKIN_SIZE(hp0->tag_len);
  651         hp = malloc(size, M_NETGRAPH_TAG, M_WAITOK);
  652         /* M_WAITOK can't return NULL. */
  653         bcopy(hp0, hp, size);
  654 
  655         /* Free previous tag, if any, and assign new one. */
  656         if (hip->in != NULL)
  657                 free(hip->in, M_NETGRAPH_TAG);
  658         hip->in = hp;
  659 
  660         /*
  661          * Resolve hook names to pointers.
  662          *
  663          * As ng_findhook() is expensive operation to do it on every packet
  664          * after tag matching check, we do it here and use resolved pointers
  665          * where appropriate.
  666          *
  667          * XXX The drawback is that user can configure a hook to use
  668          * ifMatch/ifNotMatch hooks that do not yet exist and will be added
  669          * by user later, so that resolved pointers will be NULL even
  670          * if the hook already exists, causing node to drop packets and
  671          * user to report bugs.  We could do check for this situation on
  672          * every hook creation with pointers correction, but that involves
  673          * re-resolving for all pointers in all hooks, up to O(n^2) operations,
  674          * so we better document this in man page for user not to do
  675          * configuration before creating all hooks.
  676          */
  677         hip->hi_match = ng_findhook(NG_HOOK_NODE(hook), hip->in->ifMatch);
  678         hip->hi_nonmatch = ng_findhook(NG_HOOK_NODE(hook), hip->in->ifNotMatch);
  679 
  680         /* Fill internal values from API structures. */
  681         hip->in_tag_cookie = hip->in->tag_cookie;
  682         hip->in_tag_id = hip->in->tag_id;
  683         hip->in_tag_len = hip->in->tag_len;
  684         hip->strip = hip->in->strip;
  685         hip->in_tag_data = (void*)(hip->in->tag_data);
  686         return (0);
  687 }
  688 
  689 /*
  690  * Set the OUT tag values associated with a hook.
  691  */
  692 static int
  693 ng_tag_setdata_out(hook_p hook, const struct ng_tag_hookout *hp0)
  694 {
  695         const hinfo_p hip = NG_HOOK_PRIVATE(hook);
  696         struct ng_tag_hookout *hp;
  697         int size;
  698 
  699         /* Make a copy of the tag values and data. */
  700         size = NG_TAG_HOOKOUT_SIZE(hp0->tag_len);
  701         hp = malloc(size, M_NETGRAPH_TAG, M_WAITOK);
  702         /* M_WAITOK can't return NULL. */
  703         bcopy(hp0, hp, size);
  704 
  705         /* Free previous tag, if any, and assign new one. */
  706         if (hip->out != NULL)
  707                 free(hip->out, M_NETGRAPH_TAG);
  708         hip->out = hp;
  709 
  710         /* Fill internal values from API structures. */
  711         hip->out_tag_cookie = hip->out->tag_cookie;
  712         hip->out_tag_id = hip->out->tag_id;
  713         hip->out_tag_len = hip->out->tag_len;
  714         hip->out_tag_data = (void*)(hip->out->tag_data);
  715         return (0);
  716 }
  717 

Cache object: 63c6f3ae7592bd79b99d8e878d8dbc45


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.