s_int32_t bpn_sock_listen_uninit (struct bgp *bgp) { struct bgp_listen_sock_lnode *tmp_lnode_nxt; struct bgp_listen_sock_lnode *tmp_lnode; s_int32_t ret; ret = 0; if (! bgp) { ret = -1; goto EXIT; } /* Release all Listen Socket Threads */ for (tmp_lnode = bgp->listen_sock_lnode; tmp_lnode; tmp_lnode = tmp_lnode_nxt) { tmp_lnode_nxt = tmp_lnode->next; SSOCK_FD_CLOSE (&BLG, tmp_lnode->listen_sock); BGP_READ_OFF (&BLG, tmp_lnode->t_accept); XFREE (MTYPE_TMP, tmp_lnode); } bgp->listen_sock_lnode = NULL; EXIT: return ret; }
/* Add thread to Listen Thread List */ tmp_lnode = XCALLOC (MTYPE_TMP, sizeof (struct bgp_listen_sock_lnode)); if (! tmp_lnode) { zlog_err (&BLG, "[NETWORK] Server Sock:" " Cannot allocate memory (%d) @ %s:%d", sizeof (struct bgp_peer_inconn_req), __FILE__, __LINE__); SSOCK_FD_CLOSE (&BLG, bgp_sock); BGP_READ_OFF (&BLG, t_accept); continue; } tmp_lnode->listen_sock = bgp_sock; tmp_lnode->t_accept = t_accept; if (bgp->listen_sock_lnode) tmp_lnode->next = bgp->listen_sock_lnode; bgp->listen_sock_lnode = tmp_lnode; } pal_sock_freeaddrinfo (ainfo_head); return ret; } #else /* HAVE_IPV6 && !NRL */ s_int32_t bpn_sock_listen (struct bgp *bgp, u_int16_t port) { struct bgp_listen_sock_lnode *tmp_lnode; struct thread *t_accept; union sockunion su; s_int32_t bgp_sock; fib_id_t fib_id; s_int32_t ret; pal_mem_set (&su, 0, sizeof (union sockunion)); t_accept = NULL; ret = 0; if (! bgp) { zlog_err (&BLG, "[NETWORK] Server Sock: Invalid 'bgp' instance"); ret = -1; goto EXIT; } fib_id = LIB_VRF_GET_FIB_ID (bgp->owning_ivrf); /* Specify address family. */ su.sa.sa_family = AF_INET; bgp_sock = pal_sock (&BLG, su.sa.sa_family, SOCK_STREAM, 0); if (bgp_sock < 0) { zlog_err (&BLG, "[NETWORK] Server Sock: socket() Failed, FIB-ID %d, " "Err:%d-%s", fib_id, errno, pal_strerror (errno)); ret = -1; goto EXIT; } pal_sock_set_reuseaddr (bgp_sock, PAL_TRUE); pal_sock_set_reuseport (bgp_sock, PAL_TRUE); /* Bind socket to FIB. */ ret = pal_sock_set_bindtofib (bgp_sock, fib_id); if (ret < 0) { zlog_err (&BLG, "[NETWORK] Server Sock: bindtofib() Failed, Sock %d" ", FIB-ID %d, Err:%d-%s", bgp_sock, fib_id, errno, pal_strerror (errno)); SSOCK_FD_CLOSE (&BLG, bgp_sock); /* Ignore platform error */ ret = 0; goto EXIT; } ret = sockunion_bind (&BLG, bgp_sock, &su, port, NULL); if (ret < 0) { zlog_err (&BLG, "[NETWORK] Server Sock: bind() Failed, Err: %d-%s", errno, pal_strerror (errno)); SSOCK_FD_CLOSE (&BLG, bgp_sock); /* Ignore platform error */ ret = 0; goto EXIT; } #ifdef HAVE_TCP_MD5SIG bgp_md5_set_server (bgp, bgp_sock); #endif /* TCP_MD5SIG */ ret = pal_sock_listen (bgp_sock, BGP_SOCK_LISTEN_BACKLOG); if (ret < 0) { zlog_err (&BLG, "[NETWORK] Server Sock: listen() Failed, Sock %d, " "FIB-ID %d, Err:%d-%s", bgp_sock, fib_id, errno, pal_strerror (errno)); SSOCK_FD_CLOSE (&BLG, bgp_sock); /* Ignore platform error */ ret = 0; goto EXIT; } /* Start a fresh Accept Thread */ BGP_READ_ON (&BLG, t_accept, bgp, bpn_sock_accept, bgp_sock); /* Add thread to Listen Thread List */ tmp_lnode = XCALLOC (MTYPE_TMP, sizeof (struct bgp_listen_sock_lnode)); if (! tmp_lnode) { zlog_err (&BLG, "[NETWORK] Server Sock:" " Cannot allocate memory (%d) @ %s:%d", sizeof (struct bgp_peer_inconn_req), __FILE__, __LINE__); SSOCK_FD_CLOSE (&BLG, bgp_sock); BGP_READ_OFF (&BLG, t_accept); ret = -1; goto EXIT; } tmp_lnode->listen_sock = bgp_sock; tmp_lnode->t_accept = t_accept; if (bgp->listen_sock_lnode) tmp_lnode->next = bgp->listen_sock_lnode; bgp->listen_sock_lnode = tmp_lnode; EXIT: return ret; }
s_int32_t bpn_sock_listen (struct bgp *bgp, u_int16_t port) { struct bgp_listen_sock_lnode *tmp_lnode; u_int8_t port_str [SU_ADDRSTRLEN]; struct pal_addrinfo *ainfo_save[2], *ainfo_head; struct pal_addrinfo *ainfo; struct pal_sockaddr_in4 ain4; struct pal_sockaddr_in6 ain6; struct pal_addrinfo req; struct thread *t_accept; s_int32_t bgp_sock; u_int8_t addr_set; fib_id_t fib_id; s_int32_t ret; int i, flags = 1; pal_mem_set (&req, 0, sizeof (struct pal_addrinfo)); t_accept = NULL; ainfo_save[0] = NULL; ainfo_save[1] = NULL; ret = 0; addr_set = 0; if (! bgp) { zlog_err (&BLG, "[NETWORK] Server Sock: Invalid 'bgp' instance"); return -1; } fib_id = LIB_VRF_GET_FIB_ID (bgp->owning_ivrf); req.ai_flags = AI_PASSIVE; req.ai_family = AF_UNSPEC; req.ai_socktype = SOCK_STREAM; pal_snprintf (port_str, SU_ADDRSTRLEN, "%d", port); port_str[sizeof (port_str) - 1] = '\0'; ret = pal_sock_getaddrinfo (NULL, port_str, &req, &ainfo); if (ret != 0) { zlog_err (&BLG, "[NETWORK] Server Sock: getaddrinfo() failed: %d-%s", errno, pal_strerror (errno)); return ret; } ainfo_head = ainfo; /* IPv4 can connect to IPv6 socket, not other way around. */ while (ainfo) { if (ainfo->ai_family == AF_INET) ainfo_save[1] = ainfo; else if (ainfo->ai_family == AF_INET6) ainfo_save[0] = ainfo; ainfo = ainfo->ai_next; } for (i = 0; i < 2; i++) { ainfo = ainfo_save[i]; if (! ainfo) continue; if (ainfo->ai_family != AF_INET && ainfo->ai_family != AF_INET6) continue; bgp_sock = pal_sock (&BLG, ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol); if (bgp_sock < 0) { zlog_err (&BLG, "[NETWORK] Server Sock: socket() Failed for AF" "=%d, FIB-ID %d, Err:%d-%s", ainfo->ai_family, fib_id, errno, pal_strerror (errno)); continue; } /* set socket as ipv6 only */ if (ainfo->ai_family == AF_INET6) { ret = setsockopt(bgp_sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &flags, sizeof(flags)); if (ret < 0) { zlog_err (&BLG, "[NETWORK] Server Sock: socket() failed to" "set option for AF=%d, Err:%d-%s", ainfo->ai_family, errno, pal_strerror (errno)); } } ret = pal_sock_set_reuseaddr (bgp_sock, PAL_TRUE); pal_sock_set_reuseport (bgp_sock, PAL_TRUE); /* Bind socket to FIB. */ ret = pal_sock_set_bindtofib (bgp_sock, fib_id); if (ret < 0) { zlog_err (&BLG, "[NETWORK] Server Sock: bindtofib() Failed for" " AF=%d, Sock %d, FIB-ID %d, Err:%d-%s", ainfo->ai_family, bgp_sock, fib_id, errno, pal_strerror (errno)); SSOCK_FD_CLOSE (&BLG, bgp_sock); ret = 0; continue; } /* If the ai_addr is NULL, bind it to the port. */ if (ainfo->ai_addr == NULL) { if (ainfo->ai_family == AF_INET) { pal_mem_set (&ain4, 0, sizeof (ain4)); ain4.sin_family = AF_INET; ain4.sin_port = pal_hton16 (port); ainfo->ai_addr = (struct pal_sockaddr *) &ain4; ainfo->ai_addrlen = sizeof (struct pal_sockaddr_in4); addr_set = 1; } else if (ainfo->ai_family == AF_INET6) { pal_mem_set (&ain6, 0, sizeof (ain6)); ain6.sin6_family = AF_INET6; ain6.sin6_port = pal_hton16 (port); ainfo->ai_addr = (struct pal_sockaddr *) &ain6; ainfo->ai_addrlen = sizeof (struct pal_sockaddr_in6); addr_set = 1; } else { zlog_err (&BLG, "[NETWORK] Server Sock: getaddrinfo() returned" "invalid address" " AF=%d, Sock %d", ainfo->ai_family, bgp_sock); SSOCK_FD_CLOSE (&BLG, bgp_sock); ret = 0; continue; } } ret = pal_sock_bind (bgp_sock, ainfo->ai_addr, ainfo->ai_addrlen); if (addr_set) ainfo->ai_addr = NULL; if (ret < 0) { zlog_err (&BLG, "[NETWORK] Server Sock: bind() Failed for AF=" "%d, Err: %d-%s, port[%d]", ainfo->ai_family, errno, pal_strerror (errno), port); SSOCK_FD_CLOSE (&BLG, bgp_sock); ret = 0; continue; } #ifdef HAVE_TCP_MD5SIG bgp_md5_set_server (bgp, bgp_sock); #endif /* TCP_MD5SIG */ ret = pal_sock_listen (bgp_sock, BGP_SOCK_LISTEN_BACKLOG); if (ret < 0) { zlog_err (&BLG, "[NETWORK] Server Sock: listen() Failed for " "AF=%d, Sock %d, FIB-ID %d, Err:%d-%s", ainfo->ai_family, bgp_sock, fib_id, errno, pal_strerror (errno)); SSOCK_FD_CLOSE (&BLG, bgp_sock); ret = 0; continue; } /* Start a fresh Accept Thread */ t_accept = NULL; BGP_READ_ON (&BLG, t_accept, bgp, bpn_sock_accept, bgp_sock); /* Add thread to Listen Thread List */ tmp_lnode = XCALLOC (MTYPE_TMP, sizeof (struct bgp_listen_sock_lnode)); if (! tmp_lnode) { zlog_err (&BLG, "[NETWORK] Server Sock:" " Cannot allocate memory (%d) @ %s:%d", sizeof (struct bgp_peer_inconn_req), __FILE__, __LINE__); SSOCK_FD_CLOSE (&BLG, bgp_sock); BGP_READ_OFF (&BLG, t_accept); continue; } tmp_lnode->listen_sock = bgp_sock; tmp_lnode->t_accept = t_accept; if (bgp->listen_sock_lnode) tmp_lnode->next = bgp->listen_sock_lnode; bgp->listen_sock_lnode = tmp_lnode; } pal_sock_freeaddrinfo (ainfo_head); return ret; }
/* May be called multiple times for the same peer */ int bgp_stop (struct peer *peer) { afi_t afi; safi_t safi; char orf_name[BUFSIZ]; /* Can't do this in Clearing; events are used for state transitions */ if (peer->status != Clearing) { /* Delete all existing events of the peer */ BGP_EVENT_FLUSH (peer); } /* Increment Dropped count. */ if (peer->status == Established) { peer->dropped++; /* bgp log-neighbor-changes of neighbor Down */ if (bgp_flag_check (peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES)) zlog_info ("%%ADJCHANGE: neighbor %s Down %s", peer->host, peer_down_str [(int) peer->last_reset]); /* graceful restart */ if (peer->t_gr_stale) { BGP_TIMER_OFF (peer->t_gr_stale); if (BGP_DEBUG (events, EVENTS)) zlog_debug ("%s graceful restart stalepath timer stopped", peer->host); } if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT)) { if (BGP_DEBUG (events, EVENTS)) { zlog_debug ("%s graceful restart timer started for %d sec", peer->host, peer->v_gr_restart); zlog_debug ("%s graceful restart stalepath timer started for %d sec", peer->host, peer->bgp->stalepath_time); } BGP_TIMER_ON (peer->t_gr_restart, bgp_graceful_restart_timer_expire, peer->v_gr_restart); BGP_TIMER_ON (peer->t_gr_stale, bgp_graceful_stale_timer_expire, peer->bgp->stalepath_time); } else { UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE); for (afi = AFI_IP ; afi < AFI_MAX ; afi++) for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++) peer->nsf[afi][safi] = 0; } /* set last reset time */ peer->resettime = peer->uptime = bgp_clock (); #ifdef HAVE_SNMP bgpTrapBackwardTransition (peer); #endif /* HAVE_SNMP */ /* Reset peer synctime */ peer->synctime = 0; } /* Stop read and write threads when exists. */ BGP_READ_OFF (peer->t_read); BGP_WRITE_OFF (peer->t_write); /* Stop all timers. */ BGP_TIMER_OFF (peer->t_start); BGP_TIMER_OFF (peer->t_connect); BGP_TIMER_OFF (peer->t_holdtime); BGP_TIMER_OFF (peer->t_keepalive); BGP_TIMER_OFF (peer->t_asorig); BGP_TIMER_OFF (peer->t_routeadv); /* Stream reset. */ peer->packet_size = 0; /* Clear input and output buffer. */ if (peer->ibuf) stream_reset (peer->ibuf); if (peer->work) stream_reset (peer->work); if (peer->obuf) stream_fifo_clean (peer->obuf); /* Close of file descriptor. */ if (peer->fd >= 0) { close (peer->fd); peer->fd = -1; } for (afi = AFI_IP ; afi < AFI_MAX ; afi++) for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) { /* Reset all negotiated variables */ peer->afc_nego[afi][safi] = 0; peer->afc_adv[afi][safi] = 0; peer->afc_recv[afi][safi] = 0; /* peer address family capability flags*/ peer->af_cap[afi][safi] = 0; /* peer address family status flags*/ peer->af_sflags[afi][safi] = 0; /* Received ORF prefix-filter */ peer->orf_plist[afi][safi] = NULL; /* ORF received prefix-filter pnt */ sprintf (orf_name, "%s.%d.%d", peer->host, afi, safi); prefix_bgp_orf_remove_all (orf_name); } /* Reset keepalive and holdtime */ if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)) { peer->v_keepalive = peer->keepalive; peer->v_holdtime = peer->holdtime; } else { peer->v_keepalive = peer->bgp->default_keepalive; peer->v_holdtime = peer->bgp->default_holdtime; } peer->update_time = 0; /* Until we are sure that there is no problem about prefix count this should be commented out.*/ #if 0 /* Reset prefix count */ peer->pcount[AFI_IP][SAFI_UNICAST] = 0; peer->pcount[AFI_IP][SAFI_MULTICAST] = 0; peer->pcount[AFI_IP][SAFI_MPLS_VPN] = 0; peer->pcount[AFI_IP6][SAFI_UNICAST] = 0; peer->pcount[AFI_IP6][SAFI_MULTICAST] = 0; #endif /* 0 */ return 0; }
/* Administrative BGP peer stop event. */ int bgp_stop (struct peer *peer) { int established = 0; afi_t afi; safi_t safi; char orf_name[BUFSIZ]; /* Increment Dropped count. */ if (peer->status == Established) { established = 1; peer->dropped++; bgp_fsm_change_status (peer, Idle); #ifdef HAVE_SNMP bgpTrapBackwardTransition (peer); #endif /* HAVE_SNMP */ } /* Reset uptime. */ bgp_uptime_reset (peer); /* Need of clear of peer. */ if (established) bgp_clear_route_all (peer); /* Stop read and write threads when exists. */ BGP_READ_OFF (peer->t_read); BGP_WRITE_OFF (peer->t_write); /* Stop all timers. */ BGP_TIMER_OFF (peer->t_start); BGP_TIMER_OFF (peer->t_connect); BGP_TIMER_OFF (peer->t_holdtime); BGP_TIMER_OFF (peer->t_keepalive); BGP_TIMER_OFF (peer->t_asorig); BGP_TIMER_OFF (peer->t_routeadv); /* Delete all existing events of the peer. */ BGP_EVENT_DELETE (peer); /* Stream reset. */ peer->packet_size = 0; /* Clear input and output buffer. */ if (peer->ibuf) stream_reset (peer->ibuf); if (peer->work) stream_reset (peer->work); stream_fifo_clean (peer->obuf); /* Close of file descriptor. */ if (peer->fd >= 0) { close (peer->fd); peer->fd = -1; } /* Connection information. */ if (peer->su_local) { XFREE (MTYPE_SOCKUNION, peer->su_local); peer->su_local = NULL; } if (peer->su_remote) { XFREE (MTYPE_SOCKUNION, peer->su_remote); peer->su_remote = NULL; } /* Clear remote router-id. */ peer->remote_id.s_addr = 0; /* Reset all negotiated variables */ peer->afc_nego[AFI_IP][SAFI_UNICAST] = 0; peer->afc_nego[AFI_IP][SAFI_MULTICAST] = 0; peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] = 0; peer->afc_nego[AFI_IP6][SAFI_UNICAST] = 0; peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = 0; peer->afc_adv[AFI_IP][SAFI_UNICAST] = 0; peer->afc_adv[AFI_IP][SAFI_MULTICAST] = 0; peer->afc_adv[AFI_IP][SAFI_MPLS_VPN] = 0; peer->afc_adv[AFI_IP6][SAFI_UNICAST] = 0; peer->afc_adv[AFI_IP6][SAFI_MULTICAST] = 0; peer->afc_recv[AFI_IP][SAFI_UNICAST] = 0; peer->afc_recv[AFI_IP][SAFI_MULTICAST] = 0; peer->afc_recv[AFI_IP][SAFI_MPLS_VPN] = 0; peer->afc_recv[AFI_IP6][SAFI_UNICAST] = 0; peer->afc_recv[AFI_IP6][SAFI_MULTICAST] = 0; /* Reset route refresh flag. */ UNSET_FLAG (peer->cap, PEER_CAP_REFRESH_ADV); UNSET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV); UNSET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV); UNSET_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV); UNSET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV); for (afi = AFI_IP ; afi < AFI_MAX ; afi++) for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) { /* peer address family capability flags*/ peer->af_cap[afi][safi] = 0; /* peer address family status flags*/ peer->af_sflags[afi][safi] = 0; /* Received ORF prefix-filter */ peer->orf_plist[afi][safi] = NULL; /* ORF received prefix-filter pnt */ sprintf (orf_name, "%s.%d.%d", peer->host, afi, safi); prefix_bgp_orf_remove_all (orf_name); } UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST], PEER_FLAG_DEFAULT_ORIGINATE_CHECK); UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_MULTICAST], PEER_FLAG_DEFAULT_ORIGINATE_CHECK); UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_UNICAST], PEER_FLAG_DEFAULT_ORIGINATE_CHECK); UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_MULTICAST], PEER_FLAG_DEFAULT_ORIGINATE_CHECK); /* Reset keepalive and holdtime */ if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)) { peer->v_keepalive = peer->keepalive; peer->v_holdtime = peer->holdtime; } else { peer->v_keepalive = peer->bgp->default_keepalive; peer->v_holdtime = peer->bgp->default_holdtime; } peer->update_time = 0; /* Until we are sure that there is no problem about prefix count this should be commented out.*/ #if 0 /* Reset prefix count */ peer->pcount[AFI_IP][SAFI_UNICAST] = 0; peer->pcount[AFI_IP][SAFI_MULTICAST] = 0; peer->pcount[AFI_IP][SAFI_MPLS_VPN] = 0; peer->pcount[AFI_IP6][SAFI_UNICAST] = 0; peer->pcount[AFI_IP6][SAFI_MULTICAST] = 0; #endif /* 0 */ return 0; }