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/netpfil/ipfw/ip_fw_table_value.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) 2014 Yandex LLC
    3  * Copyright (c) 2014 Alexander V. Chernikov
    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, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 /*
   31  * Multi-field value support for ipfw tables.
   32  *
   33  * This file contains necessary functions to convert
   34  * large multi-field values into u32 indices suitable to be fed
   35  * to various table algorithms. Other machinery like proper refcounting,
   36  * internal structures resizing are also kept here.
   37  */
   38 
   39 #include "opt_ipfw.h"
   40 
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/malloc.h>
   44 #include <sys/kernel.h>
   45 #include <sys/hash.h>
   46 #include <sys/lock.h>
   47 #include <sys/rwlock.h>
   48 #include <sys/rmlock.h>
   49 #include <sys/socket.h>
   50 #include <sys/socketvar.h>
   51 #include <sys/queue.h>
   52 #include <net/if.h>     /* ip_fw.h requires IFNAMSIZ */
   53 
   54 #include <netinet/in.h>
   55 #include <netinet/ip_var.h>     /* struct ipfw_rule_ref */
   56 #include <netinet/ip_fw.h>
   57 
   58 #include <netpfil/ipfw/ip_fw_private.h>
   59 #include <netpfil/ipfw/ip_fw_table.h>
   60 
   61 static uint32_t hash_table_value(struct namedobj_instance *ni, const void *key,
   62     uint32_t kopt);
   63 static int cmp_table_value(struct named_object *no, const void *key,
   64     uint32_t kopt);
   65 
   66 static int list_table_values(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
   67     struct sockopt_data *sd);
   68 
   69 static struct ipfw_sopt_handler scodes[] = {
   70         { IP_FW_TABLE_VLIST,    0,      HDIR_GET,       list_table_values },
   71 };
   72 
   73 #define CHAIN_TO_VI(chain)      (CHAIN_TO_TCFG(chain)->valhash)
   74 
   75 struct table_val_link
   76 {
   77         struct named_object     no;
   78         struct table_value      *pval;  /* Pointer to real table value */
   79 };
   80 #define VALDATA_START_SIZE      64      /* Allocate 64-items array by default */
   81 
   82 struct vdump_args {
   83         struct ip_fw_chain *ch;
   84         struct sockopt_data *sd;
   85         struct table_value *pval;
   86         int error;
   87 };
   88 
   89 static uint32_t
   90 hash_table_value(struct namedobj_instance *ni, const void *key, uint32_t kopt)
   91 {
   92 
   93         return (hash32_buf(key, 56, 0));
   94 }
   95 
   96 static int
   97 cmp_table_value(struct named_object *no, const void *key, uint32_t kopt)
   98 {
   99 
  100         return (memcmp(((struct table_val_link *)no)->pval, key, 56));
  101 }
  102 
  103 static void
  104 mask_table_value(struct table_value *src, struct table_value *dst,
  105     uint32_t mask)
  106 {
  107 #define _MCPY(f, b)     if ((mask & (b)) != 0) { dst->f = src->f; }
  108 
  109         memset(dst, 0, sizeof(*dst));
  110         _MCPY(tag, IPFW_VTYPE_TAG);
  111         _MCPY(pipe, IPFW_VTYPE_PIPE);
  112         _MCPY(divert, IPFW_VTYPE_DIVERT);
  113         _MCPY(skipto, IPFW_VTYPE_SKIPTO);
  114         _MCPY(netgraph, IPFW_VTYPE_NETGRAPH);
  115         _MCPY(fib, IPFW_VTYPE_FIB);
  116         _MCPY(nat, IPFW_VTYPE_NAT);
  117         _MCPY(dscp, IPFW_VTYPE_DSCP);
  118         _MCPY(nh4, IPFW_VTYPE_NH4);
  119         _MCPY(nh6, IPFW_VTYPE_NH6);
  120         _MCPY(zoneid, IPFW_VTYPE_NH6);
  121 #undef  _MCPY
  122 }
  123 
  124 static void
  125 get_value_ptrs(struct ip_fw_chain *ch, struct table_config *tc, int vshared,
  126     struct table_value **ptv, struct namedobj_instance **pvi)
  127 {
  128         struct table_value *pval;
  129         struct namedobj_instance *vi;
  130 
  131         if (vshared != 0) {
  132                 pval = (struct table_value *)ch->valuestate;
  133                 vi = CHAIN_TO_VI(ch);
  134         } else {
  135                 pval = NULL;
  136                 vi = NULL;
  137                 //pval = (struct table_value *)&tc->ti.data;
  138         }
  139 
  140         if (ptv != NULL)
  141                 *ptv = pval;
  142         if (pvi != NULL)
  143                 *pvi = vi;
  144 }
  145 
  146 /*
  147  * Update pointers to real vaues after @pval change.
  148  */
  149 static int
  150 update_tvalue(struct namedobj_instance *ni, struct named_object *no, void *arg)
  151 {
  152         struct vdump_args *da;
  153         struct table_val_link *ptv;
  154         struct table_value *pval;
  155 
  156         da = (struct vdump_args *)arg;
  157         ptv = (struct table_val_link *)no;
  158 
  159         pval = da->pval;
  160         ptv->pval = &pval[ptv->no.kidx];
  161         ptv->no.name = (char *)&pval[ptv->no.kidx];
  162         return (0);
  163 }
  164 
  165 /*
  166  * Grows value storage shared among all tables.
  167  * Drops/reacquires UH locks.
  168  * Notifies other running adds on @ch shared storage resize.
  169  * Note function does not guarantee that free space
  170  * will be available after invocation, so one caller needs
  171  * to roll cycle himself.
  172  *
  173  * Returns 0 if case of no errors.
  174  */
  175 static int
  176 resize_shared_value_storage(struct ip_fw_chain *ch)
  177 {
  178         struct tables_config *tcfg;
  179         struct namedobj_instance *vi;
  180         struct table_value *pval, *valuestate, *old_valuestate;
  181         void *new_idx;
  182         struct vdump_args da;
  183         int new_blocks;
  184         int val_size, val_size_old;
  185 
  186         IPFW_UH_WLOCK_ASSERT(ch);
  187 
  188         valuestate = NULL;
  189         new_idx = NULL;
  190 
  191         pval = (struct table_value *)ch->valuestate;
  192         vi = CHAIN_TO_VI(ch);
  193         tcfg = CHAIN_TO_TCFG(ch);
  194 
  195         val_size = tcfg->val_size * 2;
  196 
  197         if (val_size == (1 << 30))
  198                 return (ENOSPC);
  199 
  200         IPFW_UH_WUNLOCK(ch);
  201 
  202         valuestate = malloc(sizeof(struct table_value) * val_size, M_IPFW,
  203             M_WAITOK | M_ZERO);
  204         ipfw_objhash_bitmap_alloc(val_size, (void *)&new_idx,
  205             &new_blocks);
  206 
  207         IPFW_UH_WLOCK(ch);
  208 
  209         /*
  210          * Check if we still need to resize
  211          */
  212         if (tcfg->val_size >= val_size)
  213                 goto done;
  214 
  215         /* Update pointers and notify everyone we're changing @ch */
  216         pval = (struct table_value *)ch->valuestate;
  217         rollback_toperation_state(ch, ch);
  218 
  219         /* Good. Let's merge */
  220         memcpy(valuestate, pval, sizeof(struct table_value) * tcfg->val_size);
  221         ipfw_objhash_bitmap_merge(CHAIN_TO_VI(ch), &new_idx, &new_blocks);
  222 
  223         IPFW_WLOCK(ch);
  224         /* Change pointers */
  225         old_valuestate = ch->valuestate;
  226         ch->valuestate = valuestate;
  227         valuestate = old_valuestate;
  228         ipfw_objhash_bitmap_swap(CHAIN_TO_VI(ch), &new_idx, &new_blocks);
  229 
  230         val_size_old = tcfg->val_size;
  231         tcfg->val_size = val_size;
  232         val_size = val_size_old;
  233         IPFW_WUNLOCK(ch);
  234         /* Update pointers to reflect resize */
  235         memset(&da, 0, sizeof(da));
  236         da.pval = (struct table_value *)ch->valuestate;
  237         ipfw_objhash_foreach(vi, update_tvalue, &da);
  238 
  239 done:
  240         free(valuestate, M_IPFW);
  241         ipfw_objhash_bitmap_free(new_idx, new_blocks);
  242 
  243         return (0);
  244 }
  245 
  246 /*
  247  * Drops reference for table value with index @kidx, stored in @pval and
  248  * @vi. Frees value if it has no references.
  249  */
  250 static void
  251 unref_table_value(struct namedobj_instance *vi, struct table_value *pval,
  252     uint32_t kidx)
  253 {
  254         struct table_val_link *ptvl;
  255 
  256         KASSERT(pval[kidx].refcnt > 0, ("Refcount is 0 on kidx %d", kidx));
  257         if (--pval[kidx].refcnt > 0)
  258                 return;
  259 
  260         /* Last reference, delete item */
  261         ptvl = (struct table_val_link *)ipfw_objhash_lookup_kidx(vi, kidx);
  262         KASSERT(ptvl != NULL, ("lookup on value kidx %d failed", kidx));
  263         ipfw_objhash_del(vi, &ptvl->no);
  264         ipfw_objhash_free_idx(vi, kidx);
  265         free(ptvl, M_IPFW);
  266 }
  267 
  268 struct flush_args {
  269         struct ip_fw_chain *ch;
  270         struct table_algo *ta;
  271         struct table_info *ti;
  272         void *astate;
  273         ipfw_obj_tentry tent;
  274 };
  275 
  276 static int
  277 unref_table_value_cb(void *e, void *arg)
  278 {
  279         struct flush_args *fa;
  280         struct ip_fw_chain *ch;
  281         struct table_algo *ta;
  282         ipfw_obj_tentry *tent;
  283         int error;
  284 
  285         fa = (struct flush_args *)arg;
  286 
  287         ta = fa->ta;
  288         memset(&fa->tent, 0, sizeof(fa->tent));
  289         tent = &fa->tent;
  290         error = ta->dump_tentry(fa->astate, fa->ti, e, tent);
  291         if (error != 0)
  292                 return (error);
  293 
  294         ch = fa->ch;
  295 
  296         unref_table_value(CHAIN_TO_VI(ch),
  297             (struct table_value *)ch->valuestate, tent->v.kidx);
  298 
  299         return (0);
  300 }
  301 
  302 /*
  303  * Drop references for each value used in @tc.
  304  */
  305 void
  306 ipfw_unref_table_values(struct ip_fw_chain *ch, struct table_config *tc,
  307     struct table_algo *ta, void *astate, struct table_info *ti)
  308 {
  309         struct flush_args fa;
  310 
  311         IPFW_UH_WLOCK_ASSERT(ch);
  312 
  313         memset(&fa, 0, sizeof(fa));
  314         fa.ch = ch;
  315         fa.ta = ta;
  316         fa.astate = astate;
  317         fa.ti = ti;
  318 
  319         ta->foreach(astate, ti, unref_table_value_cb, &fa);
  320 }
  321 
  322 /*
  323  * Table operation state handler.
  324  * Called when we are going to change something in @tc which
  325  * may lead to inconsistencies in on-going table data addition.
  326  *
  327  * Here we rollback all already committed state (table values, currently)
  328  * and set "modified" field to non-zero value to indicate
  329  * that we need to restart original operation.
  330  */
  331 void
  332 rollback_table_values(struct tableop_state *ts)
  333 {
  334         struct ip_fw_chain *ch;
  335         struct table_value *pval;
  336         struct tentry_info *ptei;
  337         struct namedobj_instance *vi;
  338         int i;
  339 
  340         ch = ts->ch;
  341 
  342         IPFW_UH_WLOCK_ASSERT(ch);
  343 
  344         /* Get current table value pointer */
  345         get_value_ptrs(ch, ts->tc, ts->vshared, &pval, &vi);
  346 
  347         for (i = 0; i < ts->count; i++) {
  348                 ptei = &ts->tei[i];
  349 
  350                 if (ptei->value == 0)
  351                         continue;
  352 
  353                 unref_table_value(vi, pval, ptei->value);
  354         }
  355 }
  356 
  357 /*
  358  * Allocate new value index in either shared or per-table array.
  359  * Function may drop/reacquire UH lock.
  360  *
  361  * Returns 0 on success.
  362  */
  363 static int
  364 alloc_table_vidx(struct ip_fw_chain *ch, struct tableop_state *ts,
  365     struct namedobj_instance *vi, uint16_t *pvidx, uint8_t flags)
  366 {
  367         int error, vlimit;
  368         uint16_t vidx;
  369 
  370         IPFW_UH_WLOCK_ASSERT(ch);
  371 
  372         error = ipfw_objhash_alloc_idx(vi, &vidx);
  373         if (error != 0) {
  374                 /*
  375                  * We need to resize array. This involves
  376                  * lock/unlock, so we need to check "modified"
  377                  * state.
  378                  */
  379                 ts->opstate.func(ts->tc, &ts->opstate);
  380                 error = resize_shared_value_storage(ch);
  381                 return (error); /* ts->modified should be set, we will restart */
  382         }
  383 
  384         vlimit = ts->ta->vlimit;
  385         if (vlimit != 0 && vidx >= vlimit && !(flags & IPFW_CTF_ATOMIC)) {
  386                 /*
  387                  * Algorithm is not able to store given index.
  388                  * We have to rollback state, start using
  389                  * per-table value array or return error
  390                  * if we're already using it.
  391                  */
  392                 if (ts->vshared != 0) {
  393                         /* shared -> per-table  */
  394                         return (ENOSPC); /* TODO: proper error */
  395                 }
  396 
  397                 /* per-table. Fail for now. */
  398                 return (ENOSPC); /* TODO: proper error */
  399         }
  400 
  401         *pvidx = vidx;
  402         return (0);
  403 }
  404 
  405 /*
  406  * Drops value reference for unused values (updates, deletes, partially
  407  * successful adds or rollbacks).
  408  */
  409 void
  410 ipfw_garbage_table_values(struct ip_fw_chain *ch, struct table_config *tc,
  411     struct tentry_info *tei, uint32_t count, int rollback)
  412 {
  413         int i;
  414         struct tentry_info *ptei;
  415         struct table_value *pval;
  416         struct namedobj_instance *vi;
  417 
  418         /*
  419          * We have two slightly different ADD cases here:
  420          * either (1) we are successful / partially successful,
  421          * in that case we need
  422          * * to ignore ADDED entries values
  423          * * rollback every other values if atomicity is not
  424          * * required (either UPDATED since old value has been
  425          *   stored there, or some failure like EXISTS or LIMIT
  426          *   or simply "ignored" case.
  427          *
  428          * (2): atomic rollback of partially successful operation
  429          * in that case we simply need to unref all entries.
  430          *
  431          * DELETE case is simpler: no atomic support there, so
  432          * we simply unref all non-zero values.
  433          */
  434 
  435         /*
  436          * Get current table value pointers.
  437          * XXX: Properly read vshared
  438          */
  439         get_value_ptrs(ch, tc, 1, &pval, &vi);
  440 
  441         for (i = 0; i < count; i++) {
  442                 ptei = &tei[i];
  443 
  444                 if (ptei->value == 0) {
  445                         /*
  446                          * We may be deleting non-existing record.
  447                          * Skip.
  448                          */
  449                         continue;
  450                 }
  451 
  452                 if ((ptei->flags & TEI_FLAGS_ADDED) != 0 && rollback == 0) {
  453                         ptei->value = 0;
  454                         continue;
  455                 }
  456 
  457                 unref_table_value(vi, pval, ptei->value);
  458                 ptei->value = 0;
  459         }
  460 }
  461 
  462 /*
  463  * Main function used to link values of entries going to be added,
  464  * to the index. Since we may perform many UH locks drops/acquires,
  465  * handle changes by checking tablestate "modified" field.
  466  *
  467  * Success: return 0.
  468  */
  469 int
  470 ipfw_link_table_values(struct ip_fw_chain *ch, struct tableop_state *ts,
  471     uint8_t flags)
  472 {
  473         int error, i, found;
  474         struct namedobj_instance *vi;
  475         struct table_config *tc;
  476         struct tentry_info *tei, *ptei;
  477         uint32_t count, vlimit;
  478         uint16_t vidx;
  479         struct table_val_link *ptv;
  480         struct table_value tval, *pval;
  481 
  482         /*
  483          * Stage 1: reference all existing values and
  484          * save their indices.
  485          */
  486         IPFW_UH_WLOCK_ASSERT(ch);
  487         get_value_ptrs(ch, ts->tc, ts->vshared, &pval, &vi);
  488 
  489         error = 0;
  490         found = 0;
  491         vlimit = ts->ta->vlimit;
  492         vidx = 0;
  493         tc = ts->tc;
  494         tei = ts->tei;
  495         count = ts->count;
  496         for (i = 0; i < count; i++) {
  497                 ptei = &tei[i];
  498                 ptei->value = 0; /* Ensure value is always 0 in the beginning */
  499                 mask_table_value(ptei->pvalue, &tval, ts->vmask);
  500                 ptv = (struct table_val_link *)ipfw_objhash_lookup_name(vi, 0,
  501                     (char *)&tval);
  502                 if (ptv == NULL)
  503                         continue;
  504                 /* Deal with vlimit later */
  505                 if (vlimit > 0 && vlimit <= ptv->no.kidx)
  506                         continue;
  507 
  508                 /* Value found. Bump refcount */
  509                 ptv->pval->refcnt++;
  510                 ptei->value = ptv->no.kidx;
  511                 found++;
  512         }
  513 
  514         if (ts->count == found) {
  515                 /* We've found all values , no need ts create new ones */
  516                 return (0);
  517         }
  518 
  519         /*
  520          * we have added some state here, let's attach operation
  521          * state ts the list ts be able ts rollback if necessary.
  522          */
  523         add_toperation_state(ch, ts);
  524         /* Ensure table won't disappear */
  525         tc_ref(tc);
  526         IPFW_UH_WUNLOCK(ch);
  527 
  528         /*
  529          * Stage 2: allocate objects for non-existing values.
  530          */
  531         for (i = 0; i < count; i++) {
  532                 ptei = &tei[i];
  533                 if (ptei->value != 0)
  534                         continue;
  535                 if (ptei->ptv != NULL)
  536                         continue;
  537                 ptei->ptv = malloc(sizeof(struct table_val_link), M_IPFW,
  538                     M_WAITOK | M_ZERO);
  539         }
  540 
  541         /*
  542          * Stage 3: allocate index numbers for new values
  543          * and link them to index.
  544          */
  545         IPFW_UH_WLOCK(ch);
  546         tc_unref(tc);
  547         del_toperation_state(ch, ts);
  548         if (ts->modified != 0) {
  549                 /*
  550                  * In general, we should free all state/indexes here
  551                  * and return. However, we keep allocated state instead
  552                  * to ensure we achieve some progress on each restart.
  553                  */
  554                 return (0);
  555         }
  556 
  557         KASSERT(pval == ch->valuestate, ("resize_storage() notify failure"));
  558 
  559         /* Let's try to link values */
  560         for (i = 0; i < count; i++) {
  561                 ptei = &tei[i];
  562 
  563                 /* Check if record has appeared */
  564                 mask_table_value(ptei->pvalue, &tval, ts->vmask);
  565                 ptv = (struct table_val_link *)ipfw_objhash_lookup_name(vi, 0,
  566                     (char *)&tval);
  567                 if (ptv != NULL) {
  568                         ptv->pval->refcnt++;
  569                         ptei->value = ptv->no.kidx;
  570                         continue;
  571                 }
  572 
  573                 /* May perform UH unlock/lock */
  574                 error = alloc_table_vidx(ch, ts, vi, &vidx, flags);
  575                 if (error != 0) {
  576                         ts->opstate.func(ts->tc, &ts->opstate);
  577                         return (error);
  578                 }
  579                 /* value storage resize has happened, return */
  580                 if (ts->modified != 0)
  581                         return (0);
  582 
  583                 /* Finally, we have allocated valid index, let's add entry */
  584                 ptei->value = vidx;
  585                 ptv = (struct table_val_link *)ptei->ptv;
  586                 ptei->ptv = NULL;
  587 
  588                 ptv->no.kidx = vidx;
  589                 ptv->no.name = (char *)&pval[vidx];
  590                 ptv->pval = &pval[vidx];
  591                 memcpy(ptv->pval, &tval, sizeof(struct table_value));
  592                 pval[vidx].refcnt = 1;
  593                 ipfw_objhash_add(vi, &ptv->no);
  594         }
  595 
  596         return (0);
  597 }
  598 
  599 /*
  600  * Compatibility function used to import data from old
  601  * IP_FW_TABLE_ADD / IP_FW_TABLE_XADD opcodes.
  602  */
  603 void
  604 ipfw_import_table_value_legacy(uint32_t value, struct table_value *v)
  605 {
  606 
  607         memset(v, 0, sizeof(*v));
  608         v->tag = value;
  609         v->pipe = value;
  610         v->divert = value;
  611         v->skipto = value;
  612         v->netgraph = value;
  613         v->fib = value;
  614         v->nat = value;
  615         v->nh4 = value; /* host format */
  616         v->dscp = value;
  617         v->limit = value;
  618 }
  619 
  620 /*
  621  * Export data to legacy table dumps opcodes.
  622  */
  623 uint32_t
  624 ipfw_export_table_value_legacy(struct table_value *v)
  625 {
  626 
  627         /*
  628          * TODO: provide more compatibility depending on
  629          * vmask value.
  630          */
  631         return (v->tag);
  632 }
  633 
  634 /*
  635  * Imports table value from current userland format.
  636  * Saves value in kernel format to the same place.
  637  */
  638 void
  639 ipfw_import_table_value_v1(ipfw_table_value *iv)
  640 {
  641         struct table_value v;
  642 
  643         memset(&v, 0, sizeof(v));
  644         v.tag = iv->tag;
  645         v.pipe = iv->pipe;
  646         v.divert = iv->divert;
  647         v.skipto = iv->skipto;
  648         v.netgraph = iv->netgraph;
  649         v.fib = iv->fib;
  650         v.nat = iv->nat;
  651         v.dscp = iv->dscp;
  652         v.nh4 = iv->nh4;
  653         v.nh6 = iv->nh6;
  654         v.limit = iv->limit;
  655         v.zoneid = iv->zoneid;
  656 
  657         memcpy(iv, &v, sizeof(ipfw_table_value));
  658 }
  659 
  660 /*
  661  * Export real table value @v to current userland format.
  662  * Note that @v and @piv may point to the same memory.
  663  */
  664 void
  665 ipfw_export_table_value_v1(struct table_value *v, ipfw_table_value *piv)
  666 {
  667         ipfw_table_value iv;
  668 
  669         memset(&iv, 0, sizeof(iv));
  670         iv.tag = v->tag;
  671         iv.pipe = v->pipe;
  672         iv.divert = v->divert;
  673         iv.skipto = v->skipto;
  674         iv.netgraph = v->netgraph;
  675         iv.fib = v->fib;
  676         iv.nat = v->nat;
  677         iv.dscp = v->dscp;
  678         iv.limit = v->limit;
  679         iv.nh4 = v->nh4;
  680         iv.nh6 = v->nh6;
  681         iv.zoneid = v->zoneid;
  682 
  683         memcpy(piv, &iv, sizeof(iv));
  684 }
  685 
  686 /*
  687  * Exports real value data into ipfw_table_value structure.
  688  * Utilizes "spare1" field to store kernel index.
  689  */
  690 static int
  691 dump_tvalue(struct namedobj_instance *ni, struct named_object *no, void *arg)
  692 {
  693         struct vdump_args *da;
  694         struct table_val_link *ptv;
  695         struct table_value *v;
  696 
  697         da = (struct vdump_args *)arg;
  698         ptv = (struct table_val_link *)no;
  699 
  700         v = (struct table_value *)ipfw_get_sopt_space(da->sd, sizeof(*v));
  701         /* Out of memory, returning */
  702         if (v == NULL) {
  703                 da->error = ENOMEM;
  704                 return (ENOMEM);
  705         }
  706 
  707         memcpy(v, ptv->pval, sizeof(*v));
  708         v->spare1 = ptv->no.kidx;
  709         return (0);
  710 }
  711 
  712 /*
  713  * Dumps all shared/table value data
  714  * Data layout (v1)(current):
  715  * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size
  716  * Reply: [ ipfw_obj_lheader ipfw_table_value x N ]
  717  *
  718  * Returns 0 on success
  719  */
  720 static int
  721 list_table_values(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
  722     struct sockopt_data *sd)
  723 {
  724         struct _ipfw_obj_lheader *olh;
  725         struct namedobj_instance *vi;
  726         struct vdump_args da;
  727         uint32_t count, size;
  728 
  729         olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh));
  730         if (olh == NULL)
  731                 return (EINVAL);
  732         if (sd->valsize < olh->size)
  733                 return (EINVAL);
  734 
  735         IPFW_UH_RLOCK(ch);
  736         vi = CHAIN_TO_VI(ch);
  737 
  738         count = ipfw_objhash_count(vi);
  739         size = count * sizeof(ipfw_table_value) + sizeof(ipfw_obj_lheader);
  740 
  741         /* Fill in header regadless of buffer size */
  742         olh->count = count;
  743         olh->objsize = sizeof(ipfw_table_value);
  744 
  745         if (size > olh->size) {
  746                 olh->size = size;
  747                 IPFW_UH_RUNLOCK(ch);
  748                 return (ENOMEM);
  749         }
  750         olh->size = size;
  751 
  752         /*
  753          * Do the actual value dump
  754          */
  755         memset(&da, 0, sizeof(da));
  756         da.ch = ch;
  757         da.sd = sd;
  758         ipfw_objhash_foreach(vi, dump_tvalue, &da);
  759 
  760         IPFW_UH_RUNLOCK(ch);
  761 
  762         return (0);
  763 }
  764 
  765 void
  766 ipfw_table_value_init(struct ip_fw_chain *ch, int first)
  767 {
  768         struct tables_config *tcfg;
  769 
  770         ch->valuestate = malloc(VALDATA_START_SIZE * sizeof(struct table_value),
  771             M_IPFW, M_WAITOK | M_ZERO);
  772 
  773         tcfg = ch->tblcfg;
  774 
  775         tcfg->val_size = VALDATA_START_SIZE;
  776         tcfg->valhash = ipfw_objhash_create(tcfg->val_size);
  777         ipfw_objhash_set_funcs(tcfg->valhash, hash_table_value,
  778             cmp_table_value);
  779 
  780         IPFW_ADD_SOPT_HANDLER(first, scodes);
  781 }
  782 
  783 static int
  784 destroy_value(struct namedobj_instance *ni, struct named_object *no,
  785     void *arg)
  786 {
  787 
  788         free(no, M_IPFW);
  789         return (0);
  790 }
  791 
  792 void
  793 ipfw_table_value_destroy(struct ip_fw_chain *ch, int last)
  794 {
  795 
  796         IPFW_DEL_SOPT_HANDLER(last, scodes);
  797 
  798         free(ch->valuestate, M_IPFW);
  799         ipfw_objhash_foreach(CHAIN_TO_VI(ch), destroy_value, ch);
  800         ipfw_objhash_destroy(CHAIN_TO_VI(ch));
  801 }

Cache object: 409e23981164eace300d438ce24f5040


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