/* Fake execution of the thread with given arguemment. */ struct thread * thread_execute (struct thread_master *master, int (*func)(struct thread *), void *arg, int val) { struct thread dummy; pal_mem_set (&dummy, 0, sizeof (struct thread)); dummy.type = THREAD_EVENT; dummy.master = NULL; dummy.func = func; dummy.arg = arg; dummy.u.val = val; thread_call (&dummy); return NULL; }
/* Fake execution of the thread with given arguemment. */ struct thread * thread_execute (struct lib_globals *zg, int (*func)(struct thread *), void *arg, int val) { struct thread dummy; /* Set the global VR context to PVR. */ if (zg) zg->vr_in_cxt = ipi_vr_get_privileged(zg); pal_mem_set (&dummy, 0, sizeof (struct thread)); dummy.type = THREAD_EVENT; dummy.master = NULL; dummy.func = func; dummy.arg = arg; dummy.u.val = val; thread_call (&dummy); return NULL; }
/* 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; }
/* BGP Peer TCP Socket bind to 'update-source' address * * Specify the TCP client's source IP address. * This function must be called before calling connect(). * The source port is set to "any port" * (i.e., picked by the kernel) unless a user specified it. */ s_int32_t bpn_sock_bind_address (struct bgp_peer *peer, pal_sock_handle_t sck_fd) { struct prefix *if_prefix; struct interface *ifp; union sockunion uaddr; s_int32_t uaddr_len; s_int32_t ret; pal_mem_set (&uaddr, 0, sizeof (union sockunion)); uaddr_len = 0; ret = 0; /* Ifname is exist. */ if (peer->update_if) { ifp = if_lookup_by_name (&BGP_VR.owning_ivr->ifm, peer->update_if); if (! ifp) { ret = -1; goto EXIT; } if_prefix = if_get_connected_address (ifp, peer->su.sa.sa_family); if (! if_prefix) { ret = -1; goto EXIT; } uaddr.sa.sa_family = if_prefix->family; if (uaddr.sa.sa_family == AF_INET) { uaddr.sin.sin_family = AF_INET; uaddr_len = sizeof (struct pal_sockaddr_in4); #ifdef HAVE_SIN_LEN uaddr.sin.sin_len = pal_hton16 (uaddr_len); #endif /* HAVE_SIN_LEN */ IPV4_ADDR_COPY (&uaddr.sin.sin_addr, &if_prefix->u.prefix4); if (peer->sock_port == BGP_PORT_DEFAULT) uaddr.sin.sin_port = bpn_get_port_any (AF_INET, SOCK_STREAM, &uaddr.sa); else uaddr.sin.sin_port = pal_hton16 (peer->sock_port); } #ifdef HAVE_IPV6 else if (BGP_CAP_HAVE_IPV6 && uaddr.sa.sa_family == AF_INET6) { uaddr.sin6.sin6_family = AF_INET6; uaddr_len = sizeof (struct pal_sockaddr_in6); #ifdef HAVE_SIN_LEN uaddr.sin6.sin6_len = pal_hton16 (uaddr_len); #endif /* HAVE_SIN_LEN */ IPV6_ADDR_COPY (&uaddr.sin6.sin6_addr, &if_prefix->u.prefix6); if (peer->sock_port == BGP_PORT_DEFAULT) uaddr.sin6.sin6_port = bpn_get_port_any (AF_INET6, SOCK_STREAM, &uaddr.sa); else uaddr.sin6.sin6_port = pal_hton16 (peer->sock_port); } #endif /* HAVE_IPV6 */ else { if (BGP_DEBUG (events, EVENTS)) zlog_err (&BLG, "%s-%s [NETWORK] bind addr: socket (%d), " "unknown update-interface family (%d)", peer->host, BGP_PEER_DIR_STR (peer), sck_fd, uaddr.sa.sa_family); ret = -1; goto EXIT; } } else if (peer->update_source) { uaddr.sa.sa_family = peer->update_source->sa.sa_family; if (uaddr.sa.sa_family == AF_INET) { uaddr.sin.sin_family = AF_INET; uaddr_len = sizeof (struct pal_sockaddr_in4); if (peer->sock_port == BGP_PORT_DEFAULT) uaddr.sin.sin_port = bpn_get_port_any (AF_INET, SOCK_STREAM, &peer->update_source->sa); else uaddr.sin.sin_port = pal_hton16 (peer->sock_port); #ifdef HAVE_SIN_LEN uaddr.sin.sin_len = pal_hton16 (uaddr_len); #endif /* HAVE_SIN_LEN */ IPV4_ADDR_COPY (&uaddr.sin.sin_addr, &peer->update_source->sin.sin_addr); } #ifdef HAVE_IPV6 else if (BGP_CAP_HAVE_IPV6 && uaddr.sa.sa_family == AF_INET6) { uaddr.sin6.sin6_family = AF_INET6; uaddr_len = sizeof (struct pal_sockaddr_in6); if (peer->sock_port == BGP_PORT_DEFAULT) uaddr.sin6.sin6_port = bpn_get_port_any (AF_INET6, SOCK_STREAM, &peer->update_source->sa); else uaddr.sin.sin_port = pal_hton16 (peer->sock_port); #ifdef HAVE_SIN_LEN uaddr.sin6.sin6_len = pal_hton16 (uaddr_len); #endif /* HAVE_SIN_LEN */ IPV6_ADDR_COPY (&uaddr.sin6.sin6_addr, &peer->update_source->sin6.sin6_addr); } #endif /* HAVE_IPV6 */ else { if (BGP_DEBUG (events, EVENTS)) zlog_err (&BLG, "%s-%s [NETWORK] bind addr: socket (%d), " "unknown update-address family (%d)", peer->host, BGP_PEER_DIR_STR (peer), sck_fd, uaddr.sa.sa_family); ret = -1; goto EXIT; } } if (uaddr_len) { ret = pal_sock_bind (sck_fd, (struct pal_sockaddr *) &uaddr, uaddr_len); if (ret < 0) if (BGP_DEBUG (events, EVENTS)) zlog_err (&BLG, "%s-%s [NETWORK] bind addr: socket (%d), bind" " failed (%d-%s)", peer->host, BGP_PEER_DIR_STR (peer), sck_fd, errno, pal_strerror (errno)); } EXIT: return ret; }
in_port_t bpn_get_port_any (int family, int socktype, struct pal_sockaddr *sa) { struct pal_addrinfo hints; struct pal_addrinfo *res; void *src; socklen_t size; in_port_t port_any = 0; char addr_str[INET6_ADDRSTRLEN]; const char *s; int ret; pal_mem_set (&hints, 0, sizeof(hints)); hints.ai_flags |= (AI_NUMERICHOST | AI_NUMERICSERV); hints.ai_family = family; hints.ai_socktype = socktype; switch (family) { case AF_INET: if (sa->sa_family != AF_INET) { zlog_warn (&BLG, "[NETWORK] %s: family mismatch (AF_INET - %d)", __FUNCTION__, sa->sa_family); goto fallback; } src = &(((struct pal_sockaddr_in4 *)sa)->sin_addr); size = INET_ADDRSTRLEN; break; #ifdef HAVE_IPV6 case AF_INET6: if (sa->sa_family != AF_INET6) { zlog_warn (&BLG, "[NETWORK] %s: family mismatch (AF_INET6 - %d)", __FUNCTION__, sa->sa_family); goto fallback; } src = &(((struct pal_sockaddr_in6 *)sa)->sin6_addr); size = INET6_ADDRSTRLEN; break; #endif /* HAVE_IPV6 */ default: zlog_warn (&BLG, "[NETWORK] %s: wrong family param (%d)", __FUNCTION__, sa->sa_family); goto fallback; } s = pal_inet_ntop (family, src, addr_str, size); if (!s) { zlog_warn (&BLG, "[NETWORK] %s: inet_ntop(%d)", __FUNCTION__, errno); goto fallback; } ret = pal_sock_getaddrinfo (addr_str, NULL, &hints, &res); if (ret < 0) { zlog_warn (&BLG, "[NETWORK] %s: getaddrinfo(%d)", __FUNCTION__, errno); goto fallback; } switch (res->ai_family) { case AF_INET: port_any = ((struct pal_sockaddr_in4 *)(res->ai_addr))->sin_port; break; #ifdef HAVE_IPV6 case AF_INET6: port_any = ((struct pal_sockaddr_in6 *)(res->ai_addr))->sin6_port; break; #endif /* HAVE_IPV6 */ default: zlog_warn (&BLG, "[NETWORK] %s: wrong family from getaddrinfo(): %d", __FUNCTION__, res->ai_family); break; } pal_sock_freeaddrinfo (res); fallback: return port_any; }