bgpd, vtysh: Add support for route tags
[Forward ported by Cumulus]
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>
Signed-off-by: Piotr Chytla <pch@packetconsulting.pl>
Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
Edits by: Paul Jakma <paul.jakma@hpe.com - conflicts on re-ordering with the
rmap-event and table-map patches, those will now need to update the tags stuff.
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 616f779..ac67c62 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -495,6 +495,7 @@
MIX(extra->weight);
MIX(extra->mp_nexthop_global_in.s_addr);
MIX(extra->originator_id.s_addr);
+ MIX(extra->tag);
}
if (attr->aspath)
@@ -540,6 +541,7 @@
&& ae1->aggregator_as == ae2->aggregator_as
&& ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
&& ae1->weight == ae2->weight
+ && ae1->tag == ae2->tag
&& ae1->mp_nexthop_len == ae2->mp_nexthop_len
&& IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
&& IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
@@ -691,6 +693,7 @@
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);
attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index 000ceaa..0bbb912 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -92,6 +92,9 @@
uint16_t encap_tunneltype; /* grr */
struct bgp_attr_encap_subtlv *encap_subtlvs; /* rfc5512 */
+
+ /* route tag */
+ u_short tag;
};
/* BGP core attribute structure. */
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 93902de..bab9961 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -5605,7 +5605,7 @@
void
bgp_redistribute_add (struct prefix *p, const struct in_addr *nexthop,
const struct in6_addr *nexthop6,
- u_int32_t metric, u_char type)
+ u_int32_t metric, u_char type, u_short tag)
{
struct bgp *bgp;
struct listnode *node, *nnode;
@@ -5632,6 +5632,7 @@
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))
{
@@ -6292,7 +6293,7 @@
VTY_NEWLINE);
}
- /* 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))
@@ -6305,6 +6306,9 @@
if (attr->extra && attr->extra->weight != 0)
vty_out (vty, ", weight %u", attr->extra->weight);
+
+ if (attr->extra && attr->extra->tag != 0)
+ vty_out (vty, ", tag %d", attr->extra->tag);
if (! CHECK_FLAG (binfo->flags, BGP_INFO_VALID))
vty_out (vty, ", invalid");
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index 81df8fa..324e006 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -221,7 +221,7 @@
extern void bgp_redistribute_add (struct prefix *, const struct in_addr *,
const struct in6_addr *,
- u_int32_t, u_char);
+ u_int32_t, u_char, u_short);
extern void bgp_redistribute_delete (struct prefix *, u_char);
extern void bgp_redistribute_withdraw (struct bgp *, afi_t, int);
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index a9b6b50..204644a 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -71,7 +71,7 @@
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
@@ -91,7 +91,7 @@
metric : Done
metric-type : Not yet
origin : Done
- tag : (This will not be implemented by bgpd)
+ tag : Done
weight : Done
o Local extensions
@@ -1004,6 +1004,72 @@
/* `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
{
@@ -1777,6 +1843,73 @@
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,
+};
+
+
/* `match ipv6 address IP_ACCESS_LIST' */
static route_map_result_t
@@ -2998,6 +3131,37 @@
"local IGP\n"
"unknown heritage\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]);
+}
+
+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);
+
+ return bgp_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_ip_nexthop,
set_ip_nexthop_cmd,
"set ip next-hop A.B.C.D",
@@ -3663,6 +3827,38 @@
"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")
+
+
DEFUN (match_ipv6_address,
match_ipv6_address_cmd,
"match ipv6 address WORD",
@@ -3979,6 +4175,7 @@
route_map_install_match (&route_match_metric_cmd);
route_map_install_match (&route_match_origin_cmd);
route_map_install_match (&route_match_probability_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);
@@ -3995,6 +4192,7 @@
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);
@@ -4043,6 +4241,9 @@
install_element (RMAP_NODE, &match_probability_cmd);
install_element (RMAP_NODE, &no_match_probability_cmd);
install_element (RMAP_NODE, &no_match_probability_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);
@@ -4094,6 +4295,9 @@
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);
route_map_install_match (&route_match_ipv6_address_cmd);
route_map_install_match (&route_match_ipv6_next_hop_cmd);
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 5283d74..6c57a6f 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -296,8 +296,8 @@
api.metric,
api.tag);
}
- bgp_redistribute_add((struct prefix *)&p, &nexthop, NULL,
- api.metric, api.type);
+ bgp_redistribute_add ((struct prefix *)&p, &nexthop, NULL,
+ api.metric, api.type, api.tag);
}
else
{
@@ -388,7 +388,7 @@
api.tag);
}
bgp_redistribute_add ((struct prefix *)&p, NULL, &nexthop,
- api.metric, api.type);
+ api.metric, api.type, api.tag);
}
else
{
@@ -705,6 +705,9 @@
flags = 0;
peer = info->peer;
+ if ((info->attr->extra) && (info->attr->extra->tag != 0))
+ tag = info->attr->extra->tag;
+
if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED)
{
SET_FLAG (flags, ZEBRA_FLAG_IBGP);
@@ -758,10 +761,10 @@
api.metric = info->attr->med;
if (tag)
- {
- SET_FLAG (api.message, ZAPI_MESSAGE_TAG);
- api.tag = tag;
- }
+ {
+ SET_FLAG (api.message, ZAPI_MESSAGE_TAG);
+ api.tag = tag;
+ }
distance = bgp_distance_apply (p, info, bgp);
@@ -1005,13 +1008,20 @@
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
api.metric = info->attr->med;
+ if ((info->attr->extra) && (info->attr->extra->tag != 0))
+ {
+ SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
+ api.tag = info->attr->extra->tag;
+ }
+
if (BGP_DEBUG(zebra, ZEBRA))
{
char buf[2][INET_ADDRSTRLEN];
- zlog_debug("Zebra send: IPv4 route delete %s/%d metric %u",
+ zlog_debug("Zebra send: IPv4 route delete %s/%d metric %u tag %d",
inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
p->prefixlen,
- api.metric);
+ api.metric,
+ api.tag);
}
zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient,
@@ -1033,13 +1043,20 @@
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
api.metric = info->attr->med;
+ if ((info->attr->extra) && (info->attr->extra->tag != 0))
+ {
+ SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
+ api.tag = info->attr->extra->tag;
+ }
+
if (BGP_DEBUG(zebra, ZEBRA))
{
char buf[2][INET6_ADDRSTRLEN];
- zlog_debug("Zebra send: IPv6 route delete %s/%d metric %u",
+ zlog_debug("Zebra send: IPv6 route delete %s/%d metric %u tag %d",
inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
p->prefixlen,
- api.metric);
+ api.metric,
+ api.tag);
}
zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient,
diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in
index 81adf35..924cffe 100755
--- a/vtysh/extract.pl.in
+++ b/vtysh/extract.pl.in
@@ -181,7 +181,7 @@
}
}
-my $bad_cli_stomps = 96;
+my $bad_cli_stomps = 102;
# Currently we have $bad_cli_stomps. This was determined by
# running this script and counting up the collisions from what
# was returned.