]>
Commit | Line | Data |
---|---|---|
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 | 29 | static 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 | 53 | static 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 | 116 | int 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 | 203 | int 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 | } |