]> git.proxmox.com Git - mirror_frr.git/commitdiff
bgpd: refactor route-map objects modifying integer values
authorTimo Teräs <timo.teras@iki.fi>
Wed, 29 Apr 2015 06:43:02 +0000 (09:43 +0300)
committervivek <vivek@cumulusnetworks.com>
Mon, 6 Jun 2016 15:04:57 +0000 (08:04 -0700)
Use common code to parse, validate and adjust the route-map
objects that contain a simple integer value. This also allows
compiling the add/sub format metric object.

Signed-off-by: Timo Teräs <timo.teras@iki.fi>
Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
(cherry picked from commit 38f22ab07c8e1f0f12e23c2e2d0a3e1f71bef695)

Conflicts:
bgpd/bgp_routemap.c

bgpd/bgp_routemap.c

index f237f7689b11e94a7deb41fcab052ab84629f7b9..7a7814d414b0a07b74d3c02042f4352a46e81ffd 100644 (file)
@@ -108,6 +108,86 @@ o Local extensions
 
 */ 
 
+ /* generic value manipulation to be shared in multiple rules */
+
+#define RMAP_VALUE_SET 0
+#define RMAP_VALUE_ADD 1
+#define RMAP_VALUE_SUB 2
+
+struct rmap_value
+{
+  u_int8_t action;
+  u_int32_t value;
+};
+
+static int
+route_value_match (struct rmap_value *rv, u_int32_t value)
+{
+  if (value == rv->value)
+    return RMAP_MATCH;
+
+  return RMAP_NOMATCH;
+}
+
+static u_int32_t
+route_value_adjust (struct rmap_value *rv, u_int32_t current)
+{
+  u_int32_t value = rv->value;
+
+  switch (rv->action)
+    {
+    case RMAP_VALUE_ADD:
+      if (current > UINT32_MAX-value)
+        return UINT32_MAX;
+      return current + value;
+    case RMAP_VALUE_SUB:
+      if (current <= value)
+        return 0;
+      return current - value;
+    default:
+      return value;
+    }
+}
+
+static void *
+route_value_compile (const char *arg)
+{
+  u_int8_t action = RMAP_VALUE_SET;
+  unsigned long larg;
+  char *endptr = NULL;
+  struct rmap_value *rv;
+
+  if (arg[0] == '+')
+    {
+      action = RMAP_VALUE_ADD;
+      arg++;
+    }
+  else if (arg[0] == '-')
+    {
+      action = RMAP_VALUE_SUB;
+      arg++;
+    }
+
+  errno = 0;
+  larg = strtoul (arg, &endptr, 10);
+  if (*arg == 0 || *endptr != 0 || errno || larg > UINT32_MAX)
+    return NULL;
+
+  rv = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_value));
+  if (!rv)
+    return NULL;
+
+  rv->action = action;
+  rv->value = larg;
+  return rv;
+}
+
+static void
+route_value_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
  /* generic as path object to be shared in multiple rules */
 
 static void *
@@ -591,62 +671,25 @@ static route_map_result_t
 route_match_metric (void *rule, struct prefix *prefix, 
                    route_map_object_t type, void *object)
 {
-  u_int32_t *med;
+  struct rmap_value *rv;
   struct bgp_info *bgp_info;
 
   if (type == RMAP_BGP)
     {
-      med = rule;
+      rv = rule;
       bgp_info = object;
-    
-      if (bgp_info->attr->med == *med)
-       return RMAP_MATCH;
-      else
-       return RMAP_NOMATCH;
+      return route_value_match(rv, bgp_info->attr->med);
     }
   return RMAP_NOMATCH;
 }
 
-/* Route map `match metric' match statement. `arg' is MED value */
-static void *
-route_match_metric_compile (const char *arg)
-{
-  u_int32_t *med;
-  char *endptr = NULL;
-  unsigned long tmpval;
-
-  /* Metric value shoud be integer. */
-  if (! all_digit (arg))
-    return NULL;
-
-  errno = 0;
-  tmpval = strtoul (arg, &endptr, 10);
-  if (*endptr != '\0' || errno || tmpval > UINT32_MAX)
-    return NULL;
-    
-  med = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
-  
-  if (!med)
-    return med;
-  
-  *med = tmpval;
-  return med;
-}
-
-/* Free route map's compiled `match metric' value. */
-static void
-route_match_metric_free (void *rule)
-{
-  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
-}
-
 /* Route map commands for metric matching. */
 struct route_map_rule_cmd route_match_metric_cmd =
 {
   "metric",
   route_match_metric,
-  route_match_metric_compile,
-  route_match_metric_free
+  route_value_compile,
+  route_value_free,
 };
 
 /* `match as-path ASPATH' */
@@ -1186,64 +1229,34 @@ static route_map_result_t
 route_set_local_pref (void *rule, struct prefix *prefix,
                      route_map_object_t type, void *object)
 {
-  u_int32_t *local_pref;
+  struct rmap_value *rv;
   struct bgp_info *bgp_info;
+  u_int32_t locpref = 0;
 
   if (type == RMAP_BGP)
     {
       /* Fetch routemap's rule information. */
-      local_pref = rule;
+      rv = rule;
       bgp_info = object;
     
       /* Set local preference value. */ 
+      if (bgp_info->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
+       locpref = bgp_info->attr->local_pref;
+
       bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
-      bgp_info->attr->local_pref = *local_pref;
+      bgp_info->attr->local_pref = route_value_adjust(rv, locpref);
     }
 
   return RMAP_OKAY;
 }
 
-/* set local preference compilation. */
-static void *
-route_set_local_pref_compile (const char *arg)
-{
-  unsigned long tmp;
-  u_int32_t *local_pref;
-  char *endptr = NULL;
-
-  /* Local preference value shoud be integer. */
-  if (! all_digit (arg))
-    return NULL;
-  
-  errno = 0;
-  tmp = strtoul (arg, &endptr, 10);
-  if (*endptr != '\0' || errno || tmp > UINT32_MAX)
-    return NULL;
-   
-  local_pref = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); 
-  
-  if (!local_pref)
-    return local_pref;
-  
-  *local_pref = tmp;
-  
-  return local_pref;
-}
-
-/* Free route map's local preference value. */
-static void
-route_set_local_pref_free (void *rule)
-{
-  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
-}
-
 /* Set local preference rule structure. */
 struct route_map_rule_cmd route_set_local_pref_cmd = 
 {
   "local-preference",
   route_set_local_pref,
-  route_set_local_pref_compile,
-  route_set_local_pref_free,
+  route_value_compile,
+  route_value_free,
 };
 
 /* `set weight WEIGHT' */
@@ -1253,18 +1266,20 @@ static route_map_result_t
 route_set_weight (void *rule, struct prefix *prefix, route_map_object_t type,
                  void *object)
 {
-  u_int32_t *weight;
+  struct rmap_value *rv;
   struct bgp_info *bgp_info;
+  u_int32_t weight;
 
   if (type == RMAP_BGP)
     {
       /* Fetch routemap's rule information. */
-      weight = rule;
+      rv = rule;
       bgp_info = object;
     
       /* Set weight value. */ 
-      if (*weight)
-        (bgp_attr_extra_get (bgp_info->attr))->weight = *weight;
+      weight = route_value_adjust(rv, 0);
+      if (weight)
+        (bgp_attr_extra_get (bgp_info->attr))->weight = weight;
       else if (bgp_info->attr->extra)
         bgp_info->attr->extra->weight = 0;
     }
@@ -1272,47 +1287,13 @@ route_set_weight (void *rule, struct prefix *prefix, route_map_object_t type,
   return RMAP_OKAY;
 }
 
-/* set local preference compilation. */
-static void *
-route_set_weight_compile (const char *arg)
-{
-  unsigned long tmp;
-  u_int32_t *weight;
-  char *endptr = NULL;
-
-  /* Local preference value shoud be integer. */
-  if (! all_digit (arg))
-    return NULL;
-
-  errno = 0;
-  tmp = strtoul (arg, &endptr, 10);
-  if (*endptr != '\0' || errno || tmp > UINT32_MAX)
-    return NULL;
-  
-  weight = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
-  
-  if (weight == NULL)
-    return weight;
-  
-  *weight = tmp;  
-  
-  return weight;
-}
-
-/* Free route map's local preference value. */
-static void
-route_set_weight_free (void *rule)
-{
-  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
-}
-
 /* Set local preference rule structure. */
 struct route_map_rule_cmd route_set_weight_cmd = 
 {
   "weight",
   route_set_weight,
-  route_set_weight_compile,
-  route_set_weight_free,
+  route_value_compile,
+  route_value_free,
 };
 
 /* `set metric METRIC' */
@@ -1322,94 +1303,32 @@ static route_map_result_t
 route_set_metric (void *rule, struct prefix *prefix, 
                  route_map_object_t type, void *object)
 {
-  char *metric;
-  u_int32_t metric_val;
+  struct rmap_value *rv;
   struct bgp_info *bgp_info;
+  u_int32_t med = 0;
 
   if (type == RMAP_BGP)
     {
       /* Fetch routemap's rule information. */
-      metric = rule;
+      rv = rule;
       bgp_info = object;
 
-      if (! (bgp_info->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)))
-       bgp_info->attr->med = 0;
-      bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
+      if (bgp_info->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
+       med = bgp_info->attr->med;
 
-      if (all_digit (metric))
-       {
-         metric_val = strtoul (metric, (char **)NULL, 10);
-         bgp_info->attr->med = metric_val;
-       }
-      else
-       {
-         metric_val = strtoul (metric+1, (char **)NULL, 10);
-
-         if (strncmp (metric, "+", 1) == 0)
-           {
-             if (bgp_info->attr->med/2 + metric_val/2 > BGP_MED_MAX/2)
-               bgp_info->attr->med = BGP_MED_MAX - 1;
-             else
-               bgp_info->attr->med += metric_val;
-           }
-         else if (strncmp (metric, "-", 1) == 0)
-           {
-             if (bgp_info->attr->med <= metric_val)
-               bgp_info->attr->med = 0;
-             else
-               bgp_info->attr->med -= metric_val;
-           }
-       }
+      bgp_info->attr->med = route_value_adjust(rv, med);
+      bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
     }
   return RMAP_OKAY;
 }
 
-/* set metric compilation. */
-static void *
-route_set_metric_compile (const char *arg)
-{
-  unsigned long larg;
-  char *endptr = NULL;
-
-  if (all_digit (arg))
-    {
-      /* set metric value check*/
-      errno = 0;
-      larg = strtoul (arg, &endptr, 10);
-      if (*endptr != '\0' || errno || larg > UINT32_MAX)
-        return NULL;
-    }
-  else
-    {
-      /* set metric <+/-metric> check */
-      if ((strncmp (arg, "+", 1) != 0
-          && strncmp (arg, "-", 1) != 0)
-          || (! all_digit (arg+1)))
-       return NULL;
-
-      errno = 0;
-      larg = strtoul (arg+1, &endptr, 10);
-      if (*endptr != '\0' || errno || larg > UINT32_MAX)
-       return NULL;
-    }
-
-  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
-}
-
-/* Free route map's compiled `set metric' value. */
-static void
-route_set_metric_free (void *rule)
-{
-  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
-}
-
 /* Set metric rule structure. */
 struct route_map_rule_cmd route_set_metric_cmd = 
 {
   "metric",
   route_set_metric,
-  route_set_metric_compile,
-  route_set_metric_free,
+  route_value_compile,
+  route_value_free,
 };
 
 /* `set as-path prepend ASPATH' */