diff options
Diffstat (limited to 'bgpd')
-rw-r--r-- | bgpd/bgp_aspath.c | 40 | ||||
-rw-r--r-- | bgpd/bgp_aspath.h | 2 | ||||
-rw-r--r-- | bgpd/bgp_attr.c | 11 | ||||
-rw-r--r-- | bgpd/bgp_network.c | 190 | ||||
-rw-r--r-- | bgpd/bgp_network.h | 3 | ||||
-rw-r--r-- | bgpd/bgp_vty.c | 5 | ||||
-rw-r--r-- | bgpd/bgpd.c | 22 |
7 files changed, 173 insertions, 100 deletions
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 13f32b86..440815b4 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -1122,6 +1122,42 @@ aspath_private_as_check (struct aspath *aspath) return 1; } +/* AS path confed check. If aspath contains confed set or sequence then return 1. */ +int +aspath_confed_check (struct aspath *aspath) +{ + struct assegment *seg; + + if ( !(aspath && aspath->segments) ) + return 0; + + seg = aspath->segments; + + while (seg) + { + if (seg->type == AS_CONFED_SET || seg->type == AS_CONFED_SEQUENCE) + return 1; + seg = seg->next; + } + return 0; +} + +/* Leftmost AS path segment confed check. If leftmost AS segment is of type + AS_CONFED_SEQUENCE or AS_CONFED_SET then return 1. */ +int +aspath_left_confed_check (struct aspath *aspath) +{ + + if ( !(aspath && aspath->segments) ) + return 0; + + if ( (aspath->segments->type == AS_CONFED_SEQUENCE) + || (aspath->segments->type == AS_CONFED_SET) ) + return 1; + + return 0; +} + /* Merge as1 to as2. as2 should be uninterned aspath. */ static struct aspath * aspath_merge (struct aspath *as1, struct aspath *as2) @@ -1172,6 +1208,10 @@ aspath_prepend (struct aspath *as1, struct aspath *as2) while (seg1 && seg1->next) seg1 = seg1->next; + /* Delete any AS_CONFED_SEQUENCE segment from as2. */ + if (seg1->type == AS_SEQUENCE && seg2->type == AS_CONFED_SEQUENCE) + as2 = aspath_delete_confed_seq (as2); + /* Compare last segment type of as1 and first segment type of as2. */ if (seg1->type != seg2->type) return aspath_merge (as1, as2); diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index 2b4625c8..9854d186 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -88,6 +88,8 @@ extern unsigned int aspath_key_make (void *); extern int aspath_loop_check (struct aspath *, as_t); extern int aspath_private_as_check (struct aspath *); extern int aspath_firstas_check (struct aspath *, as_t); +extern int aspath_confed_check (struct aspath *); +extern int aspath_left_confed_check (struct aspath *); extern unsigned long aspath_count (void); extern unsigned int aspath_count_hops (struct aspath *); extern unsigned int aspath_count_confeds (struct aspath *); diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 94168372..a664858c 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -872,6 +872,17 @@ static int bgp_attr_aspath_check( struct peer *peer, bgp = peer->bgp; + /* Confederation sanity check. */ + if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) || + (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath))) + { + zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host); + bgp_notify_send (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_MAL_AS_PATH); + return -1; + } + /* First AS check for EBGP. */ if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS)) { diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 77847008..ade0fbc6 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -39,6 +39,13 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA extern struct zebra_privs_t bgpd_privs; +/* BGP listening socket. */ +struct bgp_listener +{ + int fd; + union sockunion su; + struct thread *thread; +}; /* * Set MD5 key for the socket, for the given IPv4 peer address. @@ -365,37 +372,90 @@ bgp_getsockname (struct peer *peer) bgp_nexthop_set (peer->su_local, peer->su_remote, &peer->nexthop, peer); } + +static int +bgp_listener (int sock, struct sockaddr *sa, socklen_t salen) +{ + struct bgp_listener *listener; + int ret, en; + + sockopt_reuseaddr (sock); + sockopt_reuseport (sock); + +#ifdef IPTOS_PREC_INTERNETCONTROL + if (sa->sa_family == AF_INET) + setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL); +#endif + +#ifdef IPV6_V6ONLY + /* Want only IPV6 on ipv6 socket (not mapped addresses) */ + if (sa->sa_family == AF_INET6) { + int on = 1; + setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, + (void *) &on, sizeof (on)); + } +#endif + + if (bgpd_privs.change (ZPRIVS_RAISE) ) + zlog_err ("bgp_socket: could not raise privs"); + + ret = bind (sock, sa, salen); + en = errno; + if (bgpd_privs.change (ZPRIVS_LOWER) ) + zlog_err ("bgp_bind_address: could not lower privs"); + + if (ret < 0) + { + zlog_err ("bind: %s", safe_strerror (en)); + return ret; + } + + ret = listen (sock, 3); + if (ret < 0) + { + zlog_err ("listen: %s", safe_strerror (errno)); + return ret; + } + + listener = XMALLOC (MTYPE_BGP_LISTENER, sizeof(*listener)); + listener->fd = sock; + memcpy(&listener->su, sa, salen); + listener->thread = thread_add_read (master, bgp_accept, listener, sock); + listnode_add (bm->listen_sockets, listener); + + return 0; +} + /* IPv6 supported version of BGP server socket setup. */ #if defined (HAVE_IPV6) && ! defined (NRL) int -bgp_socket (struct bgp *bgp, unsigned short port, char *address) +bgp_socket (unsigned short port, const char *address) { - int ret, en; - struct addrinfo req; struct addrinfo *ainfo; struct addrinfo *ainfo_save; - int sock = 0; + static const struct addrinfo req = { + .ai_family = AF_UNSPEC, + .ai_flags = AI_PASSIVE, + .ai_socktype = SOCK_STREAM, + }; + int ret, count; char port_str[BUFSIZ]; - memset (&req, 0, sizeof (struct addrinfo)); - - req.ai_flags = AI_PASSIVE; - req.ai_family = AF_UNSPEC; - req.ai_socktype = SOCK_STREAM; snprintf (port_str, sizeof(port_str), "%d", port); port_str[sizeof (port_str) - 1] = '\0'; - ret = getaddrinfo (address, port_str, &req, &ainfo); + ret = getaddrinfo (address, port_str, &req, &ainfo_save); if (ret != 0) { zlog_err ("getaddrinfo: %s", gai_strerror (ret)); return -1; } - ainfo_save = ainfo; - - do + count = 0; + for (ainfo = ainfo_save; ainfo; ainfo = ainfo->ai_next) { + int sock; + if (ainfo->ai_family != AF_INET && ainfo->ai_family != AF_INET6) continue; @@ -406,59 +466,25 @@ bgp_socket (struct bgp *bgp, unsigned short port, char *address) continue; } - sockopt_reuseaddr (sock); - sockopt_reuseport (sock); - -#ifdef IPTOS_PREC_INTERNETCONTROL - if (ainfo->ai_family == AF_INET) - setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL); -#endif - -#ifdef IPV6_V6ONLY - /* Want only IPV6 on ipv6 socket (not mapped addresses) */ - if (ainfo->ai_family == AF_INET6) { - int on = 1; - setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, - (void *) &on, sizeof (on)); - } -#endif - - if (bgpd_privs.change (ZPRIVS_RAISE) ) - zlog_err ("bgp_socket: could not raise privs"); - - ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen); - en = errno; - if (bgpd_privs.change (ZPRIVS_LOWER) ) - zlog_err ("bgp_bind_address: could not lower privs"); - - if (ret < 0) - { - zlog_err ("bind: %s", safe_strerror (en)); - close(sock); - continue; - } - - ret = listen (sock, 3); - if (ret < 0) - { - zlog_err ("listen: %s", safe_strerror (errno)); - close (sock); - continue; - } - - listnode_add (bm->listen_sockets, (void *)(long)sock); - thread_add_read (master, bgp_accept, bgp, sock); + ret = bgp_listener (sock, ainfo->ai_addr, ainfo->ai_addrlen); + if (ret == 0) + ++count; + else + close(sock); } - while ((ainfo = ainfo->ai_next) != NULL); - freeaddrinfo (ainfo_save); + if (count == 0) + { + zlog_err ("%s: no usable addresses", __func__); + return -1; + } - return sock; + return 0; } #else /* Traditional IPv4 only version. */ int -bgp_socket (struct bgp *bgp, unsigned short port, char *address) +bgp_socket (unsigned short port, const char *address) { int sock; int socklen; @@ -472,15 +498,7 @@ bgp_socket (struct bgp *bgp, unsigned short port, char *address) return sock; } - sockopt_reuseaddr (sock); - sockopt_reuseport (sock); - -#ifdef IPTOS_PREC_INTERNETCONTROL - setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL); -#endif - memset (&sin, 0, sizeof (struct sockaddr_in)); - sin.sin_family = AF_INET; sin.sin_port = htons (port); socklen = sizeof (struct sockaddr_in); @@ -495,33 +513,27 @@ bgp_socket (struct bgp *bgp, unsigned short port, char *address) sin.sin_len = socklen; #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - if ( bgpd_privs.change (ZPRIVS_RAISE) ) - zlog_err ("bgp_socket: could not raise privs"); - - ret = bind (sock, (struct sockaddr *) &sin, socklen); - en = errno; - - if (bgpd_privs.change (ZPRIVS_LOWER) ) - zlog_err ("bgp_socket: could not lower privs"); - - if (ret < 0) - { - zlog_err ("bind: %s", safe_strerror (en)); - close (sock); - return ret; - } - - ret = listen (sock, 3); + ret = bgp_listener (sock, (struct sockaddr *) &sin, socklen); if (ret < 0) { - zlog_err ("listen: %s", safe_strerror (errno)); close (sock); return ret; } - - listnode_add (bm->listen_sockets, (void *)(long)sock); - thread_add_read (bm->master, bgp_accept, bgp, sock); - return sock; } #endif /* HAVE_IPV6 && !NRL */ + +void +bgp_close (void) +{ + struct listnode *node, *next; + struct bgp_listener *listener; + + for (ALL_LIST_ELEMENTS (bm->listen_sockets, node, next, listener)) + { + thread_cancel (listener->thread); + close (listener->fd); + listnode_delete (bm->listen_sockets, listener); + XFREE (MTYPE_BGP_LISTENER, listener); + } +} diff --git a/bgpd/bgp_network.h b/bgpd/bgp_network.h index 618d8dbb..5bf2e5ff 100644 --- a/bgpd/bgp_network.h +++ b/bgpd/bgp_network.h @@ -21,7 +21,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #ifndef _QUAGGA_BGP_NETWORK_H #define _QUAGGA_BGP_NETWORK_H -extern int bgp_socket (struct bgp *, unsigned short, char *); +extern int bgp_socket (unsigned short, const char *); +extern void bgp_close (void); extern int bgp_connect (struct peer *); extern void bgp_getsockname (struct peer *); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 13c37b57..88be52e2 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -2820,10 +2820,11 @@ peer_update_source_vty (struct vty *vty, const char *peer_str, return CMD_SUCCESS; } -#define BGP_UPDATE_SOURCE_STR "(A.B.C.D|X:X::X:X)" +#define BGP_UPDATE_SOURCE_STR "(A.B.C.D|X:X::X:X|WORD)" #define BGP_UPDATE_SOURCE_HELP_STR \ "IPv4 address\n" \ - "IPv6 address\n" + "IPv6 address\n" \ + "Interface name (requires zebra to be running)\n" DEFUN (neighbor_update_source, neighbor_update_source_cmd, diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 60722d27..ef8fbe97 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2036,6 +2036,13 @@ bgp_get (struct bgp **bgp_val, as_t *as, const char *name) } } + /* Create BGP server socket, if first instance. */ + if (list_isempty(bm->bgp)) + { + if (bgp_socket (bm->port, bm->address) < 0) + return BGP_ERR_INVALID_VALUE; + } + bgp = bgp_create (as, name); listnode_add (bm->bgp, bgp); bgp_router_id_set(bgp, &router_id_zebra); @@ -2081,7 +2088,9 @@ bgp_delete (struct bgp *bgp) * routes to be processed still referencing the struct bgp. */ listnode_delete (bm->bgp, bgp); - + if (list_isempty(bm->bgp)) + bgp_close (); + bgp_unlock(bgp); /* initial reference */ return 0; @@ -2262,7 +2271,7 @@ struct peer_flag_action u_char peer_down; }; -struct peer_flag_action peer_flag_action_list[] = +static const struct peer_flag_action peer_flag_action_list[] = { { PEER_FLAG_PASSIVE, 0, peer_change_reset }, { PEER_FLAG_SHUTDOWN, 0, peer_change_reset }, @@ -2274,7 +2283,7 @@ struct peer_flag_action peer_flag_action_list[] = { 0, 0, 0 } }; -struct peer_flag_action peer_af_flag_action_list[] = +static const struct peer_flag_action peer_af_flag_action_list[] = { { PEER_FLAG_NEXTHOP_SELF, 1, peer_change_reset_out }, { PEER_FLAG_SEND_COMMUNITY, 1, peer_change_reset_out }, @@ -2295,14 +2304,14 @@ struct peer_flag_action peer_af_flag_action_list[] = /* Proper action set. */ static int -peer_flag_action_set (struct peer_flag_action *action_list, int size, +peer_flag_action_set (const struct peer_flag_action *action_list, int size, struct peer_flag_action *action, u_int32_t flag) { int i; int found = 0; int reset_in = 0; int reset_out = 0; - struct peer_flag_action *match = NULL; + const struct peer_flag_action *match = NULL; /* Check peer's frag action. */ for (i = 0; i < size; i++) @@ -5137,9 +5146,6 @@ bgp_init (void) /* BGP VTY commands installation. */ bgp_vty_init (); - /* Create BGP server socket. */ - bgp_socket (NULL, bm->port, bm->address); - /* Init zebra. */ bgp_zebra_init (); |