ospfd, vtysh: Add support for Route tags
[Forward ported by Cumulus]
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.
Signed-off-by: Daniel Walton <dwalton@cumulusnetworks.com>
Signed-off-by: Piotr Chytla <pch@packetconsulting.pl>
Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c
index 122e70b..4b53690 100644
--- a/ospfd/ospf_asbr.c
+++ b/ospfd/ospf_asbr.c
@@ -135,7 +135,8 @@
/* Add an External info for AS-external-LSA. */
struct external_info *
ospf_external_info_add (u_char type, struct prefix_ipv4 p,
- ifindex_t ifindex, struct in_addr nexthop)
+ ifindex_t ifindex, struct in_addr nexthop,
+ u_short tag)
{
struct external_info *new;
struct route_node *rn;
@@ -162,7 +163,7 @@
new->p = p;
new->ifindex = ifindex;
new->nexthop = nexthop;
- new->tag = 0;
+ new->tag = tag;
if (rn)
rn->info = new;
diff --git a/ospfd/ospf_asbr.h b/ospfd/ospf_asbr.h
index d151cb1..2709a6c 100644
--- a/ospfd/ospf_asbr.h
+++ b/ospfd/ospf_asbr.h
@@ -62,7 +62,8 @@
extern struct external_info *ospf_external_info_add (u_char,
struct prefix_ipv4,
ifindex_t,
- 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 *);
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
index c1b1e0e..4341cd9 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
@@ -1649,8 +1649,8 @@
/* 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. */
@@ -2163,7 +2163,7 @@
/* 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)))
diff --git a/ospfd/ospf_routemap.c b/ospfd/ospf_routemap.c
index d0ebce6..7bd6c3d 100644
--- a/ospfd/ospf_routemap.c
+++ b/ospfd/ospf_routemap.c
@@ -417,6 +417,67 @@
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 @@
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 @@
"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 @@
"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 @@
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 @@
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 @@
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);
}
diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c
index d9b0837..ce268cd 100644
--- a/ospfd/ospf_zebra.c
+++ b/ospfd/ospf_zebra.c
@@ -370,6 +370,12 @@
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);
@@ -437,6 +443,9 @@
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);
@@ -911,8 +920,12 @@
* || 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
diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c
index a01af60..98d6d77 100644
--- a/ospfd/ospfd.c
+++ b/ospfd/ospfd.c
@@ -197,6 +197,7 @@
{
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;
diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h
index 508f623..4181d11 100644
--- a/ospfd/ospfd.h
+++ b/ospfd/ospfd.h
@@ -238,6 +238,9 @@
-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
{
diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in
index 0bbc2a7..81adf35 100755
--- a/vtysh/extract.pl.in
+++ b/vtysh/extract.pl.in
@@ -181,7 +181,7 @@
}
}
-my $bad_cli_stomps = 90;
+my $bad_cli_stomps = 96;
# Currently we have $bad_cli_stomps. This was determined by
# running this script and counting up the collisions from what
# was returned.