1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * EIGRP Network Related Functions.
4 * Copyright (C) 2013-2014
19 #include "sockunion.h"
25 #include "lib_errors.h"
27 #include "eigrpd/eigrp_structs.h"
28 #include "eigrpd/eigrpd.h"
29 #include "eigrpd/eigrp_interface.h"
30 #include "eigrpd/eigrp_neighbor.h"
31 #include "eigrpd/eigrp_packet.h"
32 #include "eigrpd/eigrp_zebra.h"
33 #include "eigrpd/eigrp_vty.h"
34 #include "eigrpd/eigrp_network.h"
36 static int eigrp_network_match_iface(const struct prefix
*connected_prefix
,
37 const struct prefix
*prefix
);
38 static void eigrp_network_run_interface(struct eigrp
*, struct prefix
*,
41 int eigrp_sock_init(struct vrf
*vrf
)
52 frr_with_privs(&eigrpd_privs
) {
53 eigrp_sock
= vrf_socket(
54 AF_INET
, SOCK_RAW
, IPPROTO_EIGRPIGP
, vrf
->vrf_id
,
55 vrf
->vrf_id
!= VRF_DEFAULT
? vrf
->name
: NULL
);
57 zlog_err("%s: socket: %s",
58 __func__
, safe_strerror(errno
));
63 /* we will include IP header with packet */
64 ret
= setsockopt(eigrp_sock
, IPPROTO_IP
, IP_HDRINCL
, &hincl
,
67 zlog_warn("Can't set IP_HDRINCL option for fd %d: %s",
68 eigrp_sock
, safe_strerror(errno
));
70 #elif defined(IPTOS_PREC_INTERNETCONTROL)
71 #warning "IP_HDRINCL not available on this system"
72 #warning "using IPTOS_PREC_INTERNETCONTROL"
73 ret
= setsockopt_ipv4_tos(eigrp_sock
,
74 IPTOS_PREC_INTERNETCONTROL
);
76 zlog_warn("can't set sockopt IP_TOS %d to socket %d: %s",
77 tos
, eigrp_sock
, safe_strerror(errno
));
78 close(eigrp_sock
); /* Prevent sd leak. */
81 #else /* !IPTOS_PREC_INTERNETCONTROL */
82 #warning "IP_HDRINCL not available, nor is IPTOS_PREC_INTERNETCONTROL"
83 zlog_warn("IP_HDRINCL option not available");
84 #endif /* IP_HDRINCL */
86 ret
= setsockopt_ifindex(AF_INET
, eigrp_sock
, 1);
88 zlog_warn("Can't set pktinfo option for fd %d",
95 void eigrp_adjust_sndbuflen(struct eigrp
*eigrp
, unsigned int buflen
)
98 /* Check if any work has to be done at all. */
99 if (eigrp
->maxsndbuflen
>= buflen
)
102 /* Now we try to set SO_SNDBUF to what our caller has requested
103 * (the MTU of a newly added interface). However, if the OS has
104 * truncated the actual buffer size to somewhat less size, try
105 * to detect it and update our records appropriately. The OS
106 * may allocate more buffer space, than requested, this isn't
109 setsockopt_so_sendbuf(eigrp
->fd
, buflen
);
110 newbuflen
= getsockopt_so_sendbuf(eigrp
->fd
);
111 if (newbuflen
< 0 || newbuflen
< (int)buflen
)
112 zlog_warn("%s: tried to set SO_SNDBUF to %u, but got %d",
113 __func__
, buflen
, newbuflen
);
115 eigrp
->maxsndbuflen
= (unsigned int)newbuflen
;
117 zlog_warn("%s: failed to get SO_SNDBUF", __func__
);
120 int eigrp_if_ipmulticast(struct eigrp
*top
, struct prefix
*p
,
121 unsigned int ifindex
)
129 /* Prevent receiving self-origined multicast packets. */
130 ret
= setsockopt(top
->fd
, IPPROTO_IP
, IP_MULTICAST_LOOP
, (void *)&val
,
134 "can't setsockopt IP_MULTICAST_LOOP (0) for fd %d: %s",
135 top
->fd
, safe_strerror(errno
));
137 /* Explicitly set multicast ttl to 1 -- endo. */
139 ret
= setsockopt(top
->fd
, IPPROTO_IP
, IP_MULTICAST_TTL
, (void *)&val
,
142 zlog_warn("can't setsockopt IP_MULTICAST_TTL (1) for fd %d: %s",
143 top
->fd
, safe_strerror(errno
));
145 ret
= setsockopt_ipv4_multicast_if(top
->fd
, p
->u
.prefix4
, ifindex
);
148 "can't setsockopt IP_MULTICAST_IF (fd %d, addr %pI4, ifindex %u): %s",
149 top
->fd
, &p
->u
.prefix4
, ifindex
, safe_strerror(errno
));
154 /* Join to the EIGRP multicast group. */
155 int eigrp_if_add_allspfrouters(struct eigrp
*top
, struct prefix
*p
,
156 unsigned int ifindex
)
160 ret
= setsockopt_ipv4_multicast(
161 top
->fd
, IP_ADD_MEMBERSHIP
, p
->u
.prefix4
,
162 htonl(EIGRP_MULTICAST_ADDRESS
), ifindex
);
165 "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?",
166 top
->fd
, &p
->u
.prefix4
, ifindex
, safe_strerror(errno
));
168 zlog_debug("interface %pI4 [%u] join EIGRP Multicast group.",
169 &p
->u
.prefix4
, ifindex
);
174 int eigrp_if_drop_allspfrouters(struct eigrp
*top
, struct prefix
*p
,
175 unsigned int ifindex
)
179 ret
= setsockopt_ipv4_multicast(
180 top
->fd
, IP_DROP_MEMBERSHIP
, p
->u
.prefix4
,
181 htonl(EIGRP_MULTICAST_ADDRESS
), ifindex
);
184 "can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %pI4, ifindex %u, AllSPFRouters): %s",
185 top
->fd
, &p
->u
.prefix4
, ifindex
, safe_strerror(errno
));
187 zlog_debug("interface %pI4 [%u] leave EIGRP Multicast group.",
188 &p
->u
.prefix4
, ifindex
);
193 int eigrp_network_set(struct eigrp
*eigrp
, struct prefix
*p
)
195 struct vrf
*vrf
= vrf_lookup_by_id(eigrp
->vrf_id
);
196 struct route_node
*rn
;
197 struct interface
*ifp
;
199 rn
= route_node_get(eigrp
->networks
, p
);
201 /* There is already same network statement. */
202 route_unlock_node(rn
);
206 struct prefix
*pref
= prefix_new();
207 prefix_copy(pref
, p
);
208 rn
->info
= (void *)pref
;
210 /* Schedule Router ID Update. */
211 if (eigrp
->router_id
.s_addr
== INADDR_ANY
)
212 eigrp_router_id_update(eigrp
);
213 /* Run network config now. */
214 /* Get target interface. */
215 FOR_ALL_INTERFACES (vrf
, ifp
) {
216 zlog_debug("Setting up %s", ifp
->name
);
217 eigrp_network_run_interface(eigrp
, p
, ifp
);
222 /* Check whether interface matches given network
223 * returns: 1, true. 0, false
225 static int eigrp_network_match_iface(const struct prefix
*co_prefix
,
226 const struct prefix
*net
)
228 /* new approach: more elegant and conceptually clean */
229 return prefix_match_network_statement(net
, co_prefix
);
232 static void eigrp_network_run_interface(struct eigrp
*eigrp
, struct prefix
*p
,
233 struct interface
*ifp
)
235 struct eigrp_interface
*ei
;
236 struct listnode
*cnode
;
237 struct connected
*co
;
239 /* if interface prefix is match specified prefix,
240 then create socket and join multicast group. */
241 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, cnode
, co
)) {
243 if (CHECK_FLAG(co
->flags
, ZEBRA_IFA_SECONDARY
))
246 if (p
->family
== co
->address
->family
&& !ifp
->info
247 && eigrp_network_match_iface(co
->address
, p
)) {
249 ei
= eigrp_if_new(eigrp
, ifp
, co
->address
);
251 /* Relate eigrp interface to eigrp instance. */
254 /* if router_id is not configured, dont bring up
256 * eigrp_router_id_update() will call eigrp_if_update
257 * whenever r-id is configured instead.
259 if (if_is_operative(ifp
))
265 void eigrp_if_update(struct interface
*ifp
)
267 struct listnode
*node
, *nnode
;
268 struct route_node
*rn
;
272 * In the event there are multiple eigrp autonymnous systems running,
273 * we need to check eac one and add the interface as approperate
275 for (ALL_LIST_ELEMENTS(eigrp_om
->eigrp
, node
, nnode
, eigrp
)) {
276 if (ifp
->vrf
->vrf_id
!= eigrp
->vrf_id
)
279 /* EIGRP must be on and Router-ID must be configured. */
280 if (eigrp
->router_id
.s_addr
== INADDR_ANY
)
283 /* Run each network for this interface. */
284 for (rn
= route_top(eigrp
->networks
); rn
; rn
= route_next(rn
))
285 if (rn
->info
!= NULL
) {
286 eigrp_network_run_interface(eigrp
, &rn
->p
, ifp
);
291 int eigrp_network_unset(struct eigrp
*eigrp
, struct prefix
*p
)
293 struct route_node
*rn
;
294 struct listnode
*node
, *nnode
;
295 struct eigrp_interface
*ei
;
298 rn
= route_node_lookup(eigrp
->networks
, p
);
303 route_unlock_node(rn
);
305 if (!IPV4_ADDR_SAME(&pref
->u
.prefix4
, &p
->u
.prefix4
))
308 prefix_ipv4_free((struct prefix_ipv4
**)&rn
->info
);
309 route_unlock_node(rn
); /* initial reference */
311 /* Find interfaces that not configured already. */
312 for (ALL_LIST_ELEMENTS(eigrp
->eiflist
, node
, nnode
, ei
)) {
315 for (rn
= route_top(eigrp
->networks
); rn
; rn
= route_next(rn
)) {
316 if (rn
->info
== NULL
)
319 if (eigrp_network_match_iface(&ei
->address
, &rn
->p
)) {
321 route_unlock_node(rn
);
327 eigrp_if_free(ei
, INTERFACE_DOWN_BY_VTY
);
334 void eigrp_external_routes_refresh(struct eigrp
*eigrp
, int type
)