]> git.puffer.fish Git - mirror/frr.git/commitdiff
Add support for route tags
authorDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 20 May 2015 00:46:33 +0000 (17:46 -0700)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 20 May 2015 00:46:33 +0000 (17:46 -0700)
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 <dwalton@cumulusnetworks.com>
21 files changed:
bgpd/bgp_attr.c
bgpd/bgp_attr.h
bgpd/bgp_route.c
bgpd/bgp_route.h
bgpd/bgp_routemap.c
bgpd/bgp_zebra.c
lib/zclient.c
lib/zclient.h
ospfd/ospf_asbr.c
ospfd/ospf_asbr.h
ospfd/ospf_lsa.c
ospfd/ospf_routemap.c
ospfd/ospf_zebra.c
ospfd/ospfd.c
ospfd/ospfd.h
ripd/rip_routemap.c
ripngd/ripng_routemap.c
zebra/rib.h
zebra/zebra_rib.c
zebra/zebra_vty.c
zebra/zserv.c

index e7a6a9e17ef88fbdcadbec4fd21a0b6b1dd5f875..7709ff4a4c1c7a5a487eb57b53bb4e16a96b6923 100644 (file)
@@ -435,6 +435,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)
@@ -482,6 +483,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)
@@ -618,6 +620,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;
index 5aa0c39f952024d95c4e1e4fd8c046b341b7556a..91626f25c67a9514291ca23f8e346ef62cf2a376 100644 (file)
@@ -85,6 +85,9 @@ struct attr_extra
   
   /* MP Nexthop length */
   u_char mp_nexthop_len;
+
+  /* route tag */
+  u_short tag;
 };
 
 /* BGP core attribute structure. */
index be6cb3b2598081f0bb5679eeac44640039f4795e..d45ffd0e182d754af288a6075db232ceb488077a 100644 (file)
@@ -5593,7 +5593,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;
@@ -5623,6 +5623,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))
     {
@@ -6288,7 +6289,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))
@@ -6301,6 +6302,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_HISTORY))
        vty_out (vty, ", valid");
index 905295b94e23b6950213c257582a5769d2aaaed0..eab51bb62a27dad14a02bdd61dc0dcfd5ca79a33 100644 (file)
@@ -217,7 +217,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);
 
index 49cde8ea951d995a2ab8685794690ec3afac0798..2d821cac522922e33c143ed64a796d3c66c962cd 100644 (file)
@@ -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
@@ -1007,6 +1007,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
 {
@@ -1878,6 +1944,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' */
 
@@ -3447,6 +3580,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",
@@ -4094,6 +4262,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, 
@@ -4421,6 +4620,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);
@@ -4437,6 +4637,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);
@@ -4488,6 +4689,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);
@@ -4537,6 +4741,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);
index 9391030c1e72137e99d73994af4f8e3c226ba0a7..369bcddf0a6540d04d8844db5048a89a6456df6c 100644 (file)
@@ -402,32 +402,41 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length)
       api.nexthop_num = stream_getc (s);
       nexthop.s_addr = stream_get_ipv4 (s);
     }
+
   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX))
     {
       api.ifindex_num = stream_getc (s);
       ifindex = stream_getl (s); /* ifindex, unused */
     }
+
   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
     api.distance = stream_getc (s);
+
   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
     api.metric = stream_getl (s);
   else
     api.metric = 0;
 
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG))
+    api.tag = stream_getw (s);
+  else
+    api.tag = 0;
+
   if (command == ZEBRA_IPV4_ROUTE_ADD)
     {
       if (BGP_DEBUG(zebra, ZEBRA))
        {
          char buf[2][INET_ADDRSTRLEN];
-         zlog_debug("Zebra rcvd: IPv4 route add %s %s/%d nexthop %s metric %u",
+         zlog_debug("Zebra rcvd: IPv4 route add %s %s/%d nexthop %s metric %u tag %d",
                     zebra_route_string(api.type),
                     inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
                     p.prefixlen,
                     inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
-                    api.metric);
+                    api.metric,
+                    api.tag);
        }
       bgp_redistribute_add((struct prefix *)&p, &nexthop, NULL, ifindex,
-                          api.metric, api.type);
+                          api.metric, api.type, api.tag);
     }
   else
     {
@@ -435,12 +444,13 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length)
        {
          char buf[2][INET_ADDRSTRLEN];
          zlog_debug("Zebra rcvd: IPv4 route delete %s %s/%d "
-                    "nexthop %s metric %u",
+                    "nexthop %s metric %u tag %d",
                     zebra_route_string(api.type),
                     inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
                     p.prefixlen,
                     inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
-                    api.metric);
+                    api.metric,
+                    api.tag);
        }
       bgp_redistribute_delete((struct prefix *)&p, api.type);
     }
@@ -479,20 +489,28 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length)
       api.nexthop_num = stream_getc (s);
       stream_get (&nexthop, s, 16);
     }
+
   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX))
     {
       api.ifindex_num = stream_getc (s);
       ifindex = stream_getl (s); /* ifindex, unused */
     }
+
   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
     api.distance = stream_getc (s);
   else
     api.distance = 0;
+
   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
     api.metric = stream_getl (s);
   else
     api.metric = 0;
 
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG))
+    api.tag = stream_getw (s);
+  else
+    api.tag = 0;
+
   /* Simply ignore link-local address. */
   if (IN6_IS_ADDR_LINKLOCAL (&p.prefix))
     return 0;
@@ -502,15 +520,16 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length)
       if (BGP_DEBUG(zebra, ZEBRA))
        {
          char buf[2][INET6_ADDRSTRLEN];
-         zlog_debug("Zebra rcvd: IPv6 route add %s %s/%d nexthop %s metric %u",
+         zlog_debug("Zebra rcvd: IPv6 route add %s %s/%d nexthop %s metric %u tag %d",
                     zebra_route_string(api.type),
                     inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])),
                     p.prefixlen,
                     inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
-                    api.metric);
+                    api.metric,
+                    api.tag);
        }
       bgp_redistribute_add ((struct prefix *)&p, NULL, &nexthop, ifindex,
-                           api.metric, api.type);
+                           api.metric, api.type, api.tag);
     }
   else
     {
@@ -518,12 +537,13 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length)
        {
          char buf[2][INET6_ADDRSTRLEN];
          zlog_debug("Zebra rcvd: IPv6 route delete %s %s/%d "
-                    "nexthop %s metric %u",
+                    "nexthop %s metric %u tag %d",
                     zebra_route_string(api.type),
                     inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])),
                     p.prefixlen,
                     inet_ntop(AF_INET6, &nexthop, buf[1], sizeof(buf[1])),
-                    api.metric);
+                    api.metric,
+                     api.tag);
        }
       bgp_redistribute_delete ((struct prefix *) &p, api.type);
     }
@@ -876,6 +896,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
   u_int32_t nhcount, metric;
   struct bgp_info local_info;
   struct bgp_info *info_cp = &local_info;
+  u_short tag;
 
   if (zclient->sock < 0)
     return;
@@ -889,6 +910,11 @@ 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;
+  else
+    tag = 0;
+
   if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED)
     {
       SET_FLAG (flags, ZEBRA_FLAG_IBGP);
@@ -937,6 +963,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);
         }
@@ -988,6 +1017,12 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
       SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
       api.metric = metric;
 
+      if (tag)
+        {
+          SET_FLAG (api.message, ZAPI_MESSAGE_TAG);
+          api.tag = tag;
+        }
+
       distance = bgp_distance_apply (p, info, bgp);
 
       if (distance)
@@ -999,10 +1034,10 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
       if (BGP_DEBUG(zebra, ZEBRA))
         {
           int i;
-          zlog_debug("Zebra send: IPv4 route %s %s/%d  metric %u"
+          zlog_debug("Zebra send: IPv4 route %s %s/%d metric %u tag %d"
                      " count %d", (valid_nh_count ? "add":"delete"),
                      inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
-                     p->prefixlen, api.metric, api.nexthop_num);
+                     p->prefixlen, api.metric, api.tag, api.nexthop_num);
           for (i = 0; i < api.nexthop_num; i++)
             zlog_debug("  IPv4 [nexthop %d] %s", i+1,
                        inet_ntop(AF_INET, api.nexthop[i], buf[1], sizeof(buf[1])));
@@ -1069,6 +1104,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);
         }
@@ -1149,13 +1187,19 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
       SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
       api.metric = metric;
 
+      if (tag)
+        {
+          SET_FLAG (api.message, ZAPI_MESSAGE_TAG);
+          api.tag = tag;
+        }
+
       if (BGP_DEBUG(zebra, ZEBRA))
         {
           int i;
-          zlog_debug("Zebra send: IPv6 route %s %s/%d metric %u",
+          zlog_debug("Zebra send: IPv6 route %s %s/%d metric %u tag %d",
                    valid_nh_count ? "add" : "delete",
                    inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
-                   p->prefixlen, api.metric);
+                   p->prefixlen, api.metric, api.tag);
           for (i = 0; i < api.nexthop_num; i++)
             zlog_debug("  IPv6 [nexthop %d] %s", i+1,
                        inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1])));
@@ -1233,14 +1277,21 @@ 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 nexthop %s metric %u",
+         zlog_debug("Zebra send: IPv4 route delete %s/%d nexthop %s metric %u tag %d",
                     inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
                     p->prefixlen,
                     inet_ntop(AF_INET, nexthop, buf[1], sizeof(buf[1])),
-                    api.metric);
+                    api.metric,
+                    api.tag);
        }
 
       zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient, 
@@ -1291,14 +1342,21 @@ 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 nexthop %s metric %u",
+         zlog_debug("Zebra send: IPv6 route delete %s/%d nexthop %s metric %u tag %d",
                     inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
                     p->prefixlen,
                     inet_ntop(AF_INET6, nexthop, buf[1], sizeof(buf[1])),
-                    api.metric);
+                    api.metric,
+                     api.tag);
        }
 
       zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, 
index 8b4597714e90a1fe2d1937d5bb4d42acaf4ce3eb..72367206b763c3d896a418eb5a698ce37b794dc3 100644 (file)
@@ -456,6 +456,8 @@ zclient_connect (struct thread *t)
   * If ZAPI_MESSAGE_METRIC is set, the metric value is written as an 8
   * byte value.
   *
+  * If ZAPI_MESSAGE_TAG is set, the tag value is written as a 2 byte value
+  *
   * XXX: No attention paid to alignment.
   */ 
 int
@@ -512,6 +514,8 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p,
     stream_putc (s, api->distance);
   if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC))
     stream_putl (s, api->metric);
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_TAG))
+    stream_putw (s, api->tag);
 
   /* Put length at the first point of the stream. */
   stream_putw_at (s, 0, stream_get_endp (s));
@@ -566,6 +570,8 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p,
     stream_putc (s, api->distance);
   if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC))
     stream_putl (s, api->metric);
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_TAG))
+    stream_putw (s, api->tag);
 
   /* Put length at the first point of the stream. */
   stream_putw_at (s, 0, stream_get_endp (s));
index 5c24ee4592aea0b8a3ccd96fc6a045e4bf781765..9b627b65f96076f34d3c26494a592daafe175d44 100644 (file)
@@ -92,6 +92,7 @@ struct zclient
 #define ZAPI_MESSAGE_IFINDEX  0x02
 #define ZAPI_MESSAGE_DISTANCE 0x04
 #define ZAPI_MESSAGE_METRIC   0x08
+#define ZAPI_MESSAGE_TAG      0x20
 
 /* Zserv protocol message header */
 struct zserv_header
@@ -125,6 +126,8 @@ struct zapi_ipv4
   u_char distance;
 
   u_int32_t metric;
+
+  u_short tag;
 };
 
 /* Prototypes of zebra client service functions. */
@@ -185,6 +188,8 @@ struct zapi_ipv6
   u_char distance;
 
   u_int32_t metric;
+
+  u_short tag;
 };
 
 extern int zapi_ipv6_route (u_char cmd, struct zclient *zclient, 
index dbf7f11f53e82f0ce1bf1d0b243568c3603ac7e0..f4140b858c55f860d216ba1ef499a03f3f57ce66 100644 (file)
@@ -135,7 +135,8 @@ ospf_route_map_set_compare (struct route_map_set_values *values1,
 /* Add an External info for AS-external-LSA. */
 struct external_info *
 ospf_external_info_add (u_char type, struct prefix_ipv4 p,
-                       unsigned int ifindex, struct in_addr nexthop)
+                       unsigned int ifindex, struct in_addr nexthop,
+                        u_short tag)
 {
   struct external_info *new;
   struct route_node *rn;
@@ -162,7 +163,7 @@ ospf_external_info_add (u_char type, struct prefix_ipv4 p,
   new->p = p;
   new->ifindex = ifindex;
   new->nexthop = nexthop;
-  new->tag = 0;
+  new->tag = tag;
 
   if (rn)
     rn->info = new;
index 724acf481779f0204a6e7180a5f8e06aa54b6484..bb773c979042f802c1e2867f2dc872f0dc3e6241 100644 (file)
@@ -62,7 +62,8 @@ extern int ospf_route_map_set_compare (struct route_map_set_values *,
 extern struct external_info *ospf_external_info_add (u_char, 
                                               struct prefix_ipv4,
                                              unsigned int, 
-                                             struct in_addr);
+                                             struct in_addr,
+                                             u_short);
 extern void ospf_external_info_delete (u_char, struct prefix_ipv4);
 extern struct external_info *ospf_external_info_lookup (u_char, 
                                                  struct prefix_ipv4 *);
index 31cbaaef24e8c96566e5af830f090051c91f8d12..eabfa7b689ab2a01d65c64426c3246185bd82f58 100644 (file)
@@ -1638,8 +1638,8 @@ ospf_external_lsa_body_set (struct stream *s, struct external_info *ei,
   /* Put forwarding address. */
   stream_put_ipv4 (s, fwd_addr.s_addr);
   
-  /* Put route tag -- This value should be introduced from configuration. */
-  stream_putl (s, 0);
+  /* Put route tag -- only first 16bits are used for compatibility */
+  stream_putl (s, ei->tag);
 }
 
 /* Create new external-LSA. */
@@ -2152,7 +2152,7 @@ ospf_default_originate_timer (struct thread *thread)
       /* If there is no default route via redistribute,
         then originate AS-external-LSA with nexthop 0 (self). */
       nexthop.s_addr = 0;
-      ospf_external_info_add (DEFAULT_ROUTE, p, 0, nexthop);
+      ospf_external_info_add (DEFAULT_ROUTE, p, 0, nexthop, 0);
     }
 
   if ((ei = ospf_default_external_info (ospf)))
index d0ebce66ee3b71e368f42d24f53db076c39ae48e..7bd6c3d9613d6c2eaf961194fd3ff2267b205fab 100644 (file)
@@ -417,6 +417,67 @@ struct route_map_rule_cmd route_match_interface_cmd =
   route_match_interface_free
 };
 
+/* 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 external_info *ei;
+
+  if (type == RMAP_OSPF)
+    {
+      tag = rule;
+      ei = object;
+
+      return ((ei->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 metric METRIC' */
 /* Set metric to attribute. */
 static route_map_result_t
@@ -531,6 +592,67 @@ struct route_map_rule_cmd route_set_metric_type_cmd =
   route_set_metric_type_free,
 };
 
+static route_map_result_t
+route_set_tag (void *rule, struct prefix *prefix,
+               route_map_object_t type, void *object)
+{
+  u_short *tag;
+  struct external_info *ei;
+
+  if (type == RMAP_OSPF)
+    {
+      tag = rule;
+      ei = object;
+
+      /* Set tag value */
+      ei->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,
+};
+
 DEFUN (match_ip_nexthop,
        match_ip_nexthop_cmd,
        "match ip next-hop (<1-199>|<1300-2699>|WORD)",
@@ -716,6 +838,37 @@ 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 ospf_route_match_add (vty, vty->index, "tag", argv[0]);
+}
+
+DEFUN (no_match_tag,
+       no_match_tag_cmd,
+       "no match tag",
+       NO_STR
+       MATCH_STR
+       "Match tag of route\n")
+{
+  if (argc == 0)
+    return ospf_route_match_delete (vty, vty->index, "tag", NULL);
+
+  return ospf_route_match_delete (vty, vty->index, "tag", argv[0]);
+}
+
+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_metric,
        set_metric_cmd,
        "set metric <0-4294967295>",
@@ -785,6 +938,37 @@ ALIAS (no_set_metric_type,
        "OSPF[6] external type 1 metric\n"
        "OSPF[6] external type 2 metric\n")
 
+DEFUN (set_tag,
+       set_tag_cmd,
+       "set tag <1-65535>",
+       SET_STR
+       "Tag value for routing protocol\n"
+       "Tag value\n")
+{
+  return ospf_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)
+      ospf_route_set_delete(vty, vty->index, "tag", NULL);
+
+  return ospf_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")
+
 /* Route-map init */
 void
 ospf_route_map_init (void)
@@ -801,9 +985,11 @@ ospf_route_map_init (void)
   route_map_install_match (&route_match_ip_address_cmd);
   route_map_install_match (&route_match_ip_address_prefix_list_cmd);
   route_map_install_match (&route_match_interface_cmd);
+  route_map_install_match (&route_match_tag_cmd);
 
   route_map_install_set (&route_set_metric_cmd);
   route_map_install_set (&route_set_metric_type_cmd);
+  route_map_install_set (&route_set_tag_cmd);
 
   install_element (RMAP_NODE, &match_ip_nexthop_cmd);
   install_element (RMAP_NODE, &no_match_ip_nexthop_cmd);
@@ -820,6 +1006,9 @@ ospf_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_metric_cmd);
   install_element (RMAP_NODE, &no_set_metric_cmd);
@@ -827,4 +1016,7 @@ ospf_route_map_init (void)
   install_element (RMAP_NODE, &set_metric_type_cmd);
   install_element (RMAP_NODE, &no_set_metric_type_cmd);
   install_element (RMAP_NODE, &no_set_metric_type_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);
 }
index b6d3260b4f1aa019f324ed5916df6b622c2bc059..94edc28632c7f18af0997d89a4a096ac70a67f02 100644 (file)
@@ -349,6 +349,12 @@ ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or)
       if (distance)
         SET_FLAG (message, ZAPI_MESSAGE_DISTANCE);
 
+      /* Check if path type is ASE and use only 16bit tags */
+      if (((or->path_type == OSPF_PATH_TYPE1_EXTERNAL) ||
+          (or->path_type == OSPF_PATH_TYPE2_EXTERNAL)) &&
+           (or->u.ext.tag > 0) && (or->u.ext.tag < UINT16_MAX))
+        SET_FLAG (message, ZAPI_MESSAGE_TAG);
+
       /* Make packet. */
       s = zclient->obuf;
       stream_reset (s);
@@ -416,6 +422,9 @@ ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or)
             stream_putl (s, or->cost);
         }
 
+      if (CHECK_FLAG (message, ZAPI_MESSAGE_TAG))
+         stream_putw (s, (u_short)or->u.ext.tag);
+
       stream_putw_at (s, 0, stream_get_endp (s));
 
       zclient_send_message(zclient);
@@ -523,6 +532,7 @@ ospf_zebra_add_discard (struct prefix_ipv4 *p)
       SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
       api.nexthop_num = 0;
       api.ifindex_num = 0;
+      api.tag = 0;
 
       zapi_ipv4_route (ZEBRA_IPV4_ROUTE_ADD, zclient, p, &api);
 
@@ -546,6 +556,7 @@ ospf_zebra_delete_discard (struct prefix_ipv4 *p)
       SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
       api.nexthop_num = 0;
       api.ifindex_num = 0;
+      api.tag = 0;
 
       zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient, p, &api);
 
@@ -860,6 +871,10 @@ ospf_zebra_read_ipv4 (int command, struct zclient *zclient,
     api.distance = stream_getc (s);
   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
     api.metric = stream_getl (s);
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG))
+    api.tag = stream_getw (s);
+  else
+    api.tag = 0;
 
   ospf = ospf_lookup ();
   if (ospf == NULL)
@@ -877,8 +892,12 @@ ospf_zebra_read_ipv4 (int command, struct zclient *zclient,
        *     || CHECK_FLAG (api.flags, ZEBRA_FLAG_REJECT))
        * return 0;
        */
-        
-      ei = ospf_external_info_add (api.type, p, ifindex, nexthop);
+
+      /* Protocol tag overwrites all other tag value send by zebra */
+      if (ospf->dtag[api.type] > 0)
+       api.tag = ospf->dtag[api.type];
+
+      ei = ospf_external_info_add (api.type, p, ifindex, nexthop, api.tag);
 
       if (ospf->router_id.s_addr == 0)
         /* Set flags to generate AS-external-LSA originate event
index 4cddca67d21cffb3d456f176e83e13827714a820..272c544bc67fc158f52c516c2350adeb24025441 100644 (file)
@@ -189,6 +189,7 @@ ospf_new (void)
     {
       new->dmetric[i].type = -1;
       new->dmetric[i].value = -1;
+      new->dtag[i] = 0;
     }
   new->default_metric = -1;
   new->ref_bandwidth = OSPF_DEFAULT_REF_BANDWIDTH;
index 9920a6e2ef47218a949f85fd85967de7421e6976..11525a5fb87c3addb01431bf80f7497042460fe5 100644 (file)
@@ -244,6 +244,9 @@ struct ospf
                                   -1 means metric value is not set. */
   } dmetric [ZEBRA_ROUTE_MAX + 1];
 
+  /* Redistribute tag info. */
+  u_short dtag [ZEBRA_ROUTE_MAX + 1];
+
   /* For redistribute route map. */
   struct
   {
index 9bafdcde1d139a6fbd441efa9e3e7af4ed3d9534..cc0ed61fff661f7a7fbdbe93f880c89467a1e8c3 100644 (file)
@@ -485,9 +485,22 @@ 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));
-  *tag = atoi (arg);
+
+  if (!tag)
+    return tag;
+
+  *tag = tmp;
 
   return tag;
 }
@@ -937,7 +950,7 @@ ALIAS (no_match_ip_address_prefix_list,
 
 DEFUN (match_tag, 
        match_tag_cmd,
-       "match tag <0-65535>",
+       "match tag <1-65535>",
        MATCH_STR
        "Match tag of route\n"
        "Metric value\n")
@@ -960,7 +973,7 @@ DEFUN (no_match_tag,
 
 ALIAS (no_match_tag,
        no_match_tag_val_cmd,
-       "no match tag <0-65535>",
+       "no match tag <1-65535>",
        NO_STR
        MATCH_STR
        "Match tag of route\n"
@@ -1060,7 +1073,7 @@ ALIAS (no_set_ip_nexthop,
 
 DEFUN (set_tag,
        set_tag_cmd,
-       "set tag <0-65535>",
+       "set tag <1-65535>",
        SET_STR
        "Tag value for routing protocol\n"
        "Tag value\n")
@@ -1083,7 +1096,7 @@ DEFUN (no_set_tag,
 
 ALIAS (no_set_tag,
        no_set_tag_val_cmd,
-       "no set tag <0-65535>",
+       "no set tag <1-65535>",
        NO_STR
        SET_STR
        "Tag value for routing protocol\n"
index f4fadb67e5dcbfc2240709f3ca07a3d7c5767fb4..a316301ab5af05eaf80437e6d11cc93aa0c580eb 100644 (file)
@@ -564,7 +564,7 @@ ALIAS (no_match_interface,
 
 DEFUN (match_tag,
        match_tag_cmd,
-       "match tag <0-65535>",
+       "match tag <1-65535>",
        MATCH_STR
        "Match tag of route\n"
        "Metric value\n")
@@ -587,7 +587,7 @@ DEFUN (no_match_tag,
 
 ALIAS (no_match_tag,
        no_match_tag_val_cmd,
-       "no match tag <0-65535>",
+       "no match tag <1-65535>",
        NO_STR
        MATCH_STR
        "Match tag of route\n"
@@ -675,7 +675,7 @@ ALIAS (no_set_ipv6_nexthop_local,
 
 DEFUN (set_tag,
        set_tag_cmd,
-       "set tag <0-65535>",
+       "set tag <1-65535>",
        SET_STR
        "Tag value for routing protocol\n"
        "Tag value\n")
@@ -698,7 +698,7 @@ DEFUN (no_set_tag,
 
 ALIAS (no_set_tag,
        no_set_tag_val_cmd,
-       "no set tag <0-65535>",
+       "no set tag <1-65535>",
        NO_STR
        SET_STR
        "Tag value for routing protocol\n"
index 833b892cb5cb3733d350e47b94c07874688be781..c2b28d196705b8382d383790da38d92e7cd71a9f 100644 (file)
@@ -57,6 +57,9 @@ struct rib
   /* Distance. */
   u_char distance;
 
+  /* Tag */
+  u_short tag;
+
   /* Flags of this route.
    * This flag's definition is in lib/zebra.h ZEBRA_FLAG_* and is exposed
    * to clients via Zserv
@@ -165,6 +168,9 @@ struct static_ipv4
   /* Administrative distance. */
   u_char distance;
 
+  /* Tag */
+  u_short tag;
+
   /* Flag for this static route's type. */
   u_char type;
 #define STATIC_IPV4_GATEWAY     1
@@ -197,6 +203,9 @@ struct static_ipv6
   /* Administrative distance. */
   u_char distance;
 
+  /* Tag */
+  u_short tag;
+
   /* Flag for this static route's type. */
   u_char type;
 #define STATIC_IPV6_GATEWAY          1
@@ -393,11 +402,11 @@ extern unsigned long rib_score_proto (u_char proto);
 
 extern int
 static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname,
-       u_char flags, u_char distance, u_int32_t vrf_id);
+                 u_char flags, u_short tag, u_char distance, u_int32_t vrf_id);
 
 extern int
 static_delete_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname,
-                   u_char distance, u_int32_t vrf_id);
+                   u_short tag, u_char distance, u_int32_t vrf_id);
 
 #ifdef HAVE_IPV6
 extern int
@@ -417,8 +426,8 @@ extern struct route_table *rib_table_ipv6;
 
 extern int
 static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
-                const char *ifname, u_char flags, u_char distance,
-                u_int32_t vrf_id);
+                const char *ifname, u_char flags, u_short tag,
+                 u_char distance, u_int32_t vrf_id);
 
 extern int
 rib_add_ipv6_multipath (struct prefix_ipv6 *, struct rib *, safi_t,
@@ -426,7 +435,8 @@ rib_add_ipv6_multipath (struct prefix_ipv6 *, struct rib *, safi_t,
 
 extern int
 static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
-                   const char *ifname, u_char distance, u_int32_t vrf_id);
+                   const char *ifname, u_short tag, u_char distance,
+                    u_int32_t vrf_id);
 
 #endif /* HAVE_IPV6 */
 
index af04adaa49fc8cf9970f4180c40c0785d4cc1465..7caa793f24fd0f736a6c80d7c58a2fa9574c0f52 100644 (file)
@@ -2303,6 +2303,10 @@ static_install_ipv4 (struct prefix *p, struct static_ipv4 *si)
 
   if (rib)
     {
+      /* if tag value changed , update old value in RIB */
+      if (rib->tag != si->tag)
+        rib->tag = si->tag;
+
       /* Same distance static route is there.  Update it with new
          nexthop. */
       route_unlock_node (rn);
@@ -2330,6 +2334,7 @@ static_install_ipv4 (struct prefix *p, struct static_ipv4 *si)
       rib->metric = 0;
       rib->table = zebrad.rtm_table_default;
       rib->nexthop_num = 0;
+      rib->tag = si->tag;
 
       switch (si->type)
         {
@@ -2393,7 +2398,8 @@ static_uninstall_ipv4 (struct prefix *p, struct static_ipv4 *si)
       if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
         continue;
 
-      if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance)
+      if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance &&
+          rib->tag == si->tag)
         break;
     }
 
@@ -2433,7 +2439,7 @@ static_uninstall_ipv4 (struct prefix *p, struct static_ipv4 *si)
 /* Add static route into static route configuration. */
 int
 static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname,
-                u_char flags, u_char distance, u_int32_t vrf_id)
+                u_char flags, u_short tag, u_char distance, u_int32_t vrf_id)
 {
   u_char type = 0;
   struct route_node *rn;
@@ -2466,7 +2472,7 @@ static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname,
          && (! gate || IPV4_ADDR_SAME (gate, &si->gate.ipv4))
          && (! ifname || strcmp (ifname, si->gate.ifname) == 0))
        {
-         if (distance == si->distance)
+         if ((distance == si->distance) && (tag == si->tag))
            {
              route_unlock_node (rn);
              return 0;
@@ -2476,9 +2482,9 @@ static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname,
        }
     }
 
-  /* Distance changed.  */
+  /* Distance or tag changed. */
   if (update)
-    static_delete_ipv4 (p, gate, ifname, update->distance, vrf_id);
+    static_delete_ipv4 (p, gate, ifname, update->tag, update->distance, vrf_id);
 
   /* Make new static route structure. */
   si = XCALLOC (MTYPE_STATIC_IPV4, sizeof (struct static_ipv4));
@@ -2486,6 +2492,7 @@ static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname,
   si->type = type;
   si->distance = distance;
   si->flags = flags;
+  si->tag = tag;
 
   if (gate)
     si->gate.ipv4 = *gate;
@@ -2528,7 +2535,7 @@ static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname,
 /* Delete static route from static route configuration. */
 int
 static_delete_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname,
-                   u_char distance, u_int32_t vrf_id)
+                   u_short tag, u_char distance, u_int32_t vrf_id)
 {
   u_char type = 0;
   struct route_node *rn;
@@ -2557,7 +2564,8 @@ static_delete_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname,
   for (si = rn->info; si; si = si->next)
     if (type == si->type
        && (! gate || IPV4_ADDR_SAME (gate, &si->gate.ipv4))
-       && (! ifname || strcmp (ifname, si->gate.ifname) == 0))
+       && (! ifname || strcmp (ifname, si->gate.ifname) == 0)
+       && (! tag || (tag == si->tag)))
       break;
 
   /* Can't find static route. */
@@ -2972,6 +2980,10 @@ static_install_ipv6 (struct prefix *p, struct static_ipv6 *si)
 
   if (rib)
     {
+      /* if tag value changed , update old value in RIB */
+      if (rib->tag != si->tag)
+        rib->tag = si->tag;
+
       /* Same distance static route is there.  Update it with new
          nexthop. */
       route_unlock_node (rn);
@@ -3000,6 +3012,7 @@ static_install_ipv6 (struct prefix *p, struct static_ipv6 *si)
       rib->metric = 0;
       rib->table = zebrad.rtm_table_default;
       rib->nexthop_num = 0;
+      rib->tag = si->tag;
 
       switch (si->type)
        {
@@ -3064,7 +3077,8 @@ static_uninstall_ipv6 (struct prefix *p, struct static_ipv6 *si)
       if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
         continue;
     
-      if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance)
+      if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance &&
+          rib->tag == si->tag)
         break;
     }
 
@@ -3106,8 +3120,8 @@ static_uninstall_ipv6 (struct prefix *p, struct static_ipv6 *si)
 /* Add static route into static route configuration. */
 int
 static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
-                const char *ifname, u_char flags, u_char distance,
-                u_int32_t vrf_id)
+                const char *ifname, u_char flags, u_short tag,
+                 u_char distance, u_int32_t vrf_id)
 {
   struct route_node *rn;
   struct static_ipv6 *si;
@@ -3136,6 +3150,7 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
     {
       if (distance == si->distance 
          && type == si->type
+         && tag == si->tag
          && (! gate || IPV6_ADDR_SAME (gate, &si->ipv6))
          && (! ifname || strcmp (ifname, si->ifname) == 0))
        {
@@ -3150,6 +3165,7 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
   si->type = type;
   si->distance = distance;
   si->flags = flags;
+  si->tag = tag;
 
   switch (type)
     {
@@ -3194,7 +3210,8 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
 /* Delete static route from static route configuration. */
 int
 static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
-                   const char *ifname, u_char distance, u_int32_t vrf_id)
+                   const char *ifname, u_short tag, u_char distance,
+                    u_int32_t vrf_id)
 {
   struct route_node *rn;
   struct static_ipv6 *si;
@@ -3215,7 +3232,8 @@ static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
     if (distance == si->distance 
        && type == si->type
        && (! gate || IPV6_ADDR_SAME (gate, &si->ipv6))
-       && (! ifname || strcmp (ifname, si->ifname) == 0))
+       && (! ifname || strcmp (ifname, si->ifname) == 0)
+       && (! tag || (tag == si->tag)))
       break;
 
   /* Can't find static route. */
index c8e0d1f6f4eb3a8f433e7328cff1a2f6793f3b3f..6031da87662970ca7e49d2dfd029c3aff380c81d 100644 (file)
@@ -36,7 +36,8 @@
 static int
 zebra_static_ipv4 (struct vty *vty, int add_cmd, const char *dest_str,
                   const char *mask_str, const char *gate_str,
-                  const char *flag_str, const char *distance_str)
+                  const char *flag_str, const char *tag_str,
+                  const char *distance_str)
 {
   int ret;
   u_char distance;
@@ -45,6 +46,7 @@ zebra_static_ipv4 (struct vty *vty, int add_cmd, const char *dest_str,
   struct in_addr mask;
   const char *ifname;
   u_char flag = 0;
+  u_short tag = 0;
   
   ret = str2prefix (dest_str, &p);
   if (ret <= 0)
@@ -74,6 +76,10 @@ zebra_static_ipv4 (struct vty *vty, int add_cmd, const char *dest_str,
   else
     distance = ZEBRA_STATIC_DISTANCE_DEFAULT;
 
+  /* tag */
+  if (tag_str)
+    tag = atoi(tag_str);
+
   /* Null0 static route.  */
   if ((gate_str != NULL) && (strncasecmp (gate_str, "Null0", strlen (gate_str)) == 0))
     {
@@ -83,9 +89,9 @@ zebra_static_ipv4 (struct vty *vty, int add_cmd, const char *dest_str,
           return CMD_WARNING;
         }
       if (add_cmd)
-        static_add_ipv4 (&p, NULL, NULL, ZEBRA_FLAG_BLACKHOLE, distance, 0);
+        static_add_ipv4 (&p, NULL, NULL, ZEBRA_FLAG_BLACKHOLE, tag, distance, 0);
       else
-        static_delete_ipv4 (&p, NULL, NULL, distance, 0);
+        static_delete_ipv4 (&p, NULL, NULL, tag, distance, 0);
       return CMD_SUCCESS;
     }
 
@@ -109,9 +115,9 @@ zebra_static_ipv4 (struct vty *vty, int add_cmd, const char *dest_str,
   if (gate_str == NULL)
   {
     if (add_cmd)
-      static_add_ipv4 (&p, NULL, NULL, flag, distance, 0);
+      static_add_ipv4 (&p, NULL, NULL, flag, tag, distance, 0);
     else
-      static_delete_ipv4 (&p, NULL, NULL, distance, 0);
+      static_delete_ipv4 (&p, NULL, NULL, tag, distance, 0);
 
     return CMD_SUCCESS;
   }
@@ -125,9 +131,9 @@ zebra_static_ipv4 (struct vty *vty, int add_cmd, const char *dest_str,
     ifname = gate_str;
 
   if (add_cmd)
-    static_add_ipv4 (&p, ifname ? NULL : &gate, ifname, flag, distance, 0);
+    static_add_ipv4 (&p, ifname ? NULL : &gate, ifname, flag, tag, distance, 0);
   else
-    static_delete_ipv4 (&p, ifname ? NULL : &gate, ifname, distance, 0);
+    static_delete_ipv4 (&p, ifname ? NULL : &gate, ifname, tag, distance, 0);
 
   return CMD_SUCCESS;
 }
@@ -143,7 +149,22 @@ DEFUN (ip_route,
        "IP gateway interface name\n"
        "Null interface\n")
 {
-  return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL, NULL);
+  return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL, NULL, NULL);
+}
+
+DEFUN (ip_route_tag,
+       ip_route_tag_cmd,
+       "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535>",
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix (e.g. 10.0.0.0/8)\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Null interface\n"
+       "Set tag for this route\n"
+       "Tag value\n")
+{
+  return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL, argv[2], NULL);
 }
 
 DEFUN (ip_route_flags,
@@ -157,7 +178,24 @@ DEFUN (ip_route_flags,
        "Emit an ICMP unreachable when matched\n"
        "Silently discard pkts when matched\n")
 {
-  return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2], NULL);
+  return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2], NULL, NULL);
+}
+
+DEFUN (ip_route_flags_tag,
+       ip_route_flags_tag_cmd,
+       "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535>",
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix (e.g. 10.0.0.0/8)\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Emit an ICMP unreachable when matched\n"
+       "Silently discard pkts when matched\n"
+       "Set tag for this route\n"
+       "Tag value\n")
+
+{
+  return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2], argv[3], NULL);
 }
 
 DEFUN (ip_route_flags2,
@@ -169,7 +207,22 @@ DEFUN (ip_route_flags2,
        "Emit an ICMP unreachable when matched\n"
        "Silently discard pkts when matched\n")
 {
-  return zebra_static_ipv4 (vty, 1, argv[0], NULL, NULL, argv[1], NULL);
+  return zebra_static_ipv4 (vty, 1, argv[0], NULL, NULL, argv[1], NULL, NULL);
+}
+
+DEFUN (ip_route_flags2_tag,
+       ip_route_flags2_tag_cmd,
+       "ip route A.B.C.D/M (reject|blackhole) tag <1-65535>",
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix (e.g. 10.0.0.0/8)\n"
+       "Emit an ICMP unreachable when matched\n"
+       "Silently discard pkts when matched\n"
+       "Set tag for this route\n"
+       "Tag value\n")
+
+{
+  return zebra_static_ipv4 (vty, 1, argv[0], NULL, NULL, argv[1], argv[2], NULL);
 }
 
 /* Mask as A.B.C.D format.  */
@@ -184,7 +237,24 @@ DEFUN (ip_route_mask,
        "IP gateway interface name\n"
        "Null interface\n")
 {
-  return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL, NULL);
+  return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL, NULL, NULL);
+}
+
+DEFUN (ip_route_mask_tag,
+       ip_route_mask_tag_cmd,
+       "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535>",
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix\n"
+       "IP destination prefix mask\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Null interface\n"
+       "Set tag for this route\n"
+       "Tag value\n")
+
+{
+  return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], NULL);
 }
 
 DEFUN (ip_route_mask_flags,
@@ -199,7 +269,25 @@ DEFUN (ip_route_mask_flags,
        "Emit an ICMP unreachable when matched\n"
        "Silently discard pkts when matched\n")
 {
-  return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL);
+  return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL, NULL);
+}
+
+DEFUN (ip_route_mask_flags_tag,
+       ip_route_mask_flags_tag_cmd,
+       "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535>",
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix\n"
+       "IP destination prefix mask\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Emit an ICMP unreachable when matched\n"
+       "Silently discard pkts when matched\n"
+       "Set tag for this route\n"
+       "Tag value\n")
+
+{
+  return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], NULL);
 }
 
 DEFUN (ip_route_mask_flags2,
@@ -212,7 +300,22 @@ DEFUN (ip_route_mask_flags2,
        "Emit an ICMP unreachable when matched\n"
        "Silently discard pkts when matched\n")
 {
-  return zebra_static_ipv4 (vty, 1, argv[0], argv[1], NULL, argv[2], NULL);
+  return zebra_static_ipv4 (vty, 1, argv[0], argv[1], NULL, argv[2], NULL, NULL);
+}
+
+DEFUN (ip_route_mask_flags2_tag,
+       ip_route_mask_flags2_tag_cmd,
+       "ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535>",
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix\n"
+       "IP destination prefix mask\n"
+       "Emit an ICMP unreachable when matched\n"
+       "Silently discard pkts when matched\n"
+       "Set tag for this route\n"
+       "Tag value\n")
+{
+  return zebra_static_ipv4 (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], NULL);
 }
 
 /* Distance option value.  */
@@ -227,7 +330,24 @@ DEFUN (ip_route_distance,
        "Null interface\n"
        "Distance value for this route\n")
 {
-  return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL, argv[2]);
+  return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL, NULL, argv[2]);
+}
+
+DEFUN (ip_route_tag_distance,
+       ip_route_tag_distance_cmd,
+       "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>",
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix (e.g. 10.0.0.0/8)\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Null interface\n"
+       "Set tag for this route\n"
+       "Tag value\n"
+       "Distance value for this route\n")
+
+{
+  return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL, argv[2], argv[3]);
 }
 
 DEFUN (ip_route_flags_distance,
@@ -242,7 +362,24 @@ DEFUN (ip_route_flags_distance,
        "Silently discard pkts when matched\n"
        "Distance value for this route\n")
 {
-  return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2], argv[3]);
+  return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2], NULL, argv[3]);
+}
+
+DEFUN (ip_route_flags_tag_distance,
+       ip_route_flags_tag_distance_cmd,
+       "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>",
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix (e.g. 10.0.0.0/8)\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Emit an ICMP unreachable when matched\n"
+       "Silently discard pkts when matched\n"
+       "Set tag for this route\n"
+       "Tag value\n"
+       "Distance value for this route\n")
+{
+  return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2], argv[3], argv[4]);
 }
 
 DEFUN (ip_route_flags_distance2,
@@ -255,7 +392,22 @@ DEFUN (ip_route_flags_distance2,
        "Silently discard pkts when matched\n"
        "Distance value for this route\n")
 {
-  return zebra_static_ipv4 (vty, 1, argv[0], NULL, NULL, argv[1], argv[2]);
+  return zebra_static_ipv4 (vty, 1, argv[0], NULL, NULL, argv[1], NULL, argv[2]);
+}
+
+DEFUN (ip_route_flags_tag_distance2,
+       ip_route_flags_tag_distance2_cmd,
+       "ip route A.B.C.D/M (reject|blackhole) tag <1-65535> <1-255>",
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix (e.g. 10.0.0.0/8)\n"
+       "Emit an ICMP unreachable when matched\n"
+       "Silently discard pkts when matched\n"
+       "Set tag for this route\n"
+       "Tag value\n"
+       "Distance value for this route\n")
+{
+  return zebra_static_ipv4 (vty, 1, argv[0], NULL, NULL, argv[1], argv[2], argv[3]);
 }
 
 DEFUN (ip_route_mask_distance,
@@ -270,9 +422,45 @@ DEFUN (ip_route_mask_distance,
        "Null interface\n"
        "Distance value for this route\n")
 {
-  return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3]);
+  return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL, NULL, argv[3]);
 }
 
+DEFUN (ip_route_mask_tag_distance,
+       ip_route_mask_tag_distance_cmd,
+       "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>",
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix\n"
+       "IP destination prefix mask\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Null interface\n"
+       "Set tag for this route\n"
+       "Tag value\n"
+       "Distance value for this route\n")
+{
+  return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], argv[4]);
+}
+
+DEFUN (ip_route_mask_flags_tag_distance,
+       ip_route_mask_flags_tag_distance_cmd,
+       "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole)  tag <1-65535> <1-255>",
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix\n"
+       "IP destination prefix mask\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Set tag for this route\n"
+       "Tag value\n"
+       "Distance value for this route\n"
+       "Emit an ICMP unreachable when matched\n"
+       "Silently discard pkts when matched\n")
+{
+  return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
+}
+
+
 DEFUN (ip_route_mask_flags_distance,
        ip_route_mask_flags_distance_cmd,
        "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) <1-255>",
@@ -286,7 +474,7 @@ DEFUN (ip_route_mask_flags_distance,
        "Silently discard pkts when matched\n"
        "Distance value for this route\n")
 {
-  return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4]);
+  return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL, argv[4]);
 }
 
 DEFUN (ip_route_mask_flags_distance2,
@@ -300,7 +488,23 @@ DEFUN (ip_route_mask_flags_distance2,
        "Silently discard pkts when matched\n"
        "Distance value for this route\n")
 {
-  return zebra_static_ipv4 (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3]);
+  return zebra_static_ipv4 (vty, 1, argv[0], argv[1], NULL, argv[2], NULL, argv[3]);
+}
+
+DEFUN (ip_route_mask_flags_tag_distance2,
+       ip_route_mask_flags_tag_distance2_cmd,
+       "ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535> <1-255>",
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix\n"
+       "IP destination prefix mask\n"
+       "Set tag for this route\n"
+       "Tag value\n"
+       "Distance value for this route\n"
+       "Emit an ICMP unreachable when matched\n"
+       "Silently discard pkts when matched\n")
+{
+  return zebra_static_ipv4 (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], argv[4]);
 }
 
 DEFUN (no_ip_route, 
@@ -314,7 +518,23 @@ DEFUN (no_ip_route,
        "IP gateway interface name\n"
        "Null interface\n")
 {
-  return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL, NULL);
+  return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL, NULL, NULL);
+}
+
+DEFUN (no_ip_route_tag,
+       no_ip_route_tag_cmd,
+       "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535>",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix (e.g. 10.0.0.0/8)\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Null interface\n"
+       "Tag of this route\n"
+       "Tag value\n")
+{
+  return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL, argv[2], NULL);
 }
 
 ALIAS (no_ip_route,
@@ -329,6 +549,20 @@ ALIAS (no_ip_route,
        "Emit an ICMP unreachable when matched\n"
        "Silently discard pkts when matched\n")
 
+ALIAS (no_ip_route_tag,
+       no_ip_route_flags_tag_cmd,
+       "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535>",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix (e.g. 10.0.0.0/8)\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Emit an ICMP unreachable when matched\n"
+       "Silently discard pkts when matched\n"
+       "Tag of this route\n"
+       "Tag value\n")
+
 DEFUN (no_ip_route_flags2,
        no_ip_route_flags2_cmd,
        "no ip route A.B.C.D/M (reject|blackhole)",
@@ -339,7 +573,22 @@ DEFUN (no_ip_route_flags2,
        "Emit an ICMP unreachable when matched\n"
        "Silently discard pkts when matched\n")
 {
-  return zebra_static_ipv4 (vty, 0, argv[0], NULL, NULL, NULL, NULL);
+  return zebra_static_ipv4 (vty, 0, argv[0], NULL, NULL, NULL, NULL, NULL);
+}
+
+DEFUN (no_ip_route_flags2_tag,
+       no_ip_route_flags2_tag_cmd,
+       "no ip route A.B.C.D/M (reject|blackhole) tag <1-65535>",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix (e.g. 10.0.0.0/8)\n"
+       "Emit an ICMP unreachable when matched\n"
+       "Silently discard pkts when matched\n"
+       "Tag of this route\n"
+       "Tag value\n")
+{
+  return zebra_static_ipv4 (vty, 0, argv[0], NULL, NULL, NULL, argv[1], NULL);
 }
 
 DEFUN (no_ip_route_mask,
@@ -354,7 +603,24 @@ DEFUN (no_ip_route_mask,
        "IP gateway interface name\n"
        "Null interface\n")
 {
-  return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL, NULL);
+  return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL, NULL, NULL);
+}
+
+DEFUN (no_ip_route_mask_tag,
+       no_ip_route_mask_tag_cmd,
+       "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535>",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix\n"
+       "IP destination prefix mask\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Null interface\n"
+       "Tag of this route\n"
+       "Tag value\n")
+{
+  return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], NULL);
 }
 
 ALIAS (no_ip_route_mask,
@@ -370,6 +636,21 @@ ALIAS (no_ip_route_mask,
        "Emit an ICMP unreachable when matched\n"
        "Silently discard pkts when matched\n")
 
+ALIAS (no_ip_route_mask_tag,
+       no_ip_route_mask_flags_tag_cmd,
+       "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535>",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix\n"
+       "IP destination prefix mask\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Emit an ICMP unreachable when matched\n"
+       "Silently discard pkts when matched\n"
+       "Tag of this route\n"
+       "Tag value\n")
+
 DEFUN (no_ip_route_mask_flags2,
        no_ip_route_mask_flags2_cmd,
        "no ip route A.B.C.D A.B.C.D (reject|blackhole)",
@@ -381,9 +662,26 @@ DEFUN (no_ip_route_mask_flags2,
        "Emit an ICMP unreachable when matched\n"
        "Silently discard pkts when matched\n")
 {
-  return zebra_static_ipv4 (vty, 0, argv[0], argv[1], NULL, NULL, NULL);
+  return zebra_static_ipv4 (vty, 0, argv[0], argv[1], NULL, NULL, NULL, NULL);
+}
+
+DEFUN (no_ip_route_mask_flags2_tag,
+       no_ip_route_mask_flags2_tag_cmd,
+       "no ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535>",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix\n"
+       "IP destination prefix mask\n"
+       "Emit an ICMP unreachable when matched\n"
+       "Silently discard pkts when matched\n"
+       "Tag of this route\n"
+       "Tag value\n")
+{
+  return zebra_static_ipv4 (vty, 0, argv[0], argv[1], NULL, NULL, argv[2], NULL);
 }
 
+
 DEFUN (no_ip_route_distance,
        no_ip_route_distance_cmd,
        "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) <1-255>",
@@ -396,7 +694,24 @@ DEFUN (no_ip_route_distance,
        "Null interface\n"
        "Distance value for this route\n")
 {
-  return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL, argv[2]);
+  return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL, NULL, argv[2]);
+}
+
+DEFUN (no_ip_route_tag_distance,
+       no_ip_route_tag_distance_cmd,
+       "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix (e.g. 10.0.0.0/8)\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Null interface\n"
+       "Tag of this route\n"
+       "Tag value\n"
+       "Distance value for this route\n")
+{
+  return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL, argv[2], argv[3]);
 }
 
 DEFUN (no_ip_route_flags_distance,
@@ -412,7 +727,25 @@ DEFUN (no_ip_route_flags_distance,
        "Silently discard pkts when matched\n"
        "Distance value for this route\n")
 {
-  return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], argv[2], argv[3]);
+  return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], argv[2], NULL, argv[3]);
+}
+
+DEFUN (no_ip_route_flags_tag_distance,
+       no_ip_route_flags_tag_distance_cmd,
+       "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix (e.g. 10.0.0.0/8)\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Emit an ICMP unreachable when matched\n"
+       "Silently discard pkts when matched\n"
+       "Tag of this route\n"
+       "Tag value\n"
+       "Distance value for this route\n")
+{
+  return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], argv[2], argv[3], argv[4]);
 }
 
 DEFUN (no_ip_route_flags_distance2,
@@ -426,7 +759,23 @@ DEFUN (no_ip_route_flags_distance2,
        "Silently discard pkts when matched\n"
        "Distance value for this route\n")
 {
-  return zebra_static_ipv4 (vty, 0, argv[0], NULL, NULL, argv[1], argv[2]);
+  return zebra_static_ipv4 (vty, 0, argv[0], NULL, NULL, argv[1], NULL, argv[2]);
+}
+
+DEFUN (no_ip_route_flags_tag_distance2,
+       no_ip_route_flags_tag_distance2_cmd,
+       "no ip route A.B.C.D/M (reject|blackhole) tag <1-65535> <1-255>",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix (e.g. 10.0.0.0/8)\n"
+       "Emit an ICMP unreachable when matched\n"
+       "Silently discard pkts when matched\n"
+       "Tag of this route\n"
+       "Tag value\n"
+       "Distance value for this route\n")
+{
+  return zebra_static_ipv4 (vty, 0, argv[0], NULL, NULL, argv[1], argv[2] , argv[3]);
 }
 
 DEFUN (no_ip_route_mask_distance,
@@ -442,7 +791,25 @@ DEFUN (no_ip_route_mask_distance,
        "Null interface\n"
        "Distance value for this route\n")
 {
-  return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3]);
+  return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL, NULL, argv[3]);
+}
+
+DEFUN (no_ip_route_mask_tag_distance,
+       no_ip_route_mask_tag_distance_cmd,
+       "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) tag <1-65535> <1-255>",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix\n"
+       "IP destination prefix mask\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Null interface\n"
+       "Tag of this route\n"
+       "Tag value\n"
+       "Distance value for this route\n")
+{
+  return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], argv[4]);
 }
 
 DEFUN (no_ip_route_mask_flags_distance,
@@ -459,7 +826,26 @@ DEFUN (no_ip_route_mask_flags_distance,
        "Silently discard pkts when matched\n"
        "Distance value for this route\n")
 {
-  return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4]);
+  return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], argv[3], NULL, argv[4]);
+}
+
+DEFUN (no_ip_route_mask_flags_tag_distance,
+       no_ip_route_mask_flags_tag_distance_cmd,
+       "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix\n"
+       "IP destination prefix mask\n"
+       "IP gateway address\n"
+       "IP gateway interface name\n"
+       "Emit an ICMP unreachable when matched\n"
+       "Silently discard pkts when matched\n"
+       "Tag of this route\n"
+       "Tag value\n"
+       "Distance value for this route\n")
+{
+  return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
 }
 
 DEFUN (no_ip_route_mask_flags_distance2,
@@ -474,7 +860,24 @@ DEFUN (no_ip_route_mask_flags_distance2,
        "Silently discard pkts when matched\n"
        "Distance value for this route\n")
 {
-  return zebra_static_ipv4 (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3]);
+  return zebra_static_ipv4 (vty, 0, argv[0], argv[1], NULL, argv[2], NULL, argv[3]);
+}
+
+DEFUN (no_ip_route_mask_flags_tag_distance2,
+       no_ip_route_mask_flags_tag_distance2_cmd,
+       "no ip route A.B.C.D A.B.C.D (reject|blackhole) tag <1-65535> <1-255>",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IP destination prefix\n"
+       "IP destination prefix mask\n"
+       "Emit an ICMP unreachable when matched\n"
+       "Silently discard pkts when matched\n"
+       "Tag of this route\n"
+       "Tag value\n"
+       "Distance value for this route\n")
+{
+  return zebra_static_ipv4 (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3], argv[4]);
 }
 
 /* New RIB.  Detailed information for IPv4 route. */
@@ -492,6 +895,8 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn)
               VTY_NEWLINE);
       vty_out (vty, "  Known via \"%s\"", zebra_route_string (rib->type));
       vty_out (vty, ", distance %u, metric %u", rib->distance, rib->metric);
+      if (rib->tag)
+       vty_out (vty, ", tag %d", rib->tag);
       if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
        vty_out (vty, ", best");
       if (rib->refcnt)
@@ -782,6 +1187,46 @@ DEFUN (show_ipv6_nht,
   return CMD_SUCCESS;
 }
 
+DEFUN (show_ip_route_tag,
+       show_ip_route_tag_cmd,
+       "show ip route tag <1-65535>",
+       SHOW_STR
+       IP_STR
+       "IP routing table\n"
+       "Show only routes with tag\n"
+       "Tag value\n")
+{
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *rib;
+  int first = 1;
+  u_short tag = 0;
+
+  if (argv[0])
+    tag = atoi(argv[0]);
+
+  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  if (! table)
+    return CMD_SUCCESS;
+
+  /* Show all IPv4 routes with matching tag value. */
+  for (rn = route_top (table); rn; rn = route_next (rn))
+    RNODE_FOREACH_RIB (rn, rib)
+      {
+        if (rib->tag != tag)
+          continue;
+
+        if (first)
+          {
+            vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE, VTY_NEWLINE,
+                     VTY_NEWLINE);
+            first = 0;
+          }
+        vty_show_ip_route (vty, rn, rib);
+      }
+  return CMD_SUCCESS;
+}
+
 DEFUN (show_ip_route_prefix_longer,
        show_ip_route_prefix_longer_cmd,
        "show ip route A.B.C.D/M longer-prefixes",
@@ -1207,6 +1652,9 @@ static_config_ipv4 (struct vty *vty)
               vty_out (vty, " %s", "blackhole");
           }
 
+        if (si->tag)
+          vty_out (vty, " tag %d", si->tag);
+
         if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT)
           vty_out (vty, " %d", si->distance);
 
@@ -1257,7 +1705,8 @@ DEFUN (show_ip_mroute,
 static int
 static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str,
                  const char *gate_str, const char *ifname,
-                 const char *flag_str, const char *distance_str)
+                 const char *flag_str, const char *tag_str,
+                  const char *distance_str)
 {
   int ret;
   u_char distance;
@@ -1267,6 +1716,7 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str,
   u_char type = 0;
   int table = 0;
   u_char flag = 0;
+  u_short tag = 0;
   
   ret = str2prefix (dest_str, &p);
   if (ret <= 0)
@@ -1301,6 +1751,10 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str,
   else
     distance = ZEBRA_STATIC_DISTANCE_DEFAULT;
 
+  /* tag */
+  if (tag_str)
+    tag = atoi(tag_str);
+
   /* When gateway is valid IPv6 addrees, then gate is treated as
      nexthop address other case gate is treated as interface name. */
   ret = inet_pton (AF_INET6, gate_str, &gate_addr);
@@ -1332,9 +1786,9 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str,
     }
 
   if (add_cmd)
-    static_add_ipv6 (&p, type, gate, ifname, flag, distance, table);
+    static_add_ipv6 (&p, type, gate, ifname, flag, tag, distance, table);
   else
-    static_delete_ipv6 (&p, type, gate, ifname, distance, table);
+    static_delete_ipv6 (&p, type, gate, ifname, tag, distance, table);
 
   return CMD_SUCCESS;
 }
@@ -1348,7 +1802,21 @@ DEFUN (ipv6_route,
        "IPv6 gateway address\n"
        "IPv6 gateway interface name\n")
 {
-  return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, NULL);
+  return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, NULL, NULL);
+}
+
+DEFUN (ipv6_route_tag,
+       ipv6_route_tag_cmd,
+       "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535>",
+       IP_STR
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n"
+       "Set tag for this route\n"
+       "Tag value\n")
+{
+  return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, argv[2], NULL);
 }
 
 DEFUN (ipv6_route_flags,
@@ -1362,7 +1830,23 @@ DEFUN (ipv6_route_flags,
        "Emit an ICMP unreachable when matched\n"
        "Silently discard pkts when matched\n")
 {
-  return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], NULL);
+  return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], NULL, NULL);
+}
+
+DEFUN (ipv6_route_flags_tag,
+       ipv6_route_flags_tag_cmd,
+       "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535>",
+       IP_STR
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n"
+       "Emit an ICMP unreachable when matched\n"
+       "Silently discard pkts when matched\n"
+       "Set tag for this route\n"
+       "Tag value\n")
+{
+  return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], NULL);
 }
 
 DEFUN (ipv6_route_ifname,
@@ -1374,7 +1858,20 @@ DEFUN (ipv6_route_ifname,
        "IPv6 gateway address\n"
        "IPv6 gateway interface name\n")
 {
-  return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, NULL);
+  return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, NULL, NULL);
+}
+DEFUN (ipv6_route_ifname_tag,
+       ipv6_route_ifname_tag_cmd,
+       "ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535>",
+       IP_STR
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n"
+       "Set tag for this route\n"
+       "Tag value\n")
+{
+  return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], NULL);
 }
 
 DEFUN (ipv6_route_ifname_flags,
@@ -1388,7 +1885,23 @@ DEFUN (ipv6_route_ifname_flags,
        "Emit an ICMP unreachable when matched\n"
        "Silently discard pkts when matched\n")
 {
-  return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL);
+  return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL, NULL);
+}
+
+DEFUN (ipv6_route_ifname_flags_tag,
+       ipv6_route_ifname_flags_tag_cmd,
+       "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535>",
+       IP_STR
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n"
+       "Emit an ICMP unreachable when matched\n"
+       "Silently discard pkts when matched\n"
+       "Set tag for this route\n"
+       "Tag value\n")
+{
+  return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], NULL);
 }
 
 DEFUN (ipv6_route_pref,
@@ -1401,7 +1914,22 @@ DEFUN (ipv6_route_pref,
        "IPv6 gateway interface name\n"
        "Distance value for this prefix\n")
 {
-  return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, argv[2]);
+  return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, NULL, argv[2]);
+}
+
+DEFUN (ipv6_route_pref_tag,
+       ipv6_route_pref_tag_cmd,
+       "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535> <1-255>",
+       IP_STR
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n"
+       "Set tag for this route\n"
+       "Tag value\n"
+       "Distance value for this prefix\n")
+{
+  return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, argv[2], argv[3]);
 }
 
 DEFUN (ipv6_route_flags_pref,
@@ -1416,7 +1944,24 @@ DEFUN (ipv6_route_flags_pref,
        "Silently discard pkts when matched\n"
        "Distance value for this prefix\n")
 {
-  return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3]);
+  return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], NULL, argv[3]);
+}
+
+DEFUN (ipv6_route_flags_pref_tag,
+       ipv6_route_flags_pref_tag_cmd,
+       "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>",
+       IP_STR
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n"
+       "Emit an ICMP unreachable when matched\n"
+       "Silently discard pkts when matched\n"
+       "Set tag for this route\n"
+       "Tag value\n"
+       "Distance value for this prefix\n")
+{
+  return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3], argv[4]);
 }
 
 DEFUN (ipv6_route_ifname_pref,
@@ -1429,7 +1974,22 @@ DEFUN (ipv6_route_ifname_pref,
        "IPv6 gateway interface name\n"
        "Distance value for this prefix\n")
 {
-  return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3]);
+  return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, NULL, argv[3]);
+}
+
+DEFUN (ipv6_route_ifname_pref_tag,
+       ipv6_route_ifname_pref_tag_cmd,
+       "ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535> <1-255>",
+       IP_STR
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n"
+       "Set tag for this route\n"
+       "Tag value\n"
+       "Distance value for this prefix\n")
+{
+  return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3], argv[4]);
 }
 
 DEFUN (ipv6_route_ifname_flags_pref,
@@ -1444,7 +2004,24 @@ DEFUN (ipv6_route_ifname_flags_pref,
        "Silently discard pkts when matched\n"
        "Distance value for this prefix\n")
 {
-  return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4]);
+  return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL, argv[4]);
+}
+
+DEFUN (ipv6_route_ifname_flags_pref_tag,
+       ipv6_route_ifname_flags_pref_tag_cmd,
+       "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535> <1-255>",
+       IP_STR
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n"
+       "Emit an ICMP unreachable when matched\n"
+       "Silently discard pkts when matched\n"
+       "Set tag for this route\n"
+       "Tag value\n"
+       "Distance value for this prefix\n")
+{
+  return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
 }
 
 DEFUN (no_ipv6_route,
@@ -1457,7 +2034,22 @@ DEFUN (no_ipv6_route,
        "IPv6 gateway address\n"
        "IPv6 gateway interface name\n")
 {
-  return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, NULL);
+  return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, NULL, NULL);
+}
+
+DEFUN (no_ipv6_route_tag,
+       no_ipv6_route_tag_cmd,
+       "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535>",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n"
+       "Set tag for this route\n"
+       "Tag value\n")
+{
+  return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, argv[2], NULL);
 }
 
 ALIAS (no_ipv6_route,
@@ -1472,6 +2064,20 @@ ALIAS (no_ipv6_route,
        "Emit an ICMP unreachable when matched\n"
        "Silently discard pkts when matched\n")
 
+ALIAS (no_ipv6_route_tag,
+       no_ipv6_route_flags_tag_cmd,
+       "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535>",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n"
+       "Emit an ICMP unreachable when matched\n"
+       "Silently discard pkts when matched\n"
+       "Set tag for this route\n"
+       "Tag value\n")
+
 DEFUN (no_ipv6_route_ifname,
        no_ipv6_route_ifname_cmd,
        "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE",
@@ -1482,7 +2088,22 @@ DEFUN (no_ipv6_route_ifname,
        "IPv6 gateway address\n"
        "IPv6 gateway interface name\n")
 {
-  return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, NULL);
+  return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, NULL, NULL);
+}
+
+DEFUN (no_ipv6_route_ifname_tag,
+       no_ipv6_route_ifname_tag_cmd,
+       "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535>",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n"
+       "Set tag for this route\n"
+       "Tag value\n")
+{
+  return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], NULL);
 }
 
 ALIAS (no_ipv6_route_ifname,
@@ -1497,6 +2118,20 @@ ALIAS (no_ipv6_route_ifname,
        "Emit an ICMP unreachable when matched\n"
        "Silently discard pkts when matched\n")
 
+ALIAS (no_ipv6_route_ifname_tag,
+       no_ipv6_route_ifname_flags_tag_cmd,
+       "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535>",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n"
+       "Emit an ICMP unreachable when matched\n"
+       "Silently discard pkts when matched\n"
+       "Set tag for this route\n"
+       "Tag value\n")
+
 DEFUN (no_ipv6_route_pref,
        no_ipv6_route_pref_cmd,
        "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) <1-255>",
@@ -1508,7 +2143,23 @@ DEFUN (no_ipv6_route_pref,
        "IPv6 gateway interface name\n"
        "Distance value for this prefix\n")
 {
-  return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, argv[2]);
+  return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, NULL, argv[2]);
+}
+
+DEFUN (no_ipv6_route_pref_tag,
+       no_ipv6_route_pref_tag_cmd,
+       "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) tag <1-65535> <1-255>",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n"
+       "Set tag for this route\n"
+       "Tag value\n"
+       "Distance value for this prefix\n")
+{
+  return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, argv[2], argv[3]);
 }
 
 DEFUN (no_ipv6_route_flags_pref,
@@ -1525,7 +2176,26 @@ DEFUN (no_ipv6_route_flags_pref,
        "Distance value for this prefix\n")
 {
   /* We do not care about argv[2] */
-  return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3]);
+  return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2], NULL, argv[3]);
+}
+
+DEFUN (no_ipv6_route_flags_pref_tag,
+       no_ipv6_route_flags_pref_tag_cmd,
+       "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) tag <1-65535> <1-255>",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n"
+       "Emit an ICMP unreachable when matched\n"
+       "Silently discard pkts when matched\n"
+       "Set tag for this route\n"
+       "Tag value\n"
+       "Distance value for this prefix\n")
+{
+  /* We do not care about argv[2] */
+  return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3], argv[4]);
 }
 
 DEFUN (no_ipv6_route_ifname_pref,
@@ -1539,7 +2209,23 @@ DEFUN (no_ipv6_route_ifname_pref,
        "IPv6 gateway interface name\n"
        "Distance value for this prefix\n")
 {
-  return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3]);
+  return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, NULL, argv[3]);
+}
+
+DEFUN (no_ipv6_route_ifname_pref_tag,
+       no_ipv6_route_ifname_pref_tag_cmd,
+       "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE tag <1-65535> <1-255>",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n"
+       "Set tag for this route\n"
+       "Tag value\n"
+       "Distance value for this prefix\n")
+{
+  return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3], argv[4]);
 }
 
 DEFUN (no_ipv6_route_ifname_flags_pref,
@@ -1555,7 +2241,25 @@ DEFUN (no_ipv6_route_ifname_flags_pref,
        "Silently discard pkts when matched\n"
        "Distance value for this prefix\n")
 {
-  return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4]);
+  return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3], NULL, argv[4]);
+}
+
+DEFUN (no_ipv6_route_ifname_flags_pref_tag,
+       no_ipv6_route_ifname_flags_pref_tag_cmd,
+       "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) tag <1-65535> <1-255>",
+       NO_STR
+       IP_STR
+       "Establish static routes\n"
+       "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+       "IPv6 gateway address\n"
+       "IPv6 gateway interface name\n"
+       "Emit an ICMP unreachable when matched\n"
+       "Silently discard pkts when matched\n"
+       "Set tag for this route\n"
+       "Tag value\n"
+       "Distance value for this prefix\n")
+{
+  return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
 }
 
 /* New RIB.  Detailed information for IPv6 route. */
@@ -1575,6 +2279,8 @@ vty_show_ipv6_route_detail (struct vty *vty, struct route_node *rn)
               VTY_NEWLINE);
       vty_out (vty, "  Known via \"%s\"", zebra_route_string (rib->type));
       vty_out (vty, ", distance %u, metric %u", rib->distance, rib->metric);
+      if (rib->tag)
+       vty_out (vty, ", tag %d", rib->tag);
       if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
        vty_out (vty, ", best");
       if (rib->refcnt)
@@ -1790,6 +2496,45 @@ DEFUN (show_ipv6_route,
   return CMD_SUCCESS;
 }
 
+DEFUN (show_ipv6_route_tag,
+       show_ipv6_route_tag_cmd,
+       "show ipv6 route tag <1-65535>",
+       SHOW_STR
+       IP_STR
+       "IPv6 routing table\n"
+       "Show only routes with tag\n"
+       "Tag value\n")
+{
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *rib;
+  int first = 1;
+  u_short tag = 0;
+
+  if (argv[0])
+    tag = atoi(argv[0]);
+
+  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  if (! table)
+    return CMD_SUCCESS;
+
+  /* Show all IPv6 routes with matching tag value. */
+  for (rn = route_top (table); rn; rn = route_next (rn))
+    RNODE_FOREACH_RIB (rn, rib)
+      {
+        if (rib->tag != tag)
+          continue;
+
+       if (first)
+         {
+           vty_out (vty, SHOW_ROUTE_V6_HEADER);
+           first = 0;
+         }
+       vty_show_ipv6_route (vty, rn, rib);
+      }
+  return CMD_SUCCESS;
+}
+
 DEFUN (show_ipv6_route_prefix_longer,
        show_ipv6_route_prefix_longer_cmd,
        "show ipv6 route X:X::X:X/M longer-prefixes",
@@ -2068,6 +2813,9 @@ static_config_ipv6 (struct vty *vty)
        if (CHECK_FLAG(si->flags, ZEBRA_FLAG_BLACKHOLE))
                vty_out (vty, " %s", "blackhole");
 
+        if (si->tag)
+          vty_out (vty, " tag %d", si->tag);
+
        if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT)
          vty_out (vty, " %d", si->distance);
        vty_out (vty, "%s", VTY_NEWLINE);
@@ -2102,30 +2850,56 @@ zebra_vty_init (void)
   install_node (&ip_node, zebra_ip_config);
 
   install_element (CONFIG_NODE, &ip_route_cmd);
+  install_element (CONFIG_NODE, &ip_route_tag_cmd);
   install_element (CONFIG_NODE, &ip_route_flags_cmd);
+  install_element (CONFIG_NODE, &ip_route_flags_tag_cmd);
   install_element (CONFIG_NODE, &ip_route_flags2_cmd);
+  install_element (CONFIG_NODE, &ip_route_flags2_tag_cmd);
   install_element (CONFIG_NODE, &ip_route_mask_cmd);
+  install_element (CONFIG_NODE, &ip_route_mask_tag_cmd);
   install_element (CONFIG_NODE, &ip_route_mask_flags_cmd);
+  install_element (CONFIG_NODE, &ip_route_mask_flags_tag_cmd);
   install_element (CONFIG_NODE, &ip_route_mask_flags2_cmd);
+  install_element (CONFIG_NODE, &ip_route_mask_flags2_tag_cmd);
   install_element (CONFIG_NODE, &no_ip_route_cmd);
+  install_element (CONFIG_NODE, &no_ip_route_tag_cmd);
   install_element (CONFIG_NODE, &no_ip_route_flags_cmd);
+  install_element (CONFIG_NODE, &no_ip_route_flags_tag_cmd);
   install_element (CONFIG_NODE, &no_ip_route_flags2_cmd);
+  install_element (CONFIG_NODE, &no_ip_route_flags2_tag_cmd);
   install_element (CONFIG_NODE, &no_ip_route_mask_cmd);
+  install_element (CONFIG_NODE, &no_ip_route_mask_tag_cmd);
   install_element (CONFIG_NODE, &no_ip_route_mask_flags_cmd);
+  install_element (CONFIG_NODE, &no_ip_route_mask_flags_tag_cmd);
   install_element (CONFIG_NODE, &no_ip_route_mask_flags2_cmd);
+  install_element (CONFIG_NODE, &no_ip_route_mask_flags2_tag_cmd);
   install_element (CONFIG_NODE, &ip_route_distance_cmd);
+  install_element (CONFIG_NODE, &ip_route_tag_distance_cmd);
   install_element (CONFIG_NODE, &ip_route_flags_distance_cmd);
+  install_element (CONFIG_NODE, &ip_route_flags_tag_distance_cmd);
   install_element (CONFIG_NODE, &ip_route_flags_distance2_cmd);
+  install_element (CONFIG_NODE, &ip_route_flags_tag_distance2_cmd);
   install_element (CONFIG_NODE, &ip_route_mask_distance_cmd);
+  install_element (CONFIG_NODE, &ip_route_mask_tag_distance_cmd);
   install_element (CONFIG_NODE, &ip_route_mask_flags_distance_cmd);
+  install_element (CONFIG_NODE, &ip_route_mask_flags_tag_distance_cmd);
   install_element (CONFIG_NODE, &ip_route_mask_flags_distance2_cmd);
+  install_element (CONFIG_NODE, &ip_route_mask_flags_tag_distance2_cmd);
   install_element (CONFIG_NODE, &no_ip_route_distance_cmd);
+  install_element (CONFIG_NODE, &no_ip_route_tag_distance_cmd);
   install_element (CONFIG_NODE, &no_ip_route_flags_distance_cmd);
+  install_element (CONFIG_NODE, &no_ip_route_flags_tag_distance_cmd);
   install_element (CONFIG_NODE, &no_ip_route_flags_distance2_cmd);
+  install_element (CONFIG_NODE, &no_ip_route_flags_tag_distance2_cmd);
+  install_element (CONFIG_NODE, &no_ip_route_mask_distance_cmd);
+  install_element (CONFIG_NODE, &no_ip_route_mask_tag_distance_cmd);
   install_element (CONFIG_NODE, &no_ip_route_mask_flags_distance_cmd);
+  install_element (CONFIG_NODE, &no_ip_route_mask_flags_tag_distance_cmd);
   install_element (CONFIG_NODE, &no_ip_route_mask_flags_distance2_cmd);
+  install_element (CONFIG_NODE, &no_ip_route_mask_flags_tag_distance2_cmd);
 
   install_element (VIEW_NODE, &show_ip_route_cmd);
+  install_element (VIEW_NODE, &show_ip_route_tag_cmd);
   install_element (VIEW_NODE, &show_ip_nht_cmd);
   install_element (VIEW_NODE, &show_ipv6_nht_cmd);
   install_element (VIEW_NODE, &show_ip_route_addr_cmd);
@@ -2136,6 +2910,7 @@ zebra_vty_init (void)
   install_element (VIEW_NODE, &show_ip_route_summary_cmd);
   install_element (VIEW_NODE, &show_ip_route_summary_prefix_cmd);
   install_element (ENABLE_NODE, &show_ip_route_cmd);
+  install_element (ENABLE_NODE, &show_ip_route_tag_cmd);
   install_element (ENABLE_NODE, &show_ip_nht_cmd);
   install_element (ENABLE_NODE, &show_ipv6_nht_cmd);
   install_element (ENABLE_NODE, &show_ip_route_addr_cmd);
@@ -2167,7 +2942,24 @@ zebra_vty_init (void)
   install_element (CONFIG_NODE, &no_ipv6_route_flags_pref_cmd);
   install_element (CONFIG_NODE, &no_ipv6_route_ifname_pref_cmd);
   install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_pref_cmd);
+  install_element (CONFIG_NODE, &ipv6_route_tag_cmd);
+  install_element (CONFIG_NODE, &ipv6_route_flags_tag_cmd);
+  install_element (CONFIG_NODE, &ipv6_route_ifname_tag_cmd);
+  install_element (CONFIG_NODE, &ipv6_route_ifname_flags_tag_cmd);
+  install_element (CONFIG_NODE, &ipv6_route_pref_tag_cmd);
+  install_element (CONFIG_NODE, &ipv6_route_flags_pref_tag_cmd);
+  install_element (CONFIG_NODE, &ipv6_route_ifname_pref_tag_cmd);
+  install_element (CONFIG_NODE, &ipv6_route_ifname_flags_pref_tag_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_route_tag_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_route_flags_tag_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_route_ifname_tag_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_tag_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_route_pref_tag_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_route_flags_pref_tag_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_route_ifname_pref_tag_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_pref_tag_cmd);
   install_element (VIEW_NODE, &show_ipv6_route_cmd);
+  install_element (VIEW_NODE, &show_ipv6_route_tag_cmd);
   install_element (VIEW_NODE, &show_ipv6_route_summary_cmd);
   install_element (VIEW_NODE, &show_ipv6_route_summary_prefix_cmd);
   install_element (VIEW_NODE, &show_ipv6_route_protocol_cmd);
@@ -2175,6 +2967,7 @@ zebra_vty_init (void)
   install_element (VIEW_NODE, &show_ipv6_route_prefix_cmd);
   install_element (VIEW_NODE, &show_ipv6_route_prefix_longer_cmd);
   install_element (ENABLE_NODE, &show_ipv6_route_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_route_tag_cmd);
   install_element (ENABLE_NODE, &show_ipv6_route_protocol_cmd);
   install_element (ENABLE_NODE, &show_ipv6_route_addr_cmd);
   install_element (ENABLE_NODE, &show_ipv6_route_prefix_cmd);
index f4ce81f788845b9234a43b00a1c0e35fbba88b8d..471e2c668c051740c8b3df417030b33f6e879f9d 100644 (file)
@@ -588,6 +588,13 @@ zsend_route_multipath (int cmd, struct zserv *client, struct prefix *p,
       stream_putc (s, rib->distance);
       SET_FLAG (zapi_flags, ZAPI_MESSAGE_METRIC);
       stream_putl (s, rib->metric);
+
+      /* tag */
+      if (rib->tag)
+        {
+          SET_FLAG(zapi_flags, ZAPI_MESSAGE_TAG);
+          stream_putw(s, rib->tag);
+        }
     }
   
   /* write real message flags value */
@@ -1026,6 +1033,12 @@ zread_ipv4_add (struct zserv *client, u_short length)
   if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC))
     rib->metric = stream_getl (s);
     
+  /* Tag */
+  if (CHECK_FLAG (message, ZAPI_MESSAGE_TAG))
+    rib->tag = stream_getw (s);
+  else
+    rib->tag = 0;
+
   /* Table */
   rib->table=zebrad.rtm_table_default;
   rib_add_ipv4_multipath (&p, rib, safi);
@@ -1109,6 +1122,12 @@ zread_ipv4_delete (struct zserv *client, u_short length)
   else
     api.metric = 0;
     
+  /* tag */
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG))
+    api.tag = stream_getw (s);
+  else
+    api.tag = 0;
+
   rib_delete_ipv4 (api.type, api.flags, &p, nexthop_p, ifindex,
                   client->rtm_table, api.safi);
   return 0;
@@ -1249,6 +1268,12 @@ zread_ipv6_add (struct zserv *client, u_short length)
   if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC))
     rib->metric = stream_getl (s);
     
+  /* Tag */
+  if (CHECK_FLAG (message, ZAPI_MESSAGE_TAG))
+    rib->tag = stream_getw (s);
+  else
+    rib->tag = 0;
+
   /* Table */
   rib->table=zebrad.rtm_table_default;
   rib_add_ipv6_multipath (&p, rib, safi, ifindex);
@@ -1304,15 +1329,24 @@ zread_ipv6_delete (struct zserv *client, u_short length)
        }
     }
 
+  /* Distance. */
   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
     api.distance = stream_getc (s);
   else
     api.distance = 0;
+
+  /* Metric. */
   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
     api.metric = stream_getl (s);
   else
     api.metric = 0;
     
+  /* tag */
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG))
+    api.tag = stream_getw (s);
+  else
+    api.tag = 0;
+
   if (IN6_IS_ADDR_UNSPECIFIED (&nexthop))
     rib_delete_ipv6 (api.type, api.flags, &p, NULL, ifindex, client->rtm_table, api.safi);
   else