diff options
Diffstat (limited to 'bgpd/bgp_network.c')
| -rw-r--r-- | bgpd/bgp_network.c | 256 |
1 files changed, 166 insertions, 90 deletions
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index e235a61f59..dbb34b048f 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -35,7 +35,7 @@ extern struct zebra_privs_t bgpd_privs; -static char *bgp_get_bound_name(struct peer *peer); +static char *bgp_get_bound_name(struct peer_connection *connection); void bgp_dump_listener_info(struct vty *vty) { @@ -117,11 +117,13 @@ static int bgp_md5_set_connect(int socket, union sockunion *su, return ret; } -static int bgp_md5_set_password(struct peer *peer, const char *password) +static int bgp_md5_set_password(struct peer_connection *connection, + const char *password) { struct listnode *node; int ret = 0; struct bgp_listener *listener; + struct peer *peer = connection->peer; /* * Set or unset the password on the listen socket(s). Outbound @@ -130,9 +132,9 @@ static int bgp_md5_set_password(struct peer *peer, const char *password) frr_with_privs(&bgpd_privs) { for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, listener)) if (listener->su.sa.sa_family == - peer->su.sa.sa_family) { + connection->su.sa.sa_family) { uint16_t prefixlen = - peer->su.sa.sa_family == AF_INET + connection->su.sa.sa_family == AF_INET ? IPV4_MAX_BITLEN : IPV6_MAX_BITLEN; @@ -149,8 +151,8 @@ static int bgp_md5_set_password(struct peer *peer, const char *password) continue; ret = bgp_md5_set_socket(listener->fd, - &peer->su, prefixlen, - password); + &connection->su, + prefixlen, password); break; } } @@ -186,10 +188,10 @@ int bgp_md5_unset_prefix(struct bgp *bgp, struct prefix *p) return bgp_md5_set_prefix(bgp, p, NULL); } -int bgp_md5_set(struct peer *peer) +int bgp_md5_set(struct peer_connection *connection) { /* Set the password from listen socket. */ - return bgp_md5_set_password(peer, peer->password); + return bgp_md5_set_password(connection, connection->peer->password); } static void bgp_update_setsockopt_tcp_keepalive(struct bgp *bgp, int fd) @@ -211,18 +213,20 @@ static void bgp_update_setsockopt_tcp_keepalive(struct bgp *bgp, int fd) } } -int bgp_md5_unset(struct peer *peer) +int bgp_md5_unset(struct peer_connection *connection) { /* Unset the password from listen socket. */ - return bgp_md5_set_password(peer, NULL); + return bgp_md5_set_password(connection, NULL); } -int bgp_set_socket_ttl(struct peer *peer, int bgp_sock) +int bgp_set_socket_ttl(struct peer_connection *connection) { int ret = 0; + struct peer *peer = connection->peer; if (!peer->gtsm_hops) { - ret = sockopt_ttl(peer->su.sa.sa_family, bgp_sock, peer->ttl); + ret = sockopt_ttl(connection->su.sa.sa_family, connection->fd, + peer->ttl); if (ret) { flog_err( EC_LIB_SOCKET, @@ -235,7 +239,8 @@ int bgp_set_socket_ttl(struct peer *peer, int bgp_sock) with the outgoing ttl. Therefore setting both. */ - ret = sockopt_ttl(peer->su.sa.sa_family, bgp_sock, MAXTTL); + ret = sockopt_ttl(connection->su.sa.sa_family, connection->fd, + MAXTTL); if (ret) { flog_err( EC_LIB_SOCKET, @@ -243,7 +248,7 @@ int bgp_set_socket_ttl(struct peer *peer, int bgp_sock) __func__, &peer->remote_id, errno); return ret; } - ret = sockopt_minttl(peer->su.sa.sa_family, bgp_sock, + ret = sockopt_minttl(connection->su.sa.sa_family, connection->fd, MAXTTL + 1 - peer->gtsm_hops); if (ret) { flog_err( @@ -329,6 +334,53 @@ static int bgp_get_instance_for_inc_conn(int sock, struct bgp **bgp_inst) #endif } +int bgp_tcp_mss_set(struct peer *peer) +{ + struct listnode *node; + int ret = 0; + struct bgp_listener *listener; + uint32_t min_mss = 0; + struct peer *p; + + for (ALL_LIST_ELEMENTS_RO(peer->bgp->peer, node, p)) { + if (!CHECK_FLAG(p->flags, PEER_FLAG_TCP_MSS)) + continue; + + if (!p->tcp_mss) + continue; + + if (!min_mss) + min_mss = p->tcp_mss; + + min_mss = MIN(min_mss, p->tcp_mss); + } + + frr_with_privs(&bgpd_privs) { + for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, listener)) { + if (listener->su.sa.sa_family != + peer->connection->su.sa.sa_family) + continue; + + if (!listener->bgp) { + if (peer->bgp->vrf_id != VRF_DEFAULT) + continue; + } else if (listener->bgp != peer->bgp) + continue; + + /* Set TCP MSS per listener only if there is at least + * one peer that is in passive mode. Otherwise, TCP MSS + * is set per socket via bgp_connect(). + */ + if (CHECK_FLAG(peer->flags, PEER_FLAG_PASSIVE)) + sockopt_tcp_mss_set(listener->fd, min_mss); + + break; + } + } + + return ret; +} + static void bgp_socket_set_buffer_size(const int fd) { if (getsockopt_so_sendbuf(fd) < (int)bm->socket_buffer) @@ -344,8 +396,8 @@ static void bgp_accept(struct event *thread) int accept_sock; union sockunion su; struct bgp_listener *listener = EVENT_ARG(thread); - struct peer *peer; - struct peer *peer1; + struct peer *peer, *peer1; + struct peer_connection *connection, *connection1; char buf[SU_ADDRSTRLEN]; struct bgp *bgp = NULL; @@ -428,25 +480,37 @@ static void bgp_accept(struct event *thread) if (!peer1) { peer1 = peer_lookup_dynamic_neighbor(bgp, &su); if (peer1) { + connection1 = peer1->connection; /* Dynamic neighbor has been created, let it proceed */ - peer1->fd = bgp_sock; + connection1->fd = bgp_sock; + + if (bgp_set_socket_ttl(connection1) < 0) { + peer1->last_reset = PEER_DOWN_SOCKET_ERROR; + zlog_err("%s: Unable to set min/max TTL on peer %s (dynamic), error received: %s(%d)", + __func__, peer1->host, + safe_strerror(errno), errno); + return; + } /* Set the user configured MSS to TCP socket */ if (CHECK_FLAG(peer1->flags, PEER_FLAG_TCP_MSS)) sockopt_tcp_mss_set(bgp_sock, peer1->tcp_mss); - bgp_fsm_change_status(peer1, Active); - EVENT_OFF( - peer1->t_start); /* created in peer_create() */ + frr_with_privs (&bgpd_privs) { + vrf_bind(peer1->bgp->vrf_id, bgp_sock, + bgp_get_bound_name(connection1)); + } + bgp_peer_reg_with_nht(peer1); + bgp_fsm_change_status(connection1, Active); + EVENT_OFF(connection1->t_start); if (peer_active(peer1)) { if (CHECK_FLAG(peer1->flags, PEER_FLAG_TIMER_DELAYOPEN)) - BGP_EVENT_ADD( - peer1, - TCP_connection_open_w_delay); + BGP_EVENT_ADD(connection1, + TCP_connection_open_w_delay); else - BGP_EVENT_ADD(peer1, + BGP_EVENT_ADD(connection1, TCP_connection_open); } @@ -465,6 +529,7 @@ static void bgp_accept(struct event *thread) return; } + connection1 = peer1->connection; if (CHECK_FLAG(peer1->flags, PEER_FLAG_SHUTDOWN) || CHECK_FLAG(peer1->bgp->flags, BGP_FLAG_SHUTDOWN)) { if (bgp_debug_neighbor_events(peer1)) @@ -482,11 +547,11 @@ static void bgp_accept(struct event *thread) * Established and then the Clearing_Completed event is generated. Also, * block incoming connection in Deleted state. */ - if (peer1->status == Clearing || peer1->status == Deleted) { + if (connection1->status == Clearing || connection1->status == Deleted) { if (bgp_debug_neighbor_events(peer1)) - zlog_debug( - "[Event] Closing incoming conn for %s (%p) state %d", - peer1->host, peer1, peer1->status); + zlog_debug("[Event] Closing incoming conn for %s (%p) state %d", + peer1->host, peer1, + peer1->connection->status); close(bgp_sock); return; } @@ -521,10 +586,9 @@ static void bgp_accept(struct event *thread) } if (bgp_debug_neighbor_events(peer1)) - zlog_debug( - "[Event] connection from %s fd %d, active peer status %d fd %d", - inet_sutop(&su, buf), bgp_sock, peer1->status, - peer1->fd); + zlog_debug("[Event] connection from %s fd %d, active peer status %d fd %d", + inet_sutop(&su, buf), bgp_sock, connection1->status, + connection1->fd); if (peer1->doppelganger) { /* We have an existing connection. Kill the existing one and run @@ -537,15 +601,11 @@ static void bgp_accept(struct event *thread) peer_delete(peer1->doppelganger); } - if (bgp_set_socket_ttl(peer1, bgp_sock) < 0) - if (bgp_debug_neighbor_events(peer1)) - zlog_debug( - "[Event] Unable to set min/max TTL on peer %s, Continuing", - peer1->host); - peer = peer_create(&su, peer1->conf_if, peer1->bgp, peer1->local_as, peer1->as, peer1->as_type, NULL, false, NULL); + connection = peer->connection; + peer_xfer_config(peer, peer1); bgp_peer_gr_flags_update(peer); @@ -563,18 +623,25 @@ static void bgp_accept(struct event *thread) peer->doppelganger = peer1; peer1->doppelganger = peer; - peer->fd = bgp_sock; + connection->fd = bgp_sock; + + if (bgp_set_socket_ttl(connection) < 0) + if (bgp_debug_neighbor_events(peer)) + zlog_debug("[Event] Unable to set min/max TTL on peer %s, Continuing", + peer->host); + frr_with_privs(&bgpd_privs) { - vrf_bind(peer->bgp->vrf_id, bgp_sock, bgp_get_bound_name(peer)); + vrf_bind(peer->bgp->vrf_id, bgp_sock, + bgp_get_bound_name(peer->connection)); } bgp_peer_reg_with_nht(peer); - bgp_fsm_change_status(peer, Active); - EVENT_OFF(peer->t_start); /* created in peer_create() */ + bgp_fsm_change_status(connection, Active); + EVENT_OFF(connection->t_start); /* created in peer_create() */ SET_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER); /* Make dummy peer until read Open packet. */ - if (peer_established(peer1) - && CHECK_FLAG(peer1->sflags, PEER_STATUS_NSF_MODE)) { + if (peer_established(connection1) && + CHECK_FLAG(peer1->sflags, PEER_STATUS_NSF_MODE)) { /* If we have an existing established connection with graceful * restart * capability announced with one or more address families, then @@ -588,14 +655,14 @@ static void bgp_accept(struct event *thread) PEER_FLAG_GRACEFUL_RESTART_HELPER)) SET_FLAG(peer1->sflags, PEER_STATUS_NSF_WAIT); - bgp_event_update(peer1, TCP_connection_closed); + bgp_event_update(connection1, TCP_connection_closed); } if (peer_active(peer)) { if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER_DELAYOPEN)) - BGP_EVENT_ADD(peer, TCP_connection_open_w_delay); + BGP_EVENT_ADD(connection, TCP_connection_open_w_delay); else - BGP_EVENT_ADD(peer, TCP_connection_open); + BGP_EVENT_ADD(connection, TCP_connection_open); } /* @@ -606,24 +673,23 @@ static void bgp_accept(struct event *thread) } /* BGP socket bind. */ -static char *bgp_get_bound_name(struct peer *peer) +static char *bgp_get_bound_name(struct peer_connection *connection) { - if (!peer) - return NULL; + struct peer *peer = connection->peer; if ((peer->bgp->vrf_id == VRF_DEFAULT) && !peer->ifname && !peer->conf_if) return NULL; - if (peer->su.sa.sa_family != AF_INET - && peer->su.sa.sa_family != AF_INET6) + if (connection->su.sa.sa_family != AF_INET && + connection->su.sa.sa_family != AF_INET6) return NULL; // unexpected /* For IPv6 peering, interface (unnumbered or link-local with interface) * takes precedence over VRF. For IPv4 peering, explicit interface or * VRF are the situations to bind. */ - if (peer->su.sa.sa_family == AF_INET6 && peer->conf_if) + if (connection->su.sa.sa_family == AF_INET6 && peer->conf_if) return peer->conf_if; if (peer->ifname) @@ -640,7 +706,6 @@ int bgp_update_address(struct interface *ifp, const union sockunion *dst, { struct prefix *p, *sel, d; struct connected *connected; - struct listnode *node; int common; if (!sockunion2hostprefix(dst, &d)) @@ -649,7 +714,7 @@ int bgp_update_address(struct interface *ifp, const union sockunion *dst, sel = NULL; common = -1; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) { + frr_each (if_connected, ifp->connected, connected) { p = connected->address; if (p->family != d.family) continue; @@ -667,11 +732,12 @@ int bgp_update_address(struct interface *ifp, const union sockunion *dst, } /* Update source selection. */ -static int bgp_update_source(struct peer *peer) +static int bgp_update_source(struct peer_connection *connection) { struct interface *ifp; union sockunion addr; int ret = 0; + struct peer *peer = connection->peer; sockunion_init(&addr); @@ -681,38 +747,41 @@ static int bgp_update_source(struct peer *peer) if (!ifp) return -1; - if (bgp_update_address(ifp, &peer->su, &addr)) + if (bgp_update_address(ifp, &connection->su, &addr)) return -1; - ret = sockunion_bind(peer->fd, &addr, 0, &addr); + ret = sockunion_bind(connection->fd, &addr, 0, &addr); } /* Source is specified with IP address. */ if (peer->update_source) - ret = sockunion_bind(peer->fd, peer->update_source, 0, + ret = sockunion_bind(connection->fd, peer->update_source, 0, peer->update_source); return ret; } /* BGP try to connect to the peer. */ -int bgp_connect(struct peer *peer) +int bgp_connect(struct peer_connection *connection) { - assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_WRITES_ON)); - assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_READS_ON)); + struct peer *peer = connection->peer; + + assert(!CHECK_FLAG(connection->thread_flags, PEER_THREAD_WRITES_ON)); + assert(!CHECK_FLAG(connection->thread_flags, PEER_THREAD_READS_ON)); ifindex_t ifindex = 0; - if (peer->conf_if && BGP_PEER_SU_UNSPEC(peer)) { + if (peer->conf_if && BGP_CONNECTION_SU_UNSPEC(connection)) { if (bgp_debug_neighbor_events(peer)) zlog_debug("Peer address not learnt: Returning from connect"); return 0; } frr_with_privs(&bgpd_privs) { - /* Make socket for the peer. */ - peer->fd = vrf_sockunion_socket(&peer->su, peer->bgp->vrf_id, - bgp_get_bound_name(peer)); + /* Make socket for the peer. */ + connection->fd = + vrf_sockunion_socket(&connection->su, peer->bgp->vrf_id, + bgp_get_bound_name(connection)); } - if (peer->fd < 0) { + if (connection->fd < 0) { peer->last_reset = PEER_DOWN_SOCKET_ERROR; if (bgp_debug_neighbor_events(peer)) zlog_debug("%s: Failure to create socket for connection to %s, error received: %s(%d)", @@ -721,18 +790,18 @@ int bgp_connect(struct peer *peer) return -1; } - set_nonblocking(peer->fd); + set_nonblocking(connection->fd); /* Set the user configured MSS to TCP socket */ if (CHECK_FLAG(peer->flags, PEER_FLAG_TCP_MSS)) - sockopt_tcp_mss_set(peer->fd, peer->tcp_mss); + sockopt_tcp_mss_set(connection->fd, peer->tcp_mss); - bgp_socket_set_buffer_size(peer->fd); + bgp_socket_set_buffer_size(connection->fd); /* Set TCP keepalive when TCP keepalive is enabled */ - bgp_update_setsockopt_tcp_keepalive(peer->bgp, peer->fd); + bgp_update_setsockopt_tcp_keepalive(peer->bgp, connection->fd); - if (bgp_set_socket_ttl(peer, peer->fd) < 0) { + if (bgp_set_socket_ttl(peer->connection) < 0) { peer->last_reset = PEER_DOWN_SOCKET_ERROR; if (bgp_debug_neighbor_events(peer)) zlog_debug("%s: Failure to set socket ttl for connection to %s, error received: %s(%d)", @@ -742,36 +811,42 @@ int bgp_connect(struct peer *peer) return -1; } - sockopt_reuseaddr(peer->fd); - sockopt_reuseport(peer->fd); + sockopt_reuseaddr(connection->fd); + sockopt_reuseport(connection->fd); #ifdef IPTOS_PREC_INTERNETCONTROL frr_with_privs(&bgpd_privs) { - if (sockunion_family(&peer->su) == AF_INET) - setsockopt_ipv4_tos(peer->fd, bm->tcp_dscp); - else if (sockunion_family(&peer->su) == AF_INET6) - setsockopt_ipv6_tclass(peer->fd, bm->tcp_dscp); + if (sockunion_family(&connection->su) == AF_INET) + setsockopt_ipv4_tos(connection->fd, bm->tcp_dscp); + else if (sockunion_family(&connection->su) == AF_INET6) + setsockopt_ipv6_tclass(connection->fd, bm->tcp_dscp); } #endif if (peer->password) { - uint16_t prefixlen = peer->su.sa.sa_family == AF_INET + uint16_t prefixlen = peer->connection->su.sa.sa_family == AF_INET ? IPV4_MAX_BITLEN : IPV6_MAX_BITLEN; - if (!BGP_PEER_SU_UNSPEC(peer)) - bgp_md5_set(peer); + if (!BGP_CONNECTION_SU_UNSPEC(connection)) + bgp_md5_set(connection); - bgp_md5_set_connect(peer->fd, &peer->su, prefixlen, + bgp_md5_set_connect(connection->fd, &connection->su, prefixlen, peer->password); } /* Update source bind. */ - if (bgp_update_source(peer) < 0) { + if (bgp_update_source(connection) < 0) { peer->last_reset = PEER_DOWN_SOCKET_ERROR; return connect_error; } + /* If the peer is passive mode, force to move to Active mode. */ + if (CHECK_FLAG(peer->flags, PEER_FLAG_PASSIVE)) { + BGP_EVENT_ADD(connection, TCP_connection_open_failed); + return BGP_FSM_SUCCESS; + } + if (peer->conf_if || peer->ifname) ifindex = ifname2ifindex(peer->conf_if ? peer->conf_if : peer->ifname, @@ -779,11 +854,11 @@ int bgp_connect(struct peer *peer) if (bgp_debug_neighbor_events(peer)) zlog_debug("%s [Event] Connect start to %s fd %d", peer->host, - peer->host, peer->fd); + peer->host, connection->fd); /* Connect to the remote peer. */ - return sockunion_connect(peer->fd, &peer->su, htons(peer->port), - ifindex); + return sockunion_connect(connection->fd, &connection->su, + htons(peer->port), ifindex); } /* After TCP connection is established. Get local address and port. */ @@ -799,10 +874,10 @@ int bgp_getsockname(struct peer *peer) peer->su_remote = NULL; } - peer->su_local = sockunion_getsockname(peer->fd); + peer->su_local = sockunion_getsockname(peer->connection->fd); if (!peer->su_local) return -1; - peer->su_remote = sockunion_getpeername(peer->fd); + peer->su_remote = sockunion_getpeername(peer->connection->fd); if (!peer->su_remote) return -1; @@ -810,8 +885,9 @@ int bgp_getsockname(struct peer *peer) &peer->nexthop, peer)) { flog_err( EC_BGP_NH_UPD, - "%s: nexthop_set failed, resetting connection - intf %s", - peer->host, + "%s: nexthop_set failed, local: %pSUp remote: %pSUp update_if: %s resetting connection - intf %s", + peer->host, peer->su_local, peer->su_remote, + peer->update_if ? peer->update_if : "(None)", peer->nexthop.ifp ? peer->nexthop.ifp->name : "(Unknown)"); return -1; |
