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