summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_attr.c44
-rw-r--r--bgpd/bgp_attr.h5
-rw-r--r--bgpd/bgp_evpn.c2
-rw-r--r--bgpd/bgp_route.c86
-rw-r--r--bgpd/bgp_route.h9
-rw-r--r--bgpd/bgp_routemap.c35
-rw-r--r--bgpd/bgpd.h1
-rw-r--r--doc/user/bgp.rst34
-rw-r--r--tests/topotests/bgp_aggregate-address_route-map/__init__.py0
-rw-r--r--tests/topotests/bgp_aggregate-address_route-map/r1/bgpd.conf10
-rw-r--r--tests/topotests/bgp_aggregate-address_route-map/r1/zebra.conf9
-rw-r--r--tests/topotests/bgp_aggregate-address_route-map/r2/bgpd.conf4
-rw-r--r--tests/topotests/bgp_aggregate-address_route-map/r2/zebra.conf6
-rw-r--r--tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py109
-rw-r--r--zebra/zebra_nhg.c33
15 files changed, 344 insertions, 43 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index e21c84355e..ab9dc3092a 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -724,10 +724,13 @@ struct attr *bgp_attr_aggregate_intern(struct bgp *bgp, uint8_t origin,
struct community *community,
struct ecommunity *ecommunity,
struct lcommunity *lcommunity,
- int as_set, uint8_t atomic_aggregate)
+ struct bgp_aggregate *aggregate,
+ uint8_t atomic_aggregate,
+ struct prefix *p)
{
struct attr attr;
struct attr *new;
+ int ret;
memset(&attr, 0, sizeof(struct attr));
@@ -778,7 +781,7 @@ struct attr *bgp_attr_aggregate_intern(struct bgp *bgp, uint8_t origin,
attr.label = MPLS_INVALID_LABEL;
attr.weight = BGP_ATTR_DEFAULT_WEIGHT;
attr.mp_nexthop_len = IPV6_MAX_BYTELEN;
- if (!as_set || atomic_aggregate)
+ if (!aggregate->as_set || atomic_aggregate)
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE);
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR);
if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
@@ -789,7 +792,42 @@ struct attr *bgp_attr_aggregate_intern(struct bgp *bgp, uint8_t origin,
attr.label_index = BGP_INVALID_LABEL_INDEX;
attr.label = MPLS_INVALID_LABEL;
- new = bgp_attr_intern(&attr);
+ /* Apply route-map */
+ if (aggregate->rmap.name) {
+ struct attr attr_tmp = attr;
+ struct bgp_path_info rmap_path;
+
+ memset(&rmap_path, 0, sizeof(struct bgp_path_info));
+ rmap_path.peer = bgp->peer_self;
+ rmap_path.attr = &attr_tmp;
+
+ SET_FLAG(bgp->peer_self->rmap_type, PEER_RMAP_TYPE_AGGREGATE);
+
+ ret = route_map_apply(aggregate->rmap.map, p, RMAP_BGP,
+ &rmap_path);
+
+ bgp->peer_self->rmap_type = 0;
+
+ if (ret == RMAP_DENYMATCH) {
+ /* Free uninterned attribute. */
+ bgp_attr_flush(&attr_tmp);
+
+ /* Unintern original. */
+ aspath_unintern(&attr.aspath);
+ return NULL;
+ }
+
+ if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN))
+ bgp_attr_add_gshut_community(&attr_tmp);
+
+ new = bgp_attr_intern(&attr_tmp);
+ } else {
+
+ if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN))
+ bgp_attr_add_gshut_community(&attr);
+
+ new = bgp_attr_intern(&attr);
+ }
aspath_unintern(&new->aspath);
return new;
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index 1592a8df4e..f1a871fe43 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -272,8 +272,9 @@ extern struct attr *bgp_attr_aggregate_intern(struct bgp *bgp, uint8_t origin,
struct community *community,
struct ecommunity *ecommunity,
struct lcommunity *lcommunity,
- int as_set,
- uint8_t atomic_aggregate);
+ struct bgp_aggregate *aggregate,
+ uint8_t atomic_aggregate,
+ struct prefix *p);
extern bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *,
struct stream *, struct attr *,
struct bpacket_attr_vec_arr *vecarr,
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index 6c77f18f33..50fef00a96 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -5668,6 +5668,8 @@ int bgp_evpn_local_l3vni_del(vni_t l3vni, vrf_id_t vrf_id)
for (ALL_LIST_ELEMENTS(bgp_vrf->l2vnis, node, next, vpn))
bgpevpn_unlink_from_l3vni(vpn);
+ UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY);
+
/* Delete the instance if it was autocreated */
if (CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_AUTO))
bgp_delete(bgp_vrf);
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 32c9fb16f3..5eeab36742 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -5704,6 +5704,8 @@ static struct bgp_aggregate *bgp_aggregate_new(void)
static void bgp_aggregate_free(struct bgp_aggregate *aggregate)
{
+ XFREE(MTYPE_ROUTE_MAP_NAME, aggregate->rmap.name);
+ route_map_counter_decrement(aggregate->rmap.map);
XFREE(MTYPE_BGP_AGGREGATE, aggregate);
}
@@ -5754,6 +5756,7 @@ static void bgp_aggregate_install(struct bgp *bgp, afi_t afi, safi_t safi,
struct bgp_node *rn;
struct bgp_table *table;
struct bgp_path_info *pi, *orig, *new;
+ struct attr *attr;
table = bgp->rib[afi][safi];
@@ -5791,14 +5794,18 @@ static void bgp_aggregate_install(struct bgp *bgp, afi_t afi, safi_t safi,
if (pi)
bgp_path_info_delete(rn, pi);
+ attr = bgp_attr_aggregate_intern(
+ bgp, origin, aspath, community, ecommunity, lcommunity,
+ aggregate, atomic_aggregate, p);
+
+ if (!attr) {
+ bgp_aggregate_delete(bgp, p, afi, safi, aggregate);
+ return;
+ }
+
new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_AGGREGATE, 0,
- bgp->peer_self,
- bgp_attr_aggregate_intern(bgp, origin, aspath,
- community, ecommunity,
- lcommunity,
- aggregate->as_set,
- atomic_aggregate),
- rn);
+ bgp->peer_self, attr, rn);
+
SET_FLAG(new->flags, BGP_PATH_VALID);
bgp_path_info_add(rn, new);
@@ -5821,7 +5828,7 @@ static void bgp_aggregate_install(struct bgp *bgp, afi_t afi, safi_t safi,
}
/* Update an aggregate as routes are added/removed from the BGP table */
-static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p,
+void bgp_aggregate_route(struct bgp *bgp, struct prefix *p,
afi_t afi, safi_t safi,
struct bgp_aggregate *aggregate)
{
@@ -5982,7 +5989,7 @@ static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p,
aggregate);
}
-static void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi,
+void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi,
safi_t safi, struct bgp_aggregate *aggregate)
{
struct bgp_table *table;
@@ -6426,7 +6433,8 @@ static int bgp_aggregate_unset(struct vty *vty, const char *prefix_str,
}
static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi,
- safi_t safi, uint8_t summary_only, uint8_t as_set)
+ safi_t safi, const char *rmap, uint8_t summary_only,
+ uint8_t as_set)
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
int ret;
@@ -6451,8 +6459,9 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi,
/* Old configuration check. */
rn = bgp_node_get(bgp->aggregate[afi][safi], &p);
+ aggregate = bgp_node_get_bgp_aggregate_info(rn);
- if (bgp_node_has_bgp_path_info_data(rn)) {
+ if (aggregate) {
vty_out(vty, "There is already same aggregate network.\n");
/* try to remove the old entry */
ret = bgp_aggregate_unset(vty, prefix_str, afi, safi);
@@ -6468,6 +6477,15 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi,
aggregate->summary_only = summary_only;
aggregate->as_set = as_set;
aggregate->safi = safi;
+
+ if (rmap) {
+ XFREE(MTYPE_ROUTE_MAP_NAME, aggregate->rmap.name);
+ route_map_counter_decrement(aggregate->rmap.map);
+ aggregate->rmap.name =
+ XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
+ aggregate->rmap.map = route_map_lookup_by_name(rmap);
+ route_map_counter_increment(aggregate->rmap.map);
+ }
bgp_node_set_bgp_aggregate_info(rn, aggregate);
/* Aggregate address insert into BGP routing table. */
@@ -6478,17 +6496,20 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi,
DEFUN (aggregate_address,
aggregate_address_cmd,
- "aggregate-address A.B.C.D/M [<as-set [summary-only]|summary-only [as-set]>]",
+ "aggregate-address A.B.C.D/M [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD]",
"Configure BGP aggregate entries\n"
"Aggregate prefix\n"
"Generate AS set path information\n"
"Filter more specific routes from updates\n"
"Filter more specific routes from updates\n"
- "Generate AS set path information\n")
+ "Generate AS set path information\n"
+ "Apply route map to aggregate network\n"
+ "Name of route map\n")
{
int idx = 0;
argv_find(argv, argc, "A.B.C.D/M", &idx);
char *prefix = argv[idx]->arg;
+ char *rmap = NULL;
int as_set =
argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : 0;
idx = 0;
@@ -6496,25 +6517,33 @@ DEFUN (aggregate_address,
? AGGREGATE_SUMMARY_ONLY
: 0;
+ idx = 0;
+ argv_find(argv, argc, "WORD", &idx);
+ if (idx)
+ rmap = argv[idx]->arg;
+
return bgp_aggregate_set(vty, prefix, AFI_IP, bgp_node_safi(vty),
- summary_only, as_set);
+ rmap, summary_only, as_set);
}
DEFUN (aggregate_address_mask,
aggregate_address_mask_cmd,
- "aggregate-address A.B.C.D A.B.C.D [<as-set [summary-only]|summary-only [as-set]>]",
+ "aggregate-address A.B.C.D A.B.C.D [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD]",
"Configure BGP aggregate entries\n"
"Aggregate address\n"
"Aggregate mask\n"
"Generate AS set path information\n"
"Filter more specific routes from updates\n"
"Filter more specific routes from updates\n"
- "Generate AS set path information\n")
+ "Generate AS set path information\n"
+ "Apply route map to aggregate network\n"
+ "Name of route map\n")
{
int idx = 0;
argv_find(argv, argc, "A.B.C.D", &idx);
char *prefix = argv[idx]->arg;
char *mask = argv[idx + 1]->arg;
+ char *rmap = NULL;
int as_set =
argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : 0;
idx = 0;
@@ -6522,6 +6551,10 @@ DEFUN (aggregate_address_mask,
? AGGREGATE_SUMMARY_ONLY
: 0;
+ argv_find(argv, argc, "WORD", &idx);
+ if (idx)
+ rmap = argv[idx]->arg;
+
char prefix_str[BUFSIZ];
int ret = netmask_str2prefix_str(prefix, mask, prefix_str);
@@ -6531,7 +6564,7 @@ DEFUN (aggregate_address_mask,
}
return bgp_aggregate_set(vty, prefix_str, AFI_IP, bgp_node_safi(vty),
- summary_only, as_set);
+ rmap, summary_only, as_set);
}
DEFUN (no_aggregate_address,
@@ -6581,17 +6614,20 @@ DEFUN (no_aggregate_address_mask,
DEFUN (ipv6_aggregate_address,
ipv6_aggregate_address_cmd,
- "aggregate-address X:X::X:X/M [<as-set [summary-only]|summary-only [as-set]>]",
+ "aggregate-address X:X::X:X/M [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD]",
"Configure BGP aggregate entries\n"
"Aggregate prefix\n"
"Generate AS set path information\n"
"Filter more specific routes from updates\n"
"Filter more specific routes from updates\n"
- "Generate AS set path information\n")
+ "Generate AS set path information\n"
+ "Apply route map to aggregate network\n"
+ "Name of route map\n")
{
int idx = 0;
argv_find(argv, argc, "X:X::X:X/M", &idx);
char *prefix = argv[idx]->arg;
+ char *rmap = NULL;
int as_set =
argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : 0;
@@ -6599,8 +6635,13 @@ DEFUN (ipv6_aggregate_address,
int sum_only = argv_find(argv, argc, "summary-only", &idx)
? AGGREGATE_SUMMARY_ONLY
: 0;
- return bgp_aggregate_set(vty, prefix, AFI_IP6, SAFI_UNICAST, sum_only,
- as_set);
+
+ argv_find(argv, argc, "WORD", &idx);
+ if (idx)
+ rmap = argv[idx]->arg;
+
+ return bgp_aggregate_set(vty, prefix, AFI_IP6, SAFI_UNICAST, rmap,
+ sum_only, as_set);
}
DEFUN (no_ipv6_aggregate_address,
@@ -12467,6 +12508,9 @@ void bgp_config_write_network(struct vty *vty, struct bgp *bgp, afi_t afi,
if (bgp_aggregate->summary_only)
vty_out(vty, " summary-only");
+ if (bgp_aggregate->rmap.name)
+ vty_out(vty, " route-map %s", bgp_aggregate->rmap.name);
+
vty_out(vty, "\n");
}
}
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index 704cd39710..ba4e32c23d 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -313,7 +313,10 @@ struct bgp_aggregate {
uint8_t as_set;
/* Route-map for aggregated route. */
- struct route_map *map;
+ struct {
+ char *name;
+ struct route_map *map;
+ } rmap;
/* Suppress-count. */
unsigned long count;
@@ -545,6 +548,10 @@ extern void bgp_config_write_network(struct vty *, struct bgp *, afi_t, safi_t);
extern void bgp_config_write_distance(struct vty *, struct bgp *, afi_t,
safi_t);
+extern void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi,
+ safi_t safi, struct bgp_aggregate *aggregate);
+extern void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, afi_t afi,
+ safi_t safi, struct bgp_aggregate *aggregate);
extern void bgp_aggregate_increment(struct bgp *bgp, struct prefix *p,
struct bgp_path_info *path, afi_t afi,
safi_t safi);
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 545ca19762..b1f1819b6b 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -269,7 +269,8 @@ route_match_peer(void *rule, const struct prefix *prefix,
/* If su='0.0.0.0' (command 'match peer local'), and it's a
NETWORK,
- REDISTRIBUTE or DEFAULT_GENERATED route => return RMAP_MATCH
+ REDISTRIBUTE, AGGREGATE-ADDRESS or DEFAULT_GENERATED route
+ => return RMAP_MATCH
*/
if (sockunion_same(su, &su_def)) {
int ret;
@@ -277,6 +278,8 @@ route_match_peer(void *rule, const struct prefix *prefix,
|| CHECK_FLAG(peer->rmap_type,
PEER_RMAP_TYPE_REDISTRIBUTE)
|| CHECK_FLAG(peer->rmap_type,
+ PEER_RMAP_TYPE_AGGREGATE)
+ || CHECK_FLAG(peer->rmap_type,
PEER_RMAP_TYPE_DEFAULT))
ret = RMAP_MATCH;
else
@@ -3248,6 +3251,7 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,
struct peer *peer;
struct bgp_node *bn;
struct bgp_static *bgp_static;
+ struct bgp_aggregate *aggregate;
struct listnode *node, *nnode;
struct route_map *map;
char buf[INET6_ADDRSTRLEN];
@@ -3331,6 +3335,35 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,
safi);
}
}
+
+ /* For aggregate-address route-map updates. */
+ for (bn = bgp_table_top(bgp->aggregate[afi][safi]); bn;
+ bn = bgp_route_next(bn)) {
+ aggregate = bgp_node_get_bgp_aggregate_info(bn);
+ if (!aggregate)
+ continue;
+
+ if (!aggregate->rmap.name
+ || (strcmp(rmap_name, aggregate->rmap.name) != 0))
+ continue;
+
+ if (!aggregate->rmap.map)
+ route_map_counter_increment(map);
+
+ aggregate->rmap.map = map;
+
+ if (route_update) {
+ if (bgp_debug_zebra(&bn->p))
+ zlog_debug(
+ "Processing route_map %s update on aggregate-address route %s",
+ rmap_name,
+ inet_ntop(bn->p.family,
+ &bn->p.u.prefix, buf,
+ INET6_ADDRSTRLEN));
+ bgp_aggregate_route(bgp, &bn->p, afi, safi,
+ aggregate);
+ }
+ }
}
/* For redistribute route-map updates. */
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index e9b07bc403..9d45d96987 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -1211,6 +1211,7 @@ struct peer {
#define PEER_RMAP_TYPE_NOSET (1 << 5) /* not allow to set commands */
#define PEER_RMAP_TYPE_IMPORT (1 << 6) /* neighbor route-map import */
#define PEER_RMAP_TYPE_EXPORT (1 << 7) /* neighbor route-map export */
+#define PEER_RMAP_TYPE_AGGREGATE (1 << 8) /* aggregate-address route-map */
/* peer specific BFD information */
struct bfd_info *bfd_info;
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index 7883d0e4c6..7b3cdf2c4b 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -685,6 +685,11 @@ Route Aggregation-IPv4 Address Family
This command specifies an aggregate address.
+.. index:: aggregate-address A.B.C.D/M route-map NAME
+.. clicmd:: aggregate-address A.B.C.D/M route-map NAME
+
+ Apply a route-map for an aggregated prefix.
+
.. index:: aggregate-address A.B.C.D/M as-set
.. clicmd:: aggregate-address A.B.C.D/M as-set
@@ -699,11 +704,11 @@ Route Aggregation-IPv4 Address Family
.. index:: no aggregate-address A.B.C.D/M
.. clicmd:: no aggregate-address A.B.C.D/M
-
+
This command removes an aggregate address.
- This configuration example setup the aggregate-address under
+ This configuration example setup the aggregate-address under
ipv4 address-family.
.. code-block:: frr
@@ -713,6 +718,7 @@ Route Aggregation-IPv4 Address Family
aggregate-address 10.0.0.0/8
aggregate-address 20.0.0.0/8 as-set
aggregate-address 40.0.0.0/8 summary-only
+ aggregate-address 50.0.0.0/8 route-map aggr-rmap
exit-address-family
@@ -726,6 +732,11 @@ Route Aggregation-IPv6 Address Family
This command specifies an aggregate address.
+.. index:: aggregate-address X:X::X:X/M route-map NAME
+.. clicmd:: aggregate-address X:X::X:X/M route-map NAME
+
+ Apply a route-map for an aggregated prefix.
+
.. index:: aggregate-address X:X::X:X/M as-set
.. clicmd:: aggregate-address X:X::X:X/M as-set
@@ -744,16 +755,17 @@ Route Aggregation-IPv6 Address Family
This command removes an aggregate address.
- This configuration example setup the aggregate-address under
- ipv4 address-family.
+ This configuration example setup the aggregate-address under
+ ipv6 address-family.
.. code-block:: frr
router bgp 1
address-family ipv6 unicast
aggregate-address 10::0/64
- aggregate-address 20::0/64 as-set
- aggregate-address 40::0/64 summary-only
+ aggregate-address 20::0/64 as-set
+ aggregate-address 40::0/64 summary-only
+ aggregate-address 50::0/64 route-map aggr-rmap
exit-address-family
.. _bgp-redistribute-to-bgp:
@@ -2321,7 +2333,7 @@ attribute.
Displaying Routes by Large Community Attribute
----------------------------------------------
-The following commands allow displaying routes based on their
+The following commands allow displaying routes based on their
large community attribute.
.. index:: show [ip] bgp <ipv4|ipv6> large-community
@@ -2338,8 +2350,8 @@ large community attribute.
These commands display BGP routes which have the large community attribute.
attribute. When ``LARGE-COMMUNITY`` is specified, BGP routes that match that
- large community are displayed. When `exact-match` is specified, it display
- only routes that have an exact match. When `json` is specified, it display
+ large community are displayed. When `exact-match` is specified, it display
+ only routes that have an exact match. When `json` is specified, it display
routes in json format.
.. index:: show [ip] bgp <ipv4|ipv6> large-community-list WORD
@@ -2352,8 +2364,8 @@ large community attribute.
.. clicmd:: show [ip] bgp <ipv4|ipv6> large-community-list WORD json
These commands display BGP routes for the address family specified that
- match the specified large community list. When `exact-match` is specified,
- it displays only routes that have an exact match. When `json` is specified,
+ match the specified large community list. When `exact-match` is specified,
+ it displays only routes that have an exact match. When `json` is specified,
it display routes in json format.
.. _bgp-display-routes-by-as-path:
diff --git a/tests/topotests/bgp_aggregate-address_route-map/__init__.py b/tests/topotests/bgp_aggregate-address_route-map/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_aggregate-address_route-map/__init__.py
diff --git a/tests/topotests/bgp_aggregate-address_route-map/r1/bgpd.conf b/tests/topotests/bgp_aggregate-address_route-map/r1/bgpd.conf
new file mode 100644
index 0000000000..ef34817bb1
--- /dev/null
+++ b/tests/topotests/bgp_aggregate-address_route-map/r1/bgpd.conf
@@ -0,0 +1,10 @@
+router bgp 65000
+ neighbor 192.168.255.2 remote-as 65001
+ address-family ipv4 unicast
+ redistribute connected
+ aggregate-address 172.16.255.0/24 route-map aggr-rmap
+ exit-address-family
+!
+route-map aggr-rmap permit 10
+ set metric 123
+!
diff --git a/tests/topotests/bgp_aggregate-address_route-map/r1/zebra.conf b/tests/topotests/bgp_aggregate-address_route-map/r1/zebra.conf
new file mode 100644
index 0000000000..0a283c06d5
--- /dev/null
+++ b/tests/topotests/bgp_aggregate-address_route-map/r1/zebra.conf
@@ -0,0 +1,9 @@
+!
+interface lo
+ ip address 172.16.255.254/32
+!
+interface r1-eth0
+ ip address 192.168.255.1/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_aggregate-address_route-map/r2/bgpd.conf b/tests/topotests/bgp_aggregate-address_route-map/r2/bgpd.conf
new file mode 100644
index 0000000000..73d4d0aeea
--- /dev/null
+++ b/tests/topotests/bgp_aggregate-address_route-map/r2/bgpd.conf
@@ -0,0 +1,4 @@
+router bgp 65001
+ neighbor 192.168.255.1 remote-as 65000
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_aggregate-address_route-map/r2/zebra.conf b/tests/topotests/bgp_aggregate-address_route-map/r2/zebra.conf
new file mode 100644
index 0000000000..606c17bec9
--- /dev/null
+++ b/tests/topotests/bgp_aggregate-address_route-map/r2/zebra.conf
@@ -0,0 +1,6 @@
+!
+interface r2-eth0
+ ip address 192.168.255.2/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py b/tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py
new file mode 100644
index 0000000000..387d25d0f8
--- /dev/null
+++ b/tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py
@@ -0,0 +1,109 @@
+#!/usr/bin/env python
+
+#
+# bgp_aggregate-address_route-map.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2019 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+bgp_aggregate-address_route-map.py:
+
+Test if works the following commands:
+router bgp 65031
+ address-family ipv4 unicast
+ aggregate-address 192.168.255.0/24 route-map aggr-rmap
+
+route-map aggr-rmap permit 10
+ set metric 123
+"""
+
+import os
+import sys
+import json
+import time
+import pytest
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+from mininet.topo import Topo
+
+class TemplateTopo(Topo):
+ def build(self, *_args, **_opts):
+ tgen = get_topogen(self)
+
+ for routern in range(1, 3):
+ tgen.add_router('r{}'.format(routern))
+
+ switch = tgen.add_switch('s1')
+ switch.add_link(tgen.gears['r1'])
+ switch.add_link(tgen.gears['r2'])
+
+def setup_module(mod):
+ tgen = Topogen(TemplateTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.iteritems(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA,
+ os.path.join(CWD, '{}/zebra.conf'.format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP,
+ os.path.join(CWD, '{}/bgpd.conf'.format(rname))
+ )
+
+ tgen.start_router()
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+def test_bgp_maximum_prefix_invalid():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ def _bgp_converge(router):
+ while True:
+ output = json.loads(tgen.gears[router].vtysh_cmd("show ip bgp neighbor 192.168.255.1 json"))
+ if output['192.168.255.1']['bgpState'] == 'Established':
+ if output['192.168.255.1']['addressFamilyInfo']['IPv4 Unicast']['acceptedPrefixCounter'] == 3:
+ return True
+
+ def _bgp_aggregate_address_has_metric(router):
+ output = json.loads(tgen.gears[router].vtysh_cmd("show ip bgp 172.16.255.0/24 json"))
+ if output['paths'][0]['med'] == 123:
+ return True
+ return False
+
+ if _bgp_converge('r2'):
+ assert _bgp_aggregate_address_has_metric('r2') == True
+
+if __name__ == '__main__':
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index ee2956d3ea..35df02a19a 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -122,6 +122,33 @@ static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop,
_nexthop_add(&nexthop->resolved, resolved_hop);
}
+/* Checks if nexthop we are trying to resolve to is valid */
+static bool nexthop_valid_resolve(const struct nexthop *nexthop,
+ const struct nexthop *resolved)
+{
+ /* Can't resolve to a recursive nexthop */
+ if (CHECK_FLAG(resolved->flags, NEXTHOP_FLAG_RECURSIVE))
+ return false;
+
+ switch (nexthop->type) {
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ /* If the nexthop we are resolving to does not match the
+ * ifindex for the nexthop the route wanted, its not valid.
+ */
+ if (nexthop->ifindex != resolved->ifindex)
+ return false;
+ break;
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IFINDEX:
+ case NEXTHOP_TYPE_BLACKHOLE:
+ break;
+ }
+
+ return true;
+}
+
/*
* Given a nexthop we need to properly recursively resolve
* the route. As such, do a table lookup to find and match
@@ -287,8 +314,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
if (!CHECK_FLAG(match->status,
ROUTE_ENTRY_INSTALLED))
continue;
- if (CHECK_FLAG(newhop->flags,
- NEXTHOP_FLAG_RECURSIVE))
+ if (!nexthop_valid_resolve(nexthop, newhop))
continue;
SET_FLAG(nexthop->flags,
@@ -308,8 +334,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
if (!CHECK_FLAG(match->status,
ROUTE_ENTRY_INSTALLED))
continue;
- if (CHECK_FLAG(newhop->flags,
- NEXTHOP_FLAG_RECURSIVE))
+ if (!nexthop_valid_resolve(nexthop, newhop))
continue;
SET_FLAG(nexthop->flags,