enum nhrp_route_type nhrp_route_address(struct interface *in_ifp, union sockunion *addr, struct prefix *p, struct nhrp_peer **peer) { struct interface *ifp = in_ifp; struct nhrp_interface *nifp; struct nhrp_cache *c; union sockunion via[4]; uint32_t network_id = 0; afi_t afi = family2afi(sockunion_family(addr)); int i; if (ifp) { nifp = ifp->info; network_id = nifp->afi[afi].network_id; c = nhrp_cache_get(ifp, addr, 0); if (c && c->cur.type == NHRP_CACHE_LOCAL) { if (p) memset(p, 0, sizeof(*p)); return NHRP_ROUTE_LOCAL; } } for (i = 0; i < 4; i++) { if (!nhrp_route_get_nexthop(addr, p, &via[i], &ifp)) return NHRP_ROUTE_BLACKHOLE; if (ifp) { /* Departing from nbma network? */ nifp = ifp->info; if (network_id && network_id != nifp->afi[afi].network_id) return NHRP_ROUTE_OFF_NBMA; } if (sockunion_family(&via[i]) == AF_UNSPEC) break; /* Resolve via node, but return the prefix of first match */ addr = &via[i]; p = NULL; } if (ifp) { c = nhrp_cache_get(ifp, addr, 0); if (c && c->cur.type >= NHRP_CACHE_DYNAMIC) { if (p) memset(p, 0, sizeof(*p)); if (c->cur.type == NHRP_CACHE_LOCAL) return NHRP_ROUTE_LOCAL; if (peer) *peer = nhrp_peer_ref(c->cur.peer); return NHRP_ROUTE_NBMA_NEXTHOP; } } return NHRP_ROUTE_BLACKHOLE; }
int nhrp_interface_address_add(int cmd, struct zclient *client, zebra_size_t length, vrf_id_t vrf_id) { struct connected *ifc; char buf[PREFIX_STRLEN]; ifc = zebra_interface_address_read(cmd, client->ibuf, vrf_id); if (ifc == NULL) return 0; debugf(NHRP_DEBUG_IF, "if-addr-add: %s: %s", ifc->ifp->name, prefix2str(ifc->address, buf, sizeof buf)); nhrp_interface_update_address(ifc->ifp, family2afi(PREFIX_FAMILY(ifc->address)), 0); return 0; }
static struct route_node *nhrp_route_update_get(const struct prefix *p, int create) { struct route_node *rn; afi_t afi = family2afi(PREFIX_FAMILY(p)); if (!zebra_rib[afi]) return NULL; if (create) { rn = route_node_get(zebra_rib[afi], p); if (!rn->info) { rn->info = XCALLOC(MTYPE_NHRP_ROUTE, sizeof(struct route_info)); route_lock_node(rn); } return rn; } else { return route_node_lookup(zebra_rib[afi], p); } }
int nhrp_route_get_nexthop(const union sockunion *addr, struct prefix *p, union sockunion *via, struct interface **ifp) { struct route_node *rn; struct route_info *ri; struct prefix lookup; afi_t afi = family2afi(sockunion_family(addr)); char buf[PREFIX_STRLEN]; sockunion2hostprefix(addr, &lookup); rn = route_node_match(zebra_rib[afi], &lookup); if (!rn) return 0; ri = rn->info; if (ri->nhrp_ifp) { debugf(NHRP_DEBUG_ROUTE, "lookup %s: nhrp_if=%s", prefix2str(&lookup, buf, sizeof buf), ri->nhrp_ifp->name); if (via) sockunion_family(via) = AF_UNSPEC; if (ifp) *ifp = ri->nhrp_ifp; } else { debugf(NHRP_DEBUG_ROUTE, "lookup %s: zebra route dev %s", prefix2str(&lookup, buf, sizeof buf), ri->ifp ? ri->ifp->name : "(none)"); if (via) *via = ri->via; if (ifp) *ifp = ri->ifp; } if (p) *p = rn->p; route_unlock_node(rn); return 1; }
int zebra_evaluate_rnh_table (vrf_id_t vrfid, int family) { struct route_table *ptable; struct route_table *ntable; struct route_node *prn; struct route_node *nrn; struct rnh *rnh; struct zserv *client; struct listnode *node; struct rib *rib; ntable = lookup_rnh_table(vrfid, family); if (!ntable) { zlog_debug("evaluate_rnh_table: rnh table not found\n"); return -1; } ptable = zebra_vrf_table(family2afi(family), SAFI_UNICAST, vrfid); if (!ptable) { zlog_debug("evaluate_rnh_table: prefix table not found\n"); return -1; } for (nrn = route_top (ntable); nrn; nrn = route_next (nrn)) { if (!nrn->info) continue; rnh = nrn->info; prn = route_node_match(ptable, &nrn->p); if (!prn) rib = NULL; else { RNODE_FOREACH_RIB(prn, rib) { if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) continue; if (! CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) continue; if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) { if (rib->type == ZEBRA_ROUTE_CONNECT) break; if (rib->type == ZEBRA_ROUTE_NHRP) { struct nexthop *nexthop; for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) if (nexthop->type == NEXTHOP_TYPE_IFINDEX || nexthop->type == NEXTHOP_TYPE_IFNAME) break; if (nexthop) break; } } else break; } } if (compare_state(rib, rnh->state)) { if (IS_ZEBRA_DEBUG_NHT) { char bufn[INET6_ADDRSTRLEN]; char bufp[INET6_ADDRSTRLEN]; prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN); if (prn) prefix2str(&prn->p, bufp, INET6_ADDRSTRLEN); else strcpy(bufp, "null"); zlog_debug("rnh %s resolved through route %s - sending " "nexthop %s event to clients", bufn, bufp, rib ? "reachable" : "unreachable"); } copy_state(rnh, rib); for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) send_client(rnh, client, vrfid); } } return 1; }
/* This function is the first starting point of all BGP connection. It try to connect to remote peer with non-blocking IO. */ int bgp_start (struct peer *peer) { int status; int connected = 0; if (BGP_PEER_START_SUPPRESSED (peer)) { if (BGP_DEBUG (fsm, FSM)) plog_err (peer->log, "%s [FSM] Trying to start suppressed peer" " - this is never supposed to happen!", peer->host); return -1; } /* Scrub some information that might be left over from a previous, * session */ /* Connection information. */ if (peer->su_local) { sockunion_free (peer->su_local); peer->su_local = NULL; } if (peer->su_remote) { sockunion_free (peer->su_remote); peer->su_remote = NULL; } /* Clear remote router-id. */ peer->remote_id.s_addr = 0; /* Clear peer capability flag. */ peer->cap = 0; /* If the peer is passive mode, force to move to Active mode. */ if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSIVE)) { BGP_EVENT_ADD (peer, TCP_connection_open_failed); return 0; } /* Register to be notified on peer up */ if ((peer->ttl == 1) || (peer->gtsm_hops == 1)) connected = 1; bgp_find_or_add_nexthop(family2afi(peer->su.sa.sa_family), NULL, peer, connected); status = bgp_connect (peer); switch (status) { case connect_error: if (BGP_DEBUG (fsm, FSM)) plog_debug (peer->log, "%s [FSM] Connect error", peer->host); BGP_EVENT_ADD (peer, TCP_connection_open_failed); break; case connect_success: if (BGP_DEBUG (fsm, FSM)) plog_debug (peer->log, "%s [FSM] Connect immediately success", peer->host); BGP_EVENT_ADD (peer, TCP_connection_open); break; case connect_in_progress: /* To check nonblocking connect, we wait until socket is readable or writable. */ if (BGP_DEBUG (fsm, FSM)) plog_debug (peer->log, "%s [FSM] Non blocking connect waiting result", peer->host); if (peer->fd < 0) { zlog_err ("bgp_start peer's fd is negative value %d", peer->fd); return -1; } BGP_READ_ON (peer->t_read, bgp_read, peer->fd); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); break; } return 0; }