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: releng/6.0/sys/netgraph/netflow/ng_netflow.c 148931 2005-08-10 15:00:57Z glebius $";
   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         return (0);
  192 }
  193 
  194 /*
  195  * ng_netflow supports two hooks: data and export.
  196  * Incoming traffic is expected on data, and expired
  197  * netflow datagrams are sent to export.
  198  */
  199 static int
  200 ng_netflow_newhook(node_p node, hook_p hook, const char *name)
  201 {
  202         const priv_p priv = NG_NODE_PRIVATE(node);
  203 
  204         if (strncmp(name, NG_NETFLOW_HOOK_DATA, /* an iface hook? */
  205             strlen(NG_NETFLOW_HOOK_DATA)) == 0) {
  206                 iface_p iface;
  207                 int ifnum = -1;
  208                 const char *cp;
  209                 char *eptr;
  210 
  211                 cp = name + strlen(NG_NETFLOW_HOOK_DATA);
  212                 if (!isdigit(*cp) || (cp[0] == '' && cp[1] != '\0'))
  213                         return (EINVAL);
  214 
  215                 ifnum = (int)strtoul(cp, &eptr, 10);
  216                 if (*eptr != '\0' || ifnum < 0 || ifnum >= NG_NETFLOW_MAXIFACES)
  217                         return (EINVAL);
  218 
  219                 /* See if hook is already connected */
  220                 if (priv->ifaces[ifnum].hook != NULL)
  221                         return (EISCONN);
  222 
  223                 iface = &priv->ifaces[ifnum];
  224 
  225                 /* Link private info and hook together */
  226                 NG_HOOK_SET_PRIVATE(hook, iface);
  227                 iface->hook = hook;
  228 
  229                 /*
  230                  * In most cases traffic accounting is done on an
  231                  * Ethernet interface, so default data link type
  232                  * will be DLT_EN10MB.
  233                  */
  234                 iface->info.ifinfo_dlt = DLT_EN10MB;
  235 
  236         } else if (strncmp(name, NG_NETFLOW_HOOK_OUT,
  237             strlen(NG_NETFLOW_HOOK_OUT)) == 0) {
  238                 iface_p iface;
  239                 int ifnum = -1;
  240                 const char *cp;
  241                 char *eptr;
  242 
  243                 cp = name + strlen(NG_NETFLOW_HOOK_OUT);
  244                 if (!isdigit(*cp) || (cp[0] == '' && cp[1] != '\0'))
  245                         return (EINVAL);
  246 
  247                 ifnum = (int)strtoul(cp, &eptr, 10);
  248                 if (*eptr != '\0' || ifnum < 0 || ifnum >= NG_NETFLOW_MAXIFACES)
  249                         return (EINVAL);
  250 
  251                 /* See if hook is already connected */
  252                 if (priv->ifaces[ifnum].out != NULL)
  253                         return (EISCONN);
  254 
  255                 iface = &priv->ifaces[ifnum];
  256 
  257                 /* Link private info and hook together */
  258                 NG_HOOK_SET_PRIVATE(hook, iface);
  259                 iface->out = hook;
  260 
  261         } else if (strcmp(name, NG_NETFLOW_HOOK_EXPORT) == 0) {
  262 
  263                 if (priv->export != NULL)
  264                         return (EISCONN);
  265 
  266                 priv->export = hook;
  267 
  268 #if 0   /* TODO: profile & test first */
  269                 /*
  270                  * We send export dgrams in interrupt handlers and in
  271                  * callout threads. We'd better queue data for later
  272                  * netgraph ISR processing.
  273                  */
  274                 NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
  275 #endif
  276 
  277                 /* Exporter is ready. Let's schedule expiry. */
  278                 callout_reset(&priv->exp_callout, (1*hz), &ng_netflow_expire,
  279                     (void *)priv);
  280         } else
  281                 return (EINVAL);
  282 
  283         return (0);
  284 }
  285 
  286 /* Get a netgraph control message. */
  287 static int
  288 ng_netflow_rcvmsg (node_p node, item_p item, hook_p lasthook)
  289 {
  290         const priv_p priv = NG_NODE_PRIVATE(node);
  291         struct ng_mesg *resp = NULL;
  292         int error = 0;
  293         struct ng_mesg *msg;
  294 
  295         NGI_GET_MSG(item, msg);
  296 
  297         /* Deal with message according to cookie and command */
  298         switch (msg->header.typecookie) {
  299         case NGM_NETFLOW_COOKIE:
  300                 switch (msg->header.cmd) {
  301                 case NGM_NETFLOW_INFO:
  302                 {
  303                         struct ng_netflow_info *i;
  304 
  305                         NG_MKRESPONSE(resp, msg, sizeof(struct ng_netflow_info),
  306                             M_NOWAIT);
  307                         i = (struct ng_netflow_info *)resp->data;
  308                         ng_netflow_copyinfo(priv, i);
  309 
  310                         break;
  311                 }
  312                 case NGM_NETFLOW_IFINFO:
  313                 {
  314                         struct ng_netflow_ifinfo *i;
  315                         const uint16_t *index;
  316 
  317                         if (msg->header.arglen != sizeof(uint16_t))
  318                                  ERROUT(EINVAL);
  319 
  320                         index  = (uint16_t *)msg->data;
  321                         if (*index > NG_NETFLOW_MAXIFACES)
  322                                 ERROUT(EINVAL);
  323 
  324                         /* connected iface? */
  325                         if (priv->ifaces[*index].hook == NULL)
  326                                  ERROUT(EINVAL);
  327 
  328                         NG_MKRESPONSE(resp, msg,
  329                              sizeof(struct ng_netflow_ifinfo), M_NOWAIT);
  330                         i = (struct ng_netflow_ifinfo *)resp->data;
  331                         memcpy((void *)i, (void *)&priv->ifaces[*index].info,
  332                             sizeof(priv->ifaces[*index].info));
  333 
  334                         break;
  335                 }
  336                 case NGM_NETFLOW_SETDLT:
  337                 {
  338                         struct ng_netflow_setdlt *set;
  339                         struct ng_netflow_iface *iface;
  340 
  341                         if (msg->header.arglen != sizeof(struct ng_netflow_setdlt))
  342                                 ERROUT(EINVAL);
  343 
  344                         set = (struct ng_netflow_setdlt *)msg->data;
  345                         if (set->iface > NG_NETFLOW_MAXIFACES)
  346                                 ERROUT(EINVAL);
  347                         iface = &priv->ifaces[set->iface];
  348 
  349                         /* connected iface? */
  350                         if (iface->hook == NULL)
  351                                 ERROUT(EINVAL);
  352 
  353                         switch (set->dlt) {
  354                         case    DLT_EN10MB:
  355                                 iface->info.ifinfo_dlt = DLT_EN10MB;
  356                                 break;
  357                         case    DLT_RAW:
  358                                 iface->info.ifinfo_dlt = DLT_RAW;
  359                                 break;
  360                         default:
  361                                 ERROUT(EINVAL);
  362                         }
  363                         break;
  364                 }
  365                 case NGM_NETFLOW_SETIFINDEX:
  366                 {
  367                         struct ng_netflow_setifindex *set;
  368                         struct ng_netflow_iface *iface;
  369 
  370                         if (msg->header.arglen != sizeof(struct ng_netflow_setifindex))
  371                                 ERROUT(EINVAL);
  372 
  373                         set = (struct ng_netflow_setifindex *)msg->data;
  374                         if (set->iface > NG_NETFLOW_MAXIFACES)
  375                                 ERROUT(EINVAL);
  376                         iface = &priv->ifaces[set->iface];
  377 
  378                         /* connected iface? */
  379                         if (iface->hook == NULL)
  380                                 ERROUT(EINVAL);
  381 
  382                         iface->info.ifinfo_index = set->index;
  383 
  384                         break;
  385                 }
  386                 case NGM_NETFLOW_SETTIMEOUTS:
  387                 {
  388                         struct ng_netflow_settimeouts *set;
  389 
  390                         if (msg->header.arglen != sizeof(struct ng_netflow_settimeouts))
  391                                 ERROUT(EINVAL);
  392 
  393                         set = (struct ng_netflow_settimeouts *)msg->data;
  394 
  395                         priv->info.nfinfo_inact_t = set->inactive_timeout;
  396                         priv->info.nfinfo_act_t = set->active_timeout;
  397 
  398                         break;
  399                 }
  400                 case NGM_NETFLOW_SHOW:
  401                 {
  402                         uint32_t *last;
  403 
  404                         if (msg->header.arglen != sizeof(uint32_t))
  405                                 ERROUT(EINVAL);
  406 
  407                         last = (uint32_t *)msg->data;
  408 
  409                         NG_MKRESPONSE(resp, msg, NGRESP_SIZE, M_NOWAIT);
  410 
  411                         if (!resp)
  412                                 ERROUT(ENOMEM);
  413 
  414                         error = ng_netflow_flow_show(priv, *last, resp);
  415 
  416                         break;
  417                 }
  418                 default:
  419                         ERROUT(EINVAL);         /* unknown command */
  420                         break;
  421                 }
  422                 break;
  423         default:
  424                 ERROUT(EINVAL);         /* incorrect cookie */
  425                 break;
  426         }
  427 
  428         /*
  429          * Take care of synchronous response, if any.
  430          * Free memory and return.
  431          */
  432 done:
  433         NG_RESPOND_MSG(error, node, item, resp);
  434         NG_FREE_MSG(msg);
  435 
  436         return (error);
  437 }
  438 
  439 /* Receive data on hook. */
  440 static int
  441 ng_netflow_rcvdata (hook_p hook, item_p item)
  442 {
  443         const node_p node = NG_HOOK_NODE(hook);
  444         const priv_p priv = NG_NODE_PRIVATE(node);
  445         const iface_p iface = NG_HOOK_PRIVATE(hook);
  446         struct mbuf *m = NULL;
  447         struct ip *ip;
  448         int pullup_len = 0;
  449         int error = 0;
  450 
  451         if (hook == priv->export) {
  452                 /*
  453                  * Data arrived on export hook.
  454                  * This must not happen.
  455                  */
  456                 log(LOG_ERR, "ng_netflow: incoming data on export hook!\n");
  457                 ERROUT(EINVAL);
  458         };
  459 
  460         if (hook == iface->out) {
  461                 /*
  462                  * Data arrived on out hook. Bypass it.
  463                  */
  464                 if (iface->hook == NULL)
  465                         ERROUT(ENOTCONN);
  466 
  467                 NG_FWD_ITEM_HOOK(error, item, iface->hook);
  468                 return (error);
  469         }
  470 
  471         NGI_GET_M(item, m);
  472 
  473         /* Increase counters. */
  474         iface->info.ifinfo_packets++;
  475 
  476         /*
  477          * Depending on interface data link type and packet contents
  478          * we pullup enough data, so that ng_netflow_flow_add() does not
  479          * need to know about mbuf at all. We keep current length of data
  480          * needed to be contiguous in pullup_len. mtod() is done at the
  481          * very end one more time, since m can had changed after pulluping.
  482          *
  483          * In case of unrecognized data we don't return error, but just
  484          * pass data to downstream hook, if it is available.
  485          */
  486 
  487 #define M_CHECK(length) do {                                    \
  488         pullup_len += length;                                   \
  489         if ((m)->m_pkthdr.len < (pullup_len)) {                 \
  490                 error = EINVAL;                                 \
  491                 goto bypass;                                    \
  492         }                                                       \
  493         if ((m)->m_len < (pullup_len) &&                        \
  494            (((m) = m_pullup((m),(pullup_len))) == NULL)) {      \
  495                 error = ENOBUFS;                                \
  496                 goto done;                                      \
  497         }                                                       \
  498 } while (0)
  499 
  500         switch (iface->info.ifinfo_dlt) {
  501         case DLT_EN10MB:        /* Ethernet */
  502             {
  503                 struct ether_header *eh;
  504                 uint16_t etype;
  505 
  506                 M_CHECK(sizeof(struct ether_header));
  507                 eh = mtod(m, struct ether_header *);
  508 
  509                 /* Make sure this is IP frame. */
  510                 etype = ntohs(eh->ether_type);
  511                 switch (etype) {
  512                 case ETHERTYPE_IP:
  513                         M_CHECK(sizeof(struct ip));
  514                         eh = mtod(m, struct ether_header *);
  515                         ip = (struct ip *)(eh + 1);
  516                         break;
  517                 default:
  518                         goto bypass;    /* pass this frame */
  519                 }
  520                 break;
  521             }
  522         case DLT_RAW:           /* IP packets */
  523                 M_CHECK(sizeof(struct ip));
  524                 ip = mtod(m, struct ip *);
  525                 break;
  526         default:
  527                 goto bypass;
  528                 break;
  529         }
  530 
  531         if ((ip->ip_off & htons(IP_OFFMASK)) == 0) {
  532                 /*
  533                  * In case of IP header with options, we haven't pulled
  534                  * up enough, yet.
  535                  */
  536                 pullup_len += (ip->ip_hl << 2) - sizeof(struct ip);
  537 
  538                 switch (ip->ip_p) {
  539                 case IPPROTO_TCP:
  540                         M_CHECK(sizeof(struct tcphdr));
  541                         break;
  542                 case IPPROTO_UDP:
  543                         M_CHECK(sizeof(struct udphdr));
  544                         break;
  545                 }
  546         }
  547 
  548         switch (iface->info.ifinfo_dlt) {
  549         case DLT_EN10MB:
  550             {
  551                 struct ether_header *eh;
  552 
  553                 eh = mtod(m, struct ether_header *);
  554                 ip = (struct ip *)(eh + 1);
  555                 break;
  556              }
  557         case DLT_RAW:
  558                 ip = mtod(m, struct ip *);
  559                 break;
  560         default:
  561                 panic("ng_netflow entered deadcode");
  562         }
  563 
  564 #undef  M_CHECK
  565 
  566         error = ng_netflow_flow_add(priv, ip, iface, m->m_pkthdr.rcvif);
  567 
  568 bypass:
  569         if (iface->out != NULL) {
  570                 /* XXX: error gets overwritten here */
  571                 NG_FWD_NEW_DATA(error, item, iface->out, m);
  572                 return (error);
  573         }
  574 done:
  575         if (item)
  576                 NG_FREE_ITEM(item);
  577         if (m)
  578                 NG_FREE_M(m);
  579 
  580         return (error); 
  581 }
  582 
  583 /* We will be shut down in a moment */
  584 static int
  585 ng_netflow_close(node_p node)
  586 {
  587         const priv_p priv = NG_NODE_PRIVATE(node);
  588 
  589         callout_drain(&priv->exp_callout);
  590         ng_netflow_cache_flush(priv);
  591 
  592         return (0);
  593 }
  594 
  595 /* Do local shutdown processing. */
  596 static int
  597 ng_netflow_rmnode(node_p node)
  598 {
  599         const priv_p priv = NG_NODE_PRIVATE(node);
  600 
  601         NG_NODE_SET_PRIVATE(node, NULL);
  602         NG_NODE_UNREF(priv->node);
  603 
  604         FREE(priv, M_NETGRAPH);
  605 
  606         return (0);
  607 }
  608 
  609 /* Hook disconnection. */
  610 static int
  611 ng_netflow_disconnect(hook_p hook)
  612 {
  613         node_p node = NG_HOOK_NODE(hook);
  614         priv_p priv = NG_NODE_PRIVATE(node);
  615         iface_p iface = NG_HOOK_PRIVATE(hook);
  616 
  617         if (iface != NULL)
  618                 iface->hook = NULL;
  619 
  620         /* if export hook disconnected stop running expire(). */
  621         if (hook == priv->export) {
  622                 callout_drain(&priv->exp_callout);
  623                 priv->export = NULL;
  624         }
  625 
  626         /* Removal of the last link destroys the node. */
  627         if (NG_NODE_NUMHOOKS(node) == 0)
  628                 ng_rmnode_self(node);
  629 
  630         return (0);
  631 }

Cache object: d1dfa90ccd1478b39dcae5891e171bd5


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