From: Daniel Walton <[email protected]>

Credit
------
A huge amount of credit for this patch goes to Piotr Chytla for
their 'route tags support' patch that was submitted to quagga-dev
in June 2007.

Documentation
-------------
All ipv4 and ipv6 static route commands now have a "tag" option
which allows the user to set a tag between 1 and 65535.

quagga(config)# ip route 1.1.1.1/32 10.1.1.1 tag ?
  <1-65535>  Tag value
quagga(config)# ip route 1.1.1.1/32 10.1.1.1 tag 40
quagga(config)#

quagga# show ip route 1.1.1.1/32
Routing entry for 1.1.1.1/32
  Known via "static", distance 1, metric 0, tag 40, best
  * 10.1.1.1, via swp1

quagga#

The route-map parser supports matching on tags and setting tags
!
route-map MATCH_TAG_18 permit 10
 match tag 18
!

!
route-map SET_TAG_22 permit 10
 set tag 22
!

BGP and OSPF support:
- matching on tags when redistribing routes from the RIB into BGP/OSPF.
- setting tags when redistribing routes from the RIB into BGP/OSPF.

BGP also supports setting a tag via a table-map, when installing BGP
routes into the RIB.

Signed-off-by: Daniel Walton <[email protected]>
Signed-off-by: Piotr Chytla <[email protected]>
Signed-off-by: Donald Sharp <[email protected]>
---
 bgpd/bgp_attr.c     |   3 +
 bgpd/bgp_attr.h     |   3 +
 bgpd/bgp_route.c    |   8 +-
 bgpd/bgp_route.h    |   2 +-
 bgpd/bgp_routemap.c | 211 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 bgpd/bgp_zebra.c    |  43 ++++++++---
 vtysh/extract.pl.in |   2 +-
 7 files changed, 256 insertions(+), 16 deletions(-)

diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 6aba287..c4c6cc8 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -436,6 +436,7 @@ attrhash_key_make (void *p)
       MIX(extra->weight);
       MIX(extra->mp_nexthop_global_in.s_addr);
       MIX(extra->originator_id.s_addr);
+      MIX(extra->tag);
     }
   
   if (attr->aspath)
@@ -483,6 +484,7 @@ attrhash_cmp (const void *p1, const void *p2)
           && ae1->aggregator_as == ae2->aggregator_as
           && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
           && ae1->weight == ae2->weight
+          && ae1->tag == ae2->tag
 #ifdef HAVE_IPV6
           && ae1->mp_nexthop_len == ae2->mp_nexthop_len
           && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
@@ -630,6 +632,7 @@ bgp_attr_default_set (struct attr *attr, u_char origin)
   attr->aspath = aspath_empty ();
   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
   attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
+  attr->extra->tag = 0;
   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
 #ifdef HAVE_IPV6
   attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index e63202c..95d9594 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -85,6 +85,9 @@ struct attr_extra
   
   /* MP Nexthop length */
   u_char mp_nexthop_len;
+
+  /* route tag */
+  u_short tag;
 };
 
 /* BGP core attribute structure. */
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index e17396d..0e2c81b 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -5630,7 +5630,7 @@ ALIAS (no_ipv6_aggregate_address_summary_only,
 void
 bgp_redistribute_add (struct prefix *p, const struct in_addr *nexthop,
                      const struct in6_addr *nexthop6, unsigned int ifindex,
-                     u_int32_t metric, u_char type)
+                     u_int32_t metric, u_char type, u_short tag)
 {
   struct bgp *bgp;
   struct listnode *node, *nnode;
@@ -5660,6 +5660,7 @@ bgp_redistribute_add (struct prefix *p, const struct 
in_addr *nexthop,
 
   attr.med = metric;
   attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
+  attr.extra->tag = tag;
 
   for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp))
     {
@@ -6284,7 +6285,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, 
struct prefix *p,
        }
 #endif /* HAVE_IPV6 */
 
-      /* Line 3 display Origin, Med, Locpref, Weight, valid, Int/Ext/Local, 
Atomic, best */
+      /* Line 3 display Origin, Med, Locpref, Weight, Tag, valid, 
Int/Ext/Local, Atomic, best */
       vty_out (vty, "      Origin %s", bgp_origin_long_str[attr->origin]);
          
       if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC))
@@ -6297,6 +6298,9 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, 
struct prefix *p,
 
       if (attr->extra && attr->extra->weight != 0)
        vty_out (vty, ", weight %u", attr->extra->weight);
+
+      if (attr->extra && attr->extra->tag != 0)
+        vty_out (vty, ", tag %d", attr->extra->tag);
        
       if (! CHECK_FLAG (binfo->flags, BGP_INFO_VALID))
        vty_out (vty, ", invalid");
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index 399d5e0..2ed93f3 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -224,7 +224,7 @@ extern int bgp_maximum_prefix_overflow (struct peer *, 
afi_t, safi_t, int);
 
 extern void bgp_redistribute_add (struct prefix *, const struct in_addr *,
                                  const struct in6_addr *, unsigned int ifindex,
-                                 u_int32_t, u_char);
+                                 u_int32_t, u_char, u_short);
 extern void bgp_redistribute_delete (struct prefix *, u_char);
 extern void bgp_redistribute_withdraw (struct bgp *, afi_t, int);
 
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 320393d..c7b7f29 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -76,7 +76,7 @@ o Cisco route-map
        length           :  (This will not be implemented by bgpd)
        metric           :  Done
        route-type       :  (This will not be implemented by bgpd)
-       tag              :  (This will not be implemented by bgpd)
+       tag              :  Done
        local-preference :  Done
 
  set  as-path prepend   :  Done
@@ -96,7 +96,7 @@ o Cisco route-map
       metric            :  Done
       metric-type       :  Not yet
       origin            :  Done
-      tag               :  (This will not be implemented by bgpd)
+      tag               :  Done
       weight            :  Done
 
 o Local extensions
@@ -1060,6 +1060,72 @@ struct route_map_rule_cmd route_match_interface_cmd =
 
 /* `set ip next-hop IP_ADDRESS' */
 
+/* Match function return 1 if match is success else return zero. */
+static route_map_result_t
+route_match_tag (void *rule, struct prefix *prefix,
+                 route_map_object_t type, void *object)
+{
+  u_short *tag;
+  struct bgp_info *bgp_info;
+
+  if (type == RMAP_BGP)
+    {
+      tag = rule;
+      bgp_info = object;
+
+      if (!bgp_info->attr->extra)
+         return RMAP_NOMATCH;
+
+      return ((bgp_info->attr->extra->tag == *tag)? RMAP_MATCH : RMAP_NOMATCH);
+    }
+
+  return RMAP_NOMATCH;
+}
+
+
+/*  Route map `match tag' match statement. `arg' is TAG value */
+static void *
+route_match_tag_compile (const char *arg)
+{
+  u_short *tag;
+  u_short tmp;
+
+  /* tag value shoud be integer. */
+  if (! all_digit (arg))
+    return NULL;
+
+  tmp = atoi(arg);
+  if (tmp < 1)
+    return NULL;
+
+  tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short));
+
+  if (!tag)
+    return tag;
+
+  *tag = tmp;
+
+  return tag;
+}
+
+
+/* Free route map's compiled 'match tag' value. */
+static void
+route_match_tag_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for tag matching. */
+struct route_map_rule_cmd route_match_tag_cmd =
+{
+  "tag",
+  route_match_tag,
+  route_match_tag_compile,
+  route_match_tag_free,
+};
+
+
 /* Set nexthop to object.  ojbect must be pointer to struct attr. */
 struct rmap_ip_nexthop_set
 {
@@ -1833,6 +1899,73 @@ struct route_map_rule_cmd route_set_aggregator_as_cmd =
   route_set_aggregator_as_free,
 };
 
+/* Set tag to object. object must be pointer to struct bgp_info */
+static route_map_result_t
+route_set_tag (void *rule, struct prefix *prefix,
+               route_map_object_t type, void *object)
+{
+  u_short *tag;
+  struct bgp_info *bgp_info;
+  struct attr_extra *ae;
+
+  if (type == RMAP_BGP)
+    {
+      tag = rule;
+      bgp_info = object;
+      ae = bgp_attr_extra_get (bgp_info->attr);
+
+      /* Set tag value */
+      ae->tag=*tag;
+
+    }
+
+  return RMAP_OKAY;
+}
+
+/* Route map `tag' compile function.  Given string is converted to u_short. */
+static void *
+route_set_tag_compile (const char *arg)
+{
+  u_short *tag;
+  u_short tmp;
+
+  /* tag value shoud be integer. */
+  if (! all_digit (arg))
+    return NULL;
+
+  tmp = atoi(arg);
+
+  if (tmp < 1)
+      return NULL;
+
+  tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short));
+
+  if (!tag)
+    return tag;
+
+  *tag = tmp;
+
+  return tag;
+}
+
+/* Free route map's tag value. */
+static void
+route_set_tag_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+
+/* Route map commands for tag set. */
+struct route_map_rule_cmd route_set_tag_cmd =
+{
+  "tag",
+  route_set_tag,
+  route_set_tag_compile,
+  route_set_tag_free,
+};
+
+
 #ifdef HAVE_IPV6
 /* `match ipv6 address IP_ACCESS_LIST' */
 
@@ -3399,6 +3532,41 @@ ALIAS (no_match_interface,
        "Match first hop interface of route\n"
        "Interface name\n")
 
+DEFUN (match_tag,
+       match_tag_cmd,
+       "match tag <1-65535>",
+       MATCH_STR
+       "Match tag of route\n"
+       "Tag value\n")
+{
+  return bgp_route_match_add (vty, vty->index, "tag", argv[0],
+                             RMAP_EVENT_MATCH_ADDED);
+}
+
+DEFUN (no_match_tag,
+       no_match_tag_cmd,
+       "no match tag",
+       NO_STR
+       MATCH_STR
+       "Match tag of route\n")
+{
+  if (argc == 0)
+    return bgp_route_match_delete (vty, vty->index, "tag", NULL,
+                                  RMAP_EVENT_MATCH_DELETED);
+
+  return bgp_route_match_delete (vty, vty->index, "tag", argv[0],
+                                RMAP_EVENT_MATCH_DELETED);
+}
+
+ALIAS (no_match_tag,
+       no_match_tag_val_cmd,
+       "no match tag <1-65535>",
+       NO_STR
+       MATCH_STR
+       "Match tag of route\n"
+       "Tag value\n")
+
+
 DEFUN (set_ip_nexthop,
        set_ip_nexthop_cmd,
        "set ip next-hop A.B.C.D",
@@ -4064,6 +4232,37 @@ ALIAS (no_set_aggregator_as,
        "AS number\n"
        "IP address of aggregator\n")
 
+DEFUN (set_tag,
+       set_tag_cmd,
+       "set tag <1-65535>",
+       SET_STR
+       "Tag value for routing protocol\n"
+       "Tag value\n")
+{
+  return bgp_route_set_add (vty, vty->index, "tag", argv[0]);
+}
+
+DEFUN (no_set_tag,
+       no_set_tag_cmd,
+       "no set tag",
+       NO_STR
+       SET_STR
+       "Tag value for routing protocol\n")
+{
+  if (argc == 0)
+      bgp_route_set_delete(vty, vty->index, "tag", NULL);
+
+  return bgp_route_set_delete (vty, vty->index, "tag", argv[0]);
+}
+
+ALIAS (no_set_tag,
+       no_set_tag_val_cmd,
+       "no set tag <1-65535>",
+       NO_STR
+       SET_STR
+       "Tag value for routing protocol\n"
+       "Tag value\n")
+
 
 #ifdef HAVE_IPV6
 DEFUN (match_ipv6_address, 
@@ -4391,6 +4590,7 @@ bgp_route_map_init (void)
   route_map_install_match (&route_match_origin_cmd);
   route_map_install_match (&route_match_probability_cmd);
   route_map_install_match (&route_match_interface_cmd);
+  route_map_install_match (&route_match_tag_cmd);
 
   route_map_install_set (&route_set_ip_nexthop_cmd);
   route_map_install_set (&route_set_local_pref_cmd);
@@ -4407,6 +4607,7 @@ bgp_route_map_init (void)
   route_map_install_set (&route_set_originator_id_cmd);
   route_map_install_set (&route_set_ecommunity_rt_cmd);
   route_map_install_set (&route_set_ecommunity_soo_cmd);
+  route_map_install_set (&route_set_tag_cmd);
 
   install_element (RMAP_NODE, &match_peer_cmd);
   install_element (RMAP_NODE, &match_peer_local_cmd);
@@ -4458,6 +4659,9 @@ bgp_route_map_init (void)
   install_element (RMAP_NODE, &match_interface_cmd);
   install_element (RMAP_NODE, &no_match_interface_cmd);
   install_element (RMAP_NODE, &no_match_interface_val_cmd);
+  install_element (RMAP_NODE, &match_tag_cmd);
+  install_element (RMAP_NODE, &no_match_tag_cmd);
+  install_element (RMAP_NODE, &no_match_tag_val_cmd);
 
   install_element (RMAP_NODE, &set_ip_nexthop_cmd);
   install_element (RMAP_NODE, &set_ip_nexthop_peer_cmd);
@@ -4509,6 +4713,9 @@ bgp_route_map_init (void)
   install_element (RMAP_NODE, &set_originator_id_cmd);
   install_element (RMAP_NODE, &no_set_originator_id_cmd);
   install_element (RMAP_NODE, &no_set_originator_id_val_cmd);
+  install_element (RMAP_NODE, &set_tag_cmd);
+  install_element (RMAP_NODE, &no_set_tag_cmd);
+  install_element (RMAP_NODE, &no_set_tag_val_cmd);
 
 #ifdef HAVE_IPV6
   route_map_install_match (&route_match_ipv6_address_cmd);
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index d95e92d..6ba671b 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -443,7 +443,7 @@ zebra_read_ipv4 (int command, struct zclient *zclient, 
zebra_size_t length,
                     api.tag);
        }
       bgp_redistribute_add((struct prefix *)&p, &nexthop, NULL, ifindex,
-                          api.metric, api.type);
+                          api.metric, api.type, api.tag);
     }
   else
     {
@@ -538,7 +538,7 @@ zebra_read_ipv6 (int command, struct zclient *zclient, 
zebra_size_t length,
                     api.tag);
        }
       bgp_redistribute_add ((struct prefix *)&p, NULL, &nexthop, ifindex,
-                           api.metric, api.type);
+                           api.metric, api.type, api.tag);
     }
   else
     {
@@ -924,6 +924,9 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info 
*info, struct bgp *bgp,
   flags = 0;
   peer = info->peer;
 
+  if ((info->attr->extra) && (info->attr->extra->tag != 0))
+    tag = info->attr->extra->tag;
+
   if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED)
     {
       SET_FLAG (flags, ZEBRA_FLAG_IBGP);
@@ -972,6 +975,9 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info 
*info, struct bgp *bgp,
             {
               metric = info_cp->attr->med;
               nexthop = &info_cp->attr->nexthop;
+
+              if (info_cp->attr->extra)
+                tag = info_cp->attr->extra->tag;
             }
           BGP_INFO_ATTR_BUF_FREE(info_cp);
         }
@@ -1029,10 +1035,10 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info 
*info, struct bgp *bgp,
       api.metric = metric;
 
       if (tag)
-       {
-         SET_FLAG (api.message, ZAPI_MESSAGE_TAG);
-         api.tag = tag;
-       }
+        {
+          SET_FLAG (api.message, ZAPI_MESSAGE_TAG);
+          api.tag = tag;
+        }
 
       distance = bgp_distance_apply (p, info, bgp);
 
@@ -1115,6 +1121,9 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info 
*info, struct bgp *bgp,
             {
               metric = info_cp->attr->med;
               nexthop = bgp_info_to_ipv6_nexthop(info_cp);
+
+              if (info_cp->attr->extra)
+                tag = info_cp->attr->extra->tag;
             }
           BGP_INFO_ATTR_BUF_FREE(info_cp);
         }
@@ -1287,13 +1296,20 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info 
*info, safi_t safi)
       SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
       api.metric = info->attr->med;
 
+      if ((info->attr->extra) && (info->attr->extra->tag != 0))
+        {
+          SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
+          api.tag = info->attr->extra->tag;
+        }
+
       if (BGP_DEBUG(zebra, ZEBRA))
        {
          char buf[2][INET_ADDRSTRLEN];
-         zlog_debug("Zebra send: IPv4 route delete %s/%d metric %u",
+         zlog_debug("Zebra send: IPv4 route delete %s/%d metric %u tag %d",
                     inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
                     p->prefixlen,
-                    api.metric);
+                    api.metric,
+                    api.tag);
        }
 
       zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient, 
@@ -1314,13 +1330,20 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info 
*info, safi_t safi)
       SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
       api.metric = info->attr->med;
 
+      if ((info->attr->extra) && (info->attr->extra->tag != 0))
+        {
+          SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
+          api.tag = info->attr->extra->tag;
+        }
+
       if (BGP_DEBUG(zebra, ZEBRA))
        {
          char buf[2][INET6_ADDRSTRLEN];
-         zlog_debug("Zebra send: IPv6 route delete %s/%d metric %u",
+         zlog_debug("Zebra send: IPv6 route delete %s/%d metric %u tag %d",
                     inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
                     p->prefixlen,
-                    api.metric);
+                    api.metric,
+                    api.tag);
        }
 
       zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, 
diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in
index 8415e7e..e02521f 100755
--- a/vtysh/extract.pl.in
+++ b/vtysh/extract.pl.in
@@ -177,7 +177,7 @@ foreach (@ARGV) {
     }
 }
 
-my $bad_cli_stomps = 93;
+my $bad_cli_stomps = 99;
 # Currently we have $bad_cli_stomps.  This was determined by
 # running this script and counting up the collisions from what
 # was returned.
-- 
1.9.1


_______________________________________________
Quagga-dev mailing list
[email protected]
https://lists.quagga.net/mailman/listinfo/quagga-dev

Reply via email to