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

Cache object: 475fcf4e83437820a20597d31c6aac2b


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