]> git.proxmox.com Git - mirror_frr.git/blob - ospfd/ospf_network.c
aff8ed05c723542ed1118ce70c20799695ace683
[mirror_frr.git] / ospfd / ospf_network.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * OSPF network related functions
4 * Copyright (C) 1999 Toshiaki Takada
5 */
6
7 #include <zebra.h>
8
9 #include "frrevent.h"
10 #include "linklist.h"
11 #include "prefix.h"
12 #include "if.h"
13 #include "sockunion.h"
14 #include "log.h"
15 #include "sockopt.h"
16 #include "privs.h"
17 #include "lib_errors.h"
18 #include "lib/table.h"
19
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"
28 #include "ospfd/ospf_dump.h"
29
30 /* Join to the OSPF ALL SPF ROUTERS multicast group. */
31 int ospf_if_add_allspfrouters(struct ospf *top, struct prefix *p,
32 ifindex_t ifindex)
33 {
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)
40 flog_err(
41 EC_LIB_SOCKET,
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,
44 safe_strerror(errno));
45 else {
46 if (IS_DEBUG_OSPF_EVENT)
47 zlog_debug(
48 "interface %pI4 [%u] join AllSPFRouters Multicast group.",
49 &p->u.prefix4, ifindex);
50 }
51
52 return ret;
53 }
54
55 int ospf_if_drop_allspfrouters(struct ospf *top, struct prefix *p,
56 ifindex_t ifindex)
57 {
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)
64 flog_err(EC_LIB_SOCKET,
65 "can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %pI4, ifindex %u, AllSPFRouters): %s",
66 top->fd, &p->u.prefix4, ifindex,
67 safe_strerror(errno));
68 else {
69 if (IS_DEBUG_OSPF_EVENT)
70 zlog_debug(
71 "interface %pI4 [%u] leave AllSPFRouters Multicast group.",
72 &p->u.prefix4, ifindex);
73 }
74
75 return ret;
76 }
77
78 /* Join to the OSPF ALL Designated ROUTERS multicast group. */
79 int ospf_if_add_alldrouters(struct ospf *top, struct prefix *p,
80 ifindex_t ifindex)
81 {
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)
88 flog_err(
89 EC_LIB_SOCKET,
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,
92 safe_strerror(errno));
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 }
99 return ret;
100 }
101
102 int ospf_if_drop_alldrouters(struct ospf *top, struct prefix *p,
103 ifindex_t ifindex)
104 {
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)
111 flog_err(EC_LIB_SOCKET,
112 "can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %pI4, ifindex %u, AllDRouters): %s",
113 top->fd, &p->u.prefix4, ifindex,
114 safe_strerror(errno));
115 else if (IS_DEBUG_OSPF_EVENT)
116 zlog_debug(
117 "interface %pI4 [%u] leave AllDRouters Multicast group.",
118 &p->u.prefix4, ifindex);
119
120 return ret;
121 }
122
123 int ospf_if_ipmulticast(int fd, struct prefix *p, ifindex_t ifindex)
124 {
125 uint8_t val;
126 int ret, len;
127
128 /* Prevent receiving self-origined multicast packets. */
129 ret = setsockopt_ipv4_multicast_loop(fd, 0);
130 if (ret < 0)
131 flog_err(EC_LIB_SOCKET,
132 "can't setsockopt IP_MULTICAST_LOOP(0) for fd %d: %s",
133 fd, safe_strerror(errno));
134
135 /* Explicitly set multicast ttl to 1 -- endo. */
136 val = 1;
137 len = sizeof(val);
138 ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&val, len);
139 if (ret < 0)
140 flog_err(EC_LIB_SOCKET,
141 "can't setsockopt IP_MULTICAST_TTL(1) for fd %d: %s",
142 fd, safe_strerror(errno));
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 */
147 ret = setsockopt_ipv4_multicast_if(fd, p->u.prefix4, ifindex);
148 if (ret < 0)
149 flog_err(EC_LIB_SOCKET,
150 "can't setsockopt IP_MULTICAST_IF(fd %d, addr %pI4, ifindex %u): %s",
151 fd, &p->u.prefix4, ifindex,
152 safe_strerror(errno));
153 #endif
154
155 return ret;
156 }
157
158 /*
159 * Helper to open and set up a socket; returns the new fd on success,
160 * -1 on error.
161 */
162 static int sock_init_common(vrf_id_t vrf_id, const char *name, int *pfd)
163 {
164 int ospf_sock;
165 int ret, hincl = 1;
166
167 if (vrf_id == VRF_UNKNOWN) {
168 /* silently return since VRF is not ready */
169 return -1;
170 }
171
172 frr_with_privs(&ospfd_privs) {
173 ospf_sock = vrf_socket(AF_INET, SOCK_RAW, IPPROTO_OSPFIGP,
174 vrf_id, name);
175 if (ospf_sock < 0) {
176 flog_err(EC_LIB_SOCKET, "%s: socket: %s", __func__,
177 safe_strerror(errno));
178 return -1;
179 }
180
181 #ifdef IP_HDRINCL
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) {
186 flog_err(EC_LIB_SOCKET,
187 "Can't set IP_HDRINCL option for fd %d: %s",
188 ospf_sock, safe_strerror(errno));
189 break;
190 }
191 #elif defined(IPTOS_PREC_INTERNETCONTROL)
192 #warning "IP_HDRINCL not available on this system"
193 #warning "using IPTOS_PREC_INTERNETCONTROL"
194 ret = setsockopt_ipv4_tos(ospf_sock,
195 IPTOS_PREC_INTERNETCONTROL);
196 if (ret < 0) {
197 flog_err(EC_LIB_SOCKET,
198 "can't set sockopt IP_TOS %d to socket %d: %s",
199 tos, ospf_sock, safe_strerror(errno));
200 break;
201 }
202 #else /* !IPTOS_PREC_INTERNETCONTROL */
203 #warning "IP_HDRINCL not available, nor is IPTOS_PREC_INTERNETCONTROL"
204 flog_err(EC_LIB_UNAVAILABLE, "IP_HDRINCL option not available");
205 #endif /* IP_HDRINCL */
206
207 ret = setsockopt_ifindex(AF_INET, ospf_sock, 1);
208
209 if (ret < 0)
210 flog_err(EC_LIB_SOCKET,
211 "Can't set pktinfo option for fd %d",
212 ospf_sock);
213 }
214
215 *pfd = ospf_sock;
216
217 return ret;
218 }
219
220 /*
221 * Update a socket bufsize(s), based on its ospf instance
222 */
223 void 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 }
238
239 int 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 */
258 int 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 */
295 int 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 }