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$
   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 static 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_NOWAIT | M_ZERO);
  307         if (hip == NULL)
  308                 return (ENOMEM);
  309         NG_HOOK_SET_PRIVATE(hook, hip);
  310 
  311         /*
  312          * After M_ZERO both in and out hook pointers are set to NULL,
  313          * as well as all members and pointers to in and out API
  314          * structures, so we need to set explicitly only thisHook field
  315          * in that structures (after allocating them, of course).
  316          */
  317 
  318         /* Attach the default IN data. */
  319         if ((error = ng_tag_setdata_in(hook, &ng_tag_default_in)) != 0) {
  320                 free(hip, M_NETGRAPH_TAG);
  321                 return (error);
  322         }
  323 
  324         /* Attach the default OUT data. */
  325         if ((error = ng_tag_setdata_out(hook, &ng_tag_default_out)) != 0) {
  326                 free(hip, M_NETGRAPH_TAG);
  327                 return (error);
  328         }
  329 
  330         /*
  331          * Set hook name.  This is done only once at hook creation time
  332          * since hook name can't change, rather than to do it on every
  333          * response to messages requesting API structures with data who
  334          * we are etc.
  335          */
  336         strncpy(hip->in->thisHook, name, sizeof(hip->in->thisHook) - 1);
  337         hip->in->thisHook[sizeof(hip->in->thisHook) - 1] = '\0';
  338         strncpy(hip->out->thisHook, name, sizeof(hip->out->thisHook) - 1);
  339         hip->out->thisHook[sizeof(hip->out->thisHook) - 1] = '\0';
  340         return (0);
  341 }
  342 
  343 /*
  344  * Receive a control message.
  345  */
  346 static int
  347 ng_tag_rcvmsg(node_p node, item_p item, hook_p lasthook)
  348 {
  349         struct ng_mesg *msg;
  350         struct ng_mesg *resp = NULL;
  351         int error = 0;
  352 
  353         NGI_GET_MSG(item, msg);
  354         switch (msg->header.typecookie) {
  355         case NGM_TAG_COOKIE:
  356                 switch (msg->header.cmd) {
  357                 case NGM_TAG_SET_HOOKIN:
  358                     {
  359                         struct ng_tag_hookin *const
  360                             hp = (struct ng_tag_hookin *)msg->data;
  361                         hook_p hook;
  362 
  363                         /* Sanity check. */
  364                         if (msg->header.arglen < sizeof(*hp) ||
  365                             msg->header.arglen < 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 < NG_TAG_HOOKOUT_SIZE(hp->tag_len))
  387                                 ERROUT(EINVAL);
  388 
  389                         /* Find hook. */
  390                         if ((hook = ng_findhook(node, hp->thisHook)) == NULL)
  391                                 ERROUT(ENOENT);
  392 
  393                         /* Set new tag values. */
  394                         if ((error = ng_tag_setdata_out(hook, hp)) != 0)
  395                                 ERROUT(error);
  396                         break;
  397                     }
  398 
  399                 case NGM_TAG_GET_HOOKIN:
  400                     {
  401                         struct ng_tag_hookin *hp;
  402                         hook_p hook;
  403 
  404                         /* Sanity check. */
  405                         if (msg->header.arglen == 0)
  406                                 ERROUT(EINVAL);
  407                         msg->data[msg->header.arglen - 1] = '\0';
  408 
  409                         /* Find hook. */
  410                         if ((hook = ng_findhook(node, msg->data)) == NULL)
  411                                 ERROUT(ENOENT);
  412 
  413                         /* Build response. */
  414                         hp = ((hinfo_p)NG_HOOK_PRIVATE(hook))->in;
  415                         NG_MKRESPONSE(resp, msg,
  416                             NG_TAG_HOOKIN_SIZE(hp->tag_len), M_WAITOK);
  417                         /* M_WAITOK can't return NULL. */
  418                         bcopy(hp, resp->data,
  419                            NG_TAG_HOOKIN_SIZE(hp->tag_len));
  420                         break;
  421                     }
  422 
  423                 case NGM_TAG_GET_HOOKOUT:
  424                     {
  425                         struct ng_tag_hookout *hp;
  426                         hook_p hook;
  427 
  428                         /* Sanity check. */
  429                         if (msg->header.arglen == 0)
  430                                 ERROUT(EINVAL);
  431                         msg->data[msg->header.arglen - 1] = '\0';
  432 
  433                         /* Find hook. */
  434                         if ((hook = ng_findhook(node, msg->data)) == NULL)
  435                                 ERROUT(ENOENT);
  436 
  437                         /* Build response. */
  438                         hp = ((hinfo_p)NG_HOOK_PRIVATE(hook))->out;
  439                         NG_MKRESPONSE(resp, msg,
  440                             NG_TAG_HOOKOUT_SIZE(hp->tag_len), M_WAITOK);
  441                         /* M_WAITOK can't return NULL. */
  442                         bcopy(hp, resp->data,
  443                            NG_TAG_HOOKOUT_SIZE(hp->tag_len));
  444                         break;
  445                     }
  446 
  447 #ifdef NG_TAG_DEBUG
  448                 case NGM_TAG_GET_STATS:
  449                 case NGM_TAG_CLR_STATS:
  450                 case NGM_TAG_GETCLR_STATS:
  451                     {
  452                         struct ng_tag_hookstat *stats;
  453                         hook_p hook;
  454 
  455                         /* Sanity check. */
  456                         if (msg->header.arglen == 0)
  457                                 ERROUT(EINVAL);
  458                         msg->data[msg->header.arglen - 1] = '\0';
  459 
  460                         /* Find hook. */
  461                         if ((hook = ng_findhook(node, msg->data)) == NULL)
  462                                 ERROUT(ENOENT);
  463                         stats = &((hinfo_p)NG_HOOK_PRIVATE(hook))->stats;
  464 
  465                         /* Build response (if desired). */
  466                         if (msg->header.cmd != NGM_TAG_CLR_STATS) {
  467                                 NG_MKRESPONSE(resp,
  468                                     msg, sizeof(*stats), M_WAITOK);
  469                                 /* M_WAITOK can't return NULL. */
  470                                 bcopy(stats, resp->data, sizeof(*stats));
  471                         }
  472 
  473                         /* Clear stats (if desired). */
  474                         if (msg->header.cmd != NGM_TAG_GET_STATS)
  475                                 bzero(stats, sizeof(*stats));
  476                         break;
  477                     }
  478 #endif /* NG_TAG_DEBUG */
  479 
  480                 default:
  481                         error = EINVAL;
  482                         break;
  483                 }
  484                 break;
  485         default:
  486                 error = EINVAL;
  487                 break;
  488         }
  489 done:
  490         NG_RESPOND_MSG(error, node, item, resp);
  491         NG_FREE_MSG(msg);
  492         return (error);
  493 }
  494 
  495 /*
  496  * Receive data on a hook.
  497  *
  498  * Apply the filter, and then drop or forward packet as appropriate.
  499  */
  500 static int
  501 ng_tag_rcvdata(hook_p hook, item_p item)
  502 {
  503         struct mbuf *m;
  504         struct m_tag *tag = NULL;
  505         const hinfo_p hip = NG_HOOK_PRIVATE(hook);
  506         uint16_t type, tag_len;
  507         uint32_t cookie;
  508         hinfo_p dhip;
  509         hook_p dest;
  510         int totlen;
  511         int found = 0, error = 0;
  512 
  513         m = NGI_M(item);        /* 'item' still owns it.. we are peeking */
  514         totlen = m->m_pkthdr.len;
  515 
  516 #ifdef NG_TAG_DEBUG
  517         hip->stats.recvFrames++;
  518         hip->stats.recvOctets += totlen;
  519 #endif
  520 
  521         /* Looking up incoming tag. */
  522         cookie = hip->in_tag_cookie;
  523         type = hip->in_tag_id;
  524         tag_len = hip->in_tag_len;
  525 
  526         /*
  527          * We treat case of all zeroes specially (that is, cookie and
  528          * type are equal to zero), as we assume that such tag
  529          * can never occur in the wild.  So we don't waste time trying
  530          * to find such tag (for example, these are zeroes after hook
  531          * creation in default structures).
  532          */
  533         if ((cookie != 0) || (type != 0)) {
  534                 tag = m_tag_locate(m, cookie, type, NULL);
  535                 while (tag != NULL) {
  536                         if (memcmp((void *)(tag + 1),
  537                             hip->in_tag_data, tag_len) == 0) {
  538                                 found = 1;
  539                                 break;
  540                         }
  541                         tag = m_tag_locate(m, cookie, type, tag);
  542                 }
  543         }
  544         
  545         /* See if we got a match and find destination hook. */
  546         if (found) {
  547 #ifdef NG_TAG_DEBUG
  548                 hip->stats.recvMatchFrames++;
  549                 hip->stats.recvMatchOctets += totlen;
  550 #endif
  551                 if (hip->strip)
  552                         m_tag_delete(m, tag);
  553                 dest = hip->hi_match;
  554         } else
  555                 dest = hip->hi_nonmatch;
  556         if (dest == NULL) {
  557                 NG_FREE_ITEM(item);
  558                 return (0);
  559         }
  560 
  561         /* Deliver frame out destination hook. */
  562         dhip = NG_HOOK_PRIVATE(dest);
  563 
  564 #ifdef NG_TAG_DEBUG
  565         dhip->stats.xmitOctets += totlen;
  566         dhip->stats.xmitFrames++;
  567 #endif
  568         
  569         cookie = dhip->out_tag_cookie;
  570         type = dhip->out_tag_id;
  571         tag_len = dhip->out_tag_len;
  572         
  573         if ((cookie != 0) || (type != 0)) {
  574                 tag = m_tag_alloc(cookie, type, tag_len, M_NOWAIT);
  575                 /* XXX may be free the mbuf if tag allocation failed? */
  576                 if (tag != NULL) {
  577                         if (tag_len != 0) {
  578                                 /* copy tag data to its place */
  579                                 memcpy((void *)(tag + 1),
  580                                     dhip->out_tag_data, tag_len);
  581                         }
  582                         m_tag_prepend(m, tag);
  583                 }
  584         }
  585         
  586         NG_FWD_ITEM_HOOK(error, item, dest);
  587         return (error);
  588 }
  589 
  590 /*
  591  * Shutdown processing.
  592  */
  593 static int
  594 ng_tag_shutdown(node_p node)
  595 {
  596         NG_NODE_UNREF(node);
  597         return (0);
  598 }
  599 
  600 /*
  601  * Hook disconnection.
  602  *
  603  * We must check all hooks, since they may reference this one.
  604  */
  605 static int
  606 ng_tag_disconnect(hook_p hook)
  607 {
  608         const hinfo_p hip = NG_HOOK_PRIVATE(hook);
  609         node_p node = NG_HOOK_NODE(hook);
  610         hook_p hook2;
  611 
  612         KASSERT(hip != NULL, ("%s: null info", __func__));
  613 
  614         LIST_FOREACH(hook2, &node->nd_hooks, hk_hooks) {
  615                 hinfo_p priv = NG_HOOK_PRIVATE(hook2);
  616 
  617                 if (priv->hi_match == hook)
  618                         priv->hi_match = NULL;
  619                 if (priv->hi_nonmatch == hook)
  620                         priv->hi_nonmatch = NULL;
  621         }
  622 
  623         free(hip->in, M_NETGRAPH_TAG);
  624         free(hip->out, M_NETGRAPH_TAG);
  625         free(hip, M_NETGRAPH_TAG);
  626         NG_HOOK_SET_PRIVATE(hook, NULL);                        /* for good measure */
  627         if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) &&
  628             (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) {
  629                 ng_rmnode_self(NG_HOOK_NODE(hook));
  630         }
  631         return (0);
  632 }
  633 
  634 /************************************************************************
  635                         HELPER STUFF
  636  ************************************************************************/
  637 
  638 /*
  639  * Set the IN tag values associated with a hook.
  640  */
  641 static int
  642 ng_tag_setdata_in(hook_p hook, const struct ng_tag_hookin *hp0)
  643 {
  644         const hinfo_p hip = NG_HOOK_PRIVATE(hook);
  645         struct ng_tag_hookin *hp;
  646         int size;
  647 
  648         /* Make a copy of the tag values and data. */
  649         size = NG_TAG_HOOKIN_SIZE(hp0->tag_len);
  650         hp = malloc(size, M_NETGRAPH_TAG, M_WAITOK);
  651         /* M_WAITOK can't return NULL. */
  652         bcopy(hp0, hp, size);
  653 
  654         /* Free previous tag, if any, and assign new one. */
  655         if (hip->in != NULL)
  656                 free(hip->in, M_NETGRAPH_TAG);
  657         hip->in = hp;
  658 
  659         /*
  660          * Resolve hook names to pointers.
  661          *
  662          * As ng_findhook() is expensive operation to do it on every packet
  663          * after tag matching check, we do it here and use resolved pointers
  664          * where appropriate.
  665          *
  666          * XXX The drawback is that user can configure a hook to use
  667          * ifMatch/ifNotMatch hooks that do not yet exist and will be added
  668          * by user later, so that resolved pointers will be NULL even
  669          * if the hook already exists, causing node to drop packets and
  670          * user to report bugs.  We could do check for this situation on
  671          * every hook creation with pointers correction, but that involves
  672          * re-resolving for all pointers in all hooks, up to O(n^2) operations,
  673          * so we better document this in man page for user not to do
  674          * configuration before creating all hooks.
  675          */
  676         hip->hi_match = ng_findhook(NG_HOOK_NODE(hook), hip->in->ifMatch);
  677         hip->hi_nonmatch = ng_findhook(NG_HOOK_NODE(hook), hip->in->ifNotMatch);
  678 
  679         /* Fill internal values from API structures. */
  680         hip->in_tag_cookie = hip->in->tag_cookie;
  681         hip->in_tag_id = hip->in->tag_id;
  682         hip->in_tag_len = hip->in->tag_len;
  683         hip->strip = hip->in->strip;
  684         hip->in_tag_data = (void*)(hip->in->tag_data);
  685         return (0);
  686 }
  687 
  688 /*
  689  * Set the OUT tag values associated with a hook.
  690  */
  691 static int
  692 ng_tag_setdata_out(hook_p hook, const struct ng_tag_hookout *hp0)
  693 {
  694         const hinfo_p hip = NG_HOOK_PRIVATE(hook);
  695         struct ng_tag_hookout *hp;
  696         int size;
  697 
  698         /* Make a copy of the tag values and data. */
  699         size = NG_TAG_HOOKOUT_SIZE(hp0->tag_len);
  700         hp = malloc(size, M_NETGRAPH_TAG, M_WAITOK);
  701         /* M_WAITOK can't return NULL. */
  702         bcopy(hp0, hp, size);
  703 
  704         /* Free previous tag, if any, and assign new one. */
  705         if (hip->out != NULL)
  706                 free(hip->out, M_NETGRAPH_TAG);
  707         hip->out = hp;
  708 
  709         /* Fill internal values from API structures. */
  710         hip->out_tag_cookie = hip->out->tag_cookie;
  711         hip->out_tag_id = hip->out->tag_id;
  712         hip->out_tag_len = hip->out->tag_len;
  713         hip->out_tag_data = (void*)(hip->out->tag_data);
  714         return (0);
  715 }
  716 

Cache object: 2a265253a45b38f4249b33748400d027


[ 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.