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"
41 extern struct zebra_privs_t eigrpd_privs
;
43 #include "eigrpd/eigrp_structs.h"
44 #include "eigrpd/eigrpd.h"
45 #include "eigrpd/eigrp_interface.h"
46 #include "eigrpd/eigrp_neighbor.h"
47 #include "eigrpd/eigrp_packet.h"
48 #include "eigrpd/eigrp_zebra.h"
49 #include "eigrpd/eigrp_vty.h"
50 #include "eigrpd/eigrp_network.h"
53 eigrp_network_match_iface(const struct connected
*, const struct prefix
*);
55 eigrp_network_run_interface(struct eigrp
*, struct prefix
*, struct interface
*);
63 if (eigrpd_privs
.change(ZPRIVS_RAISE
))
64 zlog_err("eigrp_sock_init: could not raise privs, %s",
65 safe_strerror(errno
));
67 eigrp_sock
= socket(AF_INET
, SOCK_RAW
, IPPROTO_EIGRPIGP
);
70 int save_errno
= errno
;
71 if (eigrpd_privs
.change(ZPRIVS_LOWER
))
72 zlog_err("eigrp_sock_init: could not lower privs, %s",
73 safe_strerror(errno
));
74 zlog_err("eigrp_read_sock_init: socket: %s", safe_strerror(save_errno
));
79 /* we will include IP header with packet */
80 ret
= setsockopt(eigrp_sock
, IPPROTO_IP
, IP_HDRINCL
, &hincl
, sizeof(hincl
));
83 int save_errno
= errno
;
84 if (eigrpd_privs
.change(ZPRIVS_LOWER
))
85 zlog_err("eigrp_sock_init: could not lower privs, %s",
86 safe_strerror(errno
));
87 zlog_warn("Can't set IP_HDRINCL option for fd %d: %s", eigrp_sock
,
88 safe_strerror(save_errno
));
91 #elif defined (IPTOS_PREC_INTERNETCONTROL)
92 #warning "IP_HDRINCL not available on this system"
93 #warning "using IPTOS_PREC_INTERNETCONTROL"
94 ret
= setsockopt_ipv4_tos (eigrp_sock
, IPTOS_PREC_INTERNETCONTROL
);
97 int save_errno
= errno
;
98 if ( eigrpd_privs
.change (ZPRIVS_LOWER
) )
99 zlog_err ("eigrpd_sock_init: could not lower privs, %s",
100 safe_strerror (errno
) );
101 zlog_warn ("can't set sockopt IP_TOS %d to socket %d: %s",
102 tos
, eigrp_sock
, safe_strerror (save_errno
));
103 close (eigrp_sock
); /* Prevent sd leak. */
106 #else /* !IPTOS_PREC_INTERNETCONTROL */
107 #warning "IP_HDRINCL not available, nor is IPTOS_PREC_INTERNETCONTROL"
108 zlog_warn ("IP_HDRINCL option not available");
109 #endif /* IP_HDRINCL */
111 ret
= setsockopt_ifindex(AF_INET
, eigrp_sock
, 1);
114 zlog_warn("Can't set pktinfo option for fd %d", eigrp_sock
);
116 if (eigrpd_privs
.change(ZPRIVS_LOWER
))
118 zlog_err("eigrp_sock_init: could not lower privs, %s",
119 safe_strerror(errno
));
126 eigrp_adjust_sndbuflen(struct eigrp
* eigrp
, unsigned int buflen
)
129 /* Check if any work has to be done at all. */
130 if (eigrp
->maxsndbuflen
>= buflen
)
132 if (eigrpd_privs
.change(ZPRIVS_RAISE
))
133 zlog_err("%s: could not raise privs, %s", __func__
, safe_strerror(errno
));
135 /* Now we try to set SO_SNDBUF to what our caller has requested
136 * (the MTU of a newly added interface). However, if the OS has
137 * truncated the actual buffer size to somewhat less size, try
138 * to detect it and update our records appropriately. The OS
139 * may allocate more buffer space, than requested, this isn't
142 setsockopt_so_sendbuf(eigrp
->fd
, buflen
);
143 newbuflen
= getsockopt_so_sendbuf(eigrp
->fd
);
144 if (newbuflen
< 0 || newbuflen
< (int) buflen
)
145 zlog_warn("%s: tried to set SO_SNDBUF to %u, but got %d", __func__
, buflen
,
148 eigrp
->maxsndbuflen
= (unsigned int) newbuflen
;
150 zlog_warn("%s: failed to get SO_SNDBUF", __func__
);
151 if (eigrpd_privs
.change(ZPRIVS_LOWER
))
152 zlog_err("%s: could not lower privs, %s", __func__
, safe_strerror(errno
));
156 eigrp_if_ipmulticast(struct eigrp
*top
, struct prefix
*p
, unsigned int ifindex
)
164 /* Prevent receiving self-origined multicast packets. */
165 ret
= setsockopt(top
->fd
, IPPROTO_IP
, IP_MULTICAST_LOOP
, (void *) &val
, len
);
167 zlog_warn("can't setsockopt IP_MULTICAST_LOOP (0) for fd %d: %s", top
->fd
,
168 safe_strerror(errno
));
170 /* Explicitly set multicast ttl to 1 -- endo. */
172 ret
= setsockopt(top
->fd
, IPPROTO_IP
, IP_MULTICAST_TTL
, (void *) &val
, len
);
174 zlog_warn("can't setsockopt IP_MULTICAST_TTL (1) for fd %d: %s", top
->fd
,
175 safe_strerror(errno
));
177 ret
= setsockopt_ipv4_multicast_if(top
->fd
, p
->u
.prefix4
, ifindex
);
179 zlog_warn("can't setsockopt IP_MULTICAST_IF (fd %d, addr %s, "
180 "ifindex %u): %s", top
->fd
, inet_ntoa(p
->u
.prefix4
), ifindex
,
181 safe_strerror(errno
));
186 /* Join to the EIGRP multicast group. */
188 eigrp_if_add_allspfrouters(struct eigrp
*top
, struct prefix
*p
,
189 unsigned int ifindex
)
193 ret
= setsockopt_ipv4_multicast(top
->fd
, IP_ADD_MEMBERSHIP
, p
->u
.prefix4
,
194 htonl(EIGRP_MULTICAST_ADDRESS
), ifindex
);
196 zlog_warn("can't setsockopt IP_ADD_MEMBERSHIP (fd %d, addr %s, "
197 "ifindex %u, AllSPFRouters): %s; perhaps a kernel limit "
198 "on # of multicast group memberships has been exceeded?", top
->fd
,
199 inet_ntoa(p
->u
.prefix4
), ifindex
, safe_strerror(errno
));
201 zlog_debug("interface %s [%u] join EIGRP Multicast group.",
202 inet_ntoa(p
->u
.prefix4
), ifindex
);
208 eigrp_if_drop_allspfrouters(struct eigrp
*top
, struct prefix
*p
,
209 unsigned int ifindex
)
213 ret
= setsockopt_ipv4_multicast(top
->fd
, IP_DROP_MEMBERSHIP
, p
->u
.prefix4
,
214 htonl(EIGRP_MULTICAST_ADDRESS
), ifindex
);
216 zlog_warn("can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %s, "
217 "ifindex %u, AllSPFRouters): %s", top
->fd
, inet_ntoa(p
->u
.prefix4
),
218 ifindex
, safe_strerror(errno
));
220 zlog_debug("interface %s [%u] leave EIGRP Multicast group.",
221 inet_ntoa(p
->u
.prefix4
), ifindex
);
227 eigrp_network_set(struct eigrp
*eigrp
, struct prefix_ipv4
*p
)
229 struct route_node
*rn
;
230 struct interface
*ifp
;
231 struct listnode
*node
;
233 rn
= route_node_get(eigrp
->networks
, (struct prefix
*) p
);
236 /* There is already same network statement. */
237 route_unlock_node(rn
);
241 struct prefix_ipv4
*pref
= prefix_ipv4_new();
242 PREFIX_COPY_IPV4(pref
,p
);
243 rn
->info
= (void *) pref
;
245 /* Schedule Router ID Update. */
246 // if (eigrp->router_id == 0)
247 // eigrp_router_id_update(eigrp);
248 /* Run network config now. */
249 /* Get target interface. */
250 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT
), node
, ifp
))
252 zlog_debug("Setting up %s", ifp
->name
);
253 eigrp_network_run_interface(eigrp
, (struct prefix
*) p
, ifp
);
258 /* Check whether interface matches given network
259 * returns: 1, true. 0, false
262 eigrp_network_match_iface(const struct connected
*co
, const struct prefix
*net
)
264 /* new approach: more elegant and conceptually clean */
265 return prefix_match(net
, CONNECTED_PREFIX (co
));
269 eigrp_network_run_interface(struct eigrp
*eigrp
, struct prefix
*p
,
270 struct interface
*ifp
)
272 struct listnode
*cnode
;
273 struct connected
*co
;
275 /* if interface prefix is match specified prefix,
276 then create socket and join multicast group. */
277 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, cnode
, co
))
280 if (CHECK_FLAG (co
->flags
,ZEBRA_IFA_SECONDARY
))
283 if (p
->family
== co
->address
->family
284 && !eigrp_if_table_lookup(ifp
, co
->address
)
285 && eigrp_network_match_iface(co
, p
))
287 struct eigrp_interface
*ei
;
289 ei
= eigrp_if_new(eigrp
, ifp
, co
->address
);
292 ei
->params
= eigrp_lookup_if_params(ifp
, ei
->address
->u
.prefix4
);
294 /* Relate eigrp interface to eigrp instance. */
297 /* update network type as interface flag */
298 /* If network type is specified previously,
299 skip network type setting. */
300 ei
->type
= IF_DEF_PARAMS (ifp
)->type
;
302 /* if router_id is not configured, dont bring up
304 * eigrp_router_id_update() will call eigrp_if_update
305 * whenever r-id is configured instead.
307 if (if_is_operative(ifp
))
314 eigrp_if_update(struct interface
*ifp
)
316 struct listnode
*node
, *nnode
;
317 struct route_node
*rn
;
321 * In the event there are multiple eigrp autonymnous systems running,
322 * we need to check eac one and add the interface as approperate
324 for (ALL_LIST_ELEMENTS(eigrp_om
->eigrp
, node
, nnode
, eigrp
))
326 /* EIGRP must be on and Router-ID must be configured. */
327 if (!eigrp
|| eigrp
->router_id
== 0)
330 /* Run each network for this interface. */
331 for (rn
= route_top(eigrp
->networks
); rn
; rn
= route_next(rn
))
332 if (rn
->info
!= NULL
)
334 eigrp_network_run_interface(eigrp
, &rn
->p
, ifp
);
340 eigrp_network_unset(struct eigrp
*eigrp
, struct prefix_ipv4
*p
)
342 struct route_node
*rn
;
343 struct listnode
*node
, *nnode
;
344 struct eigrp_interface
*ei
;
347 rn
= route_node_lookup(eigrp
->networks
, (struct prefix
*) p
);
352 route_unlock_node (rn
);
354 if (!IPV4_ADDR_SAME (&pref
->u
.prefix4
, &p
->prefix
))
357 prefix_ipv4_free(rn
->info
);
359 route_unlock_node(rn
); /* initial reference */
361 /* Find interfaces that not configured already. */
362 for (ALL_LIST_ELEMENTS(eigrp
->eiflist
, node
, nnode
, ei
))
365 struct connected
*co
= ei
->connected
;
367 for (rn
= route_top(eigrp
->networks
); rn
; rn
= route_next(rn
))
369 if (rn
->info
== NULL
)
372 if (eigrp_network_match_iface(co
, &rn
->p
))
375 route_unlock_node(rn
);
382 eigrp_if_free(ei
, INTERFACE_DOWN_BY_VTY
);
390 eigrp_calculate_metrics(struct eigrp
*eigrp
, struct eigrp_metrics
*metric
)
392 uint64_t temp_metric
;
395 if(metric
->delay
== EIGRP_MAX_METRIC
)
396 return EIGRP_MAX_METRIC
;
398 // EIGRP Metric = {K1*BW+[(K2*BW)/(256-load)]+(K3*delay)}*{K5/(reliability+K4)}
400 if (eigrp
->k_values
[0])
401 temp_metric
+= (eigrp
->k_values
[0] * metric
->bandwith
);
402 if (eigrp
->k_values
[1])
403 temp_metric
+= ((eigrp
->k_values
[1] * metric
->bandwith
)
404 / (256 - metric
->load
));
405 if (eigrp
->k_values
[2])
406 temp_metric
+= (eigrp
->k_values
[2] * metric
->delay
);
407 if (eigrp
->k_values
[3] && !eigrp
->k_values
[4])
408 temp_metric
*= eigrp
->k_values
[3];
409 if (!eigrp
->k_values
[3] && eigrp
->k_values
[4])
410 temp_metric
*= (eigrp
->k_values
[4] / metric
->reliability
);
411 if (eigrp
->k_values
[3] && eigrp
->k_values
[4])
412 temp_metric
*= ((eigrp
->k_values
[4] / metric
->reliability
)
413 + eigrp
->k_values
[3]);
415 if (temp_metric
<= EIGRP_MAX_METRIC
)
416 return (u_int32_t
) temp_metric
;
418 return EIGRP_MAX_METRIC
;
422 eigrp_calculate_total_metrics(struct eigrp
*eigrp
,
423 struct eigrp_neighbor_entry
*entry
)
425 entry
->total_metric
= entry
->reported_metric
;
426 uint64_t temp_delay
= (uint64_t) entry
->total_metric
.delay
427 + (uint64_t) eigrp_delay_to_scaled (EIGRP_IF_PARAM (entry
->ei
, delay
));
428 entry
->total_metric
.delay
=
429 temp_delay
> EIGRP_MAX_METRIC
? EIGRP_MAX_METRIC
: (u_int32_t
) temp_delay
;
431 u_int32_t bw
= eigrp_bandwidth_to_scaled (EIGRP_IF_PARAM (entry
->ei
,bandwidth
));
432 entry
->total_metric
.bandwith
=
433 entry
->total_metric
.bandwith
> bw
? bw
: entry
->total_metric
.bandwith
;
435 return eigrp_calculate_metrics(eigrp
, &entry
->total_metric
);
439 eigrp_metrics_is_same(struct eigrp_metrics
*metric1
,
440 struct eigrp_metrics
*metric2
)
442 if ((metric1
->bandwith
== metric2
->bandwith
)
443 && (metric1
->delay
== metric2
->delay
)
444 && (metric1
->hop_count
== metric2
->hop_count
)
445 && (metric1
->load
== metric2
->load
)
446 && (metric1
->reliability
== metric2
->reliability
)
447 && (metric1
->mtu
[0] == metric2
->mtu
[0])
448 && (metric1
->mtu
[1] == metric2
->mtu
[1])
449 && (metric1
->mtu
[2] == metric2
->mtu
[2]))
452 return 0; // if different
456 eigrp_external_routes_refresh (struct eigrp
*eigrp
, int type
)