bgpd: allow using rtt in route-map's set metric
Useful when the BGP neighbors are over tunnels that have large
differences in geographic distances and RTTs. Especially useful
for DMVPN setups to allow preferring closes hub.
The parameter is added as new alias command as otherwise it seems
the command parser is not able to match it properly (it seems
merging is done for the various 'set metric' route-map objects in
different routing engines). For same reason also they are listed
as three separate options: optional +/- seems not possibly easily.
Related research papers:
http://www.pps.univ-paris-diderot.fr/~jch/research/delay-based.pdf
http://arxiv.org/pdf/1309.0632.pdf
Paper on similar extension to Babel:
http://www.pps.univ-paris-diderot.fr/~jch/research/rapport-jonglez-2013.pdf
Signed-off-by: Timo Teräs <timo.teras@iki.fi>
Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 4a0dac7..5467cfd 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -110,22 +110,33 @@
struct rmap_value
{
u_int8_t action;
+ u_int8_t variable;
u_int32_t value;
};
static int
route_value_match (struct rmap_value *rv, u_int32_t value)
{
- if (value == rv->value)
+ if (rv->variable == 0 && value == rv->value)
return RMAP_MATCH;
return RMAP_NOMATCH;
}
static u_int32_t
-route_value_adjust (struct rmap_value *rv, u_int32_t current)
+route_value_adjust (struct rmap_value *rv, u_int32_t current, struct peer *peer)
{
- u_int32_t value = rv->value;
+ u_int32_t value;
+
+ switch (rv->variable)
+ {
+ case 1:
+ value = peer->rtt;
+ break;
+ default:
+ value = rv->value;
+ break;
+ }
switch (rv->action)
{
@@ -145,8 +156,8 @@
static void *
route_value_compile (const char *arg)
{
- u_int8_t action = RMAP_VALUE_SET;
- unsigned long larg;
+ u_int8_t action = RMAP_VALUE_SET, var = 0;
+ unsigned long larg = 0;
char *endptr = NULL;
struct rmap_value *rv;
@@ -161,16 +172,27 @@
arg++;
}
- errno = 0;
- larg = strtoul (arg, &endptr, 10);
- if (*arg == 0 || *endptr != 0 || errno || larg > UINT32_MAX)
- return NULL;
+ if (all_digit(arg))
+ {
+ errno = 0;
+ larg = strtoul (arg, &endptr, 10);
+ if (*arg == 0 || *endptr != 0 || errno || larg > UINT32_MAX)
+ return NULL;
+ }
+ else
+ {
+ if (strcmp(arg, "rtt") == 0)
+ var = 1;
+ else
+ return NULL;
+ }
rv = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_value));
if (!rv)
return NULL;
rv->action = action;
+ rv->variable = var;
rv->value = larg;
return rv;
}
@@ -1050,7 +1072,7 @@
locpref = bgp_info->attr->local_pref;
bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
- bgp_info->attr->local_pref = route_value_adjust(rv, locpref);
+ bgp_info->attr->local_pref = route_value_adjust(rv, locpref, bgp_info->peer);
}
return RMAP_OKAY;
@@ -1083,7 +1105,7 @@
bgp_info = object;
/* Set weight value. */
- weight = route_value_adjust(rv, 0);
+ weight = route_value_adjust(rv, 0, bgp_info->peer);
if (weight)
(bgp_attr_extra_get (bgp_info->attr))->weight = weight;
else if (bgp_info->attr->extra)
@@ -1122,7 +1144,7 @@
if (bgp_info->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
med = bgp_info->attr->med;
- bgp_info->attr->med = route_value_adjust(rv, med);
+ bgp_info->attr->med = route_value_adjust(rv, med, bgp_info->peer);
bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
}
return RMAP_OKAY;
@@ -2974,6 +2996,15 @@
"Metric value for destination routing protocol\n"
"Add or subtract metric\n")
+ALIAS (set_metric,
+ set_metric_rtt_cmd,
+ "set metric (rtt|+rtt|-rtt)",
+ SET_STR
+ "Metric value for destination routing protocol\n"
+ "Assign round trip time\n"
+ "Add round trip time\n"
+ "Subtract round trip time\n")
+
DEFUN (no_set_metric,
no_set_metric_cmd,
"no set metric",
@@ -3937,6 +3968,7 @@
install_element (RMAP_NODE, &no_set_weight_val_cmd);
install_element (RMAP_NODE, &set_metric_cmd);
install_element (RMAP_NODE, &set_metric_addsub_cmd);
+ install_element (RMAP_NODE, &set_metric_rtt_cmd);
install_element (RMAP_NODE, &no_set_metric_cmd);
install_element (RMAP_NODE, &no_set_metric_val_cmd);
install_element (RMAP_NODE, &set_aspath_prepend_cmd);