summaryrefslogtreecommitdiff
path: root/bgpd/bgp_zebra.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_zebra.c')
-rw-r--r--bgpd/bgp_zebra.c141
1 files changed, 132 insertions, 9 deletions
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 23f626e960..22284fd28d 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -54,6 +54,7 @@
#include "bgpd/rfapi/vnc_export_bgp.h"
#endif
#include "bgpd/bgp_evpn.h"
+#include "bgpd/bgp_mplsvpn.h"
/* All information about zebra. */
struct zclient *zclient = NULL;
@@ -987,6 +988,7 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
struct bgp_info *mpinfo_cp = &local_info;
route_tag_t tag;
mpls_label_t label;
+ int nh_othervrf = 0;
/* Don't try to install if we're not connected to Zebra or Zebra doesn't
* know of this instance.
@@ -997,6 +999,12 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
if (bgp->main_zebra_update_hold)
return;
+ /*
+ * vrf leaking support (will have only one nexthop)
+ */
+ if (info->extra && info->extra->bgp_orig)
+ nh_othervrf = 1;
+
/* Make Zebra API structure. */
memset(&api, 0, sizeof(api));
memcpy(&api.rmac, &(info->attr->rmac), sizeof(struct ethaddr));
@@ -1008,6 +1016,21 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
peer = info->peer;
+ if (info->type == ZEBRA_ROUTE_BGP
+ && info->sub_type == BGP_ROUTE_IMPORTED) {
+
+ struct bgp_info *bi;
+
+ /*
+ * Look at parent chain for peer sort
+ */
+ for (bi = info; bi->extra && bi->extra->parent;
+ bi = bi->extra->parent) {
+
+ peer = ((struct bgp_info *)(bi->extra->parent))->peer;
+ }
+ }
+
tag = info->attr->tag;
/* When we create an aggregate route we must also install a Null0 route
@@ -1060,12 +1083,38 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
if (nh_family == AF_INET) {
struct in_addr *nexthop;
- if (bgp->table_map[afi][safi].name) {
+ if (bgp_debug_zebra(&api.prefix)) {
+ char buf_prefix[PREFIX_STRLEN];
+ prefix2str(&api.prefix, buf_prefix,
+ sizeof(buf_prefix));
+ if (mpinfo->extra) {
+ zlog_debug(
+ "%s: p=%s, bgp_is_valid_label: %d",
+ __func__, buf_prefix,
+ bgp_is_valid_label(
+ &mpinfo->extra
+ ->label[0]));
+ } else {
+ zlog_debug(
+ "%s: p=%s, extra is NULL, no label",
+ __func__, buf_prefix);
+ }
+ }
+
+ if (bgp->table_map[afi][safi].name || nh_othervrf) {
/* Copy info and attributes, so the route-map
apply doesn't modify the BGP route info. */
local_attr = *mpinfo->attr;
mpinfo_cp->attr = &local_attr;
+ if (nh_othervrf) {
+ /* allow route-map to modify */
+ local_attr.nexthop =
+ info->extra->nexthop_orig.u
+ .prefix4;
+ }
+ }
+ if (bgp->table_map[afi][safi].name) {
if (!bgp_table_map_apply(
bgp->table_map[afi][safi].map, p,
mpinfo_cp))
@@ -1082,6 +1131,9 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
nexthop = &mpinfo_cp->attr->nexthop;
api_nh->gate.ipv4 = *nexthop;
+ api_nh->vrf_id = nh_othervrf
+ ? info->extra->bgp_orig->vrf_id
+ : bgp->vrf_id;
/* EVPN type-2 routes are
programmed as onlink on l3-vni SVI
*/
@@ -1095,6 +1147,21 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
ifindex = 0;
+ if (bgp->table_map[afi][safi].name || nh_othervrf) {
+ /* Copy info and attributes, so the route-map
+ apply doesn't modify the BGP route info. */
+ local_attr = *mpinfo->attr;
+ mpinfo_cp->attr = &local_attr;
+ if (nh_othervrf) {
+ /* allow route-map to modify */
+ local_attr.mp_nexthop_global =
+ info->extra->nexthop_orig.u
+ .prefix6;
+ local_attr.mp_nexthop_len =
+ BGP_ATTR_NHLEN_IPV6_GLOBAL;
+ }
+ }
+
if (bgp->table_map[afi][safi].name) {
/* Copy info and attributes, so the route-map
apply doesn't modify the BGP route info. */
@@ -1139,6 +1206,9 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
api_nh->gate.ipv6 = *nexthop;
api_nh->ifindex = ifindex;
api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
+ /* api_nh->vrf_id is not set for normal case? */
+ if (nh_othervrf)
+ api_nh->vrf_id = info->extra->bgp_orig->vrf_id;
}
if (mpinfo->extra
@@ -1229,9 +1299,12 @@ void bgp_zebra_announce_table(struct bgp *bgp, afi_t afi, safi_t 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)
+ if (CHECK_FLAG(ri->flags, BGP_INFO_SELECTED) &&
+
+ (ri->type == ZEBRA_ROUTE_BGP
+ && (ri->sub_type == BGP_ROUTE_NORMAL
+ || ri->sub_type == BGP_ROUTE_IMPORTED)))
+
bgp_zebra_announce(rn, &rn->p, ri, bgp, afi,
safi);
}
@@ -1244,6 +1317,21 @@ void bgp_zebra_withdraw(struct prefix *p, struct bgp_info *info, safi_t safi)
peer = info->peer;
assert(peer);
+ if (info->type == ZEBRA_ROUTE_BGP
+ && info->sub_type == BGP_ROUTE_IMPORTED) {
+
+ struct bgp_info *bi;
+
+ /*
+ * Look at parent chain for peer sort
+ */
+ for (bi = info; bi->extra && bi->extra->parent;
+ bi = bi->extra->parent) {
+
+ peer = ((struct bgp_info *)(bi->extra->parent))->peer;
+ }
+ }
+
/* Don't try to install if we're not connected to Zebra or Zebra doesn't
* know of this instance.
*/
@@ -1363,7 +1451,27 @@ int bgp_redistribute_set(struct bgp *bgp, afi_t afi, int type, u_short instance)
}
#endif
+ /* vpn -> vrf (happens within bgp but we hijack redist bits */
+ if ((bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT
+ || bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
+ && type == ZEBRA_ROUTE_BGP_VPN) {
+
+ /* leak update all */
+ vpn_leak_prechange(BGP_VPN_POLICY_DIR_FROMVPN, afi,
+ bgp_get_default(), bgp);
+ }
+
vrf_bitmap_set(zclient->redist[afi][type], bgp->vrf_id);
+
+ /* vpn -> vrf (happens within bgp but we hijack redist bits */
+ if ((bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT
+ || bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
+ && type == ZEBRA_ROUTE_BGP_VPN) {
+
+ /* leak update all */
+ vpn_leak_postchange(BGP_VPN_POLICY_DIR_FROMVPN, afi,
+ bgp_get_default(), bgp);
+ }
}
/*
@@ -1484,11 +1592,6 @@ int bgp_redistribute_unreg(struct bgp *bgp, afi_t afi, int type,
vrf_bitmap_unset(zclient->redist[afi][type], bgp->vrf_id);
}
-#if ENABLE_BGP_VNC
- if (bgp->vrf_id == VRF_DEFAULT && type == ZEBRA_ROUTE_VNC_DIRECT) {
- vnc_export_bgp_disable(bgp, afi);
- }
-#endif
if (bgp_install_info_to_zebra(bgp)) {
/* Send distribute delete message to zebra. */
@@ -1512,6 +1615,26 @@ int bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type,
{
struct bgp_redist *red;
+/*
+ * vnc and vpn->vrf checks must be before red check because
+ * they operate within bgpd irrespective of zebra connection
+ * status. red lookup fails if there is no zebra connection.
+ */
+#if ENABLE_BGP_VNC
+ if (bgp->vrf_id == VRF_DEFAULT && type == ZEBRA_ROUTE_VNC_DIRECT) {
+ vnc_export_bgp_disable(bgp, afi);
+ }
+#endif
+ /* vpn -> vrf (happend within bgp but we hijack redist bits */
+ if ((bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT
+ || bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
+ && type == ZEBRA_ROUTE_BGP_VPN) {
+
+ /* leak withdraw all */
+ vpn_leak_prechange(BGP_VPN_POLICY_DIR_FROMVPN, afi,
+ bgp_get_default(), bgp);
+ }
+
red = bgp_redist_lookup(bgp, afi, type, instance);
if (!red)
return CMD_SUCCESS;