summaryrefslogtreecommitdiff
path: root/bgpd
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd')
-rw-r--r--bgpd/bgp_aspath.c40
-rw-r--r--bgpd/bgp_aspath.h2
-rw-r--r--bgpd/bgp_attr.c11
-rw-r--r--bgpd/bgp_network.c190
-rw-r--r--bgpd/bgp_network.h3
-rw-r--r--bgpd/bgp_vty.c5
-rw-r--r--bgpd/bgpd.c22
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 ();