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/netflow/ng_netflow.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) 2004-2005 Gleb Smirnoff <glebius@FreeBSD.org>
    3  * Copyright (c) 2001-2003 Roman V. Palagin <romanp@unshadow.net>
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following 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  * $SourceForge: ng_netflow.c,v 1.30 2004/09/05 11:37:43 glebius Exp $
   28  */
   29 
   30 static const char rcs_id[] =
   31     "@(#) $FreeBSD: src/sys/netgraph/netflow/ng_netflow.c,v 1.2.2.6 2006/01/10 10:22:22 glebius Exp $";
   32 
   33 #include <sys/param.h>
   34 #include <sys/systm.h>
   35 #include <sys/kernel.h>
   36 #include <sys/mbuf.h>
   37 #include <sys/socket.h>
   38 #include <sys/syslog.h>
   39 #include <sys/ctype.h>
   40 
   41 #include <net/if.h>
   42 #include <net/ethernet.h>
   43 #include <net/if_arp.h>
   44 #include <net/if_var.h>
   45 #include <net/bpf.h>
   46 #include <netinet/in.h>
   47 #include <netinet/in_systm.h>
   48 #include <netinet/ip.h>
   49 #include <netinet/tcp.h>
   50 #include <netinet/udp.h>
   51 
   52 #include <netgraph/ng_message.h>
   53 #include <netgraph/ng_parse.h>
   54 #include <netgraph/netgraph.h>
   55 #include <netgraph/netflow/netflow.h>
   56 #include <netgraph/netflow/ng_netflow.h>
   57 
   58 /* Netgraph methods */
   59 static ng_constructor_t ng_netflow_constructor;
   60 static ng_rcvmsg_t      ng_netflow_rcvmsg;
   61 static ng_close_t       ng_netflow_close;
   62 static ng_shutdown_t    ng_netflow_rmnode;
   63 static ng_newhook_t     ng_netflow_newhook;
   64 static ng_rcvdata_t     ng_netflow_rcvdata;
   65 static ng_disconnect_t  ng_netflow_disconnect;
   66 
   67 /* Parse type for struct ng_netflow_info */
   68 static const struct ng_parse_struct_field ng_netflow_info_type_fields[]
   69         = NG_NETFLOW_INFO_TYPE;
   70 static const struct ng_parse_type ng_netflow_info_type = {
   71         &ng_parse_struct_type,
   72         &ng_netflow_info_type_fields
   73 };
   74 
   75 /*  Parse type for struct ng_netflow_ifinfo */
   76 static const struct ng_parse_struct_field ng_netflow_ifinfo_type_fields[]
   77         = NG_NETFLOW_IFINFO_TYPE;
   78 static const struct ng_parse_type ng_netflow_ifinfo_type = {
   79         &ng_parse_struct_type,
   80         &ng_netflow_ifinfo_type_fields
   81 };
   82 
   83 /* Parse type for struct ng_netflow_setdlt */
   84 static const struct ng_parse_struct_field ng_netflow_setdlt_type_fields[]
   85         = NG_NETFLOW_SETDLT_TYPE;
   86 static const struct ng_parse_type ng_netflow_setdlt_type = {
   87         &ng_parse_struct_type,
   88         &ng_netflow_setdlt_type_fields
   89 };
   90 
   91 /* Parse type for ng_netflow_setifindex */
   92 static const struct ng_parse_struct_field ng_netflow_setifindex_type_fields[]
   93         = NG_NETFLOW_SETIFINDEX_TYPE;
   94 static const struct ng_parse_type ng_netflow_setifindex_type = {
   95         &ng_parse_struct_type,
   96         &ng_netflow_setifindex_type_fields
   97 };
   98 
   99 /* Parse type for ng_netflow_settimeouts */
  100 static const struct ng_parse_struct_field ng_netflow_settimeouts_type_fields[]
  101         = NG_NETFLOW_SETTIMEOUTS_TYPE;
  102 static const struct ng_parse_type ng_netflow_settimeouts_type = {
  103         &ng_parse_struct_type,
  104         &ng_netflow_settimeouts_type_fields
  105 };
  106 
  107 /* List of commands and how to convert arguments to/from ASCII */
  108 static const struct ng_cmdlist ng_netflow_cmds[] = {
  109        {
  110          NGM_NETFLOW_COOKIE,
  111          NGM_NETFLOW_INFO,
  112          "info",
  113          NULL,
  114          &ng_netflow_info_type
  115        },
  116        {
  117         NGM_NETFLOW_COOKIE,
  118         NGM_NETFLOW_IFINFO,
  119         "ifinfo",
  120         &ng_parse_uint16_type,
  121         &ng_netflow_ifinfo_type
  122        },
  123        {
  124         NGM_NETFLOW_COOKIE,
  125         NGM_NETFLOW_SETDLT,
  126         "setdlt",
  127         &ng_netflow_setdlt_type,
  128         NULL
  129        },
  130        {
  131         NGM_NETFLOW_COOKIE,
  132         NGM_NETFLOW_SETIFINDEX,
  133         "setifindex",
  134         &ng_netflow_setifindex_type,
  135         NULL
  136        },
  137        {
  138         NGM_NETFLOW_COOKIE,
  139         NGM_NETFLOW_SETTIMEOUTS,
  140         "settimeouts",
  141         &ng_netflow_settimeouts_type,
  142         NULL
  143        },
  144        { 0 }
  145 };
  146 
  147 
  148 /* Netgraph node type descriptor */
  149 static struct ng_type ng_netflow_typestruct = {
  150         .version =      NG_ABI_VERSION,
  151         .name =         NG_NETFLOW_NODE_TYPE,
  152         .constructor =  ng_netflow_constructor,
  153         .rcvmsg =       ng_netflow_rcvmsg,
  154         .close =        ng_netflow_close,
  155         .shutdown =     ng_netflow_rmnode,
  156         .newhook =      ng_netflow_newhook,
  157         .rcvdata =      ng_netflow_rcvdata,
  158         .disconnect =   ng_netflow_disconnect,
  159         .cmdlist =      ng_netflow_cmds,
  160 };
  161 NETGRAPH_INIT(netflow, &ng_netflow_typestruct);
  162 
  163 /* Called at node creation */
  164 static int
  165 ng_netflow_constructor (node_p node)
  166 {
  167         priv_p priv;
  168         int error = 0;
  169 
  170         /* Initialize private data */
  171         MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT);
  172         if (priv == NULL)
  173                 return (ENOMEM);
  174         bzero(priv, sizeof(*priv));
  175 
  176         /* Make node and its data point at each other */
  177         NG_NODE_SET_PRIVATE(node, priv);
  178         priv->node = node;
  179 
  180         /* Initialize timeouts to default values */
  181         priv->info.nfinfo_inact_t = INACTIVE_TIMEOUT;
  182         priv->info.nfinfo_act_t = ACTIVE_TIMEOUT;
  183 
  184         /* Initialize callout handle */
  185         callout_init(&priv->exp_callout, 1);
  186 
  187         /* Allocate memory and set up flow cache */
  188         if ((error = ng_netflow_cache_init(priv)))
  189                 return (error);
  190 
  191         priv->dgram.header.version = htons(NETFLOW_V5);
  192 
  193         return (0);
  194 }
  195 
  196 /*
  197  * ng_netflow supports two hooks: data and export.
  198  * Incoming traffic is expected on data, and expired
  199  * netflow datagrams are sent to export.
  200  */
  201 static int
  202 ng_netflow_newhook(node_p node, hook_p hook, const char *name)
  203 {
  204         const priv_p priv = NG_NODE_PRIVATE(node);
  205 
  206         if (strncmp(name, NG_NETFLOW_HOOK_DATA, /* an iface hook? */
  207             strlen(NG_NETFLOW_HOOK_DATA)) == 0) {
  208                 iface_p iface;
  209                 int ifnum = -1;
  210                 const char *cp;
  211                 char *eptr;
  212 
  213                 cp = name + strlen(NG_NETFLOW_HOOK_DATA);
  214                 if (!isdigit(*cp) || (cp[0] == '' && cp[1] != '\0'))
  215                         return (EINVAL);
  216 
  217                 ifnum = (int)strtoul(cp, &eptr, 10);
  218                 if (*eptr != '\0' || ifnum < 0 || ifnum >= NG_NETFLOW_MAXIFACES)
  219                         return (EINVAL);
  220 
  221                 /* See if hook is already connected */
  222                 if (priv->ifaces[ifnum].hook != NULL)
  223                         return (EISCONN);
  224 
  225                 iface = &priv->ifaces[ifnum];
  226 
  227                 /* Link private info and hook together */
  228                 NG_HOOK_SET_PRIVATE(hook, iface);
  229                 iface->hook = hook;
  230 
  231                 /*
  232                  * In most cases traffic accounting is done on an
  233                  * Ethernet interface, so default data link type
  234                  * will be DLT_EN10MB.
  235                  */
  236                 iface->info.ifinfo_dlt = DLT_EN10MB;
  237 
  238         } else if (strncmp(name, NG_NETFLOW_HOOK_OUT,
  239             strlen(NG_NETFLOW_HOOK_OUT)) == 0) {
  240                 iface_p iface;
  241                 int ifnum = -1;
  242                 const char *cp;
  243                 char *eptr;
  244 
  245                 cp = name + strlen(NG_NETFLOW_HOOK_OUT);
  246                 if (!isdigit(*cp) || (cp[0] == '' && cp[1] != '\0'))
  247                         return (EINVAL);
  248 
  249                 ifnum = (int)strtoul(cp, &eptr, 10);
  250                 if (*eptr != '\0' || ifnum < 0 || ifnum >= NG_NETFLOW_MAXIFACES)
  251                         return (EINVAL);
  252 
  253                 /* See if hook is already connected */
  254                 if (priv->ifaces[ifnum].out != NULL)
  255                         return (EISCONN);
  256 
  257                 iface = &priv->ifaces[ifnum];
  258 
  259                 /* Link private info and hook together */
  260                 NG_HOOK_SET_PRIVATE(hook, iface);
  261                 iface->out = hook;
  262 
  263         } else if (strcmp(name, NG_NETFLOW_HOOK_EXPORT) == 0) {
  264 
  265                 if (priv->export != NULL)
  266                         return (EISCONN);
  267 
  268                 priv->export = hook;
  269 
  270                 /* Exporter is ready. Let's schedule expiry. */
  271                 callout_reset(&priv->exp_callout, (1*hz), &ng_netflow_expire,
  272                     (void *)priv);
  273         } else
  274                 return (EINVAL);
  275 
  276         return (0);
  277 }
  278 
  279 /* Get a netgraph control message. */
  280 static int
  281 ng_netflow_rcvmsg (node_p node, item_p item, hook_p lasthook)
  282 {
  283         const priv_p priv = NG_NODE_PRIVATE(node);
  284         struct ng_mesg *resp = NULL;
  285         int error = 0;
  286         struct ng_mesg *msg;
  287 
  288         NGI_GET_MSG(item, msg);
  289 
  290         /* Deal with message according to cookie and command */
  291         switch (msg->header.typecookie) {
  292         case NGM_NETFLOW_COOKIE:
  293                 switch (msg->header.cmd) {
  294                 case NGM_NETFLOW_INFO:
  295                 {
  296                         struct ng_netflow_info *i;
  297 
  298                         NG_MKRESPONSE(resp, msg, sizeof(struct ng_netflow_info),
  299                             M_NOWAIT);
  300                         i = (struct ng_netflow_info *)resp->data;
  301                         ng_netflow_copyinfo(priv, i);
  302 
  303                         break;
  304                 }
  305                 case NGM_NETFLOW_IFINFO:
  306                 {
  307                         struct ng_netflow_ifinfo *i;
  308                         const uint16_t *index;
  309 
  310                         if (msg->header.arglen != sizeof(uint16_t))
  311                                  ERROUT(EINVAL);
  312 
  313                         index  = (uint16_t *)msg->data;
  314                         if (*index > NG_NETFLOW_MAXIFACES)
  315                                 ERROUT(EINVAL);
  316 
  317                         /* connected iface? */
  318                         if (priv->ifaces[*index].hook == NULL)
  319                                  ERROUT(EINVAL);
  320 
  321                         NG_MKRESPONSE(resp, msg,
  322                              sizeof(struct ng_netflow_ifinfo), M_NOWAIT);
  323                         i = (struct ng_netflow_ifinfo *)resp->data;
  324                         memcpy((void *)i, (void *)&priv->ifaces[*index].info,
  325                             sizeof(priv->ifaces[*index].info));
  326 
  327                         break;
  328                 }
  329                 case NGM_NETFLOW_SETDLT:
  330                 {
  331                         struct ng_netflow_setdlt *set;
  332                         struct ng_netflow_iface *iface;
  333 
  334                         if (msg->header.arglen != sizeof(struct ng_netflow_setdlt))
  335                                 ERROUT(EINVAL);
  336 
  337                         set = (struct ng_netflow_setdlt *)msg->data;
  338                         if (set->iface > NG_NETFLOW_MAXIFACES)
  339                                 ERROUT(EINVAL);
  340                         iface = &priv->ifaces[set->iface];
  341 
  342                         /* connected iface? */
  343                         if (iface->hook == NULL)
  344                                 ERROUT(EINVAL);
  345 
  346                         switch (set->dlt) {
  347                         case    DLT_EN10MB:
  348                                 iface->info.ifinfo_dlt = DLT_EN10MB;
  349                                 break;
  350                         case    DLT_RAW:
  351                                 iface->info.ifinfo_dlt = DLT_RAW;
  352                                 break;
  353                         default:
  354                                 ERROUT(EINVAL);
  355                         }
  356                         break;
  357                 }
  358                 case NGM_NETFLOW_SETIFINDEX:
  359                 {
  360                         struct ng_netflow_setifindex *set;
  361                         struct ng_netflow_iface *iface;
  362 
  363                         if (msg->header.arglen != sizeof(struct ng_netflow_setifindex))
  364                                 ERROUT(EINVAL);
  365 
  366                         set = (struct ng_netflow_setifindex *)msg->data;
  367                         if (set->iface > NG_NETFLOW_MAXIFACES)
  368                                 ERROUT(EINVAL);
  369                         iface = &priv->ifaces[set->iface];
  370 
  371                         /* connected iface? */
  372                         if (iface->hook == NULL)
  373                                 ERROUT(EINVAL);
  374 
  375                         iface->info.ifinfo_index = set->index;
  376 
  377                         break;
  378                 }
  379                 case NGM_NETFLOW_SETTIMEOUTS:
  380                 {
  381                         struct ng_netflow_settimeouts *set;
  382 
  383                         if (msg->header.arglen != sizeof(struct ng_netflow_settimeouts))
  384                                 ERROUT(EINVAL);
  385 
  386                         set = (struct ng_netflow_settimeouts *)msg->data;
  387 
  388                         priv->info.nfinfo_inact_t = set->inactive_timeout;
  389                         priv->info.nfinfo_act_t = set->active_timeout;
  390 
  391                         break;
  392                 }
  393                 case NGM_NETFLOW_SHOW:
  394                 {
  395                         uint32_t *last;
  396 
  397                         if (msg->header.arglen != sizeof(uint32_t))
  398                                 ERROUT(EINVAL);
  399 
  400                         last = (uint32_t *)msg->data;
  401 
  402                         NG_MKRESPONSE(resp, msg, NGRESP_SIZE, M_NOWAIT);
  403 
  404                         if (!resp)
  405                                 ERROUT(ENOMEM);
  406 
  407                         error = ng_netflow_flow_show(priv, *last, resp);
  408 
  409                         break;
  410                 }
  411                 default:
  412                         ERROUT(EINVAL);         /* unknown command */
  413                         break;
  414                 }
  415                 break;
  416         default:
  417                 ERROUT(EINVAL);         /* incorrect cookie */
  418                 break;
  419         }
  420 
  421         /*
  422          * Take care of synchronous response, if any.
  423          * Free memory and return.
  424          */
  425 done:
  426         NG_RESPOND_MSG(error, node, item, resp);
  427         NG_FREE_MSG(msg);
  428 
  429         return (error);
  430 }
  431 
  432 /* Receive data on hook. */
  433 static int
  434 ng_netflow_rcvdata (hook_p hook, item_p item)
  435 {
  436         const node_p node = NG_HOOK_NODE(hook);
  437         const priv_p priv = NG_NODE_PRIVATE(node);
  438         const iface_p iface = NG_HOOK_PRIVATE(hook);
  439         struct mbuf *m = NULL;
  440         struct ip *ip;
  441         int pullup_len = 0;
  442         int error = 0;
  443 
  444         if (hook == priv->export) {
  445                 /*
  446                  * Data arrived on export hook.
  447                  * This must not happen.
  448                  */
  449                 log(LOG_ERR, "ng_netflow: incoming data on export hook!\n");
  450                 ERROUT(EINVAL);
  451         };
  452 
  453         if (hook == iface->out) {
  454                 /*
  455                  * Data arrived on out hook. Bypass it.
  456                  */
  457                 if (iface->hook == NULL)
  458                         ERROUT(ENOTCONN);
  459 
  460                 NG_FWD_ITEM_HOOK(error, item, iface->hook);
  461                 return (error);
  462         }
  463 
  464         NGI_GET_M(item, m);
  465 
  466         /* Increase counters. */
  467         iface->info.ifinfo_packets++;
  468 
  469         /*
  470          * Depending on interface data link type and packet contents
  471          * we pullup enough data, so that ng_netflow_flow_add() does not
  472          * need to know about mbuf at all. We keep current length of data
  473          * needed to be contiguous in pullup_len. mtod() is done at the
  474          * very end one more time, since m can had changed after pulluping.
  475          *
  476          * In case of unrecognized data we don't return error, but just
  477          * pass data to downstream hook, if it is available.
  478          */
  479 
  480 #define M_CHECK(length) do {                                    \
  481         pullup_len += length;                                   \
  482         if ((m)->m_pkthdr.len < (pullup_len)) {                 \
  483                 error = EINVAL;                                 \
  484                 goto bypass;                                    \
  485         }                                                       \
  486         if ((m)->m_len < (pullup_len) &&                        \
  487            (((m) = m_pullup((m),(pullup_len))) == NULL)) {      \
  488                 error = ENOBUFS;                                \
  489                 goto done;                                      \
  490         }                                                       \
  491 } while (0)
  492 
  493         switch (iface->info.ifinfo_dlt) {
  494         case DLT_EN10MB:        /* Ethernet */
  495             {
  496                 struct ether_header *eh;
  497                 uint16_t etype;
  498 
  499                 M_CHECK(sizeof(struct ether_header));
  500                 eh = mtod(m, struct ether_header *);
  501 
  502                 /* Make sure this is IP frame. */
  503                 etype = ntohs(eh->ether_type);
  504                 switch (etype) {
  505                 case ETHERTYPE_IP:
  506                         M_CHECK(sizeof(struct ip));
  507                         eh = mtod(m, struct ether_header *);
  508                         ip = (struct ip *)(eh + 1);
  509                         break;
  510                 default:
  511                         goto bypass;    /* pass this frame */
  512                 }
  513                 break;
  514             }
  515         case DLT_RAW:           /* IP packets */
  516                 M_CHECK(sizeof(struct ip));
  517                 ip = mtod(m, struct ip *);
  518                 break;
  519         default:
  520                 goto bypass;
  521                 break;
  522         }
  523 
  524         /*
  525          * In case of IP header with options, we haven't pulled
  526          * up enough, yet.
  527          */
  528         pullup_len += (ip->ip_hl << 2) - sizeof(struct ip);
  529 
  530         switch (ip->ip_p) {
  531         case IPPROTO_TCP:
  532                 M_CHECK(sizeof(struct tcphdr));
  533                 break;
  534         case IPPROTO_UDP:
  535                 M_CHECK(sizeof(struct udphdr));
  536                 break;
  537         }
  538 
  539         switch (iface->info.ifinfo_dlt) {
  540         case DLT_EN10MB:
  541             {
  542                 struct ether_header *eh;
  543 
  544                 eh = mtod(m, struct ether_header *);
  545                 ip = (struct ip *)(eh + 1);
  546                 break;
  547              }
  548         case DLT_RAW:
  549                 ip = mtod(m, struct ip *);
  550                 break;
  551         default:
  552                 panic("ng_netflow entered deadcode");
  553         }
  554 
  555 #undef  M_CHECK
  556 
  557         error = ng_netflow_flow_add(priv, ip, iface, m->m_pkthdr.rcvif);
  558 
  559 bypass:
  560         if (iface->out != NULL) {
  561                 /* XXX: error gets overwritten here */
  562                 NG_FWD_NEW_DATA(error, item, iface->out, m);
  563                 return (error);
  564         }
  565 done:
  566         if (item)
  567                 NG_FREE_ITEM(item);
  568         if (m)
  569                 NG_FREE_M(m);
  570 
  571         return (error); 
  572 }
  573 
  574 /* We will be shut down in a moment */
  575 static int
  576 ng_netflow_close(node_p node)
  577 {
  578         const priv_p priv = NG_NODE_PRIVATE(node);
  579 
  580         callout_drain(&priv->exp_callout);
  581         ng_netflow_cache_flush(priv);
  582 
  583         return (0);
  584 }
  585 
  586 /* Do local shutdown processing. */
  587 static int
  588 ng_netflow_rmnode(node_p node)
  589 {
  590         const priv_p priv = NG_NODE_PRIVATE(node);
  591 
  592         NG_NODE_SET_PRIVATE(node, NULL);
  593         NG_NODE_UNREF(priv->node);
  594 
  595         FREE(priv, M_NETGRAPH);
  596 
  597         return (0);
  598 }
  599 
  600 /* Hook disconnection. */
  601 static int
  602 ng_netflow_disconnect(hook_p hook)
  603 {
  604         node_p node = NG_HOOK_NODE(hook);
  605         priv_p priv = NG_NODE_PRIVATE(node);
  606         iface_p iface = NG_HOOK_PRIVATE(hook);
  607 
  608         if (iface != NULL) {
  609                 if (iface->hook == hook)
  610                         iface->hook = NULL;
  611                 if (iface->out == hook)
  612                         iface->out = NULL;
  613         }
  614 
  615         /* if export hook disconnected stop running expire(). */
  616         if (hook == priv->export) {
  617                 callout_drain(&priv->exp_callout);
  618                 priv->export = NULL;
  619         }
  620 
  621         /* Removal of the last link destroys the node. */
  622         if (NG_NODE_NUMHOOKS(node) == 0)
  623                 ng_rmnode_self(node);
  624 
  625         return (0);
  626 }

Cache object: dce5a0ad607c98d7b35d0287b9eb970c


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