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/11.0/sys/netgraph/ng_tag.c 230272 2012-01-17 18:10:25Z glebius $
   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 !=
  366                             NG_TAG_HOOKIN_SIZE(hp->tag_len))
  367                                 ERROUT(EINVAL);
  368 
  369                         /* Find hook. */
  370                         if ((hook = ng_findhook(node, hp->thisHook)) == NULL)
  371                                 ERROUT(ENOENT);
  372 
  373                         /* Set new tag values. */
  374                         if ((error = ng_tag_setdata_in(hook, hp)) != 0)
  375                                 ERROUT(error);
  376                         break;
  377                     }
  378 
  379                 case NGM_TAG_SET_HOOKOUT:
  380                     {
  381                         struct ng_tag_hookout *const
  382                             hp = (struct ng_tag_hookout *)msg->data;
  383                         hook_p hook;
  384 
  385                         /* Sanity check. */
  386                         if (msg->header.arglen < sizeof(*hp)
  387                             || msg->header.arglen !=
  388                             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: e1586ff38262d519957df39708cd42b2


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