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