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