--- embedaddon/quagga/bgpd/bgp_routemap.c 2013/07/21 23:54:38 1.1.1.3 +++ embedaddon/quagga/bgpd/bgp_routemap.c 2016/11/02 10:09:10 1.1.1.4 @@ -93,14 +93,136 @@ o Cisco route-map tag : (This will not be implemented by bgpd) weight : Done -o Local extention +o Local extensions set ipv6 next-hop global: Done set ipv6 next-hop local : Done set as-path exclude : Done */ - + + /* generic value manipulation to be shared in multiple rules */ + +#define RMAP_VALUE_SET 0 +#define RMAP_VALUE_ADD 1 +#define RMAP_VALUE_SUB 2 + +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 (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, struct peer *peer) +{ + u_int32_t value; + + switch (rv->variable) + { + case 1: + value = peer->rtt; + break; + default: + value = rv->value; + break; + } + + switch (rv->action) + { + case RMAP_VALUE_ADD: + if (current > UINT32_MAX-value) + return UINT32_MAX; + return current + value; + case RMAP_VALUE_SUB: + if (current <= value) + return 0; + return current - value; + default: + return value; + } +} + +static void * +route_value_compile (const char *arg) +{ + u_int8_t action = RMAP_VALUE_SET, var = 0; + unsigned long larg = 0; + char *endptr = NULL; + struct rmap_value *rv; + + if (arg[0] == '+') + { + action = RMAP_VALUE_ADD; + arg++; + } + else if (arg[0] == '-') + { + action = RMAP_VALUE_SUB; + arg++; + } + + 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; +} + +static void +route_value_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + + /* generic as path object to be shared in multiple rules */ + +static void * +route_aspath_compile (const char *arg) +{ + struct aspath *aspath; + + aspath = aspath_str2aspath (arg); + if (! aspath) + return NULL; + return aspath; +} + +static void +route_aspath_free (void *rule) +{ + struct aspath *aspath = rule; + aspath_free (aspath); +} + /* 'match peer (A.B.C.D|X:X::X:X)' */ /* Compares the peer specified in the 'match peer' clause with the peer @@ -111,8 +233,8 @@ route_match_peer (void *rule, struct prefix *prefix, r void *object) { union sockunion *su; - union sockunion su_def = { .sa.sa_family = AF_INET, - .sin.sin_addr.s_addr = INADDR_ANY }; + union sockunion su_def = { .sin = { .sin_family = AF_INET, + .sin_addr.s_addr = INADDR_ANY } }; struct peer_group *group; struct peer *peer; struct listnode *node, *nnode; @@ -240,7 +362,7 @@ struct route_map_rule_cmd route_match_ip_address_cmd = route_match_ip_address_compile, route_match_ip_address_free }; - + /* `match ip next-hop IP_ADDRESS' */ /* Match function return 1 if match is success else return zero. */ @@ -292,7 +414,7 @@ struct route_map_rule_cmd route_match_ip_next_hop_cmd route_match_ip_next_hop_compile, route_match_ip_next_hop_free }; - + /* `match ip route-source ACCESS-LIST' */ /* Match function return 1 if match is success else return zero. */ @@ -350,7 +472,7 @@ struct route_map_rule_cmd route_match_ip_route_source_ route_match_ip_route_source_compile, route_match_ip_route_source_free }; - + /* `match ip address prefix-list PREFIX_LIST' */ static route_map_result_t @@ -390,7 +512,7 @@ struct route_map_rule_cmd route_match_ip_address_prefi route_match_ip_address_prefix_list_compile, route_match_ip_address_prefix_list_free }; - + /* `match ip next-hop prefix-list PREFIX_LIST' */ static route_map_result_t @@ -437,7 +559,7 @@ struct route_map_rule_cmd route_match_ip_next_hop_pref route_match_ip_next_hop_prefix_list_compile, route_match_ip_next_hop_prefix_list_free }; - + /* `match ip route-source prefix-list PREFIX_LIST' */ static route_map_result_t @@ -490,7 +612,7 @@ struct route_map_rule_cmd route_match_ip_route_source_ route_match_ip_route_source_prefix_list_compile, route_match_ip_route_source_prefix_list_free }; - + /* `match metric METRIC' */ /* Match function return 1 if match is success else return zero. */ @@ -498,64 +620,27 @@ static route_map_result_t route_match_metric (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { - u_int32_t *med; + struct rmap_value *rv; struct bgp_info *bgp_info; if (type == RMAP_BGP) { - med = rule; + rv = rule; bgp_info = object; - - if (bgp_info->attr->med == *med) - return RMAP_MATCH; - else - return RMAP_NOMATCH; + return route_value_match(rv, bgp_info->attr->med); } return RMAP_NOMATCH; } -/* Route map `match metric' match statement. `arg' is MED value */ -static void * -route_match_metric_compile (const char *arg) -{ - u_int32_t *med; - char *endptr = NULL; - unsigned long tmpval; - - /* Metric value shoud be integer. */ - if (! all_digit (arg)) - return NULL; - - errno = 0; - tmpval = strtoul (arg, &endptr, 10); - if (*endptr != '\0' || errno || tmpval > UINT32_MAX) - return NULL; - - med = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); - - if (!med) - return med; - - *med = tmpval; - return med; -} - -/* Free route map's compiled `match metric' value. */ -static void -route_match_metric_free (void *rule) -{ - XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); -} - /* Route map commands for metric matching. */ struct route_map_rule_cmd route_match_metric_cmd = { "metric", route_match_metric, - route_match_metric_compile, - route_match_metric_free + route_value_compile, + route_value_free, }; - + /* `match as-path ASPATH' */ /* Match function for as-path match. I assume given object is */ @@ -603,7 +688,7 @@ struct route_map_rule_cmd route_match_aspath_cmd = route_match_aspath_compile, route_match_aspath_free }; - + /* `match community COMMUNIY' */ struct rmap_community { @@ -687,7 +772,7 @@ struct route_map_rule_cmd route_match_community_cmd = route_match_community_compile, route_match_community_free }; - + /* Match function for extcommunity match. */ static route_map_result_t route_match_ecommunity (void *rule, struct prefix *prefix, @@ -736,10 +821,10 @@ struct route_map_rule_cmd route_match_ecommunity_cmd = route_match_ecommunity_compile, route_match_ecommunity_free }; - + /* `match nlri` and `set nlri` are replaced by `address-family ipv4` and `address-family vpnv4'. */ - + /* `match origin' */ static route_map_result_t route_match_origin (void *rule, struct prefix *prefix, @@ -799,19 +884,14 @@ static route_map_result_t route_match_probability (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { - long r; -#if _SVID_SOURCE || _BSD_SOURCE || _XOPEN_SOURCE >= 500 - r = random(); -#else - r = (long) rand(); -#endif + long r = random(); - switch (*(unsigned *) rule) + switch (*(long *) rule) { case 0: break; case RAND_MAX: return RMAP_MATCH; default: - if (r < *(unsigned *) rule) + if (r < *(long *) rule) { return RMAP_MATCH; } @@ -823,17 +903,11 @@ route_match_probability (void *rule, struct prefix *pr static void * route_match_probability_compile (const char *arg) { - unsigned *lobule; + long *lobule; unsigned perc; -#if _SVID_SOURCE || _BSD_SOURCE || _XOPEN_SOURCE >= 500 - srandom (time (NULL)); -#else - srand (time (NULL)); -#endif - perc = atoi (arg); - lobule = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (unsigned)); + lobule = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (long)); switch (perc) { @@ -964,7 +1038,7 @@ struct route_map_rule_cmd route_set_ip_nexthop_cmd = route_set_ip_nexthop_compile, route_set_ip_nexthop_free }; - + /* `set local-preference LOCAL_PREF' */ /* Set local preference. */ @@ -972,66 +1046,36 @@ static route_map_result_t route_set_local_pref (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { - u_int32_t *local_pref; + struct rmap_value *rv; struct bgp_info *bgp_info; + u_int32_t locpref = 0; if (type == RMAP_BGP) { /* Fetch routemap's rule information. */ - local_pref = rule; + rv = rule; bgp_info = object; /* Set local preference value. */ + if (bgp_info->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) + locpref = bgp_info->attr->local_pref; + bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF); - bgp_info->attr->local_pref = *local_pref; + bgp_info->attr->local_pref = route_value_adjust(rv, locpref, bgp_info->peer); } return RMAP_OKAY; } -/* set local preference compilation. */ -static void * -route_set_local_pref_compile (const char *arg) -{ - unsigned long tmp; - u_int32_t *local_pref; - char *endptr = NULL; - - /* Local preference value shoud be integer. */ - if (! all_digit (arg)) - return NULL; - - errno = 0; - tmp = strtoul (arg, &endptr, 10); - if (*endptr != '\0' || errno || tmp > UINT32_MAX) - return NULL; - - local_pref = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); - - if (!local_pref) - return local_pref; - - *local_pref = tmp; - - return local_pref; -} - -/* Free route map's local preference value. */ -static void -route_set_local_pref_free (void *rule) -{ - XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); -} - /* Set local preference rule structure. */ struct route_map_rule_cmd route_set_local_pref_cmd = { "local-preference", route_set_local_pref, - route_set_local_pref_compile, - route_set_local_pref_free, + route_value_compile, + route_value_free, }; - + /* `set weight WEIGHT' */ /* Set weight. */ @@ -1039,18 +1083,20 @@ static route_map_result_t route_set_weight (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { - u_int32_t *weight; + struct rmap_value *rv; struct bgp_info *bgp_info; + u_int32_t weight; if (type == RMAP_BGP) { /* Fetch routemap's rule information. */ - weight = rule; + rv = rule; bgp_info = object; /* Set weight value. */ - if (*weight) - (bgp_attr_extra_get (bgp_info->attr))->weight = *weight; + 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) bgp_info->attr->extra->weight = 0; } @@ -1058,49 +1104,15 @@ route_set_weight (void *rule, struct prefix *prefix, r return RMAP_OKAY; } -/* set local preference compilation. */ -static void * -route_set_weight_compile (const char *arg) -{ - unsigned long tmp; - u_int32_t *weight; - char *endptr = NULL; - - /* Local preference value shoud be integer. */ - if (! all_digit (arg)) - return NULL; - - errno = 0; - tmp = strtoul (arg, &endptr, 10); - if (*endptr != '\0' || errno || tmp > UINT32_MAX) - return NULL; - - weight = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); - - if (weight == NULL) - return weight; - - *weight = tmp; - - return weight; -} - -/* Free route map's local preference value. */ -static void -route_set_weight_free (void *rule) -{ - XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); -} - /* Set local preference rule structure. */ struct route_map_rule_cmd route_set_weight_cmd = { "weight", route_set_weight, - route_set_weight_compile, - route_set_weight_free, + route_value_compile, + route_value_free, }; - + /* `set metric METRIC' */ /* Set metric to attribute. */ @@ -1108,99 +1120,34 @@ static route_map_result_t route_set_metric (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { - char *metric; - u_int32_t metric_val; + struct rmap_value *rv; struct bgp_info *bgp_info; + u_int32_t med = 0; if (type == RMAP_BGP) { /* Fetch routemap's rule information. */ - metric = rule; + rv = rule; bgp_info = object; - if (! (bgp_info->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))) - bgp_info->attr->med = 0; - bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); + if (bgp_info->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) + med = bgp_info->attr->med; - if (all_digit (metric)) - { - metric_val = strtoul (metric, (char **)NULL, 10); - bgp_info->attr->med = metric_val; - } - else - { - metric_val = strtoul (metric+1, (char **)NULL, 10); - - if (strncmp (metric, "+", 1) == 0) - { - if (bgp_info->attr->med/2 + metric_val/2 > BGP_MED_MAX/2) - bgp_info->attr->med = BGP_MED_MAX - 1; - else - bgp_info->attr->med += metric_val; - } - else if (strncmp (metric, "-", 1) == 0) - { - if (bgp_info->attr->med <= metric_val) - bgp_info->attr->med = 0; - else - bgp_info->attr->med -= metric_val; - } - } + 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; } -/* set metric compilation. */ -static void * -route_set_metric_compile (const char *arg) -{ - u_int32_t metric; - unsigned long larg; - char *endptr = NULL; - - if (all_digit (arg)) - { - /* set metric value check*/ - errno = 0; - larg = strtoul (arg, &endptr, 10); - if (*endptr != '\0' || errno || larg > UINT32_MAX) - return NULL; - metric = larg; - } - else - { - /* set metric +/-value check */ - if ((strncmp (arg, "+", 1) != 0 - && strncmp (arg, "-", 1) != 0) - || (! all_digit (arg+1))) - return NULL; - - errno = 0; - larg = strtoul (arg+1, &endptr, 10); - if (*endptr != '\0' || errno || larg > UINT32_MAX) - return NULL; - metric = larg; - } - - return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); -} - -/* Free route map's compiled `set metric' value. */ -static void -route_set_metric_free (void *rule) -{ - XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); -} - /* Set metric rule structure. */ struct route_map_rule_cmd route_set_metric_cmd = { "metric", route_set_metric, - route_set_metric_compile, - route_set_metric_free, + route_value_compile, + route_value_free, }; - + /* `set as-path prepend ASPATH' */ /* For AS path prepend mechanism. */ @@ -1213,7 +1160,6 @@ route_set_aspath_prepend (void *rule, struct prefix *p if (type == RMAP_BGP) { - aspath = rule; binfo = object; if (binfo->attr->aspath->refcnt) @@ -1221,34 +1167,44 @@ route_set_aspath_prepend (void *rule, struct prefix *p else new = binfo->attr->aspath; - aspath_prepend (aspath, new); + if ((uintptr_t)rule > 10) + { + aspath = rule; + aspath_prepend (aspath, new); + } + else + { + as_t as = aspath_leftmost(new); + if (!as) as = binfo->peer->as; + new = aspath_add_seq_n (new, as, (uintptr_t) rule); + } + binfo->attr->aspath = new; } return RMAP_OKAY; } -/* Compile function for as-path prepend. */ static void * route_set_aspath_prepend_compile (const char *arg) { - struct aspath *aspath; + unsigned int num; - aspath = aspath_str2aspath (arg); - if (! aspath) - return NULL; - return aspath; + if (sscanf(arg, "last-as %u", &num) == 1 && num > 0 && num < 10) + return (void*)(uintptr_t)num; + + return route_aspath_compile(arg); } -/* Compile function for as-path prepend. */ static void route_set_aspath_prepend_free (void *rule) { - struct aspath *aspath = rule; - aspath_free (aspath); + if ((uintptr_t)rule > 10) + route_aspath_free(rule); } -/* Set metric rule structure. */ + +/* Set as-path prepend rule structure. */ struct route_map_rule_cmd route_set_aspath_prepend_cmd = { "as-path prepend", @@ -1256,7 +1212,7 @@ struct route_map_rule_cmd route_set_aspath_prepend_cmd route_set_aspath_prepend_compile, route_set_aspath_prepend_free, }; - + /* `set as-path exclude ASn' */ /* For ASN exclude mechanism. @@ -1282,39 +1238,15 @@ route_set_aspath_exclude (void *rule, struct prefix *d return RMAP_OKAY; } -/* FIXME: consider using route_set_aspath_prepend_compile() and - * route_set_aspath_prepend_free(), which two below function are - * exact clones of. - */ - -/* Compile function for as-path exclude. */ -static void * -route_set_aspath_exclude_compile (const char *arg) -{ - struct aspath *aspath; - - aspath = aspath_str2aspath (arg); - if (! aspath) - return NULL; - return aspath; -} - -static void -route_set_aspath_exclude_free (void *rule) -{ - struct aspath *aspath = rule; - aspath_free (aspath); -} - /* Set ASn exlude rule structure. */ struct route_map_rule_cmd route_set_aspath_exclude_cmd = { "as-path exclude", route_set_aspath_exclude, - route_set_aspath_exclude_compile, - route_set_aspath_exclude_free, + route_aspath_compile, + route_aspath_free, }; - + /* `set community COMMUNITY' */ struct rmap_com_set { @@ -1438,7 +1370,7 @@ struct route_map_rule_cmd route_set_community_cmd = route_set_community_compile, route_set_community_free, }; - + /* `set comm-list (<1-99>|<100-500>|WORD) delete' */ /* For community set mechanism. */ @@ -1527,13 +1459,13 @@ struct route_map_rule_cmd route_set_community_delete_c route_set_community_delete_compile, route_set_community_delete_free, }; - + /* `set extcommunity rt COMMUNITY' */ -/* For community set mechanism. */ +/* For community set mechanism. Used by _rt and _soo. */ static route_map_result_t -route_set_ecommunity_rt (void *rule, struct prefix *prefix, - route_map_object_t type, void *object) +route_set_ecommunity (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) { struct ecommunity *ecom; struct ecommunity *new_ecom; @@ -1552,15 +1484,20 @@ route_set_ecommunity_rt (void *rule, struct prefix *pr old_ecom = (bgp_attr_extra_get (bgp_info->attr))->ecommunity; if (old_ecom) - new_ecom = ecommunity_merge (ecommunity_dup (old_ecom), ecom); + { + new_ecom = ecommunity_merge (ecommunity_dup (old_ecom), ecom); + + /* old_ecom->refcnt = 1 => owned elsewhere, e.g. bgp_update_receive() + * ->refcnt = 0 => set by a previous route-map statement */ + if (!old_ecom->refcnt) + ecommunity_free (&old_ecom); + } else new_ecom = ecommunity_dup (ecom); - bgp_info->attr->extra->ecommunity = ecommunity_intern (new_ecom); + /* will be intern()'d or attr_flush()'d by bgp_update_main() */ + bgp_info->attr->extra->ecommunity = new_ecom; - if (old_ecom) - ecommunity_unintern (&old_ecom); - bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); } return RMAP_OKAY; @@ -1578,9 +1515,9 @@ route_set_ecommunity_rt_compile (const char *arg) return ecommunity_intern (ecom); } -/* Free function for set community. */ +/* Free function for set community. Used by _rt and _soo */ static void -route_set_ecommunity_rt_free (void *rule) +route_set_ecommunity_free (void *rule) { struct ecommunity *ecom = rule; ecommunity_unintern (&ecom); @@ -1590,46 +1527,13 @@ route_set_ecommunity_rt_free (void *rule) struct route_map_rule_cmd route_set_ecommunity_rt_cmd = { "extcommunity rt", - route_set_ecommunity_rt, + route_set_ecommunity, route_set_ecommunity_rt_compile, - route_set_ecommunity_rt_free, + route_set_ecommunity_free, }; /* `set extcommunity soo COMMUNITY' */ -/* For community set mechanism. */ -static route_map_result_t -route_set_ecommunity_soo (void *rule, struct prefix *prefix, - route_map_object_t type, void *object) -{ - struct ecommunity *ecom, *old_ecom, *new_ecom; - struct bgp_info *bgp_info; - - if (type == RMAP_BGP) - { - ecom = rule; - bgp_info = object; - - if (! ecom) - return RMAP_OKAY; - - old_ecom = (bgp_attr_extra_get (bgp_info->attr))->ecommunity; - - if (old_ecom) - new_ecom = ecommunity_merge (ecommunity_dup (old_ecom), ecom); - else - new_ecom = ecommunity_dup (ecom); - - bgp_info->attr->extra->ecommunity = ecommunity_intern (new_ecom); - - if (old_ecom) - ecommunity_unintern (&old_ecom); - - bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); - } - return RMAP_OKAY; -} - /* Compile function for set community. */ static void * route_set_ecommunity_soo_compile (const char *arg) @@ -1643,23 +1547,15 @@ route_set_ecommunity_soo_compile (const char *arg) return ecommunity_intern (ecom); } -/* Free function for set community. */ -static void -route_set_ecommunity_soo_free (void *rule) -{ - struct ecommunity *ecom = rule; - ecommunity_unintern (&ecom); -} - /* Set community rule structure. */ struct route_map_rule_cmd route_set_ecommunity_soo_cmd = { "extcommunity soo", - route_set_ecommunity_soo, + route_set_ecommunity, route_set_ecommunity_soo_compile, - route_set_ecommunity_soo_free, + route_set_ecommunity_free, }; - + /* `set origin ORIGIN' */ /* For origin set. */ @@ -1705,7 +1601,7 @@ route_set_origin_free (void *rule) XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } -/* Set metric rule structure. */ +/* Set origin rule structure. */ struct route_map_rule_cmd route_set_origin_cmd = { "origin", @@ -1713,7 +1609,7 @@ struct route_map_rule_cmd route_set_origin_cmd = route_set_origin_compile, route_set_origin_free, }; - + /* `set atomic-aggregate' */ /* For atomic aggregate set. */ @@ -1754,7 +1650,7 @@ struct route_map_rule_cmd route_set_atomic_aggregate_c route_set_atomic_aggregate_compile, route_set_atomic_aggregate_free, }; - + /* `set aggregator as AS A.B.C.D' */ struct aggregator { @@ -1813,8 +1709,7 @@ struct route_map_rule_cmd route_set_aggregator_as_cmd route_set_aggregator_as_compile, route_set_aggregator_as_free, }; - -#ifdef HAVE_IPV6 + /* `match ipv6 address IP_ACCESS_LIST' */ static route_map_result_t @@ -1855,29 +1750,28 @@ struct route_map_rule_cmd route_match_ipv6_address_cmd route_match_ipv6_address_compile, route_match_ipv6_address_free }; - + /* `match ipv6 next-hop IP_ADDRESS' */ static route_map_result_t route_match_ipv6_next_hop (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { - struct in6_addr *addr; + struct in6_addr *addr = rule; struct bgp_info *bgp_info; if (type == RMAP_BGP) { - addr = rule; bgp_info = object; if (!bgp_info->attr->extra) return RMAP_NOMATCH; - if (IPV6_ADDR_SAME (&bgp_info->attr->extra->mp_nexthop_global, rule)) + if (IPV6_ADDR_SAME (&bgp_info->attr->extra->mp_nexthop_global, addr)) return RMAP_MATCH; if (bgp_info->attr->extra->mp_nexthop_len == 32 && - IPV6_ADDR_SAME (&bgp_info->attr->extra->mp_nexthop_local, rule)) + IPV6_ADDR_SAME (&bgp_info->attr->extra->mp_nexthop_local, addr)) return RMAP_MATCH; return RMAP_NOMATCH; @@ -1917,7 +1811,7 @@ struct route_map_rule_cmd route_match_ipv6_next_hop_cm route_match_ipv6_next_hop_compile, route_match_ipv6_next_hop_free }; - + /* `match ipv6 address prefix-list PREFIX_LIST' */ static route_map_result_t @@ -1957,7 +1851,7 @@ struct route_map_rule_cmd route_match_ipv6_address_pre route_match_ipv6_address_prefix_list_compile, route_match_ipv6_address_prefix_list_free }; - + /* `set ipv6 nexthop global IP_ADDRESS' */ /* Set nexthop to object. ojbect must be pointer to struct attr. */ @@ -2021,7 +1915,7 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_globa route_set_ipv6_nexthop_global_compile, route_set_ipv6_nexthop_global_free }; - + /* `set ipv6 nexthop local IP_ADDRESS' */ /* Set nexthop to object. ojbect must be pointer to struct attr. */ @@ -2085,8 +1979,97 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_local route_set_ipv6_nexthop_local_compile, route_set_ipv6_nexthop_local_free }; -#endif /* HAVE_IPV6 */ - + +/* `set ipv6 nexthop peer-address' */ + +/* Set nexthop to object. ojbect must be pointer to struct attr. */ +static route_map_result_t +route_set_ipv6_nexthop_peer (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct in6_addr peer_address; + struct bgp_info *bgp_info; + struct peer *peer; + char peer_addr_buf[INET6_ADDRSTRLEN]; + + if (type == RMAP_BGP) + { + /* Fetch routemap's rule information. */ + bgp_info = object; + peer = bgp_info->peer; + + if ((CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IN) || + CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IMPORT)) + && peer->su_remote + && sockunion_family (peer->su_remote) == AF_INET6) + { + inet_pton (AF_INET6, sockunion2str (peer->su_remote, + peer_addr_buf, + INET6_ADDRSTRLEN), + &peer_address); + } + else if (CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_OUT) + && peer->su_local + && sockunion_family (peer->su_local) == AF_INET6) + { + inet_pton (AF_INET, sockunion2str (peer->su_local, + peer_addr_buf, + INET6_ADDRSTRLEN), + &peer_address); + } + + if (IN6_IS_ADDR_LINKLOCAL(&peer_address)) + { + /* Set next hop value. */ + (bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_local = peer_address; + + /* Set nexthop length. */ + if (bgp_info->attr->extra->mp_nexthop_len != 32) + bgp_info->attr->extra->mp_nexthop_len = 32; + } + else + { + /* Set next hop value. */ + (bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_global = peer_address; + + /* Set nexthop length. */ + if (bgp_info->attr->extra->mp_nexthop_len == 0) + bgp_info->attr->extra->mp_nexthop_len = 16; + } + } + + return RMAP_OKAY; +} + +/* Route map `ip next-hop' compile function. Given string is converted + to struct in_addr structure. */ +static void * +route_set_ipv6_nexthop_peer_compile (const char *arg) +{ + int *rins = NULL; + + rins = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (int)); + *rins = 1; + + return rins; +} + +/* Free route map's compiled `ip next-hop' value. */ +static void +route_set_ipv6_nexthop_peer_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip nexthop set. */ +struct route_map_rule_cmd route_set_ipv6_nexthop_peer_cmd = +{ + "ipv6 next-hop peer-address", + route_set_ipv6_nexthop_peer, + route_set_ipv6_nexthop_peer_compile, + route_set_ipv6_nexthop_peer_free +}; + /* `set vpnv4 nexthop A.B.C.D' */ static route_map_result_t @@ -2104,6 +2087,7 @@ route_set_vpnv4_nexthop (void *rule, struct prefix *pr /* Set next hop value. */ (bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_global_in = *address; + (bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_len = 4; } return RMAP_OKAY; @@ -2142,7 +2126,7 @@ struct route_map_rule_cmd route_set_vpnv4_nexthop_cmd route_set_vpnv4_nexthop_compile, route_set_vpnv4_nexthop_free }; - + /* `set originator-id' */ /* For origin set. */ @@ -2191,7 +2175,7 @@ route_set_originator_id_free (void *rule) XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } -/* Set metric rule structure. */ +/* Set originator-id rule structure. */ struct route_map_rule_cmd route_set_originator_id_cmd = { "originator-id", @@ -2199,7 +2183,7 @@ struct route_map_rule_cmd route_set_originator_id_cmd route_set_originator_id_compile, route_set_originator_id_free, }; - + /* Add bgp route map rule. */ static int bgp_route_match_add (struct vty *vty, struct route_map_index *index, @@ -2309,6 +2293,9 @@ bgp_route_map_update (const char *unused) struct bgp_node *bn; struct bgp_static *bgp_static; + if (bm->bgp == NULL) /* may be called during cleanup */ + return; + /* For neighbor route-map updates. */ for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp)) { @@ -2397,18 +2384,16 @@ bgp_route_map_update (const char *unused) { for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { - if (bgp->rmap[ZEBRA_FAMILY_IPV4][i].name) - bgp->rmap[ZEBRA_FAMILY_IPV4][i].map = - route_map_lookup_by_name (bgp->rmap[ZEBRA_FAMILY_IPV4][i].name); -#ifdef HAVE_IPV6 - if (bgp->rmap[ZEBRA_FAMILY_IPV6][i].name) - bgp->rmap[ZEBRA_FAMILY_IPV6][i].map = - route_map_lookup_by_name (bgp->rmap[ZEBRA_FAMILY_IPV6][i].name); -#endif /* HAVE_IPV6 */ + if (bgp->rmap[AFI_IP][i].name) + bgp->rmap[AFI_IP][i].map = + route_map_lookup_by_name (bgp->rmap[AFI_IP][i].name); + if (bgp->rmap[AFI_IP6][i].name) + bgp->rmap[AFI_IP6][i].map = + route_map_lookup_by_name (bgp->rmap[AFI_IP][i].name); } } } - + DEFUN (match_peer, match_peer_cmd, "match peer (A.B.C.D|X:X::X:X)", @@ -2999,6 +2984,15 @@ ALIAS (set_metric, "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", @@ -3100,6 +3094,15 @@ DEFUN (set_aspath_prepend, return ret; } +ALIAS (set_aspath_prepend, + set_aspath_prepend_lastas_cmd, + "set as-path prepend (last-as) <1-10>", + SET_STR + "Transform BGP AS_PATH attribute\n" + "Prepend to the as-path\n" + "Use the peer's AS-number\n" + "Number of times to insert") + DEFUN (no_set_aspath_prepend, no_set_aspath_prepend_cmd, "no set as-path prepend", @@ -3490,7 +3493,7 @@ DEFUN (set_aggregator_as, "IP address of aggregator\n") { int ret; - as_t as; + as_t as __attribute__((unused)); /* dummy for VTY_GET_INTEGER_RANGE */ struct in_addr address; char *argstr; @@ -3524,7 +3527,7 @@ DEFUN (no_set_aggregator_as, "AS number of aggregator\n") { int ret; - as_t as; + as_t as __attribute__((unused)); /* dummy for VTY_GET_INTEGER_RANGE */ struct in_addr address; char *argstr; @@ -3562,8 +3565,6 @@ ALIAS (no_set_aggregator_as, "AS number\n" "IP address of aggregator\n") - -#ifdef HAVE_IPV6 DEFUN (match_ipv6_address, match_ipv6_address_cmd, "match ipv6 address WORD", @@ -3635,6 +3636,29 @@ DEFUN (no_match_ipv6_address_prefix_list, return bgp_route_match_delete (vty, vty->index, "ipv6 address prefix-list", argv[0]); } +DEFUN (set_ipv6_nexthop_peer, + set_ipv6_nexthop_peer_cmd, + "set ipv6 next-hop peer-address", + SET_STR + IPV6_STR + "Next hop address\n" + "Use peer address (for BGP only)\n") +{ + return bgp_route_set_add (vty, vty->index, "ipv6 next-hop peer-address", NULL); +} + +DEFUN (no_set_ipv6_nexthop_peer, + no_set_ipv6_nexthop_peer_cmd, + "no set ipv6 next-hop peer-address", + NO_STR + SET_STR + IPV6_STR + "IPv6 next-hop address\n" + ) +{ + return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop", argv[0]); +} + DEFUN (set_ipv6_nexthop_global, set_ipv6_nexthop_global_cmd, "set ipv6 next-hop global X:X::X:X", @@ -3708,7 +3732,6 @@ ALIAS (no_set_ipv6_nexthop_local, "IPv6 next-hop address\n" "IPv6 local address\n" "IPv6 address of next hop\n") -#endif /* HAVE_IPV6 */ DEFUN (set_vpnv4_nexthop, set_vpnv4_nexthop_cmd, @@ -3833,7 +3856,7 @@ ALIAS (no_match_pathlimit_as, "BGP AS-Pathlimit attribute\n" "Match Pathlimit ASN\n") - + /* Initialization of route map. */ void bgp_route_map_init (void) @@ -3930,9 +3953,11 @@ bgp_route_map_init (void) 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); + install_element (RMAP_NODE, &set_aspath_prepend_lastas_cmd); install_element (RMAP_NODE, &set_aspath_exclude_cmd); install_element (RMAP_NODE, &no_set_aspath_prepend_cmd); install_element (RMAP_NODE, &no_set_aspath_prepend_val_cmd); @@ -3967,13 +3992,13 @@ bgp_route_map_init (void) install_element (RMAP_NODE, &no_set_originator_id_cmd); install_element (RMAP_NODE, &no_set_originator_id_val_cmd); -#ifdef HAVE_IPV6 route_map_install_match (&route_match_ipv6_address_cmd); route_map_install_match (&route_match_ipv6_next_hop_cmd); route_map_install_match (&route_match_ipv6_address_prefix_list_cmd); route_map_install_set (&route_set_ipv6_nexthop_global_cmd); route_map_install_set (&route_set_ipv6_nexthop_local_cmd); - + route_map_install_set (&route_set_ipv6_nexthop_peer_cmd); + install_element (RMAP_NODE, &match_ipv6_address_cmd); install_element (RMAP_NODE, &no_match_ipv6_address_cmd); install_element (RMAP_NODE, &match_ipv6_next_hop_cmd); @@ -3986,7 +4011,8 @@ bgp_route_map_init (void) install_element (RMAP_NODE, &set_ipv6_nexthop_local_cmd); install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_cmd); install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_val_cmd); -#endif /* HAVE_IPV6 */ + install_element (RMAP_NODE, &set_ipv6_nexthop_peer_cmd); + install_element (RMAP_NODE, &no_set_ipv6_nexthop_peer_cmd); /* AS-Pathlimit: functionality removed, commands kept for * compatibility.