]> git.proxmox.com Git - mirror_frr.git/blob - eigrpd/eigrp_interface.c
Merge pull request #629 from donaldsharp/eigrp_network
[mirror_frr.git] / eigrpd / eigrp_interface.c
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 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
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
57 static void
58 eigrp_delete_from_if (struct interface *, struct eigrp_interface *);
59
60 static void
61 eigrp_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
77 struct eigrp_interface *
78 eigrp_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 {
108 ei->list[i] = NULL;
109 ei->prefix[i] = NULL;
110 ei->routemap[i] = NULL;
111 }
112
113 return ei;
114 }
115
116 /* lookup ei for specified prefix/ifp */
117 struct eigrp_interface *
118 eigrp_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
137 int
138 eigrp_if_delete_hook (struct interface *ifp)
139 {
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
155 struct list *eigrp_iflist;
156
157 void
158 eigrp_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
165 int
166 eigrp_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
204 struct eigrp_if_params *
205 eigrp_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
223 return eip;
224 }
225
226 void
227 eigrp_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
235 struct eigrp_if_params *
236 eigrp_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
256 int
257 eigrp_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
278 thread_add_event(master, eigrp_hello_timer, ei, (1), NULL);
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 = prefix_ipv4_new ();
307 prefix_copy ((struct prefix *)pe->destination_ipv4,
308 (struct prefix *)dest_addr);
309 pe->af = AF_INET;
310 pe->nt = EIGRP_TOPOLOGY_TYPE_CONNECTED;
311
312 pe->state = EIGRP_FSM_STATE_PASSIVE;
313 pe->fdistance = eigrp_calculate_metrics (eigrp, &metric);
314 pe->req_action |= EIGRP_FSM_NEED_UPDATE;
315 eigrp_prefix_entry_add (eigrp->topology_table, pe);
316 listnode_add(eigrp->topology_changes_internalIPV4, pe);
317 }
318 ne = eigrp_neighbor_entry_new ();
319 ne->ei = ei;
320 ne->reported_metric = metric;
321 ne->total_metric = metric;
322 ne->distance = eigrp_calculate_metrics (eigrp, &metric);
323 ne->reported_distance = 0;
324 ne->prefix = pe;
325 ne->adv_router = eigrp->neighbor_self;
326 ne->flags = EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG;
327 eigrp_neighbor_entry_add (pe, ne);
328
329 for (ALL_LIST_ELEMENTS (eigrp->eiflist, node, nnode, ei2))
330 {
331 if (ei2->nbrs->count != 0)
332 {
333 eigrp_update_send (ei2);
334 }
335 }
336
337 pe->req_action &= ~EIGRP_FSM_NEED_UPDATE;
338 listnode_delete(eigrp->topology_changes_internalIPV4, pe);
339
340 return 1;
341 }
342
343 int
344 eigrp_if_down (struct eigrp_interface *ei)
345 {
346 struct listnode *node, *nnode;
347 struct eigrp_neighbor *nbr;
348
349 if (ei == NULL)
350 return 0;
351
352 /* Shutdown packet reception and sending */
353 if(ei->t_hello)
354 THREAD_OFF (ei->t_hello);
355
356 eigrp_if_stream_unset (ei);
357
358 /*Set infinite metrics to routes learned by this interface and start query process*/
359 for (ALL_LIST_ELEMENTS (ei->nbrs, node, nnode, nbr))
360 {
361 eigrp_nbr_delete(nbr);
362 }
363
364 return 1;
365 }
366
367 void
368 eigrp_if_stream_set (struct eigrp_interface *ei)
369 {
370 /* set output fifo queue. */
371 if (ei->obuf == NULL)
372 ei->obuf = eigrp_fifo_new ();
373 }
374
375 void
376 eigrp_if_stream_unset (struct eigrp_interface *ei)
377 {
378 struct eigrp *eigrp = ei->eigrp;
379
380 if (ei->obuf)
381 {
382 eigrp_fifo_free (ei->obuf);
383 ei->obuf = NULL;
384
385 if (ei->on_write_q)
386 {
387 listnode_delete (eigrp->oi_write_q, ei);
388 if (list_isempty (eigrp->oi_write_q))
389 thread_cancel (eigrp->t_write);
390 ei->on_write_q = 0;
391 }
392 }
393 }
394
395 void
396 eigrp_if_set_multicast (struct eigrp_interface *ei)
397 {
398 if ((EIGRP_IF_PASSIVE_STATUS (ei) == EIGRP_IF_ACTIVE))
399 {
400 /* The interface should belong to the EIGRP-all-routers group. */
401 if (!EI_MEMBER_CHECK (ei, MEMBER_ALLROUTERS)
402 && (eigrp_if_add_allspfrouters (ei->eigrp, ei->address,
403 ei->ifp->ifindex) >= 0))
404 /* Set the flag only if the system call to join succeeded. */
405 EI_MEMBER_JOINED (ei, MEMBER_ALLROUTERS);
406 }
407 else
408 {
409 /* The interface should NOT belong to the EIGRP-all-routers group. */
410 if (EI_MEMBER_CHECK (ei, MEMBER_ALLROUTERS))
411 {
412 /* Only actually drop if this is the last reference */
413 if (EI_MEMBER_COUNT (ei, MEMBER_ALLROUTERS) == 1)
414 eigrp_if_drop_allspfrouters (ei->eigrp, ei->address,
415 ei->ifp->ifindex);
416 /* Unset the flag regardless of whether the system call to leave
417 the group succeeded, since it's much safer to assume that
418 we are not a member. */
419 EI_MEMBER_LEFT (ei, MEMBER_ALLROUTERS);
420 }
421 }
422 }
423
424 u_char
425 eigrp_default_iftype (struct interface *ifp)
426 {
427 if (if_is_pointopoint (ifp))
428 return EIGRP_IFTYPE_POINTOPOINT;
429 else if (if_is_loopback (ifp))
430 return EIGRP_IFTYPE_LOOPBACK;
431 else
432 return EIGRP_IFTYPE_BROADCAST;
433 }
434
435 void
436 eigrp_if_free (struct eigrp_interface *ei, int source)
437 {
438 struct prefix_ipv4 dest_addr;
439 struct eigrp_prefix_entry *pe;
440 struct eigrp *eigrp = eigrp_lookup ();
441
442 if (source == INTERFACE_DOWN_BY_VTY)
443 {
444 THREAD_OFF (ei->t_hello);
445 eigrp_hello_send(ei,EIGRP_HELLO_GRACEFUL_SHUTDOWN, NULL);
446 }
447
448 dest_addr.family = AF_INET;
449 dest_addr.prefix = ei->connected->address->u.prefix4;
450 dest_addr.prefixlen = ei->connected->address->prefixlen;
451 apply_mask_ipv4(&dest_addr);
452 pe = eigrp_topology_table_lookup_ipv4 (eigrp->topology_table, &dest_addr);
453 if (pe)
454 eigrp_prefix_entry_delete (eigrp->topology_table, pe);
455
456 eigrp_if_down (ei);
457
458 list_delete (ei->nbrs);
459 eigrp_delete_from_if (ei->ifp, ei);
460 listnode_delete (ei->eigrp->eiflist, ei);
461
462 thread_cancel_event (master, ei);
463
464 memset (ei, 0, sizeof (*ei));
465 XFREE (MTYPE_EIGRP_IF, ei);
466 }
467
468 static void
469 eigrp_delete_from_if (struct interface *ifp, struct eigrp_interface *ei)
470 {
471 struct route_node *rn;
472 struct prefix p;
473
474 p = *ei->address;
475 p.prefixlen = IPV4_MAX_PREFIXLEN;
476
477 rn = route_node_lookup (IF_OIFS (ei->ifp), &p);
478 assert (rn);
479 assert (rn->info);
480 rn->info = NULL;
481 route_unlock_node (rn);
482 route_unlock_node (rn);
483 }
484
485 /* Simulate down/up on the interface. This is needed, for example, when
486 the MTU changes. */
487 void
488 eigrp_if_reset (struct interface *ifp)
489 {
490 struct route_node *rn;
491
492 for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
493 {
494 struct eigrp_interface *ei;
495
496 if ((ei = rn->info) == NULL)
497 continue;
498
499 eigrp_if_down (ei);
500 eigrp_if_up (ei);
501 }
502 }
503
504 struct eigrp_interface *
505 eigrp_if_lookup_by_local_addr (struct eigrp *eigrp, struct interface *ifp,
506 struct in_addr address)
507 {
508 struct listnode *node;
509 struct eigrp_interface *ei;
510
511 for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei))
512 {
513 if (ifp && ei->ifp != ifp)
514 continue;
515
516 if (IPV4_ADDR_SAME (&address, &ei->address->u.prefix4))
517 return ei;
518 }
519
520 return NULL;
521 }
522
523 /**
524 * @fn eigrp_if_lookup_by_name
525 *
526 * @param[in] eigrp EIGRP process
527 * @param[in] if_name Name of the interface
528 *
529 * @return struct eigrp_interface *
530 *
531 * @par
532 * Function is used for lookup interface by name.
533 */
534 struct eigrp_interface *
535 eigrp_if_lookup_by_name (struct eigrp *eigrp, const char *if_name)
536 {
537 struct eigrp_interface *ei;
538 struct listnode *node;
539
540 /* iterate over all eigrp interfaces */
541 for (ALL_LIST_ELEMENTS_RO (eigrp->eiflist, node, ei))
542 {
543 /* compare int name with eigrp interface's name */
544 if(strcmp(ei->ifp->name, if_name) == 0)
545 {
546 return ei;
547 }
548 }
549
550 return NULL;
551 }
552
553 /* determine receiving interface by ifp and source address */
554 struct eigrp_interface *
555 eigrp_if_lookup_recv_if (struct eigrp *eigrp, struct in_addr src,
556 struct interface *ifp)
557 {
558 struct route_node *rn;
559 struct prefix_ipv4 addr;
560 struct eigrp_interface *ei, *match;
561
562 addr.family = AF_INET;
563 addr.prefix = src;
564 addr.prefixlen = IPV4_MAX_BITLEN;
565
566 match = NULL;
567
568 for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn))
569 {
570 ei = rn->info;
571
572 if (!ei) /* oi can be NULL for PtP aliases */
573 continue;
574
575 if (if_is_loopback (ei->ifp))
576 continue;
577
578 if (prefix_match (CONNECTED_PREFIX (ei->connected),
579 (struct prefix *) &addr))
580 {
581 if ((match == NULL)
582 || (match->address->prefixlen < ei->address->prefixlen))
583 match = ei;
584 }
585 }
586
587 return match;
588 }
589
590 u_int32_t
591 eigrp_bandwidth_to_scaled (u_int32_t bandwidth)
592 {
593 uint64_t temp_bandwidth = (256ull * 10000000) / bandwidth;
594
595 temp_bandwidth =
596 temp_bandwidth < EIGRP_MAX_METRIC ? temp_bandwidth : EIGRP_MAX_METRIC;
597
598 return (u_int32_t) temp_bandwidth;
599 }
600
601 u_int32_t
602 eigrp_scaled_to_bandwidth (u_int32_t scaled)
603 {
604 uint64_t temp_scaled = scaled * (256ull * 10000000);
605
606 temp_scaled =
607 temp_scaled < EIGRP_MAX_METRIC ? temp_scaled : EIGRP_MAX_METRIC;
608
609 return (u_int32_t) temp_scaled;
610 }
611
612 u_int32_t
613 eigrp_delay_to_scaled (u_int32_t delay)
614 {
615 return delay * 256;
616 }
617
618 u_int32_t
619 eigrp_scaled_to_delay (u_int32_t scaled)
620 {
621 return scaled / 256;
622 }