1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * OSPF network related functions
4 * Copyright (C) 1999 Toshiaki Takada
13 #include "sockunion.h"
17 #include "lib_errors.h"
18 #include "lib/table.h"
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"
30 /* Join to the OSPF ALL SPF ROUTERS multicast group. */
31 int ospf_if_add_allspfrouters(struct ospf
*top
, struct prefix
*p
,
36 ret
= setsockopt_ipv4_multicast(top
->fd
, IP_ADD_MEMBERSHIP
,
37 p
->u
.prefix4
, htonl(OSPF_ALLSPFROUTERS
),
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
));
46 if (IS_DEBUG_OSPF_EVENT
)
48 "interface %pI4 [%u] join AllSPFRouters Multicast group.",
49 &p
->u
.prefix4
, ifindex
);
55 int ospf_if_drop_allspfrouters(struct ospf
*top
, struct prefix
*p
,
60 ret
= setsockopt_ipv4_multicast(top
->fd
, IP_DROP_MEMBERSHIP
,
61 p
->u
.prefix4
, htonl(OSPF_ALLSPFROUTERS
),
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
));
69 if (IS_DEBUG_OSPF_EVENT
)
71 "interface %pI4 [%u] leave AllSPFRouters Multicast group.",
72 &p
->u
.prefix4
, ifindex
);
78 /* Join to the OSPF ALL Designated ROUTERS multicast group. */
79 int ospf_if_add_alldrouters(struct ospf
*top
, struct prefix
*p
,
84 ret
= setsockopt_ipv4_multicast(top
->fd
, IP_ADD_MEMBERSHIP
,
85 p
->u
.prefix4
, htonl(OSPF_ALLDROUTERS
),
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
));
94 if (IS_DEBUG_OSPF_EVENT
)
96 "interface %pI4 [%u] join AllDRouters Multicast group.",
97 &p
->u
.prefix4
, ifindex
);
102 int ospf_if_drop_alldrouters(struct ospf
*top
, struct prefix
*p
,
107 ret
= setsockopt_ipv4_multicast(top
->fd
, IP_DROP_MEMBERSHIP
,
108 p
->u
.prefix4
, htonl(OSPF_ALLDROUTERS
),
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
)
117 "interface %pI4 [%u] leave AllDRouters Multicast group.",
118 &p
->u
.prefix4
, ifindex
);
123 int ospf_if_ipmulticast(int fd
, struct prefix
*p
, ifindex_t ifindex
)
128 /* Prevent receiving self-origined multicast packets. */
129 ret
= setsockopt_ipv4_multicast_loop(fd
, 0);
131 flog_err(EC_LIB_SOCKET
,
132 "can't setsockopt IP_MULTICAST_LOOP(0) for fd %d: %s",
133 fd
, safe_strerror(errno
));
135 /* Explicitly set multicast ttl to 1 -- endo. */
138 ret
= setsockopt(fd
, IPPROTO_IP
, IP_MULTICAST_TTL
, (void *)&val
, len
);
140 flog_err(EC_LIB_SOCKET
,
141 "can't setsockopt IP_MULTICAST_TTL(1) for fd %d: %s",
142 fd
, safe_strerror(errno
));
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.
147 ret
= setsockopt_ipv4_multicast_if(fd
, p
->u
.prefix4
, ifindex
);
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
));
159 * Helper to open and set up a socket; returns the new fd on success,
162 static int sock_init_common(vrf_id_t vrf_id
, const char *name
, int *pfd
)
167 if (vrf_id
== VRF_UNKNOWN
) {
168 /* silently return since VRF is not ready */
172 frr_with_privs(&ospfd_privs
) {
173 ospf_sock
= vrf_socket(AF_INET
, SOCK_RAW
, IPPROTO_OSPFIGP
,
176 flog_err(EC_LIB_SOCKET
, "%s: socket: %s", __func__
,
177 safe_strerror(errno
));
182 /* we will include IP header with packet */
183 ret
= setsockopt(ospf_sock
, IPPROTO_IP
, IP_HDRINCL
, &hincl
,
186 flog_err(EC_LIB_SOCKET
,
187 "Can't set IP_HDRINCL option for fd %d: %s",
188 ospf_sock
, safe_strerror(errno
));
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
);
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
));
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 */
207 ret
= setsockopt_ifindex(AF_INET
, ospf_sock
, 1);
210 flog_err(EC_LIB_SOCKET
,
211 "Can't set pktinfo option for fd %d",
221 * Update a socket bufsize(s), based on its ospf instance
223 void ospf_sock_bufsize_update(const struct ospf
*ospf
, int sock
,
224 enum ospf_sock_type_e type
)
228 if (type
== OSPF_SOCK_BOTH
|| type
== OSPF_SOCK_RECV
) {
229 bufsize
= ospf
->recv_sock_bufsize
;
230 setsockopt_so_recvbuf(sock
, bufsize
);
233 if (type
== OSPF_SOCK_BOTH
|| type
== OSPF_SOCK_SEND
) {
234 bufsize
= ospf
->send_sock_bufsize
;
235 setsockopt_so_sendbuf(sock
, bufsize
);
239 int ospf_sock_init(struct ospf
*ospf
)
243 /* silently ignore. already done */
247 ret
= sock_init_common(ospf
->vrf_id
, ospf
->name
, &(ospf
->fd
));
249 if (ret
>= 0) /* Update socket buffer sizes */
250 ospf_sock_bufsize_update(ospf
, ospf
->fd
, OSPF_SOCK_BOTH
);
256 * Open per-interface write socket
258 int ospf_ifp_sock_init(struct interface
*ifp
)
260 struct ospf_if_info
*oii
;
261 struct ospf_interface
*oi
;
263 struct route_node
*rn
;
266 oii
= IF_OSPF_IF_INFO(ifp
);
273 rn
= route_top(IF_OIFS(ifp
));
274 if (rn
&& rn
->info
) {
280 ret
= sock_init_common(ifp
->vrf
->vrf_id
, ifp
->name
, &oii
->oii_fd
);
282 if (ret
>= 0) /* Update socket buffer sizes */
283 ospf_sock_bufsize_update(ospf
, oii
->oii_fd
, OSPF_SOCK_BOTH
);
285 if (IS_DEBUG_OSPF_EVENT
)
286 zlog_debug("%s: ifp %s, oii %p, fd %d", __func__
, ifp
->name
,
293 * Close per-interface write socket
295 int ospf_ifp_sock_close(struct interface
*ifp
)
297 struct ospf_if_info
*oii
;
299 oii
= IF_OSPF_IF_INFO(ifp
);
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
);