]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_network.c
Initial revision
[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"
25#include "memory.h"
26#include "log.h"
27#include "if.h"
28#include "prefix.h"
29#include "command.h"
30
31#include "bgpd/bgpd.h"
32#include "bgpd/bgp_fsm.h"
33#include "bgpd/bgp_attr.h"
34#include "bgpd/bgp_debug.h"
35#include "bgpd/bgp_network.h"
36\f
37/* Accept bgp connection. */
38static int
39bgp_accept (struct thread *thread)
40{
41 int bgp_sock;
42 int accept_sock;
43 union sockunion su;
44 struct peer *peer;
45 struct peer *peer1;
46 struct bgp *bgp;
47 char buf[SU_ADDRSTRLEN];
48
49 /* Regiser accept thread. */
50 accept_sock = THREAD_FD (thread);
51 bgp = THREAD_ARG (thread);
52
53 if (accept_sock < 0)
54 {
55 zlog_err ("accept_sock is nevative value %d", accept_sock);
56 return -1;
57 }
58 thread_add_read (master, bgp_accept, bgp, accept_sock);
59
60 /* Accept client connection. */
61 bgp_sock = sockunion_accept (accept_sock, &su);
62 if (bgp_sock < 0)
63 {
64 zlog_err ("[Error] BGP socket accept failed (%s)", strerror (errno));
65 return -1;
66 }
67
68 if (BGP_DEBUG (events, EVENTS))
69 zlog_info ("[Event] BGP connection from host %s", inet_sutop (&su, buf));
70
71 /* Check remote IP address */
72 peer1 = peer_lookup (bgp, &su);
73 if (! peer1 || peer1->status == Idle)
74 {
75 if (BGP_DEBUG (events, EVENTS))
76 {
77 if (! peer1)
78 zlog_info ("[Event] BGP connection IP address %s is not configured",
79 inet_sutop (&su, buf));
80 else
81 zlog_info ("[Event] BGP connection IP address %s is Idle state",
82 inet_sutop (&su, buf));
83 }
84 close (bgp_sock);
85 return -1;
86 }
87
88 /* In case of peer is EBGP, we should set TTL for this connection. */
89 if (peer_sort (peer1) == BGP_PEER_EBGP)
90 sockopt_ttl (peer1->su.sa.sa_family, bgp_sock, peer1->ttl);
91
92 if (! bgp)
93 bgp = peer1->bgp;
94
95 /* Make dummy peer until read Open packet. */
96 if (BGP_DEBUG (events, EVENTS))
97 zlog_info ("[Event] Make dummy peer structure until read Open packet");
98
99 {
100 char buf[SU_ADDRSTRLEN + 1];
101
102 peer = peer_create_accept (bgp);
103 SET_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER);
104 peer->su = su;
105 peer->fd = bgp_sock;
106 peer->status = Active;
107 peer->local_id = peer1->local_id;
108
109 /* Make peer's address string. */
110 sockunion2str (&su, buf, SU_ADDRSTRLEN);
111 peer->host = strdup (buf);
112 }
113
114 BGP_EVENT_ADD (peer, TCP_connection_open);
115
116 return 0;
117}
118
119/* BGP socket bind. */
120int
121bgp_bind (struct peer *peer)
122{
123#ifdef SO_BINDTODEVICE
124 int ret;
125 struct ifreq ifreq;
126
127 if (! peer->ifname)
128 return 0;
129
130 strncpy ((char *)&ifreq.ifr_name, peer->ifname, sizeof (ifreq.ifr_name));
131
132 ret = setsockopt (peer->fd, SOL_SOCKET, SO_BINDTODEVICE,
133 &ifreq, sizeof (ifreq));
134 if (ret < 0)
135 {
136 zlog (peer->log, LOG_INFO, "bind to interface %s failed", peer->ifname);
137 return ret;
138 }
139#endif /* SO_BINDTODEVICE */
140 return 0;
141}
142
143int
144bgp_bind_address (int sock, struct in_addr *addr)
145{
146 int ret;
147 struct sockaddr_in local;
148
149 memset (&local, 0, sizeof (struct sockaddr_in));
150 local.sin_family = AF_INET;
151#ifdef HAVE_SIN_LEN
152 local.sin_len = sizeof(struct sockaddr_in);
153#endif /* HAVE_SIN_LEN */
154 memcpy (&local.sin_addr, addr, sizeof (struct in_addr));
155
156 ret = bind (sock, (struct sockaddr *)&local, sizeof (struct sockaddr_in));
157 if (ret < 0)
158 ;
159 return 0;
160}
161
162struct in_addr *
163bgp_update_address (struct interface *ifp)
164{
165 struct prefix_ipv4 *p;
166 struct connected *connected;
167 listnode node;
168
169 for (node = listhead (ifp->connected); node; nextnode (node))
170 {
171 connected = getdata (node);
172
173 p = (struct prefix_ipv4 *) connected->address;
174
175 if (p->family == AF_INET)
176 return &p->prefix;
177 }
178 return NULL;
179}
180
181/* Update source selection. */
182void
183bgp_update_source (struct peer *peer)
184{
185 struct interface *ifp;
186 struct in_addr *addr;
187
188 /* Source is specified with interface name. */
189 if (peer->update_if)
190 {
191 ifp = if_lookup_by_name (peer->update_if);
192 if (! ifp)
193 return;
194
195 addr = bgp_update_address (ifp);
196 if (! addr)
197 return;
198
199 bgp_bind_address (peer->fd, addr);
200 }
201
202 /* Source is specified with IP address. */
203 if (peer->update_source)
204 sockunion_bind (peer->fd, peer->update_source, 0, peer->update_source);
205}
206
207/* BGP try to connect to the peer. */
208int
209bgp_connect (struct peer *peer)
210{
211 unsigned int ifindex = 0;
212
213 /* Make socket for the peer. */
214 peer->fd = sockunion_socket (&peer->su);
215 if (peer->fd < 0)
216 return -1;
217
218 /* If we can get socket for the peer, adjest TTL and make connection. */
219 if (peer_sort (peer) == BGP_PEER_EBGP)
220 sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl);
221
222 sockopt_reuseaddr (peer->fd);
223 sockopt_reuseport (peer->fd);
224
225 /* Bind socket. */
226 bgp_bind (peer);
227
228 /* Update source bind. */
229 bgp_update_source (peer);
230
231#ifdef HAVE_IPV6
232 if (peer->ifname)
233 ifindex = if_nametoindex (peer->ifname);
234#endif /* HAVE_IPV6 */
235
236 if (BGP_DEBUG (events, EVENTS))
237 plog_info (peer->log, "%s [Event] Connect start to %s fd %d",
238 peer->host, peer->host, peer->fd);
239
240 /* Connect to the remote peer. */
241 return sockunion_connect (peer->fd, &peer->su, htons (peer->port), ifindex);
242}
243
244/* After TCP connection is established. Get local address and port. */
245void
246bgp_getsockname (struct peer *peer)
247{
248 if (peer->su_local)
249 {
250 XFREE (MTYPE_TMP, peer->su_local);
251 peer->su_local = NULL;
252 }
253
254 if (peer->su_remote)
255 {
256 XFREE (MTYPE_TMP, peer->su_remote);
257 peer->su_remote = NULL;
258 }
259
260 peer->su_local = sockunion_getsockname (peer->fd);
261 peer->su_remote = sockunion_getpeername (peer->fd);
262
263 bgp_nexthop_set (peer->su_local, peer->su_remote, &peer->nexthop, peer);
264}
265
266/* IPv6 supported version of BGP server socket setup. */
267#if defined (HAVE_IPV6) && ! defined (NRL)
268int
269bgp_socket (struct bgp *bgp, unsigned short port)
270{
271 int ret;
272 struct addrinfo req;
273 struct addrinfo *ainfo;
274 struct addrinfo *ainfo_save;
275 int sock = 0;
276 char port_str[BUFSIZ];
277
278 memset (&req, 0, sizeof (struct addrinfo));
279
280 req.ai_flags = AI_PASSIVE;
281 req.ai_family = AF_UNSPEC;
282 req.ai_socktype = SOCK_STREAM;
283 sprintf (port_str, "%d", port);
284 port_str[sizeof (port_str) - 1] = '\0';
285
286 ret = getaddrinfo (NULL, port_str, &req, &ainfo);
287 if (ret != 0)
288 {
289 zlog_err ("getaddrinfo: %s", gai_strerror (ret));
290 return -1;
291 }
292
293 ainfo_save = ainfo;
294
295 do
296 {
297 if (ainfo->ai_family != AF_INET && ainfo->ai_family != AF_INET6)
298 continue;
299
300 sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
301 if (sock < 0)
302 {
303 zlog_err ("socket: %s", strerror (errno));
304 continue;
305 }
306
307 sockopt_reuseaddr (sock);
308 sockopt_reuseport (sock);
309
310 ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen);
311 if (ret < 0)
312 {
313 zlog_err ("bind: %s", strerror (errno));
314 close (sock);
315 continue;
316 }
317 ret = listen (sock, 3);
318 if (ret < 0)
319 {
320 zlog_err ("listen: %s", strerror (errno));
321 close (sock);
322 continue;
323 }
324
325 thread_add_read (master, bgp_accept, bgp, sock);
326 }
327 while ((ainfo = ainfo->ai_next) != NULL);
328
329 freeaddrinfo (ainfo_save);
330
331 return sock;
332}
333#else
334/* Traditional IPv4 only version. */
335int
336bgp_socket (struct bgp *bgp, unsigned short port)
337{
338 int sock;
339 int socklen;
340 struct sockaddr_in sin;
341 int ret;
342
343 sock = socket (AF_INET, SOCK_STREAM, 0);
344 if (sock < 0)
345 {
346 zlog_err ("socket: %s", strerror (errno));
347 return sock;
348 }
349
350 sockopt_reuseaddr (sock);
351 sockopt_reuseport (sock);
352
353 memset (&sin, 0, sizeof (struct sockaddr_in));
354
355 sin.sin_family = AF_INET;
356 sin.sin_port = htons (port);
357 socklen = sizeof (struct sockaddr_in);
358#ifdef HAVE_SIN_LEN
359 sin.sin_len = socklen;
360#endif /* HAVE_SIN_LEN */
361
362 ret = bind (sock, (struct sockaddr *) &sin, socklen);
363 if (ret < 0)
364 {
365 zlog_err ("bind: %s", strerror (errno));
366 close (sock);
367 return ret;
368 }
369 ret = listen (sock, 3);
370 if (ret < 0)
371 {
372 zlog_err ("listen: %s", strerror (errno));
373 close (sock);
374 return ret;
375 }
376
377 thread_add_read (bm->master, bgp_accept, bgp, sock);
378
379 return sock;
380}
381#endif /* HAVE_IPV6 && !NRL */