]> git.proxmox.com Git - mirror_frr.git/blame - eigrpd/eigrp_network.c
7.1: isisd: The RFC states that v6 addresses are limited to 16 in a hello … (#4475)
[mirror_frr.git] / eigrpd / eigrp_network.c
CommitLineData
7f57883e
DS
1/*
2 * EIGRP Network Related Functions.
3 * Copyright (C) 2013-2014
4 * Authors:
5 * Donnie Savage
6 * Jan Janovic
7 * Matej Perina
8 * Peter Orsag
9 * Peter Paluch
10 *
11 * This file is part of GNU Zebra.
12 *
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
16 * later version.
17 *
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.
22 *
896014f4
DL
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
7f57883e
DS
26 */
27
28#include <zebra.h>
29
30#include "thread.h"
31#include "linklist.h"
32#include "prefix.h"
33#include "if.h"
34#include "sockunion.h"
35#include "log.h"
36#include "sockopt.h"
37#include "privs.h"
38#include "table.h"
39#include "vty.h"
6ae7ed45 40#include "lib_errors.h"
7f57883e 41
7f57883e
DS
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"
50
952248db
DS
51static int eigrp_network_match_iface(const struct prefix *connected_prefix,
52 const struct prefix *prefix);
d62a17ae 53static void eigrp_network_run_interface(struct eigrp *, struct prefix *,
54 struct interface *);
7f57883e 55
d62a17ae 56int eigrp_sock_init(void)
7f57883e 57{
d62a17ae 58 int eigrp_sock;
029a775e 59 int ret;
60#ifdef IP_HDRINCL
61 int hincl = 1;
62#endif
d62a17ae 63
6bb30c2c
DL
64 frr_elevate_privs(&eigrpd_privs) {
65 eigrp_sock = socket(AF_INET, SOCK_RAW, IPPROTO_EIGRPIGP);
66 if (eigrp_sock < 0) {
67 zlog_err("eigrp_read_sock_init: socket: %s",
68 safe_strerror(errno));
69 exit(1);
70 }
7f57883e
DS
71
72#ifdef IP_HDRINCL
6bb30c2c
DL
73 /* we will include IP header with packet */
74 ret = setsockopt(eigrp_sock, IPPROTO_IP, IP_HDRINCL, &hincl,
75 sizeof(hincl));
76 if (ret < 0) {
77 zlog_warn("Can't set IP_HDRINCL option for fd %d: %s",
78 eigrp_sock, safe_strerror(errno));
79 }
d62a17ae 80#elif defined(IPTOS_PREC_INTERNETCONTROL)
7f57883e
DS
81#warning "IP_HDRINCL not available on this system"
82#warning "using IPTOS_PREC_INTERNETCONTROL"
6bb30c2c
DL
83 ret = setsockopt_ipv4_tos(eigrp_sock,
84 IPTOS_PREC_INTERNETCONTROL);
85 if (ret < 0) {
86 zlog_warn("can't set sockopt IP_TOS %d to socket %d: %s",
87 tos, eigrp_sock, safe_strerror(errno));
88 close(eigrp_sock); /* Prevent sd leak. */
89 return ret;
90 }
7f57883e
DS
91#else /* !IPTOS_PREC_INTERNETCONTROL */
92#warning "IP_HDRINCL not available, nor is IPTOS_PREC_INTERNETCONTROL"
6bb30c2c 93 zlog_warn("IP_HDRINCL option not available");
7f57883e
DS
94#endif /* IP_HDRINCL */
95
6bb30c2c
DL
96 ret = setsockopt_ifindex(AF_INET, eigrp_sock, 1);
97 if (ret < 0)
98 zlog_warn("Can't set pktinfo option for fd %d",
99 eigrp_sock);
d62a17ae 100 }
7f57883e 101
d62a17ae 102 return eigrp_sock;
7f57883e
DS
103}
104
d62a17ae 105void eigrp_adjust_sndbuflen(struct eigrp *eigrp, unsigned int buflen)
7f57883e 106{
d62a17ae 107 int newbuflen;
108 /* Check if any work has to be done at all. */
109 if (eigrp->maxsndbuflen >= buflen)
110 return;
d62a17ae 111
112 /* Now we try to set SO_SNDBUF to what our caller has requested
113 * (the MTU of a newly added interface). However, if the OS has
114 * truncated the actual buffer size to somewhat less size, try
115 * to detect it and update our records appropriately. The OS
116 * may allocate more buffer space, than requested, this isn't
117 * a error.
118 */
338b8e91
RW
119 setsockopt_so_sendbuf(eigrp->fd, buflen);
120 newbuflen = getsockopt_so_sendbuf(eigrp->fd);
121 if (newbuflen < 0 || newbuflen < (int)buflen)
122 zlog_warn("%s: tried to set SO_SNDBUF to %u, but got %d",
123 __func__, buflen, newbuflen);
124 if (newbuflen >= 0)
125 eigrp->maxsndbuflen = (unsigned int)newbuflen;
126 else
127 zlog_warn("%s: failed to get SO_SNDBUF", __func__);
7f57883e
DS
128}
129
d62a17ae 130int eigrp_if_ipmulticast(struct eigrp *top, struct prefix *p,
131 unsigned int ifindex)
7f57883e 132{
d7c0a89a 133 uint8_t val;
d62a17ae 134 int ret, len;
135
136 val = 0;
137 len = sizeof(val);
138
139 /* Prevent receiving self-origined multicast packets. */
140 ret = setsockopt(top->fd, IPPROTO_IP, IP_MULTICAST_LOOP, (void *)&val,
141 len);
142 if (ret < 0)
143 zlog_warn(
144 "can't setsockopt IP_MULTICAST_LOOP (0) for fd %d: %s",
145 top->fd, safe_strerror(errno));
146
147 /* Explicitly set multicast ttl to 1 -- endo. */
148 val = 1;
149 ret = setsockopt(top->fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&val,
150 len);
151 if (ret < 0)
152 zlog_warn("can't setsockopt IP_MULTICAST_TTL (1) for fd %d: %s",
153 top->fd, safe_strerror(errno));
154
155 ret = setsockopt_ipv4_multicast_if(top->fd, p->u.prefix4, ifindex);
156 if (ret < 0)
157 zlog_warn(
158 "can't setsockopt IP_MULTICAST_IF (fd %d, addr %s, "
159 "ifindex %u): %s",
160 top->fd, inet_ntoa(p->u.prefix4), ifindex,
161 safe_strerror(errno));
162
163 return ret;
7f57883e
DS
164}
165
166/* Join to the EIGRP multicast group. */
d62a17ae 167int eigrp_if_add_allspfrouters(struct eigrp *top, struct prefix *p,
168 unsigned int ifindex)
7f57883e 169{
d62a17ae 170 int ret;
171
172 ret = setsockopt_ipv4_multicast(
173 top->fd, IP_ADD_MEMBERSHIP, p->u.prefix4,
174 htonl(EIGRP_MULTICAST_ADDRESS), ifindex);
175 if (ret < 0)
176 zlog_warn(
177 "can't setsockopt IP_ADD_MEMBERSHIP (fd %d, addr %s, "
178 "ifindex %u, AllSPFRouters): %s; perhaps a kernel limit "
179 "on # of multicast group memberships has been exceeded?",
180 top->fd, inet_ntoa(p->u.prefix4), ifindex,
181 safe_strerror(errno));
182 else
183 zlog_debug("interface %s [%u] join EIGRP Multicast group.",
184 inet_ntoa(p->u.prefix4), ifindex);
185
186 return ret;
7f57883e
DS
187}
188
d62a17ae 189int eigrp_if_drop_allspfrouters(struct eigrp *top, struct prefix *p,
190 unsigned int ifindex)
7f57883e 191{
d62a17ae 192 int ret;
193
194 ret = setsockopt_ipv4_multicast(
195 top->fd, IP_DROP_MEMBERSHIP, p->u.prefix4,
196 htonl(EIGRP_MULTICAST_ADDRESS), ifindex);
197 if (ret < 0)
198 zlog_warn(
199 "can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %s, "
200 "ifindex %u, AllSPFRouters): %s",
201 top->fd, inet_ntoa(p->u.prefix4), ifindex,
202 safe_strerror(errno));
203 else
204 zlog_debug("interface %s [%u] leave EIGRP Multicast group.",
205 inet_ntoa(p->u.prefix4), ifindex);
206
207 return ret;
7f57883e
DS
208}
209
cd6c066e 210int eigrp_network_set(struct eigrp *eigrp, struct prefix *p)
7f57883e 211{
f4e14fdb 212 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
d62a17ae 213 struct route_node *rn;
214 struct interface *ifp;
d62a17ae 215
216 rn = route_node_get(eigrp->networks, (struct prefix *)p);
217 if (rn->info) {
218 /* There is already same network statement. */
219 route_unlock_node(rn);
220 return 0;
221 }
222
a96029f8 223 struct prefix *pref = prefix_new();
d62a17ae 224 PREFIX_COPY_IPV4(pref, p);
225 rn->info = (void *)pref;
226
227 /* Schedule Router ID Update. */
900e2d42 228 if (eigrp->router_id.s_addr == 0)
d62a17ae 229 eigrp_router_id_update(eigrp);
230 /* Run network config now. */
231 /* Get target interface. */
451fda4f 232 FOR_ALL_INTERFACES (vrf, ifp) {
d62a17ae 233 zlog_debug("Setting up %s", ifp->name);
a96029f8 234 eigrp_network_run_interface(eigrp, p, ifp);
d62a17ae 235 }
236 return 1;
7f57883e
DS
237}
238
239/* Check whether interface matches given network
240 * returns: 1, true. 0, false
241 */
952248db 242static int eigrp_network_match_iface(const struct prefix *co_prefix,
d62a17ae 243 const struct prefix *net)
7f57883e 244{
d62a17ae 245 /* new approach: more elegant and conceptually clean */
952248db 246 return prefix_match_network_statement(net, co_prefix);
7f57883e
DS
247}
248
d62a17ae 249static void eigrp_network_run_interface(struct eigrp *eigrp, struct prefix *p,
250 struct interface *ifp)
7f57883e 251{
b748db67 252 struct eigrp_interface *ei;
d62a17ae 253 struct listnode *cnode;
254 struct connected *co;
255
256 /* if interface prefix is match specified prefix,
257 then create socket and join multicast group. */
258 for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, co)) {
259
260 if (CHECK_FLAG(co->flags, ZEBRA_IFA_SECONDARY))
261 continue;
262
996c9314 263 if (p->family == co->address->family && !ifp->info
952248db 264 && eigrp_network_match_iface(co->address, p)) {
d62a17ae 265
266 ei = eigrp_if_new(eigrp, ifp, co->address);
d62a17ae 267
d62a17ae 268 /* Relate eigrp interface to eigrp instance. */
269 ei->eigrp = eigrp;
270
d62a17ae 271 /* if router_id is not configured, dont bring up
272 * interfaces.
273 * eigrp_router_id_update() will call eigrp_if_update
274 * whenever r-id is configured instead.
275 */
276 if (if_is_operative(ifp))
277 eigrp_if_up(ei);
278 }
279 }
7f57883e
DS
280}
281
d62a17ae 282void eigrp_if_update(struct interface *ifp)
7f57883e 283{
d62a17ae 284 struct listnode *node, *nnode;
285 struct route_node *rn;
286 struct eigrp *eigrp;
287
288 /*
289 * In the event there are multiple eigrp autonymnous systems running,
290 * we need to check eac one and add the interface as approperate
291 */
292 for (ALL_LIST_ELEMENTS(eigrp_om->eigrp, node, nnode, eigrp)) {
293 /* EIGRP must be on and Router-ID must be configured. */
5edc2cf3 294 if (eigrp->router_id.s_addr == 0)
d62a17ae 295 continue;
296
297 /* Run each network for this interface. */
298 for (rn = route_top(eigrp->networks); rn; rn = route_next(rn))
299 if (rn->info != NULL) {
300 eigrp_network_run_interface(eigrp, &rn->p, ifp);
301 }
302 }
7f57883e
DS
303}
304
cd6c066e 305int eigrp_network_unset(struct eigrp *eigrp, struct prefix *p)
7f57883e 306{
d62a17ae 307 struct route_node *rn;
308 struct listnode *node, *nnode;
309 struct eigrp_interface *ei;
310 struct prefix *pref;
311
cd6c066e 312 rn = route_node_lookup(eigrp->networks, p);
d62a17ae 313 if (rn == NULL)
314 return 0;
315
316 pref = rn->info;
317 route_unlock_node(rn);
318
cd6c066e 319 if (!IPV4_ADDR_SAME(&pref->u.prefix4, &p->u.prefix4))
d62a17ae 320 return 0;
321
322 prefix_ipv4_free(rn->info);
323 rn->info = NULL;
324 route_unlock_node(rn); /* initial reference */
325
326 /* Find interfaces that not configured already. */
327 for (ALL_LIST_ELEMENTS(eigrp->eiflist, node, nnode, ei)) {
952248db 328 bool found = false;
d62a17ae 329
330 for (rn = route_top(eigrp->networks); rn; rn = route_next(rn)) {
331 if (rn->info == NULL)
332 continue;
333
b245781a 334 if (eigrp_network_match_iface(&ei->address, &rn->p)) {
952248db 335 found = true;
d62a17ae 336 route_unlock_node(rn);
337 break;
338 }
339 }
340
952248db 341 if (!found) {
d62a17ae 342 eigrp_if_free(ei, INTERFACE_DOWN_BY_VTY);
343 }
344 }
345
346 return 1;
7f57883e
DS
347}
348
d7c0a89a
QY
349uint32_t eigrp_calculate_metrics(struct eigrp *eigrp,
350 struct eigrp_metrics metric)
7f57883e 351{
d62a17ae 352 uint64_t temp_metric;
353 temp_metric = 0;
354
355 if (metric.delay == EIGRP_MAX_METRIC)
356 return EIGRP_MAX_METRIC;
357
358 // EIGRP Metric =
359 // {K1*BW+[(K2*BW)/(256-load)]+(K3*delay)}*{K5/(reliability+K4)}
360
361 if (eigrp->k_values[0])
b1968f83 362 temp_metric += (eigrp->k_values[0] * metric.bandwidth);
d62a17ae 363 if (eigrp->k_values[1])
b1968f83 364 temp_metric += ((eigrp->k_values[1] * metric.bandwidth)
d62a17ae 365 / (256 - metric.load));
366 if (eigrp->k_values[2])
367 temp_metric += (eigrp->k_values[2] * metric.delay);
368 if (eigrp->k_values[3] && !eigrp->k_values[4])
369 temp_metric *= eigrp->k_values[3];
370 if (!eigrp->k_values[3] && eigrp->k_values[4])
371 temp_metric *= (eigrp->k_values[4] / metric.reliability);
372 if (eigrp->k_values[3] && eigrp->k_values[4])
373 temp_metric *= ((eigrp->k_values[4] / metric.reliability)
374 + eigrp->k_values[3]);
375
376 if (temp_metric <= EIGRP_MAX_METRIC)
d7c0a89a 377 return (uint32_t)temp_metric;
d62a17ae 378 else
379 return EIGRP_MAX_METRIC;
7f57883e
DS
380}
381
d7c0a89a
QY
382uint32_t eigrp_calculate_total_metrics(struct eigrp *eigrp,
383 struct eigrp_nexthop_entry *entry)
7f57883e 384{
b748db67
DS
385 struct eigrp_interface *ei = entry->ei;
386
d62a17ae 387 entry->total_metric = entry->reported_metric;
996c9314
LB
388 uint64_t temp_delay =
389 (uint64_t)entry->total_metric.delay
390 + (uint64_t)eigrp_delay_to_scaled(ei->params.delay);
d62a17ae 391 entry->total_metric.delay = temp_delay > EIGRP_MAX_METRIC
392 ? EIGRP_MAX_METRIC
d7c0a89a 393 : (uint32_t)temp_delay;
d62a17ae 394
d7c0a89a 395 uint32_t bw = eigrp_bandwidth_to_scaled(ei->params.bandwidth);
b1968f83 396 entry->total_metric.bandwidth = entry->total_metric.bandwidth > bw
996c9314
LB
397 ? bw
398 : entry->total_metric.bandwidth;
d62a17ae 399
400 return eigrp_calculate_metrics(eigrp, entry->total_metric);
7f57883e
DS
401}
402
d7c0a89a
QY
403uint8_t eigrp_metrics_is_same(struct eigrp_metrics metric1,
404 struct eigrp_metrics metric2)
7f57883e 405{
b1968f83 406 if ((metric1.bandwidth == metric2.bandwidth)
d62a17ae 407 && (metric1.delay == metric2.delay)
408 && (metric1.hop_count == metric2.hop_count)
409 && (metric1.load == metric2.load)
410 && (metric1.reliability == metric2.reliability)
411 && (metric1.mtu[0] == metric2.mtu[0])
412 && (metric1.mtu[1] == metric2.mtu[1])
413 && (metric1.mtu[2] == metric2.mtu[2]))
414 return 1;
415
416 return 0; // if different
7f57883e 417}
f9e5c9ca 418
d62a17ae 419void eigrp_external_routes_refresh(struct eigrp *eigrp, int type)
7f57883e 420{
7f57883e 421}