]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_msdp_socket.c
Merge pull request #13522 from LabNConsulting/chopps/fix-bgp-test
[mirror_frr.git] / pimd / pim_msdp_socket.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * IP MSDP socket management
4 * Copyright (C) 2016 Cumulus Networks, Inc.
5 */
6
7 #include <zebra.h>
8
9 #include <lib/log.h>
10 #include <lib/network.h>
11 #include <lib/sockunion.h>
12 #include "frrevent.h"
13 #include <lib/vty.h>
14 #include <lib/if.h>
15 #include <lib/vrf.h>
16 #include <lib/lib_errors.h>
17
18 #include "pimd.h"
19 #include "pim_instance.h"
20 #include "pim_sock.h"
21 #include "pim_errors.h"
22
23 #include "pim_msdp.h"
24 #include "pim_msdp_socket.h"
25
26 #include "sockopt.h"
27
28 /* increase socket send buffer size */
29 static void pim_msdp_update_sock_send_buffer_size(int fd)
30 {
31 int size = PIM_MSDP_SOCKET_SNDBUF_SIZE;
32 int optval;
33 socklen_t optlen = sizeof(optval);
34
35 if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &optval, &optlen) < 0) {
36 flog_err_sys(EC_LIB_SOCKET,
37 "getsockopt of SO_SNDBUF failed %s",
38 safe_strerror(errno));
39 return;
40 }
41
42 if (optval < size) {
43 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size))
44 < 0) {
45 flog_err_sys(EC_LIB_SOCKET,
46 "Couldn't increase send buffer: %s",
47 safe_strerror(errno));
48 }
49 }
50 }
51
52 /* passive peer socket accept */
53 static void pim_msdp_sock_accept(struct event *thread)
54 {
55 union sockunion su;
56 struct pim_instance *pim = EVENT_ARG(thread);
57 int accept_sock;
58 int msdp_sock;
59 struct pim_msdp_peer *mp;
60
61 sockunion_init(&su);
62
63 /* re-register accept thread */
64 accept_sock = EVENT_FD(thread);
65 if (accept_sock < 0) {
66 flog_err(EC_LIB_DEVELOPMENT, "accept_sock is negative value %d",
67 accept_sock);
68 return;
69 }
70 pim->msdp.listener.thread = NULL;
71 event_add_read(router->master, pim_msdp_sock_accept, pim, accept_sock,
72 &pim->msdp.listener.thread);
73
74 /* accept client connection. */
75 msdp_sock = sockunion_accept(accept_sock, &su);
76 if (msdp_sock < 0) {
77 flog_err_sys(EC_LIB_SOCKET, "pim_msdp_sock_accept failed (%s)",
78 safe_strerror(errno));
79 return;
80 }
81
82 /* see if have peer config for this */
83 mp = pim_msdp_peer_find(pim, su.sin.sin_addr);
84 if (!mp || !PIM_MSDP_PEER_IS_LISTENER(mp)) {
85 ++pim->msdp.rejected_accepts;
86 if (PIM_DEBUG_MSDP_EVENTS) {
87 flog_err(EC_PIM_MSDP_PACKET,
88 "msdp peer connection refused from %pSU", &su);
89 }
90 close(msdp_sock);
91 return;
92 }
93
94 if (PIM_DEBUG_MSDP_INTERNAL) {
95 zlog_debug("MSDP peer %s accept success%s", mp->key_str,
96 mp->fd >= 0 ? "(dup)" : "");
97 }
98
99 /* if we have an existing connection we need to kill that one
100 * with this one */
101 if (mp->fd >= 0) {
102 if (PIM_DEBUG_MSDP_EVENTS) {
103 zlog_notice(
104 "msdp peer new connection from %pSU stop old connection",
105 &su);
106 }
107 pim_msdp_peer_stop_tcp_conn(mp, true /* chg_state */);
108 }
109 mp->fd = msdp_sock;
110 set_nonblocking(mp->fd);
111 pim_msdp_update_sock_send_buffer_size(mp->fd);
112 pim_msdp_peer_established(mp);
113 }
114
115 /* global listener for the MSDP well know TCP port */
116 int pim_msdp_sock_listen(struct pim_instance *pim)
117 {
118 int sock;
119 int socklen;
120 struct sockaddr_in sin;
121 int rc;
122 struct pim_msdp_listener *listener = &pim->msdp.listener;
123
124 if (pim->msdp.flags & PIM_MSDPF_LISTENER) {
125 /* listener already setup */
126 return 0;
127 }
128
129 sock = socket(AF_INET, SOCK_STREAM, 0);
130 if (sock < 0) {
131 flog_err_sys(EC_LIB_SOCKET, "socket: %s", safe_strerror(errno));
132 return sock;
133 }
134
135 memset(&sin, 0, sizeof(struct sockaddr_in));
136 sin.sin_family = AF_INET;
137 sin.sin_port = htons(PIM_MSDP_TCP_PORT);
138 socklen = sizeof(struct sockaddr_in);
139 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
140 sin.sin_len = socklen;
141 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
142
143 sockopt_reuseaddr(sock);
144 sockopt_reuseport(sock);
145
146 if (pim->vrf->vrf_id != VRF_DEFAULT) {
147 struct interface *ifp =
148 if_lookup_by_name(pim->vrf->name, pim->vrf->vrf_id);
149 if (!ifp) {
150 flog_err(EC_LIB_INTERFACE,
151 "%s: Unable to lookup vrf interface: %s",
152 __func__, pim->vrf->name);
153 close(sock);
154 return -1;
155 }
156 if (pim_socket_bind(sock, ifp)) {
157 flog_err_sys(EC_LIB_SOCKET,
158 "%s: Unable to bind to socket: %s",
159 __func__, safe_strerror(errno));
160 close(sock);
161 return -1;
162 }
163 }
164
165 frr_with_privs(&pimd_privs) {
166 /* bind to well known TCP port */
167 rc = bind(sock, (struct sockaddr *)&sin, socklen);
168 }
169
170 if (rc < 0) {
171 flog_err_sys(EC_LIB_SOCKET,
172 "pim_msdp_socket bind to port %d: %s",
173 ntohs(sin.sin_port), safe_strerror(errno));
174 close(sock);
175 return rc;
176 }
177
178 rc = listen(sock, 3 /* backlog */);
179 if (rc < 0) {
180 flog_err_sys(EC_LIB_SOCKET, "pim_msdp_socket listen: %s",
181 safe_strerror(errno));
182 close(sock);
183 return rc;
184 }
185
186 /* Set socket DSCP byte */
187 if (setsockopt_ipv4_tos(sock, IPTOS_PREC_INTERNETCONTROL)) {
188 zlog_warn("can't set sockopt IP_TOS to MSDP socket %d: %s",
189 sock, safe_strerror(errno));
190 }
191
192 /* add accept thread */
193 listener->fd = sock;
194 memcpy(&listener->su, &sin, socklen);
195 event_add_read(pim->msdp.master, pim_msdp_sock_accept, pim, sock,
196 &listener->thread);
197
198 pim->msdp.flags |= PIM_MSDPF_LISTENER;
199 return 0;
200 }
201
202 /* active peer socket setup */
203 int pim_msdp_sock_connect(struct pim_msdp_peer *mp)
204 {
205 int rc;
206
207 if (PIM_DEBUG_MSDP_INTERNAL) {
208 zlog_debug("MSDP peer %s attempt connect%s", mp->key_str,
209 mp->fd < 0 ? "" : "(dup)");
210 }
211
212 /* if we have an existing connection we need to kill that one
213 * with this one */
214 if (mp->fd >= 0) {
215 if (PIM_DEBUG_MSDP_EVENTS) {
216 zlog_notice(
217 "msdp duplicate connect to %s nuke old connection",
218 mp->key_str);
219 }
220 pim_msdp_peer_stop_tcp_conn(mp, false /* chg_state */);
221 }
222
223 /* Make socket for the peer. */
224 mp->fd = sockunion_socket(&mp->su_peer);
225 if (mp->fd < 0) {
226 flog_err_sys(EC_LIB_SOCKET,
227 "pim_msdp_socket socket failure: %s",
228 safe_strerror(errno));
229 return -1;
230 }
231
232 if (mp->pim->vrf->vrf_id != VRF_DEFAULT) {
233 struct interface *ifp = if_lookup_by_name(mp->pim->vrf->name,
234 mp->pim->vrf->vrf_id);
235 if (!ifp) {
236 flog_err(EC_LIB_INTERFACE,
237 "%s: Unable to lookup vrf interface: %s",
238 __func__, mp->pim->vrf->name);
239 return -1;
240 }
241 if (pim_socket_bind(mp->fd, ifp)) {
242 flog_err_sys(EC_LIB_SOCKET,
243 "%s: Unable to bind to socket: %s",
244 __func__, safe_strerror(errno));
245 close(mp->fd);
246 mp->fd = -1;
247 return -1;
248 }
249 }
250
251 set_nonblocking(mp->fd);
252
253 /* Set socket send buffer size */
254 pim_msdp_update_sock_send_buffer_size(mp->fd);
255 sockopt_reuseaddr(mp->fd);
256 sockopt_reuseport(mp->fd);
257
258 /* source bind */
259 rc = sockunion_bind(mp->fd, &mp->su_local, 0, &mp->su_local);
260 if (rc < 0) {
261 flog_err_sys(EC_LIB_SOCKET,
262 "pim_msdp_socket connect bind failure: %s",
263 safe_strerror(errno));
264 close(mp->fd);
265 mp->fd = -1;
266 return rc;
267 }
268
269 /* Set socket DSCP byte */
270 if (setsockopt_ipv4_tos(mp->fd, IPTOS_PREC_INTERNETCONTROL)) {
271 zlog_warn("can't set sockopt IP_TOS to MSDP socket %d: %s",
272 mp->fd, safe_strerror(errno));
273 }
274
275 /* Connect to the remote mp. */
276 return (sockunion_connect(mp->fd, &mp->su_peer,
277 htons(PIM_MSDP_TCP_PORT), 0));
278 }