]> git.proxmox.com Git - mirror_frr.git/blame - eigrpd/eigrp_interface.c
*: make consistent & update GPLv2 file headers
[mirror_frr.git] / eigrpd / eigrp_interface.c
CommitLineData
7f57883e
DS
1/*
2 * EIGRP Interface Functions.
3 * Copyright (C) 2013-2016
4 * Authors:
5 * Donnie Savage
6 * Jan Janovic
7 * Matej Perina
8 * Peter Orsag
9 * Peter Paluch
10 * Frantisek Gazo
11 * Tomas Hvorkovy
12 * Martin Kontsek
13 * Lukas Koribsky
14 *
15 * This file is part of GNU Zebra.
16 *
17 * GNU Zebra is free software; you can redistribute it and/or modify it
18 * under the terms of the GNU General Public License as published by the
19 * Free Software Foundation; either version 2, or (at your option) any
20 * later version.
21 *
22 * GNU Zebra is distributed in the hope that it will be useful, but
23 * WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * General Public License for more details.
26 *
896014f4
DL
27 * You should have received a copy of the GNU General Public License along
28 * with this program; see the file COPYING; if not, write to the Free Software
29 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
7f57883e
DS
30 */
31
32#include <zebra.h>
33
34#include "thread.h"
35#include "linklist.h"
36#include "prefix.h"
37#include "if.h"
38#include "table.h"
39#include "memory.h"
40#include "command.h"
41#include "stream.h"
42#include "log.h"
43#include "keychain.h"
44#include "vrf.h"
45
46#include "eigrpd/eigrp_structs.h"
47#include "eigrpd/eigrpd.h"
48#include "eigrpd/eigrp_interface.h"
49#include "eigrpd/eigrp_neighbor.h"
50#include "eigrpd/eigrp_packet.h"
51#include "eigrpd/eigrp_zebra.h"
52#include "eigrpd/eigrp_vty.h"
53#include "eigrpd/eigrp_network.h"
54#include "eigrpd/eigrp_topology.h"
55#include "eigrpd/eigrp_memory.h"
56
57static void
58eigrp_delete_from_if (struct interface *, struct eigrp_interface *);
59
60static void
61eigrp_add_to_if (struct interface *ifp, struct eigrp_interface *ei)
62{
63 struct route_node *rn;
64 struct prefix p;
65
66 p = *ei->address;
67 p.prefixlen = IPV4_MAX_PREFIXLEN;
68
69 rn = route_node_get (IF_OIFS (ifp), &p);
70 /* rn->info should either be NULL or equal to this ei
71 * as route_node_get may return an existing node
72 */
73 assert (!rn->info || rn->info == ei);
74 rn->info = ei;
75}
76
77struct eigrp_interface *
78eigrp_if_new (struct eigrp *eigrp, struct interface *ifp, struct prefix *p)
79{
80 struct eigrp_interface *ei;
81 int i;
82
83 if ((ei = eigrp_if_table_lookup (ifp, p)) == NULL)
84 {
85 ei = XCALLOC (MTYPE_EIGRP_IF, sizeof (struct eigrp_interface));
86 memset (ei, 0, sizeof (struct eigrp_interface));
87 }
88 else
89 return ei;
90
91 /* Set zebra interface pointer. */
92 ei->ifp = ifp;
93 ei->address = p;
94
95 eigrp_add_to_if (ifp, ei);
96 listnode_add (eigrp->eiflist, ei);
97
98 ei->type = EIGRP_IFTYPE_BROADCAST;
99
100 /* Initialize neighbor list. */
101 ei->nbrs = list_new ();
102
103 ei->crypt_seqnum = time (NULL);
104
105 /* Initialize lists */
106 for (i = 0; i < EIGRP_FILTER_MAX; i++)
107 {
f9e5c9ca
DS
108 ei->list[i] = NULL;
109 ei->prefix[i] = NULL;
110 ei->routemap[i] = NULL;
7f57883e
DS
111 }
112
113 return ei;
114}
115
116/* lookup ei for specified prefix/ifp */
117struct eigrp_interface *
118eigrp_if_table_lookup (struct interface *ifp, struct prefix *prefix)
119{
120 struct prefix p;
121 struct route_node *rn;
122 struct eigrp_interface *rninfo = NULL;
123
124 p = *prefix;
125 p.prefixlen = IPV4_MAX_PREFIXLEN;
126
127 /* route_node_get implicitly locks */
128 if ((rn = route_node_lookup (IF_OIFS (ifp), &p)))
129 {
130 rninfo = (struct eigrp_interface *) rn->info;
131 route_unlock_node (rn);
132 }
133
134 return rninfo;
135}
136
137int
138eigrp_if_delete_hook (struct interface *ifp)
139{
7f57883e
DS
140 struct route_node *rn;
141
142 route_table_finish (IF_OIFS (ifp));
143
144 for (rn = route_top (IF_OIFS_PARAMS (ifp)); rn; rn = route_next (rn))
145 if (rn->info)
146 eigrp_del_if_params (rn->info);
147 route_table_finish (IF_OIFS_PARAMS (ifp));
148
149 XFREE (MTYPE_EIGRP_IF_INFO, ifp->info);
150 ifp->info = NULL;
151
152 return 0;
153}
154
155struct list *eigrp_iflist;
156
157void
158eigrp_if_init ()
159{
160 /* Initialize Zebra interface data structure. */
161 if_add_hook (IF_NEW_HOOK, eigrp_if_new_hook);
162 if_add_hook (IF_DELETE_HOOK, eigrp_if_delete_hook);
163}
164
165int
166eigrp_if_new_hook (struct interface *ifp)
167{
168 int rc = 0;
169
170 ifp->info = XCALLOC (MTYPE_EIGRP_IF_INFO, sizeof (struct eigrp_if_info));
171
172 IF_OIFS (ifp) = route_table_init ();
173 IF_OIFS_PARAMS (ifp) = route_table_init ();
174
175 IF_DEF_PARAMS (ifp) = eigrp_new_if_params ();
176
177 SET_IF_PARAM (IF_DEF_PARAMS (ifp), v_hello);
178 IF_DEF_PARAMS (ifp)->v_hello = (u_int32_t) EIGRP_HELLO_INTERVAL_DEFAULT;
179
180 SET_IF_PARAM (IF_DEF_PARAMS (ifp), v_wait);
181 IF_DEF_PARAMS (ifp)->v_wait = (u_int16_t) EIGRP_HOLD_INTERVAL_DEFAULT;
182
183 SET_IF_PARAM (IF_DEF_PARAMS (ifp), bandwidth);
184 IF_DEF_PARAMS (ifp)->bandwidth = (u_int32_t) EIGRP_BANDWIDTH_DEFAULT;
185
186 SET_IF_PARAM (IF_DEF_PARAMS (ifp), delay);
187 IF_DEF_PARAMS (ifp)->delay = (u_int32_t) EIGRP_DELAY_DEFAULT;
188
189 SET_IF_PARAM (IF_DEF_PARAMS (ifp), reliability);
190 IF_DEF_PARAMS (ifp)->reliability = (u_char) EIGRP_RELIABILITY_DEFAULT;
191
192 SET_IF_PARAM (IF_DEF_PARAMS (ifp), load);
193 IF_DEF_PARAMS (ifp)->load = (u_char) EIGRP_LOAD_DEFAULT;
194
195 SET_IF_PARAM (IF_DEF_PARAMS (ifp), auth_type);
196 IF_DEF_PARAMS (ifp)->auth_type = EIGRP_AUTH_TYPE_NONE;
197
198 SET_IF_PARAM (IF_DEF_PARAMS (ifp), auth_keychain);
199 IF_DEF_PARAMS (ifp)->auth_keychain= NULL;
200
201 return rc;
202}
203
204struct eigrp_if_params *
205eigrp_new_if_params (void)
206{
207 struct eigrp_if_params *eip;
208
209 eip = XCALLOC (MTYPE_EIGRP_IF_PARAMS, sizeof (struct eigrp_if_params));
210 if (!eip)
211 return NULL;
212
213 UNSET_IF_PARAM (eip, passive_interface);
214 UNSET_IF_PARAM (eip, v_hello);
215 UNSET_IF_PARAM (eip, v_wait);
216 UNSET_IF_PARAM (eip, bandwidth);
217 UNSET_IF_PARAM (eip, delay);
218 UNSET_IF_PARAM (eip, reliability);
219 UNSET_IF_PARAM (eip, load);
220 UNSET_IF_PARAM (eip, auth_keychain);
221 UNSET_IF_PARAM (eip, auth_type);
222
7f57883e
DS
223 return eip;
224}
225
226void
227eigrp_del_if_params (struct eigrp_if_params *eip)
228{
229 if(eip->auth_keychain)
230 free(eip->auth_keychain);
231
232 XFREE (MTYPE_EIGRP_IF_PARAMS, eip);
233}
234
235struct eigrp_if_params *
236eigrp_lookup_if_params (struct interface *ifp, struct in_addr addr)
237{
238 struct prefix_ipv4 p;
239 struct route_node *rn;
240
241 p.family = AF_INET;
242 p.prefixlen = IPV4_MAX_PREFIXLEN;
243 p.prefix = addr;
244
245 rn = route_node_lookup (IF_OIFS_PARAMS (ifp), (struct prefix*) &p);
246
247 if (rn)
248 {
249 route_unlock_node (rn);
250 return rn->info;
251 }
252
253 return NULL;
254}
255
256int
257eigrp_if_up (struct eigrp_interface *ei)
258{
259 struct eigrp_prefix_entry *pe;
260 struct eigrp_neighbor_entry *ne;
261 struct eigrp_metrics metric;
262 struct eigrp_interface *ei2;
263 struct listnode *node, *nnode;
264 struct eigrp *eigrp = eigrp_lookup ();
265
266 if (ei == NULL)
267 return 0;
268
269 if (eigrp != NULL)
270 eigrp_adjust_sndbuflen (eigrp, ei->ifp->mtu);
271 else
272 zlog_warn ("%s: eigrp_lookup () returned NULL", __func__);
273 eigrp_if_stream_set (ei);
274
275 /* Set multicast memberships appropriately for new state. */
276 eigrp_if_set_multicast (ei);
277
c94671b8 278 thread_add_event(master, eigrp_hello_timer, ei, (1), NULL);
7f57883e
DS
279
280 /*Prepare metrics*/
281 metric.bandwith = eigrp_bandwidth_to_scaled (EIGRP_IF_PARAM (ei,bandwidth));
282 metric.delay = eigrp_delay_to_scaled (EIGRP_IF_PARAM (ei,delay));
283 metric.load = EIGRP_IF_PARAM (ei,load);
284 metric.reliability = EIGRP_IF_PARAM (ei,reliability);
285 metric.mtu[0] = 0xDC;
286 metric.mtu[1] = 0x05;
287 metric.mtu[2] = 0x00;
288 metric.hop_count = 0;
289 metric.flags = 0;
290 metric.tag = 0;
291
292 /*Add connected entry to topology table*/
293
294 struct prefix_ipv4 *dest_addr = prefix_ipv4_new ();
295
296 dest_addr->family = AF_INET;
297 dest_addr->prefix = ei->connected->address->u.prefix4;
298 dest_addr->prefixlen = ei->connected->address->prefixlen;
299 apply_mask_ipv4 (dest_addr);
300 pe = eigrp_topology_table_lookup_ipv4 (eigrp->topology_table, dest_addr);
301
302 if (pe == NULL)
303 {
304 pe = eigrp_prefix_entry_new ();
305 pe->serno = eigrp->serno;
306 pe->destination_ipv4 = dest_addr;
307 pe->af = AF_INET;
308 pe->nt = EIGRP_TOPOLOGY_TYPE_CONNECTED;
309
310 pe->state = EIGRP_FSM_STATE_PASSIVE;
311 pe->fdistance = eigrp_calculate_metrics (eigrp, &metric);
312 pe->req_action |= EIGRP_FSM_NEED_UPDATE;
313 eigrp_prefix_entry_add (eigrp->topology_table, pe);
314 listnode_add(eigrp->topology_changes_internalIPV4, pe);
315 }
316 ne = eigrp_neighbor_entry_new ();
317 ne->ei = ei;
318 ne->reported_metric = metric;
319 ne->total_metric = metric;
320 ne->distance = eigrp_calculate_metrics (eigrp, &metric);
321 ne->reported_distance = 0;
322 ne->prefix = pe;
323 ne->adv_router = eigrp->neighbor_self;
324 ne->flags = EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG;
325 eigrp_neighbor_entry_add (pe, ne);
326
327 for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei2))
328 {
329 if (ei2->nbrs->count != 0)
330 {
331 eigrp_update_send (ei2);
332 }
333 }
334
335 pe->req_action &= ~EIGRP_FSM_NEED_UPDATE;
336 listnode_delete(eigrp->topology_changes_internalIPV4, pe);
337
338 return 1;
339}
340
341int
342eigrp_if_down (struct eigrp_interface *ei)
343{
344 struct listnode *node, *nnode;
345 struct eigrp_neighbor *nbr;
346
347 if (ei == NULL)
348 return 0;
349
350 /* Shutdown packet reception and sending */
351 if(ei->t_hello)
352 THREAD_OFF (ei->t_hello);
353
354 eigrp_if_stream_unset (ei);
355
356 /*Set infinite metrics to routes learned by this interface and start query process*/
357 for (ALL_LIST_ELEMENTS (ei->nbrs, node, nnode, nbr))
358 {
359 eigrp_nbr_delete(nbr);
360 }
361
362 return 1;
363}
364
365void
366eigrp_if_stream_set (struct eigrp_interface *ei)
367{
368 /* set output fifo queue. */
369 if (ei->obuf == NULL)
370 ei->obuf = eigrp_fifo_new ();
371}
372
373void
374eigrp_if_stream_unset (struct eigrp_interface *ei)
375{
376 struct eigrp *eigrp = ei->eigrp;
377
378 if (ei->obuf)
379 {
380 eigrp_fifo_free (ei->obuf);
381 ei->obuf = NULL;
382
383 if (ei->on_write_q)
384 {
385 listnode_delete (eigrp->oi_write_q, ei);
386 if (list_isempty (eigrp->oi_write_q))
387 thread_cancel (eigrp->t_write);
388 ei->on_write_q = 0;
389 }
390 }
391}
392
393void
394eigrp_if_set_multicast (struct eigrp_interface *ei)
395{
396 if ((EIGRP_IF_PASSIVE_STATUS (ei) == EIGRP_IF_ACTIVE))
397 {
398 /* The interface should belong to the EIGRP-all-routers group. */
399 if (!EI_MEMBER_CHECK (ei, MEMBER_ALLROUTERS)
400 && (eigrp_if_add_allspfrouters (ei->eigrp, ei->address,
f9e5c9ca 401 ei->ifp->ifindex) >= 0))
7f57883e
DS
402 /* Set the flag only if the system call to join succeeded. */
403 EI_MEMBER_JOINED (ei, MEMBER_ALLROUTERS);
404 }
405 else
406 {
407 /* The interface should NOT belong to the EIGRP-all-routers group. */
408 if (EI_MEMBER_CHECK (ei, MEMBER_ALLROUTERS))
409 {
410 /* Only actually drop if this is the last reference */
411 if (EI_MEMBER_COUNT (ei, MEMBER_ALLROUTERS) == 1)
412 eigrp_if_drop_allspfrouters (ei->eigrp, ei->address,
f9e5c9ca 413 ei->ifp->ifindex);
7f57883e 414 /* Unset the flag regardless of whether the system call to leave
f9e5c9ca
DS
415 the group succeeded, since it's much safer to assume that
416 we are not a member. */
7f57883e
DS
417 EI_MEMBER_LEFT (ei, MEMBER_ALLROUTERS);
418 }
419 }
420}
421
422u_char
423eigrp_default_iftype (struct interface *ifp)
424{
425 if (if_is_pointopoint (ifp))
426 return EIGRP_IFTYPE_POINTOPOINT;
427 else if (if_is_loopback (ifp))
428 return EIGRP_IFTYPE_LOOPBACK;
429 else
430 return EIGRP_IFTYPE_BROADCAST;
431}
432
433void
434eigrp_if_free (struct eigrp_interface *ei, int source)
435{
43250446
DS
436 struct prefix_ipv4 dest_addr;
437 struct eigrp_prefix_entry *pe;
438 struct eigrp *eigrp = eigrp_lookup ();
7f57883e
DS
439
440 if (source == INTERFACE_DOWN_BY_VTY)
441 {
442 THREAD_OFF (ei->t_hello);
443 eigrp_hello_send(ei,EIGRP_HELLO_GRACEFUL_SHUTDOWN, NULL);
444 }
445
43250446
DS
446 dest_addr.family = AF_INET;
447 dest_addr.prefix = ei->connected->address->u.prefix4;
448 dest_addr.prefixlen = ei->connected->address->prefixlen;
449 apply_mask_ipv4(&dest_addr);
450 pe = eigrp_topology_table_lookup_ipv4 (eigrp->topology_table, &dest_addr);
451 if (pe)
452 eigrp_prefix_entry_delete (eigrp->topology_table, pe);
453
7f57883e
DS
454 eigrp_if_down (ei);
455
456 list_delete (ei->nbrs);
457 eigrp_delete_from_if (ei->ifp, ei);
458 listnode_delete (ei->eigrp->eiflist, ei);
459
460 thread_cancel_event (master, ei);
461
462 memset (ei, 0, sizeof (*ei));
463 XFREE (MTYPE_EIGRP_IF, ei);
464}
465
466static void
467eigrp_delete_from_if (struct interface *ifp, struct eigrp_interface *ei)
468{
469 struct route_node *rn;
470 struct prefix p;
471
472 p = *ei->address;
473 p.prefixlen = IPV4_MAX_PREFIXLEN;
474
475 rn = route_node_lookup (IF_OIFS (ei->ifp), &p);
476 assert (rn);
477 assert (rn->info);
478 rn->info = NULL;
479 route_unlock_node (rn);
480 route_unlock_node (rn);
481}
482
483/* Simulate down/up on the interface. This is needed, for example, when
f9e5c9ca 484 the MTU changes. */
7f57883e
DS
485void
486eigrp_if_reset (struct interface *ifp)
487{
488 struct route_node *rn;
489
490 for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
491 {
492 struct eigrp_interface *ei;
493
494 if ((ei = rn->info) == NULL)
495 continue;
496
497 eigrp_if_down (ei);
498 eigrp_if_up (ei);
499 }
500}
501
502struct eigrp_interface *
503eigrp_if_lookup_by_local_addr (struct eigrp *eigrp, struct interface *ifp,
f9e5c9ca 504 struct in_addr address)
7f57883e
DS
505{
506 struct listnode *node;
507 struct eigrp_interface *ei;
508
509 for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei))
510 {
511 if (ifp && ei->ifp != ifp)
512 continue;
513
514 if (IPV4_ADDR_SAME (&address, &ei->address->u.prefix4))
515 return ei;
516 }
517
518 return NULL;
519}
520
521/**
522 * @fn eigrp_if_lookup_by_name
523 *
524 * @param[in] eigrp EIGRP process
525 * @param[in] if_name Name of the interface
526 *
527 * @return struct eigrp_interface *
528 *
529 * @par
530 * Function is used for lookup interface by name.
531 */
532struct eigrp_interface *
533eigrp_if_lookup_by_name (struct eigrp *eigrp, const char *if_name)
534{
f9e5c9ca
DS
535 struct eigrp_interface *ei;
536 struct listnode *node;
537
538 /* iterate over all eigrp interfaces */
539 for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei))
540 {
541 /* compare int name with eigrp interface's name */
542 if(strcmp(ei->ifp->name, if_name) == 0)
543 {
544 return ei;
545 }
546 }
547
548 return NULL;
7f57883e
DS
549}
550
551/* determine receiving interface by ifp and source address */
552struct eigrp_interface *
553eigrp_if_lookup_recv_if (struct eigrp *eigrp, struct in_addr src,
f9e5c9ca 554 struct interface *ifp)
7f57883e
DS
555{
556 struct route_node *rn;
557 struct prefix_ipv4 addr;
558 struct eigrp_interface *ei, *match;
559
560 addr.family = AF_INET;
561 addr.prefix = src;
562 addr.prefixlen = IPV4_MAX_BITLEN;
563
564 match = NULL;
565
566 for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
567 {
568 ei = rn->info;
569
570 if (!ei) /* oi can be NULL for PtP aliases */
571 continue;
572
573 if (if_is_loopback (ei->ifp))
574 continue;
575
576 if (prefix_match (CONNECTED_PREFIX (ei->connected),
f9e5c9ca 577 (struct prefix *) &addr))
7f57883e
DS
578 {
579 if ((match == NULL)
580 || (match->address->prefixlen < ei->address->prefixlen))
581 match = ei;
582 }
583 }
584
585 return match;
586}
587
588u_int32_t
589eigrp_bandwidth_to_scaled (u_int32_t bandwidth)
590{
838cf8ab 591 uint64_t temp_bandwidth = (256ull * 10000000) / bandwidth;
7f57883e
DS
592
593 temp_bandwidth =
f9e5c9ca 594 temp_bandwidth < EIGRP_MAX_METRIC ? temp_bandwidth : EIGRP_MAX_METRIC;
7f57883e
DS
595
596 return (u_int32_t) temp_bandwidth;
7f57883e
DS
597}
598
599u_int32_t
600eigrp_scaled_to_bandwidth (u_int32_t scaled)
601{
838cf8ab 602 uint64_t temp_scaled = scaled * (256ull * 10000000);
7f57883e
DS
603
604 temp_scaled =
f9e5c9ca 605 temp_scaled < EIGRP_MAX_METRIC ? temp_scaled : EIGRP_MAX_METRIC;
7f57883e
DS
606
607 return (u_int32_t) temp_scaled;
608}
609
610u_int32_t
611eigrp_delay_to_scaled (u_int32_t delay)
612{
613 return delay * 256;
614}
615
616u_int32_t
617eigrp_scaled_to_delay (u_int32_t scaled)
618{
619 return scaled / 256;
620}