]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Add bitfield route attribute type
authorOndrej Zajicek <santiago@crfreenet.org>
Sat, 9 May 2015 16:50:15 +0000 (18:50 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Sun, 10 May 2015 17:44:10 +0000 (19:44 +0200)
filter/filter.c
nest/route.h
nest/rt-attr.c

index a4f123300a18c77f7304ac30f475d6f3bd82fd5a..3b14fc0cf03ff73f0bd9d3a59ef6457bcc95fc05 100644 (file)
@@ -462,7 +462,7 @@ static int f_flags;
 
 static inline void f_rte_cow(void)
 {
-  *f_rte = rte_cow(*f_rte); 
+  *f_rte = rte_cow(*f_rte);
 }
 
 /*
@@ -479,7 +479,7 @@ f_rta_cow(void)
     /* Store old rta to free it later */
     f_old_rta = (*f_rte)->attrs;
 
-    /* 
+    /*
      * Alloc new rta, do shallow copy and update rte. Fields eattrs
      * and nexthops of rta are shared with f_old_rta (they will be
      * copied when the cached rta will be obtained at the end of
@@ -516,6 +516,9 @@ static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
 #define ACCESS_RTE \
   do { if (!f_rte) runtime("No route to access"); } while (0)
 
+#define BITFIELD_MASK(what) \
+  (1u << (what->a2.i >> 24))
+
 /**
  * interpret
  * @what: filter to interpret
@@ -526,7 +529,7 @@ static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
  * Each instruction has 4 fields: code (which is instruction code),
  * aux (which is extension to instruction code, typically type),
  * arg1 and arg2 - arguments. Depending on instruction, arguments
- * are either integers, or pointers to instruction trees. Common 
+ * are either integers, or pointers to instruction trees. Common
  * instructions like +, that have two expressions as arguments use
  * TWOARGS macro to get both of them evaluated.
  *
@@ -585,7 +588,7 @@ interpret(struct f_inst *what)
     default: runtime( "Usage of unknown type" );
     }
     break;
-    
+
   case '&':
   case '|':
     ARG(v1, a1.p);
@@ -625,7 +628,7 @@ interpret(struct f_inst *what)
 
       if (v1.type == T_INT) {
        ipv4_used = 0; key = v1.val.i;
-      } 
+      }
       else if (v1.type == T_QUAD) {
        ipv4_used = 1; key = v1.val.i;
       }
@@ -724,7 +727,7 @@ interpret(struct f_inst *what)
 #endif
       runtime( "Assigning to variable of incompatible type" );
     }
-    *vp = v2; 
+    *vp = v2;
     break;
 
     /* some constants have value in a2, some in *a1.p, strange. */
@@ -864,12 +867,14 @@ interpret(struct f_inst *what)
     ACCESS_RTE;
     {
       eattr *e = NULL;
+      u16 code = what->a2.i;
+
       if (!(f_flags & FF_FORCE_TMPATTR))
-       e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i );
-      if (!e) 
-       e = ea_find( (*f_tmp_attrs), what->a2.i );
+       e = ea_find((*f_rte)->attrs->eattrs, code);
+      if (!e)
+       e = ea_find((*f_tmp_attrs), code);
       if ((!e) && (f_flags & FF_FORCE_TMPATTR))
-       e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i );
+       e = ea_find((*f_rte)->attrs->eattrs, code);
 
       if (!e) {
        /* A special case: undefined int_set looks like empty int_set */
@@ -878,8 +883,9 @@ interpret(struct f_inst *what)
          res.val.ad = adata_empty(f_pool, 0);
          break;
        }
+
        /* The same special case for ec_set */
-       else if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_EC_SET) {
+       if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_EC_SET) {
          res.type = T_ECLIST;
          res.val.ad = adata_empty(f_pool, 0);
          break;
@@ -912,6 +918,10 @@ interpret(struct f_inst *what)
         res.type = T_PATH;
        res.val.ad = e->u.ptr;
        break;
+      case EAF_TYPE_BITFIELD:
+       res.type = T_BOOL;
+       res.val.i = !!(e->u.data & BITFIELD_MASK(what));
+       break;
       case EAF_TYPE_INT_SET:
        res.type = T_CLIST;
        res.val.ad = e->u.ptr;
@@ -933,13 +943,15 @@ interpret(struct f_inst *what)
     ONEARG;
     {
       struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr));
+      u16 code = what->a2.i;
 
       l->next = NULL;
       l->flags = EALF_SORTED;
       l->count = 1;
-      l->attrs[0].id = what->a2.i;
+      l->attrs[0].id = code;
       l->attrs[0].flags = 0;
       l->attrs[0].type = what->aux | EAF_ORIGINATED;
+
       switch (what->aux & EAF_TYPE_MASK) {
       case EAF_TYPE_INT:
        if (v1.type != T_INT)
@@ -978,6 +990,26 @@ interpret(struct f_inst *what)
          runtime( "Setting path attribute to non-path value" );
        l->attrs[0].u.ptr = v1.val.ad;
        break;
+      case EAF_TYPE_BITFIELD:
+       if (v1.type != T_BOOL)
+         runtime( "Setting bit in bitfield attribute to non-bool value" );
+       {
+         /* First, we have to find the old value */
+         eattr *e = NULL;
+         if (!(f_flags & FF_FORCE_TMPATTR))
+           e = ea_find((*f_rte)->attrs->eattrs, code);
+         if (!e)
+           e = ea_find((*f_tmp_attrs), code);
+         if ((!e) && (f_flags & FF_FORCE_TMPATTR))
+           e = ea_find((*f_rte)->attrs->eattrs, code);
+         u32 data = e ? e->u.data : 0;
+
+         if (v1.val.i)
+           l->attrs[0].u.data = data | BITFIELD_MASK(what);
+         else
+           l->attrs[0].u.data = data & ~BITFIELD_MASK(what);;
+       }
+       break;
       case EAF_TYPE_INT_SET:
        if (v1.type != T_CLIST)
          runtime( "Setting clist attribute to non-clist value" );
@@ -1073,7 +1105,7 @@ interpret(struct f_inst *what)
     res = interpret(what->a2.p);
     if (res.type == T_RETURN)
       return res;
-    res.type &= ~T_RETURN;    
+    res.type &= ~T_RETURN;
     break;
   case P('c','v'):     /* Clear local variables */
     for (sym = what->a1.p; sym != NULL; sym = sym->aux2)
@@ -1090,7 +1122,7 @@ interpret(struct f_inst *what)
          debug( "No else statement?\n");
          break;
        }
-      }        
+      }
       /* It is actually possible to have t->data NULL */
 
       res = interpret(t->data);
@@ -1184,10 +1216,10 @@ interpret(struct f_inst *what)
          runtime("Can't add set");
        else if (!arg_set)
          res.val.ad = int_set_add(f_pool, v1.val.ad, n);
-       else 
+       else
          res.val.ad = int_set_union(f_pool, v1.val.ad, v2.val.ad);
        break;
-      
+
       case 'd':
        if (!arg_set)
          res.val.ad = int_set_del(f_pool, v1.val.ad, n);
@@ -1209,7 +1241,7 @@ interpret(struct f_inst *what)
     {
       /* Extended community list */
       int arg_set = 0;
-      
+
       /* v2.val is either EC or EC-set */
       if ((v2.type == T_SET) && eclist_set_type(v2.val.t))
        arg_set = 1;
@@ -1226,10 +1258,10 @@ interpret(struct f_inst *what)
          runtime("Can't add set");
        else if (!arg_set)
          res.val.ad = ec_set_add(f_pool, v1.val.ad, v2.val.ec);
-       else 
+       else
          res.val.ad = ec_set_union(f_pool, v1.val.ad, v2.val.ad);
        break;
-      
+
       case 'd':
        if (!arg_set)
          res.val.ad = ec_set_del(f_pool, v1.val.ad, v2.val.ec);
@@ -1353,7 +1385,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
     }
     break;
 
-  case 'c': 
+  case 'c':
     switch (f1->aux) {
 
     case T_PREFIX_SET:
@@ -1381,7 +1413,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
       return 0;
     break;
 
-  case 'V': 
+  case 'V':
     if (strcmp((char *) f1->a2.p, (char *) f2->a2.p))
       return 0;
     break;
@@ -1399,12 +1431,12 @@ i_same(struct f_inst *f1, struct f_inst *f2)
   case 'r': ONEARG; break;
   case P('c','p'): ONEARG; break;
   case P('c','a'): /* Call rewriting trickery to avoid exponential behaviour */
-             ONEARG; 
+             ONEARG;
             if (!i_same(f1->a2.p, f2->a2.p))
-              return 0; 
+              return 0;
             f2->a2.p = f1->a2.p;
             break;
-  case P('c','v'): break; /* internal instruction */ 
+  case P('c','v'): break; /* internal instruction */
   case P('S','W'): ONEARG; if (!same_tree(f1->a2.p, f2->a2.p)) return 0; break;
   case P('i','M'): TWOARGS; break;
   case P('A','p'): TWOARGS; break;
@@ -1414,7 +1446,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
   case P('R','C'):
     TWOARGS;
     /* Does not really make sense - ROA check resuls may change anyway */
-    if (strcmp(((struct f_inst_roa_check *) f1)->rtc->name, 
+    if (strcmp(((struct f_inst_roa_check *) f1)->rtc->name,
               ((struct f_inst_roa_check *) f2)->rtc->name))
       return 0;
     break;
index 5ee04a3082ee50ae121890cfbba7508e8cc77a86..fccc571b6d463f7d23e8220af454bac4a79d1fcd 100644 (file)
@@ -417,13 +417,15 @@ typedef struct eattr {
 
 #define EA_CODE_MASK 0xffff
 #define EA_ALLOW_UNDEF 0x10000         /* ea_find: allow EAF_TYPE_UNDEF */
+#define EA_BIT(n) ((n) << 24)          /* Used in bitfield accessors */
 
 #define EAF_TYPE_MASK 0x0f             /* Mask with this to get type */
-#define EAF_TYPE_INT 0x01              /* 32-bit signed integer number */
+#define EAF_TYPE_INT 0x01              /* 32-bit unsigned integer number */
 #define EAF_TYPE_OPAQUE 0x02           /* Opaque byte string (not filterable) */
 #define EAF_TYPE_IP_ADDRESS 0x04       /* IP address */
 #define EAF_TYPE_ROUTER_ID 0x05                /* Router ID (IPv4 address) */
 #define EAF_TYPE_AS_PATH 0x06          /* BGP AS path (encoding per RFC 1771:4.3) */
+#define EAF_TYPE_BITFIELD 0x09         /* 32-bit embedded bitfield */
 #define EAF_TYPE_INT_SET 0x0a          /* Set of u32's (e.g., a community list) */
 #define EAF_TYPE_EC_SET 0x0e           /* Set of pairs of u32's - ext. community list */
 #define EAF_TYPE_UNDEF 0x0f            /* `force undefined' entry */
@@ -469,6 +471,7 @@ void ea_merge(ea_list *from, ea_list *to); /* Merge sub-lists to allocated buffe
 int ea_same(ea_list *x, ea_list *y);   /* Test whether two ea_lists are identical */
 unsigned int ea_hash(ea_list *e);      /* Calculate 16-bit hash value */
 ea_list *ea_append(ea_list *to, ea_list *what);
+void ea_format_bitfield(struct eattr *a, byte *buf, int bufsize, const char **names, int min, int max);
 
 int mpnh__same(struct mpnh *x, struct mpnh *y); /* Compare multipath nexthops */
 static inline int mpnh_same(struct mpnh *x, struct mpnh *y)
index 09691bf1498c0bb67be7ed5a5248862aff025b61..938b2b44623d03b6e4c6f9f8df96f0eb3046da5a 100644 (file)
@@ -563,6 +563,32 @@ get_generic_attr(eattr *a, byte **buf, int buflen UNUSED)
   return GA_UNKNOWN;
 }
 
+void
+ea_format_bitfield(struct eattr *a, byte *buf, int bufsize, const char **names, int min, int max)
+{
+  byte *bound = buf + bufsize - 32;
+  u32 data = a->u.data;
+  int i;
+
+  for (i = min; i < max; i++)
+    if ((data & (1u << i)) && names[i])
+    {
+      if (buf > bound)
+      {
+       strcpy(buf, " ...");
+       return;
+      }
+
+      buf += bsprintf(buf, " %s", names[i]);
+      data &= ~(1u << i);
+    }
+
+  if (data)
+    bsprintf(buf, " %08x", data);
+
+  return;
+}
+
 static inline void
 opaque_format(struct adata *ad, byte *buf, unsigned int size)
 {
@@ -665,6 +691,9 @@ ea_show(struct cli *c, eattr *e)
        case EAF_TYPE_AS_PATH:
          as_path_format(ad, pos, end - pos);
          break;
+       case EAF_TYPE_BITFIELD:
+         bsprintf(pos, "%08x", e->u.data);
+         break;
        case EAF_TYPE_INT_SET:
          ea_show_int_set(c, ad, 1, pos, buf, end);
          return;