]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_network.c
zebra: zebra-warnings.patch
[mirror_frr.git] / bgpd / bgp_network.c
CommitLineData
718e3744 1/* BGP network related fucntions
2 Copyright (C) 1999 Kunihiro Ishiguro
3
4This file is part of GNU Zebra.
5
6GNU Zebra is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
8Free Software Foundation; either version 2, or (at your option) any
9later version.
10
11GNU Zebra is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Zebra; see the file COPYING. If not, write to the Free
18Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1902111-1307, USA. */
20
21#include <zebra.h>
22
23#include "thread.h"
24#include "sockunion.h"
0df7c91f 25#include "sockopt.h"
718e3744 26#include "memory.h"
27#include "log.h"
28#include "if.h"
29#include "prefix.h"
30#include "command.h"
edd7c245 31#include "privs.h"
0df7c91f 32#include "linklist.h"
fdbc8e77 33#include "network.h"
3f9c7369 34#include "queue.h"
718e3744 35
36#include "bgpd/bgpd.h"
1ff9a340 37#include "bgpd/bgp_open.h"
718e3744 38#include "bgpd/bgp_fsm.h"
39#include "bgpd/bgp_attr.h"
40#include "bgpd/bgp_debug.h"
41#include "bgpd/bgp_network.h"
edd7c245 42
43extern struct zebra_privs_t bgpd_privs;
44
f2345335
DS
45static int bgp_bind(struct peer *);
46
d023aec4
SH
47/* BGP listening socket. */
48struct bgp_listener
49{
50 int fd;
51 union sockunion su;
52 struct thread *thread;
53};
6b0655a2 54
0df7c91f
PJ
55/*
56 * Set MD5 key for the socket, for the given IPv4 peer address.
57 * If the password is NULL or zero-length, the option will be disabled.
58 */
59static int
60bgp_md5_set_socket (int socket, union sockunion *su, const char *password)
61{
62 int ret = -1;
63 int en = ENOSYS;
64
65 assert (socket >= 0);
66
67#if HAVE_DECL_TCP_MD5SIG
68 ret = sockopt_tcp_signature (socket, su, password);
69 en = errno;
70#endif /* HAVE_TCP_MD5SIG */
71
72 if (ret < 0)
16286195 73 zlog_warn ("can't set TCP_MD5SIG option on socket %d: %s", socket, safe_strerror (en));
0df7c91f
PJ
74
75 return ret;
76}
77
78/* Helper for bgp_connect */
79static int
80bgp_md5_set_connect (int socket, union sockunion *su, const char *password)
81{
82 int ret = -1;
83
84#if HAVE_DECL_TCP_MD5SIG
85 if ( bgpd_privs.change (ZPRIVS_RAISE) )
86 {
87 zlog_err ("%s: could not raise privs", __func__);
88 return ret;
89 }
90
91 ret = bgp_md5_set_socket (socket, su, password);
92
93 if (bgpd_privs.change (ZPRIVS_LOWER) )
94 zlog_err ("%s: could not lower privs", __func__);
95#endif /* HAVE_TCP_MD5SIG */
96
97 return ret;
98}
99
100int
101bgp_md5_set (struct peer *peer)
102{
103 struct listnode *node;
d1c21cab
SH
104 int ret = 0;
105 struct bgp_listener *listener;
0df7c91f
PJ
106
107 if ( bgpd_privs.change (ZPRIVS_RAISE) )
108 {
109 zlog_err ("%s: could not raise privs", __func__);
110 return -1;
111 }
112
113 /* Just set the password on the listen socket(s). Outbound connections
114 * are taken care of in bgp_connect() below.
115 */
d1c21cab
SH
116 for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, listener))
117 if (listener->su.sa.sa_family == peer->su.sa.sa_family)
118 {
119 ret = bgp_md5_set_socket (listener->fd, &peer->su, peer->password);
120 break;
121 }
122
0df7c91f
PJ
123 if (bgpd_privs.change (ZPRIVS_LOWER) )
124 zlog_err ("%s: could not lower privs", __func__);
125
d1c21cab 126 return ret;
0df7c91f 127}
3374bef0
VK
128
129/* Update BGP socket send buffer size */
130static void
131bgp_update_sock_send_buffer_size (int fd)
132{
133 int size = BGP_SOCKET_SNDBUF_SIZE;
134 int optval;
135 socklen_t optlen = sizeof(optval);
136
137 if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &optval, &optlen) < 0)
138 {
139 zlog_err("getsockopt of SO_SNDBUF failed %s\n", safe_strerror(errno));
140 return;
141 }
142 if (optval < size)
143 {
144 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) < 0)
145 {
146 zlog_err("Couldn't increase send buffer: %s\n", safe_strerror(errno));
147 }
148 }
149}
150
ef0b0c3e
DL
151static void
152bgp_set_socket_ttl (struct peer *peer, int bgp_sock)
153{
5d804b43 154 char buf[INET_ADDRSTRLEN];
1ff9a340 155 int ret = 0;
5d804b43
PM
156
157 /* In case of peer is EBGP, we should set TTL for this connection. */
158 if (!peer->gtsm_hops && (peer_sort (peer) == BGP_PEER_EBGP))
159 {
160 ret = sockopt_ttl (peer->su.sa.sa_family, bgp_sock, peer->ttl);
161 if (ret)
162 {
163 zlog_err ("%s: Can't set TxTTL on peer (rtrid %s) socket, err = %d",
164 __func__,
165 inet_ntop (AF_INET, &peer->remote_id, buf, sizeof(buf)),
166 errno);
167 }
168 }
169 else if (peer->gtsm_hops)
170 {
171 /* On Linux, setting minttl without setting ttl seems to mess with the
172 outgoing ttl. Therefore setting both.
173 */
174 ret = sockopt_ttl (peer->su.sa.sa_family, bgp_sock, MAXTTL);
175 if (ret)
176 {
177 zlog_err ("%s: Can't set TxTTL on peer (rtrid %s) socket, err = %d",
178 __func__,
179 inet_ntop (AF_INET, &peer->remote_id, buf, sizeof(buf)),
180 errno);
181 }
182 ret = sockopt_minttl (peer->su.sa.sa_family, bgp_sock,
183 MAXTTL + 1 - peer->gtsm_hops);
184 if (ret)
185 {
186 zlog_err ("%s: Can't set MinTTL on peer (rtrid %s) socket, err = %d",
187 __func__,
188 inet_ntop (AF_INET, &peer->remote_id, buf, sizeof(buf)),
189 errno);
190 }
191 }
ef0b0c3e
DL
192}
193
718e3744 194/* Accept bgp connection. */
195static int
196bgp_accept (struct thread *thread)
197{
198 int bgp_sock;
199 int accept_sock;
200 union sockunion su;
5bd58818 201 struct bgp_listener *listener = THREAD_ARG(thread);
718e3744 202 struct peer *peer;
eb821189 203 struct peer *peer1;
718e3744 204 char buf[SU_ADDRSTRLEN];
205
5bd58818 206 /* Register accept thread. */
718e3744 207 accept_sock = THREAD_FD (thread);
718e3744 208 if (accept_sock < 0)
209 {
210 zlog_err ("accept_sock is nevative value %d", accept_sock);
211 return -1;
212 }
5bd58818 213 listener->thread = thread_add_read (master, bgp_accept, listener, accept_sock);
718e3744 214
215 /* Accept client connection. */
216 bgp_sock = sockunion_accept (accept_sock, &su);
217 if (bgp_sock < 0)
218 {
6099b3b5 219 zlog_err ("[Error] BGP socket accept failed (%s)", safe_strerror (errno));
718e3744 220 return -1;
221 }
35398589 222 set_nonblocking (bgp_sock);
718e3744 223
3374bef0
VK
224 /* Set socket send buffer size */
225 bgp_update_sock_send_buffer_size(bgp_sock);
226
718e3744 227 /* Check remote IP address */
5bd58818 228 peer1 = peer_lookup (NULL, &su);
f14e6fdb
DS
229
230 if (! peer1)
231 {
232 peer1 = peer_lookup_dynamic_neighbor (NULL, &su);
233 if (peer1)
234 {
235 /* Dynamic neighbor has been created, let it proceed */
236 peer1->fd = bgp_sock;
237 bgp_fsm_change_status(peer1, Active);
238 BGP_TIMER_OFF(peer1->t_start); /* created in peer_create() */
239
240 if (peer_active (peer1))
241 BGP_EVENT_ADD (peer1, TCP_connection_open);
242
243 return 0;
244 }
245 }
246
1ff9a340 247 if (! peer1)
718e3744 248 {
167d390a 249 if (bgp_debug_neighbor_events(NULL))
718e3744 250 {
f14e6fdb
DS
251 zlog_debug ("[Event] %s connection rejected - not configured"
252 " and not valid for dynamic",
1ff9a340 253 inet_sutop (&su, buf));
718e3744 254 }
255 close (bgp_sock);
256 return -1;
257 }
258
1ff9a340
DS
259 if (CHECK_FLAG(peer1->flags, PEER_FLAG_SHUTDOWN))
260 {
167d390a 261 if (bgp_debug_neighbor_events(peer1))
16286195
DS
262 zlog_debug ("[Event] connection from %s rejected due to admin shutdown",
263 inet_sutop (&su, buf));
1ff9a340
DS
264 close (bgp_sock);
265 return -1;
266 }
267
268 /*
269 * Do not accept incoming connections in Clearing state. This can result
270 * in incorect state transitions - e.g., the connection goes back to
271 * Established and then the Clearing_Completed event is generated. Also,
272 * block incoming connection in Deleted state.
273 */
274 if (peer1->status == Clearing || peer1->status == Deleted)
275 {
276 struct bgp *bgp = peer1->bgp;
277
16286195 278 if (bgp_debug_neighbor_events(peer1))
1ff9a340
DS
279 zlog_debug("[Event] Closing incoming conn for %s (0x%x) state %d",
280 peer1->host, peer1, peer1->status);
281 close (bgp_sock);
282 return -1;
283 }
284
2672319b
DS
285 /* Check that at least one AF is activated for the peer. */
286 if (!peer_active (peer1))
287 {
288 if (bgp_debug_neighbor_events(peer1))
289 zlog_debug ("%s - incoming conn rejected - no AF activated for peer",
290 peer1->host);
291 close (bgp_sock);
292 return -1;
293 }
294
16286195 295 if (bgp_debug_neighbor_events(peer1))
5b6dc0dd
DS
296 zlog_debug ("[Event] BGP connection from host %s fd %d",
297 inet_sutop (&su, buf), bgp_sock);
16286195 298
1ff9a340
DS
299 if (peer1->doppelganger)
300 {
301 /* We have an existing connection. Kill the existing one and run
302 with this one.
303 */
167d390a 304 if (bgp_debug_neighbor_events(peer1))
1ff9a340
DS
305 zlog_debug ("[Event] New active connection from peer %s, Killing"
306 " previous active connection", peer1->host);
307 peer_delete(peer1->doppelganger);
308 }
309
ef0b0c3e 310 bgp_set_socket_ttl (peer1, bgp_sock);
718e3744 311
a80beece 312 peer = peer_create (&su, peer1->conf_if, peer1->bgp, peer1->local_as,
0299c004 313 peer1->as, peer1->as_type, 0, 0);
eb821189 314
1ff9a340
DS
315 peer_xfer_config(peer, peer1);
316 UNSET_FLAG (peer->flags, PEER_FLAG_CONFIG_NODE);
eb821189 317
1ff9a340
DS
318 peer->doppelganger = peer1;
319 peer1->doppelganger = peer;
320 peer->fd = bgp_sock;
f2345335 321 bgp_bind(peer);
1ff9a340
DS
322 bgp_fsm_change_status(peer, Active);
323 BGP_TIMER_OFF(peer->t_start); /* created in peer_create() */
718e3744 324
1ff9a340 325 SET_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER);
718e3744 326
1ff9a340
DS
327 /* Make dummy peer until read Open packet. */
328 if (peer1->status == Established &&
329 CHECK_FLAG (peer1->sflags, PEER_STATUS_NSF_MODE))
330 {
331 /* If we have an existing established connection with graceful restart
332 * capability announced with one or more address families, then drop
333 * existing established connection and move state to connect.
334 */
335 peer1->last_reset = PEER_DOWN_NSF_CLOSE_SESSION;
336 SET_FLAG (peer1->sflags, PEER_STATUS_NSF_WAIT);
337 bgp_event_update(peer1, TCP_connection_closed);
338 }
339
340 if (peer_active (peer))
341 {
342 BGP_EVENT_ADD (peer, TCP_connection_open);
343 }
718e3744 344
345 return 0;
346}
347
348/* BGP socket bind. */
94f2b392 349static int
718e3744 350bgp_bind (struct peer *peer)
351{
352#ifdef SO_BINDTODEVICE
353 int ret;
a80beece 354 char *name;
718e3744 355
a80beece 356 if (! peer->ifname && !peer->conf_if)
718e3744 357 return 0;
358
a80beece
DS
359 name = (peer->conf_if ? peer->conf_if : peer->ifname);
360
98f5163c 361 if ( bgpd_privs.change (ZPRIVS_RAISE) )
362 zlog_err ("bgp_bind: could not raise privs");
363
f2345335
DS
364 ret = setsockopt (peer->fd, SOL_SOCKET, SO_BINDTODEVICE,
365 name, strlen(name));
98f5163c 366
367 if (bgpd_privs.change (ZPRIVS_LOWER) )
368 zlog_err ("bgp_bind: could not lower privs");
369
718e3744 370 if (ret < 0)
371 {
16286195 372 zlog_info ("bind to interface %s failed", name);
718e3744 373 return ret;
374 }
375#endif /* SO_BINDTODEVICE */
376 return 0;
377}
378
1727d2e2
DL
379static int
380bgp_update_address (struct interface *ifp, const union sockunion *dst,
381 union sockunion *addr)
718e3744 382{
1727d2e2 383 struct prefix *p, *sel, *d;
718e3744 384 struct connected *connected;
52dc7ee6 385 struct listnode *node;
1727d2e2
DL
386 int common;
387
388 d = sockunion2hostprefix (dst);
389 sel = NULL;
390 common = -1;
718e3744 391
1eb8ef25 392 for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected))
718e3744 393 {
1727d2e2
DL
394 p = connected->address;
395 if (p->family != d->family)
396 continue;
397 if (prefix_common_bits (p, d) > common)
398 {
399 sel = p;
400 common = prefix_common_bits (sel, d);
401 }
718e3744 402 }
1727d2e2
DL
403
404 prefix_free (d);
405 if (!sel)
406 return 1;
407
408 prefix2sockunion (sel, addr);
409 return 0;
718e3744 410}
411
412/* Update source selection. */
94f2b392 413static void
718e3744 414bgp_update_source (struct peer *peer)
415{
416 struct interface *ifp;
1727d2e2 417 union sockunion addr;
718e3744 418
419 /* Source is specified with interface name. */
420 if (peer->update_if)
421 {
422 ifp = if_lookup_by_name (peer->update_if);
423 if (! ifp)
424 return;
425
1727d2e2 426 if (bgp_update_address (ifp, &peer->su, &addr))
718e3744 427 return;
428
1727d2e2 429 sockunion_bind (peer->fd, &addr, 0, &addr);
718e3744 430 }
431
432 /* Source is specified with IP address. */
433 if (peer->update_source)
eb821189 434 sockunion_bind (peer->fd, peer->update_source, 0, peer->update_source);
718e3744 435}
436
437/* BGP try to connect to the peer. */
438int
439bgp_connect (struct peer *peer)
440{
441 unsigned int ifindex = 0;
442
a80beece
DS
443 if (peer->conf_if && BGP_PEER_SU_UNSPEC(peer))
444 {
445 zlog_debug("Peer address not learnt: Returning from connect");
446 return 0;
447 }
718e3744 448 /* Make socket for the peer. */
eb821189 449 peer->fd = sockunion_socket (&peer->su);
450 if (peer->fd < 0)
718e3744 451 return -1;
452
48fc05fb
VK
453 set_nonblocking (peer->fd);
454
3374bef0
VK
455 /* Set socket send buffer size */
456 bgp_update_sock_send_buffer_size(peer->fd);
457
ef0b0c3e 458 bgp_set_socket_ttl (peer, peer->fd);
718e3744 459
eb821189 460 sockopt_reuseaddr (peer->fd);
461 sockopt_reuseport (peer->fd);
0df7c91f 462
1423c809 463#ifdef IPTOS_PREC_INTERNETCONTROL
5c88f19d
CL
464 if (bgpd_privs.change (ZPRIVS_RAISE))
465 zlog_err ("%s: could not raise privs", __func__);
1423c809
SH
466 if (sockunion_family (&peer->su) == AF_INET)
467 setsockopt_ipv4_tos (peer->fd, IPTOS_PREC_INTERNETCONTROL);
6d0732c8
SH
468# ifdef HAVE_IPV6
469 else if (sockunion_family (&peer->su) == AF_INET6)
470 setsockopt_ipv6_tclass (peer->fd, IPTOS_PREC_INTERNETCONTROL);
471# endif
5c88f19d
CL
472 if (bgpd_privs.change (ZPRIVS_LOWER))
473 zlog_err ("%s: could not lower privs", __func__);
1423c809
SH
474#endif
475
0df7c91f
PJ
476 if (peer->password)
477 bgp_md5_set_connect (peer->fd, &peer->su, peer->password);
718e3744 478
479 /* Bind socket. */
480 bgp_bind (peer);
481
482 /* Update source bind. */
483 bgp_update_source (peer);
484
485#ifdef HAVE_IPV6
a80beece
DS
486 if (peer->conf_if || peer->ifname)
487 ifindex = if_nametoindex (peer->conf_if ? peer->conf_if : peer->ifname);
718e3744 488#endif /* HAVE_IPV6 */
489
16286195
DS
490 if (bgp_debug_neighbor_events(peer))
491 zlog_debug ("%s [Event] Connect start to %s fd %d",
492 peer->host, peer->host, peer->fd);
718e3744 493
494 /* Connect to the remote peer. */
eb821189 495 return sockunion_connect (peer->fd, &peer->su, htons (peer->port), ifindex);
718e3744 496}
497
498/* After TCP connection is established. Get local address and port. */
1ff9a340 499int
718e3744 500bgp_getsockname (struct peer *peer)
501{
502 if (peer->su_local)
503 {
22db9dec 504 sockunion_free (peer->su_local);
718e3744 505 peer->su_local = NULL;
506 }
507
508 if (peer->su_remote)
509 {
22db9dec 510 sockunion_free (peer->su_remote);
718e3744 511 peer->su_remote = NULL;
512 }
513
eb821189 514 peer->su_local = sockunion_getsockname (peer->fd);
1ff9a340 515 if (!peer->su_local) return -1;
eb821189 516 peer->su_remote = sockunion_getpeername (peer->fd);
1ff9a340 517 if (!peer->su_remote) return -1;
718e3744 518
519 bgp_nexthop_set (peer->su_local, peer->su_remote, &peer->nexthop, peer);
1ff9a340
DS
520
521 return 0;
718e3744 522}
523
d023aec4
SH
524
525static int
526bgp_listener (int sock, struct sockaddr *sa, socklen_t salen)
527{
528 struct bgp_listener *listener;
529 int ret, en;
530
531 sockopt_reuseaddr (sock);
532 sockopt_reuseport (sock);
533
5c88f19d
CL
534 if (bgpd_privs.change (ZPRIVS_RAISE))
535 zlog_err ("%s: could not raise privs", __func__);
536
d023aec4
SH
537#ifdef IPTOS_PREC_INTERNETCONTROL
538 if (sa->sa_family == AF_INET)
539 setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL);
6d0732c8
SH
540# ifdef HAVE_IPV6
541 else if (sa->sa_family == AF_INET6)
542 setsockopt_ipv6_tclass (sock, IPTOS_PREC_INTERNETCONTROL);
543# endif
d023aec4
SH
544#endif
545
ca051269 546 sockopt_v6only (sa->sa_family, sock);
d023aec4 547
d023aec4
SH
548 ret = bind (sock, sa, salen);
549 en = errno;
5c88f19d
CL
550 if (bgpd_privs.change (ZPRIVS_LOWER))
551 zlog_err ("%s: could not lower privs", __func__);
d023aec4
SH
552
553 if (ret < 0)
554 {
555 zlog_err ("bind: %s", safe_strerror (en));
556 return ret;
557 }
558
559 ret = listen (sock, 3);
560 if (ret < 0)
561 {
562 zlog_err ("listen: %s", safe_strerror (errno));
563 return ret;
564 }
565
566 listener = XMALLOC (MTYPE_BGP_LISTENER, sizeof(*listener));
567 listener->fd = sock;
568 memcpy(&listener->su, sa, salen);
569 listener->thread = thread_add_read (master, bgp_accept, listener, sock);
570 listnode_add (bm->listen_sockets, listener);
571
572 return 0;
573}
574
718e3744 575/* IPv6 supported version of BGP server socket setup. */
576#if defined (HAVE_IPV6) && ! defined (NRL)
577int
d023aec4 578bgp_socket (unsigned short port, const char *address)
718e3744 579{
718e3744 580 struct addrinfo *ainfo;
581 struct addrinfo *ainfo_save;
d023aec4
SH
582 static const struct addrinfo req = {
583 .ai_family = AF_UNSPEC,
584 .ai_flags = AI_PASSIVE,
585 .ai_socktype = SOCK_STREAM,
586 };
587 int ret, count;
718e3744 588 char port_str[BUFSIZ];
589
90b68769 590 snprintf (port_str, sizeof(port_str), "%d", port);
718e3744 591 port_str[sizeof (port_str) - 1] = '\0';
592
d023aec4 593 ret = getaddrinfo (address, port_str, &req, &ainfo_save);
718e3744 594 if (ret != 0)
595 {
596 zlog_err ("getaddrinfo: %s", gai_strerror (ret));
597 return -1;
598 }
599
d023aec4
SH
600 count = 0;
601 for (ainfo = ainfo_save; ainfo; ainfo = ainfo->ai_next)
718e3744 602 {
d023aec4
SH
603 int sock;
604
718e3744 605 if (ainfo->ai_family != AF_INET && ainfo->ai_family != AF_INET6)
606 continue;
607
608 sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
609 if (sock < 0)
610 {
6099b3b5 611 zlog_err ("socket: %s", safe_strerror (errno));
718e3744 612 continue;
613 }
fa411a21
NH
614
615 /* if we intend to implement ttl-security, this socket needs ttl=255 */
616 sockopt_ttl (ainfo->ai_family, sock, MAXTTL);
617
d023aec4
SH
618 ret = bgp_listener (sock, ainfo->ai_addr, ainfo->ai_addrlen);
619 if (ret == 0)
620 ++count;
621 else
622 close(sock);
718e3744 623 }
718e3744 624 freeaddrinfo (ainfo_save);
d023aec4
SH
625 if (count == 0)
626 {
627 zlog_err ("%s: no usable addresses", __func__);
628 return -1;
629 }
718e3744 630
d023aec4 631 return 0;
718e3744 632}
633#else
634/* Traditional IPv4 only version. */
635int
d023aec4 636bgp_socket (unsigned short port, const char *address)
718e3744 637{
638 int sock;
639 int socklen;
640 struct sockaddr_in sin;
4a1a2716 641 int ret, en;
718e3744 642
643 sock = socket (AF_INET, SOCK_STREAM, 0);
644 if (sock < 0)
645 {
6099b3b5 646 zlog_err ("socket: %s", safe_strerror (errno));
718e3744 647 return sock;
648 }
649
fa411a21
NH
650 /* if we intend to implement ttl-security, this socket needs ttl=255 */
651 sockopt_ttl (AF_INET, sock, MAXTTL);
652
718e3744 653 memset (&sin, 0, sizeof (struct sockaddr_in));
718e3744 654 sin.sin_family = AF_INET;
655 sin.sin_port = htons (port);
656 socklen = sizeof (struct sockaddr_in);
3a02d1f7 657
90b68769 658 if (address && ((ret = inet_aton(address, &sin.sin_addr)) < 1))
3a02d1f7 659 {
90b68769
PJ
660 zlog_err("bgp_socket: could not parse ip address %s: %s",
661 address, safe_strerror (errno));
3a02d1f7
PJ
662 return ret;
663 }
6f0e3f6e 664#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
718e3744 665 sin.sin_len = socklen;
6f0e3f6e 666#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
718e3744 667
d023aec4 668 ret = bgp_listener (sock, (struct sockaddr *) &sin, socklen);
718e3744 669 if (ret < 0)
670 {
718e3744 671 close (sock);
672 return ret;
673 }
718e3744 674 return sock;
675}
676#endif /* HAVE_IPV6 && !NRL */
d023aec4
SH
677
678void
679bgp_close (void)
680{
681 struct listnode *node, *next;
682 struct bgp_listener *listener;
683
1ff9a340
DS
684 if (bm->listen_sockets == NULL)
685 return;
686
d023aec4
SH
687 for (ALL_LIST_ELEMENTS (bm->listen_sockets, node, next, listener))
688 {
689 thread_cancel (listener->thread);
690 close (listener->fd);
691 listnode_delete (bm->listen_sockets, listener);
692 XFREE (MTYPE_BGP_LISTENER, listener);
693 }
694}