]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_msdp_socket.c
*: reindent
[mirror_frr.git] / pimd / pim_msdp_socket.c
1 /*
2 * IP MSDP socket management
3 * Copyright (C) 2016 Cumulus Networks, Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #include <zebra.h>
21
22 #include <lib/log.h>
23 #include <lib/network.h>
24 #include <lib/sockunion.h>
25 #include <lib/thread.h>
26 #include <lib/vty.h>
27
28 #include "pimd.h"
29
30 #include "pim_msdp.h"
31 #include "pim_msdp_socket.h"
32
33 /* increase socket send buffer size */
34 static void pim_msdp_update_sock_send_buffer_size(int fd)
35 {
36 int size = PIM_MSDP_SOCKET_SNDBUF_SIZE;
37 int optval;
38 socklen_t optlen = sizeof(optval);
39
40 if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &optval, &optlen) < 0) {
41 zlog_err("getsockopt of SO_SNDBUF failed %s\n",
42 safe_strerror(errno));
43 return;
44 }
45
46 if (optval < size) {
47 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size))
48 < 0) {
49 zlog_err("Couldn't increase send buffer: %s\n",
50 safe_strerror(errno));
51 }
52 }
53 }
54
55 /* passive peer socket accept */
56 static int pim_msdp_sock_accept(struct thread *thread)
57 {
58 union sockunion su;
59 struct pim_msdp_listener *listener = THREAD_ARG(thread);
60 int accept_sock;
61 int msdp_sock;
62 struct pim_msdp_peer *mp;
63 char buf[SU_ADDRSTRLEN];
64
65 sockunion_init(&su);
66
67 /* re-register accept thread */
68 accept_sock = THREAD_FD(thread);
69 if (accept_sock < 0) {
70 zlog_err("accept_sock is negative value %d", accept_sock);
71 return -1;
72 }
73 listener->thread = NULL;
74 thread_add_read(master, pim_msdp_sock_accept, listener, accept_sock,
75 &listener->thread);
76
77 /* accept client connection. */
78 msdp_sock = sockunion_accept(accept_sock, &su);
79 if (msdp_sock < 0) {
80 zlog_err("pim_msdp_sock_accept failed (%s)",
81 safe_strerror(errno));
82 return -1;
83 }
84
85 /* see if have peer config for this */
86 mp = pim_msdp_peer_find(su.sin.sin_addr);
87 if (!mp || !PIM_MSDP_PEER_IS_LISTENER(mp)) {
88 ++msdp->rejected_accepts;
89 if (PIM_DEBUG_MSDP_EVENTS) {
90 zlog_err("msdp peer connection refused from %s",
91 sockunion2str(&su, buf, SU_ADDRSTRLEN));
92 }
93 close(msdp_sock);
94 return -1;
95 }
96
97 if (PIM_DEBUG_MSDP_INTERNAL) {
98 zlog_debug("MSDP peer %s accept success%s", mp->key_str,
99 mp->fd >= 0 ? "(dup)" : "");
100 }
101
102 /* if we have an existing connection we need to kill that one
103 * with this one */
104 if (mp->fd >= 0) {
105 if (PIM_DEBUG_MSDP_EVENTS) {
106 zlog_err(
107 "msdp peer new connection from %s stop old connection",
108 sockunion2str(&su, buf, SU_ADDRSTRLEN));
109 }
110 pim_msdp_peer_stop_tcp_conn(mp, true /* chg_state */);
111 }
112 mp->fd = msdp_sock;
113 set_nonblocking(mp->fd);
114 pim_msdp_update_sock_send_buffer_size(mp->fd);
115 pim_msdp_peer_established(mp);
116 return 0;
117 }
118
119 /* global listener for the MSDP well know TCP port */
120 int pim_msdp_sock_listen(void)
121 {
122 int sock;
123 int socklen;
124 struct sockaddr_in sin;
125 int rc;
126 struct pim_msdp_listener *listener = &msdp->listener;
127
128 if (msdp->flags & PIM_MSDPF_LISTENER) {
129 /* listener already setup */
130 return 0;
131 }
132
133 sock = socket(AF_INET, SOCK_STREAM, 0);
134 if (sock < 0) {
135 zlog_err("socket: %s", safe_strerror(errno));
136 return sock;
137 }
138
139 memset(&sin, 0, sizeof(struct sockaddr_in));
140 sin.sin_family = AF_INET;
141 sin.sin_port = htons(PIM_MSDP_TCP_PORT);
142 socklen = sizeof(struct sockaddr_in);
143 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
144 sin.sin_len = socklen;
145 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
146
147 sockopt_reuseaddr(sock);
148 sockopt_reuseport(sock);
149
150 if (pimd_privs.change(ZPRIVS_RAISE)) {
151 zlog_err("pim_msdp_socket: could not raise privs, %s",
152 safe_strerror(errno));
153 }
154
155 /* bind to well known TCP port */
156 rc = bind(sock, (struct sockaddr *)&sin, socklen);
157
158 if (pimd_privs.change(ZPRIVS_LOWER)) {
159 zlog_err("pim_msdp_socket: could not lower privs, %s",
160 safe_strerror(errno));
161 }
162
163 if (rc < 0) {
164 zlog_err("pim_msdp_socket bind to port %d: %s",
165 ntohs(sin.sin_port), safe_strerror(errno));
166 close(sock);
167 return rc;
168 }
169
170 rc = listen(sock, 3 /* backlog */);
171 if (rc < 0) {
172 zlog_err("pim_msdp_socket listen: %s", safe_strerror(errno));
173 close(sock);
174 return rc;
175 }
176
177 /* add accept thread */
178 listener->fd = sock;
179 memcpy(&listener->su, &sin, socklen);
180 listener->thread = NULL;
181 thread_add_read(msdp->master, pim_msdp_sock_accept, listener, sock,
182 &listener->thread);
183
184 msdp->flags |= PIM_MSDPF_LISTENER;
185 return 0;
186 }
187
188 /* active peer socket setup */
189 int pim_msdp_sock_connect(struct pim_msdp_peer *mp)
190 {
191 int rc;
192
193 if (PIM_DEBUG_MSDP_INTERNAL) {
194 zlog_debug("MSDP peer %s attempt connect%s", mp->key_str,
195 mp->fd < 0 ? "" : "(dup)");
196 }
197
198 /* if we have an existing connection we need to kill that one
199 * with this one */
200 if (mp->fd >= 0) {
201 if (PIM_DEBUG_MSDP_EVENTS) {
202 zlog_err(
203 "msdp duplicate connect to %s nuke old connection",
204 mp->key_str);
205 }
206 pim_msdp_peer_stop_tcp_conn(mp, false /* chg_state */);
207 }
208
209 /* Make socket for the peer. */
210 mp->fd = sockunion_socket(&mp->su_peer);
211 if (mp->fd < 0) {
212 zlog_err("pim_msdp_socket socket failure: %s",
213 safe_strerror(errno));
214 return -1;
215 }
216
217 set_nonblocking(mp->fd);
218
219 /* Set socket send buffer size */
220 pim_msdp_update_sock_send_buffer_size(mp->fd);
221 sockopt_reuseaddr(mp->fd);
222 sockopt_reuseport(mp->fd);
223
224 /* source bind */
225 rc = sockunion_bind(mp->fd, &mp->su_local, 0, &mp->su_local);
226 if (rc < 0) {
227 zlog_err("pim_msdp_socket connect bind failure: %s",
228 safe_strerror(errno));
229 close(mp->fd);
230 mp->fd = -1;
231 return rc;
232 }
233
234 /* Connect to the remote mp. */
235 return (sockunion_connect(mp->fd, &mp->su_peer,
236 htons(PIM_MSDP_TCP_PORT), 0));
237 }