]> git.proxmox.com Git - mirror_frr.git/blob - ospfd/ospf_network.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[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 "thread.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
19 #include "ospfd/ospfd.h"
20 #include "ospfd/ospf_network.h"
21 #include "ospfd/ospf_interface.h"
22 #include "ospfd/ospf_asbr.h"
23 #include "ospfd/ospf_lsa.h"
24 #include "ospfd/ospf_lsdb.h"
25 #include "ospfd/ospf_neighbor.h"
26 #include "ospfd/ospf_packet.h"
27 #include "ospfd/ospf_dump.h"
28
29 /* Join to the OSPF ALL SPF ROUTERS multicast group. */
30 int ospf_if_add_allspfrouters(struct ospf *top, struct prefix *p,
31 ifindex_t ifindex)
32 {
33 int ret;
34
35 ret = setsockopt_ipv4_multicast(top->fd, IP_ADD_MEMBERSHIP,
36 p->u.prefix4, htonl(OSPF_ALLSPFROUTERS),
37 ifindex);
38 if (ret < 0)
39 flog_err(
40 EC_LIB_SOCKET,
41 "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?",
42 top->fd, &p->u.prefix4, ifindex,
43 safe_strerror(errno));
44 else {
45 if (IS_DEBUG_OSPF_EVENT)
46 zlog_debug(
47 "interface %pI4 [%u] join AllSPFRouters Multicast group.",
48 &p->u.prefix4, ifindex);
49 }
50
51 return ret;
52 }
53
54 int ospf_if_drop_allspfrouters(struct ospf *top, struct prefix *p,
55 ifindex_t ifindex)
56 {
57 int ret;
58
59 ret = setsockopt_ipv4_multicast(top->fd, IP_DROP_MEMBERSHIP,
60 p->u.prefix4, htonl(OSPF_ALLSPFROUTERS),
61 ifindex);
62 if (ret < 0)
63 flog_err(EC_LIB_SOCKET,
64 "can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %pI4, ifindex %u, AllSPFRouters): %s",
65 top->fd, &p->u.prefix4, ifindex,
66 safe_strerror(errno));
67 else {
68 if (IS_DEBUG_OSPF_EVENT)
69 zlog_debug(
70 "interface %pI4 [%u] leave AllSPFRouters Multicast group.",
71 &p->u.prefix4, ifindex);
72 }
73
74 return ret;
75 }
76
77 /* Join to the OSPF ALL Designated ROUTERS multicast group. */
78 int ospf_if_add_alldrouters(struct ospf *top, struct prefix *p,
79 ifindex_t ifindex)
80 {
81 int ret;
82
83 ret = setsockopt_ipv4_multicast(top->fd, IP_ADD_MEMBERSHIP,
84 p->u.prefix4, htonl(OSPF_ALLDROUTERS),
85 ifindex);
86 if (ret < 0)
87 flog_err(
88 EC_LIB_SOCKET,
89 "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?",
90 top->fd, &p->u.prefix4, ifindex,
91 safe_strerror(errno));
92 else {
93 if (IS_DEBUG_OSPF_EVENT)
94 zlog_debug(
95 "interface %pI4 [%u] join AllDRouters Multicast group.",
96 &p->u.prefix4, ifindex);
97 }
98 return ret;
99 }
100
101 int ospf_if_drop_alldrouters(struct ospf *top, struct prefix *p,
102 ifindex_t ifindex)
103 {
104 int ret;
105
106 ret = setsockopt_ipv4_multicast(top->fd, IP_DROP_MEMBERSHIP,
107 p->u.prefix4, htonl(OSPF_ALLDROUTERS),
108 ifindex);
109 if (ret < 0)
110 flog_err(EC_LIB_SOCKET,
111 "can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %pI4, ifindex %u, AllDRouters): %s",
112 top->fd, &p->u.prefix4, ifindex,
113 safe_strerror(errno));
114 else
115 zlog_debug(
116 "interface %pI4 [%u] leave AllDRouters Multicast group.",
117 &p->u.prefix4, ifindex);
118
119 return ret;
120 }
121
122 int ospf_if_ipmulticast(struct ospf *top, struct prefix *p, ifindex_t ifindex)
123 {
124 uint8_t val;
125 int ret, len;
126
127 /* Prevent receiving self-origined multicast packets. */
128 ret = setsockopt_ipv4_multicast_loop(top->fd, 0);
129 if (ret < 0)
130 flog_err(EC_LIB_SOCKET,
131 "can't setsockopt IP_MULTICAST_LOOP(0) for fd %d: %s",
132 top->fd, safe_strerror(errno));
133
134 /* Explicitly set multicast ttl to 1 -- endo. */
135 val = 1;
136 len = sizeof(val);
137 ret = setsockopt(top->fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&val,
138 len);
139 if (ret < 0)
140 flog_err(EC_LIB_SOCKET,
141 "can't setsockopt IP_MULTICAST_TTL(1) for fd %d: %s",
142 top->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(top->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 top->fd, &p->u.prefix4, ifindex,
152 safe_strerror(errno));
153 #endif
154
155 return ret;
156 }
157
158 int ospf_sock_init(struct ospf *ospf)
159 {
160 int ospf_sock;
161 int ret, hincl = 1;
162 int bufsize = (8 * 1024 * 1024);
163
164 /* silently ignore. already done */
165 if (ospf->fd > 0)
166 return -1;
167
168 if (ospf->vrf_id == VRF_UNKNOWN) {
169 /* silently return since VRF is not ready */
170 return -1;
171 }
172 frr_with_privs(&ospfd_privs) {
173 ospf_sock = vrf_socket(AF_INET, SOCK_RAW, IPPROTO_OSPFIGP,
174 ospf->vrf_id, ospf->name);
175 if (ospf_sock < 0) {
176 flog_err(EC_LIB_SOCKET,
177 "ospf_read_sock_init: socket: %s",
178 safe_strerror(errno));
179 return -1;
180 }
181
182 #ifdef IP_HDRINCL
183 /* we will include IP header with packet */
184 ret = setsockopt(ospf_sock, IPPROTO_IP, IP_HDRINCL, &hincl,
185 sizeof(hincl));
186 if (ret < 0) {
187 flog_err(EC_LIB_SOCKET,
188 "Can't set IP_HDRINCL option for fd %d: %s",
189 ospf_sock, safe_strerror(errno));
190 break;
191 }
192 #elif defined(IPTOS_PREC_INTERNETCONTROL)
193 #warning "IP_HDRINCL not available on this system"
194 #warning "using IPTOS_PREC_INTERNETCONTROL"
195 ret = setsockopt_ipv4_tos(ospf_sock,
196 IPTOS_PREC_INTERNETCONTROL);
197 if (ret < 0) {
198 flog_err(EC_LIB_SOCKET,
199 "can't set sockopt IP_TOS %d to socket %d: %s",
200 tos, ospf_sock, safe_strerror(errno));
201 break;
202 }
203 #else /* !IPTOS_PREC_INTERNETCONTROL */
204 #warning "IP_HDRINCL not available, nor is IPTOS_PREC_INTERNETCONTROL"
205 flog_err(EC_LIB_UNAVAILABLE, "IP_HDRINCL option not available");
206 #endif /* IP_HDRINCL */
207
208 ret = setsockopt_ifindex(AF_INET, ospf_sock, 1);
209
210 if (ret < 0)
211 flog_err(EC_LIB_SOCKET,
212 "Can't set pktinfo option for fd %d",
213 ospf_sock);
214 }
215
216 setsockopt_so_sendbuf(ospf_sock, bufsize);
217 setsockopt_so_recvbuf(ospf_sock, bufsize);
218
219 ospf->fd = ospf_sock;
220 return ret;
221 }