2 * EIGRP Network Related Functions.
3 * Copyright (C) 2013-2014
11 * This file is part of GNU Zebra.
13 * GNU Zebra is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2, or (at your option) any
18 * GNU Zebra is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * General Public License for more details.
23 * You should have received a copy of the GNU General Public License along
24 * with this program; see the file COPYING; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
34 #include "sockunion.h"
40 #include "lib_errors.h"
42 #include "eigrpd/eigrp_structs.h"
43 #include "eigrpd/eigrpd.h"
44 #include "eigrpd/eigrp_interface.h"
45 #include "eigrpd/eigrp_neighbor.h"
46 #include "eigrpd/eigrp_packet.h"
47 #include "eigrpd/eigrp_zebra.h"
48 #include "eigrpd/eigrp_vty.h"
49 #include "eigrpd/eigrp_network.h"
51 static int eigrp_network_match_iface(const struct connected
*,
52 const struct prefix
*);
53 static void eigrp_network_run_interface(struct eigrp
*, struct prefix
*,
56 int eigrp_sock_init(void)
64 if (eigrpd_privs
.change(ZPRIVS_RAISE
))
65 zlog_ferr(LIB_ERR_PRIVILEGES
,
66 "eigrp_sock_init: could not raise privs, %s",
67 safe_strerror(errno
));
69 eigrp_sock
= socket(AF_INET
, SOCK_RAW
, IPPROTO_EIGRPIGP
);
71 int save_errno
= errno
;
72 if (eigrpd_privs
.change(ZPRIVS_LOWER
))
73 zlog_ferr(LIB_ERR_PRIVILEGES
,
74 "eigrp_sock_init: could not lower privs, %s",
75 safe_strerror(errno
));
76 zlog_ferr(LIB_ERR_SOCKET
, "eigrp_read_sock_init: socket: %s",
77 safe_strerror(save_errno
));
82 /* we will include IP header with packet */
83 ret
= setsockopt(eigrp_sock
, IPPROTO_IP
, IP_HDRINCL
, &hincl
,
86 int save_errno
= errno
;
87 if (eigrpd_privs
.change(ZPRIVS_LOWER
))
88 zlog_ferr(LIB_ERR_PRIVILEGES
,
89 "eigrp_sock_init: could not lower privs, %s",
90 safe_strerror(errno
));
91 zlog_warn("Can't set IP_HDRINCL option for fd %d: %s",
92 eigrp_sock
, safe_strerror(save_errno
));
94 #elif defined(IPTOS_PREC_INTERNETCONTROL)
95 #warning "IP_HDRINCL not available on this system"
96 #warning "using IPTOS_PREC_INTERNETCONTROL"
97 ret
= setsockopt_ipv4_tos(eigrp_sock
, IPTOS_PREC_INTERNETCONTROL
);
99 int save_errno
= errno
;
100 if (eigrpd_privs
.change(ZPRIVS_LOWER
))
101 zlog_ferr(LIB_ERR_PRIVILEGES
,
102 "eigrpd_sock_init: could not lower privs, %s",
103 safe_strerror(errno
));
104 zlog_warn("can't set sockopt IP_TOS %d to socket %d: %s", tos
,
105 eigrp_sock
, safe_strerror(save_errno
));
106 close(eigrp_sock
); /* Prevent sd leak. */
109 #else /* !IPTOS_PREC_INTERNETCONTROL */
110 #warning "IP_HDRINCL not available, nor is IPTOS_PREC_INTERNETCONTROL"
111 zlog_warn("IP_HDRINCL option not available");
112 #endif /* IP_HDRINCL */
114 ret
= setsockopt_ifindex(AF_INET
, eigrp_sock
, 1);
117 zlog_warn("Can't set pktinfo option for fd %d", eigrp_sock
);
119 if (eigrpd_privs
.change(ZPRIVS_LOWER
)) {
120 zlog_ferr(LIB_ERR_PRIVILEGES
,
121 "eigrp_sock_init: could not lower privs, %s",
122 safe_strerror(errno
));
128 void eigrp_adjust_sndbuflen(struct eigrp
*eigrp
, unsigned int buflen
)
131 /* Check if any work has to be done at all. */
132 if (eigrp
->maxsndbuflen
>= buflen
)
134 if (eigrpd_privs
.change(ZPRIVS_RAISE
))
135 zlog_ferr(LIB_ERR_PRIVILEGES
, "%s: could not raise privs, %s",
136 __func__
, safe_strerror(errno
));
138 /* Now we try to set SO_SNDBUF to what our caller has requested
139 * (the MTU of a newly added interface). However, if the OS has
140 * truncated the actual buffer size to somewhat less size, try
141 * to detect it and update our records appropriately. The OS
142 * may allocate more buffer space, than requested, this isn't
145 setsockopt_so_sendbuf(eigrp
->fd
, buflen
);
146 newbuflen
= getsockopt_so_sendbuf(eigrp
->fd
);
147 if (newbuflen
< 0 || newbuflen
< (int)buflen
)
148 zlog_warn("%s: tried to set SO_SNDBUF to %u, but got %d",
149 __func__
, buflen
, newbuflen
);
151 eigrp
->maxsndbuflen
= (unsigned int)newbuflen
;
153 zlog_warn("%s: failed to get SO_SNDBUF", __func__
);
154 if (eigrpd_privs
.change(ZPRIVS_LOWER
))
155 zlog_ferr(LIB_ERR_PRIVILEGES
, "%s: could not lower privs, %s",
156 __func__
, safe_strerror(errno
));
159 int eigrp_if_ipmulticast(struct eigrp
*top
, struct prefix
*p
,
160 unsigned int ifindex
)
168 /* Prevent receiving self-origined multicast packets. */
169 ret
= setsockopt(top
->fd
, IPPROTO_IP
, IP_MULTICAST_LOOP
, (void *)&val
,
173 "can't setsockopt IP_MULTICAST_LOOP (0) for fd %d: %s",
174 top
->fd
, safe_strerror(errno
));
176 /* Explicitly set multicast ttl to 1 -- endo. */
178 ret
= setsockopt(top
->fd
, IPPROTO_IP
, IP_MULTICAST_TTL
, (void *)&val
,
181 zlog_warn("can't setsockopt IP_MULTICAST_TTL (1) for fd %d: %s",
182 top
->fd
, safe_strerror(errno
));
184 ret
= setsockopt_ipv4_multicast_if(top
->fd
, p
->u
.prefix4
, ifindex
);
187 "can't setsockopt IP_MULTICAST_IF (fd %d, addr %s, "
189 top
->fd
, inet_ntoa(p
->u
.prefix4
), ifindex
,
190 safe_strerror(errno
));
195 /* Join to the EIGRP multicast group. */
196 int eigrp_if_add_allspfrouters(struct eigrp
*top
, struct prefix
*p
,
197 unsigned int ifindex
)
201 ret
= setsockopt_ipv4_multicast(
202 top
->fd
, IP_ADD_MEMBERSHIP
, p
->u
.prefix4
,
203 htonl(EIGRP_MULTICAST_ADDRESS
), ifindex
);
206 "can't setsockopt IP_ADD_MEMBERSHIP (fd %d, addr %s, "
207 "ifindex %u, AllSPFRouters): %s; perhaps a kernel limit "
208 "on # of multicast group memberships has been exceeded?",
209 top
->fd
, inet_ntoa(p
->u
.prefix4
), ifindex
,
210 safe_strerror(errno
));
212 zlog_debug("interface %s [%u] join EIGRP Multicast group.",
213 inet_ntoa(p
->u
.prefix4
), ifindex
);
218 int eigrp_if_drop_allspfrouters(struct eigrp
*top
, struct prefix
*p
,
219 unsigned int ifindex
)
223 ret
= setsockopt_ipv4_multicast(
224 top
->fd
, IP_DROP_MEMBERSHIP
, p
->u
.prefix4
,
225 htonl(EIGRP_MULTICAST_ADDRESS
), ifindex
);
228 "can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %s, "
229 "ifindex %u, AllSPFRouters): %s",
230 top
->fd
, inet_ntoa(p
->u
.prefix4
), ifindex
,
231 safe_strerror(errno
));
233 zlog_debug("interface %s [%u] leave EIGRP Multicast group.",
234 inet_ntoa(p
->u
.prefix4
), ifindex
);
239 int eigrp_network_set(struct eigrp
*eigrp
, struct prefix
*p
)
241 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
242 struct route_node
*rn
;
243 struct interface
*ifp
;
245 rn
= route_node_get(eigrp
->networks
, (struct prefix
*)p
);
247 /* There is already same network statement. */
248 route_unlock_node(rn
);
252 struct prefix
*pref
= prefix_new();
253 PREFIX_COPY_IPV4(pref
, p
);
254 rn
->info
= (void *)pref
;
256 /* Schedule Router ID Update. */
257 if (eigrp
->router_id
== 0)
258 eigrp_router_id_update(eigrp
);
259 /* Run network config now. */
260 /* Get target interface. */
261 FOR_ALL_INTERFACES (vrf
, ifp
) {
262 zlog_debug("Setting up %s", ifp
->name
);
263 eigrp_network_run_interface(eigrp
, p
, ifp
);
268 /* Check whether interface matches given network
269 * returns: 1, true. 0, false
271 static int eigrp_network_match_iface(const struct connected
*co
,
272 const struct prefix
*net
)
274 /* new approach: more elegant and conceptually clean */
275 return prefix_match_network_statement(net
, CONNECTED_PREFIX(co
));
278 static void eigrp_network_run_interface(struct eigrp
*eigrp
, struct prefix
*p
,
279 struct interface
*ifp
)
281 struct eigrp_interface
*ei
;
282 struct listnode
*cnode
;
283 struct connected
*co
;
285 /* if interface prefix is match specified prefix,
286 then create socket and join multicast group. */
287 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, cnode
, co
)) {
289 if (CHECK_FLAG(co
->flags
, ZEBRA_IFA_SECONDARY
))
292 if (p
->family
== co
->address
->family
&& !ifp
->info
293 && eigrp_network_match_iface(co
, p
)) {
295 ei
= eigrp_if_new(eigrp
, ifp
, co
->address
);
298 /* Relate eigrp interface to eigrp instance. */
301 /* if router_id is not configured, dont bring up
303 * eigrp_router_id_update() will call eigrp_if_update
304 * whenever r-id is configured instead.
306 if (if_is_operative(ifp
))
312 void eigrp_if_update(struct interface
*ifp
)
314 struct listnode
*node
, *nnode
;
315 struct route_node
*rn
;
319 * In the event there are multiple eigrp autonymnous systems running,
320 * we need to check eac one and add the interface as approperate
322 for (ALL_LIST_ELEMENTS(eigrp_om
->eigrp
, node
, nnode
, eigrp
)) {
323 /* EIGRP must be on and Router-ID must be configured. */
324 if (!eigrp
|| eigrp
->router_id
== 0)
327 /* Run each network for this interface. */
328 for (rn
= route_top(eigrp
->networks
); rn
; rn
= route_next(rn
))
329 if (rn
->info
!= NULL
) {
330 eigrp_network_run_interface(eigrp
, &rn
->p
, ifp
);
335 int eigrp_network_unset(struct eigrp
*eigrp
, struct prefix
*p
)
337 struct route_node
*rn
;
338 struct listnode
*node
, *nnode
;
339 struct eigrp_interface
*ei
;
342 rn
= route_node_lookup(eigrp
->networks
, p
);
347 route_unlock_node(rn
);
349 if (!IPV4_ADDR_SAME(&pref
->u
.prefix4
, &p
->u
.prefix4
))
352 prefix_ipv4_free(rn
->info
);
354 route_unlock_node(rn
); /* initial reference */
356 /* Find interfaces that not configured already. */
357 for (ALL_LIST_ELEMENTS(eigrp
->eiflist
, node
, nnode
, ei
)) {
359 struct connected
*co
= ei
->connected
;
361 for (rn
= route_top(eigrp
->networks
); rn
; rn
= route_next(rn
)) {
362 if (rn
->info
== NULL
)
365 if (eigrp_network_match_iface(co
, &rn
->p
)) {
367 route_unlock_node(rn
);
373 eigrp_if_free(ei
, INTERFACE_DOWN_BY_VTY
);
380 uint32_t eigrp_calculate_metrics(struct eigrp
*eigrp
,
381 struct eigrp_metrics metric
)
383 uint64_t temp_metric
;
386 if (metric
.delay
== EIGRP_MAX_METRIC
)
387 return EIGRP_MAX_METRIC
;
390 // {K1*BW+[(K2*BW)/(256-load)]+(K3*delay)}*{K5/(reliability+K4)}
392 if (eigrp
->k_values
[0])
393 temp_metric
+= (eigrp
->k_values
[0] * metric
.bandwidth
);
394 if (eigrp
->k_values
[1])
395 temp_metric
+= ((eigrp
->k_values
[1] * metric
.bandwidth
)
396 / (256 - metric
.load
));
397 if (eigrp
->k_values
[2])
398 temp_metric
+= (eigrp
->k_values
[2] * metric
.delay
);
399 if (eigrp
->k_values
[3] && !eigrp
->k_values
[4])
400 temp_metric
*= eigrp
->k_values
[3];
401 if (!eigrp
->k_values
[3] && eigrp
->k_values
[4])
402 temp_metric
*= (eigrp
->k_values
[4] / metric
.reliability
);
403 if (eigrp
->k_values
[3] && eigrp
->k_values
[4])
404 temp_metric
*= ((eigrp
->k_values
[4] / metric
.reliability
)
405 + eigrp
->k_values
[3]);
407 if (temp_metric
<= EIGRP_MAX_METRIC
)
408 return (uint32_t)temp_metric
;
410 return EIGRP_MAX_METRIC
;
413 uint32_t eigrp_calculate_total_metrics(struct eigrp
*eigrp
,
414 struct eigrp_nexthop_entry
*entry
)
416 struct eigrp_interface
*ei
= entry
->ei
;
418 entry
->total_metric
= entry
->reported_metric
;
419 uint64_t temp_delay
=
420 (uint64_t)entry
->total_metric
.delay
421 + (uint64_t)eigrp_delay_to_scaled(ei
->params
.delay
);
422 entry
->total_metric
.delay
= temp_delay
> EIGRP_MAX_METRIC
424 : (uint32_t)temp_delay
;
426 uint32_t bw
= eigrp_bandwidth_to_scaled(ei
->params
.bandwidth
);
427 entry
->total_metric
.bandwidth
= entry
->total_metric
.bandwidth
> bw
429 : entry
->total_metric
.bandwidth
;
431 return eigrp_calculate_metrics(eigrp
, entry
->total_metric
);
434 uint8_t eigrp_metrics_is_same(struct eigrp_metrics metric1
,
435 struct eigrp_metrics metric2
)
437 if ((metric1
.bandwidth
== metric2
.bandwidth
)
438 && (metric1
.delay
== metric2
.delay
)
439 && (metric1
.hop_count
== metric2
.hop_count
)
440 && (metric1
.load
== metric2
.load
)
441 && (metric1
.reliability
== metric2
.reliability
)
442 && (metric1
.mtu
[0] == metric2
.mtu
[0])
443 && (metric1
.mtu
[1] == metric2
.mtu
[1])
444 && (metric1
.mtu
[2] == metric2
.mtu
[2]))
447 return 0; // if different
450 void eigrp_external_routes_refresh(struct eigrp
*eigrp
, int type
)