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

Cache object: aeb13bd5c30da7d92c4a698ba42d4b6e


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