File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / bird / filter / filter.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 19:50:23 2021 UTC (3 years, 4 months ago) by misho
Branches: bird, MAIN
CVS tags: v1_6_8p3, HEAD
bird 1.6.8

    1: /*
    2:  *	Filters: utility functions
    3:  *
    4:  *	Copyright 1998 Pavel Machek <pavel@ucw.cz>
    5:  *
    6:  *	Can be freely distributed and used under the terms of the GNU GPL.
    7:  *
    8:  */
    9: 
   10: /**
   11:  * DOC: Filters
   12:  *
   13:  * You can find sources of the filter language in |filter/|
   14:  * directory. File |filter/config.Y| contains filter grammar and basically translates
   15:  * the source from user into a tree of &f_inst structures. These trees are
   16:  * later interpreted using code in |filter/filter.c|.
   17:  *
   18:  * A filter is represented by a tree of &f_inst structures, one structure per
   19:  * "instruction". Each &f_inst contains @code, @aux value which is
   20:  * usually the data type this instruction operates on and two generic
   21:  * arguments (@a1, @a2). Some instructions contain pointer(s) to other
   22:  * instructions in their (@a1, @a2) fields.
   23:  *
   24:  * Filters use a &f_val structure for their data. Each &f_val
   25:  * contains type and value (types are constants prefixed with %T_). Few
   26:  * of the types are special; %T_RETURN can be or-ed with a type to indicate
   27:  * that return from a function or from the whole filter should be
   28:  * forced. Important thing about &f_val's is that they may be copied
   29:  * with a simple |=|. That's fine for all currently defined types: strings
   30:  * are read-only (and therefore okay), paths are copied for each
   31:  * operation (okay too).
   32:  */
   33: 
   34: #undef LOCAL_DEBUG
   35: 
   36: #include "nest/bird.h"
   37: #include "lib/lists.h"
   38: #include "lib/resource.h"
   39: #include "lib/socket.h"
   40: #include "lib/string.h"
   41: #include "lib/unaligned.h"
   42: #include "nest/route.h"
   43: #include "nest/protocol.h"
   44: #include "nest/iface.h"
   45: #include "nest/attrs.h"
   46: #include "conf/conf.h"
   47: #include "filter/filter.h"
   48: 
   49: #define CMP_ERROR 999
   50: 
   51: static struct adata *
   52: adata_empty(struct linpool *pool, int l)
   53: {
   54:   struct adata *res = lp_alloc(pool, sizeof(struct adata) + l);
   55:   res->length = l;
   56:   return res;
   57: }
   58: 
   59: static void
   60: pm_format(struct f_path_mask *p, buffer *buf)
   61: {
   62:   buffer_puts(buf, "[= ");
   63: 
   64:   while (p)
   65:   {
   66:     switch(p->kind)
   67:     {
   68:     case PM_ASN:
   69:       buffer_print(buf, "%u ", p->val);
   70:       break;
   71: 
   72:     case PM_QUESTION:
   73:       buffer_puts(buf, "? ");
   74:       break;
   75: 
   76:     case PM_ASTERISK:
   77:       buffer_puts(buf, "* ");
   78:       break;
   79: 
   80:     case PM_ASN_RANGE:
   81:       buffer_print(buf, "%u..%u ", p->val, p->val2);
   82:       break;
   83: 
   84:     case PM_ASN_EXPR:
   85:       ASSERT(0);
   86:     }
   87: 
   88:     p = p->next;
   89:   }
   90: 
   91:   buffer_puts(buf, "=]");
   92: }
   93: 
   94: static inline int
   95: uint_cmp(uint i1, uint i2)
   96: {
   97:   return (int)(i1 > i2) - (int)(i1 < i2);
   98: }
   99: 
  100: static inline int
  101: u64_cmp(u64 i1, u64 i2)
  102: {
  103:   return (int)(i1 > i2) - (int)(i1 < i2);
  104: }
  105: 
  106: static inline int
  107: lcomm_cmp(lcomm v1, lcomm v2)
  108: {
  109:   if (v1.asn != v2.asn)
  110:     return (v1.asn > v2.asn) ? 1 : -1;
  111:   if (v1.ldp1 != v2.ldp1)
  112:     return (v1.ldp1 > v2.ldp1) ? 1 : -1;
  113:   if (v1.ldp2 != v2.ldp2)
  114:     return (v1.ldp2 > v2.ldp2) ? 1 : -1;
  115:   return 0;
  116: }
  117: 
  118: /**
  119:  * val_compare - compare two values
  120:  * @v1: first value
  121:  * @v2: second value
  122:  *
  123:  * Compares two values and returns -1, 0, 1 on <, =, > or CMP_ERROR on
  124:  * error. Tree module relies on this giving consistent results so
  125:  * that it can be used for building balanced trees.
  126:  */
  127: int
  128: val_compare(struct f_val v1, struct f_val v2)
  129: {
  130:   int rc;
  131: 
  132:   if (v1.type != v2.type) {
  133:     if (v1.type == T_VOID)	/* Hack for else */
  134:       return -1;
  135:     if (v2.type == T_VOID)
  136:       return 1;
  137: 
  138: #ifndef IPV6
  139:     /* IP->Quad implicit conversion */
  140:     if ((v1.type == T_QUAD) && (v2.type == T_IP))
  141:       return uint_cmp(v1.val.i, ipa_to_u32(v2.val.px.ip));
  142:     if ((v1.type == T_IP) && (v2.type == T_QUAD))
  143:       return uint_cmp(ipa_to_u32(v1.val.px.ip), v2.val.i);
  144: #endif
  145: 
  146:     debug( "Types do not match in val_compare\n" );
  147:     return CMP_ERROR;
  148:   }
  149: 
  150:   switch (v1.type) {
  151:   case T_VOID:
  152:     return 0;
  153:   case T_ENUM:
  154:   case T_INT:
  155:   case T_BOOL:
  156:   case T_PAIR:
  157:   case T_QUAD:
  158:     return uint_cmp(v1.val.i, v2.val.i);
  159:   case T_EC:
  160:     return u64_cmp(v1.val.ec, v2.val.ec);
  161:   case T_LC:
  162:     return lcomm_cmp(v1.val.lc, v2.val.lc);
  163:   case T_IP:
  164:     return ipa_compare(v1.val.px.ip, v2.val.px.ip);
  165:   case T_PREFIX:
  166:     if (rc = ipa_compare(v1.val.px.ip, v2.val.px.ip))
  167:       return rc;
  168:     return uint_cmp(v1.val.px.len, v2.val.px.len);
  169:   case T_STRING:
  170:     return strcmp(v1.val.s, v2.val.s);
  171:   default:
  172:     return CMP_ERROR;
  173:   }
  174: }
  175: 
  176: static int
  177: pm_same(struct f_path_mask *m1, struct f_path_mask *m2)
  178: {
  179:   while (m1 && m2)
  180:   {
  181:     if (m1->kind != m2->kind)
  182:       return 0;
  183: 
  184:     if (m1->kind == PM_ASN_EXPR)
  185:     {
  186:       if (!i_same((struct f_inst *) m1->val, (struct f_inst *) m2->val))
  187: 	return 0;
  188:     }
  189:     else
  190:     {
  191:       if ((m1->val != m2->val) || (m1->val2 != m2->val2))
  192: 	return 0;
  193:     }
  194: 
  195:     m1 = m1->next;
  196:     m2 = m2->next;
  197:   }
  198: 
  199:   return !m1 && !m2;
  200: }
  201: 
  202: /**
  203:  * val_same - compare two values
  204:  * @v1: first value
  205:  * @v2: second value
  206:  *
  207:  * Compares two values and returns 1 if they are same and 0 if not.
  208:  * Comparison of values of different types is valid and returns 0.
  209:  */
  210: int
  211: val_same(struct f_val v1, struct f_val v2)
  212: {
  213:   int rc;
  214: 
  215:   rc = val_compare(v1, v2);
  216:   if (rc != CMP_ERROR)
  217:     return !rc;
  218: 
  219:   if (v1.type != v2.type)
  220:     return 0;
  221: 
  222:   switch (v1.type) {
  223:   case T_PATH_MASK:
  224:     return pm_same(v1.val.path_mask, v2.val.path_mask);
  225:   case T_PATH:
  226:   case T_CLIST:
  227:   case T_ECLIST:
  228:   case T_LCLIST:
  229:     return adata_same(v1.val.ad, v2.val.ad);
  230:   case T_SET:
  231:     return same_tree(v1.val.t, v2.val.t);
  232:   case T_PREFIX_SET:
  233:     return trie_same(v1.val.ti, v2.val.ti);
  234:   default:
  235:     bug("Invalid type in val_same(): %x", v1.type);
  236:   }
  237: }
  238: 
  239: void
  240: fprefix_get_bounds(struct f_prefix *px, int *l, int *h)
  241: {
  242:   *l = *h = px->len & LEN_MASK;
  243: 
  244:   if (px->len & LEN_MINUS)
  245:     *l = 0;
  246: 
  247:   else if (px->len & LEN_PLUS)
  248:     *h = MAX_PREFIX_LENGTH;
  249: 
  250:   else if (px->len & LEN_RANGE)
  251:     {
  252:       *l = 0xff & (px->len >> 16);
  253:       *h = 0xff & (px->len >> 8);
  254:     }
  255: }
  256: 
  257: static int
  258: clist_set_type(struct f_tree *set, struct f_val *v)
  259: {
  260:  switch (set->from.type) {
  261:   case T_PAIR:
  262:     v->type = T_PAIR;
  263:     return 1;
  264:   case T_QUAD:
  265: #ifndef IPV6
  266:   case T_IP:
  267: #endif
  268:     v->type = T_QUAD;
  269:     return 1;
  270:     break;
  271:   default:
  272:     v->type = T_VOID;
  273:     return 0;
  274:   }
  275: }
  276: 
  277: static inline int
  278: eclist_set_type(struct f_tree *set)
  279: { return set->from.type == T_EC; }
  280: 
  281: static inline int
  282: lclist_set_type(struct f_tree *set)
  283: { return set->from.type == T_LC; }
  284: 
  285: static int
  286: clist_match_set(struct adata *clist, struct f_tree *set)
  287: {
  288:   if (!clist)
  289:     return 0;
  290: 
  291:   struct f_val v;
  292:   if (!clist_set_type(set, &v))
  293:     return CMP_ERROR;
  294: 
  295:   u32 *l = (u32 *) clist->data;
  296:   u32 *end = l + clist->length/4;
  297: 
  298:   while (l < end) {
  299:     v.val.i = *l++;
  300:     if (find_tree(set, v))
  301:       return 1;
  302:   }
  303:   return 0;
  304: }
  305: 
  306: static int
  307: eclist_match_set(struct adata *list, struct f_tree *set)
  308: {
  309:   if (!list)
  310:     return 0;
  311: 
  312:   if (!eclist_set_type(set))
  313:     return CMP_ERROR;
  314: 
  315:   struct f_val v;
  316:   u32 *l = int_set_get_data(list);
  317:   int len = int_set_get_size(list);
  318:   int i;
  319: 
  320:   v.type = T_EC;
  321:   for (i = 0; i < len; i += 2) {
  322:     v.val.ec = ec_get(l, i);
  323:     if (find_tree(set, v))
  324:       return 1;
  325:   }
  326: 
  327:   return 0;
  328: }
  329: 
  330: static int
  331: lclist_match_set(struct adata *list, struct f_tree *set)
  332: {
  333:   if (!list)
  334:     return 0;
  335: 
  336:   if (!lclist_set_type(set))
  337:     return CMP_ERROR;
  338: 
  339:   struct f_val v;
  340:   u32 *l = int_set_get_data(list);
  341:   int len = int_set_get_size(list);
  342:   int i;
  343: 
  344:   v.type = T_LC;
  345:   for (i = 0; i < len; i += 3) {
  346:     v.val.lc = lc_get(l, i);
  347:     if (find_tree(set, v))
  348:       return 1;
  349:   }
  350: 
  351:   return 0;
  352: }
  353: 
  354: static struct adata *
  355: clist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos)
  356: {
  357:   if (!list)
  358:     return NULL;
  359: 
  360:   int tree = (set.type == T_SET);	/* 1 -> set is T_SET, 0 -> set is T_CLIST */
  361:   struct f_val v;
  362:   if (tree)
  363:     clist_set_type(set.val.t, &v);
  364:   else
  365:     v.type = T_PAIR;
  366: 
  367:   int len = int_set_get_size(list);
  368:   u32 *l = int_set_get_data(list);
  369:   u32 tmp[len];
  370:   u32 *k = tmp;
  371:   u32 *end = l + len;
  372: 
  373:   while (l < end) {
  374:     v.val.i = *l++;
  375:     /* pos && member(val, set) || !pos && !member(val, set),  member() depends on tree */
  376:     if ((tree ? !!find_tree(set.val.t, v) : int_set_contains(set.val.ad, v.val.i)) == pos)
  377:       *k++ = v.val.i;
  378:   }
  379: 
  380:   uint nl = (k - tmp) * sizeof(u32);
  381:   if (nl == list->length)
  382:     return list;
  383: 
  384:   struct adata *res = adata_empty(pool, nl);
  385:   memcpy(res->data, tmp, nl);
  386:   return res;
  387: }
  388: 
  389: static struct adata *
  390: eclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos)
  391: {
  392:   if (!list)
  393:     return NULL;
  394: 
  395:   int tree = (set.type == T_SET);	/* 1 -> set is T_SET, 0 -> set is T_CLIST */
  396:   struct f_val v;
  397: 
  398:   int len = int_set_get_size(list);
  399:   u32 *l = int_set_get_data(list);
  400:   u32 tmp[len];
  401:   u32 *k = tmp;
  402:   int i;
  403: 
  404:   v.type = T_EC;
  405:   for (i = 0; i < len; i += 2) {
  406:     v.val.ec = ec_get(l, i);
  407:     /* pos && member(val, set) || !pos && !member(val, set),  member() depends on tree */
  408:     if ((tree ? !!find_tree(set.val.t, v) : ec_set_contains(set.val.ad, v.val.ec)) == pos) {
  409:       *k++ = l[i];
  410:       *k++ = l[i+1];
  411:     }
  412:   }
  413: 
  414:   uint nl = (k - tmp) * sizeof(u32);
  415:   if (nl == list->length)
  416:     return list;
  417: 
  418:   struct adata *res = adata_empty(pool, nl);
  419:   memcpy(res->data, tmp, nl);
  420:   return res;
  421: }
  422: 
  423: static struct adata *
  424: lclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos)
  425: {
  426:   if (!list)
  427:     return NULL;
  428: 
  429:   int tree = (set.type == T_SET);	/* 1 -> set is T_SET, 0 -> set is T_CLIST */
  430:   struct f_val v;
  431: 
  432:   int len = int_set_get_size(list);
  433:   u32 *l = int_set_get_data(list);
  434:   u32 tmp[len];
  435:   u32 *k = tmp;
  436:   int i;
  437: 
  438:   v.type = T_LC;
  439:   for (i = 0; i < len; i += 3) {
  440:     v.val.lc = lc_get(l, i);
  441:     /* pos && member(val, set) || !pos && !member(val, set),  member() depends on tree */
  442:     if ((tree ? !!find_tree(set.val.t, v) : lc_set_contains(set.val.ad, v.val.lc)) == pos)
  443:       k = lc_copy(k, l+i);
  444:   }
  445: 
  446:   uint nl = (k - tmp) * sizeof(u32);
  447:   if (nl == list->length)
  448:     return list;
  449: 
  450:   struct adata *res = adata_empty(pool, nl);
  451:   memcpy(res->data, tmp, nl);
  452:   return res;
  453: }
  454: 
  455: /**
  456:  * val_in_range - implement |~| operator
  457:  * @v1: element
  458:  * @v2: set
  459:  *
  460:  * Checks if @v1 is element (|~| operator) of @v2.
  461:  */
  462: static int
  463: val_in_range(struct f_val v1, struct f_val v2)
  464: {
  465:   if ((v1.type == T_PATH) && (v2.type == T_PATH_MASK))
  466:     return as_path_match(v1.val.ad, v2.val.path_mask);
  467: 
  468:   if ((v1.type == T_INT) && (v2.type == T_PATH))
  469:     return as_path_contains(v2.val.ad, v1.val.i, 1);
  470: 
  471:   if (((v1.type == T_PAIR) || (v1.type == T_QUAD)) && (v2.type == T_CLIST))
  472:     return int_set_contains(v2.val.ad, v1.val.i);
  473: #ifndef IPV6
  474:   /* IP->Quad implicit conversion */
  475:   if ((v1.type == T_IP) && (v2.type == T_CLIST))
  476:     return int_set_contains(v2.val.ad, ipa_to_u32(v1.val.px.ip));
  477: #endif
  478: 
  479:   if ((v1.type == T_EC) && (v2.type == T_ECLIST))
  480:     return ec_set_contains(v2.val.ad, v1.val.ec);
  481: 
  482:   if ((v1.type == T_LC) && (v2.type == T_LCLIST))
  483:     return lc_set_contains(v2.val.ad, v1.val.lc);
  484: 
  485:   if ((v1.type == T_STRING) && (v2.type == T_STRING))
  486:     return patmatch(v2.val.s, v1.val.s);
  487: 
  488:   if ((v1.type == T_IP) && (v2.type == T_PREFIX))
  489:     return ipa_in_net(v1.val.px.ip, v2.val.px.ip, v2.val.px.len);
  490: 
  491:   if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX))
  492:     return net_in_net(v1.val.px.ip, v1.val.px.len, v2.val.px.ip, v2.val.px.len);
  493: 
  494:   if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX_SET))
  495:     return trie_match_fprefix(v2.val.ti, &v1.val.px);
  496: 
  497:   if (v2.type != T_SET)
  498:     return CMP_ERROR;
  499: 
  500:   /* With integrated Quad<->IP implicit conversion */
  501:   if ((v1.type == v2.val.t->from.type) ||
  502:       ((IP_VERSION == 4) && (v1.type == T_QUAD) && (v2.val.t->from.type == T_IP)))
  503:     return !!find_tree(v2.val.t, v1);
  504: 
  505:   if (v1.type == T_CLIST)
  506:     return clist_match_set(v1.val.ad, v2.val.t);
  507: 
  508:   if (v1.type == T_ECLIST)
  509:     return eclist_match_set(v1.val.ad, v2.val.t);
  510: 
  511:   if (v1.type == T_LCLIST)
  512:     return lclist_match_set(v1.val.ad, v2.val.t);
  513: 
  514:   if (v1.type == T_PATH)
  515:     return as_path_match_set(v1.val.ad, v2.val.t);
  516: 
  517:   return CMP_ERROR;
  518: }
  519: 
  520: /*
  521:  * val_format - format filter value
  522:  */
  523: void
  524: val_format(struct f_val v, buffer *buf)
  525: {
  526:   char buf2[1024];
  527:   switch (v.type)
  528:   {
  529:   case T_VOID:	buffer_puts(buf, "(void)"); return;
  530:   case T_BOOL:	buffer_puts(buf, v.val.i ? "TRUE" : "FALSE"); return;
  531:   case T_INT:	buffer_print(buf, "%u", v.val.i); return;
  532:   case T_STRING: buffer_print(buf, "%s", v.val.s); return;
  533:   case T_IP:	buffer_print(buf, "%I", v.val.px.ip); return;
  534:   case T_PREFIX: buffer_print(buf, "%I/%d", v.val.px.ip, v.val.px.len); return;
  535:   case T_PAIR:	buffer_print(buf, "(%u,%u)", v.val.i >> 16, v.val.i & 0xffff); return;
  536:   case T_QUAD:	buffer_print(buf, "%R", v.val.i); return;
  537:   case T_EC:	ec_format(buf2, v.val.ec); buffer_print(buf, "%s", buf2); return;
  538:   case T_LC:	lc_format(buf2, v.val.lc); buffer_print(buf, "%s", buf2); return;
  539:   case T_PREFIX_SET: trie_format(v.val.ti, buf); return;
  540:   case T_SET:	tree_format(v.val.t, buf); return;
  541:   case T_ENUM:	buffer_print(buf, "(enum %x)%u", v.type, v.val.i); return;
  542:   case T_PATH:	as_path_format(v.val.ad, buf2, 1000); buffer_print(buf, "(path %s)", buf2); return;
  543:   case T_CLIST:	int_set_format(v.val.ad, 1, -1, buf2, 1000); buffer_print(buf, "(clist %s)", buf2); return;
  544:   case T_ECLIST: ec_set_format(v.val.ad, -1, buf2, 1000); buffer_print(buf, "(eclist %s)", buf2); return;
  545:   case T_LCLIST: lc_set_format(v.val.ad, -1, buf2, 1000); buffer_print(buf, "(lclist %s)", buf2); return;
  546:   case T_PATH_MASK: pm_format(v.val.path_mask, buf); return;
  547:   default:	buffer_print(buf, "[unknown type %x]", v.type); return;
  548:   }
  549: }
  550: 
  551: static struct rte **f_rte;
  552: static struct rta *f_old_rta;
  553: static struct ea_list **f_tmp_attrs;
  554: static struct linpool *f_pool;
  555: static struct buffer f_buf;
  556: static int f_flags;
  557: 
  558: static inline void f_rte_cow(void)
  559: {
  560:   *f_rte = rte_cow(*f_rte);
  561: }
  562: 
  563: /*
  564:  * rta_cow - prepare rta for modification by filter
  565:  */
  566: static void
  567: f_rta_cow(void)
  568: {
  569:   if (!rta_is_cached((*f_rte)->attrs))
  570:     return;
  571: 
  572:   /* Prepare to modify rte */
  573:   f_rte_cow();
  574: 
  575:   /* Store old rta to free it later, it stores reference from rte_cow() */
  576:   f_old_rta = (*f_rte)->attrs;
  577: 
  578:   /*
  579:    * Get shallow copy of rta. Fields eattrs and nexthops of rta are shared
  580:    * with f_old_rta (they will be copied when the cached rta will be obtained
  581:    * at the end of f_run()), also the lock of hostentry is inherited (we
  582:    * suppose hostentry is not changed by filters).
  583:    */
  584:   (*f_rte)->attrs = rta_do_cow((*f_rte)->attrs, f_pool);
  585: }
  586: 
  587: static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
  588: 
  589: #define runtime(x) do { \
  590:     if (!(f_flags & FF_SILENT)) \
  591:       log_rl(&rl_runtime_err, L_ERR "filters, line %d: %s", what->lineno, x); \
  592:     res.type = T_RETURN; \
  593:     res.val.i = F_ERROR; \
  594:     return res; \
  595:   } while(0)
  596: 
  597: #define ARG(x,y) \
  598: 	x = interpret(what->y); \
  599: 	if (x.type & T_RETURN) \
  600: 		return x;
  601: 
  602: #define ONEARG ARG(v1, a1.p)
  603: #define TWOARGS ARG(v1, a1.p) \
  604: 		ARG(v2, a2.p)
  605: #define TWOARGS_C TWOARGS \
  606:                   if (v1.type != v2.type) \
  607: 		    runtime( "Can't operate with values of incompatible types" );
  608: #define ACCESS_RTE \
  609:   do { if (!f_rte) runtime("No route to access"); } while (0)
  610: 
  611: #define BITFIELD_MASK(what) \
  612:   (1u << (what->a2.i >> 24))
  613: 
  614: /**
  615:  * interpret
  616:  * @what: filter to interpret
  617:  *
  618:  * Interpret given tree of filter instructions. This is core function
  619:  * of filter system and does all the hard work.
  620:  *
  621:  * Each instruction has 4 fields: code (which is instruction code),
  622:  * aux (which is extension to instruction code, typically type),
  623:  * arg1 and arg2 - arguments. Depending on instruction, arguments
  624:  * are either integers, or pointers to instruction trees. Common
  625:  * instructions like +, that have two expressions as arguments use
  626:  * TWOARGS macro to get both of them evaluated.
  627:  *
  628:  * &f_val structures are copied around, so there are no problems with
  629:  * memory managment.
  630:  */
  631: static struct f_val
  632: interpret(struct f_inst *what)
  633: {
  634:   struct symbol *sym;
  635:   struct f_val v1, v2, res = { .type = T_VOID }, *vp;
  636:   unsigned u1, u2;
  637:   int i;
  638:   u32 as;
  639: 
  640:   for ( ; what; what = what->next) {
  641:   res.type = T_VOID;
  642:   switch(what->fi_code) {
  643: /* Binary operators */
  644:   case FI_ADD:
  645:     TWOARGS_C;
  646:     switch (res.type = v1.type) {
  647:     case T_VOID: runtime( "Can't operate with values of type void" );
  648:     case T_INT: res.val.i = v1.val.i + v2.val.i; break;
  649:     default: runtime( "Usage of unknown type" );
  650:     }
  651:     break;
  652:   case FI_SUBTRACT:
  653:     TWOARGS_C;
  654:     switch (res.type = v1.type) {
  655:     case T_VOID: runtime( "Can't operate with values of type void" );
  656:     case T_INT: res.val.i = v1.val.i - v2.val.i; break;
  657:     default: runtime( "Usage of unknown type" );
  658:     }
  659:     break;
  660:   case FI_MULTIPLY:
  661:     TWOARGS_C;
  662:     switch (res.type = v1.type) {
  663:     case T_VOID: runtime( "Can't operate with values of type void" );
  664:     case T_INT: res.val.i = v1.val.i * v2.val.i; break;
  665:     default: runtime( "Usage of unknown type" );
  666:     }
  667:     break;
  668:   case FI_DIVIDE:
  669:     TWOARGS_C;
  670:     switch (res.type = v1.type) {
  671:     case T_VOID: runtime( "Can't operate with values of type void" );
  672:     case T_INT: if (v2.val.i == 0) runtime( "Mother told me not to divide by 0" );
  673:       	        res.val.i = v1.val.i / v2.val.i; break;
  674:     default: runtime( "Usage of unknown type" );
  675:     }
  676:     break;
  677: 
  678:   case FI_AND:
  679:   case FI_OR:
  680:     ARG(v1, a1.p);
  681:     if (v1.type != T_BOOL)
  682:       runtime( "Can't do boolean operation on non-booleans" );
  683:     if (v1.val.i == (what->fi_code == FI_OR)) {
  684:       res.type = T_BOOL;
  685:       res.val.i = v1.val.i;
  686:       break;
  687:     }
  688: 
  689:     ARG(v2, a2.p);
  690:     if (v2.type != T_BOOL)
  691:       runtime( "Can't do boolean operation on non-booleans" );
  692:     res.type = T_BOOL;
  693:     res.val.i = v2.val.i;
  694:     break;
  695: 
  696:   case FI_PAIR_CONSTRUCT:
  697:     TWOARGS;
  698:     if ((v1.type != T_INT) || (v2.type != T_INT))
  699:       runtime( "Can't operate with value of non-integer type in pair constructor" );
  700:     u1 = v1.val.i;
  701:     u2 = v2.val.i;
  702:     if ((u1 > 0xFFFF) || (u2 > 0xFFFF))
  703:       runtime( "Can't operate with value out of bounds in pair constructor" );
  704:     res.val.i = (u1 << 16) | u2;
  705:     res.type = T_PAIR;
  706:     break;
  707: 
  708:   case FI_EC_CONSTRUCT:
  709:     {
  710:       TWOARGS;
  711: 
  712:       int check, ipv4_used;
  713:       u32 key, val;
  714: 
  715:       if (v1.type == T_INT) {
  716: 	ipv4_used = 0; key = v1.val.i;
  717:       }
  718:       else if (v1.type == T_QUAD) {
  719: 	ipv4_used = 1; key = v1.val.i;
  720:       }
  721: #ifndef IPV6
  722:       /* IP->Quad implicit conversion */
  723:       else if (v1.type == T_IP) {
  724: 	ipv4_used = 1; key = ipa_to_u32(v1.val.px.ip);
  725:       }
  726: #endif
  727:       else
  728: 	runtime("Can't operate with key of non-integer/IPv4 type in EC constructor");
  729: 
  730:       if (v2.type != T_INT)
  731: 	runtime("Can't operate with value of non-integer type in EC constructor");
  732:       val = v2.val.i;
  733: 
  734:       /* XXXX */
  735:       res.type = T_EC;
  736: 
  737:       if (what->aux == EC_GENERIC) {
  738: 	check = 0; res.val.ec = ec_generic(key, val);
  739:       }
  740:       else if (ipv4_used) {
  741: 	check = 1; res.val.ec = ec_ip4(what->aux, key, val);
  742:       }
  743:       else if (key < 0x10000) {
  744: 	check = 0; res.val.ec = ec_as2(what->aux, key, val);
  745:       }
  746:       else {
  747: 	check = 1; res.val.ec = ec_as4(what->aux, key, val);
  748:       }
  749: 
  750:       if (check && (val > 0xFFFF))
  751: 	runtime("Can't operate with value out of bounds in EC constructor");
  752: 
  753:       break;
  754:     }
  755: 
  756:   case FI_LC_CONSTRUCT:
  757:     {
  758:       TWOARGS;
  759: 
  760:       /* Third argument hack */
  761:       struct f_val v3 = interpret(INST3(what).p);
  762:       if (v3.type & T_RETURN)
  763: 	return v3;
  764: 
  765:       if ((v1.type != T_INT) || (v2.type != T_INT) || (v3.type != T_INT))
  766: 	runtime( "Can't operate with value of non-integer type in LC constructor" );
  767: 
  768:       res.type = T_LC;
  769:       res.val.lc = (lcomm) { v1.val.i, v2.val.i, v3.val.i };
  770: 
  771:       break;
  772:     }
  773: 
  774:   case FI_PATHMASK_CONSTRUCT:
  775:     {
  776:       struct f_path_mask *tt = what->a1.p, *vbegin, **vv = &vbegin;
  777: 
  778:       while (tt) {
  779: 	*vv = lp_alloc(f_pool, sizeof(struct f_path_mask));
  780: 	if (tt->kind == PM_ASN_EXPR) {
  781: 	  struct f_val res = interpret((struct f_inst *) tt->val);
  782: 	  (*vv)->kind = PM_ASN;
  783: 	  if (res.type != T_INT) {
  784: 	    runtime( "Error resolving path mask template: value not an integer" );
  785: 	    return (struct f_val) { .type = T_VOID };
  786: 	  }
  787: 
  788: 	  (*vv)->val = res.val.i;
  789: 	} else {
  790: 	  **vv = *tt;
  791: 	}
  792: 	tt = tt->next;
  793: 	vv = &((*vv)->next);
  794:       }
  795: 
  796:       res = (struct f_val) { .type = T_PATH_MASK, .val.path_mask = vbegin };
  797:       break;
  798:     }
  799: 
  800: /* Relational operators */
  801: 
  802: #define COMPARE(x) \
  803:     TWOARGS; \
  804:     i = val_compare(v1, v2); \
  805:     if (i==CMP_ERROR) \
  806:       runtime( "Can't compare values of incompatible types" ); \
  807:     res.type = T_BOOL; \
  808:     res.val.i = (x); \
  809:     break;
  810: 
  811: #define SAME(x) \
  812:     TWOARGS; \
  813:     i = val_same(v1, v2); \
  814:     res.type = T_BOOL; \
  815:     res.val.i = (x); \
  816:     break;
  817: 
  818:   case FI_NEQ: SAME(!i);
  819:   case FI_EQ: SAME(i);
  820:   case FI_LT: COMPARE(i==-1);
  821:   case FI_LTE: COMPARE(i!=1);
  822: 
  823:   case FI_NOT:
  824:     ONEARG;
  825:     if (v1.type != T_BOOL)
  826:       runtime( "Not applied to non-boolean" );
  827:     res = v1;
  828:     res.val.i = !res.val.i;
  829:     break;
  830: 
  831:   case FI_MATCH:
  832:     TWOARGS;
  833:     res.type = T_BOOL;
  834:     res.val.i = val_in_range(v1, v2);
  835:     if (res.val.i == CMP_ERROR)
  836:       runtime( "~ applied on unknown type pair" );
  837:     res.val.i = !!res.val.i;
  838:     break;
  839: 
  840:   case FI_NOT_MATCH:
  841:     TWOARGS;
  842:     res.type = T_BOOL;
  843:     res.val.i = val_in_range(v1, v2);
  844:     if (res.val.i == CMP_ERROR)
  845:       runtime( "!~ applied on unknown type pair" );
  846:     res.val.i = !res.val.i;
  847:     break;
  848: 
  849:   case FI_DEFINED:
  850:     ONEARG;
  851:     res.type = T_BOOL;
  852:     res.val.i = (v1.type != T_VOID);
  853:     break;
  854: 
  855:   /* Set to indirect value, a1 = variable, a2 = value */
  856:   case FI_SET:
  857:     ARG(v2, a2.p);
  858:     sym = what->a1.p;
  859:     vp = sym->def;
  860:     if ((sym->class != (SYM_VARIABLE | v2.type)) && (v2.type != T_VOID)) {
  861: #ifndef IPV6
  862:       /* IP->Quad implicit conversion */
  863:       if ((sym->class == (SYM_VARIABLE | T_QUAD)) && (v2.type == T_IP)) {
  864: 	vp->type = T_QUAD;
  865: 	vp->val.i = ipa_to_u32(v2.val.px.ip);
  866: 	break;
  867:       }
  868: #endif
  869:       runtime( "Assigning to variable of incompatible type" );
  870:     }
  871:     *vp = v2;
  872:     break;
  873: 
  874:     /* some constants have value in a2, some in *a1.p, strange. */
  875:   case FI_CONSTANT:	/* integer (or simple type) constant, string, set, or prefix_set */
  876:     res.type = what->aux;
  877: 
  878:     if (res.type == T_PREFIX_SET)
  879:       res.val.ti = what->a2.p;
  880:     else if (res.type == T_SET)
  881:       res.val.t = what->a2.p;
  882:     else if (res.type == T_STRING)
  883:       res.val.s = what->a2.p;
  884:     else
  885:       res.val.i = what->a2.i;
  886:     break;
  887:   case FI_VARIABLE:
  888:   case FI_CONSTANT_INDIRECT:
  889:     res = * ((struct f_val *) what->a1.p);
  890:     break;
  891:   case FI_PRINT:
  892:     ONEARG;
  893:     val_format(v1, &f_buf);
  894:     break;
  895:   case FI_CONDITION:	/* ? has really strange error value, so we can implement if ... else nicely :-) */
  896:     ONEARG;
  897:     if (v1.type != T_BOOL)
  898:       runtime( "If requires boolean expression" );
  899:     if (v1.val.i) {
  900:       ARG(res,a2.p);
  901:       res.val.i = 0;
  902:     } else res.val.i = 1;
  903:     res.type = T_BOOL;
  904:     break;
  905:   case FI_NOP:
  906:     debug( "No operation\n" );
  907:     break;
  908:   case FI_PRINT_AND_DIE:
  909:     ONEARG;
  910:     if ((what->a2.i == F_NOP || (what->a2.i != F_NONL && what->a1.p)) &&
  911: 	!(f_flags & FF_SILENT))
  912:       log_commit(*L_INFO, &f_buf);
  913: 
  914:     switch (what->a2.i) {
  915:     case F_QUITBIRD:
  916:       die( "Filter asked me to die" );
  917:     case F_ACCEPT:
  918:       /* Should take care about turning ACCEPT into MODIFY */
  919:     case F_ERROR:
  920:     case F_REJECT:	/* FIXME (noncritical) Should print complete route along with reason to reject route */
  921:       res.type = T_RETURN;
  922:       res.val.i = what->a2.i;
  923:       return res;	/* We have to return now, no more processing. */
  924:     case F_NONL:
  925:     case F_NOP:
  926:       break;
  927:     default:
  928:       bug( "unknown return type: Can't happen");
  929:     }
  930:     break;
  931:   case FI_RTA_GET:	/* rta access */
  932:     {
  933:       ACCESS_RTE;
  934:       struct rta *rta = (*f_rte)->attrs;
  935:       res.type = what->aux;
  936: 
  937:       switch (what->a2.i)
  938:       {
  939:       case SA_FROM:	res.val.px.ip = rta->from; break;
  940:       case SA_GW:	res.val.px.ip = rta->gw; break;
  941:       case SA_NET:	res.val.px.ip = (*f_rte)->net->n.prefix;
  942: 			res.val.px.len = (*f_rte)->net->n.pxlen; break;
  943:       case SA_PROTO:	res.val.s = rta->src->proto->name; break;
  944:       case SA_SOURCE:	res.val.i = rta->source; break;
  945:       case SA_SCOPE:	res.val.i = rta->scope; break;
  946:       case SA_CAST:	res.val.i = rta->cast; break;
  947:       case SA_DEST:	res.val.i = rta->dest; break;
  948:       case SA_IFNAME:	res.val.s = rta->iface ? rta->iface->name : ""; break;
  949:       case SA_IFINDEX:	res.val.i = rta->iface ? rta->iface->index : 0; break;
  950: 
  951:       default:
  952: 	bug("Invalid static attribute access (%x)", res.type);
  953:       }
  954:     }
  955:     break;
  956:   case FI_RTA_SET:
  957:     ACCESS_RTE;
  958:     ONEARG;
  959:     if (what->aux != v1.type)
  960:       runtime( "Attempt to set static attribute to incompatible type" );
  961: 
  962:     f_rta_cow();
  963:     {
  964:       struct rta *rta = (*f_rte)->attrs;
  965: 
  966:       switch (what->a2.i)
  967:       {
  968:       case SA_FROM:
  969: 	rta->from = v1.val.px.ip;
  970: 	break;
  971: 
  972:       case SA_GW:
  973: 	{
  974: 	  ip_addr ip = v1.val.px.ip;
  975: 	  neighbor *n = neigh_find(rta->src->proto, &ip, 0);
  976: 	  if (!n || (n->scope == SCOPE_HOST))
  977: 	    runtime( "Invalid gw address" );
  978: 
  979: 	  rta->dest = RTD_ROUTER;
  980: 	  rta->gw = ip;
  981: 	  rta->iface = n->iface;
  982: 	  rta->nexthops = NULL;
  983: 	  rta->hostentry = NULL;
  984: 	}
  985: 	break;
  986: 
  987:       case SA_SCOPE:
  988: 	rta->scope = v1.val.i;
  989: 	break;
  990: 
  991:       case SA_DEST:
  992: 	i = v1.val.i;
  993: 	if ((i != RTD_BLACKHOLE) && (i != RTD_UNREACHABLE) && (i != RTD_PROHIBIT))
  994: 	  runtime( "Destination can be changed only to blackhole, unreachable or prohibit" );
  995: 
  996: 	rta->dest = i;
  997: 	rta->gw = IPA_NONE;
  998: 	rta->iface = NULL;
  999: 	rta->nexthops = NULL;
 1000: 	rta->hostentry = NULL;
 1001: 	break;
 1002: 
 1003:       case SA_IFNAME:
 1004: 	{
 1005: 	  struct iface *ifa = if_find_by_name(v1.val.s);
 1006: 	  if (!ifa)
 1007: 	    runtime( "Invalid iface name" );
 1008: 
 1009: 	  rta->dest = RTD_DEVICE;
 1010: 	  rta->gw = IPA_NONE;
 1011: 	  rta->iface = ifa;
 1012: 	  rta->nexthops = NULL;
 1013: 	  rta->hostentry = NULL;
 1014: 	}
 1015: 	break;
 1016: 
 1017:       default:
 1018: 	bug("Invalid static attribute access (%x)", res.type);
 1019:       }
 1020:     }
 1021:     break;
 1022:   case FI_EA_GET:	/* Access to extended attributes */
 1023:     ACCESS_RTE;
 1024:     {
 1025:       eattr *e = NULL;
 1026:       u16 code = what->a2.i;
 1027: 
 1028:       if (!(f_flags & FF_FORCE_TMPATTR))
 1029: 	e = ea_find((*f_rte)->attrs->eattrs, code);
 1030:       if (!e)
 1031: 	e = ea_find((*f_tmp_attrs), code);
 1032:       if ((!e) && (f_flags & FF_FORCE_TMPATTR))
 1033: 	e = ea_find((*f_rte)->attrs->eattrs, code);
 1034: 
 1035:       if (!e) {
 1036: 	/* A special case: undefined int_set looks like empty int_set */
 1037: 	if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_INT_SET) {
 1038: 	  res.type = T_CLIST;
 1039: 	  res.val.ad = adata_empty(f_pool, 0);
 1040: 	  break;
 1041: 	}
 1042: 
 1043: 	/* The same special case for ec_set */
 1044: 	if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_EC_SET) {
 1045: 	  res.type = T_ECLIST;
 1046: 	  res.val.ad = adata_empty(f_pool, 0);
 1047: 	  break;
 1048: 	}
 1049: 
 1050: 	/* The same special case for lc_set */
 1051: 	if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_LC_SET) {
 1052: 	  res.type = T_LCLIST;
 1053: 	  res.val.ad = adata_empty(f_pool, 0);
 1054: 	  break;
 1055: 	}
 1056: 
 1057: 	/* Undefined value */
 1058: 	res.type = T_VOID;
 1059: 	break;
 1060:       }
 1061: 
 1062:       switch (what->aux & EAF_TYPE_MASK) {
 1063:       case EAF_TYPE_INT:
 1064: 	res.type = T_INT;
 1065: 	res.val.i = e->u.data;
 1066: 	break;
 1067:       case EAF_TYPE_ROUTER_ID:
 1068: 	res.type = T_QUAD;
 1069: 	res.val.i = e->u.data;
 1070: 	break;
 1071:       case EAF_TYPE_OPAQUE:
 1072: 	res.type = T_ENUM_EMPTY;
 1073: 	res.val.i = 0;
 1074: 	break;
 1075:       case EAF_TYPE_IP_ADDRESS:
 1076: 	res.type = T_IP;
 1077: 	struct adata * ad = e->u.ptr;
 1078: 	res.val.px.ip = * (ip_addr *) ad->data;
 1079: 	break;
 1080:       case EAF_TYPE_AS_PATH:
 1081:         res.type = T_PATH;
 1082: 	res.val.ad = e->u.ptr;
 1083: 	break;
 1084:       case EAF_TYPE_BITFIELD:
 1085: 	res.type = T_BOOL;
 1086: 	res.val.i = !!(e->u.data & BITFIELD_MASK(what));
 1087: 	break;
 1088:       case EAF_TYPE_INT_SET:
 1089: 	res.type = T_CLIST;
 1090: 	res.val.ad = e->u.ptr;
 1091: 	break;
 1092:       case EAF_TYPE_EC_SET:
 1093: 	res.type = T_ECLIST;
 1094: 	res.val.ad = e->u.ptr;
 1095: 	break;
 1096:       case EAF_TYPE_LC_SET:
 1097: 	res.type = T_LCLIST;
 1098: 	res.val.ad = e->u.ptr;
 1099: 	break;
 1100:       case EAF_TYPE_UNDEF:
 1101: 	res.type = T_VOID;
 1102: 	break;
 1103:       default:
 1104: 	bug("Unknown type in e,a");
 1105:       }
 1106:     }
 1107:     break;
 1108:   case FI_EA_SET:
 1109:     ACCESS_RTE;
 1110:     ONEARG;
 1111:     {
 1112:       struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr));
 1113:       u16 code = what->a2.i;
 1114: 
 1115:       l->next = NULL;
 1116:       l->flags = EALF_SORTED;
 1117:       l->count = 1;
 1118:       l->attrs[0].id = code;
 1119:       l->attrs[0].flags = 0;
 1120:       l->attrs[0].type = what->aux | EAF_ORIGINATED;
 1121: 
 1122:       switch (what->aux & EAF_TYPE_MASK) {
 1123:       case EAF_TYPE_INT:
 1124: 	// Enums are also ints, so allow them in.
 1125: 	if (v1.type != T_INT && (v1.type < T_ENUM_LO || v1.type > T_ENUM_HI))
 1126: 	  runtime( "Setting int attribute to non-int value" );
 1127: 	l->attrs[0].u.data = v1.val.i;
 1128: 	break;
 1129: 
 1130:       case EAF_TYPE_ROUTER_ID:
 1131: #ifndef IPV6
 1132: 	/* IP->Quad implicit conversion */
 1133: 	if (v1.type == T_IP) {
 1134: 	  l->attrs[0].u.data = ipa_to_u32(v1.val.px.ip);
 1135: 	  break;
 1136: 	}
 1137: #endif
 1138: 	/* T_INT for backward compatibility */
 1139: 	if ((v1.type != T_QUAD) && (v1.type != T_INT))
 1140: 	  runtime( "Setting quad attribute to non-quad value" );
 1141: 	l->attrs[0].u.data = v1.val.i;
 1142: 	break;
 1143: 
 1144:       case EAF_TYPE_OPAQUE:
 1145: 	runtime( "Setting opaque attribute is not allowed" );
 1146: 	break;
 1147:       case EAF_TYPE_IP_ADDRESS:
 1148: 	if (v1.type != T_IP)
 1149: 	  runtime( "Setting ip attribute to non-ip value" );
 1150: 	int len = sizeof(ip_addr);
 1151: 	struct adata *ad = lp_alloc(f_pool, sizeof(struct adata) + len);
 1152: 	ad->length = len;
 1153: 	(* (ip_addr *) ad->data) = v1.val.px.ip;
 1154: 	l->attrs[0].u.ptr = ad;
 1155: 	break;
 1156:       case EAF_TYPE_AS_PATH:
 1157: 	if (v1.type != T_PATH)
 1158: 	  runtime( "Setting path attribute to non-path value" );
 1159: 	l->attrs[0].u.ptr = v1.val.ad;
 1160: 	break;
 1161:       case EAF_TYPE_BITFIELD:
 1162: 	if (v1.type != T_BOOL)
 1163: 	  runtime( "Setting bit in bitfield attribute to non-bool value" );
 1164: 	{
 1165: 	  /* First, we have to find the old value */
 1166: 	  eattr *e = NULL;
 1167: 	  if (!(f_flags & FF_FORCE_TMPATTR))
 1168: 	    e = ea_find((*f_rte)->attrs->eattrs, code);
 1169: 	  if (!e)
 1170: 	    e = ea_find((*f_tmp_attrs), code);
 1171: 	  if ((!e) && (f_flags & FF_FORCE_TMPATTR))
 1172: 	    e = ea_find((*f_rte)->attrs->eattrs, code);
 1173: 	  u32 data = e ? e->u.data : 0;
 1174: 
 1175: 	  if (v1.val.i)
 1176: 	    l->attrs[0].u.data = data | BITFIELD_MASK(what);
 1177: 	  else
 1178: 	    l->attrs[0].u.data = data & ~BITFIELD_MASK(what);;
 1179: 	}
 1180: 	break;
 1181:       case EAF_TYPE_INT_SET:
 1182: 	if (v1.type != T_CLIST)
 1183: 	  runtime( "Setting clist attribute to non-clist value" );
 1184: 	l->attrs[0].u.ptr = v1.val.ad;
 1185: 	break;
 1186:       case EAF_TYPE_EC_SET:
 1187: 	if (v1.type != T_ECLIST)
 1188: 	  runtime( "Setting eclist attribute to non-eclist value" );
 1189: 	l->attrs[0].u.ptr = v1.val.ad;
 1190: 	break;
 1191:       case EAF_TYPE_LC_SET:
 1192: 	if (v1.type != T_LCLIST)
 1193: 	  runtime( "Setting lclist attribute to non-lclist value" );
 1194: 	l->attrs[0].u.ptr = v1.val.ad;
 1195: 	break;
 1196:       case EAF_TYPE_UNDEF:
 1197: 	if (v1.type != T_VOID)
 1198: 	  runtime( "Setting void attribute to non-void value" );
 1199: 	l->attrs[0].u.data = 0;
 1200: 	break;
 1201:       default: bug("Unknown type in e,S");
 1202:       }
 1203: 
 1204:       if (!(what->aux & EAF_TEMP) && (!(f_flags & FF_FORCE_TMPATTR))) {
 1205: 	f_rta_cow();
 1206: 	l->next = (*f_rte)->attrs->eattrs;
 1207: 	(*f_rte)->attrs->eattrs = l;
 1208:       } else {
 1209: 	l->next = (*f_tmp_attrs);
 1210: 	(*f_tmp_attrs) = l;
 1211:       }
 1212:     }
 1213:     break;
 1214:   case FI_PREF_GET:
 1215:     ACCESS_RTE;
 1216:     res.type = T_INT;
 1217:     res.val.i = (*f_rte)->pref;
 1218:     break;
 1219:   case FI_PREF_SET:
 1220:     ACCESS_RTE;
 1221:     ONEARG;
 1222:     if (v1.type != T_INT)
 1223:       runtime( "Can't set preference to non-integer" );
 1224:     if (v1.val.i > 0xFFFF)
 1225:       runtime( "Setting preference value out of bounds" );
 1226:     f_rte_cow();
 1227:     (*f_rte)->pref = v1.val.i;
 1228:     break;
 1229:   case FI_LENGTH:	/* Get length of */
 1230:     ONEARG;
 1231:     res.type = T_INT;
 1232:     switch(v1.type) {
 1233:     case T_PREFIX: res.val.i = v1.val.px.len; break;
 1234:     case T_PATH:   res.val.i = as_path_getlen(v1.val.ad); break;
 1235:     case T_CLIST:  res.val.i = int_set_get_size(v1.val.ad); break;
 1236:     case T_ECLIST: res.val.i = ec_set_get_size(v1.val.ad); break;
 1237:     case T_LCLIST: res.val.i = lc_set_get_size(v1.val.ad); break;
 1238:     default: runtime( "Prefix, path, clist or eclist expected" );
 1239:     }
 1240:     break;
 1241:   case FI_IP:	/* Convert prefix to ... */
 1242:     ONEARG;
 1243:     if (v1.type != T_PREFIX)
 1244:       runtime( "Prefix expected" );
 1245:     res.type = what->aux;
 1246:     switch(res.type) {
 1247:       /*    case T_INT:	res.val.i = v1.val.px.len; break; Not needed any more */
 1248:     case T_IP: res.val.px.ip = v1.val.px.ip; break;
 1249:     default: bug( "Unknown prefix to conversion" );
 1250:     }
 1251:     break;
 1252:   case FI_AS_PATH_FIRST:	/* Get first ASN from AS PATH */
 1253:     ONEARG;
 1254:     if (v1.type != T_PATH)
 1255:       runtime( "AS path expected" );
 1256: 
 1257:     as = 0;
 1258:     as_path_get_first(v1.val.ad, &as);
 1259:     res.type = T_INT;
 1260:     res.val.i = as;
 1261:     break;
 1262:   case FI_AS_PATH_LAST:	/* Get last ASN from AS PATH */
 1263:     ONEARG;
 1264:     if (v1.type != T_PATH)
 1265:       runtime( "AS path expected" );
 1266: 
 1267:     as = 0;
 1268:     as_path_get_last(v1.val.ad, &as);
 1269:     res.type = T_INT;
 1270:     res.val.i = as;
 1271:     break;
 1272:   case FI_AS_PATH_LAST_NAG:	/* Get last ASN from non-aggregated part of AS PATH */
 1273:     ONEARG;
 1274:     if (v1.type != T_PATH)
 1275:       runtime( "AS path expected" );
 1276: 
 1277:     res.type = T_INT;
 1278:     res.val.i = as_path_get_last_nonaggregated(v1.val.ad);
 1279:     break;
 1280:   case FI_RETURN:
 1281:     ONEARG;
 1282:     res = v1;
 1283:     res.type |= T_RETURN;
 1284:     return res;
 1285:   case FI_CALL: /* CALL: this is special: if T_RETURN and returning some value, mask it out  */
 1286:     ONEARG;
 1287:     res = interpret(what->a2.p);
 1288:     if (res.type == T_RETURN)
 1289:       return res;
 1290:     res.type &= ~T_RETURN;
 1291:     break;
 1292:   case FI_CLEAR_LOCAL_VARS:	/* Clear local variables */
 1293:     for (sym = what->a1.p; sym != NULL; sym = sym->aux2)
 1294:       ((struct f_val *) sym->def)->type = T_VOID;
 1295:     break;
 1296:   case FI_SWITCH:
 1297:     ONEARG;
 1298:     {
 1299:       struct f_tree *t = find_tree(what->a2.p, v1);
 1300:       if (!t) {
 1301: 	v1.type = T_VOID;
 1302: 	t = find_tree(what->a2.p, v1);
 1303: 	if (!t) {
 1304: 	  debug( "No else statement?\n");
 1305: 	  break;
 1306: 	}
 1307:       }
 1308:       /* It is actually possible to have t->data NULL */
 1309: 
 1310:       res = interpret(t->data);
 1311:       if (res.type & T_RETURN)
 1312: 	return res;
 1313:     }
 1314:     break;
 1315:   case FI_IP_MASK: /* IP.MASK(val) */
 1316:     TWOARGS;
 1317:     if (v2.type != T_INT)
 1318:       runtime( "Integer expected");
 1319:     if (v1.type != T_IP)
 1320:       runtime( "You can mask only IP addresses" );
 1321:     {
 1322:       ip_addr mask = ipa_mkmask(v2.val.i);
 1323:       res.type = T_IP;
 1324:       res.val.px.ip = ipa_and(mask, v1.val.px.ip);
 1325:     }
 1326:     break;
 1327: 
 1328:   case FI_EMPTY:	/* Create empty attribute */
 1329:     res.type = what->aux;
 1330:     res.val.ad = adata_empty(f_pool, 0);
 1331:     break;
 1332:   case FI_PATH_PREPEND:	/* Path prepend */
 1333:     TWOARGS;
 1334:     if (v1.type != T_PATH)
 1335:       runtime("Can't prepend to non-path");
 1336:     if (v2.type != T_INT)
 1337:       runtime("Can't prepend non-integer");
 1338: 
 1339:     res.type = T_PATH;
 1340:     res.val.ad = as_path_prepend(f_pool, v1.val.ad, v2.val.i);
 1341:     break;
 1342: 
 1343:   case FI_CLIST_ADD_DEL:	/* (Extended) Community list add or delete */
 1344:     TWOARGS;
 1345:     if (v1.type == T_PATH)
 1346:     {
 1347:       struct f_tree *set = NULL;
 1348:       u32 key = 0;
 1349:       int pos;
 1350: 
 1351:       if (v2.type == T_INT)
 1352: 	key = v2.val.i;
 1353:       else if ((v2.type == T_SET) && (v2.val.t->from.type == T_INT))
 1354: 	set = v2.val.t;
 1355:       else
 1356: 	runtime("Can't delete non-integer (set)");
 1357: 
 1358:       switch (what->aux)
 1359:       {
 1360:       case 'a':	runtime("Can't add to path");
 1361:       case 'd':	pos = 0; break;
 1362:       case 'f':	pos = 1; break;
 1363:       default:	bug("unknown Ca operation");
 1364:       }
 1365: 
 1366:       if (pos && !set)
 1367: 	runtime("Can't filter integer");
 1368: 
 1369:       res.type = T_PATH;
 1370:       res.val.ad = as_path_filter(f_pool, v1.val.ad, set, key, pos);
 1371:     }
 1372:     else if (v1.type == T_CLIST)
 1373:     {
 1374:       /* Community (or cluster) list */
 1375:       struct f_val dummy;
 1376:       int arg_set = 0;
 1377:       uint n = 0;
 1378: 
 1379:       if ((v2.type == T_PAIR) || (v2.type == T_QUAD))
 1380: 	n = v2.val.i;
 1381: #ifndef IPV6
 1382:       /* IP->Quad implicit conversion */
 1383:       else if (v2.type == T_IP)
 1384: 	n = ipa_to_u32(v2.val.px.ip);
 1385: #endif
 1386:       else if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy))
 1387: 	arg_set = 1;
 1388:       else if (v2.type == T_CLIST)
 1389: 	arg_set = 2;
 1390:       else
 1391: 	runtime("Can't add/delete non-pair");
 1392: 
 1393:       res.type = T_CLIST;
 1394:       switch (what->aux)
 1395:       {
 1396:       case 'a':
 1397: 	if (arg_set == 1)
 1398: 	  runtime("Can't add set");
 1399: 	else if (!arg_set)
 1400: 	  res.val.ad = int_set_add(f_pool, v1.val.ad, n);
 1401: 	else
 1402: 	  res.val.ad = int_set_union(f_pool, v1.val.ad, v2.val.ad);
 1403: 	break;
 1404: 
 1405:       case 'd':
 1406: 	if (!arg_set)
 1407: 	  res.val.ad = int_set_del(f_pool, v1.val.ad, n);
 1408: 	else
 1409: 	  res.val.ad = clist_filter(f_pool, v1.val.ad, v2, 0);
 1410: 	break;
 1411: 
 1412:       case 'f':
 1413: 	if (!arg_set)
 1414: 	  runtime("Can't filter pair");
 1415: 	res.val.ad = clist_filter(f_pool, v1.val.ad, v2, 1);
 1416: 	break;
 1417: 
 1418:       default:
 1419: 	bug("unknown Ca operation");
 1420:       }
 1421:     }
 1422:     else if (v1.type == T_ECLIST)
 1423:     {
 1424:       /* Extended community list */
 1425:       int arg_set = 0;
 1426: 
 1427:       /* v2.val is either EC or EC-set */
 1428:       if ((v2.type == T_SET) && eclist_set_type(v2.val.t))
 1429: 	arg_set = 1;
 1430:       else if (v2.type == T_ECLIST)
 1431: 	arg_set = 2;
 1432:       else if (v2.type != T_EC)
 1433: 	runtime("Can't add/delete non-ec");
 1434: 
 1435:       res.type = T_ECLIST;
 1436:       switch (what->aux)
 1437:       {
 1438:       case 'a':
 1439: 	if (arg_set == 1)
 1440: 	  runtime("Can't add set");
 1441: 	else if (!arg_set)
 1442: 	  res.val.ad = ec_set_add(f_pool, v1.val.ad, v2.val.ec);
 1443: 	else
 1444: 	  res.val.ad = ec_set_union(f_pool, v1.val.ad, v2.val.ad);
 1445: 	break;
 1446: 
 1447:       case 'd':
 1448: 	if (!arg_set)
 1449: 	  res.val.ad = ec_set_del(f_pool, v1.val.ad, v2.val.ec);
 1450: 	else
 1451: 	  res.val.ad = eclist_filter(f_pool, v1.val.ad, v2, 0);
 1452: 	break;
 1453: 
 1454:       case 'f':
 1455: 	if (!arg_set)
 1456: 	  runtime("Can't filter ec");
 1457: 	res.val.ad = eclist_filter(f_pool, v1.val.ad, v2, 1);
 1458: 	break;
 1459: 
 1460:       default:
 1461: 	bug("unknown Ca operation");
 1462:       }
 1463:     }
 1464:     else if (v1.type == T_LCLIST)
 1465:     {
 1466:       /* Large community list */
 1467:       int arg_set = 0;
 1468: 
 1469:       /* v2.val is either LC or LC-set */
 1470:       if ((v2.type == T_SET) && lclist_set_type(v2.val.t))
 1471: 	arg_set = 1;
 1472:       else if (v2.type == T_LCLIST)
 1473: 	arg_set = 2;
 1474:       else if (v2.type != T_LC)
 1475: 	runtime("Can't add/delete non-lc");
 1476: 
 1477:       res.type = T_LCLIST;
 1478:       switch (what->aux)
 1479:       {
 1480:       case 'a':
 1481: 	if (arg_set == 1)
 1482: 	  runtime("Can't add set");
 1483: 	else if (!arg_set)
 1484: 	  res.val.ad = lc_set_add(f_pool, v1.val.ad, v2.val.lc);
 1485: 	else
 1486: 	  res.val.ad = lc_set_union(f_pool, v1.val.ad, v2.val.ad);
 1487: 	break;
 1488: 
 1489:       case 'd':
 1490: 	if (!arg_set)
 1491: 	  res.val.ad = lc_set_del(f_pool, v1.val.ad, v2.val.lc);
 1492: 	else
 1493: 	  res.val.ad = lclist_filter(f_pool, v1.val.ad, v2, 0);
 1494: 	break;
 1495: 
 1496:       case 'f':
 1497: 	if (!arg_set)
 1498: 	  runtime("Can't filter lc");
 1499: 	res.val.ad = lclist_filter(f_pool, v1.val.ad, v2, 1);
 1500: 	break;
 1501: 
 1502:       default:
 1503: 	bug("unknown Ca operation");
 1504:       }
 1505:     }
 1506:     else
 1507:       runtime("Can't add/delete to non-[e|l]clist");
 1508: 
 1509:     break;
 1510: 
 1511:   case FI_ROA_CHECK:	/* ROA Check */
 1512:     if (what->arg1)
 1513:     {
 1514:       TWOARGS;
 1515:       if ((v1.type != T_PREFIX) || (v2.type != T_INT))
 1516: 	runtime("Invalid argument to roa_check()");
 1517: 
 1518:       as = v2.val.i;
 1519:     }
 1520:     else
 1521:     {
 1522:       ACCESS_RTE;
 1523:       v1.val.px.ip = (*f_rte)->net->n.prefix;
 1524:       v1.val.px.len = (*f_rte)->net->n.pxlen;
 1525: 
 1526:       /* We ignore temporary attributes, probably not a problem here */
 1527:       /* 0x02 is a value of BA_AS_PATH, we don't want to include BGP headers */
 1528:       eattr *e = ea_find((*f_rte)->attrs->eattrs, EA_CODE(EAP_BGP, 0x02));
 1529: 
 1530:       if (!e || ((e->type & EAF_TYPE_MASK) != EAF_TYPE_AS_PATH))
 1531: 	runtime("Missing AS_PATH attribute");
 1532: 
 1533:       as_path_get_last(e->u.ptr, &as);
 1534:     }
 1535: 
 1536:     struct roa_table_config *rtc = ((struct f_inst_roa_check *) what)->rtc;
 1537:     if (!rtc->table)
 1538:       runtime("Missing ROA table");
 1539: 
 1540:     res.type = T_ENUM_ROA;
 1541:     res.val.i = roa_check(rtc->table, v1.val.px.ip, v1.val.px.len, as);
 1542:     break;
 1543: 
 1544:   default:
 1545:     bug( "Unknown instruction %d (%c)", what->fi_code, what->fi_code & 0xff);
 1546:   }}
 1547:   return res;
 1548: }
 1549: 
 1550: #undef ARG
 1551: #define ARG(x,y) \
 1552: 	if (!i_same(f1->y, f2->y)) \
 1553: 		return 0;
 1554: 
 1555: #define ONEARG ARG(v1, a1.p)
 1556: #define TWOARGS ARG(v1, a1.p) \
 1557: 		ARG(v2, a2.p)
 1558: 
 1559: #define A2_SAME if (f1->a2.i != f2->a2.i) return 0;
 1560: 
 1561: /*
 1562:  * i_same - function that does real comparing of instruction trees, you should call filter_same from outside
 1563:  */
 1564: int
 1565: i_same(struct f_inst *f1, struct f_inst *f2)
 1566: {
 1567:   if ((!!f1) != (!!f2))
 1568:     return 0;
 1569:   if (!f1)
 1570:     return 1;
 1571:   if (f1->aux != f2->aux)
 1572:     return 0;
 1573:   if (f1->fi_code != f2->fi_code)
 1574:     return 0;
 1575:   if (f1 == f2)		/* It looks strange, but it is possible with call rewriting trickery */
 1576:     return 1;
 1577: 
 1578:   switch(f1->fi_code) {
 1579:   case FI_ADD: /* fall through */
 1580:   case FI_SUBTRACT:
 1581:   case FI_MULTIPLY:
 1582:   case FI_DIVIDE:
 1583:   case FI_OR:
 1584:   case FI_AND:
 1585:   case FI_PAIR_CONSTRUCT:
 1586:   case FI_EC_CONSTRUCT:
 1587:   case FI_NEQ:
 1588:   case FI_EQ:
 1589:   case FI_LT:
 1590:   case FI_LTE: TWOARGS; break;
 1591: 
 1592:   case FI_PATHMASK_CONSTRUCT: if (!pm_same(f1->a1.p, f2->a1.p)) return 0; break;
 1593: 
 1594:   case FI_NOT: ONEARG; break;
 1595:   case FI_NOT_MATCH:
 1596:   case FI_MATCH: TWOARGS; break;
 1597:   case FI_DEFINED: ONEARG; break;
 1598: 
 1599:   case FI_LC_CONSTRUCT:
 1600:     TWOARGS;
 1601:     if (!i_same(INST3(f1).p, INST3(f2).p))
 1602:       return 0;
 1603:     break;
 1604: 
 1605:   case FI_SET:
 1606:     ARG(v2, a2.p);
 1607:     {
 1608:       struct symbol *s1, *s2;
 1609:       s1 = f1->a1.p;
 1610:       s2 = f2->a1.p;
 1611:       if (strcmp(s1->name, s2->name))
 1612: 	return 0;
 1613:       if (s1->class != s2->class)
 1614: 	return 0;
 1615:     }
 1616:     break;
 1617: 
 1618:   case FI_CONSTANT:
 1619:     switch (f1->aux) {
 1620: 
 1621:     case T_PREFIX_SET:
 1622:       if (!trie_same(f1->a2.p, f2->a2.p))
 1623: 	return 0;
 1624:       break;
 1625: 
 1626:     case T_SET:
 1627:       if (!same_tree(f1->a2.p, f2->a2.p))
 1628: 	return 0;
 1629:       break;
 1630: 
 1631:     case T_STRING:
 1632:       if (strcmp(f1->a2.p, f2->a2.p))
 1633: 	return 0;
 1634:       break;
 1635: 
 1636:     default:
 1637:       A2_SAME;
 1638:     }
 1639:     break;
 1640: 
 1641:   case FI_CONSTANT_INDIRECT:
 1642:     if (!val_same(* (struct f_val *) f1->a1.p, * (struct f_val *) f2->a1.p))
 1643:       return 0;
 1644:     break;
 1645: 
 1646:   case FI_VARIABLE:
 1647:     if (strcmp((char *) f1->a2.p, (char *) f2->a2.p))
 1648:       return 0;
 1649:     break;
 1650:   case FI_PRINT: case FI_LENGTH: ONEARG; break;
 1651:   case FI_CONDITION: TWOARGS; break;
 1652:   case FI_NOP: case FI_EMPTY: break;
 1653:   case FI_PRINT_AND_DIE: ONEARG; A2_SAME; break;
 1654:   case FI_PREF_GET:
 1655:   case FI_RTA_GET: A2_SAME; break;
 1656:   case FI_EA_GET: A2_SAME; break;
 1657:   case FI_PREF_SET:
 1658:   case FI_RTA_SET:
 1659:   case FI_EA_SET: ONEARG; A2_SAME; break;
 1660: 
 1661:   case FI_RETURN: ONEARG; break;
 1662:   case FI_IP: ONEARG; break;
 1663:   case FI_CALL: /* Call rewriting trickery to avoid exponential behaviour */
 1664:              ONEARG;
 1665: 	     if (!i_same(f1->a2.p, f2->a2.p))
 1666: 	       return 0;
 1667: 	     f2->a2.p = f1->a2.p;
 1668: 	     break;
 1669:   case FI_CLEAR_LOCAL_VARS: break; /* internal instruction */
 1670:   case FI_SWITCH: ONEARG; if (!same_tree(f1->a2.p, f2->a2.p)) return 0; break;
 1671:   case FI_IP_MASK: TWOARGS; break;
 1672:   case FI_PATH_PREPEND: TWOARGS; break;
 1673:   case FI_CLIST_ADD_DEL: TWOARGS; break;
 1674:   case FI_AS_PATH_FIRST:
 1675:   case FI_AS_PATH_LAST:
 1676:   case FI_AS_PATH_LAST_NAG: ONEARG; break;
 1677:   case FI_ROA_CHECK:
 1678:     TWOARGS;
 1679:     /* Does not really make sense - ROA check resuls may change anyway */
 1680:     if (strcmp(((struct f_inst_roa_check *) f1)->rtc->name,
 1681: 	       ((struct f_inst_roa_check *) f2)->rtc->name))
 1682:       return 0;
 1683:     break;
 1684:   default:
 1685:     bug( "Unknown instruction %d in same (%c)", f1->fi_code, f1->fi_code & 0xff);
 1686:   }
 1687:   return i_same(f1->next, f2->next);
 1688: }
 1689: 
 1690: /**
 1691:  * f_run - run a filter for a route
 1692:  * @filter: filter to run
 1693:  * @rte: route being filtered, may be modified
 1694:  * @tmp_attrs: temporary attributes, prepared by caller or generated by f_run()
 1695:  * @tmp_pool: all filter allocations go from this pool
 1696:  * @flags: flags
 1697:  *
 1698:  * If filter needs to modify the route, there are several
 1699:  * posibilities. @rte might be read-only (with REF_COW flag), in that
 1700:  * case rw copy is obtained by rte_cow() and @rte is replaced. If
 1701:  * @rte is originally rw, it may be directly modified (and it is never
 1702:  * copied).
 1703:  *
 1704:  * The returned rte may reuse the (possibly cached, cloned) rta, or
 1705:  * (if rta was modificied) contains a modified uncached rta, which
 1706:  * uses parts allocated from @tmp_pool and parts shared from original
 1707:  * rta. There is one exception - if @rte is rw but contains a cached
 1708:  * rta and that is modified, rta in returned rte is also cached.
 1709:  *
 1710:  * Ownership of cached rtas is consistent with rte, i.e.
 1711:  * if a new rte is returned, it has its own clone of cached rta
 1712:  * (and cached rta of read-only source rte is intact), if rte is
 1713:  * modified in place, old cached rta is possibly freed.
 1714:  */
 1715: int
 1716: f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool, int flags)
 1717: {
 1718:   if (filter == FILTER_ACCEPT)
 1719:     return F_ACCEPT;
 1720: 
 1721:   if (filter == FILTER_REJECT)
 1722:     return F_REJECT;
 1723: 
 1724:   int rte_cow = ((*rte)->flags & REF_COW);
 1725:   DBG( "Running filter `%s'...", filter->name );
 1726: 
 1727:   f_rte = rte;
 1728:   f_old_rta = NULL;
 1729:   f_tmp_attrs = tmp_attrs;
 1730:   f_pool = tmp_pool;
 1731:   f_flags = flags;
 1732: 
 1733:   LOG_BUFFER_INIT(f_buf);
 1734: 
 1735:   struct f_val res = interpret(filter->root);
 1736: 
 1737:   if (f_old_rta) {
 1738:     /*
 1739:      * Cached rta was modified and f_rte contains now an uncached one,
 1740:      * sharing some part with the cached one. The cached rta should
 1741:      * be freed (if rte was originally COW, f_old_rta is a clone
 1742:      * obtained during rte_cow()).
 1743:      *
 1744:      * This also implements the exception mentioned in f_run()
 1745:      * description. The reason for this is that rta reuses parts of
 1746:      * f_old_rta, and these may be freed during rta_free(f_old_rta).
 1747:      * This is not the problem if rte was COW, because original rte
 1748:      * also holds the same rta.
 1749:      */
 1750:     if (!rte_cow)
 1751:       (*f_rte)->attrs = rta_lookup((*f_rte)->attrs);
 1752: 
 1753:     rta_free(f_old_rta);
 1754:   }
 1755: 
 1756: 
 1757:   if (res.type != T_RETURN) {
 1758:     if (!(f_flags & FF_SILENT))
 1759:       log_rl(&rl_runtime_err, L_ERR "Filter %s did not return accept nor reject. Make up your mind", filter->name);
 1760:     return F_ERROR;
 1761:   }
 1762:   DBG( "done (%u)\n", res.val.i );
 1763:   return res.val.i;
 1764: }
 1765: 
 1766: /* TODO: perhaps we could integrate f_eval(), f_eval_rte() and f_run() */
 1767: 
 1768: struct f_val
 1769: f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool)
 1770: {
 1771:   struct ea_list *tmp_attrs = NULL;
 1772: 
 1773:   f_rte = rte;
 1774:   f_old_rta = NULL;
 1775:   f_tmp_attrs = &tmp_attrs;
 1776:   f_pool = tmp_pool;
 1777:   f_flags = 0;
 1778: 
 1779:   LOG_BUFFER_INIT(f_buf);
 1780: 
 1781:   /* Note that in this function we assume that rte->attrs is private / uncached */
 1782:   struct f_val res = interpret(expr);
 1783: 
 1784:   /* Hack to include EAF_TEMP attributes to the main list */
 1785:   (*rte)->attrs->eattrs = ea_append(tmp_attrs, (*rte)->attrs->eattrs);
 1786: 
 1787:   return res;
 1788: }
 1789: 
 1790: struct f_val
 1791: f_eval(struct f_inst *expr, struct linpool *tmp_pool)
 1792: {
 1793:   f_flags = 0;
 1794:   f_tmp_attrs = NULL;
 1795:   f_rte = NULL;
 1796:   f_pool = tmp_pool;
 1797: 
 1798:   LOG_BUFFER_INIT(f_buf);
 1799: 
 1800:   return interpret(expr);
 1801: }
 1802: 
 1803: uint
 1804: f_eval_int(struct f_inst *expr)
 1805: {
 1806:   /* Called independently in parse-time to eval expressions */
 1807:   struct f_val res = f_eval(expr, cfg_mem);
 1808: 
 1809:   if (res.type != T_INT)
 1810:     cf_error("Integer expression expected");
 1811: 
 1812:   return res.val.i;
 1813: }
 1814: 
 1815: /**
 1816:  * filter_same - compare two filters
 1817:  * @new: first filter to be compared
 1818:  * @old: second filter to be compared, notice that this filter is
 1819:  * damaged while comparing.
 1820:  *
 1821:  * Returns 1 in case filters are same, otherwise 0. If there are
 1822:  * underlying bugs, it will rather say 0 on same filters than say
 1823:  * 1 on different.
 1824:  */
 1825: int
 1826: filter_same(struct filter *new, struct filter *old)
 1827: {
 1828:   if (old == new)	/* Handle FILTER_ACCEPT and FILTER_REJECT */
 1829:     return 1;
 1830:   if (old == FILTER_ACCEPT || old == FILTER_REJECT ||
 1831:       new == FILTER_ACCEPT || new == FILTER_REJECT)
 1832:     return 0;
 1833:   return i_same(new->root, old->root);
 1834: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>