]> git.proxmox.com Git - mirror_frr.git/blame - ospfd/ospf_network.c
Merge pull request #13649 from donaldsharp/unlock_the_node_or_else
[mirror_frr.git] / ospfd / ospf_network.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
718e3744 2/*
3 * OSPF network related functions
4 * Copyright (C) 1999 Toshiaki Takada
718e3744 5 */
6
7#include <zebra.h>
8
24a58196 9#include "frrevent.h"
718e3744 10#include "linklist.h"
11#include "prefix.h"
12#include "if.h"
13#include "sockunion.h"
14#include "log.h"
15#include "sockopt.h"
edd7c245 16#include "privs.h"
313d7993 17#include "lib_errors.h"
04a0401f 18#include "lib/table.h"
edd7c245 19
718e3744 20#include "ospfd/ospfd.h"
21#include "ospfd/ospf_network.h"
22#include "ospfd/ospf_interface.h"
23#include "ospfd/ospf_asbr.h"
24#include "ospfd/ospf_lsa.h"
25#include "ospfd/ospf_lsdb.h"
26#include "ospfd/ospf_neighbor.h"
27#include "ospfd/ospf_packet.h"
05ba78e4 28#include "ospfd/ospf_dump.h"
edd7c245 29
718e3744 30/* Join to the OSPF ALL SPF ROUTERS multicast group. */
d62a17ae 31int ospf_if_add_allspfrouters(struct ospf *top, struct prefix *p,
32 ifindex_t ifindex)
718e3744 33{
d62a17ae 34 int ret;
35
36 ret = setsockopt_ipv4_multicast(top->fd, IP_ADD_MEMBERSHIP,
37 p->u.prefix4, htonl(OSPF_ALLSPFROUTERS),
38 ifindex);
39 if (ret < 0)
ade6974d 40 flog_err(
450971aa 41 EC_LIB_SOCKET,
96b663a3
MS
42 "can't setsockopt IP_ADD_MEMBERSHIP (fd %d, addr %pI4, ifindex %u, AllSPFRouters): %s; perhaps a kernel limit on # of multicast group memberships has been exceeded?",
43 top->fd, &p->u.prefix4, ifindex,
ade6974d 44 safe_strerror(errno));
05ba78e4
CS
45 else {
46 if (IS_DEBUG_OSPF_EVENT)
996c9314 47 zlog_debug(
96b663a3
MS
48 "interface %pI4 [%u] join AllSPFRouters Multicast group.",
49 &p->u.prefix4, ifindex);
05ba78e4 50 }
d62a17ae 51
52 return ret;
718e3744 53}
54
d62a17ae 55int ospf_if_drop_allspfrouters(struct ospf *top, struct prefix *p,
56 ifindex_t ifindex)
718e3744 57{
d62a17ae 58 int ret;
59
60 ret = setsockopt_ipv4_multicast(top->fd, IP_DROP_MEMBERSHIP,
61 p->u.prefix4, htonl(OSPF_ALLSPFROUTERS),
62 ifindex);
63 if (ret < 0)
450971aa 64 flog_err(EC_LIB_SOCKET,
96b663a3
MS
65 "can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %pI4, ifindex %u, AllSPFRouters): %s",
66 top->fd, &p->u.prefix4, ifindex,
abcc171c 67 safe_strerror(errno));
05ba78e4
CS
68 else {
69 if (IS_DEBUG_OSPF_EVENT)
996c9314 70 zlog_debug(
96b663a3
MS
71 "interface %pI4 [%u] leave AllSPFRouters Multicast group.",
72 &p->u.prefix4, ifindex);
05ba78e4 73 }
d62a17ae 74
75 return ret;
718e3744 76}
77
78/* Join to the OSPF ALL Designated ROUTERS multicast group. */
d62a17ae 79int ospf_if_add_alldrouters(struct ospf *top, struct prefix *p,
80 ifindex_t ifindex)
718e3744 81{
d62a17ae 82 int ret;
83
84 ret = setsockopt_ipv4_multicast(top->fd, IP_ADD_MEMBERSHIP,
85 p->u.prefix4, htonl(OSPF_ALLDROUTERS),
86 ifindex);
87 if (ret < 0)
ade6974d 88 flog_err(
450971aa 89 EC_LIB_SOCKET,
96b663a3
MS
90 "can't setsockopt IP_ADD_MEMBERSHIP (fd %d, addr %pI4, ifindex %u, AllDRouters): %s; perhaps a kernel limit on # of multicast group memberships has been exceeded?",
91 top->fd, &p->u.prefix4, ifindex,
ade6974d 92 safe_strerror(errno));
15e78e64
DS
93 else {
94 if (IS_DEBUG_OSPF_EVENT)
95 zlog_debug(
96 "interface %pI4 [%u] join AllDRouters Multicast group.",
97 &p->u.prefix4, ifindex);
98 }
d62a17ae 99 return ret;
718e3744 100}
101
d62a17ae 102int ospf_if_drop_alldrouters(struct ospf *top, struct prefix *p,
103 ifindex_t ifindex)
718e3744 104{
d62a17ae 105 int ret;
106
107 ret = setsockopt_ipv4_multicast(top->fd, IP_DROP_MEMBERSHIP,
108 p->u.prefix4, htonl(OSPF_ALLDROUTERS),
109 ifindex);
110 if (ret < 0)
450971aa 111 flog_err(EC_LIB_SOCKET,
96b663a3
MS
112 "can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %pI4, ifindex %u, AllDRouters): %s",
113 top->fd, &p->u.prefix4, ifindex,
abcc171c 114 safe_strerror(errno));
6e6e1020 115 else if (IS_DEBUG_OSPF_EVENT)
d62a17ae 116 zlog_debug(
96b663a3
MS
117 "interface %pI4 [%u] leave AllDRouters Multicast group.",
118 &p->u.prefix4, ifindex);
d62a17ae 119
120 return ret;
718e3744 121}
122
04a0401f 123int ospf_if_ipmulticast(int fd, struct prefix *p, ifindex_t ifindex)
718e3744 124{
d7c0a89a 125 uint8_t val;
d62a17ae 126 int ret, len;
127
128 /* Prevent receiving self-origined multicast packets. */
04a0401f 129 ret = setsockopt_ipv4_multicast_loop(fd, 0);
d62a17ae 130 if (ret < 0)
450971aa 131 flog_err(EC_LIB_SOCKET,
abcc171c 132 "can't setsockopt IP_MULTICAST_LOOP(0) for fd %d: %s",
04a0401f 133 fd, safe_strerror(errno));
d62a17ae 134
135 /* Explicitly set multicast ttl to 1 -- endo. */
136 val = 1;
137 len = sizeof(val);
04a0401f 138 ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&val, len);
d62a17ae 139 if (ret < 0)
450971aa 140 flog_err(EC_LIB_SOCKET,
abcc171c 141 "can't setsockopt IP_MULTICAST_TTL(1) for fd %d: %s",
04a0401f 142 fd, safe_strerror(errno));
e1b18df1
CS
143#ifndef GNU_LINUX
144 /* For GNU LINUX ospf_write uses IP_PKTINFO, in_pktinfo to send
145 * packet out of ifindex. Below would be used Non Linux system.
146 */
04a0401f 147 ret = setsockopt_ipv4_multicast_if(fd, p->u.prefix4, ifindex);
e1b18df1 148 if (ret < 0)
450971aa 149 flog_err(EC_LIB_SOCKET,
96b663a3 150 "can't setsockopt IP_MULTICAST_IF(fd %d, addr %pI4, ifindex %u): %s",
04a0401f 151 fd, &p->u.prefix4, ifindex,
abcc171c 152 safe_strerror(errno));
e1b18df1 153#endif
d62a17ae 154
e7503eab
CS
155 return ret;
156}
157
04a0401f
MS
158/*
159 * Helper to open and set up a socket; returns the new fd on success,
160 * -1 on error.
161 */
162static int sock_init_common(vrf_id_t vrf_id, const char *name, int *pfd)
718e3744 163{
d62a17ae 164 int ospf_sock;
165 int ret, hincl = 1;
d62a17ae 166
04a0401f 167 if (vrf_id == VRF_UNKNOWN) {
3c0eb8fa
PG
168 /* silently return since VRF is not ready */
169 return -1;
170 }
04a0401f 171
0cf6db21 172 frr_with_privs(&ospfd_privs) {
6bb30c2c 173 ospf_sock = vrf_socket(AF_INET, SOCK_RAW, IPPROTO_OSPFIGP,
04a0401f 174 vrf_id, name);
6bb30c2c 175 if (ospf_sock < 0) {
04a0401f 176 flog_err(EC_LIB_SOCKET, "%s: socket: %s", __func__,
6bb30c2c 177 safe_strerror(errno));
95d7a42a 178 return -1;
6bb30c2c 179 }
d62a17ae 180
5bd4189c 181#ifdef IP_HDRINCL
6bb30c2c
DL
182 /* we will include IP header with packet */
183 ret = setsockopt(ospf_sock, IPPROTO_IP, IP_HDRINCL, &hincl,
184 sizeof(hincl));
185 if (ret < 0) {
450971aa 186 flog_err(EC_LIB_SOCKET,
abcc171c
DS
187 "Can't set IP_HDRINCL option for fd %d: %s",
188 ospf_sock, safe_strerror(errno));
6bb30c2c
DL
189 break;
190 }
d62a17ae 191#elif defined(IPTOS_PREC_INTERNETCONTROL)
5bd4189c 192#warning "IP_HDRINCL not available on this system"
193#warning "using IPTOS_PREC_INTERNETCONTROL"
6bb30c2c
DL
194 ret = setsockopt_ipv4_tos(ospf_sock,
195 IPTOS_PREC_INTERNETCONTROL);
196 if (ret < 0) {
450971aa 197 flog_err(EC_LIB_SOCKET,
abcc171c
DS
198 "can't set sockopt IP_TOS %d to socket %d: %s",
199 tos, ospf_sock, safe_strerror(errno));
6bb30c2c
DL
200 break;
201 }
5bd4189c 202#else /* !IPTOS_PREC_INTERNETCONTROL */
203#warning "IP_HDRINCL not available, nor is IPTOS_PREC_INTERNETCONTROL"
1c50c1c0 204 flog_err(EC_LIB_UNAVAILABLE, "IP_HDRINCL option not available");
5bd4189c 205#endif /* IP_HDRINCL */
718e3744 206
6bb30c2c 207 ret = setsockopt_ifindex(AF_INET, ospf_sock, 1);
ac191232 208
6bb30c2c 209 if (ret < 0)
450971aa 210 flog_err(EC_LIB_SOCKET,
abcc171c
DS
211 "Can't set pktinfo option for fd %d",
212 ospf_sock);
6bb30c2c 213 }
e7503eab 214
04a0401f 215 *pfd = ospf_sock;
338b8e91 216
e7503eab 217 return ret;
718e3744 218}
6e6e1020
MS
219
220/*
221 * Update a socket bufsize(s), based on its ospf instance
222 */
223void ospf_sock_bufsize_update(const struct ospf *ospf, int sock,
224 enum ospf_sock_type_e type)
225{
226 int bufsize;
227
228 if (type == OSPF_SOCK_BOTH || type == OSPF_SOCK_RECV) {
229 bufsize = ospf->recv_sock_bufsize;
230 setsockopt_so_recvbuf(sock, bufsize);
231 }
232
233 if (type == OSPF_SOCK_BOTH || type == OSPF_SOCK_SEND) {
234 bufsize = ospf->send_sock_bufsize;
235 setsockopt_so_sendbuf(sock, bufsize);
236 }
237}
04a0401f
MS
238
239int ospf_sock_init(struct ospf *ospf)
240{
241 int ret;
242
243 /* silently ignore. already done */
244 if (ospf->fd > 0)
245 return -1;
246
247 ret = sock_init_common(ospf->vrf_id, ospf->name, &(ospf->fd));
248
249 if (ret >= 0) /* Update socket buffer sizes */
250 ospf_sock_bufsize_update(ospf, ospf->fd, OSPF_SOCK_BOTH);
251
252 return ret;
253}
254
255/*
256 * Open per-interface write socket
257 */
258int ospf_ifp_sock_init(struct interface *ifp)
259{
260 struct ospf_if_info *oii;
261 struct ospf_interface *oi;
262 struct ospf *ospf;
263 struct route_node *rn;
264 int ret;
265
266 oii = IF_OSPF_IF_INFO(ifp);
267 if (oii == NULL)
268 return -1;
269
270 if (oii->oii_fd > 0)
271 return 0;
272
273 rn = route_top(IF_OIFS(ifp));
274 if (rn && rn->info) {
275 oi = rn->info;
276 ospf = oi->ospf;
277 } else
278 return -1;
279
280 ret = sock_init_common(ifp->vrf->vrf_id, ifp->name, &oii->oii_fd);
281
282 if (ret >= 0) /* Update socket buffer sizes */
283 ospf_sock_bufsize_update(ospf, oii->oii_fd, OSPF_SOCK_BOTH);
284
285 if (IS_DEBUG_OSPF_EVENT)
286 zlog_debug("%s: ifp %s, oii %p, fd %d", __func__, ifp->name,
287 oii, oii->oii_fd);
288
289 return ret;
290}
291
292/*
293 * Close per-interface write socket
294 */
295int ospf_ifp_sock_close(struct interface *ifp)
296{
297 struct ospf_if_info *oii;
298
299 oii = IF_OSPF_IF_INFO(ifp);
300 if (oii == NULL)
301 return 0;
302
303 if (oii->oii_fd > 0) {
304 if (IS_DEBUG_OSPF_EVENT)
305 zlog_debug("%s: ifp %s, oii %p, fd %d", __func__,
306 ifp->name, oii, oii->oii_fd);
307
308 close(oii->oii_fd);
309 oii->oii_fd = -1;
310 }
311
312 return 0;
313}