]> 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
16 * along with this program; see the file COPYING; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
18 * MA 02110-1301 USA
19 */
20
21 #include <zebra.h>
22
23 #include <lib/log.h>
24 #include <lib/network.h>
25 #include <lib/sockunion.h>
26 #include <lib/thread.h>
27 #include <lib/vty.h>
28
29 #include "pimd.h"
30
31 #include "pim_msdp.h"
32 #include "pim_msdp_socket.h"
33
34 /* increase socket send buffer size */
35 static void pim_msdp_update_sock_send_buffer_size(int fd)
36 {
37 int size = PIM_MSDP_SOCKET_SNDBUF_SIZE;
38 int optval;
39 socklen_t optlen = sizeof(optval);
40
41 if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &optval, &optlen) < 0) {
42 zlog_err("getsockopt of SO_SNDBUF failed %s\n",
43 safe_strerror(errno));
44 return;
45 }
46
47 if (optval < size) {
48 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size))
49 < 0) {
50 zlog_err("Couldn't increase send buffer: %s\n",
51 safe_strerror(errno));
52 }
53 }
54 }
55
56 /* passive peer socket accept */
57 static int pim_msdp_sock_accept(struct thread *thread)
58 {
59 union sockunion su;
60 struct pim_msdp_listener *listener = THREAD_ARG(thread);
61 int accept_sock;
62 int msdp_sock;
63 struct pim_msdp_peer *mp;
64 char buf[SU_ADDRSTRLEN];
65
66 sockunion_init(&su);
67
68 /* re-register accept thread */
69 accept_sock = THREAD_FD(thread);
70 if (accept_sock < 0) {
71 zlog_err("accept_sock is negative value %d", accept_sock);
72 return -1;
73 }
74 listener->thread = thread_add_read(master, pim_msdp_sock_accept,
75 listener, accept_sock);
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 = thread_add_read(msdp->master, pim_msdp_sock_accept,
181 listener, sock);
182
183 msdp->flags |= PIM_MSDPF_LISTENER;
184 return 0;
185 }
186
187 /* active peer socket setup */
188 int pim_msdp_sock_connect(struct pim_msdp_peer *mp)
189 {
190 int rc;
191
192 if (PIM_DEBUG_MSDP_INTERNAL) {
193 zlog_debug("MSDP peer %s attempt connect%s", mp->key_str,
194 mp->fd < 0 ? "" : "(dup)");
195 }
196
197 /* if we have an existing connection we need to kill that one
198 * with this one */
199 if (mp->fd >= 0) {
200 if (PIM_DEBUG_MSDP_EVENTS) {
201 zlog_err(
202 "msdp duplicate connect to %s nuke old connection",
203 mp->key_str);
204 }
205 pim_msdp_peer_stop_tcp_conn(mp, false /* chg_state */);
206 }
207
208 /* Make socket for the peer. */
209 mp->fd = sockunion_socket(&mp->su_peer);
210 if (mp->fd < 0) {
211 zlog_err("pim_msdp_socket socket failure: %s",
212 safe_strerror(errno));
213 return -1;
214 }
215
216 set_nonblocking(mp->fd);
217
218 /* Set socket send buffer size */
219 pim_msdp_update_sock_send_buffer_size(mp->fd);
220 sockopt_reuseaddr(mp->fd);
221 sockopt_reuseport(mp->fd);
222
223 /* source bind */
224 rc = sockunion_bind(mp->fd, &mp->su_local, 0, &mp->su_local);
225 if (rc < 0) {
226 zlog_err("pim_msdp_socket connect bind failure: %s",
227 safe_strerror(errno));
228 close(mp->fd);
229 mp->fd = -1;
230 return rc;
231 }
232
233 /* Connect to the remote mp. */
234 return (sockunion_connect(mp->fd, &mp->su_peer,
235 htons(PIM_MSDP_TCP_PORT), 0));
236 }