/* BGP try to connect to the peer. */ int bgp_connect (struct peer *peer) { unsigned int ifindex = 0; /* Make socket for the peer. */ peer->fd = sockunion_socket (&peer->su); if (peer->fd < 0) return -1; /* If we can get socket for the peer, adjest TTL and make connection. */ if (peer_sort (peer) == BGP_PEER_EBGP) { sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); if (peer->gtsm_hops) sockopt_minttl (peer->su.sa.sa_family, peer->fd, MAXTTL + 1 - peer->gtsm_hops); } sockopt_reuseaddr (peer->fd); sockopt_reuseport (peer->fd); #ifdef IPTOS_PREC_INTERNETCONTROL if (bgpd_privs.change (ZPRIVS_RAISE)) zlog_err ("%s: could not raise privs", __func__); if (sockunion_family (&peer->su) == AF_INET) setsockopt_ipv4_tos (peer->fd, IPTOS_PREC_INTERNETCONTROL); # ifdef HAVE_IPV6 else if (sockunion_family (&peer->su) == AF_INET6) setsockopt_ipv6_tclass (peer->fd, IPTOS_PREC_INTERNETCONTROL); # endif if (bgpd_privs.change (ZPRIVS_LOWER)) zlog_err ("%s: could not lower privs", __func__); #endif if (peer->password) bgp_md5_set_connect (peer->fd, &peer->su, peer->password); /* Bind socket. */ bgp_bind (peer); /* Update source bind. */ bgp_update_source (peer); #ifdef HAVE_IPV6 if (peer->ifname) ifindex = if_nametoindex (peer->ifname); #endif /* HAVE_IPV6 */ if (BGP_DEBUG (events, EVENTS)) plog_debug (peer->log, "%s [Event] Connect start to %s fd %d", peer->host, peer->host, peer->fd); /* Connect to the remote peer. */ return sockunion_connect (peer->fd, &peer->su, htons (peer->port), ifindex); }
int bgp_set_socket_ttl(struct peer *peer, int bgp_sock) { char buf[INET_ADDRSTRLEN]; int ret = 0; /* In case of peer is EBGP, we should set TTL for this connection. */ if (!peer->gtsm_hops && (peer_sort(peer) == BGP_PEER_EBGP)) { ret = sockopt_ttl(peer->su.sa.sa_family, bgp_sock, peer->ttl); if (ret) { flog_err( EC_LIB_SOCKET, "%s: Can't set TxTTL on peer (rtrid %s) socket, err = %d", __func__, inet_ntop(AF_INET, &peer->remote_id, buf, sizeof(buf)), errno); return ret; } } else if (peer->gtsm_hops) { /* On Linux, setting minttl without setting ttl seems to mess with the outgoing ttl. Therefore setting both. */ ret = sockopt_ttl(peer->su.sa.sa_family, bgp_sock, MAXTTL); if (ret) { flog_err( EC_LIB_SOCKET, "%s: Can't set TxTTL on peer (rtrid %s) socket, err = %d", __func__, inet_ntop(AF_INET, &peer->remote_id, buf, sizeof(buf)), errno); return ret; } ret = sockopt_minttl(peer->su.sa.sa_family, bgp_sock, MAXTTL + 1 - peer->gtsm_hops); if (ret) { flog_err( EC_LIB_SOCKET, "%s: Can't set MinTTL on peer (rtrid %s) socket, err = %d", __func__, inet_ntop(AF_INET, &peer->remote_id, buf, sizeof(buf)), errno); return ret; } } return ret; }
/* BGP try to connect to the peer. */ int bgp_connect (struct peer *peer) { unsigned int ifindex = 0; /* Make socket for the peer. */ peer->fd = sockunion_socket (&peer->su); if (peer->fd < 0) return -1; /* If we can get socket for the peer, adjest TTL and make connection. */ if (peer_sort (peer) == BGP_PEER_EBGP) sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); sockopt_reuseaddr (peer->fd); sockopt_reuseport (peer->fd); /* Bind socket. */ bgp_bind (peer); /* Update source bind. */ bgp_update_source (peer); #ifdef HAVE_IPV6 if (peer->ifname) ifindex = if_nametoindex (peer->ifname); #endif /* HAVE_IPV6 */ if (BGP_DEBUG (events, EVENTS)) plog_info (peer->log, "%s [Event] Connect start to %s fd %d", peer->host, peer->host, peer->fd); #ifdef HAVE_TCP_SIGNATURE if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSWORD)) bgp_tcpsig_set (peer->fd, peer); #endif /* HAVE_TCP_SIGNATURE */ /* Connect to the remote peer. */ return sockunion_connect (peer->fd, &peer->su, htons (peer->port), ifindex); }
/******************************************************************************* 函数名称 : bgp_info_mpath_update 功能描述 : mpath队列更新 输入参数 : 输出参数 : 返 回 值 : 无 -------------------------------------------------------------------------------- 最近一次修改记录 : 修改作者 : 修改目的 : 新添加函数 修改日期 : 2012-8-15 *******************************************************************************/ void bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best, struct bgp_info *old_best, struct list *mp_list, struct bgp_maxpaths_cfg *mpath_cfg) { u16 maxpaths, mpath_count, old_mpath_count; struct listnode *mp_node, *mp_next_node; struct bgp_info *cur_mpath, *new_mpath, *next_mpath, *prev_mpath; s32 mpath_changed; mpath_changed = 0; maxpaths = BGP_DEFAULT_MAXPATHS; mpath_count = 0; cur_mpath = NULL; old_mpath_count = 0; prev_mpath = new_best; mp_node = listhead (mp_list); if (new_best) { mpath_count++; if (new_best != old_best) { bgp_info_mpath_dequeue (new_best); } maxpaths = (peer_sort (new_best->peer) == BGP_PEER_IBGP) ? mpath_cfg->maxpaths_ibgp : mpath_cfg->maxpaths_ebgp; } if (old_best) { cur_mpath = bgp_info_mpath_first (old_best); old_mpath_count = bgp_info_mpath_count (old_best); bgp_info_mpath_count_set (old_best, 0); bgp_info_mpath_dequeue (old_best); } while (mp_node || cur_mpath) { if (!cur_mpath && (mpath_count >= maxpaths)) { break; } mp_next_node = mp_node ? listnextnode (mp_node) : NULL; next_mpath = cur_mpath ? bgp_info_mpath_next (cur_mpath) : NULL; if (mp_node && (listgetdata (mp_node) == cur_mpath)) { list_delete_node (mp_list, mp_node); bgp_info_mpath_dequeue (cur_mpath); if ((mpath_count < maxpaths) && bgp_info_nexthop_cmp (prev_mpath, cur_mpath)) { bgp_info_mpath_enqueue (prev_mpath, cur_mpath); prev_mpath = cur_mpath; mpath_count++; } else { mpath_changed = 1; } mp_node = mp_next_node; cur_mpath = next_mpath; continue; } if (cur_mpath && (!mp_node || (bgp_info_mpath_cmp (cur_mpath, listgetdata (mp_node)) < 0))) { bgp_info_mpath_dequeue (cur_mpath); mpath_changed = 1; cur_mpath = next_mpath; } else { new_mpath = listgetdata (mp_node); list_delete_node (mp_list, mp_node); if ((mpath_count < maxpaths) && (new_mpath != new_best) && bgp_info_nexthop_cmp (prev_mpath, new_mpath)) { if (new_mpath == next_mpath) { next_mpath = bgp_info_mpath_next (new_mpath); } bgp_info_mpath_dequeue (new_mpath); bgp_info_mpath_enqueue (prev_mpath, new_mpath); prev_mpath = new_mpath; mpath_changed = 1; mpath_count++; } mp_node = mp_next_node; } } if (new_best) { bgp_info_mpath_count_set (new_best, mpath_count-1); if (mpath_changed || (bgp_info_mpath_count (new_best) != old_mpath_count)) { SET_FLAG (new_best->flags, BGP_INFO_MULTIPATH_CHG); } } }
/* BGP Peer General TCP Socket Option Settings */ s_int32_t bpn_sock_set_opt (struct bgp_peer *peer, pal_sock_handle_t sck_fd, bool_t do_bind) { fib_id_t fib_id; s_int32_t ret; int flags = 1; fib_id = LIB_VRF_GET_FIB_ID (peer->bgp->owning_ivrf); ret = 0; /* set socket as ipv6 only */ if (peer->su.sa.sa_family == AF_INET6) { ret = setsockopt(sck_fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &flags, sizeof(flags)); if (ret < 0) { zlog_err (&BLG, "%s-%s [NETWORK] Set Sock Opt: " "failed to set option: Sock = %d", peer->host, BGP_PEER_DIR_STR (peer), sck_fd); } } /* Set Socket as Non-blocking */ pal_sock_set_nonblocking (sck_fd, PAL_TRUE); /* Set Socket to reuse Addr and Port */ ret = pal_sock_set_reuseaddr (sck_fd, PAL_TRUE); if (ret < 0) { zlog_err (&BLG, "%s-%s [NETWORK] Set Sock Opt: " "failed to reuse addr: Sock %d", peer->host, BGP_PEER_DIR_STR (peer), sck_fd); return ret; } pal_sock_set_reuseport (sck_fd, PAL_TRUE); /* Set TTL for EBGP peers */ if (peer_sort (peer) == BGP_PEER_EBGP) { if (peer->su.sa.sa_family == AF_INET) ret = (s_int32_t)pal_sock_set_ipv4_unicast_hops (sck_fd, peer->ttl); #ifdef HAVE_IPV6 else if (BGP_CAP_HAVE_IPV6 && peer->su.sa.sa_family == AF_INET6) ret = (s_int32_t)pal_sock_set_ipv6_hoplimit (sck_fd, peer->ttl); #endif /* HAVE_IPV6 */ if (ret < 0) zlog_warn (&BLG, "Can't set Hop Limit: %s(%d)", pal_strerror (errno), errno); } if (PAL_TRUE == do_bind) { /* Bind socket to FIB */ ret = pal_sock_set_bindtofib (sck_fd, fib_id); if (ret < 0) { zlog_err (&BLG, "%s-%s [NETWORK] Set Sock Opt: Failed to bind " "Sock %d to FIB with VRF-ID %d", peer->host, BGP_PEER_DIR_STR (peer), sck_fd, fib_id); return ret; } } /* Bind Socket to Interface */ #ifdef SO_BINDTODEVICE if (peer->ifname) { ret = pal_sock_set_bindtodevice (sck_fd, peer->ifname); if (ret < 0) { zlog_err (&BLG, "%s-%s [NETWORK] Set Sock Opt: Failed to " "bind Sock %d to IF %s", peer->host, BGP_PEER_DIR_STR (peer), sck_fd, peer->ifname); return ret; } } #endif /* SO_BINDTODEVICE */ /* Update-source address bind */ if (do_bind == PAL_TRUE) { ret = bpn_sock_bind_address (peer, sck_fd); if (ret < 0) { zlog_err (&BLG, "%s-%s [NETWORK] Set Sock Opt: Update-source " "failed on Sock %d", peer->host, BGP_PEER_DIR_STR (peer), sck_fd); return ret; } } /* Set TCP MD5 authentication */ #ifdef HAVE_TCP_MD5SIG if (CHECK_FLAG (peer->config, PEER_CONFIG_PASSWORD)) if (sockunion_family (&peer->su) == AF_INET) bgp_md5_set (sck_fd, &peer->su.sin.sin_addr, peer->password); #endif /* TCP_MD5SIG */ return ret; }
/* Accept bgp connection. */ static int bgp_accept (struct thread *thread) { int bgp_sock; int accept_sock; union sockunion su; struct bgp_listener *listener = THREAD_ARG(thread); struct peer *peer; struct peer *peer1; char buf[SU_ADDRSTRLEN]; /* Register accept thread. */ accept_sock = THREAD_FD (thread); if (accept_sock < 0) { zlog_err ("accept_sock is nevative value %d", accept_sock); return -1; } listener->thread = thread_add_read (master, bgp_accept, listener, accept_sock); /* Accept client connection. */ bgp_sock = sockunion_accept (accept_sock, &su); if (bgp_sock < 0) { zlog_err ("[Error] BGP socket accept failed (%s)", safe_strerror (errno)); return -1; } set_nonblocking (bgp_sock); if (BGP_DEBUG (events, EVENTS)) zlog_debug ("[Event] BGP connection from host %s", inet_sutop (&su, buf)); /* Check remote IP address */ peer1 = peer_lookup (NULL, &su); if (! peer1 || peer1->status == Idle) { if (BGP_DEBUG (events, EVENTS)) { if (! peer1) zlog_debug ("[Event] BGP connection IP address %s is not configured", inet_sutop (&su, buf)); else zlog_debug ("[Event] BGP connection IP address %s is Idle state", inet_sutop (&su, buf)); } close (bgp_sock); return -1; } /* In case of peer is EBGP, we should set TTL for this connection. */ if (peer_sort (peer1) == BGP_PEER_EBGP) { sockopt_ttl (peer1->su.sa.sa_family, bgp_sock, peer1->ttl); if (peer1->gtsm_hops) sockopt_minttl (peer1->su.sa.sa_family, bgp_sock, MAXTTL + 1 - peer1->gtsm_hops); } /* Make dummy peer until read Open packet. */ if (BGP_DEBUG (events, EVENTS)) zlog_debug ("[Event] Make dummy peer structure until read Open packet"); { char buf[SU_ADDRSTRLEN + 1]; peer = peer_create_accept (peer1->bgp); SET_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER); peer->su = su; peer->fd = bgp_sock; peer->status = Active; peer->local_id = peer1->local_id; peer->v_holdtime = peer1->v_holdtime; peer->v_keepalive = peer1->v_keepalive; /* Make peer's address string. */ sockunion2str (&su, buf, SU_ADDRSTRLEN); peer->host = STRDUP (MTYPE_BGP_PEER_HOST, buf); } BGP_EVENT_ADD (peer, TCP_connection_open); return 0; }
static void bgp_scan (afi_t afi, safi_t safi) { struct bgp_node *rn; struct bgp *bgp; struct bgp_info *bi; struct bgp_info *next; struct peer *peer; struct listnode *node, *nnode; int valid; int current; int changed; int metricchanged; /* Change cache. */ if (bgp_nexthop_cache_table[afi] == cache1_table[afi]) bgp_nexthop_cache_table[afi] = cache2_table[afi]; else bgp_nexthop_cache_table[afi] = cache1_table[afi]; /* Get default bgp. */ bgp = bgp_get_default (); if (bgp == NULL) return; /* Maximum prefix check */ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if (peer->status != Established) continue; if (peer->afc[afi][SAFI_UNICAST]) bgp_maximum_prefix_overflow (peer, afi, SAFI_UNICAST, 1); if (peer->afc[afi][SAFI_MULTICAST]) bgp_maximum_prefix_overflow (peer, afi, SAFI_MULTICAST, 1); if (peer->afc[afi][SAFI_MPLS_VPN]) bgp_maximum_prefix_overflow (peer, afi, SAFI_MPLS_VPN, 1); } for (rn = bgp_table_top (bgp->rib[afi][SAFI_UNICAST]); rn; rn = bgp_route_next (rn)) { for (bi = rn->info; bi; bi = next) { next = bi->next; if (bi->type == ZEBRA_ROUTE_BGP && bi->sub_type == BGP_ROUTE_NORMAL) { changed = 0; metricchanged = 0; if (peer_sort (bi->peer) == BGP_PEER_EBGP && bi->peer->ttl == 1) valid = bgp_nexthop_check_ebgp (afi, bi->attr); else valid = bgp_nexthop_lookup (afi, bi->peer, bi, &changed, &metricchanged); current = CHECK_FLAG (bi->flags, BGP_INFO_VALID) ? 1 : 0; if (changed) SET_FLAG (bi->flags, BGP_INFO_IGP_CHANGED); else UNSET_FLAG (bi->flags, BGP_INFO_IGP_CHANGED); if (valid != current) { if (CHECK_FLAG (bi->flags, BGP_INFO_VALID)) { bgp_aggregate_decrement (bgp, &rn->p, bi, afi, SAFI_UNICAST); bgp_info_unset_flag (rn, bi, BGP_INFO_VALID); } else { bgp_info_set_flag (rn, bi, BGP_INFO_VALID); bgp_aggregate_increment (bgp, &rn->p, bi, afi, SAFI_UNICAST); } } if (CHECK_FLAG (bgp->af_flags[afi][SAFI_UNICAST], BGP_CONFIG_DAMPENING) && bi->extra && bi->extra->damp_info ) if (bgp_damp_scan (bi, afi, SAFI_UNICAST)) bgp_aggregate_increment (bgp, &rn->p, bi, afi, SAFI_UNICAST); } } bgp_process (bgp, rn, afi, SAFI_UNICAST); } /* Flash old cache. */ if (bgp_nexthop_cache_table[afi] == cache1_table[afi]) bgp_nexthop_cache_reset (cache2_table[afi]); else bgp_nexthop_cache_reset (cache1_table[afi]); if (BGP_DEBUG (events, EVENTS)) { if (afi == AFI_IP) zlog_debug ("scanning IPv4 Unicast routing tables"); else if (afi == AFI_IP6) zlog_debug ("scanning IPv6 Unicast routing tables"); } }