s32 bgp_fec_announce_6pe(struct zclient *zc, struct prefix *p, struct bgp_info *info, struct bgp *bgp) { u32 flags = 0; struct stream * s = zc->obuf ; struct peer * peer = info->peer ; u32 gateway ,label ; struct rtm_fec_info_key key; struct in6_addr *nexthop = NULL; if( !info || !info->attr || !info->attr->extra ) return -1 ; if (info->attr->extra->mp_nexthop_len == 16) { nexthop = &info->attr->extra->mp_nexthop_global; } /* If both global and link-local address present. */ else 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(NULL == nexthop || !IN6_IS_ADDR_V4MAPPED(nexthop)) { return -1; } memcpy (&gateway , ((s8 *)nexthop) + 12, 4); label = decode_label ( bgp_info_extra_get(info)->tag) ; SET_FLAG(flags, ZAPI_FEC_GATEWAY); stream_reset(s); zclient_create_header(s,ZEBRA_MPLS_FEC6_INFO_ADD); stream_put_prefix(s,p); stream_putl(s, flags); stream_putl(s, ZEBRA_FEC_TYPE_6PE); if( peer ) stream_putl(s,peer->nexthop.v4.s_addr); else stream_putl(s,0); // lsr_id = 0 stream_putl(s,label); stream_putl(s,gateway); stream_putw_at (s, 0, stream_get_endp (s)); key.peer_addr = gateway; return rtm_fec_send(ZEBRA_MPLS_FEC6_INFO_ADD, zc, p, s, &key) ; }
s32 bgp_fec_announce_6vpe(bgp_litevrf_config_t *litevrf, struct prefix *p, struct bgp_info *info) { u32 flags = 0; struct stream * s = zclient->obuf ; struct peer * peer = info->peer ; u32 gateway ,label ; struct rtm_fec_info_key key; struct in6_addr *nexthop = NULL; if( !info || !info->attr || !info->attr->extra ) return -1 ; nexthop = &info->attr->extra->mp_nexthop_global; if(NULL == nexthop || !IN6_IS_ADDR_V4MAPPED(nexthop)) { return -1; } memcpy (&gateway , ((s8 *)nexthop) + 12, 4); label = decode_label ( bgp_info_extra_get(info)->tag) ; SET_FLAG(flags, ZAPI_FEC_GATEWAY|ZAPI_FEC_LITEVRF); stream_reset(s); zclient_create_header(s,ZEBRA_MPLS_FEC6_INFO_ADD); stream_put_prefix(s,p); stream_putl(s, flags); stream_putl(s,litevrf->id); stream_putl(s, ZEBRA_FEC_TYPE_6VPE); if( peer ) stream_putl(s,peer->nexthop.v4.s_addr); else stream_putl(s,0); // lsr_id = 0 stream_putl(s,label); stream_putl(s,gateway); stream_putw_at (s, 0, stream_get_endp (s)); key.peer_addr = gateway; return rtm_fec_send(ZEBRA_MPLS_FEC6_INFO_ADD, zclient, p, s, &key) ; }
/* A route becomes unreachable (RFC2439 Section 4.8.2). */ int bgp_damp_withdraw (struct bgp_info *binfo, struct bgp_node *rn, afi_t afi, safi_t safi, int attr_change) { time_t t_now; struct bgp_damp_info *bdi = NULL; double last_penalty = 0; t_now = bgp_clock (); /* Processing Unreachable Messages. */ if (binfo->extra) bdi = binfo->extra->damp_info; if (bdi == NULL) { /* If there is no previous stability history. */ /* RFC2439 said: 1. allocate a damping structure. 2. set figure-of-merit = 1. 3. withdraw the route. */ bdi = XCALLOC (MTYPE_BGP_DAMP_INFO, sizeof (struct bgp_damp_info)); bdi->binfo = binfo; bdi->rn = rn; bdi->penalty = (attr_change ? DEFAULT_PENALTY / 2 : DEFAULT_PENALTY); bdi->flap = 1; bdi->start_time = t_now; bdi->suppress_time = 0; bdi->index = -1; bdi->afi = afi; bdi->safi = safi; (bgp_info_extra_get (binfo))->damp_info = bdi; BGP_DAMP_LIST_ADD (damp, bdi); } else { last_penalty = bdi->penalty; /* 1. Set t-diff = t-now - t-updated. */ bdi->penalty = (bgp_damp_decay (t_now - bdi->t_updated, bdi->penalty) + (attr_change ? DEFAULT_PENALTY / 2 : DEFAULT_PENALTY)); if (bdi->penalty > damp->ceiling) bdi->penalty = damp->ceiling; bdi->flap++; } assert ((rn == bdi->rn) && (binfo == bdi->binfo)); bdi->lastrecord = BGP_RECORD_WITHDRAW; bdi->t_updated = t_now; /* Make this route as historical status. */ bgp_info_set_flag (rn, binfo, BGP_INFO_HISTORY); /* Remove the route from a reuse list if it is on one. */ if (CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED)) { /* If decay rate isn't equal to 0, reinsert brn. */ if (bdi->penalty != last_penalty) { bgp_reuse_list_delete (bdi); bgp_reuse_list_add (bdi); } return BGP_DAMP_SUPPRESSED; } /* If not suppressed before, do annonunce this withdraw and insert into reuse_list. */ if (bdi->penalty >= damp->suppress_value) { bgp_info_set_flag (rn, binfo, BGP_INFO_DAMPED); bdi->suppress_time = t_now; BGP_DAMP_LIST_DEL (damp, bdi); bgp_reuse_list_add (bdi); } return BGP_DAMP_USED; }
/* Check specified next-hop is reachable or not. */ int bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri, int *changed, int *metricchanged) { struct bgp_node *rn; struct prefix p; struct bgp_nexthop_cache *bnc; struct in_addr addr; /* If lookup is not enabled, return valid. */ if (zlookup->sock < 0) { if (ri->extra) ri->extra->igpmetric = 0; return 1; } #ifdef HAVE_IPV6 if (afi == AFI_IP6) return bgp_nexthop_lookup_ipv6 (peer, ri, changed, metricchanged); #endif /* HAVE_IPV6 */ addr = ri->attr->nexthop; memset (&p, 0, sizeof (struct prefix)); p.family = AF_INET; p.prefixlen = IPV4_MAX_BITLEN; p.u.prefix4 = addr; /* IBGP or ebgp-multihop */ rn = bgp_node_get (bgp_nexthop_cache_table[AFI_IP], &p); if (rn->info) { bnc = rn->info; bgp_unlock_node (rn); } else { if (NULL == (bnc = zlookup_query (addr))) bnc = bnc_new (); else { if (changed) { struct bgp_table *old; struct bgp_node *oldrn; if (bgp_nexthop_cache_table[AFI_IP] == cache1_table[AFI_IP]) old = cache2_table[AFI_IP]; else old = cache1_table[AFI_IP]; oldrn = bgp_node_lookup (old, &p); if (oldrn) { struct bgp_nexthop_cache *oldbnc = oldrn->info; bnc->changed = bgp_nexthop_cache_different (bnc, oldbnc); if (bnc->metric != oldbnc->metric) bnc->metricchanged = 1; bgp_unlock_node (oldrn); } } } rn->info = bnc; } if (changed) *changed = bnc->changed; if (metricchanged) *metricchanged = bnc->metricchanged; if (bnc->valid && bnc->metric) (bgp_info_extra_get(ri))->igpmetric = bnc->metric; else if (ri->extra) ri->extra->igpmetric = 0; return bnc->valid; }
/* Check specified next-hop is reachable or not. */ static int bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed, int *metricchanged) { struct bgp_node *rn; struct prefix p; struct bgp_nexthop_cache *bnc; struct attr *attr; /* If lookup is not enabled, return valid. */ if (zlookup->sock < 0) { if (ri->extra) ri->extra->igpmetric = 0; return 1; } /* Only check IPv6 global address only nexthop. */ attr = ri->attr; if (attr->extra->mp_nexthop_len != 16 || IN6_IS_ADDR_LINKLOCAL (&attr->extra->mp_nexthop_global)) return 1; memset (&p, 0, sizeof (struct prefix)); p.family = AF_INET6; p.prefixlen = IPV6_MAX_BITLEN; p.u.prefix6 = attr->extra->mp_nexthop_global; /* IBGP or ebgp-multihop */ rn = bgp_node_get (bgp_nexthop_cache_table[AFI_IP6], &p); if (rn->info) { bnc = rn->info; bgp_unlock_node (rn); } else { if (NULL == (bnc = zlookup_query_ipv6 (&attr->extra->mp_nexthop_global))) bnc = bnc_new (); else { if (changed) { struct bgp_table *old; struct bgp_node *oldrn; if (bgp_nexthop_cache_table[AFI_IP6] == cache1_table[AFI_IP6]) old = cache2_table[AFI_IP6]; else old = cache1_table[AFI_IP6]; oldrn = bgp_node_lookup (old, &p); if (oldrn) { struct bgp_nexthop_cache *oldbnc = oldrn->info; bnc->changed = bgp_nexthop_cache_different (bnc, oldbnc); if (bnc->metric != oldbnc->metric) bnc->metricchanged = 1; bgp_unlock_node (oldrn); } } } rn->info = bnc; } if (changed) *changed = bnc->changed; if (metricchanged) *metricchanged = bnc->metricchanged; if (bnc->valid && bnc->metric) (bgp_info_extra_get (ri))->igpmetric = bnc->metric; else if (ri->extra) ri->extra->igpmetric = 0; return bnc->valid; }