diff options
-rw-r--r-- | ChangeLog | 64 | ||||
-rw-r--r-- | bgpd/bgp_attr.c | 3 | ||||
-rw-r--r-- | bgpd/bgp_route.c | 1529 | ||||
-rw-r--r-- | bgpd/bgp_route.h | 15 | ||||
-rw-r--r-- | bgpd/bgp_routemap.c | 161 | ||||
-rw-r--r-- | bgpd/bgp_table.c | 3 | ||||
-rw-r--r-- | bgpd/bgp_table.h | 11 | ||||
-rw-r--r-- | bgpd/bgp_vty.c | 692 | ||||
-rw-r--r-- | bgpd/bgpd.c | 193 | ||||
-rw-r--r-- | bgpd/bgpd.h | 22 | ||||
-rw-r--r-- | lib/routemap.c | 131 | ||||
-rw-r--r-- | lib/routemap.h | 6 |
12 files changed, 2656 insertions, 174 deletions
@@ -1,3 +1,67 @@ +2004-09-13 Jose Luis Rubio <jrubio@dit.upm.es> + (at Technical University of Madrid as part of Euro6ix Project) + + Enhanced Route Server functionality and Route-Maps: + + * bgpd/bgpd.h: Modified 'struct peer' and 'struct bgp_filter' to + support rs-clients. A 'struct bgp_table *rib' has been added to the + first (to mantain a separated RIB for each rs-client) and two new + route-maps have been added to the last (for import/export policies). + Added the following #defines: RMAP_{IN|OUT|IMPORT|EXPORT|MAX}, + PEER_RMAP_TYPE_{IMPORT|EXPORT} and BGP_CLEAR_SOFT_RSCLIENT. + + * bgpd/bgpd.c: Modified the functions that create/delete/etc peers in + order to consider the new fields included in 'struct peer' for + supporting rs-clients, i.e. the import/export route-maps and the + 'struct bgp_table'. + + * bgpd/bgp_route.{ch}: Modified several functions related with + receiving/sending announces in order to support the new Route Server + capabilities. + Function 'bgp_process' has been reorganized, creating an auxiliar + function for best path selection ('bgp_best_selection'). + Modified 'bgp_show' and 'bgp_show_route' for displaying information + about any RIB (and not only the main bgp RIB). + Added commands for displaying information about RS-clients RIBs: + 'show bgp rsclient (A.B.C.D|X:X::X:X)', 'show bgp rsclient + (A.B.C.D|X:X::X:X) X:X::X:X/M', etc + + * bgpd/bgp_table.{ch}: The structure 'struct bgp_table' now has two + new fields: type (which can take the values BGP_TABLE_{MAIN|RSCLIENT}) + and 'void *owner' which points to 'struct bgp' or 'struct peer' which + owns the table. + When creating a new bgp_table by default 'type=BGP_TABLE_MAIN' is set. + + * bgpd/bgp_vty.c: The commands 'neighbor ... route-server-client' and + 'no neighbor ... route-server-client' now not only set/unset the flag + PEER_FLAG_RSERVER_CLIENT, but they create/destroy the 'struct + bgp_table' of the peer. Special actions are taken for peer_groups. + Command 'neighbor ... route-map WORD (in|out)' now also supports two + new kinds of route-map: 'import' and 'export'. + Added commands 'clear bgp * rsclient', etc. These commands allow a new + kind of soft_reconfig which affects only the RIB of the specified + RS-client. + Added commands 'show bgp rsclient summary', etc which display a + summary of the rs-clients configured for the corresponding address + family. + + * bgpd/bgp_routemap.c: A new match statement is available, + 'match peer (A.B.C.D|X:X::X:X)'. This statement can only be used in + import/export route-maps, and it matches when the peer who announces + (when used in an import route-map) or is going to receive (when used + in an export route-map) the route is the same than the one specified + in the statement. + For peer-groups the statement matches if the specified peer is member + of the peer-group. + A special version of the command, 'match peer local', matches with + routes originated by the Route Server (defined with 'network ...', + redistributed routes and default-originate). + + * lib/routemap.{ch}: Added a new clause 'call NAME' for use in + route-maps. It jumps into the specified route-map and when it returns + the first route-map ends if the called RM returns DENY_MATCH, or + continues in other case. + 2004-08-31 Greg Troxel <gdt@poblano.ir.bbn.com> * Makefile.am: make m4 as subdir, rather the EXTRA_DISTing it diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index d745d871..c8f5ed62 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1365,8 +1365,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, if (peer_sort (peer) == BGP_PEER_EBGP && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED) || attr->aspath->length == 0) - && ! (CHECK_FLAG (from->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) - && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT))) + && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT))) { aspath = aspath_dup (attr->aspath); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index cf65964b..6b49e2c8 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -58,16 +58,15 @@ extern char *bgp_origin_str[]; extern char *bgp_origin_long_str[]; struct bgp_node * -bgp_afi_node_get (struct bgp *bgp, afi_t afi, safi_t safi, struct prefix *p, +bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix *p, struct prefix_rd *prd) { struct bgp_node *rn; struct bgp_node *prn = NULL; - struct bgp_table *table; if (safi == SAFI_MPLS_VPN) { - prn = bgp_node_get (bgp->rib[afi][safi], (struct prefix *) prd); + prn = bgp_node_get (table, (struct prefix *) prd); if (prn->info == NULL) prn->info = bgp_table_init (); @@ -75,8 +74,6 @@ bgp_afi_node_get (struct bgp *bgp, afi_t afi, safi_t safi, struct prefix *p, bgp_unlock_node (prn); table = prn->info; } - else - table = bgp->rib[afi][safi]; rn = bgp_node_get (table, p); @@ -455,6 +452,77 @@ bgp_input_modifier (struct peer *peer, struct prefix *p, struct attr *attr, } int +bgp_export_modifier (struct peer *rsclient, struct peer *peer, + struct prefix *p, struct attr *attr, afi_t afi, safi_t safi) +{ + struct bgp_filter *filter; + struct bgp_info info; + route_map_result_t ret; + + filter = &peer->filter[afi][safi]; + + /* Route map apply. */ + if (ROUTE_MAP_EXPORT_NAME (filter)) + { + /* Duplicate current value to new strucutre for modification. */ + info.peer = rsclient; + info.attr = attr; + + SET_FLAG (rsclient->rmap_type, PEER_RMAP_TYPE_EXPORT); + + /* Apply BGP route map to the attribute. */ + ret = route_map_apply (ROUTE_MAP_EXPORT (filter), p, RMAP_BGP, &info); + + rsclient->rmap_type = 0; + + if (ret == RMAP_DENYMATCH) + { + /* Free newly generated AS path and community by route-map. */ + bgp_attr_flush (attr); + return RMAP_DENY; + } + } + return RMAP_PERMIT; +} + +int +bgp_import_modifier (struct peer *rsclient, struct peer *peer, + struct prefix *p, struct attr *attr, afi_t afi, safi_t safi) +{ + struct bgp_filter *filter; + struct bgp_info info; + route_map_result_t ret; + + filter = &rsclient->filter[afi][safi]; + + /* Apply default weight value. */ + attr->weight = peer->weight; + + /* Route map apply. */ + if (ROUTE_MAP_IMPORT_NAME (filter)) + { + /* Duplicate current value to new strucutre for modification. */ + info.peer = peer; + info.attr = attr; + + SET_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IMPORT); + + /* Apply BGP route map to the attribute. */ + ret = route_map_apply (ROUTE_MAP_IMPORT (filter), p, RMAP_BGP, &info); + + peer->rmap_type = 0; + + if (ret == RMAP_DENYMATCH) + { + /* Free newly generated AS path and community by route-map. */ + bgp_attr_flush (attr); + return RMAP_DENY; + } + } + return RMAP_PERMIT; +} + +int bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, struct attr *attr, afi_t afi, safi_t safi) { @@ -476,6 +544,10 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, return 0; #endif + /* Do not send announces to RS-clients from the 'normal' bgp_table. */ + if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) + return 0; + /* Do not send back route to sender. */ if (from == peer) return 0; @@ -636,7 +708,8 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, || (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED) && ((p->family == AF_INET && attr->nexthop.s_addr) #ifdef HAVE_IPV6 - || (p->family == AF_INET6 && ri->peer != bgp->peer_self) + || (p->family == AF_INET6 && + ! IN6_IS_ADDR_UNSPECIFIED(&attr->mp_nexthop_global)) #endif /* HAVE_IPV6 */ ))) { @@ -645,7 +718,8 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, else if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF) || (p->family == AF_INET && attr->nexthop.s_addr == 0) #ifdef HAVE_IPV6 - || (p->family == AF_INET6 && ri->peer == bgp->peer_self) + || (p->family == AF_INET6 && + IN6_IS_ADDR_UNSPECIFIED(&attr->mp_nexthop_global)) #endif /* HAVE_IPV6 */ || (peer_sort (peer) == BGP_PEER_EBGP && bgp_multiaccess_check_v4 (attr->nexthop, peer->host) == 0)) @@ -673,6 +747,19 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, #ifdef HAVE_IPV6 if (p->family == AF_INET6) { + /* Left nexthop_local unchanged if so configured. */ + if ( CHECK_FLAG (peer->af_flags[afi][safi], + PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED) ) + { + if ( IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_local) ) + attr->mp_nexthop_len=32; + else + attr->mp_nexthop_len=16; + } + + /* Default nexthop_local treatment for non-RS-Clients */ + else + { /* Link-local address should not be transit to different peer. */ attr->mp_nexthop_len = 16; @@ -694,6 +781,8 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, if (! IN6_IS_ADDR_LINKLOCAL (&peer->nexthop.v6_local)) attr->mp_nexthop_len = 16; } + + } #endif /* HAVE_IPV6 */ /* If this is EBGP peer and remove-private-AS is set. */ @@ -737,20 +826,217 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, } int -bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi) +bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient, + struct prefix *p, struct attr *attr, afi_t afi, safi_t safi) +{ + int ret; + char buf[SU_ADDRSTRLEN]; + struct bgp_filter *filter; + struct bgp_info info; + struct peer *from; + struct bgp *bgp; + + from = ri->peer; + filter = &rsclient->filter[afi][safi]; + bgp = rsclient->bgp; + +#ifdef DISABLE_BGP_ANNOUNCE + return 0; +#endif + + /* Do not send back route to sender. */ + if (from == rsclient) + return 0; + + /* Aggregate-address suppress check. */ + if (ri->suppress) + if (! UNSUPPRESS_MAP_NAME (filter)) + return 0; + + /* Default route check. */ + if (CHECK_FLAG (rsclient->af_sflags[afi][safi], + PEER_STATUS_DEFAULT_ORIGINATE)) + { + if (p->family == AF_INET && p->u.prefix4.s_addr == INADDR_ANY) + return 0; +#ifdef HAVE_IPV6 + else if (p->family == AF_INET6 && p->prefixlen == 0) + return 0; +#endif /* HAVE_IPV6 */ + } + + /* If the attribute has originator-id and it is same as remote + peer's id. */ + if (ri->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID)) + { + if (IPV4_ADDR_SAME (&rsclient->remote_id, &ri->attr->originator_id)) + { + if (BGP_DEBUG (filter, FILTER)) + zlog (rsclient->log, LOG_INFO, + "%s [Update:SEND] %s/%d originator-id is same as remote router-id", + rsclient->host, + inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen); + return 0; + } + } + + /* ORF prefix-list filter check */ + if (CHECK_FLAG (rsclient->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV) + && (CHECK_FLAG (rsclient->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV) + || CHECK_FLAG (rsclient->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV))) + if (rsclient->orf_plist[afi][safi]) + { + if (prefix_list_apply (rsclient->orf_plist[afi][safi], p) == PREFIX_DENY) + return 0; + } + + /* Output filter check. */ + if (bgp_output_filter (rsclient, p, ri->attr, afi, safi) == FILTER_DENY) + { + if (BGP_DEBUG (filter, FILTER)) + zlog (rsclient->log, LOG_INFO, + "%s [Update:SEND] %s/%d is filtered", + rsclient->host, + inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen); + return 0; + } + +#ifdef BGP_SEND_ASPATH_CHECK + /* AS path loop check. */ + if (aspath_loop_check (ri->attr->aspath, rsclient->as)) + { + if (BGP_DEBUG (filter, FILTER)) + zlog (rsclient->log, LOG_INFO, + "%s [Update:SEND] suppress announcement to peer AS %d is AS path.", + rsclient->host, rsclient->as); + return 0; + } +#endif /* BGP_SEND_ASPATH_CHECK */ + + /* For modify attribute, copy it to temporary structure. */ + *attr = *ri->attr; + + /* next-hop-set */ + if ((p->family == AF_INET && attr->nexthop.s_addr == 0) +#ifdef HAVE_IPV6 + || (p->family == AF_INET6 && + IN6_IS_ADDR_UNSPECIFIED(&attr->mp_nexthop_global)) +#endif /* HAVE_IPV6 */ + ) + { + /* Set IPv4 nexthop. */ + if (p->family == AF_INET) + { + if (safi == SAFI_MPLS_VPN) + memcpy (&attr->mp_nexthop_global_in, &rsclient->nexthop.v4, + IPV4_MAX_BYTELEN); + else + memcpy (&attr->nexthop, &rsclient->nexthop.v4, IPV4_MAX_BYTELEN); + } +#ifdef HAVE_IPV6 + /* Set IPv6 nexthop. */ + if (p->family == AF_INET6) + { + /* IPv6 global nexthop must be included. */ + memcpy (&attr->mp_nexthop_global, &rsclient->nexthop.v6_global, + + IPV6_MAX_BYTELEN); + attr->mp_nexthop_len = 16; + } +#endif /* HAVE_IPV6 */ + } + +#ifdef HAVE_IPV6 + if (p->family == AF_INET6) + { + /* Left nexthop_local unchanged if so configured. */ + if ( CHECK_FLAG (rsclient->af_flags[afi][safi], + PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED) ) + { + if ( IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_local) ) + attr->mp_nexthop_len=32; + else + attr->mp_nexthop_len=16; + } + + /* Default nexthop_local treatment for RS-Clients */ + else + { + /* Announcer and RS-Client are both in the same network */ + if (rsclient->shared_network && from->shared_network && + (rsclient->ifindex == from->ifindex)) + { + if ( IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_local) ) + attr->mp_nexthop_len=32; + else + attr->mp_nexthop_len=16; + } + + /* Set link-local address for shared network peer. */ + else if (rsclient->shared_network + && IN6_IS_ADDR_LINKLOCAL (&rsclient->nexthop.v6_local)) + { + memcpy (&attr->mp_nexthop_local, &rsclient->nexthop.v6_local, + IPV6_MAX_BYTELEN); + attr->mp_nexthop_len = 32; + } + + else + attr->mp_nexthop_len = 16; + } + + } +#endif /* HAVE_IPV6 */ + + + /* If this is EBGP peer and remove-private-AS is set. */ + if (peer_sort (rsclient) == BGP_PEER_EBGP + && peer_af_flag_check (rsclient, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS) + && aspath_private_as_check (attr->aspath)) + attr->aspath = aspath_empty_get (); + + /* Route map & unsuppress-map apply. */ + if (ROUTE_MAP_OUT_NAME (filter) || ri->suppress) + { + info.peer = rsclient; + info.attr = attr; + + SET_FLAG (rsclient->rmap_type, PEER_RMAP_TYPE_OUT); + + if (ri->suppress) + ret = route_map_apply (UNSUPPRESS_MAP (filter), p, RMAP_BGP, &info); + else + ret = route_map_apply (ROUTE_MAP_OUT (filter), p, RMAP_BGP, &info); + + rsclient->rmap_type = 0; + + if (ret == RMAP_DENYMATCH) + { + bgp_attr_flush (attr); + return 0; + } + } + + return 1; +} + +struct bgp_info_pair +{ + struct bgp_info *old; + struct bgp_info *new; +}; + +void +bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, struct bgp_info_pair *result) { - struct prefix *p; - struct bgp_info *ri; struct bgp_info *new_select; struct bgp_info *old_select; - struct listnode *nn; - struct peer *peer; - struct attr attr; + struct bgp_info *ri; struct bgp_info *ri1; struct bgp_info *ri2; - p = &rn->p; - /* bgp deterministic-med */ new_select = NULL; if (bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)) @@ -811,17 +1097,8 @@ bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi) new_select = ri; } - /* Nothing to do. */ - if (old_select && old_select == new_select) - { - if (! CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED)) + if ( (! old_select) || old_select != new_select) { - if (CHECK_FLAG (old_select->flags, BGP_INFO_IGP_CHANGED)) - bgp_zebra_announce (p, old_select, bgp); - return 0; - } - } - if (old_select) UNSET_FLAG (old_select->flags, BGP_INFO_SELECTED); if (new_select) @@ -829,29 +1106,131 @@ bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi) SET_FLAG (new_select->flags, BGP_INFO_SELECTED); UNSET_FLAG (new_select->flags, BGP_INFO_ATTR_CHANGED); } + } - /* Check each BGP peer. */ - LIST_LOOP (bgp->peer, peer, nn) + result->old = old_select; + result->new = new_select; + + return; +} + +int +bgp_process_announce_selected (struct peer *peer, struct bgp_info *selected, + struct bgp_node *rn, struct attr *attr, afi_t afi, safi_t safi) { + struct prefix *p; + + p = &rn->p; + /* Announce route to Established peer. */ if (peer->status != Established) - continue; + return 0; /* Address family configuration check. */ if (! peer->afc_nego[afi][safi]) - continue; + return 0; /* First update is deferred until ORF or ROUTE-REFRESH is received */ - if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH)) - continue; + if (CHECK_FLAG (peer->af_sflags[afi][safi], + PEER_STATUS_ORF_WAIT_REFRESH)) + return 0; + switch (rn->table->type) + { + case BGP_TABLE_MAIN: /* Announcement to peer->conf. If the route is filtered, withdraw it. */ - if (new_select - && bgp_announce_check (new_select, peer, p, &attr, afi, safi)) - bgp_adj_out_set (rn, peer, p, &attr, afi, safi, new_select); + if (selected && bgp_announce_check (selected, peer, p, attr, afi, safi)) + bgp_adj_out_set (rn, peer, p, attr, afi, safi, selected); + else + bgp_adj_out_unset (rn, peer, p, afi, safi); + break; + case BGP_TABLE_RSCLIENT: + /* Announcement to peer->conf. If the route is filtered, + withdraw it. */ + if (selected && bgp_announce_check_rsclient + (selected, peer, p, attr, afi, safi)) + bgp_adj_out_set (rn, peer, p, attr, afi, safi, selected); else bgp_adj_out_unset (rn, peer, p, afi, safi); + break; + } + return 0; + } + +int +bgp_process_rsclient (struct bgp *bgp, struct peer *rsclient, + struct bgp_node *rn, afi_t afi, safi_t safi) +{ + struct prefix *p; + struct bgp_info *new_select; + struct bgp_info *old_select; + struct bgp_info_pair old_and_new; + struct attr attr; + struct peer_group *group; + struct listnode *nn; + + p = &rn->p; + + /* Best path selection. */ + bgp_best_selection (bgp, rn, &old_and_new); + new_select = old_and_new.new; + old_select = old_and_new.old; + + if (CHECK_FLAG(rsclient->sflags, PEER_STATUS_GROUP)) + { + group = rsclient->group; + LIST_LOOP(group->peer, rsclient, nn) + { + /* Nothing to do. */ + if (old_select && old_select == new_select) + if (! CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED)) + continue; + + bgp_process_announce_selected (rsclient, new_select, rn, &attr, + afi, safi); + } + return 0; + } + + bgp_process_announce_selected (rsclient, new_select, rn, &attr, afi, safi); + + return 0; +} + +int +bgp_process_main (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi) + { + struct prefix *p; + struct bgp_info *new_select; + struct bgp_info *old_select; + struct bgp_info_pair old_and_new; + struct listnode *nn; + struct peer *peer; + struct attr attr; + + p = &rn->p; + + /* Best path selection. */ + bgp_best_selection (bgp, rn, &old_and_new); + old_select = old_and_new.old; + new_select = old_and_new.new; + + /* Nothing to do. */ + if (old_select && old_select == new_select) + { + if (! CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED)) + { + if (CHECK_FLAG (old_select->flags, BGP_INFO_IGP_CHANGED)) + bgp_zebra_announce (p, old_select, bgp); + return 0; + } + } + + /* Check each BGP peer. */ + LIST_LOOP (bgp->peer, peer, nn) + { + bgp_process_announce_selected (peer, new_select, rn, &attr, afi, safi); } /* FIB update. */ @@ -875,6 +1254,20 @@ bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi) } int +bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi) +{ + switch (rn->table->type) + { + case BGP_TABLE_MAIN: + return bgp_process_main (bgp, rn, afi, safi); + case BGP_TABLE_RSCLIENT: + return bgp_process_rsclient (bgp, (struct peer *) rn->table->owner, + rn, afi, safi); + } + return 0; +} + +int bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi, safi_t safi, int always) { @@ -940,8 +1333,12 @@ bgp_rib_remove (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer, { if (! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) { + /* Ignore 'pcount' for RS-client tables */ + if ( rn->table->type == BGP_TABLE_MAIN) + { peer->pcount[afi][safi]--; bgp_aggregate_decrement (peer->bgp, &rn->p, ri, afi, safi); + } UNSET_FLAG (ri->flags, BGP_INFO_VALID); bgp_process (peer->bgp, rn, afi, safi); } @@ -957,7 +1354,9 @@ bgp_rib_withdraw (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer, int valid; int status = BGP_DAMP_NONE; - if (! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) + /* Ignore 'pcount' for RS-client tables */ + if (! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY) && + rn->table->type == BGP_TABLE_MAIN) { peer->pcount[afi][safi]--; bgp_aggregate_decrement (peer->bgp, &rn->p, ri, afi, safi); @@ -988,8 +1387,220 @@ bgp_rib_withdraw (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer, } } +void +bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, + struct attr *attr, struct peer *peer, struct prefix *p, int type, + int sub_type, struct prefix_rd *prd, u_char *tag) +{ + struct bgp_node *rn; + struct bgp *bgp; + struct attr new_attr; + struct attr *attr_new; + struct attr *attr_new2; + struct bgp_info *ri; + struct bgp_info *new; + char *reason; + char buf[SU_ADDRSTRLEN]; + + /* Do not insert announces from a rsclient into its own 'bgp_table'. */ + if (peer == rsclient) + return; + + bgp = peer->bgp; + rn = bgp_afi_node_get (rsclient->rib[afi][safi], afi, safi, p, prd); + + /* Check previously received route. */ + for (ri = rn->info; ri; ri = ri->next) + if (ri->peer == peer && ri->type == type && ri->sub_type == sub_type) + break; + + /* AS path loop check. */ + if (aspath_loop_check (attr->aspath, rsclient->as) > peer->allowas_in[afi][safi]) + { + reason = "as-path contains our own AS;"; + goto filtered; + } + + /* Route reflector originator ID check. */ + if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID) + && IPV4_ADDR_SAME (&rsclient->remote_id, &attr->originator_id)) + { + reason = "originator is us;"; + goto filtered; + } + + new_attr = *attr; + + /* Apply export policy. */ + if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) && + bgp_export_modifier (rsclient, peer, p, &new_attr, afi, safi) == RMAP_DENY) + { + reason = "export-policy;"; + goto filtered; + } + + attr_new2 = bgp_attr_intern (&new_attr); + + /* Apply import policy. */ + if (bgp_import_modifier (rsclient, peer, p, &new_attr, afi, safi) == RMAP_DENY) + { + bgp_attr_unintern (attr_new2); + + reason = "import-policy;"; + goto filtered; + } + + attr_new = bgp_attr_intern (&new_attr); + bgp_attr_unintern (attr_new2); + + /* IPv4 unicast next hop check. */ + if (afi == AFI_IP && safi == SAFI_UNICAST) + { + /* Next hop must not be 0.0.0.0 nor Class E address. */ + if (new_attr.nexthop.s_addr == 0 + || ntohl (new_attr.nexthop.s_addr) >= 0xe0000000) + { + bgp_attr_unintern (attr_new); + + reason = "martian next-hop;"; + goto filtered; + } + } + + /* If the update is implicit withdraw. */ + if (ri) + { + ri->uptime = time (NULL); + + /* Same attribute comes in. */ + if (attrhash_cmp (ri->attr, attr_new)) + { + + UNSET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED); + + if (BGP_DEBUG (update, UPDATE_IN)) + zlog (peer->log, LOG_INFO, + "%s rcvd %s/%d for RS-client %s...duplicate ignored", + peer->host, + inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen, rsclient->host); + + bgp_unlock_node (rn); + bgp_attr_unintern (attr_new); + + return; + } + + /* Received Logging. */ + if (BGP_DEBUG (update, UPDATE_IN)) + zlog (peer->log, LOG_INFO, "%s rcvd %s/%d for RS-client %s", + peer->host, + inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen, rsclient->host); + + /* The attribute is changed. */ + SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED); + + /* Update to new attribute. */ + bgp_attr_unintern (ri->attr); + ri->attr = attr_new; + + /* Update MPLS tag. */ + if (safi == SAFI_MPLS_VPN) + memcpy (ri->tag, tag, 3); + + SET_FLAG (ri->flags, BGP_INFO_VALID); + + /* Process change. */ + bgp_process (bgp, rn, afi, safi); + bgp_unlock_node (rn); + + return; + } + + /* Received Logging. */ + if (BGP_DEBUG (update, UPDATE_IN)) + { + zlog (peer->log, LOG_INFO, "%s rcvd %s/%d for RS-client %s", + peer->host, + inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen, rsclient->host); + } + + /* Make new BGP info. */ + new = bgp_info_new (); + new->type = type; + new->sub_type = sub_type; + new->peer = peer; + new->attr = attr_new; + new->uptime = time (NULL); + + /* Update MPLS tag. */ + if (safi == SAFI_MPLS_VPN) + memcpy (new->tag, tag, 3); + + SET_FLAG (new->flags, BGP_INFO_VALID); + + /* Register new BGP information. */ + bgp_info_add (rn, new); + + /* Process change. */ + bgp_process (bgp, rn, afi, safi); + + return; + + filtered: + + /* This BGP update is filtered. Log the reason then update BGP entry. */ + if (BGP_DEBUG (update, UPDATE_IN)) + zlog (peer->log, LOG_INFO, + "%s rcvd UPDATE about %s/%d -- DENIED for RS-client %s due to: %s", + peer->host, + inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen, rsclient->host, reason); + + if (ri) + bgp_rib_withdraw (rn, ri, peer, afi, safi, 1); + + bgp_unlock_node (rn); + + return; +} + +void +bgp_withdraw_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, + struct peer *peer, struct prefix *p, int type, int sub_type, + struct prefix_rd *prd, u_char *tag) + { + struct bgp_node *rn; + struct bgp_info *ri; + char buf[SU_ADDRSTRLEN]; + + if (rsclient == peer) + return; + + rn = bgp_afi_node_get (rsclient->rib[afi][safi], afi, safi, p, prd); + + /* Lookup withdrawn route. */ + for (ri = rn->info; ri; ri = ri->next) + if (ri->peer == peer && ri->type == type && ri->sub_type == sub_type) + break; + + /* Withdraw specified route from routing table. */ + if (ri && ! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) + bgp_rib_withdraw (rn, ri, peer, afi, safi, 0); + else if (BGP_DEBUG (update, UPDATE_IN)) + zlog (peer->log, LOG_INFO, + "%s Can't find the route %s/%d", peer->host, + inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen); + + /* Unlock bgp_node_get() lock. */ + bgp_unlock_node (rn); + } + int -bgp_update (struct peer *peer, struct prefix *p, struct attr *attr, +bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, afi_t afi, safi_t safi, int type, int sub_type, struct prefix_rd *prd, u_char *tag, int soft_reconfig) { @@ -1005,7 +1616,7 @@ bgp_update (struct peer *peer, struct prefix *p, struct attr *attr, char buf[SU_ADDRSTRLEN]; bgp = peer->bgp; - rn = bgp_afi_node_get (bgp, afi, safi, p, prd); + rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd); /* When peer's soft reconfiguration enabled. Record input packet in Adj-RIBs-In. */ @@ -1283,6 +1894,32 @@ bgp_update (struct peer *peer, struct prefix *p, struct attr *attr, } int +bgp_update (struct peer *peer, struct prefix *p, struct attr *attr, + afi_t afi, safi_t safi, int type, int sub_type, + struct prefix_rd *prd, u_char *tag, int soft_reconfig) +{ + struct peer *rsclient; + struct listnode *nn; + struct bgp *bgp; + int ret; + + ret = bgp_update_main (peer, p, attr, afi, safi, type, sub_type, prd, tag, + soft_reconfig); + + bgp = peer->bgp; + + /* Process the update for each RS-client. */ + LIST_LOOP(bgp->rsclient, rsclient, nn) + { + if (CHECK_FLAG (rsclient->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) + bgp_update_rsclient (rsclient, afi, safi, attr, peer, p, type, + sub_type, prd, tag); + } + + return ret; +} + +int bgp_withdraw (struct peer *peer, struct prefix *p, struct attr *attr, int afi, int safi, int type, int sub_type, struct prefix_rd *prd, u_char *tag) @@ -1291,9 +1928,18 @@ bgp_withdraw (struct peer *peer, struct prefix *p, struct attr *attr, char buf[SU_ADDRSTRLEN]; struct bgp_node *rn; struct bgp_info *ri; + struct peer *rsclient; + struct listnode *nn; bgp = peer->bgp; + /* Process the withdraw for each RS-client. */ + LIST_LOOP (bgp->rsclient, rsclient, nn) + { + if (CHECK_FLAG (rsclient->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) + bgp_withdraw_rsclient (rsclient, afi, safi, peer, p, type, sub_type, prd, tag); + } + /* Logging. */ if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_INFO, "%s rcvd UPDATE about %s/%d -- withdrawn", @@ -1302,7 +1948,7 @@ bgp_withdraw (struct peer *peer, struct prefix *p, struct attr *attr, p->prefixlen); /* Lookup node. */ - rn = bgp_afi_node_get (bgp, afi, safi, p, prd); + rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd); /* If peer is soft reconfiguration enabled. Record input packet for further calculation. */ @@ -1380,9 +2026,13 @@ bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw) binfo.peer = bgp->peer_self; binfo.attr = &attr; + SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_DEFAULT); + ret = route_map_apply (peer->default_rmap[afi][safi].map, &p, RMAP_BGP, &binfo); + bgp->peer_self->rmap_type = 0; + if (ret == RMAP_DENYMATCH) { bgp_attr_flush (&attr); @@ -1407,14 +2057,14 @@ bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw) static void bgp_announce_table (struct peer *peer, afi_t afi, safi_t safi, - struct bgp_table *table) + struct bgp_table *table, int rsclient) { struct bgp_node *rn; struct bgp_info *ri; struct attr attr; if (! table) - table = peer->bgp->rib[afi][safi]; + table = (rsclient) ? peer->rib[afi][safi] : peer->bgp->rib[afi][safi]; if (safi != SAFI_MPLS_VPN && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)) @@ -1424,7 +2074,9 @@ bgp_announce_table (struct peer *peer, afi_t afi, safi_t safi, for (ri = rn->info; ri; ri = ri->next) if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) && ri->peer != peer) { - if (bgp_announce_check (ri, peer, &rn->p, &attr, afi, safi)) + if ( (rsclient) ? + (bgp_announce_check_rsclient (ri, peer, &rn->p, &attr, afi, safi)) + : (bgp_announce_check (ri, peer, &rn->p, &attr, afi, safi))) bgp_adj_out_set (rn, peer, &rn->p, &attr, afi, safi, ri); else bgp_adj_out_unset (rn, peer, &rn->p, afi, safi); @@ -1448,12 +2100,15 @@ bgp_announce_route (struct peer *peer, afi_t afi, safi_t safi) return; if (safi != SAFI_MPLS_VPN) - bgp_announce_table (peer, afi, safi, NULL); + bgp_announce_table (peer, afi, safi, NULL, 0); else for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn; rn = bgp_route_next(rn)) if ((table = (rn->info)) != NULL) - bgp_announce_table (peer, afi, safi, table); + bgp_announce_table (peer, afi, safi, table, 0); + + if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) + bgp_announce_table (peer, afi, safi, NULL, 1); } void @@ -1468,6 +2123,40 @@ bgp_announce_route_all (struct peer *peer) } static void +bgp_soft_reconfig_table_rsclient (struct peer *rsclient, afi_t afi, + safi_t safi, struct bgp_table *table) +{ + struct bgp_node *rn; + struct bgp_adj_in *ain; + + if (! table) + table = rsclient->bgp->rib[afi][safi]; + + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) + for (ain = rn->adj_in; ain; ain = ain->next) + { + bgp_update_rsclient (rsclient, afi, safi, ain->attr, ain->peer, + &rn->p, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL); + } +} + +void +bgp_soft_reconfig_rsclient (struct peer *rsclient, afi_t afi, safi_t safi) +{ + struct bgp_table *table; + struct bgp_node *rn; + + if (safi != SAFI_MPLS_VPN) + bgp_soft_reconfig_table_rsclient (rsclient, afi, safi, NULL); + + else + for (rn = bgp_table_top (rsclient->bgp->rib[afi][safi]); rn; + rn = bgp_route_next (rn)) + if ((table = rn->info) != NULL) + bgp_soft_reconfig_table_rsclient (rsclient, afi, safi, table); +} + +static void bgp_soft_reconfig_table (struct peer *peer, afi_t afi, safi_t safi, struct bgp_table *table) { @@ -1516,7 +2205,7 @@ bgp_soft_reconfig_in (struct peer *peer, afi_t afi, safi_t safi) static void bgp_clear_route_table (struct peer *peer, afi_t afi, safi_t safi, - struct bgp_table *table) + struct bgp_table *table, struct peer *rsclient) { struct bgp_node *rn; struct bgp_adj_in *ain; @@ -1524,7 +2213,7 @@ bgp_clear_route_table (struct peer *peer, afi_t afi, safi_t safi, struct bgp_info *ri; if (! table) - table = peer->bgp->rib[afi][safi]; + table = (rsclient) ? rsclient->rib[afi][safi] : peer->bgp->rib[afi][safi]; for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) { @@ -1556,17 +2245,25 @@ bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi) { struct bgp_node *rn; struct bgp_table *table; + struct peer *rsclient; + struct listnode *nn; if (! peer->afc[afi][safi]) return; if (safi != SAFI_MPLS_VPN) - bgp_clear_route_table (peer, afi, safi, NULL); + bgp_clear_route_table (peer, afi, safi, NULL, NULL); else for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn; rn = bgp_route_next (rn)) if ((table = rn->info) != NULL) - bgp_clear_route_table (peer, afi, safi, table); + bgp_clear_route_table (peer, afi, safi, table, NULL); + + LIST_LOOP (peer->bgp->rsclient, rsclient, nn) + { + if (CHECK_FLAG(rsclient->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) + bgp_clear_route_table (peer, afi, safi, NULL, rsclient); + } } void @@ -1821,7 +2518,174 @@ bgp_static_free (struct bgp_static *bgp_static) } void -bgp_static_update (struct bgp *bgp, struct prefix *p, +bgp_static_withdraw_rsclient (struct bgp *bgp, struct peer *rsclient, + struct prefix *p, afi_t afi, safi_t safi) +{ + struct bgp_node *rn; + struct bgp_info *ri; + + rn = bgp_afi_node_get (rsclient->rib[afi][safi], afi, safi, p, NULL); + + /* Check selected route and self inserted route. */ + for (ri = rn->info; ri; ri = ri->next) + if (ri->peer == bgp->peer_self + && ri->type == ZEBRA_ROUTE_BGP + && ri->sub_type == BGP_ROUTE_STATIC) + break; + + /* Withdraw static BGP route from routing table. */ + if (ri) + { + UNSET_FLAG (ri->flags, BGP_INFO_VALID); + bgp_process (bgp, rn, afi, safi); + bgp_info_delete (rn, ri); + bgp_info_free (ri); + bgp_unlock_node (rn); + } + + /* Unlock bgp_node_lookup. */ + bgp_unlock_node (rn); +} + +void +bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, + struct bgp_static *bgp_static, afi_t afi, safi_t safi) +{ + struct bgp_node *rn; + struct bgp_info *ri; + struct bgp_info *new; + struct bgp_info info; + struct attr new_attr; + struct attr *attr_new; + struct attr attr; + struct bgp *bgp; + int ret; + char buf[SU_ADDRSTRLEN]; + + bgp = rsclient->bgp; + + rn = bgp_afi_node_get (rsclient->rib[afi][safi], afi, safi, p, NULL); + + bgp_attr_default_set (&attr, BGP_ORIGIN_IGP); + if (bgp_static) + { + attr.nexthop = bgp_static->igpnexthop; + attr.med = bgp_static->igpmetric; + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); + } + + new_attr = attr; + + /* Apply network route-map for export to this rsclient. */ + if (bgp_static->rmap.name) + { + info.peer = rsclient; + info.attr = &new_attr; + + SET_FLAG (rsclient->rmap_type, PEER_RMAP_TYPE_EXPORT); + SET_FLAG (rsclient->rmap_type, PEER_RMAP_TYPE_NETWORK); + + ret = route_map_apply (bgp_static->rmap.map, p, RMAP_BGP, &info); + + rsclient->rmap_type = 0; + + if (ret == RMAP_DENYMATCH) + { + /* Free uninterned attribute. */ + bgp_attr_flush (&new_attr); + + /* Unintern original. */ + aspath_unintern (attr.aspath); + bgp_static_withdraw_rsclient (bgp, rsclient, p, afi, safi); + + return; + } + attr_new = bgp_attr_intern (&new_attr); + } + else + attr_new = bgp_attr_intern (&attr); + + new_attr = *attr_new; + + SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_NETWORK); + + if (bgp_import_modifier (rsclient, bgp->peer_self, p, &new_attr, afi, safi) == RMAP_DENY) +{ + /* This BGP update is filtered. Log the reason then update BGP entry. */ + if (BGP_DEBUG (update, UPDATE_IN)) + zlog (rsclient->log, LOG_INFO, + "Static UPDATE about %s/%d -- DENIED for RS-client %s due to: import-policy", + inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen, rsclient->host); + + bgp->peer_self->rmap_type = 0; + + bgp_attr_unintern (attr_new); + aspath_unintern (attr.aspath); + + bgp_static_withdraw_rsclient (bgp, rsclient, p, afi, safi); + + return; + } + + bgp->peer_self->rmap_type = 0; + + bgp_attr_unintern (attr_new); + attr_new = bgp_attr_intern (&new_attr); + + for (ri = rn->info; ri; ri = ri->next) + if (ri->peer == bgp->peer_self && ri->type == ZEBRA_ROUTE_BGP + && ri->sub_type == BGP_ROUTE_STATIC) + break; + + if (ri) + { + if (attrhash_cmp (ri->attr, attr_new)) + { + bgp_unlock_node (rn); + bgp_attr_unintern (attr_new); + aspath_unintern (attr.aspath); + return; + } + else + { + /* The attribute is changed. */ + SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED); + + /* Rewrite BGP route information. */ + bgp_attr_unintern (ri->attr); + ri->attr = attr_new; + ri->uptime = time (NULL); + + /* Process change. */ + bgp_process (bgp, rn, afi, safi); + bgp_unlock_node (rn); + aspath_unintern (attr.aspath); + return; + } +} + + /* Make new BGP info. */ + new = bgp_info_new (); + new->type = ZEBRA_ROUTE_BGP; + new->sub_type = BGP_ROUTE_STATIC; + new->peer = bgp->peer_self; + SET_FLAG (new->flags, BGP_INFO_VALID); + new->attr = attr_new; + new->uptime = time (NULL); + + /* Register new BGP information. */ + bgp_info_add (rn, new); + + /* Process change. */ + bgp_process (bgp, rn, afi, safi); + + /* Unintern original. */ + aspath_unintern (attr.aspath); +} + +void +bgp_static_update_main (struct bgp *bgp, struct prefix *p, struct bgp_static *bgp_static, afi_t afi, safi_t safi) { struct bgp_node *rn; @@ -1833,7 +2697,7 @@ bgp_static_update (struct bgp *bgp, struct prefix *p, struct attr *attr_new; int ret; - rn = bgp_afi_node_get (bgp, afi, safi, p, NULL); + rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, NULL); bgp_attr_default_set (&attr, BGP_ORIGIN_IGP); if (bgp_static) @@ -1850,8 +2714,12 @@ bgp_static_update (struct bgp *bgp, struct prefix *p, info.peer = bgp->peer_self; info.attr = &attr_tmp; + SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_NETWORK); + ret = route_map_apply (bgp_static->rmap.map, p, RMAP_BGP, &info); + bgp->peer_self->rmap_type = 0; + if (ret == RMAP_DENYMATCH) { /* Free uninterned attribute. */ @@ -1924,13 +2792,28 @@ bgp_static_update (struct bgp *bgp, struct prefix *p, } void +bgp_static_update (struct bgp *bgp, struct prefix *p, + struct bgp_static *bgp_static, afi_t afi, safi_t safi) +{ + struct peer *rsclient; + struct listnode *nn; + + bgp_static_update_main (bgp, p, bgp_static, afi, safi); + + LIST_LOOP(bgp->rsclient, rsclient, nn) + { + bgp_static_update_rsclient (rsclient, p, bgp_static, afi, safi); + } +} + +void bgp_static_update_vpnv4 (struct bgp *bgp, struct prefix *p, u_int16_t afi, u_char safi, struct prefix_rd *prd, u_char *tag) { struct bgp_node *rn; struct bgp_info *new; - rn = bgp_afi_node_get (bgp, afi, safi, p, prd); + rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd); /* Make new BGP info. */ new = bgp_info_new (); @@ -1959,7 +2842,7 @@ bgp_static_withdraw (struct bgp *bgp, struct prefix *p, afi_t afi, struct bgp_node *rn; struct bgp_info *ri; - rn = bgp_afi_node_get (bgp, afi, safi, p, NULL); + rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, NULL); /* Check selected route and self inserted route. */ for (ri = rn->info; ri; ri = ri->next) @@ -1984,13 +2867,33 @@ bgp_static_withdraw (struct bgp *bgp, struct prefix *p, afi_t afi, } void +bgp_check_local_routes_rsclient (struct peer *rsclient, afi_t afi, safi_t safi) +{ + struct bgp_static *bgp_static; + struct bgp *bgp; + struct bgp_node *rn; + struct prefix *p; + + bgp = rsclient->bgp; + + for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn)) + if ((bgp_static = rn->info) != NULL) + { + p = &rn->p; + + bgp_static_update_rsclient (rsclient, p, bgp_static, + afi, safi); + } +} + +void bgp_static_withdraw_vpnv4 (struct bgp *bgp, struct prefix *p, u_int16_t afi, u_char safi, struct prefix_rd *prd, u_char *tag) { struct bgp_node *rn; struct bgp_info *ri; - rn = bgp_afi_node_get (bgp, afi, safi, p, prd); + rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd); /* Check selected route and self inserted route. */ for (ri = rn->info; ri; ri = ri->next) @@ -3602,8 +4505,13 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop, info.peer = bgp->peer_self; info.attr = &attr_new; + SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_REDISTRIBUTE); + ret = route_map_apply (bgp->rmap[afi][type].map, p, RMAP_BGP, &info); + + bgp->peer_self->rmap_type = 0; + if (ret == RMAP_DENYMATCH) { /* Free uninterned attribute. */ @@ -3616,7 +4524,7 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop, } } - bn = bgp_afi_node_get (bgp, afi, SAFI_UNICAST, p, NULL); + bn = bgp_afi_node_get (bgp->rib[afi][SAFI_UNICAST], afi, SAFI_UNICAST, p, NULL); new_attr = bgp_attr_intern (&attr_new); for (bi = bn->info; bi; bi = bi->next) @@ -3686,7 +4594,7 @@ bgp_redistribute_delete (struct prefix *p, u_char type) if (bgp->redist[afi][type]) { - rn = bgp_afi_node_get (bgp, afi, SAFI_UNICAST, p, NULL); + rn = bgp_afi_node_get (bgp->rib[afi][SAFI_UNICAST], afi, SAFI_UNICAST, p, NULL); for (ri = rn->info; ri; ri = ri->next) if (ri->peer == bgp->peer_self @@ -4596,12 +5504,11 @@ bgp_show_callback (struct vty *vty, int unlock) } int -bgp_show (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, +bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router_id, enum bgp_show_type type) { struct bgp_info *ri; struct bgp_node *rn; - struct bgp_table *table; int header = 1; int count; int limit; @@ -4612,24 +5519,12 @@ bgp_show (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, ? vty->lines : vty->height - 2)); limit = limit > 0 ? limit : 2; - if (bgp == NULL) { - bgp = bgp_get_default (); - } - - if (bgp == NULL) - { - vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); - return CMD_WARNING; - } - count = 0; /* This is first entry point, so reset total line. */ vty->output_count = 0; vty->output_type = type; - table = bgp->rib[afi][safi]; - /* Start processing of routes. */ for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) if (rn->info != NULL) @@ -4782,7 +5677,7 @@ bgp_show (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, if (header) { - vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE); + vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (*router_id), VTY_NEWLINE); vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", VTY_NEWLINE); vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", VTY_NEWLINE, VTY_NEWLINE); if (type == bgp_show_type_dampend_paths @@ -4861,6 +5756,28 @@ bgp_show (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, return CMD_SUCCESS; } +int +bgp_show (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, + enum bgp_show_type type) +{ + struct bgp_table *table; + + if (bgp == NULL) { + bgp = bgp_get_default (); + } + + if (bgp == NULL) + { + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + + + table = bgp->rib[afi][safi]; + + return bgp_show_table (vty, table, &bgp->router_id, type); +} + /* Header of detailed BGP route information */ void route_vty_out_detail_header (struct vty *vty, struct bgp *bgp, @@ -4946,7 +5863,8 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp, /* Display specified route of BGP table. */ int -bgp_show_route (struct vty *vty, char *view_name, char *ip_str, +bgp_show_route_in_table (struct vty *vty, struct bgp *bgp, + struct bgp_table *rib, char *ip_str, afi_t afi, safi_t safi, struct prefix_rd *prd, int prefix_check) { @@ -4957,29 +5875,8 @@ bgp_show_route (struct vty *vty, char *view_name, char *ip_str, struct bgp_node *rn; struct bgp_node *rm; struct bgp_info *ri; - struct bgp *bgp; struct bgp_table *table; - /* BGP structure lookup. */ - if (view_name) - { - bgp = bgp_lookup_by_name (view_name); - if (bgp == NULL) - { - vty_out (vty, "Can't find BGP view %s%s", view_name, VTY_NEWLINE); - return CMD_WARNING; - } - } - else - { - bgp = bgp_get_default (); - if (bgp == NULL) - { - vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); - return CMD_WARNING; - } - } - /* Check IP address argument. */ ret = str2prefix (ip_str, &match); if (! ret) @@ -4992,7 +5889,7 @@ bgp_show_route (struct vty *vty, char *view_name, char *ip_str, if (safi == SAFI_MPLS_VPN) { - for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_MPLS_VPN]); rn; rn = bgp_route_next (rn)) + for (rn = bgp_table_top (rib); rn; rn = bgp_route_next (rn)) { if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) continue; @@ -5026,7 +5923,7 @@ bgp_show_route (struct vty *vty, char *view_name, char *ip_str, { header = 1; - if ((rn = bgp_node_match (bgp->rib[afi][safi], &match)) != NULL) + if ((rn = bgp_node_match (rib, &match)) != NULL) { if (! prefix_check || rn->p.prefixlen == match.prefixlen) { @@ -5053,6 +5950,38 @@ bgp_show_route (struct vty *vty, char *view_name, char *ip_str, return CMD_SUCCESS; } +/* Display specified route of Main RIB */ +int +bgp_show_route (struct vty *vty, char *view_name, char *ip_str, + afi_t afi, safi_t safi, struct prefix_rd *prd, + int prefix_check) +{ + struct bgp *bgp; + + /* BGP structure lookup. */ + if (view_name) + { + bgp = bgp_lookup_by_name (view_name); + if (bgp == NULL) + { + vty_out (vty, "Can't find BGP view %s%s", view_name, VTY_NEWLINE); + return CMD_WARNING; + } + } + else + { + bgp = bgp_get_default (); + if (bgp == NULL) + { + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + return bgp_show_route_in_table (vty, bgp, bgp->rib[afi][safi], ip_str, + afi, safi, prd, prefix_check); +} + /* BGP route print out function. */ DEFUN (show_ip_bgp, show_ip_bgp_cmd, @@ -8132,6 +9061,204 @@ DEFUN (show_ip_bgp_ipv4_neighbor_routes, bgp_show_type_neighbor); } +DEFUN (show_ip_bgp_view_rsclient, + show_ip_bgp_view_rsclient_cmd, + "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X)", + SHOW_STR + IP_STR + BGP_STR + "BGP view\n" + "BGP view name\n" + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR) +{ + struct bgp_table *table; + struct peer *peer; + + if (argc == 2) + peer = peer_lookup_in_view (vty, argv[0], argv[1]); + else + peer = peer_lookup_in_view (vty, NULL, argv[0]); + + if (! peer) + return CMD_WARNING; + + if (! peer->afc[AFI_IP][SAFI_UNICAST]) + { + vty_out (vty, "%% Activate the neighbor for the address family first%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST], + PEER_FLAG_RSERVER_CLIENT)) + { + vty_out (vty, "%% Neighbor is not a Route-Server client%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + table = peer->rib[AFI_IP][SAFI_UNICAST]; + + return bgp_show_table (vty, table, &peer->remote_id, bgp_show_type_normal); +} + +ALIAS (show_ip_bgp_view_rsclient, + show_ip_bgp_rsclient_cmd, + "show ip bgp rsclient (A.B.C.D|X:X::X:X)", + SHOW_STR + IP_STR + BGP_STR + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR) + +DEFUN (show_ip_bgp_view_rsclient_route, + show_ip_bgp_view_rsclient_route_cmd, + "show bgp view WORD rsclient (A.B.C.D|X:X::X:X) A.B.C.D", + SHOW_STR + IP_STR + BGP_STR + "BGP view\n" + "BGP view name\n" + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR + "Network in the BGP routing table to display\n") +{ + struct bgp *bgp; + struct peer *peer; + + /* BGP structure lookup. */ + if (argc == 3) + { + bgp = bgp_lookup_by_name (argv[0]); + if (bgp == NULL) + { + vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + } + else + { + bgp = bgp_get_default (); + if (bgp == NULL) + { + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + if (argc == 3) + peer = peer_lookup_in_view (vty, argv[0], argv[1]); + else + peer = peer_lookup_in_view (vty, NULL, argv[0]); + + if (! peer) + return CMD_WARNING; + + if (! peer->afc[AFI_IP][SAFI_UNICAST]) + { + vty_out (vty, "%% Activate the neighbor for the address family first%s", + VTY_NEWLINE); + return CMD_WARNING; +} + + if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST], + PEER_FLAG_RSERVER_CLIENT)) + { + vty_out (vty, "%% Neighbor is not a Route-Server client%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][SAFI_UNICAST], + (argc == 3) ? argv[2] : argv[1], + AFI_IP, SAFI_UNICAST, NULL, 0); +} + +ALIAS (show_ip_bgp_view_rsclient_route, + show_ip_bgp_rsclient_route_cmd, + "show ip bgp rsclient (A.B.C.D|X:X::X:X) A.B.C.D", + SHOW_STR + IP_STR + BGP_STR + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR + "Network in the BGP routing table to display\n") + +DEFUN (show_ip_bgp_view_rsclient_prefix, + show_ip_bgp_view_rsclient_prefix_cmd, + "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M", + SHOW_STR + IP_STR + BGP_STR + "BGP view\n" + "BGP view name\n" + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR + "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n") +{ + struct bgp *bgp; + struct peer *peer; + + /* BGP structure lookup. */ + if (argc == 3) + { + bgp = bgp_lookup_by_name (argv[0]); + if (bgp == NULL) + { + vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + } + else + { + bgp = bgp_get_default (); + if (bgp == NULL) + { + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + if (argc == 3) + peer = peer_lookup_in_view (vty, argv[0], argv[1]); + else + peer = peer_lookup_in_view (vty, NULL, argv[0]); + + if (! peer) + return CMD_WARNING; + + if (! peer->afc[AFI_IP][SAFI_UNICAST]) + { + vty_out (vty, "%% Activate the neighbor for the address family first%s", + VTY_NEWLINE); + return CMD_WARNING; +} + + if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST], + PEER_FLAG_RSERVER_CLIENT)) +{ + vty_out (vty, "%% Neighbor is not a Route-Server client%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][SAFI_UNICAST], + (argc == 3) ? argv[2] : argv[1], + AFI_IP, SAFI_UNICAST, NULL, 1); +} + +ALIAS (show_ip_bgp_view_rsclient_prefix, + show_ip_bgp_rsclient_prefix_cmd, + "show ip bgp rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M", + SHOW_STR + IP_STR + BGP_STR + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR + "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n") + + #ifdef HAVE_IPV6 DEFUN (show_bgp_view_neighbor_routes, show_bgp_view_neighbor_routes_cmd, @@ -8347,6 +9474,198 @@ ALIAS (show_bgp_view_neighbor_damp, "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the dampened routes received from neighbor\n") + +DEFUN (show_bgp_view_rsclient, + show_bgp_view_rsclient_cmd, + "show bgp view WORD rsclient (A.B.C.D|X:X::X:X)", + SHOW_STR + BGP_STR + "BGP view\n" + "BGP view name\n" + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR) +{ + struct bgp_table *table; + struct peer *peer; + + if (argc == 2) + peer = peer_lookup_in_view (vty, argv[0], argv[1]); + else + peer = peer_lookup_in_view (vty, NULL, argv[0]); + + if (! peer) + return CMD_WARNING; + + if (! peer->afc[AFI_IP6][SAFI_UNICAST]) + { + vty_out (vty, "%% Activate the neighbor for the address family first%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if ( ! CHECK_FLAG (peer->af_flags[AFI_IP6][SAFI_UNICAST], + PEER_FLAG_RSERVER_CLIENT)) + { + vty_out (vty, "%% Neighbor is not a Route-Server client%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + table = peer->rib[AFI_IP6][SAFI_UNICAST]; + + return bgp_show_table (vty, table, &peer->remote_id, bgp_show_type_normal); +} + +ALIAS (show_bgp_view_rsclient, + show_bgp_rsclient_cmd, + "show bgp rsclient (A.B.C.D|X:X::X:X)", + SHOW_STR + BGP_STR + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR) + +DEFUN (show_bgp_view_rsclient_route, + show_bgp_view_rsclient_route_cmd, + "show bgp view WORD rsclient (A.B.C.D|X:X::X:X) X:X::X:X", + SHOW_STR + BGP_STR + "BGP view\n" + "BGP view name\n" + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR + "Network in the BGP routing table to display\n") +{ + struct bgp *bgp; + struct peer *peer; + + /* BGP structure lookup. */ + if (argc == 3) + { + bgp = bgp_lookup_by_name (argv[0]); + if (bgp == NULL) + { + vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + } + else + { + bgp = bgp_get_default (); + if (bgp == NULL) + { + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + if (argc == 3) + peer = peer_lookup_in_view (vty, argv[0], argv[1]); + else + peer = peer_lookup_in_view (vty, NULL, argv[0]); + + if (! peer) + return CMD_WARNING; + + if (! peer->afc[AFI_IP6][SAFI_UNICAST]) + { + vty_out (vty, "%% Activate the neighbor for the address family first%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if ( ! CHECK_FLAG (peer->af_flags[AFI_IP6][SAFI_UNICAST], + PEER_FLAG_RSERVER_CLIENT)) + { + vty_out (vty, "%% Neighbor is not a Route-Server client%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][SAFI_UNICAST], + (argc == 3) ? argv[2] : argv[1], + AFI_IP6, SAFI_UNICAST, NULL, 0); +} + +ALIAS (show_bgp_view_rsclient_route, + show_bgp_rsclient_route_cmd, + "show bgp rsclient (A.B.C.D|X:X::X:X) X:X::X:X", + SHOW_STR + BGP_STR + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR + "Network in the BGP routing table to display\n") + +DEFUN (show_bgp_view_rsclient_prefix, + show_bgp_view_rsclient_prefix_cmd, + "show bgp view WORD rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", + SHOW_STR + BGP_STR + "BGP view\n" + "BGP view name\n" + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR + "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n") +{ + struct bgp *bgp; + struct peer *peer; + + /* BGP structure lookup. */ + if (argc == 3) + { + bgp = bgp_lookup_by_name (argv[0]); + if (bgp == NULL) + { + vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + } + else + { + bgp = bgp_get_default (); + if (bgp == NULL) + { + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + if (argc == 3) + peer = peer_lookup_in_view (vty, argv[0], argv[1]); + else + peer = peer_lookup_in_view (vty, NULL, argv[0]); + + if (! peer) + return CMD_WARNING; + + if (! peer->afc[AFI_IP6][SAFI_UNICAST]) + { + vty_out (vty, "%% Activate the neighbor for the address family first%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if ( ! CHECK_FLAG (peer->af_flags[AFI_IP6][SAFI_UNICAST], + PEER_FLAG_RSERVER_CLIENT)) + { + vty_out (vty, "%% Neighbor is not a Route-Server client%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][SAFI_UNICAST], + (argc == 3) ? argv[2] : argv[1], + AFI_IP6, SAFI_UNICAST, NULL, 1); +} + +ALIAS (show_bgp_view_rsclient_prefix, + show_bgp_rsclient_prefix_cmd, + "show bgp rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", + SHOW_STR + BGP_STR + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR + "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n") + #endif /* HAVE_IPV6 */ struct bgp_table *bgp_distance_table; @@ -9243,6 +10562,12 @@ bgp_route_init () install_element (VIEW_NODE, &show_ip_bgp_flap_route_map_cmd); install_element (VIEW_NODE, &show_ip_bgp_neighbor_flap_cmd); install_element (VIEW_NODE, &show_ip_bgp_neighbor_damp_cmd); + install_element (VIEW_NODE, &show_ip_bgp_rsclient_cmd); + install_element (VIEW_NODE, &show_ip_bgp_rsclient_route_cmd); + install_element (VIEW_NODE, &show_ip_bgp_rsclient_prefix_cmd); + install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_cmd); + install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_route_cmd); + install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_prefix_cmd); install_element (ENABLE_NODE, &show_ip_bgp_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cmd); @@ -9311,6 +10636,12 @@ bgp_route_init () install_element (ENABLE_NODE, &show_ip_bgp_flap_route_map_cmd); install_element (ENABLE_NODE, &show_ip_bgp_neighbor_flap_cmd); install_element (ENABLE_NODE, &show_ip_bgp_neighbor_damp_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_rsclient_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_rsclient_route_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_rsclient_prefix_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_route_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_prefix_cmd); /* BGP dampening clear commands */ install_element (ENABLE_NODE, &clear_ip_bgp_dampening_cmd); @@ -9389,6 +10720,9 @@ bgp_route_init () install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_flap_cmd); install_element (VIEW_NODE, &show_bgp_neighbor_damp_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_damp_cmd); + install_element (VIEW_NODE, &show_bgp_rsclient_cmd); + install_element (VIEW_NODE, &show_bgp_rsclient_route_cmd); + install_element (VIEW_NODE, &show_bgp_rsclient_prefix_cmd); install_element (VIEW_NODE, &show_bgp_view_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_cmd); install_element (VIEW_NODE, &show_bgp_view_route_cmd); @@ -9407,6 +10741,9 @@ bgp_route_init () install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_flap_cmd); install_element (VIEW_NODE, &show_bgp_view_neighbor_damp_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_damp_cmd); + install_element (VIEW_NODE, &show_bgp_view_rsclient_cmd); + install_element (VIEW_NODE, &show_bgp_view_rsclient_route_cmd); + install_element (VIEW_NODE, &show_bgp_view_rsclient_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_cmd); @@ -9458,6 +10795,9 @@ bgp_route_init () install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_flap_cmd); install_element (ENABLE_NODE, &show_bgp_neighbor_damp_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_damp_cmd); + install_element (ENABLE_NODE, &show_bgp_rsclient_cmd); + install_element (ENABLE_NODE, &show_bgp_rsclient_route_cmd); + install_element (ENABLE_NODE, &show_bgp_rsclient_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_view_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_cmd); install_element (ENABLE_NODE, &show_bgp_view_route_cmd); @@ -9476,6 +10816,9 @@ bgp_route_init () install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_flap_cmd); install_element (ENABLE_NODE, &show_bgp_view_neighbor_damp_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_damp_cmd); + install_element (ENABLE_NODE, &show_bgp_view_rsclient_cmd); + install_element (ENABLE_NODE, &show_bgp_view_rsclient_route_cmd); + install_element (ENABLE_NODE, &show_bgp_view_rsclient_prefix_cmd); /* old command */ install_element (VIEW_NODE, &show_ipv6_bgp_cmd); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 273ed41a..9aad7238 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -109,10 +109,15 @@ struct bgp_static #define FILTER_LIST_OUT_NAME(F) ((F)->aslist[FILTER_OUT].name) #define FILTER_LIST_OUT(F) ((F)->aslist[FILTER_OUT].aslist) -#define ROUTE_MAP_IN_NAME(F) ((F)->map[FILTER_IN].name) -#define ROUTE_MAP_IN(F) ((F)->map[FILTER_IN].map) -#define ROUTE_MAP_OUT_NAME(F) ((F)->map[FILTER_OUT].name) -#define ROUTE_MAP_OUT(F) ((F)->map[FILTER_OUT].map) +#define ROUTE_MAP_IN_NAME(F) ((F)->map[RMAP_IN].name) +#define ROUTE_MAP_IN(F) ((F)->map[RMAP_IN].map) +#define ROUTE_MAP_OUT_NAME(F) ((F)->map[RMAP_OUT].name) +#define ROUTE_MAP_OUT(F) ((F)->map[RMAP_OUT].map) + +#define ROUTE_MAP_IMPORT_NAME(F) ((F)->map[RMAP_IMPORT].name) +#define ROUTE_MAP_IMPORT(F) ((F)->map[RMAP_IMPORT].map) +#define ROUTE_MAP_EXPORT_NAME(F) ((F)->map[RMAP_EXPORT].name) +#define ROUTE_MAP_EXPORT(F) ((F)->map[RMAP_EXPORT].map) #define UNSUPPRESS_MAP_NAME(F) ((F)->usmap.name) #define UNSUPPRESS_MAP(F) ((F)->usmap.map) @@ -124,6 +129,8 @@ void bgp_announce_route (struct peer *, afi_t, safi_t); void bgp_announce_route_all (struct peer *); void bgp_default_originate (struct peer *, afi_t, safi_t, int); void bgp_soft_reconfig_in (struct peer *, afi_t, safi_t); +void bgp_soft_reconfig_rsclient (struct peer *, afi_t, safi_t); +void bgp_check_local_routes_rsclient (struct peer *rsclient, afi_t afi, safi_t safi); void bgp_clear_route (struct peer *, afi_t, safi_t); void bgp_clear_route_all (struct peer *); void bgp_clear_adj_in (struct peer *, afi_t, safi_t); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 261f6b87..c49c2e99 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -95,6 +95,103 @@ o Local extention */ + /* 'match peer (A.B.C.D|X:X::X:X)' */ + +/* Compares the peer specified in the 'match peer' clause with the peer + received in bgp_info->peer. If it is the same, or if the peer structure + received is a peer_group containing it, returns RMAP_MATCH. */ +route_map_result_t +route_match_peer (void *rule, struct prefix *prefix, route_map_object_t type, + void *object) +{ + union sockunion *su; + union sockunion *su2; + struct peer_group *group; + struct peer *peer; + struct listnode *nn; + + if (type == RMAP_BGP) + { + su = rule; + peer = ((struct bgp_info *) object)->peer; + + if ( ! CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IMPORT) && + ! CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_EXPORT) ) + return RMAP_NOMATCH; + + /* If su='0.0.0.0' (command 'match peer local'), and it's a NETWORK, + REDISTRIBUTE or DEFAULT_GENERATED route => return RMAP_MATCH */ + su2 = sockunion_str2su ("0.0.0.0"); + if ( sockunion_same (su, su2) ) + { + if ( CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_NETWORK) || + CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_REDISTRIBUTE) || + CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_DEFAULT)) + { + XFREE (MTYPE_SOCKUNION, su2); + + return RMAP_MATCH; + } + else + return RMAP_NOMATCH; + } + XFREE (MTYPE_SOCKUNION, su2); + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + if (sockunion_same (su, &peer->su)) + return RMAP_MATCH; + + return RMAP_NOMATCH; + } + else + { + group = peer->group; + LIST_LOOP (group->peer, peer, nn) + { + if (sockunion_same (su, &peer->su)) + return RMAP_MATCH; + + return RMAP_NOMATCH; + } + } + } + return RMAP_NOMATCH; +} + +void * +route_match_peer_compile (char *arg) +{ + union sockunion *su; + int ret; + + su = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (union sockunion)); + + ret = str2sockunion ( (arg)? arg : "0.0.0.0", su); + if (ret < 0) { + XFREE (MTYPE_ROUTE_MAP_COMPILED, su); + return NULL; + } + + return su; +} + +/* Free route map's compiled `ip address' value. */ +void +route_match_peer_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip address matching. */ +struct route_map_rule_cmd route_match_peer_cmd = +{ + "peer", + route_match_peer, + route_match_peer_compile, + route_match_peer_free +}; + /* `match ip address IP_ACCESS_LIST' */ /* Match function should return 1 if match is success else return @@ -643,7 +740,8 @@ route_set_ip_nexthop (void *rule, struct prefix *prefix, if (rins->peer_address) { - if (CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IN) + 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_INET) { @@ -1974,7 +2072,7 @@ bgp_route_map_update (char *unused) { filter = &peer->filter[afi][safi]; - for (direct = FILTER_IN; direct < FILTER_MAX; direct++) + for (direct = RMAP_IN; direct < RMAP_MAX; direct++) { if (filter->map[direct].name) filter->map[direct].map = @@ -1996,7 +2094,7 @@ bgp_route_map_update (char *unused) { filter = &group->conf->filter[afi][safi]; - for (direct = FILTER_IN; direct < FILTER_MAX; direct++) + for (direct = RMAP_IN; direct < RMAP_MAX; direct++) { if (filter->map[direct].name) filter->map[direct].map = @@ -2064,6 +2162,57 @@ bgp_route_map_update (char *unused) } } +DEFUN (match_peer, + match_peer_cmd, + "match peer (A.B.C.D|X:X::X:X)", + MATCH_STR + "Match peer address\n" + "IPv6 address of peer\n" + "IP address of peer\n") +{ + return bgp_route_match_add (vty, vty->index, "peer", argv[0]); +} + +DEFUN (match_peer_local, + match_peer_local_cmd, + "match peer local", + MATCH_STR + "Match peer address\n" + "Static or Redistributed routes\n") +{ + return bgp_route_match_add (vty, vty->index, "peer", NULL); +} + +DEFUN (no_match_peer, + no_match_peer_cmd, + "no match peer", + NO_STR + MATCH_STR + "Match peer address\n") +{ + if (argc == 0) + return bgp_route_match_delete (vty, vty->index, "peer", NULL); + + return bgp_route_match_delete (vty, vty->index, "peer", argv[0]); +} + +ALIAS (no_match_peer, + no_match_peer_val_cmd, + "no match peer (A.B.C.D|X:X::X:X)", + NO_STR + MATCH_STR + "Match peer address\n" + "IPv6 address of peer\n" + "IP address of peer\n") + +ALIAS (no_match_peer, + no_match_peer_local_cmd, + "no match peer local", + NO_STR + MATCH_STR + "Match peer address\n" + "Static or Redistributed routes\n") + DEFUN (match_ip_address, match_ip_address_cmd, "match ip address (<1-199>|<1300-2699>|WORD)", @@ -3239,6 +3388,7 @@ bgp_route_map_init () route_map_add_hook (bgp_route_map_update); route_map_delete_hook (bgp_route_map_update); + route_map_install_match (&route_match_peer_cmd); route_map_install_match (&route_match_ip_address_cmd); route_map_install_match (&route_match_ip_next_hop_cmd); route_map_install_match (&route_match_ip_address_prefix_list_cmd); @@ -3264,6 +3414,11 @@ bgp_route_map_init () route_map_install_set (&route_set_ecommunity_rt_cmd); route_map_install_set (&route_set_ecommunity_soo_cmd); + install_element (RMAP_NODE, &match_peer_cmd); + install_element (RMAP_NODE, &match_peer_local_cmd); + install_element (RMAP_NODE, &no_match_peer_cmd); + install_element (RMAP_NODE, &no_match_peer_val_cmd); + install_element (RMAP_NODE, &no_match_peer_local_cmd); install_element (RMAP_NODE, &match_ip_address_cmd); install_element (RMAP_NODE, &no_match_ip_address_cmd); install_element (RMAP_NODE, &no_match_ip_address_val_cmd); diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c index a2a3c97b..c468173d 100644 --- a/bgpd/bgp_table.c +++ b/bgpd/bgp_table.c @@ -38,6 +38,9 @@ bgp_table_init (void) rt = XMALLOC (MTYPE_BGP_TABLE, sizeof (struct bgp_table)); memset (rt, 0, sizeof (struct bgp_table)); + + rt->type = BGP_TABLE_MAIN; + return rt; } diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h index 52eb6a49..f979ac6f 100644 --- a/bgpd/bgp_table.h +++ b/bgpd/bgp_table.h @@ -18,8 +18,19 @@ along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +typedef enum +{ + BGP_TABLE_MAIN, + BGP_TABLE_RSCLIENT, +} bgp_table_t; + struct bgp_table { + bgp_table_t type; + + /* The owner of this 'bgp_table' structure. */ + void *owner; + struct bgp_node *top; }; diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index c7de8eb6..92918bdf 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -39,6 +39,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_open.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_zebra.h" +#include "bgpd/bgp_table.h" /* Utility function to get address family from current node. */ afi_t @@ -1648,7 +1649,7 @@ DEFUN (no_neighbor_dont_capability_negotiate, int peer_af_flag_modify_vty (struct vty *vty, char *peer_str, afi_t afi, - safi_t safi, u_int16_t flag, int set) + safi_t safi, u_int32_t flag, int set) { int ret; struct peer *peer; @@ -1667,14 +1668,14 @@ peer_af_flag_modify_vty (struct vty *vty, char *peer_str, afi_t afi, int peer_af_flag_set_vty (struct vty *vty, char *peer_str, afi_t afi, - safi_t safi, u_int16_t flag) + safi_t safi, u_int32_t flag) { return peer_af_flag_modify_vty (vty, peer_str, afi, safi, flag, 1); } int peer_af_flag_unset_vty (struct vty *vty, char *peer_str, afi_t afi, - safi_t safi, u_int16_t flag) + safi_t safi, u_int32_t flag) { return peer_af_flag_modify_vty (vty, peer_str, afi, safi, flag, 0); } @@ -1923,6 +1924,134 @@ DEFUN (no_neighbor_route_reflector_client, PEER_FLAG_REFLECTOR_CLIENT); } +int +peer_rsclient_set_vty (struct vty *vty, char *peer_str, int afi, int safi) +{ + int ret; + struct bgp *bgp; + struct peer *peer; + struct peer_group *group; + struct listnode *nn; + struct bgp_filter *pfilter; + struct bgp_filter *gfilter; + + bgp = vty->index; + + peer = peer_and_group_lookup_vty (vty, peer_str); + if ( ! peer ) + return CMD_WARNING; + + /* If it is already a RS-Client, don't do anything. */ + if ( CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) ) + return CMD_SUCCESS; + + if ( ! peer_rsclient_active (peer) ) + listnode_add_sort (bgp->rsclient, peer); + + ret = peer_af_flag_set (peer, afi, safi, PEER_FLAG_RSERVER_CLIENT); + if (ret < 0) + return bgp_vty_return (vty, ret); + + peer->rib[afi][safi] = bgp_table_init (); + peer->rib[afi][safi]->type = BGP_TABLE_RSCLIENT; + peer->rib[afi][safi]->owner = peer; + + /* Check for existing 'network' and 'redistribute' routes. */ + bgp_check_local_routes_rsclient (peer, afi, safi); + + /* Check for routes for peers configured with 'soft-reconfiguration'. */ + bgp_soft_reconfig_rsclient (peer, afi, safi); + + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) + { + group = peer->group; + gfilter = &peer->filter[afi][safi]; + + LIST_LOOP(group->peer, peer, nn) + { + pfilter = &peer->filter[afi][safi]; + + /* Members of a non-RS-Client group should not be RS-Clients, as that + is checked when the become part of the peer-group */ + ret = peer_af_flag_set (peer, afi, safi, PEER_FLAG_RSERVER_CLIENT); + if (ret < 0) + return bgp_vty_return (vty, ret); + + /* Make peer's RIB point to group's RIB. */ + peer->rib[afi][safi] = group->conf->rib[afi][safi]; + + /* Import policy. */ + if (pfilter->map[RMAP_IMPORT].name) + free (pfilter->map[RMAP_IMPORT].name); + if (gfilter->map[RMAP_IMPORT].name) + { + pfilter->map[RMAP_IMPORT].name = strdup (gfilter->map[RMAP_IMPORT].name); + pfilter->map[RMAP_IMPORT].map = gfilter->map[RMAP_IMPORT].map; + } + else + { + pfilter->map[RMAP_IMPORT].name = NULL; + pfilter->map[RMAP_IMPORT].map =NULL; + } + + /* Export policy. */ + if (gfilter->map[RMAP_EXPORT].name && ! pfilter->map[RMAP_EXPORT].name) + { + pfilter->map[RMAP_EXPORT].name = strdup (gfilter->map[RMAP_EXPORT].name); + pfilter->map[RMAP_EXPORT].map = gfilter->map[RMAP_EXPORT].map; + } + } + } + return CMD_SUCCESS; +} + +int +peer_rsclient_unset_vty (struct vty *vty, char *peer_str, int afi, int safi) +{ + int ret; + struct bgp *bgp; + struct peer *peer; + struct peer_group *group; + struct listnode *nn; + + bgp = vty->index; + + peer = peer_and_group_lookup_vty (vty, peer_str); + if ( ! peer ) + return CMD_WARNING; + + /* If it is not a RS-Client, don't do anything. */ + if ( ! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) ) + return CMD_SUCCESS; + + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) + { + group = peer->group; + + LIST_LOOP (group->peer, peer, nn) + { + ret = peer_af_flag_unset (peer, afi, safi, PEER_FLAG_RSERVER_CLIENT); + if (ret < 0) + return bgp_vty_return (vty, ret); + + peer->rib[afi][safi] = NULL; + } + + peer = group->conf; + } + + ret = peer_af_flag_unset (peer, afi, safi, PEER_FLAG_RSERVER_CLIENT); + if (ret < 0) + return bgp_vty_return (vty, ret); + + if ( ! peer_rsclient_active (peer) ) + listnode_delete (bgp->rsclient, peer); + + bgp_table_finish (peer->rib[bgp_node_afi(vty)][bgp_node_safi(vty)]); + + return CMD_SUCCESS; +} + /* neighbor route-server-client. */ DEFUN (neighbor_route_server_client, neighbor_route_server_client_cmd, @@ -1931,9 +2060,8 @@ DEFUN (neighbor_route_server_client, NEIGHBOR_ADDR_STR2 "Configure a neighbor as Route Server client\n") { - return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), - bgp_node_safi (vty), - PEER_FLAG_RSERVER_CLIENT); + return peer_rsclient_set_vty (vty, argv[0], bgp_node_afi(vty), + bgp_node_safi(vty)); } DEFUN (no_neighbor_route_server_client, @@ -1944,9 +2072,35 @@ DEFUN (no_neighbor_route_server_client, NEIGHBOR_ADDR_STR2 "Configure a neighbor as Route Server client\n") { + return peer_rsclient_unset_vty (vty, argv[0], bgp_node_afi(vty), + bgp_node_safi(vty)); +} + +DEFUN (neighbor_nexthop_local_unchanged, + neighbor_nexthop_local_unchanged_cmd, + NEIGHBOR_CMD2 "nexthop-local unchanged", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Configure treatment of outgoing link-local nexthop attribute\n" + "Leave link-local nexthop unchanged for this peer\n") +{ + return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), + bgp_node_safi (vty), + PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED ); +} + +DEFUN (no_neighbor_nexthop_local_unchanged, + no_neighbor_nexthop_local_unchanged_cmd, + NO_NEIGHBOR_CMD2 "nexthop-local unchanged", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Configure treatment of outgoing link-local-nexthop attribute\n" + "Leave link-local nexthop unchanged for this peer\n") +{ return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), - PEER_FLAG_RSERVER_CLIENT); + PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED ); } DEFUN (neighbor_attr_unchanged, @@ -3265,17 +3419,21 @@ peer_route_map_set_vty (struct vty *vty, char *ip_str, afi_t afi, safi_t safi, { int ret; struct peer *peer; - int direct = FILTER_IN; + int direct = RMAP_IN; peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; /* Check filter direction. */ - if (strncmp (direct_str, "i", 1) == 0) - direct = FILTER_IN; + if (strncmp (direct_str, "in", 2) == 0) + direct = RMAP_IN; else if (strncmp (direct_str, "o", 1) == 0) - direct = FILTER_OUT; + direct = RMAP_OUT; + else if (strncmp (direct_str, "im", 2) == 0) + direct = RMAP_IMPORT; + else if (strncmp (direct_str, "e", 1) == 0) + direct = RMAP_EXPORT; ret = peer_route_map_set (peer, afi, safi, direct, name_str); @@ -3288,18 +3446,21 @@ peer_route_map_unset_vty (struct vty *vty, char *ip_str, afi_t afi, { int ret; struct peer *peer; - int direct = FILTER_IN; + int direct = RMAP_IN; peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; /* Check filter direction. */ - if (strncmp (direct_str, "i", 1) == 0) - direct = FILTER_IN; + if (strncmp (direct_str, "in", 2) == 0) + direct = RMAP_IN; else if (strncmp (direct_str, "o", 1) == 0) - - direct = FILTER_OUT; + direct = RMAP_OUT; + else if (strncmp (direct_str, "im", 2) == 0) + direct = RMAP_IMPORT; + else if (strncmp (direct_str, "e", 1) == 0) + direct = RMAP_EXPORT; ret = peer_route_map_unset (peer, afi, safi, direct); @@ -3308,13 +3469,15 @@ peer_route_map_unset_vty (struct vty *vty, char *ip_str, afi_t afi, DEFUN (neighbor_route_map, neighbor_route_map_cmd, - NEIGHBOR_CMD2 "route-map WORD (in|out)", + NEIGHBOR_CMD2 "route-map WORD (in|out|import|export)", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Apply route map to neighbor\n" "Name of route map\n" "Apply map to incoming routes\n" - "Apply map to outbound routes\n") + "Apply map to outbound routes\n" + "Apply map to routes going into a Route-Server client's table\n" + "Apply map to routes coming from a Route-Server client") { return peer_route_map_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), argv[1], argv[2]); @@ -3322,14 +3485,16 @@ DEFUN (neighbor_route_map, DEFUN (no_neighbor_route_map, no_neighbor_route_map_cmd, - NO_NEIGHBOR_CMD2 "route-map WORD (in|out)", + NO_NEIGHBOR_CMD2 "route-map WORD (in|out|import|export)", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Apply route map to neighbor\n" "Name of route map\n" "Apply map to incoming routes\n" - "Apply map to outbound routes\n") + "Apply map to outbound routes\n" + "Apply map to routes going into a Route-Server client's table\n" + "Apply map to routes coming from a Route-Server client") { return peer_route_map_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), argv[2]); @@ -5990,6 +6155,166 @@ ALIAS (clear_bgp_as_soft, "Clear peers with the AS number\n" "Soft reconfig\n") +/* RS-client soft reconfiguration. */ +#ifdef HAVE_IPV6 +DEFUN (clear_bgp_all_rsclient, + clear_bgp_all_rsclient_cmd, + "clear bgp * rsclient", + CLEAR_STR + BGP_STR + "Clear all peers\n" + "Soft reconfig for rsclient RIB\n") +{ + if (argc == 1) + return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_RSCLIENT, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_RSCLIENT, NULL); +} + +ALIAS (clear_bgp_all_rsclient, + clear_bgp_ipv6_all_rsclient_cmd, + "clear bgp ipv6 * rsclient", + CLEAR_STR + BGP_STR + "Address family\n" + "Clear all peers\n" + "Soft reconfig for rsclient RIB\n") + +ALIAS (clear_bgp_all_rsclient, + clear_bgp_instance_all_rsclient_cmd, + "clear bgp view WORD * rsclient", + CLEAR_STR + BGP_STR + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Soft reconfig for rsclient RIB\n") + +ALIAS (clear_bgp_all_rsclient, + clear_bgp_ipv6_instance_all_rsclient_cmd, + "clear bgp ipv6 view WORD * rsclient", + CLEAR_STR + BGP_STR + "Address family\n" + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Soft reconfig for rsclient RIB\n") +#endif /* HAVE_IPV6 */ + +DEFUN (clear_ip_bgp_all_rsclient, + clear_ip_bgp_all_rsclient_cmd, + "clear ip bgp * rsclient", + CLEAR_STR + IP_STR + BGP_STR + "Clear all peers\n" + "Soft reconfig for rsclient RIB\n") +{ + if (argc == 1) + return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_RSCLIENT, NULL); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, + BGP_CLEAR_SOFT_RSCLIENT, NULL); +} + +ALIAS (clear_ip_bgp_all_rsclient, + clear_ip_bgp_instance_all_rsclient_cmd, + "clear ip bgp view WORD * rsclient", + CLEAR_STR + IP_STR + BGP_STR + "BGP view\n" + "view name\n" + "Clear all peers\n" + "Soft reconfig for rsclient RIB\n") + +#ifdef HAVE_IPV6 +DEFUN (clear_bgp_peer_rsclient, + clear_bgp_peer_rsclient_cmd, + "clear bgp (A.B.C.D|X:X::X:X) rsclient", + CLEAR_STR + BGP_STR + "BGP neighbor IP address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig for rsclient RIB\n") +{ + if (argc == 2) + return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_peer, + BGP_CLEAR_SOFT_RSCLIENT, argv[1]); + + return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer, + BGP_CLEAR_SOFT_RSCLIENT, argv[0]); +} + +ALIAS (clear_bgp_peer_rsclient, + clear_bgp_ipv6_peer_rsclient_cmd, + "clear bgp ipv6 (A.B.C.D|X:X::X:X) rsclient", + CLEAR_STR + BGP_STR + "Address family\n" + "BGP neighbor IP address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig for rsclient RIB\n") + +ALIAS (clear_bgp_peer_rsclient, + clear_bgp_instance_peer_rsclient_cmd, + "clear bgp view WORD (A.B.C.D|X:X::X:X) rsclient", + CLEAR_STR + BGP_STR + "BGP view\n" + "view name\n" + "BGP neighbor IP address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig for rsclient RIB\n") + +ALIAS (clear_bgp_peer_rsclient, + clear_bgp_ipv6_instance_peer_rsclient_cmd, + "clear bgp ipv6 view WORD (A.B.C.D|X:X::X:X) rsclient", + CLEAR_STR + BGP_STR + "Address family\n" + "BGP view\n" + "view name\n" + "BGP neighbor IP address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig for rsclient RIB\n") +#endif /* HAVE_IPV6 */ + +DEFUN (clear_ip_bgp_peer_rsclient, + clear_ip_bgp_peer_rsclient_cmd, + "clear ip bgp (A.B.C.D|X:X::X:X) rsclient", + CLEAR_STR + IP_STR + BGP_STR + "BGP neighbor IP address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig for rsclient RIB\n") +{ + if (argc == 2) + return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_peer, + BGP_CLEAR_SOFT_RSCLIENT, argv[1]); + + return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, + BGP_CLEAR_SOFT_RSCLIENT, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_rsclient, + clear_ip_bgp_instance_peer_rsclient_cmd, + "clear ip bgp view WORD (A.B.C.D|X:X::X:X) rsclient", + CLEAR_STR + IP_STR + BGP_STR + "BGP view\n" + "view name\n" + "BGP neighbor IP address to clear\n" + "BGP IPv6 neighbor to clear\n" + "Soft reconfig for rsclient RIB\n") + + /* Show BGP peer's summary information. */ int bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi) @@ -6443,14 +6768,18 @@ bgp_show_peer_afi (struct vty *vty, struct peer *p, afi_t afi, safi_t safi) if (filter->plist[FILTER_IN].name || filter->dlist[FILTER_IN].name || filter->aslist[FILTER_IN].name - || filter->map[FILTER_IN].name) + || filter->map[RMAP_IN].name) vty_out (vty, " Inbound path policy configured%s", VTY_NEWLINE); if (filter->plist[FILTER_OUT].name || filter->dlist[FILTER_OUT].name || filter->aslist[FILTER_OUT].name - || filter->map[FILTER_OUT].name + || filter->map[RMAP_OUT].name || filter->usmap.name) vty_out (vty, " Outbound path policy configured%s", VTY_NEWLINE); + if (filter->map[RMAP_IMPORT].name) + vty_out (vty, " Import policy for this RS-client configured%s", VTY_NEWLINE); + if (filter->map[RMAP_EXPORT].name) + vty_out (vty, " Export policy for this RS-client configured%s", VTY_NEWLINE); /* prefix-list */ if (filter->plist[FILTER_IN].name) @@ -6489,15 +6818,25 @@ bgp_show_peer_afi (struct vty *vty, struct peer *p, afi_t afi, safi_t safi) VTY_NEWLINE); /* route-map. */ - if (filter->map[FILTER_IN].name) + if (filter->map[RMAP_IN].name) vty_out (vty, " Route map for incoming advertisements is %s%s%s", - filter->map[FILTER_IN].map ? "*" : "", - filter->map[FILTER_IN].name, + filter->map[RMAP_IN].map ? "*" : "", + filter->map[RMAP_IN].name, VTY_NEWLINE); - if (filter->map[FILTER_OUT].name) + if (filter->map[RMAP_OUT].name) vty_out (vty, " Route map for outgoing advertisements is %s%s%s", - filter->map[FILTER_OUT].map ? "*" : "", - filter->map[FILTER_OUT].name, + filter->map[RMAP_OUT].map ? "*" : "", + filter->map[RMAP_OUT].name, + VTY_NEWLINE); + if (filter->map[RMAP_IMPORT].name) + vty_out (vty, " Route map for advertisements going into this RS-client's table is %s%s%s", + filter->map[RMAP_IMPORT].map ? "*" : "", + filter->map[RMAP_IMPORT].name, + VTY_NEWLINE); + if (filter->map[RMAP_EXPORT].name) + vty_out (vty, " Route map for advertisements coming from this RS-client is %s%s%s", + filter->map[RMAP_EXPORT].map ? "*" : "", + filter->map[RMAP_EXPORT].name, VTY_NEWLINE); /* unsuppress-map */ @@ -7156,6 +7495,262 @@ DEFUN (show_ip_bgp_attr_info, return CMD_SUCCESS; } +int +bgp_write_rsclient_summary (struct vty *vty, struct peer *rsclient, + afi_t afi, safi_t safi) +{ + char timebuf[BGP_UPTIME_LEN]; + char rmbuf[14]; + char *rmname; + struct peer *peer; + struct listnode *nn; + int len; + int count = 0; + + if (CHECK_FLAG (rsclient->sflags, PEER_STATUS_GROUP)) + { + LIST_LOOP (rsclient->group->peer, peer, nn) + { + count++; + bgp_write_rsclient_summary (vty, peer, afi, safi); + } + return count; + } + + len = vty_out (vty, "%s", rsclient->host); + len = 16 - len; + + if (len < 1) + vty_out (vty, "%s%*s", VTY_NEWLINE, 16, " "); + else + vty_out (vty, "%*s", len, " "); + + switch (rsclient->version) + { + case BGP_VERSION_4: + vty_out (vty, "4 "); + break; + case BGP_VERSION_MP_4_DRAFT_00: + vty_out (vty, "4-"); + break; + } + + vty_out (vty, "%5d ", rsclient->as); + + rmname = ROUTE_MAP_EXPORT_NAME(&rsclient->filter[afi][safi]); + if ( rmname && strlen (rmname) > 13 ) + { + sprintf (rmbuf, "%13s", "..."); + rmname = strncpy (rmbuf, rmname, 10); + } + else if (! rmname) + rmname = "<none>"; + vty_out (vty, " %13s ", rmname); + + rmname = ROUTE_MAP_IMPORT_NAME(&rsclient->filter[afi][safi]); + if ( rmname && strlen (rmname) > 13 ) + { + sprintf (rmbuf, "%13s", "..."); + rmname = strncpy (rmbuf, rmname, 10); + } + else if (! rmname) + rmname = "<none>"; + vty_out (vty, " %13s ", rmname); + + vty_out (vty, "%8s", peer_uptime (rsclient->uptime, timebuf, BGP_UPTIME_LEN)); + + if (CHECK_FLAG (rsclient->flags, PEER_FLAG_SHUTDOWN)) + vty_out (vty, " Idle (Admin)"); + else if (CHECK_FLAG (rsclient->sflags, PEER_STATUS_PREFIX_OVERFLOW)) + vty_out (vty, " Idle (PfxCt)"); + else + vty_out (vty, " %-11s", LOOKUP(bgp_status_msg, rsclient->status)); + + vty_out (vty, "%s", VTY_NEWLINE); + + return 1; +} + +int +bgp_show_rsclient_summary (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi) +{ + struct peer *peer; + struct listnode *nn; + int count = 0; + + /* Header string for each address family. */ + static char header[] = "Neighbor V AS Export-Policy Import-Policy Up/Down State"; + + LIST_LOOP (bgp->rsclient, peer, nn) + { + if (peer->afc[afi][safi] && + CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) + { + if (! count) + { + vty_out (vty, + "Route Server's BGP router identifier %s%s", + inet_ntoa (bgp->router_id), VTY_NEWLINE); + vty_out (vty, + "Route Server's local AS number %d%s", bgp->as, + VTY_NEWLINE); + + vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, "%s%s", header, VTY_NEWLINE); + } + + count += bgp_write_rsclient_summary (vty, peer, afi, safi); + } + } + + if (count) + vty_out (vty, "%sTotal number of Route Server Clients %d%s", VTY_NEWLINE, + count, VTY_NEWLINE); + else + vty_out (vty, "No %s Route Server Client is configured%s", + afi == AFI_IP ? "IPv4" : "IPv6", VTY_NEWLINE); + + return CMD_SUCCESS; +} + +int +bgp_show_rsclient_summary_vty (struct vty *vty, char *name, afi_t afi, safi_t safi) +{ + struct bgp *bgp; + + if (name) + { + bgp = bgp_lookup_by_name (name); + + if (! bgp) + { + vty_out (vty, "%% No such BGP instance exist%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bgp_show_rsclient_summary (vty, bgp, afi, safi); + return CMD_SUCCESS; + } + + bgp = bgp_get_default (); + + if (bgp) + bgp_show_rsclient_summary (vty, bgp, afi, safi); + + return CMD_SUCCESS; +} + +/* 'show bgp rsclient' commands. */ +DEFUN (show_ip_bgp_rsclient_summary, + show_ip_bgp_rsclient_summary_cmd, + "show ip bgp rsclient summary", + SHOW_STR + IP_STR + BGP_STR + "Information about Route Server Clients\n" + "Summary of all Route Server Clients\n") +{ + return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_instance_rsclient_summary, + show_ip_bgp_instance_rsclient_summary_cmd, + "show ip bgp view WORD rsclient summary", + SHOW_STR + IP_STR + BGP_STR + "BGP view\n" + "View name\n" + "Information about Route Server Clients\n" + "Summary of all Route Server Clients\n") +{ + return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_ipv4_rsclient_summary, + show_ip_bgp_ipv4_rsclient_summary_cmd, + "show ip bgp ipv4 (unicast|multicast) rsclient summary", + SHOW_STR + IP_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Information about Route Server Clients\n" + "Summary of all Route Server Clients\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, SAFI_MULTICAST); + + return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_instance_ipv4_rsclient_summary, + show_ip_bgp_instance_ipv4_rsclient_summary_cmd, + "show ip bgp view WORD ipv4 (unicast|multicast) rsclient summary", + SHOW_STR + IP_STR + BGP_STR + "BGP view\n" + "View name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Information about Route Server Clients\n" + "Summary of all Route Server Clients\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST); + + return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_rsclient_summary, + show_bgp_rsclient_summary_cmd, + "show bgp rsclient summary", + SHOW_STR + BGP_STR + "Information about Route Server Clients\n" + "Summary of all Route Server Clients\n") +{ + return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); +} + +DEFUN (show_bgp_instance_rsclient_summary, + show_bgp_instance_rsclient_summary_cmd, + "show bgp view WORD rsclient summary", + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Information about Route Server Clients\n" + "Summary of all Route Server Clients\n") +{ + return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST); +} + +ALIAS (show_bgp_rsclient_summary, + show_bgp_ipv6_rsclient_summary_cmd, + "show bgp ipv6 rsclient summary", + SHOW_STR + BGP_STR + "Address family\n" + "Information about Route Server Clients\n" + "Summary of all Route Server Clients\n") + +ALIAS (show_bgp_instance_rsclient_summary, + show_bgp_instance_ipv6_rsclient_summary_cmd, + "show bgp view WORD ipv6 rsclient summary", + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Address family\n" + "Information about Route Server Clients\n" + "Summary of all Route Server Clients\n") +#endif /* HAVE IPV6 */ + /* Redistribute VTY commands. */ /* Utility function to convert user input route type string to route @@ -8066,6 +8661,10 @@ bgp_vty_init () install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged9_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged10_cmd); + /* "nexthop-local unchanged" commands */ + install_element (BGP_IPV6_NODE, &neighbor_nexthop_local_unchanged_cmd); + install_element (BGP_IPV6_NODE, &no_neighbor_nexthop_local_unchanged_cmd); + /* "transparent-as" and "transparent-nexthop" for old version compatibility. */ install_element (BGP_NODE, &neighbor_transparent_as_cmd); @@ -8562,6 +9161,22 @@ bgp_vty_init () install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_cmd); #endif /* HAVE_IPV6 */ + /* "clear ip bgp neighbor rsclient" */ + install_element (ENABLE_NODE, &clear_ip_bgp_all_rsclient_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_rsclient_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_peer_rsclient_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_instance_peer_rsclient_cmd); +#ifdef HAVE_IPV6 + install_element (ENABLE_NODE, &clear_bgp_all_rsclient_cmd); + install_element (ENABLE_NODE, &clear_bgp_instance_all_rsclient_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_all_rsclient_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_instance_all_rsclient_cmd); + install_element (ENABLE_NODE, &clear_bgp_peer_rsclient_cmd); + install_element (ENABLE_NODE, &clear_bgp_instance_peer_rsclient_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_rsclient_cmd); + install_element (ENABLE_NODE, &clear_bgp_ipv6_instance_peer_rsclient_cmd); +#endif /* HAVE_IPV6 */ + /* "show ip bgp summary" commands. */ install_element (VIEW_NODE, &show_ip_bgp_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_instance_summary_cmd); @@ -8635,6 +9250,27 @@ bgp_vty_init () install_element (ENABLE_NODE, &show_ipv6_mbgp_summary_cmd); #endif /* HAVE_IPV6 */ + /* "show ip bgp rsclient" commands. */ + install_element (VIEW_NODE, &show_ip_bgp_rsclient_summary_cmd); + install_element (VIEW_NODE, &show_ip_bgp_instance_rsclient_summary_cmd); + install_element (VIEW_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd); + install_element (VIEW_NODE, &show_ip_bgp_instance_ipv4_rsclient_summary_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_rsclient_summary_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_instance_rsclient_summary_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_instance_ipv4_rsclient_summary_cmd); + +#ifdef HAVE_IPV6 + install_element (VIEW_NODE, &show_bgp_rsclient_summary_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_rsclient_summary_cmd); + install_element (VIEW_NODE, &show_bgp_instance_rsclient_summary_cmd); + install_element (VIEW_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd); + install_element (ENABLE_NODE, &show_bgp_rsclient_summary_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_rsclient_summary_cmd); + install_element (ENABLE_NODE, &show_bgp_instance_rsclient_summary_cmd); + install_element (ENABLE_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd); +#endif /* HAVE_IPV6 */ + /* "show ip bgp paths" commands. */ install_element (VIEW_NODE, &show_ip_bgp_paths_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_paths_cmd); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 47df3c83..6afbe959 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -531,6 +531,23 @@ bgp_default_local_preference_unset (struct bgp *bgp) return 0; } +/* If peer is RSERVER_CLIENT in at least one address family and is not member + of a peer_group for that family, return 1. + Used to check wether the peer is included in list bgp->rsclient. */ +int +peer_rsclient_active (struct peer *peer) +{ + int i; + int j; + + for (i=AFI_IP; i < AFI_MAX; i++) + for (j=SAFI_UNICAST; j < SAFI_MAX; j++) + if (CHECK_FLAG(peer->af_flags[i][j], PEER_FLAG_RSERVER_CLIENT) + && ! peer->af_group[i][j]) + return 1; + return 0; +} + /* Peer comparison function for sorting. */ static int peer_cmp (struct peer *p1, struct peer *p2) @@ -572,6 +589,9 @@ peer_af_flag_reset (struct peer *peer, afi_t afi, safi_t safi) free (filter->aslist[i].name); filter->aslist[i].name = NULL; } + } + for (i = RMAP_IN; i < RMAP_MAX; i++) + { if (filter->map[i].name) { free (filter->map[i].name); @@ -1092,7 +1112,18 @@ peer_delete (struct peer *peer) /* Delete from all peer list. */ if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { listnode_delete (bgp->peer, peer); + if (peer_rsclient_active (peer)) + listnode_delete (bgp->rsclient, peer); + } + + /* Free RIB for any family in which peer is RSERVER_CLIENT, and is not + member of a peer_group. */ + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + if (peer->rib[afi][safi] && ! peer->af_group[afi][safi]) + bgp_table_finish (peer->rib[afi][safi]); /* Buffer. */ if (peer->ibuf) @@ -1134,6 +1165,9 @@ peer_delete (struct peer *peer) free (filter->plist[i].name); if (filter->aslist[i].name) free (filter->aslist[i].name); + } + for (i = RMAP_IN; i < RMAP_MAX; i++) + { if (filter->map[i].name) free (filter->map[i].name); } @@ -1300,6 +1334,34 @@ peer_group2peer_config_copy (struct peer_group *group, struct peer *peer, /* allowas-in */ peer->allowas_in[afi][safi] = conf->allowas_in[afi][safi]; + /* route-server-client */ + if (CHECK_FLAG(conf->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) + { + /* Make peer's RIB point to group's RIB. */ + peer->rib[afi][safi] = group->conf->rib[afi][safi]; + + /* Import policy. */ + if (pfilter->map[RMAP_IMPORT].name) + free (pfilter->map[RMAP_IMPORT].name); + if (gfilter->map[RMAP_IMPORT].name) + { + pfilter->map[RMAP_IMPORT].name = strdup (gfilter->map[RMAP_IMPORT].name); + pfilter->map[RMAP_IMPORT].map = gfilter->map[RMAP_IMPORT].map; + } + else + { + pfilter->map[RMAP_IMPORT].name = NULL; + pfilter->map[RMAP_IMPORT].map = NULL; + } + + /* Export policy. */ + if (gfilter->map[RMAP_EXPORT].name && ! pfilter->map[RMAP_EXPORT].name) + { + pfilter->map[RMAP_EXPORT].name = strdup (gfilter->map[RMAP_EXPORT].name); + pfilter->map[RMAP_EXPORT].map = gfilter->map[RMAP_EXPORT].map; + } + } + /* default-originate route-map */ if (conf->default_rmap[afi][safi].name) { @@ -1355,12 +1417,12 @@ peer_group2peer_config_copy (struct peer_group *group, struct peer *peer, pfilter->aslist[in].name = strdup (gfilter->aslist[in].name); pfilter->aslist[in].aslist = gfilter->aslist[in].aslist; } - if (gfilter->map[in].name && ! pfilter->map[in].name) + if (gfilter->map[RMAP_IN].name && ! pfilter->map[RMAP_IN].name) { - if (pfilter->map[in].name) - free (pfilter->map[in].name); - pfilter->map[in].name = strdup (gfilter->map[in].name); - pfilter->map[in].map = gfilter->map[in].map; + if (pfilter->map[RMAP_IN].name) + free (pfilter->map[RMAP_IN].name); + pfilter->map[RMAP_IN].name = strdup (gfilter->map[RMAP_IN].name); + pfilter->map[RMAP_IN].map = gfilter->map[RMAP_IN].map; } /* outbound filter apply */ @@ -1406,19 +1468,42 @@ peer_group2peer_config_copy (struct peer_group *group, struct peer *peer, pfilter->aslist[out].name = NULL; pfilter->aslist[out].aslist = NULL; } - if (gfilter->map[out].name) + if (gfilter->map[RMAP_OUT].name) + { + if (pfilter->map[RMAP_OUT].name) + free (pfilter->map[RMAP_OUT].name); + pfilter->map[RMAP_OUT].name = strdup (gfilter->map[RMAP_OUT].name); + pfilter->map[RMAP_OUT].map = gfilter->map[RMAP_OUT].map; + } + else + { + if (pfilter->map[RMAP_OUT].name) + free (pfilter->map[RMAP_OUT].name); + pfilter->map[RMAP_OUT].name = NULL; + pfilter->map[RMAP_OUT].map = NULL; + } + + /* RS-client's import/export route-maps. */ + if (gfilter->map[RMAP_IMPORT].name) { - if (pfilter->map[out].name) - free (pfilter->map[out].name); - pfilter->map[out].name = strdup (gfilter->map[out].name); - pfilter->map[out].map = gfilter->map[out].map; + if (pfilter->map[RMAP_IMPORT].name) + free (pfilter->map[RMAP_IMPORT].name); + pfilter->map[RMAP_IMPORT].name = strdup (gfilter->map[RMAP_IMPORT].name); + pfilter->map[RMAP_IMPORT].map = gfilter->map[RMAP_IMPORT].map; } else { - if (pfilter->map[out].name) - free (pfilter->map[out].name); - pfilter->map[out].name = NULL; - pfilter->map[out].map = NULL; + if (pfilter->map[RMAP_IMPORT].name) + free (pfilter->map[RMAP_IMPORT].name); + pfilter->map[RMAP_IMPORT].name = NULL; + pfilter->map[RMAP_IMPORT].map = NULL; + } + if (gfilter->map[RMAP_EXPORT].name && ! pfilter->map[RMAP_EXPORT].name) + { + if (pfilter->map[RMAP_EXPORT].name) + free (pfilter->map[RMAP_EXPORT].name); + pfilter->map[RMAP_EXPORT].name = strdup (gfilter->map[RMAP_EXPORT].name); + pfilter->map[RMAP_EXPORT].map = gfilter->map[RMAP_EXPORT].map; } if (gfilter->usmap.name) @@ -1601,6 +1686,35 @@ peer_group_bind (struct bgp *bgp, union sockunion *su, UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); } } + + if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) + { + /* If it's not configured as RSERVER_CLIENT in any other address + family, without being member of a peer_group, remove it from + list bgp->rsclient.*/ + if (! peer_rsclient_active (peer)) + listnode_delete (bgp->rsclient, peer); + + bgp_table_finish (peer->rib[afi][safi]); + + /* Import policy. */ + if (peer->filter[afi][safi].map[RMAP_IMPORT].name) + { + free (peer->filter[afi][safi].map[RMAP_IMPORT].name); + peer->filter[afi][safi].map[RMAP_IMPORT].name = NULL; + peer->filter[afi][safi].map[RMAP_IMPORT].map = NULL; + } + + /* Export policy. */ + if (! CHECK_FLAG(group->conf->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) + && peer->filter[afi][safi].map[RMAP_EXPORT].name) + { + free (peer->filter[afi][safi].map[RMAP_EXPORT].name); + peer->filter[afi][safi].map[RMAP_EXPORT].name = NULL; + peer->filter[afi][safi].map[RMAP_EXPORT].map = NULL; + } + } + peer_group2peer_config_copy (group, peer, afi, safi); if (peer->status == Established) @@ -1629,6 +1743,9 @@ peer_group_unbind (struct bgp *bgp, struct peer *peer, peer->afc[afi][safi] = 0; peer_af_flag_reset (peer, afi, safi); + if (peer->rib[afi][safi]) + peer->rib[afi][safi] = NULL; + if (! peer_group_active (peer)) { listnode_delete (group->peer, peer); @@ -1672,6 +1789,9 @@ bgp_create (as_t *as, char *name) bgp->group = list_new (); bgp->group->cmp = (int (*)(void *, void *)) peer_group_cmp; + bgp->rsclient = list_new (); + bgp->rsclient->cmp = (int (*)(void*, void*)) peer_cmp; + for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { @@ -1826,6 +1946,9 @@ bgp_delete (struct bgp *bgp) peer_delete (peer); } + bgp->rsclient->del = (void (*)(void *)) peer_delete; + list_delete (bgp->rsclient); + listnode_delete (bm->bgp, bgp); if (bgp->name) @@ -2007,6 +2130,7 @@ struct peer_flag_action peer_af_flag_action_list[] = { PEER_FLAG_ALLOWAS_IN, 0, peer_change_reset_in }, { PEER_FLAG_ORF_PREFIX_SM, 1, peer_change_reset }, { PEER_FLAG_ORF_PREFIX_RM, 1, peer_change_reset }, + { PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED, 0, peer_change_reset_out }, { 0, 0, 0 } }; @@ -3551,10 +3675,12 @@ peer_aslist_unset (struct peer *peer,afi_t afi, safi_t safi, int direct) if (! peer->afc[afi][safi]) return BGP_ERR_PEER_INACTIVE; - if (direct != FILTER_IN && direct != FILTER_OUT) + if (direct != RMAP_IN && direct != RMAP_OUT && + direct != RMAP_IMPORT && direct != RMAP_EXPORT) return BGP_ERR_INVALID_VALUE; - if (direct == FILTER_OUT && peer_is_group_member (peer, afi, safi)) + if ( (direct == RMAP_OUT || direct == RMAP_IMPORT) + && peer_is_group_member (peer, afi, safi)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; filter = &peer->filter[afi][safi]; @@ -3662,10 +3788,12 @@ peer_route_map_set (struct peer *peer, afi_t afi, safi_t safi, int direct, if (! peer->afc[afi][safi]) return BGP_ERR_PEER_INACTIVE; - if (direct != FILTER_IN && direct != FILTER_OUT) + if (direct != RMAP_IN && direct != RMAP_OUT && + direct != RMAP_IMPORT && direct != RMAP_EXPORT) return BGP_ERR_INVALID_VALUE; - if (direct == FILTER_OUT && peer_is_group_member (peer, afi, safi)) + if ( (direct == RMAP_OUT || direct == RMAP_IMPORT) + && peer_is_group_member (peer, afi, safi)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; filter = &peer->filter[afi][safi]; @@ -3950,6 +4078,14 @@ peer_clear_soft (struct peer *peer, afi_t afi, safi_t safi, if (! peer->afc[afi][safi]) return BGP_ERR_AF_UNCONFIGURED; + if (stype == BGP_CLEAR_SOFT_RSCLIENT) + { + if (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) + return 0; + bgp_check_local_routes_rsclient (peer, afi, safi); + bgp_soft_reconfig_rsclient (peer, afi, safi); + } + if (stype == BGP_CLEAR_SOFT_OUT || stype == BGP_CLEAR_SOFT_BOTH) bgp_announce_route (peer, afi, safi); @@ -4086,14 +4222,23 @@ bgp_config_write_filter (struct vty *vty, struct peer *peer, filter->plist[out].name, VTY_NEWLINE); /* route-map. */ - if (filter->map[in].name) - if (! gfilter || ! gfilter->map[in].name - || strcmp (filter->map[in].name, gfilter->map[in].name) != 0) + if (filter->map[RMAP_IN].name) + if (! gfilter || ! gfilter->map[RMAP_IN].name + || strcmp (filter->map[RMAP_IN].name, gfilter->map[RMAP_IN].name) != 0) vty_out (vty, " neighbor %s route-map %s in%s", addr, - filter->map[in].name, VTY_NEWLINE); - if (filter->map[out].name && ! gfilter) + filter->map[RMAP_IN].name, VTY_NEWLINE); + if (filter->map[RMAP_OUT].name && ! gfilter) vty_out (vty, " neighbor %s route-map %s out%s", addr, - filter->map[out].name, VTY_NEWLINE); + filter->map[RMAP_OUT].name, VTY_NEWLINE); + if (filter->map[RMAP_IMPORT].name && ! gfilter) + vty_out (vty, " neighbor %s route-map %s import%s", addr, + filter->map[RMAP_IMPORT].name, VTY_NEWLINE); + if (filter->map[RMAP_EXPORT].name) + if (! gfilter || ! gfilter->map[RMAP_EXPORT].name + || strcmp (filter->map[RMAP_EXPORT].name, + gfilter->map[RMAP_EXPORT].name) != 0) + vty_out (vty, " neighbor %s route-map %s export%s", addr, + filter->map[RMAP_EXPORT].name, VTY_NEWLINE); /* unsuppress-map */ if (filter->usmap.name && ! gfilter) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 818f7dc8..61472d85 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -65,6 +65,9 @@ struct bgp /* BGP peer group. */ struct list *group; + /* BGP route-server-clients. */ + struct list *rsclient; + /* BGP configuration. */ u_int16_t config; #define BGP_CONFIG_ROUTER_ID (1 << 0) @@ -186,6 +189,12 @@ struct bgp_rd u_char val[BGP_RD_SIZE]; }; +#define RMAP_IN 0 +#define RMAP_OUT 1 +#define RMAP_IMPORT 2 +#define RMAP_EXPORT 3 +#define RMAP_MAX 4 + /* BGP filter structure. */ struct bgp_filter { @@ -215,7 +224,7 @@ struct bgp_filter { char *name; struct route_map *map; - } map[FILTER_MAX]; + } map[RMAP_MAX]; /* Unsuppress-map. */ struct @@ -250,6 +259,9 @@ struct peer /* Local router ID. */ struct in_addr local_id; + /* Peer specific RIB when configured as route-server-client. */ + struct bgp_table *rib[AFI_MAX][SAFI_MAX]; + /* Packet receive and send buffer. */ struct stream *ibuf; struct stream_fifo *obuf; @@ -341,6 +353,7 @@ struct peer #define PEER_FLAG_ORF_PREFIX_RM (1 << 13) /* orf capability receive-mode */ #define PEER_FLAG_MAX_PREFIX (1 << 14) /* maximum prefix */ #define PEER_FLAG_MAX_PREFIX_WARNING (1 << 15) /* maximum prefix warning-only */ +#define PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED (1 << 16) /* leave link-local nexthop unchanged */ /* default-originate route-map. */ struct @@ -480,6 +493,8 @@ struct peer #define PEER_RMAP_TYPE_REDISTRIBUTE (1 << 3) /* redistribute route-map */ #define PEER_RMAP_TYPE_DEFAULT (1 << 4) /* default-originate route-map */ #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 */ }; /* This structure's member directly points incoming packet data @@ -689,7 +704,8 @@ enum bgp_clear_type BGP_CLEAR_SOFT_OUT, BGP_CLEAR_SOFT_IN, BGP_CLEAR_SOFT_BOTH, - BGP_CLEAR_SOFT_IN_ORF_PREFIX + BGP_CLEAR_SOFT_IN_ORF_PREFIX, + BGP_CLEAR_SOFT_RSCLIENT }; /* Macros. */ @@ -797,6 +813,8 @@ int bgp_timers_unset (struct bgp *); int bgp_default_local_preference_set (struct bgp *, u_int32_t); int bgp_default_local_preference_unset (struct bgp *); +int peer_rsclient_active (struct peer *); + int peer_remote_as (struct bgp *, union sockunion *, as_t *, afi_t, safi_t); int peer_group_remote_as (struct bgp *, char *, as_t *); int peer_delete (struct peer *peer); diff --git a/lib/routemap.c b/lib/routemap.c index 9995334e..9d6bbcfd 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -26,6 +26,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "prefix.h" #include "routemap.h" #include "command.h" +#include "log.h" /* Vector for route match rules. */ static vector route_match_vec; @@ -221,9 +222,11 @@ vty_show_route_map_entry (struct vty *vty, struct route_map *map) rule->cmd->str, rule->rule_str, VTY_NEWLINE); vty_out (vty, " Action:%s", VTY_NEWLINE); - if (index->exitpolicy == RMAP_GOTO) + + if (index->nextrm) + vty_out (vty, " Call %s%s", index->nextrm, VTY_NEWLINE); + else if (index->exitpolicy == RMAP_GOTO) vty_out (vty, " Goto %d%s", index->nextpref, VTY_NEWLINE); - else if (index->exitpolicy == RMAP_NEXT) { vty_out (vty, " Goto next, (entry "); @@ -298,6 +301,10 @@ route_map_index_delete (struct route_map_index *index, int notify) else index->map->head = index->next; + /* Free 'char *nextrm' if not NULL */ + if (index->nextrm) + free (index->nextrm); + /* Execute event hook. */ if (route_map_master.event_hook && notify) (*route_map_master.event_hook) (RMAP_EVENT_INDEX_DELETED, @@ -688,18 +695,26 @@ route_map_delete_set (struct route_map_index *index, char *set_name, deny deny | cont | - action) Apply Set statements, accept route - If NEXT is specified, goto NEXT statement - If GOTO is specified, goto the first clause where pref > nextpref - If nothing is specified, do as Cisco and finish - deny) If NEXT is specified, goto NEXT statement - If nothing is specified, finally will be denied by route-map. - cont) Goto Next index + action) + -Apply Set statements, accept route + -If Call statement is present jump to the specified route-map, if it + denies the route we finish. + -If NEXT is specified, goto NEXT statement + -If GOTO is specified, goto the first clause where pref > nextpref + -If nothing is specified, do as Cisco and finish + deny) + -Route is denied by route-map. + cont) + -Goto Next index If we get no matches after we've processed all updates, then the route is dropped too. - Some notes on the new "NEXT" and "GOTO" + Some notes on the new "CALL", "NEXT" and "GOTO" + call WORD - If this clause is matched, then the set statements + are executed and then we jump to route-map 'WORD'. If + this route-map denies the route, we finish, in other case we + do whatever the exit policy (EXIT, NEXT or GOTO) tells. on-match next - If this clause is matched, then the set statements are executed and then we drop through to the next clause on-match goto n - If this clause is matched, then the set statments @@ -746,10 +761,20 @@ route_map_result_t route_map_apply (struct route_map *map, struct prefix *prefix, route_map_object_t type, void *object) { + static int recursion = 0; int ret = 0; struct route_map_index *index; struct route_map_rule *set; + if (recursion > RMAP_RECURSION_LIMIT) + { + zlog (NULL, LOG_WARNING, + "route-map recursion limit (%d) reached, discarding route", + RMAP_RECURSION_LIMIT); + recursion = 0; + return RMAP_DENYMATCH; + } + if (map == NULL) return RMAP_DENYMATCH; @@ -771,6 +796,25 @@ route_map_apply (struct route_map *map, struct prefix *prefix, for (set = index->set_list.head; set; set = set->next) ret = (*set->cmd->func_apply) (set->value, prefix, type, object); + + /* Call another route-map if available */ + if (index->nextrm) + { + struct route_map *nextrm = + route_map_lookup_by_name (index->nextrm); + + if (nextrm) /* Target route-map found, jump to it */ + { + recursion++; + ret = route_map_apply (nextrm, prefix, type, object); + recursion--; + } + + /* If nextrm returned 'deny', finish. */ + if (ret == RMAP_DENYMATCH) + return ret; + } + switch (index->exitpolicy) { case RMAP_EXIT: @@ -781,8 +825,9 @@ route_map_apply (struct route_map *map, struct prefix *prefix, { /* Find the next clause to jump to */ struct route_map_index *next = index->next; + int nextpref = index->nextpref; - while (next && next->pref < index->nextpref) + while (next && next->pref < nextpref) { index = next; next = next->next; @@ -798,9 +843,6 @@ route_map_apply (struct route_map *map, struct prefix *prefix, else if (index->type == RMAP_DENY) /* 'deny' */ { - if (index->exitpolicy == RMAP_NEXT) - continue; - else return RMAP_DENYMATCH; } } @@ -1046,7 +1088,7 @@ DEFUN (no_rmap_onmatch_goto, "no on-match goto", NO_STR "Exit policy on matches\n" - "Next clause\n") + "Goto Clause number\n") { struct route_map_index *index; @@ -1103,6 +1145,49 @@ DEFUN (rmap_show_name, return vty_show_route_map (vty, argv[0]); } +ALIAS (rmap_onmatch_goto, + rmap_continue_index_cmd, + "continue <1-65536>", + "Exit policy on matches\n" + "Goto Clause number\n") + +DEFUN (rmap_call, + rmap_call_cmd, + "call WORD", + "Jump to another Route-Map after match+set\n" + "Target route-map name\n") +{ + struct route_map_index *index; + + index = vty->index; + if (index) + { + if (index->nextrm) + free (index->nextrm); + index->nextrm = strdup (argv[0]); + } + return CMD_SUCCESS; +} + +DEFUN (no_rmap_call, + no_rmap_call_cmd, + "no call", + NO_STR + "Jump to another Route-Map after match+set\n") +{ + struct route_map_index *index; + + index = vty->index; + + if (index->nextrm) + { + free (index->nextrm); + index->nextrm = NULL; + } + + return CMD_SUCCESS; +} + /* Configuration write function. */ int route_map_config_write (struct vty *vty) @@ -1135,9 +1220,10 @@ route_map_config_write (struct vty *vty) vty_out (vty, " set %s %s%s", rule->cmd->str, rule->rule_str ? rule->rule_str : "", VTY_NEWLINE); + if (index->nextrm) + vty_out (vty, " call %s%s", index->nextrm, VTY_NEWLINE); if (index->exitpolicy == RMAP_GOTO) - vty_out (vty, " on-match goto %d%s", index->nextpref, - VTY_NEWLINE); + vty_out (vty, " on-match goto %d%s", index->nextpref, VTY_NEWLINE); if (index->exitpolicy == RMAP_NEXT) vty_out (vty," on-match next%s", VTY_NEWLINE); @@ -1173,7 +1259,16 @@ route_map_init_vty () install_element (RMAP_NODE, &no_rmap_onmatch_next_cmd); install_element (RMAP_NODE, &rmap_onmatch_goto_cmd); install_element (RMAP_NODE, &no_rmap_onmatch_goto_cmd); - + + /* Install the continue stuff (ALIAS of on-match). */ + install_element (RMAP_NODE, &rmap_continue_cmd); + install_element (RMAP_NODE, &no_rmap_continue_cmd); + install_element (RMAP_NODE, &rmap_continue_index_cmd); + + /* Install the call stuff. */ + install_element (RMAP_NODE, &rmap_call_cmd); + install_element (RMAP_NODE, &no_rmap_call_cmd); + /* Install show command */ install_element (ENABLE_NODE, &rmap_show_cmd); install_element (ENABLE_NODE, &rmap_show_name_cmd); diff --git a/lib/routemap.h b/lib/routemap.h index e37f1e7b..4fd9e5e9 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -67,6 +67,9 @@ typedef enum RMAP_EVENT_INDEX_DELETED } route_map_event_t; +/* Depth limit in RMAP recursion using RMAP_CALL. */ +#define RMAP_RECURSION_LIMIT 10 + /* Route map rule structure for matching and setting. */ struct route_map_rule_cmd { @@ -118,6 +121,9 @@ struct route_map_index /* If we're using "GOTO", to where do we go? */ int nextpref; + /* If we're using "CALL", to which route-map do ew go? */ + char *nextrm; + /* Matching rule list. */ struct route_map_rule_list match_list; struct route_map_rule_list set_list; |