void nhrp_interface_update(struct interface *ifp) { struct nhrp_interface *nifp = ifp->info; struct nhrp_afi_data *if_ad; afi_t afi; int enabled = 0; notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_CHANGED); for (afi = 0; afi < AFI_MAX; afi++) { if_ad = &nifp->afi[afi]; if (sockunion_family(&nifp->nbma) == AF_UNSPEC || ifp->ifindex == IFINDEX_INTERNAL || !if_is_up(ifp) || !if_ad->network_id) { if (if_ad->configured) { if_ad->configured = 0; nhrp_interface_update_address(ifp, afi, 1); } continue; } if (!if_ad->configured) { os_configure_dmvpn(ifp->ifindex, ifp->name, afi2family(afi)); if_ad->configured = 1; nhrp_interface_update_address(ifp, afi, 1); } enabled = 1; } if (enabled != nifp->enabled) { nifp->enabled = enabled; notifier_call(&nifp->notifier_list, enabled ? NOTIFY_INTERFACE_UP : NOTIFY_INTERFACE_DOWN); } }
static void nhrp_interface_update_address(struct interface *ifp, afi_t afi, int force) { const int family = afi2family(afi); struct nhrp_interface *nifp = ifp->info; struct nhrp_afi_data *if_ad = &nifp->afi[afi]; struct nhrp_cache *nc; struct connected *c, *best; struct listnode *cnode; union sockunion addr; char buf[PREFIX_STRLEN]; /* Select new best match preferring primary address */ best = NULL; for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) { if (PREFIX_FAMILY(c->address) != family) continue; if (best == NULL) { best = c; continue; } if ((best->flags & ZEBRA_IFA_SECONDARY) && !(c->flags & ZEBRA_IFA_SECONDARY)) { best = c; continue; } if (!(best->flags & ZEBRA_IFA_SECONDARY) && (c->flags & ZEBRA_IFA_SECONDARY)) continue; if (best->address->prefixlen > c->address->prefixlen) { best = c; continue; } if (best->address->prefixlen < c->address->prefixlen) continue; } /* On NHRP interfaces a host prefix is required */ if (best && if_ad->configured && best->address->prefixlen != 8 * prefix_blen(best->address)) { zlog_notice("%s: %s is not a host prefix", ifp->name, prefix2str(best->address, buf, sizeof buf)); best = NULL; } /* Update address if it changed */ if (best) prefix2sockunion(best->address, &addr); else memset(&addr, 0, sizeof(addr)); if (!force && sockunion_same(&if_ad->addr, &addr)) return; if (sockunion_family(&if_ad->addr) != AF_UNSPEC) { nc = nhrp_cache_get(ifp, &if_ad->addr, 0); if (nc) nhrp_cache_update_binding(nc, NHRP_CACHE_LOCAL, -1, NULL, 0, NULL); } debugf(NHRP_DEBUG_KERNEL, "%s: IPv%d address changed to %s", ifp->name, afi == AFI_IP ? 4 : 6, best ? prefix2str(best->address, buf, sizeof buf) : "(none)"); if_ad->addr = addr; if (if_ad->configured && sockunion_family(&if_ad->addr) != AF_UNSPEC) { nc = nhrp_cache_get(ifp, &addr, 1); if (nc) nhrp_cache_update_binding(nc, NHRP_CACHE_LOCAL, 0, NULL, 0, NULL); } notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_ADDRESS_CHANGED); }
int bgp_nlri_parse_encap( struct peer *peer, struct attr *attr, /* Need even for withdraw */ struct bgp_nlri *packet) { u_char *pnt; u_char *lim; afi_t afi = packet->afi; struct prefix p; int psize = 0; int prefixlen; struct rd_as rd_as; struct rd_ip rd_ip; struct prefix_rd prd; struct ecommunity *pEcom = NULL; u_int16_t rdtype = 0xffff; char buf[BUFSIZ]; /* Check peer status. */ if (peer->status != Established) return 0; /* Make prefix_rd */ if (attr && attr->extra && attr->extra->ecommunity) pEcom = attr->extra->ecommunity; ecom2prd(pEcom, &prd); memset(&rd_as, 0, sizeof(rd_as)); memset(&rd_ip, 0, sizeof(rd_ip)); if (pEcom) { rdtype = (prd.val[0] << 8) | prd.val[1]; /* Decode RD value. */ if (rdtype == RD_TYPE_AS) decode_rd_as (prd.val + 2, &rd_as); else if (rdtype == RD_TYPE_IP) decode_rd_ip (prd.val + 2, &rd_ip); else if (rdtype == RD_TYPE_AS4) decode_rd_as4 (prd.val + 2, &rd_as); else { zlog_err ("Invalid RD type %d", rdtype); } } /* * NB: this code was based on the MPLS VPN code, which supported RDs. * For the moment we are retaining the underlying RIB structure that * keeps a per-RD radix tree, but since the RDs are not carried over * the wire, we set the RD internally to 0. */ prd.family = AF_UNSPEC; prd.prefixlen = 64; memset(prd.val, 0, sizeof(prd.val)); pnt = packet->nlri; lim = pnt + packet->length; for (; pnt < lim; pnt += psize) { /* Clear prefix structure. */ memset (&p, 0, sizeof (struct prefix)); /* Fetch prefix length. */ prefixlen = *pnt++; p.family = afi2family(afi); if (p.family == 0) { /* bad afi, shouldn't happen */ zlog_warn("%s: bad afi %d, dropping incoming route", __func__, afi); continue; } psize = PSIZE (prefixlen); p.prefixlen = prefixlen; memcpy (&p.u.prefix, pnt, psize); if (pnt + psize > lim) return -1; if (rdtype == RD_TYPE_AS) zlog_info ("rd-as %u:%u prefix %s/%d", rd_as.as, rd_as.val, inet_ntop (p.family, &p.u.prefix, buf, BUFSIZ), p.prefixlen); else if (rdtype == RD_TYPE_IP) zlog_info ("rd-ip %s:%u prefix %s/%d", inet_ntoa (rd_ip.ip), rd_ip.val, inet_ntop (p.family, &p.u.prefix, buf, BUFSIZ), p.prefixlen); else if (rdtype == RD_TYPE_AS4) zlog_info ("rd-as4 %u:%u prefix %s/%d", rd_as.as, rd_as.val, inet_ntop (p.family, &p.u.prefix, buf, BUFSIZ), p.prefixlen); else zlog_info ("rd unknown, default to 0:0 prefix %s/%d", inet_ntop (p.family, &p.u.prefix, buf, BUFSIZ), p.prefixlen); if (attr) { bgp_update (peer, &p, attr, afi, SAFI_ENCAP, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0); } else { bgp_withdraw (peer, &p, attr, afi, SAFI_ENCAP, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL); } } /* Packet length consistency check. */ if (pnt != lim) return -1; return 0; }