bgpd: bgpd-table-map.patch

COMMAND:

table-map <route-map-name>

DESCRIPTION:

This feature is used to apply a route-map on route updates from BGP to Zebra.
All the applicable match operations are allowed, such as match on prefix,
next-hop, communities, etc. Set operations for this attach-point are limited
to metric and next-hop only. Any operation of this feature does not affect
BGPs internal RIB.

Supported for ipv4 and ipv6 address families. It works on multi-paths as well,
however, metric setting is based on the best-path only.

IMPLEMENTATION NOTES:

The route-map application at this point is not supposed to modify any of BGP
route's attributes (anything in bgp_info for that matter). To achieve that,
creating a copy of the bgp_attr was inevitable. Implementation tries to keep
the memory footprint low, code comments do point out the rationale behind a
few choices made.

bgp_zebra_announce() was already a big routine, adding this feature would
extend it further. Patch has created a few smaller routines/macros whereever
possible to keep the size of the routine in check without compromising on the
readability of the code/flow inside this routine.

For updating a partially filtered route (with its nexthops), BGP to Zebra
replacement semantic of the next-hops serves the purpose well. However, with
this patch there could be some redundant withdraws each time BGP announces a
route thats (all the nexthops) gets denied by the route-map application.
Handling of this case could be optimized by keeping state with the prefix and
the nexthops in BGP. The patch doesn't optimizing that case, as even with the
redundant withdraws the total number of updates to zebra are still be capped
by the total number of routes in the table.

Signed-off-by: Vipin Kumar <vipin@cumulusnetworks.com>
Reviewed-by: Pradosh Mohapatra <pmohapat@cumulusnetworks.com>
This commit is contained in:
Donald Sharp 2015-05-19 17:40:34 -07:00
parent 47fc97cc8d
commit 73ac816057
12 changed files with 496 additions and 129 deletions

View File

@ -150,7 +150,6 @@ cluster_free (struct cluster_list *cluster)
XFREE (MTYPE_CLUSTER, cluster);
}
#if 0
static struct cluster_list *
cluster_dup (struct cluster_list *cluster)
{
@ -169,7 +168,6 @@ cluster_dup (struct cluster_list *cluster)
return new;
}
#endif
static struct cluster_list *
cluster_intern (struct cluster_list *cluster)
@ -219,6 +217,23 @@ transit_free (struct transit *transit)
XFREE (MTYPE_TRANSIT, transit);
}
static struct transit *
transit_dup (struct transit *transit)
{
struct transit *new;
new = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
new->length = transit->length;
if (new->length)
{
new->val = XMALLOC (MTYPE_TRANSIT_VAL, transit->length);
memcpy (new->val, transit->val, transit->length);
}
else
new->val = NULL;
return new;
}
static void *
transit_hash_alloc (void *p)
@ -343,6 +358,46 @@ bgp_attr_dup (struct attr *new, struct attr *orig)
}
}
void
bgp_attr_deep_dup (struct attr *new, struct attr *orig)
{
if (orig->aspath)
new->aspath = aspath_dup(orig->aspath);
if (orig->community)
new->community = community_dup(orig->community);
if (orig->extra)
{
if (orig->extra->ecommunity)
new->extra->ecommunity = ecommunity_dup(orig->extra->ecommunity);
if (orig->extra->cluster)
new->extra->cluster = cluster_dup(orig->extra->cluster);
if (orig->extra->transit)
new->extra->transit = transit_dup(orig->extra->transit);
}
}
void
bgp_attr_deep_free (struct attr *attr)
{
if (attr->aspath)
aspath_free(attr->aspath);
if (attr->community)
community_free(attr->community);
if (attr->extra)
{
if (attr->extra->ecommunity)
ecommunity_free(&attr->extra->ecommunity);
if (attr->extra->cluster)
cluster_free(attr->extra->cluster);
if (attr->extra->transit)
transit_free(attr->extra->transit);
}
}
unsigned long int
attr_count (void)
{

View File

@ -155,6 +155,8 @@ extern int bgp_attr_check (struct peer *, struct attr *);
extern struct attr_extra *bgp_attr_extra_get (struct attr *);
extern void bgp_attr_extra_free (struct attr *);
extern void bgp_attr_dup (struct attr *, struct attr *);
extern void bgp_attr_deep_dup (struct attr *, struct attr *);
extern void bgp_attr_deep_free (struct attr *);
extern struct attr *bgp_attr_intern (struct attr *attr);
extern void bgp_attr_unintern_sub (struct attr *);
extern void bgp_attr_unintern (struct attr **);

View File

@ -24,6 +24,9 @@
#ifndef _QUAGGA_BGP_MPATH_H
#define _QUAGGA_BGP_MPATH_H
/* Limit on number of configured maxpaths */
#define BGP_MAXIMUM_MAXPATHS 255
/* BGP default maximum-paths */
#define BGP_DEFAULT_MAXPATHS 1

View File

@ -1598,7 +1598,7 @@ bgp_process_main (struct work_queue *wq, void *data)
{
if (CHECK_FLAG (old_select->flags, BGP_INFO_IGP_CHANGED) ||
CHECK_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG))
bgp_zebra_announce (p, old_select, bgp, safi);
bgp_zebra_announce (p, old_select, bgp, afi, safi);
UNSET_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG);
UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED);
@ -1629,7 +1629,7 @@ bgp_process_main (struct work_queue *wq, void *data)
if (new_select
&& new_select->type == ZEBRA_ROUTE_BGP
&& new_select->sub_type == BGP_ROUTE_NORMAL)
bgp_zebra_announce (p, new_select, bgp, safi);
bgp_zebra_announce (p, new_select, bgp, afi, safi);
else
{
/* Withdraw the route from the kernel. */
@ -4035,6 +4035,84 @@ bgp_static_unset_vpnv4 (struct vty *vty, const char *ip_str,
return CMD_SUCCESS;
}
static int
bgp_table_map_set (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
const char *rmap_name)
{
struct bgp_rmap *rmap;
rmap = &bgp->table_map[afi][safi];
if (rmap_name)
{
if (rmap->name)
free (rmap->name);
rmap->name = strdup (rmap_name);
rmap->map = route_map_lookup_by_name (rmap_name);
}
else
{
if (rmap->name)
free (rmap->name);
rmap->name = NULL;
rmap->map = NULL;
}
bgp_zebra_announce_table(bgp, afi, safi);
return CMD_SUCCESS;
}
static int
bgp_table_map_unset (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
const char *rmap_name)
{
struct bgp_rmap *rmap;
rmap = &bgp->table_map[afi][safi];
if (rmap->name)
free (rmap->name);
rmap->name = NULL;
rmap->map = NULL;
bgp_zebra_announce_table(bgp, afi, safi);
return CMD_SUCCESS;
}
int
bgp_config_write_table_map (struct vty *vty, struct bgp *bgp, afi_t afi,
safi_t safi, int *write)
{
if (bgp->table_map[afi][safi].name)
{
bgp_config_write_family_header (vty, afi, safi, write);
vty_out (vty, " table-map %s%s",
bgp->table_map[afi][safi].name, VTY_NEWLINE);
}
return 0;
}
DEFUN (bgp_table_map,
bgp_table_map_cmd,
"table-map WORD",
"BGP table to RIB route download filter\n"
"Name of the route map\n")
{
return bgp_table_map_set (vty, vty->index,
bgp_node_afi (vty), bgp_node_safi (vty), argv[0]);
}
DEFUN (no_bgp_table_map,
no_bgp_table_map_cmd,
"no table-map WORD",
"BGP table to RIB route download filter\n"
"Name of the route map\n")
{
return bgp_table_map_unset (vty, vty->index,
bgp_node_afi (vty), bgp_node_safi (vty), argv[0]);
}
DEFUN (bgp_network,
bgp_network_cmd,
"network A.B.C.D/M",
@ -12671,6 +12749,7 @@ bgp_route_init (void)
bgp_distance_table = bgp_table_init (AFI_IP, SAFI_UNICAST);
/* IPv4 BGP commands. */
install_element (BGP_NODE, &bgp_table_map_cmd);
install_element (BGP_NODE, &bgp_network_cmd);
install_element (BGP_NODE, &bgp_network_mask_cmd);
install_element (BGP_NODE, &bgp_network_mask_natural_cmd);
@ -12680,6 +12759,7 @@ bgp_route_init (void)
install_element (BGP_NODE, &bgp_network_backdoor_cmd);
install_element (BGP_NODE, &bgp_network_mask_backdoor_cmd);
install_element (BGP_NODE, &bgp_network_mask_natural_backdoor_cmd);
install_element (BGP_NODE, &no_bgp_table_map_cmd);
install_element (BGP_NODE, &no_bgp_network_cmd);
install_element (BGP_NODE, &no_bgp_network_mask_cmd);
install_element (BGP_NODE, &no_bgp_network_mask_natural_cmd);
@ -12712,12 +12792,14 @@ bgp_route_init (void)
install_element (BGP_NODE, &no_aggregate_address_mask_summary_as_set_cmd);
/* IPv4 unicast configuration. */
install_element (BGP_IPV4_NODE, &bgp_table_map_cmd);
install_element (BGP_IPV4_NODE, &bgp_network_cmd);
install_element (BGP_IPV4_NODE, &bgp_network_mask_cmd);
install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_cmd);
install_element (BGP_IPV4_NODE, &bgp_network_route_map_cmd);
install_element (BGP_IPV4_NODE, &bgp_network_mask_route_map_cmd);
install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_route_map_cmd);
install_element (BGP_IPV4_NODE, &no_bgp_table_map_cmd);
install_element (BGP_IPV4_NODE, &no_bgp_network_cmd);
install_element (BGP_IPV4_NODE, &no_bgp_network_mask_cmd);
install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_cmd);
@ -12747,12 +12829,14 @@ bgp_route_init (void)
install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_summary_as_set_cmd);
/* IPv4 multicast configuration. */
install_element (BGP_IPV4M_NODE, &bgp_table_map_cmd);
install_element (BGP_IPV4M_NODE, &bgp_network_cmd);
install_element (BGP_IPV4M_NODE, &bgp_network_mask_cmd);
install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_cmd);
install_element (BGP_IPV4M_NODE, &bgp_network_route_map_cmd);
install_element (BGP_IPV4M_NODE, &bgp_network_mask_route_map_cmd);
install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_route_map_cmd);
install_element (BGP_IPV4M_NODE, &no_bgp_table_map_cmd);
install_element (BGP_IPV4M_NODE, &no_bgp_network_cmd);
install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_cmd);
install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_cmd);
@ -13026,8 +13110,10 @@ bgp_route_init (void)
install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_prefix_counts_cmd);
/* New config IPv6 BGP commands. */
install_element (BGP_IPV6_NODE, &bgp_table_map_cmd);
install_element (BGP_IPV6_NODE, &ipv6_bgp_network_cmd);
install_element (BGP_IPV6_NODE, &ipv6_bgp_network_route_map_cmd);
install_element (BGP_IPV6_NODE, &no_bgp_table_map_cmd);
install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_cmd);
install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_route_map_cmd);

View File

@ -237,6 +237,8 @@ extern int bgp_withdraw (struct peer *, struct prefix *, struct attr *,
/* for bgp_nexthop and bgp_damp */
extern void bgp_process (struct bgp *, struct bgp_node *, afi_t, safi_t);
extern int bgp_config_write_table_map (struct vty *, struct bgp *, afi_t, safi_t,
int *);
extern int bgp_config_write_network (struct vty *, struct bgp *, afi_t, safi_t, int *);
extern int bgp_config_write_distance (struct vty *, struct bgp *);

View File

@ -45,6 +45,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_regex.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_clist.h"
@ -52,6 +53,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_ecommunity.h"
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_debug.h"
/* Memo of route-map commands.
@ -2409,6 +2411,23 @@ bgp_route_map_update (const char *unused)
}
}
/* For table route-map updates. */
for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
{
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
{
if (bgp->table_map[afi][safi].name)
{
bgp->table_map[afi][safi].map =
route_map_lookup_by_name (bgp->table_map[afi][safi].name);
bgp_zebra_announce_table(bgp, afi, safi);
}
else
bgp->table_map[afi][safi].map = NULL;
}
}
/* For network route-map updates. */
for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
{
@ -2443,6 +2462,32 @@ bgp_route_map_update (const char *unused)
}
}
static void
bgp_route_map_add (const char *unused)
{
if (BGP_DEBUG (events, EVENTS))
zlog_debug ("received route-map add");
bgp_route_map_update(unused);
}
static void
bgp_route_map_delete (const char *unused)
{
if (BGP_DEBUG (events, EVENTS))
zlog_debug ("received route-map delete");
bgp_route_map_update(unused);
}
static void
bgp_route_map_event (route_map_event_t event, const char *unused)
{
if (BGP_DEBUG (events, EVENTS))
zlog_debug ("received route-map event");
bgp_route_map_update(unused);
}
DEFUN (match_peer,
match_peer_cmd,
"match peer (A.B.C.D|X:X::X:X)",
@ -3897,8 +3942,9 @@ bgp_route_map_init (void)
{
route_map_init ();
route_map_init_vty ();
route_map_add_hook (bgp_route_map_update);
route_map_delete_hook (bgp_route_map_update);
route_map_add_hook (bgp_route_map_add);
route_map_delete_hook (bgp_route_map_delete);
route_map_event_hook (bgp_route_map_event);
route_map_install_match (&route_match_peer_cmd);
route_map_install_match (&route_match_ip_address_cmd);

View File

@ -672,7 +672,8 @@ bgp_maxpaths_config_vty (struct vty *vty, int peer_type, char *mpaths,
if (set)
{
VTY_GET_INTEGER_RANGE ("maximum-paths", maxpaths, mpaths, 1, 255);
VTY_GET_INTEGER_RANGE ("maximum-paths", maxpaths, mpaths, 1,
BGP_MAXIMUM_MAXPATHS);
ret = bgp_maximum_paths_set (bgp, afi, safi, peer_type, maxpaths,
options);
}

View File

@ -48,6 +48,43 @@ struct in_addr router_id_zebra;
struct stream *bgp_nexthop_buf = NULL;
struct stream *bgp_ifindices_buf = NULL;
/* These array buffers are used in making a copy of the attributes for
route-map apply. Arrays are being used here to minimize mallocs and
frees for the temporary copy of the attributes.
Given the zapi api expects the nexthop buffer to contain pointer to
pointers for nexthops, we couldnt have used a single nexthop variable
on the stack, hence we had two options:
1. maintain a linked-list and free it after zapi_*_route call
2. use an array to avoid number of mallocs.
Number of supported next-hops are finite, use of arrays should be ok. */
struct attr attr_cp[BGP_MAXIMUM_MAXPATHS];
struct attr_extra attr_extra_cp[BGP_MAXIMUM_MAXPATHS];
int attr_index = 0;
/* Once per address-family initialization of the attribute array */
#define BGP_INFO_ATTR_BUF_INIT()\
do {\
memset(attr_cp, 0, BGP_MAXIMUM_MAXPATHS * sizeof(struct attr));\
memset(attr_extra_cp, 0, BGP_MAXIMUM_MAXPATHS * sizeof(struct attr_extra));\
attr_index = 0;\
} while (0)
#define BGP_INFO_ATTR_BUF_COPY(info_src, info_dst)\
do { \
*info_dst = *info_src; \
assert(attr_index != BGP_MAXIMUM_MAXPATHS);\
attr_cp[attr_index].extra = &attr_extra_cp[attr_index]; \
bgp_attr_dup (&attr_cp[attr_index], info_src->attr); \
bgp_attr_deep_dup (&attr_cp[attr_index], info_src->attr); \
info_dst->attr = &attr_cp[attr_index]; \
attr_index++;\
} while (0)
#define BGP_INFO_ATTR_BUF_FREE(info) \
do { \
bgp_attr_deep_free(info->attr); \
} while (0)
/* Router-id update message from zebra. */
static int
bgp_router_id_update (int command, struct zclient *zclient, zebra_size_t length)
@ -671,15 +708,72 @@ bgp_nexthop_set (union sockunion *local, union sockunion *remote,
return ret;
}
static struct in6_addr *
bgp_info_to_ipv6_nexthop (struct bgp_info *info)
{
struct in6_addr *nexthop = NULL;
/* Only global address nexthop exists. */
if (info->attr->extra->mp_nexthop_len == 16)
nexthop = &info->attr->extra->mp_nexthop_global;
/* If both global and link-local address present. */
if (info->attr->extra->mp_nexthop_len == 32)
{
/* Workaround for Cisco's nexthop bug. */
if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->extra->mp_nexthop_global)
&& info->peer->su_remote->sa.sa_family == AF_INET6)
nexthop = &info->peer->su_remote->sin6.sin6_addr;
else
nexthop = &info->attr->extra->mp_nexthop_local;
}
return nexthop;
}
static int
bgp_table_map_apply (struct route_map *map, struct prefix *p,
struct bgp_info *info)
{
if (route_map_apply(map, p, RMAP_BGP, info) != RMAP_DENYMATCH)
return 1;
if (BGP_DEBUG(zebra, ZEBRA))
{
if (p->family == AF_INET)
{
char buf[2][INET_ADDRSTRLEN];
zlog_debug("Zebra rmap deny: IPv4 route %s/%d nexthop %s",
inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
p->prefixlen,
inet_ntop(AF_INET, &info->attr->nexthop, buf[1],
sizeof(buf[1])));
}
if (p->family == AF_INET6)
{
char buf[2][INET6_ADDRSTRLEN];
zlog_debug("Zebra rmap deny: IPv6 route %s/%d nexthop %s",
inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
p->prefixlen,
inet_ntop(AF_INET6, bgp_info_to_ipv6_nexthop(info), buf[1],
sizeof(buf[1])));
}
}
return 0;
}
void
bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, safi_t safi)
bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
afi_t afi, safi_t safi)
{
int flags;
u_char distance;
struct peer *peer;
struct bgp_info *mpinfo;
size_t oldsize, newsize;
u_int32_t nhcount;
u_int32_t nhcount, metric;
struct bgp_info local_info;
struct bgp_info *info_cp = &local_info;
if (zclient->sock < 0)
return;
@ -706,6 +800,8 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa
{
struct zapi_ipv4 api;
struct in_addr *nexthop;
char buf[2][INET_ADDRSTRLEN];
int valid_nh_count = 0;
/* resize nexthop buffer size if necessary */
if ((oldsize = stream_get_size (bgp_nexthop_buf)) <
@ -720,26 +816,72 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa
}
}
stream_reset (bgp_nexthop_buf);
nexthop = NULL;
/* Metric is currently based on the best-path only. */
metric = info->attr->med;
if (bgp->table_map[afi][safi].name)
{
BGP_INFO_ATTR_BUF_INIT();
/* Copy info and attributes, so the route-map apply doesn't modify the
BGP route info. */
BGP_INFO_ATTR_BUF_COPY(info, info_cp);
if (bgp_table_map_apply(bgp->table_map[afi][safi].map, p, info_cp))
{
metric = info_cp->attr->med;
nexthop = &info_cp->attr->nexthop;
}
BGP_INFO_ATTR_BUF_FREE(info_cp);
}
else
{
nexthop = &info->attr->nexthop;
}
if (nexthop)
{
stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *));
valid_nh_count++;
}
for (mpinfo = bgp_info_mpath_first (info); mpinfo;
mpinfo = bgp_info_mpath_next (mpinfo))
{
nexthop = NULL;
if (bgp->table_map[afi][safi].name)
{
/* Copy info and attributes, so the route-map apply doesn't modify the
BGP route info. */
BGP_INFO_ATTR_BUF_COPY(mpinfo, info_cp);
if (bgp_table_map_apply(bgp->table_map[afi][safi].map, p, info_cp))
nexthop = &info_cp->attr->nexthop;
BGP_INFO_ATTR_BUF_FREE(info_cp);
}
else
{
nexthop = &mpinfo->attr->nexthop;
}
if (nexthop == NULL)
continue;
stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *));
valid_nh_count++;
}
api.flags = flags;
nexthop = &info->attr->nexthop;
stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *));
for (mpinfo = bgp_info_mpath_first (info); mpinfo;
mpinfo = bgp_info_mpath_next (mpinfo))
{
nexthop = &mpinfo->attr->nexthop;
stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *));
}
api.type = ZEBRA_ROUTE_BGP;
api.message = 0;
api.safi = safi;
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
api.nexthop_num = nhcount;
api.nexthop_num = valid_nh_count;
api.nexthop = (struct in_addr **)STREAM_DATA (bgp_nexthop_buf);
api.ifindex_num = 0;
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
api.metric = info->attr->med;
api.metric = metric;
distance = bgp_distance_apply (p, info, bgp);
@ -750,23 +892,19 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa
}
if (BGP_DEBUG(zebra, ZEBRA))
{
int i;
char buf[2][INET_ADDRSTRLEN];
zlog_debug("Zebra send: IPv4 route add %s/%d nexthop %s metric %u"
" count %d",
inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
p->prefixlen,
inet_ntop(AF_INET, api.nexthop[0], buf[1], sizeof(buf[1])),
api.metric, api.nexthop_num);
for (i = 1; i < api.nexthop_num; i++)
zlog_debug("Zebra send: IPv4 route add [nexthop %d] %s",
i, inet_ntop(AF_INET, api.nexthop[i], buf[1],
sizeof(buf[1])));
}
{
int i;
zlog_debug("Zebra send: IPv4 route %s %s/%d metric %u"
" count %d", (valid_nh_count ? "add":"delete"),
inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
p->prefixlen, api.metric, api.nexthop_num);
for (i = 0; i < api.nexthop_num; i++)
zlog_debug(" IPv4 [nexthop %d] %s", i+1,
inet_ntop(AF_INET, api.nexthop[i], buf[1], sizeof(buf[1])));
}
zapi_ipv4_route (ZEBRA_IPV4_ROUTE_ADD, zclient,
(struct prefix_ipv4 *) p, &api);
zapi_ipv4_route (valid_nh_count ? ZEBRA_IPV4_ROUTE_ADD: ZEBRA_IPV4_ROUTE_DELETE,
zclient, (struct prefix_ipv4 *) p, &api);
}
#ifdef HAVE_IPV6
@ -777,6 +915,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa
struct in6_addr *nexthop;
struct zapi_ipv6 api;
int valid_nh_count = 0;
char buf[2][INET6_ADDRSTRLEN];
/* resize nexthop buffer size if necessary */
if ((oldsize = stream_get_size (bgp_nexthop_buf)) <
@ -810,94 +949,86 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa
nexthop = NULL;
assert (info->attr->extra);
/* Only global address nexthop exists. */
if (info->attr->extra->mp_nexthop_len == 16)
nexthop = &info->attr->extra->mp_nexthop_global;
/* If both global and link-local address present. */
if (info->attr->extra->mp_nexthop_len == 32)
{
/* Workaround for Cisco's nexthop bug. */
if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->extra->mp_nexthop_global)
&& peer->su_remote->sa.sa_family == AF_INET6)
nexthop = &peer->su_remote->sin6.sin6_addr;
else
nexthop = &info->attr->extra->mp_nexthop_local;
if (info->peer->nexthop.ifp)
ifindex = info->peer->nexthop.ifp->ifindex;
}
/* Metric is currently based on the best-path only. */
metric = info->attr->med;
if (nexthop == NULL)
return;
if (bgp->table_map[afi][safi].name)
{
BGP_INFO_ATTR_BUF_INIT();
if (!ifindex)
{
if (info->peer->ifname)
ifindex = if_nametoindex (info->peer->ifname);
else if (info->peer->nexthop.ifp)
ifindex = info->peer->nexthop.ifp->ifindex;
}
stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in6_addr *));
stream_put (bgp_ifindices_buf, &ifindex, sizeof (unsigned int));
valid_nh_count++;
for (mpinfo = bgp_info_mpath_first (info); mpinfo;
mpinfo = bgp_info_mpath_next (mpinfo))
{
ifindex = 0;
/* Only global address nexthop exists. */
if (mpinfo->attr->extra->mp_nexthop_len == 16)
nexthop = &mpinfo->attr->extra->mp_nexthop_global;
/* If both global and link-local address present. */
if (mpinfo->attr->extra->mp_nexthop_len == 32)
/* Copy info and attributes, so the route-map apply doesn't modify the
BGP route info. */
BGP_INFO_ATTR_BUF_COPY(info, info_cp);
if (bgp_table_map_apply(bgp->table_map[afi][safi].map, p, info_cp))
{
/* Workaround for Cisco's nexthop bug. */
if (IN6_IS_ADDR_UNSPECIFIED (&mpinfo->attr->extra->mp_nexthop_global)
&& mpinfo->peer->su_remote->sa.sa_family == AF_INET6)
{
nexthop = &mpinfo->peer->su_remote->sin6.sin6_addr;
}
else
{
nexthop = &mpinfo->attr->extra->mp_nexthop_local;
}
if (mpinfo->peer->nexthop.ifp)
{
ifindex = mpinfo->peer->nexthop.ifp->ifindex;
}
metric = info_cp->attr->med;
nexthop = bgp_info_to_ipv6_nexthop(info_cp);
}
BGP_INFO_ATTR_BUF_FREE(info_cp);
}
else
{
nexthop = bgp_info_to_ipv6_nexthop(info);
}
if (nexthop == NULL)
{
continue;
}
if (nexthop)
{
if (info->attr->extra->mp_nexthop_len == 32)
if (info->peer->nexthop.ifp)
ifindex = info->peer->nexthop.ifp->ifindex;
if (!ifindex)
{
if (mpinfo->peer->ifname)
{
ifindex = if_nametoindex (mpinfo->peer->ifname);
}
else if (mpinfo->peer->nexthop.ifp)
{
ifindex = mpinfo->peer->nexthop.ifp->ifindex;
}
}
if (ifindex == 0)
{
continue;
}
if (info->peer->ifname)
ifindex = if_nametoindex (info->peer->ifname);
else if (info->peer->nexthop.ifp)
ifindex = info->peer->nexthop.ifp->ifindex;
stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in6_addr *));
stream_put (bgp_ifindices_buf, &ifindex, sizeof (unsigned int));
valid_nh_count++;
}
}
for (mpinfo = bgp_info_mpath_first (info); mpinfo;
mpinfo = bgp_info_mpath_next (mpinfo))
{
ifindex = 0;
nexthop = NULL;
if (bgp->table_map[afi][safi].name)
{
/* Copy info and attributes, so the route-map apply doesn't modify the
BGP route info. */
BGP_INFO_ATTR_BUF_COPY(mpinfo, info_cp);
if (bgp_table_map_apply(bgp->table_map[afi][safi].map, p, info_cp))
nexthop = bgp_info_to_ipv6_nexthop(info_cp);
BGP_INFO_ATTR_BUF_FREE(info_cp);
}
else
{
nexthop = bgp_info_to_ipv6_nexthop(mpinfo);
}
if (nexthop == NULL)
continue;
if (mpinfo->attr->extra->mp_nexthop_len == 32)
if (mpinfo->peer->nexthop.ifp)
ifindex = mpinfo->peer->nexthop.ifp->ifindex;
if (!ifindex)
if (mpinfo->peer->ifname)
ifindex = if_nametoindex (mpinfo->peer->ifname);
else if (mpinfo->peer->nexthop.ifp)
ifindex = mpinfo->peer->nexthop.ifp->ifindex;
if (ifindex == 0)
continue;
stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in6_addr *));
stream_put (bgp_ifindices_buf, &ifindex, sizeof (unsigned int));
valid_nh_count++;
}
/* Make Zebra API structure. */
api.flags = flags;
@ -911,24 +1042,44 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa
api.ifindex_num = valid_nh_count;
api.ifindex = (unsigned int *)STREAM_DATA (bgp_ifindices_buf);
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
api.metric = info->attr->med;
api.metric = metric;
if (BGP_DEBUG(zebra, ZEBRA))
{
char buf[2][INET6_ADDRSTRLEN];
zlog_debug("Zebra send: IPv6 route add %s/%d nexthop %s metric %u",
inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
p->prefixlen,
inet_ntop(AF_INET6, nexthop, buf[1], sizeof(buf[1])),
api.metric);
}
{
int i;
zlog_debug("Zebra send: IPv6 route %s %s/%d metric %u",
valid_nh_count ? "add" : "delete",
inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
p->prefixlen, api.metric);
for (i = 0; i < api.nexthop_num; i++)
zlog_debug(" IPv6 [nexthop %d] %s", i+1,
inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1])));
}
zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient,
(struct prefix_ipv6 *) p, &api);
zapi_ipv6_route (valid_nh_count ? ZEBRA_IPV6_ROUTE_ADD : ZEBRA_IPV6_ROUTE_DELETE,
zclient, (struct prefix_ipv6 *) p, &api);
}
#endif /* HAVE_IPV6 */
}
/* Announce all routes of a table to zebra */
void
bgp_zebra_announce_table (struct bgp *bgp, afi_t afi, safi_t safi)
{
struct bgp_node *rn;
struct bgp_table *table;
struct bgp_info *ri;
table = bgp->rib[afi][safi];
for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
for (ri = rn->info; ri; ri = ri->next)
if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)
&& ri->type == ZEBRA_ROUTE_BGP
&& ri->sub_type == BGP_ROUTE_NORMAL)
bgp_zebra_announce (&rn->p, ri, bgp, afi, safi);
}
void
bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
{

View File

@ -33,7 +33,9 @@ extern int bgp_config_write_maxpaths (struct vty *, struct bgp *, afi_t,
safi_t, int *);
extern int bgp_config_write_redistribute (struct vty *, struct bgp *, afi_t, safi_t,
int *);
extern void bgp_zebra_announce (struct prefix *, struct bgp_info *, struct bgp *, safi_t);
extern void bgp_zebra_announce (struct prefix *, struct bgp_info *, struct bgp *,
afi_t, safi_t);
extern void bgp_zebra_announce_table (struct bgp *, afi_t, safi_t);
extern void bgp_zebra_withdraw (struct prefix *, struct bgp_info *, safi_t);
extern int bgp_redistribute_set (struct bgp *, afi_t, int);

View File

@ -5196,6 +5196,7 @@ bgp_config_write_family (struct vty *vty, struct bgp *bgp, afi_t afi,
}
bgp_config_write_maxpaths (vty, bgp, afi, safi, &write);
bgp_config_write_table_map (vty, bgp, afi, safi, &write);
if (write)
vty_out (vty, " exit-address-family%s", VTY_NEWLINE);
@ -5378,6 +5379,7 @@ bgp_config_write (struct vty *vty)
/* maximum-paths */
bgp_config_write_maxpaths (vty, bgp, AFI_IP, SAFI_UNICAST, &write);
bgp_config_write_table_map (vty, bgp, AFI_IP, SAFI_UNICAST, &write);
/* Distance configuration. */
bgp_config_write_distance (vty, bgp);

View File

@ -62,6 +62,13 @@ struct bgp_master
#define BGP_OPT_NO_LISTEN (1 << 3)
};
/* BGP route-map structure. */
struct bgp_rmap
{
char *name;
struct route_map *map;
};
/* BGP instance structure. */
struct bgp
{
@ -153,6 +160,9 @@ struct bgp
/* BGP routing information base. */
struct bgp_table *rib[AFI_MAX][SAFI_MAX];
/* BGP table route-map. */
struct bgp_rmap table_map[AFI_MAX][SAFI_MAX];
/* BGP redistribute configuration. */
u_char redist[AFI_MAX][ZEBRA_ROUTE_MAX];
@ -161,11 +171,7 @@ struct bgp
u_int32_t redist_metric[AFI_MAX][ZEBRA_ROUTE_MAX];
/* BGP redistribute route-map. */
struct
{
char *name;
struct route_map *map;
} rmap[AFI_MAX][ZEBRA_ROUTE_MAX];
struct bgp_rmap rmap[AFI_MAX][ZEBRA_ROUTE_MAX];
/* BGP distance configuration. */
u_char distance_ebgp;

View File

@ -247,6 +247,17 @@ and generates updates to its peers.
Default max-delay is 0, i.e. the feature is off by default.
@end deffn
@deffn {BGP} {table-map @var{route-map-name}} {}
This feature is used to apply a route-map on route updates from BGP to Zebra.
All the applicable match operations are allowed, such as match on prefix,
next-hop, communities, etc. Set operations for this attach-point are limited
to metric and next-hop only. Any operation of this feature does not affect
BGPs internal RIB.
Supported for ipv4 and ipv6 address families. It works on multi-paths as well,
however, metric setting is based on the best-path only.
@end deffn
@node BGP Peer
@section BGP Peer