]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_msdp_socket.c
Merge pull request #13649 from donaldsharp/unlock_the_node_or_else
[mirror_frr.git] / pimd / pim_msdp_socket.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
2a333e0f 2/*
3 * IP MSDP socket management
4 * Copyright (C) 2016 Cumulus Networks, Inc.
2a333e0f 5 */
6
7#include <zebra.h>
8
9#include <lib/log.h>
10#include <lib/network.h>
2a333e0f 11#include <lib/sockunion.h>
24a58196 12#include "frrevent.h"
3c72d654 13#include <lib/vty.h>
62fde409
DS
14#include <lib/if.h>
15#include <lib/vrf.h>
3613d898 16#include <lib/lib_errors.h>
2a333e0f 17
18#include "pimd.h"
993e3d8e 19#include "pim_instance.h"
62fde409 20#include "pim_sock.h"
d9ff4302 21#include "pim_errors.h"
2a333e0f 22
23#include "pim_msdp.h"
24#include "pim_msdp_socket.h"
25
b069b568
AMR
26#include "sockopt.h"
27
2a333e0f 28/* increase socket send buffer size */
d62a17ae 29static void pim_msdp_update_sock_send_buffer_size(int fd)
2a333e0f 30{
d62a17ae 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) {
450971aa 36 flog_err_sys(EC_LIB_SOCKET,
1d5453d6 37 "getsockopt of SO_SNDBUF failed %s",
09c866e3 38 safe_strerror(errno));
d62a17ae 39 return;
40 }
41
42 if (optval < size) {
43 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size))
44 < 0) {
450971aa 45 flog_err_sys(EC_LIB_SOCKET,
1d5453d6 46 "Couldn't increase send buffer: %s",
09c866e3 47 safe_strerror(errno));
d62a17ae 48 }
49 }
2a333e0f 50}
51
52/* passive peer socket accept */
e6685141 53static void pim_msdp_sock_accept(struct event *thread)
2a333e0f 54{
d62a17ae 55 union sockunion su;
e16d030c 56 struct pim_instance *pim = EVENT_ARG(thread);
d62a17ae 57 int accept_sock;
58 int msdp_sock;
59 struct pim_msdp_peer *mp;
d62a17ae 60
61 sockunion_init(&su);
62
63 /* re-register accept thread */
e16d030c 64 accept_sock = EVENT_FD(thread);
d62a17ae 65 if (accept_sock < 0) {
1c50c1c0
QY
66 flog_err(EC_LIB_DEVELOPMENT, "accept_sock is negative value %d",
67 accept_sock);
cc9f21da 68 return;
d62a17ae 69 }
472ad383 70 pim->msdp.listener.thread = NULL;
907a2395
DS
71 event_add_read(router->master, pim_msdp_sock_accept, pim, accept_sock,
72 &pim->msdp.listener.thread);
d62a17ae 73
74 /* accept client connection. */
75 msdp_sock = sockunion_accept(accept_sock, &su);
76 if (msdp_sock < 0) {
450971aa 77 flog_err_sys(EC_LIB_SOCKET, "pim_msdp_sock_accept failed (%s)",
09c866e3 78 safe_strerror(errno));
cc9f21da 79 return;
d62a17ae 80 }
81
82 /* see if have peer config for this */
472ad383 83 mp = pim_msdp_peer_find(pim, su.sin.sin_addr);
d62a17ae 84 if (!mp || !PIM_MSDP_PEER_IS_LISTENER(mp)) {
472ad383 85 ++pim->msdp.rejected_accepts;
d62a17ae 86 if (PIM_DEBUG_MSDP_EVENTS) {
298004a1 87 flog_err(EC_PIM_MSDP_PACKET,
6b73800b 88 "msdp peer connection refused from %pSU", &su);
d62a17ae 89 }
90 close(msdp_sock);
cc9f21da 91 return;
d62a17ae 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) {
3613d898 103 zlog_notice(
6b73800b
DS
104 "msdp peer new connection from %pSU stop old connection",
105 &su);
d62a17ae 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);
2a333e0f 113}
114
115/* global listener for the MSDP well know TCP port */
472ad383 116int pim_msdp_sock_listen(struct pim_instance *pim)
2a333e0f 117{
d62a17ae 118 int sock;
119 int socklen;
120 struct sockaddr_in sin;
121 int rc;
472ad383 122 struct pim_msdp_listener *listener = &pim->msdp.listener;
d62a17ae 123
472ad383 124 if (pim->msdp.flags & PIM_MSDPF_LISTENER) {
d62a17ae 125 /* listener already setup */
126 return 0;
127 }
128
129 sock = socket(AF_INET, SOCK_STREAM, 0);
130 if (sock < 0) {
1c50c1c0 131 flog_err_sys(EC_LIB_SOCKET, "socket: %s", safe_strerror(errno));
d62a17ae 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);
2a333e0f 139#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
d62a17ae 140 sin.sin_len = socklen;
2a333e0f 141#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
142
d62a17ae 143 sockopt_reuseaddr(sock);
144 sockopt_reuseport(sock);
145
d3cc1e45 146 if (pim->vrf->vrf_id != VRF_DEFAULT) {
2267994c 147 struct interface *ifp =
d3cc1e45 148 if_lookup_by_name(pim->vrf->name, pim->vrf->vrf_id);
449a3f5b 149 if (!ifp) {
450971aa 150 flog_err(EC_LIB_INTERFACE,
1c50c1c0 151 "%s: Unable to lookup vrf interface: %s",
5e81f5dd 152 __func__, pim->vrf->name);
e691f179
DS
153 close(sock);
154 return -1;
155 }
156 if (pim_socket_bind(sock, ifp)) {
450971aa 157 flog_err_sys(EC_LIB_SOCKET,
09c866e3 158 "%s: Unable to bind to socket: %s",
5e81f5dd 159 __func__, safe_strerror(errno));
e691f179 160 close(sock);
449a3f5b
DS
161 return -1;
162 }
2267994c
DS
163 }
164
0cf6db21 165 frr_with_privs(&pimd_privs) {
6bb30c2c
DL
166 /* bind to well known TCP port */
167 rc = bind(sock, (struct sockaddr *)&sin, socklen);
d62a17ae 168 }
169
170 if (rc < 0) {
450971aa 171 flog_err_sys(EC_LIB_SOCKET,
09c866e3
QY
172 "pim_msdp_socket bind to port %d: %s",
173 ntohs(sin.sin_port), safe_strerror(errno));
d62a17ae 174 close(sock);
175 return rc;
176 }
177
178 rc = listen(sock, 3 /* backlog */);
179 if (rc < 0) {
450971aa 180 flog_err_sys(EC_LIB_SOCKET, "pim_msdp_socket listen: %s",
09c866e3 181 safe_strerror(errno));
d62a17ae 182 close(sock);
183 return rc;
184 }
185
b069b568
AMR
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
d62a17ae 192 /* add accept thread */
193 listener->fd = sock;
194 memcpy(&listener->su, &sin, socklen);
907a2395
DS
195 event_add_read(pim->msdp.master, pim_msdp_sock_accept, pim, sock,
196 &listener->thread);
d62a17ae 197
472ad383 198 pim->msdp.flags |= PIM_MSDPF_LISTENER;
d62a17ae 199 return 0;
2a333e0f 200}
201
202/* active peer socket setup */
d62a17ae 203int pim_msdp_sock_connect(struct pim_msdp_peer *mp)
2a333e0f 204{
d62a17ae 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) {
3613d898 216 zlog_notice(
d62a17ae 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) {
450971aa 226 flog_err_sys(EC_LIB_SOCKET,
09c866e3
QY
227 "pim_msdp_socket socket failure: %s",
228 safe_strerror(errno));
d62a17ae 229 return -1;
230 }
231
d3cc1e45
DS
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);
449a3f5b 235 if (!ifp) {
450971aa 236 flog_err(EC_LIB_INTERFACE,
1c50c1c0 237 "%s: Unable to lookup vrf interface: %s",
15569c58 238 __func__, mp->pim->vrf->name);
449a3f5b
DS
239 return -1;
240 }
e691f179 241 if (pim_socket_bind(mp->fd, ifp)) {
450971aa 242 flog_err_sys(EC_LIB_SOCKET,
09c866e3 243 "%s: Unable to bind to socket: %s",
15569c58 244 __func__, safe_strerror(errno));
e691f179
DS
245 close(mp->fd);
246 mp->fd = -1;
247 return -1;
248 }
62fde409
DS
249 }
250
d62a17ae 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) {
450971aa 261 flog_err_sys(EC_LIB_SOCKET,
09c866e3
QY
262 "pim_msdp_socket connect bind failure: %s",
263 safe_strerror(errno));
d62a17ae 264 close(mp->fd);
265 mp->fd = -1;
266 return rc;
267 }
268
b069b568
AMR
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
d62a17ae 275 /* Connect to the remote mp. */
276 return (sockunion_connect(mp->fd, &mp->su_peer,
277 htons(PIM_MSDP_TCP_PORT), 0));
2a333e0f 278}