]> git.proxmox.com Git - mirror_frr.git/blame - babeld/babel_interface.c
*: eliminate IFINDEX_DELETED in favor of IFINDEX_INTERNAL
[mirror_frr.git] / babeld / babel_interface.c
CommitLineData
ca10883e
DS
1/*
2Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
3
4Permission is hereby granted, free of charge, to any person obtaining a copy
5of this software and associated documentation files (the "Software"), to deal
6in the Software without restriction, including without limitation the rights
7to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8copies of the Software, and to permit persons to whom the Software is
9furnished to do so, subject to the following conditions:
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20THE SOFTWARE.
21*/
22
23#include <zebra.h>
24#include "memory.h"
25#include "log.h"
26#include "command.h"
27#include "prefix.h"
28#include "vector.h"
29#include "distribute.h"
30
31#include "babel_main.h"
32#include "util.h"
33#include "kernel.h"
34#include "babel_interface.h"
35#include "message.h"
36#include "route.h"
37#include "babel_zebra.h"
38#include "neighbour.h"
39#include "route.h"
40#include "xroute.h"
41#include "babel_memory.h"
42
43#define IS_ENABLE(ifp) (babel_enable_if_lookup(ifp->name) >= 0)
44
45static int babel_enable_if_lookup (const char *ifname);
46static int babel_enable_if_add (const char *ifname);
47static int babel_enable_if_delete (const char *ifname);
48static int interface_recalculate(struct interface *ifp);
49static int interface_reset(struct interface *ifp);
50static int babel_if_new_hook (struct interface *ifp);
51static int babel_if_delete_hook (struct interface *ifp);
52static int interface_config_write (struct vty *vty);
53static babel_interface_nfo * babel_interface_allocate (void);
54static void babel_interface_free (babel_interface_nfo *bi);
55
56
57static vector babel_enable_if; /* enable interfaces (by cmd). */
58static struct cmd_node babel_interface_node = /* babeld's interface node. */
59{
60 INTERFACE_NODE,
61 "%s(config-if)# ",
62 1 /* VTYSH */
63};
64
65
66int
67babel_interface_up (int cmd, struct zclient *client, zebra_size_t length, vrf_id_t vrf)
68{
69 struct stream *s = NULL;
70 struct interface *ifp = NULL;
71
72 debugf(BABEL_DEBUG_IF, "receive a 'interface up'");
73
74 s = zclient->ibuf;
75 ifp = zebra_interface_state_read(s, vrf); /* it updates iflist */
76
77 if (ifp == NULL) {
78 return 0;
79 }
80
81 interface_recalculate(ifp);
82 return 0;
83}
84
85int
86babel_interface_down (int cmd, struct zclient *client, zebra_size_t length, vrf_id_t vrf)
87{
88 struct stream *s = NULL;
89 struct interface *ifp = NULL;
90
91 debugf(BABEL_DEBUG_IF, "receive a 'interface down'");
92
93 s = zclient->ibuf;
94 ifp = zebra_interface_state_read(s, vrf); /* it updates iflist */
95
96 if (ifp == NULL) {
97 return 0;
98 }
99
100 interface_reset(ifp);
101 return 0;
102}
103
104int
105babel_interface_add (int cmd, struct zclient *client, zebra_size_t length, vrf_id_t vrf)
106{
107 struct interface *ifp = NULL;
108
109 debugf(BABEL_DEBUG_IF, "receive a 'interface add'");
110
111 /* read and add the interface in the iflist. */
112 ifp = zebra_interface_add_read (zclient->ibuf, vrf);
113
114 if (ifp == NULL) {
115 return 0;
116 }
117
118 interface_recalculate(ifp);
119 return 0;
120}
121
122int
123babel_interface_delete (int cmd, struct zclient *client, zebra_size_t length, vrf_id_t vrf)
124{
125 struct interface *ifp;
126 struct stream *s;
127
128 debugf(BABEL_DEBUG_IF, "receive a 'interface delete'");
129
130 s = zclient->ibuf;
131 ifp = zebra_interface_state_read(s, vrf); /* it updates iflist */
132
133 if (ifp == NULL)
134 return 0;
135
136 if (IS_ENABLE(ifp))
137 interface_reset(ifp);
138
139 /* To support pseudo interface do not free interface structure. */
140 /* if_delete(ifp); */
141 ifp->ifindex = IFINDEX_INTERNAL;
142
143 return 0;
144}
145
146int
147babel_interface_address_add (int cmd, struct zclient *client,
148 zebra_size_t length, vrf_id_t vrf)
149{
150 babel_interface_nfo *babel_ifp;
151 struct connected *ifc;
152 struct prefix *prefix;
153
154 debugf(BABEL_DEBUG_IF, "receive a 'interface address add'");
155
156 ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD,
157 zclient->ibuf, vrf);
158
159 if (ifc == NULL)
160 return 0;
161
162 prefix = ifc->address;
163
164 if (prefix->family == AF_INET) {
165 flush_interface_routes(ifc->ifp, 0);
166 babel_ifp = babel_get_if_nfo(ifc->ifp);
167 if (babel_ifp->ipv4 == NULL) {
168 babel_ifp->ipv4 = malloc(4);
169 if (babel_ifp->ipv4 == NULL) {
170 zlog_err("not einough memory");
171 } else {
172 memcpy(babel_ifp->ipv4, &prefix->u.prefix4, 4);
173 }
174 }
175 }
176
177 send_request(ifc->ifp, NULL, 0);
178 send_update(ifc->ifp, 0, NULL, 0);
179
180 return 0;
181}
182
183int
184babel_interface_address_delete (int cmd, struct zclient *client,
185 zebra_size_t length, vrf_id_t vrf)
186{
187 babel_interface_nfo *babel_ifp;
188 struct connected *ifc;
189 struct prefix *prefix;
190
191 debugf(BABEL_DEBUG_IF, "receive a 'interface address delete'");
192
193 ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_DELETE,
194 zclient->ibuf, vrf);
195
196 if (ifc == NULL)
197 return 0;
198
199 prefix = ifc->address;
200
201 if (prefix->family == AF_INET) {
202 flush_interface_routes(ifc->ifp, 0);
203 babel_ifp = babel_get_if_nfo(ifc->ifp);
204 if (babel_ifp->ipv4 != NULL
205 && memcmp(babel_ifp->ipv4, &prefix->u.prefix4, 4) == 0) {
206 free(babel_ifp->ipv4);
207 babel_ifp->ipv4 = NULL;
208 }
209 }
210
211 send_request(ifc->ifp, NULL, 0);
212 send_update(ifc->ifp, 0, NULL, 0);
213
214 return 0;
215}
216
217/* Lookup function. */
218static int
219babel_enable_if_lookup (const char *ifname)
220{
221 unsigned int i;
222 char *str;
223
224 for (i = 0; i < vector_active (babel_enable_if); i++)
225 if ((str = vector_slot (babel_enable_if, i)) != NULL)
226 if (strcmp (str, ifname) == 0)
227 return i;
228 return -1;
229}
230
231/* Add interface to babel_enable_if. */
232static int
233babel_enable_if_add (const char *ifname)
234{
235 int ret;
236 struct interface *ifp = NULL;
237
238 ret = babel_enable_if_lookup (ifname);
239 if (ret >= 0)
240 return -1;
241
242 vector_set (babel_enable_if, strdup (ifname));
243
244 ifp = if_lookup_by_name(ifname, VRF_DEFAULT);
245 if (ifp != NULL)
246 interface_recalculate(ifp);
247
248 return 1;
249}
250
251/* Delete interface from babel_enable_if. */
252static int
253babel_enable_if_delete (const char *ifname)
254{
255 int babel_enable_if_index;
256 char *str;
257 struct interface *ifp = NULL;
258
259 babel_enable_if_index = babel_enable_if_lookup (ifname);
260 if (babel_enable_if_index < 0)
261 return -1;
262
263 str = vector_slot (babel_enable_if, babel_enable_if_index);
264 free (str);
265 vector_unset (babel_enable_if, babel_enable_if_index);
266
267 ifp = if_lookup_by_name(ifname, VRF_DEFAULT);
268 if (ifp != NULL)
269 interface_reset(ifp);
270
271 return 1;
272}
273
274/* [Babel Command] Babel enable on specified interface or matched network. */
275DEFUN (babel_network,
276 babel_network_cmd,
277 "network IF_OR_ADDR",
278 "Enable Babel protocol on specified interface or network.\n"
f84d11d1 279 "Interface or address\n")
ca10883e
DS
280{
281 int ret;
282 struct prefix p;
283
284 ret = str2prefix (argv[1]->arg, &p);
285
286 /* Given string is: */
287 if (ret) /* an IPv4 or v6 network */
288 return CMD_ERR_NO_MATCH; /* not implemented yet */
289 else /* an interface name */
290 ret = babel_enable_if_add (argv[1]->arg);
291
292 if (ret < 0) {
5c7571d4 293 vty_out (vty, "There is same network configuration %s\n",
96ade3ed 294 argv[1]->arg);
851fcbae 295 return CMD_WARNING;
ca10883e
DS
296 }
297
298 return CMD_SUCCESS;
299}
300
301/* [Babel Command] Babel enable on specified interface or matched network. */
302DEFUN (no_babel_network,
303 no_babel_network_cmd,
304 "no network IF_OR_ADDR",
305 NO_STR
306 "Disable Babel protocol on specified interface or network.\n"
bd8d8973 307 "Interface or address\n")
ca10883e
DS
308{
309 int ret;
310 struct prefix p;
311
312 ret = str2prefix (argv[2]->arg, &p);
313
314 /* Given string is: */
315 if (ret) /* an IPv4 or v6 network */
316 return CMD_ERR_NO_MATCH; /* not implemented yet */
317 else /* an interface name */
318 ret = babel_enable_if_delete (argv[2]->arg);
319
320 if (ret < 0) {
5c7571d4 321 vty_out (vty, "can't find network %s\n",argv[2]->arg);
f1a05de9 322 return CMD_WARNING_CONFIG_FAILED;
ca10883e
DS
323 }
324
325 return CMD_SUCCESS;
326}
327
328/* There are a number of interface parameters that must be changed when
329 an interface becomes wired/wireless. In Quagga, they cannot be
330 configured separately. */
331
332static void
333babel_set_wired_internal(babel_interface_nfo *babel_ifp, int wired)
334{
335 if(wired) {
336 babel_ifp->flags |= BABEL_IF_WIRED;
337 babel_ifp->flags |= BABEL_IF_SPLIT_HORIZON;
338 babel_ifp->cost = BABEL_DEFAULT_RXCOST_WIRED;
339 babel_ifp->channel = BABEL_IF_CHANNEL_NONINTERFERING;
340 babel_ifp->flags &= ~BABEL_IF_LQ;
341 } else {
342 babel_ifp->flags &= ~BABEL_IF_WIRED;
343 babel_ifp->flags &= ~BABEL_IF_SPLIT_HORIZON;
344 babel_ifp->cost = BABEL_DEFAULT_RXCOST_WIRELESS;
345 babel_ifp->channel = BABEL_IF_CHANNEL_INTERFERING;
346 babel_ifp->flags |= BABEL_IF_LQ;
347 }
348
349}
350
351/* [Interface Command] Tell the interface is wire. */
352DEFUN (babel_set_wired,
353 babel_set_wired_cmd,
354 "babel wired",
355 "Babel interface commands\n"
bd8d8973 356 "Enable wired optimizations\n")
ca10883e
DS
357{
358 VTY_DECLVAR_CONTEXT(interface, ifp);
359 babel_interface_nfo *babel_ifp;
360
361 babel_ifp = babel_get_if_nfo(ifp);
362
363 assert (babel_ifp != NULL);
364 babel_set_wired_internal(babel_ifp, 1);
365 return CMD_SUCCESS;
366}
367
368/* [Interface Command] Tell the interface is wireless (default). */
369DEFUN (babel_set_wireless,
370 babel_set_wireless_cmd,
371 "babel wireless",
372 "Babel interface commands\n"
bd8d8973 373 "Disable wired optimizations (assume wireless)\n")
ca10883e
DS
374{
375 VTY_DECLVAR_CONTEXT(interface, ifp);
376 babel_interface_nfo *babel_ifp;
377
378 babel_ifp = babel_get_if_nfo(ifp);
379
380 assert (babel_ifp != NULL);
381 babel_set_wired_internal(babel_ifp, 0);
382 return CMD_SUCCESS;
383}
384
385/* [Interface Command] Enable split horizon. */
386DEFUN (babel_split_horizon,
387 babel_split_horizon_cmd,
388 "babel split-horizon",
389 "Babel interface commands\n"
bd8d8973 390 "Enable split horizon processing\n")
ca10883e
DS
391{
392 VTY_DECLVAR_CONTEXT(interface, ifp);
393 babel_interface_nfo *babel_ifp;
394
395 babel_ifp = babel_get_if_nfo(ifp);
396
397 assert (babel_ifp != NULL);
398 babel_ifp->flags |= BABEL_IF_SPLIT_HORIZON;
399 return CMD_SUCCESS;
400}
401
402/* [Interface Command] Disable split horizon (default). */
403DEFUN (no_babel_split_horizon,
404 no_babel_split_horizon_cmd,
405 "no babel split-horizon",
406 NO_STR
407 "Babel interface commands\n"
bd8d8973 408 "Disable split horizon processing\n")
ca10883e
DS
409{
410 VTY_DECLVAR_CONTEXT(interface, ifp);
411 babel_interface_nfo *babel_ifp;
412
413 babel_ifp = babel_get_if_nfo(ifp);
414
415 assert (babel_ifp != NULL);
416 babel_ifp->flags &= ~BABEL_IF_SPLIT_HORIZON;
417 return CMD_SUCCESS;
418}
419
420/* [Interface Command]. */
421DEFUN (babel_set_hello_interval,
422 babel_set_hello_interval_cmd,
423 "babel hello-interval (20-655340)",
424 "Babel interface commands\n"
425 "Time between scheduled hellos\n"
426 "Milliseconds\n")
427{
428 VTY_DECLVAR_CONTEXT(interface, ifp);
429 babel_interface_nfo *babel_ifp;
430 int interval;
431
facfee22 432 interval = strtoul(argv[2]->arg, NULL, 10);
ca10883e
DS
433
434 babel_ifp = babel_get_if_nfo(ifp);
435 assert (babel_ifp != NULL);
436
437 babel_ifp->hello_interval = interval;
438 return CMD_SUCCESS;
439}
440
441/* [Interface Command]. */
442DEFUN (babel_set_update_interval,
443 babel_set_update_interval_cmd,
444 "babel update-interval (20-655340)",
445 "Babel interface commands\n"
446 "Time between scheduled updates\n"
447 "Milliseconds\n")
448{
449 VTY_DECLVAR_CONTEXT(interface, ifp);
450 babel_interface_nfo *babel_ifp;
451 int interval;
452
facfee22 453 interval = strtoul(argv[2]->arg, NULL, 10);
ca10883e
DS
454
455 babel_ifp = babel_get_if_nfo(ifp);
456 assert (babel_ifp != NULL);
457
458 babel_ifp->update_interval = interval;
459 return CMD_SUCCESS;
460}
461
462DEFUN (babel_set_rxcost,
463 babel_set_rxcost_cmd,
464 "babel rxcost (1-65534)",
465 "Babel interface commands\n"
466 "Rxcost multiplier\n"
bd8d8973 467 "Units\n")
ca10883e
DS
468{
469 VTY_DECLVAR_CONTEXT(interface, ifp);
470 babel_interface_nfo *babel_ifp;
471 int rxcost;
472
facfee22 473 rxcost = strtoul(argv[2]->arg, NULL, 10);
ca10883e
DS
474
475 babel_ifp = babel_get_if_nfo(ifp);
476 assert (babel_ifp != NULL);
477
478 babel_ifp->cost = rxcost;
479 return CMD_SUCCESS;
480}
481
482DEFUN (babel_set_rtt_decay,
483 babel_set_rtt_decay_cmd,
484 "babel rtt-decay (1-256)",
485 "Babel interface commands\n"
486 "Decay factor for exponential moving average of RTT samples\n"
bd8d8973 487 "Units of 1/256\n")
ca10883e
DS
488{
489 VTY_DECLVAR_CONTEXT(interface, ifp);
490 babel_interface_nfo *babel_ifp;
491 int decay;
492
facfee22 493 decay = strtoul(argv[2]->arg, NULL, 10);
ca10883e
DS
494
495 babel_ifp = babel_get_if_nfo(ifp);
496 assert (babel_ifp != NULL);
497
498 babel_ifp->rtt_decay = decay;
499 return CMD_SUCCESS;
500}
501
502DEFUN (babel_set_rtt_min,
503 babel_set_rtt_min_cmd,
504 "babel rtt-min (1-65535)",
505 "Babel interface commands\n"
506 "Minimum RTT starting for increasing cost\n"
bd8d8973 507 "Milliseconds\n")
ca10883e
DS
508{
509 VTY_DECLVAR_CONTEXT(interface, ifp);
510 babel_interface_nfo *babel_ifp;
511 int rtt;
512
facfee22 513 rtt = strtoul(argv[2]->arg, NULL, 10);
ca10883e
DS
514
515 babel_ifp = babel_get_if_nfo(ifp);
516 assert (babel_ifp != NULL);
517
518 babel_ifp->rtt_min = rtt;
519 return CMD_SUCCESS;
520}
521
522DEFUN (babel_set_rtt_max,
523 babel_set_rtt_max_cmd,
524 "babel rtt-max (1-65535)",
525 "Babel interface commands\n"
526 "Maximum RTT\n"
bd8d8973 527 "Milliseconds\n")
ca10883e
DS
528{
529 VTY_DECLVAR_CONTEXT(interface, ifp);
530 babel_interface_nfo *babel_ifp;
531 int rtt;
532
facfee22 533 rtt = strtoul(argv[2]->arg, NULL, 10);
ca10883e
DS
534
535 babel_ifp = babel_get_if_nfo(ifp);
536 assert (babel_ifp != NULL);
537
538 babel_ifp->rtt_max = rtt;
539 return CMD_SUCCESS;
540}
541
542DEFUN (babel_set_max_rtt_penalty,
543 babel_set_max_rtt_penalty_cmd,
544 "babel max-rtt-penalty (0-65535)",
545 "Babel interface commands\n"
546 "Maximum additional cost due to RTT\n"
bd8d8973 547 "Milliseconds\n")
ca10883e
DS
548{
549 VTY_DECLVAR_CONTEXT(interface, ifp);
550 babel_interface_nfo *babel_ifp;
551 int penalty;
552
facfee22 553 penalty = strtoul(argv[2]->arg, NULL, 10);
ca10883e
DS
554
555 babel_ifp = babel_get_if_nfo(ifp);
556 assert (babel_ifp != NULL);
557
558 babel_ifp->max_rtt_penalty = penalty;
559 return CMD_SUCCESS;
560}
561
562DEFUN (babel_set_enable_timestamps,
563 babel_set_enable_timestamps_cmd,
564 "babel enable-timestamps",
565 "Babel interface commands\n"
bd8d8973 566 "Enable timestamps\n")
ca10883e
DS
567{
568 VTY_DECLVAR_CONTEXT(interface, ifp);
569 babel_interface_nfo *babel_ifp;
570
571 babel_ifp = babel_get_if_nfo(ifp);
572 assert (babel_ifp != NULL);
573
574 babel_ifp->flags |= BABEL_IF_TIMESTAMPS;
575 return CMD_SUCCESS;
576}
577
578DEFUN (no_babel_set_enable_timestamps,
579 no_babel_set_enable_timestamps_cmd,
580 "no babel enable-timestamps",
bd8d8973 581 NO_STR
ca10883e 582 "Babel interface commands\n"
bd8d8973 583 "Disable timestamps\n")
ca10883e
DS
584{
585 VTY_DECLVAR_CONTEXT(interface, ifp);
586 babel_interface_nfo *babel_ifp;
587
588 babel_ifp = babel_get_if_nfo(ifp);
589 assert (babel_ifp != NULL);
590
591 babel_ifp->flags &= ~BABEL_IF_TIMESTAMPS;
592 return CMD_SUCCESS;
593}
594
595DEFUN (babel_set_channel,
596 babel_set_channel_cmd,
597 "babel channel (1-254)",
598 "Babel interface commands\n"
599 "Channel number for diversity routing\n"
bd8d8973 600 "Number\n")
ca10883e
DS
601{
602 VTY_DECLVAR_CONTEXT(interface, ifp);
603 babel_interface_nfo *babel_ifp;
604 int channel;
605
facfee22 606 channel = strtoul(argv[2]->arg, NULL, 10);
ca10883e
DS
607
608 babel_ifp = babel_get_if_nfo(ifp);
609 assert (babel_ifp != NULL);
610
611 babel_ifp->channel = channel;
612 return CMD_SUCCESS;
613}
614
615DEFUN (babel_set_channel_interfering,
616 babel_set_channel_interfering_cmd,
617 "babel channel interfering",
618 "Babel interface commands\n"
619 "Channel number for diversity routing\n"
bd8d8973 620 "Mark channel as interfering\n")
ca10883e
DS
621{
622 VTY_DECLVAR_CONTEXT(interface, ifp);
623 babel_interface_nfo *babel_ifp;
624
625 babel_ifp = babel_get_if_nfo(ifp);
626 assert (babel_ifp != NULL);
627
628 babel_ifp->channel = BABEL_IF_CHANNEL_INTERFERING;
629 return CMD_SUCCESS;
630}
631
632DEFUN (babel_set_channel_noninterfering,
633 babel_set_channel_noninterfering_cmd,
634 "babel channel noninterfering",
635 "Babel interface commands\n"
636 "Channel number for diversity routing\n"
bd8d8973 637 "Mark channel as noninterfering\n")
ca10883e
DS
638{
639 VTY_DECLVAR_CONTEXT(interface, ifp);
640 babel_interface_nfo *babel_ifp;
641
642 babel_ifp = babel_get_if_nfo(ifp);
643 assert (babel_ifp != NULL);
644
645 babel_ifp->channel = BABEL_IF_CHANNEL_NONINTERFERING;
646 return CMD_SUCCESS;
647}
648
649/* This should be no more than half the hello interval, so that hellos
650 aren't sent late. The result is in milliseconds. */
651unsigned
652jitter(babel_interface_nfo *babel_ifp, int urgent)
653{
654 unsigned interval = babel_ifp->hello_interval;
655 if(urgent)
656 interval = MIN(interval, 100);
657 else
658 interval = MIN(interval, 4000);
659 return roughly(interval) / 4;
660}
661
662unsigned
663update_jitter(babel_interface_nfo *babel_ifp, int urgent)
664{
665 unsigned interval = babel_ifp->hello_interval;
666 if(urgent)
667 interval = MIN(interval, 100);
668 else
669 interval = MIN(interval, 4000);
670 return roughly(interval);
671}
672
673/* calculate babeld's specific datas of an interface (change when the interface
674 change) */
675static int
676interface_recalculate(struct interface *ifp)
677{
678 babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
679 unsigned char *tmp = NULL;
680 int mtu, rc;
681 struct ipv6_mreq mreq;
682
683 if (!IS_ENABLE(ifp))
684 return -1;
685
686 if (!if_is_operative(ifp) || !CHECK_FLAG(ifp->flags, IFF_RUNNING)) {
687 interface_reset(ifp);
688 return -1;
689 }
690
691 babel_ifp->flags |= BABEL_IF_IS_UP;
692
693 mtu = MIN(ifp->mtu, ifp->mtu6);
694
695 /* We need to be able to fit at least two messages into a packet,
696 so MTUs below 116 require lower layer fragmentation. */
697 /* In IPv6, the minimum MTU is 1280, and every host must be able
698 to reassemble up to 1500 bytes, but I'd rather not rely on this. */
699 if(mtu < 128) {
700 debugf(BABEL_DEBUG_IF, "Suspiciously low MTU %d on interface %s (%d).",
701 mtu, ifp->name, ifp->ifindex);
702 mtu = 128;
703 }
704
705 /* 4 for Babel header; 40 for IPv6 header, 8 for UDP header, 12 for good luck. */
706 babel_ifp->bufsize = mtu - 4 - 60;
707 tmp = babel_ifp->sendbuf;
708 babel_ifp->sendbuf = realloc(babel_ifp->sendbuf, babel_ifp->bufsize);
709 if(babel_ifp->sendbuf == NULL) {
710 zlog_err("Couldn't reallocate sendbuf.");
711 free(tmp);
712 babel_ifp->bufsize = 0;
713 return -1;
714 }
715 tmp = NULL;
716
717 rc = resize_receive_buffer(mtu);
718 if(rc < 0)
719 zlog_warn("couldn't resize "
720 "receive buffer for interface %s (%d) (%d bytes).\n",
721 ifp->name, ifp->ifindex, mtu);
722
723 memset(&mreq, 0, sizeof(mreq));
724 memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16);
725 mreq.ipv6mr_interface = ifp->ifindex;
726
727 rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_JOIN_GROUP,
728 (char*)&mreq, sizeof(mreq));
729 if(rc < 0) {
730 zlog_err("setsockopt(IPV6_JOIN_GROUP) on interface '%s': %s",
731 ifp->name, safe_strerror(errno));
732 /* This is probably due to a missing link-local address,
733 so down this interface, and wait until the main loop
734 tries to up it again. */
735 interface_reset(ifp);
736 return -1;
737 }
738
739 set_timeout(&babel_ifp->hello_timeout, babel_ifp->hello_interval);
740 set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval);
741 send_hello(ifp);
742 send_request(ifp, NULL, 0);
743
744 update_interface_metric(ifp);
745
746 debugf(BABEL_DEBUG_COMMON,
747 "Upped interface %s (%s, cost=%d, channel=%d%s).",
748 ifp->name,
749 (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless",
750 babel_ifp->cost,
751 babel_ifp->channel,
752 babel_ifp->ipv4 ? ", IPv4" : "");
753
754 if(rc > 0)
755 send_update(ifp, 0, NULL, 0);
756
757 return 1;
758}
759
760/* Reset the interface as it was new: it's not removed from the interface list,
761 and may be considered as a upped interface. */
762static int
763interface_reset(struct interface *ifp)
764{
765 int rc;
766 struct ipv6_mreq mreq;
767 babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
768
769 if (!(babel_ifp->flags & BABEL_IF_IS_UP))
770 return 0;
771
772 debugf(BABEL_DEBUG_IF, "interface reset: %s", ifp->name);
773 babel_ifp->flags &= ~BABEL_IF_IS_UP;
774
775 flush_interface_routes(ifp, 0);
776 babel_ifp->buffered = 0;
777 babel_ifp->bufsize = 0;
778 free(babel_ifp->sendbuf);
779 babel_ifp->num_buffered_updates = 0;
780 babel_ifp->update_bufsize = 0;
781 if(babel_ifp->buffered_updates)
782 free(babel_ifp->buffered_updates);
783 babel_ifp->buffered_updates = NULL;
784 babel_ifp->sendbuf = NULL;
785
786 if(ifp->ifindex > 0) {
787 memset(&mreq, 0, sizeof(mreq));
788 memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16);
789 mreq.ipv6mr_interface = ifp->ifindex;
790 rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
791 (char*)&mreq, sizeof(mreq));
792 if(rc < 0)
793 zlog_err("setsockopt(IPV6_LEAVE_GROUP) on interface '%s': %s",
794 ifp->name, safe_strerror(errno));
795 }
796
797 update_interface_metric(ifp);
798
799 debugf(BABEL_DEBUG_COMMON,"Upped network %s (%s, cost=%d%s).",
800 ifp->name,
801 (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless",
802 babel_ifp->cost,
803 babel_ifp->ipv4 ? ", IPv4" : "");
804
805 return 1;
806}
807
808/* Send retraction to all, and reset all interfaces statistics. */
809void
810babel_interface_close_all(void)
811{
f4e14fdb 812 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
ca10883e 813 struct interface *ifp = NULL;
ca10883e 814
f4e14fdb 815 FOR_ALL_INTERFACES(vrf, ifp) {
ca10883e
DS
816 if(!if_up(ifp))
817 continue;
818 send_wildcard_retraction(ifp);
819 /* Make sure that we expire quickly from our neighbours'
820 association caches. */
821 send_hello_noupdate(ifp, 10);
822 flushbuf(ifp);
823 usleep(roughly(1000));
824 gettime(&babel_now);
825 }
f4e14fdb 826 FOR_ALL_INTERFACES(vrf, ifp) {
ca10883e
DS
827 if(!if_up(ifp))
828 continue;
829 /* Make sure they got it. */
830 send_wildcard_retraction(ifp);
831 send_hello_noupdate(ifp, 1);
832 flushbuf(ifp);
833 usleep(roughly(10000));
834 gettime(&babel_now);
835 interface_reset(ifp);
836 }
837}
838
839/* return "true" if address is one of our ipv6 addresses */
840int
841is_interface_ll_address(struct interface *ifp, const unsigned char *address)
842{
843 struct connected *connected;
844 struct listnode *node;
845
846 if(!if_up(ifp))
847 return 0;
848
849 FOR_ALL_INTERFACES_ADDRESSES(ifp, connected, node) {
850 if(connected->address->family == AF_INET6 &&
851 memcmp(&connected->address->u.prefix6, address, 16) == 0)
852 return 1;
853 }
854
855 return 0;
856}
857
858static void
859show_babel_interface_sub (struct vty *vty, struct interface *ifp)
860{
861 int is_up;
862 babel_interface_nfo *babel_ifp;
863
5c7571d4 864 vty_out (vty, "%s is %s\n", ifp->name,
96ade3ed 865 ((is_up = if_is_operative(ifp)) ? "up" : "down"));
5c7571d4 866 vty_out (vty, " ifindex %u, MTU %u bytes %s\n",
96ade3ed 867 ifp->ifindex, MIN(ifp->mtu, ifp->mtu6), if_flag_dump(ifp->flags));
ca10883e
DS
868
869 if (!IS_ENABLE(ifp))
870 {
5c7571d4 871 vty_out (vty, " Babel protocol is not enabled on this interface\n");
ca10883e
DS
872 return;
873 }
874 if (!is_up)
875 {
5c7571d4
DL
876 vty_out (vty,
877 " Babel protocol is enabled, but not running on this interface\n");
ca10883e
DS
878 return;
879 }
880 babel_ifp = babel_get_if_nfo (ifp);
5c7571d4 881 vty_out (vty, " Babel protocol is running on this interface\n");
181039f3 882 vty_out (vty, " Operating mode is \"%s\"\n",
96ade3ed 883 CHECK_FLAG(babel_ifp->flags, BABEL_IF_WIRED) ? "wired" : "wireless");
5c7571d4 884 vty_out (vty, " Split horizon mode is %s\n",
96ade3ed 885 CHECK_FLAG(babel_ifp->flags, BABEL_IF_SPLIT_HORIZON) ? "On" : "Off");
5c7571d4
DL
886 vty_out (vty, " Hello interval is %u ms\n", babel_ifp->hello_interval);
887 vty_out (vty, " Update interval is %u ms\n", babel_ifp->update_interval);
888 vty_out (vty, " Rxcost multiplier is %u\n", babel_ifp->cost);
ca10883e
DS
889}
890
891DEFUN (show_babel_interface,
892 show_babel_interface_cmd,
893 "show babel interface [IFNAME]",
894 SHOW_STR
895 "Babel information\n"
896 "Interface information\n"
897 "Interface\n")
898{
f4e14fdb 899 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
ca10883e 900 struct interface *ifp;
ca10883e
DS
901
902 if (argc == 3)
903 {
f4e14fdb 904 RB_FOREACH (ifp, if_name_head, &vrf->ifaces_by_name)
ca10883e
DS
905 show_babel_interface_sub (vty, ifp);
906 return CMD_SUCCESS;
907 }
908 if ((ifp = if_lookup_by_name (argv[3]->arg, VRF_DEFAULT)) == NULL)
909 {
5c7571d4 910 vty_out (vty, "No such interface name\n");
ca10883e
DS
911 return CMD_WARNING;
912 }
913 show_babel_interface_sub (vty, ifp);
914 return CMD_SUCCESS;
915}
916
917static void
918show_babel_neighbour_sub (struct vty *vty, struct neighbour *neigh)
919{
181039f3 920 vty_out (vty,
ca10883e 921 "Neighbour %s dev %s reach %04x rxcost %d txcost %d "
181039f3 922 "rtt %s rttcost %d%s.\n",
ca10883e
DS
923 format_address(neigh->address),
924 neigh->ifp->name,
925 neigh->reach,
926 neighbour_rxcost(neigh),
927 neigh->txcost,
928 format_thousands(neigh->rtt),
929 neighbour_rttcost(neigh),
96ade3ed 930 if_up(neigh->ifp) ? "" : " (down)");
ca10883e
DS
931}
932
933DEFUN (show_babel_neighbour,
934 show_babel_neighbour_cmd,
935 "show babel neighbor [IFNAME]",
936 SHOW_STR
937 "Babel information\n"
938 "Print neighbors\n"
939 "Interface\n")
940{
941 struct neighbour *neigh;
942 struct interface *ifp;
943
944 if (argc == 3) {
945 FOR_ALL_NEIGHBOURS(neigh) {
946 show_babel_neighbour_sub(vty, neigh);
947 }
948 return CMD_SUCCESS;
949 }
950 if ((ifp = if_lookup_by_name (argv[3]->arg, VRF_DEFAULT)) == NULL)
951 {
5c7571d4 952 vty_out (vty, "No such interface name\n");
ca10883e
DS
953 return CMD_WARNING;
954 }
955 FOR_ALL_NEIGHBOURS(neigh) {
956 if(ifp->ifindex == neigh->ifp->ifindex) {
957 show_babel_neighbour_sub(vty, neigh);
958 }
959 }
960 return CMD_SUCCESS;
961}
962
963static int
964babel_prefix_eq(struct prefix *prefix, unsigned char *p, int plen)
965{
966 if(prefix->family == AF_INET6) {
967 if(prefix->prefixlen != plen ||
968 memcmp(&prefix->u.prefix6, p, 16) != 0)
969 return 0;
970 } else if(prefix->family == AF_INET) {
971 if(plen < 96 || !v4mapped(p) || prefix->prefixlen != plen - 96 ||
972 memcmp(&prefix->u.prefix4, p + 12, 4) != 0)
973 return 0;
974 } else {
975 return 0;
976 }
977
978 return 1;
979}
980
981static void
982show_babel_routes_sub(struct babel_route *route, struct vty *vty,
983 struct prefix *prefix)
984{
985 const unsigned char *nexthop =
986 memcmp(route->nexthop, route->neigh->address, 16) == 0 ?
987 NULL : route->nexthop;
988 char channels[100];
989
990 if(prefix && !babel_prefix_eq(prefix, route->src->prefix, route->src->plen))
991 return;
992
993 if(route->channels[0] == 0)
994 channels[0] = '\0';
995 else {
996 int k, j = 0;
997 snprintf(channels, 100, " chan (");
998 j = strlen(channels);
999 for(k = 0; k < DIVERSITY_HOPS; k++) {
1000 if(route->channels[k] == 0)
1001 break;
1002 if(k > 0)
1003 channels[j++] = ',';
1004 snprintf(channels + j, 100 - j, "%d", route->channels[k]);
1005 j = strlen(channels);
1006 }
1007 snprintf(channels + j, 100 - j, ")");
1008 if(k == 0)
1009 channels[0] = '\0';
1010 }
1011
181039f3 1012 vty_out (vty,
ca10883e 1013 "%s metric %d refmetric %d id %s seqno %d%s age %d "
181039f3 1014 "via %s neigh %s%s%s%s\n",
ca10883e
DS
1015 format_prefix(route->src->prefix, route->src->plen),
1016 route_metric(route), route->refmetric,
1017 format_eui64(route->src->id),
1018 (int)route->seqno,
1019 channels,
1020 (int)(babel_now.tv_sec - route->time),
1021 route->neigh->ifp->name,
1022 format_address(route->neigh->address),
1023 nexthop ? " nexthop " : "",
1024 nexthop ? format_address(nexthop) : "",
96ade3ed 1025 route->installed ? " (installed)" : route_feasible(route) ? " (feasible)" : "");
ca10883e
DS
1026}
1027
1028static void
1029show_babel_xroutes_sub (struct xroute *xroute, struct vty *vty,
1030 struct prefix *prefix)
1031{
1032 if(prefix && !babel_prefix_eq(prefix, xroute->prefix, xroute->plen))
1033 return;
1034
5c7571d4 1035 vty_out (vty, "%s metric %d (exported)\n",
ca10883e 1036 format_prefix(xroute->prefix, xroute->plen),
96ade3ed 1037 xroute->metric);
ca10883e
DS
1038}
1039
1040DEFUN (show_babel_route,
1041 show_babel_route_cmd,
1042 "show babel route",
1043 SHOW_STR
1044 "Babel information\n"
1045 "Babel internal routing table\n")
1046{
1047 struct route_stream *routes = NULL;
1048 struct xroute_stream *xroutes = NULL;
1049 routes = route_stream(0);
1050 if(routes) {
1051 while(1) {
1052 struct babel_route *route = route_stream_next(routes);
1053 if(route == NULL)
1054 break;
1055 show_babel_routes_sub(route, vty, NULL);
1056 }
1057 route_stream_done(routes);
1058 } else {
1059 zlog_err("Couldn't allocate route stream.");
1060 }
dd15627e 1061 xroutes = xroute_stream();
ca10883e
DS
1062 if(xroutes) {
1063 while(1) {
1064 struct xroute *xroute = xroute_stream_next(xroutes);
1065 if(xroute == NULL)
1066 break;
1067 show_babel_xroutes_sub(xroute, vty, NULL);
1068 }
1069 xroute_stream_done(xroutes);
1070 } else {
1071 zlog_err("Couldn't allocate route stream.");
1072 }
1073 return CMD_SUCCESS;
1074}
1075
1076DEFUN (show_babel_route_prefix,
1077 show_babel_route_prefix_cmd,
1078 "show babel route <A.B.C.D/M|X:X::X:X/M>",
1079 SHOW_STR
1080 "Babel information\n"
f7bf422e 1081 "Babel internal routing table\n"
ca10883e
DS
1082 "IPv4 prefix <network>/<length>\n"
1083 "IPv6 prefix <network>/<length>\n")
1084{
1085 struct route_stream *routes = NULL;
1086 struct xroute_stream *xroutes = NULL;
1087 struct prefix prefix;
1088 int ret;
1089
1090 ret = str2prefix(argv[3]->arg, &prefix);
1091 if(ret == 0) {
5c7571d4 1092 vty_out (vty, "%% Malformed address\n");
ca10883e
DS
1093 return CMD_WARNING;
1094 }
1095
1096 routes = route_stream(0);
1097 if(routes) {
1098 while(1) {
1099 struct babel_route *route = route_stream_next(routes);
1100 if(route == NULL)
1101 break;
1102 show_babel_routes_sub(route, vty, &prefix);
1103 }
1104 route_stream_done(routes);
1105 } else {
1106 zlog_err("Couldn't allocate route stream.");
1107 }
dd15627e 1108 xroutes = xroute_stream();
ca10883e
DS
1109 if(xroutes) {
1110 while(1) {
1111 struct xroute *xroute = xroute_stream_next(xroutes);
1112 if(xroute == NULL)
1113 break;
1114 show_babel_xroutes_sub(xroute, vty, &prefix);
1115 }
1116 xroute_stream_done(xroutes);
1117 } else {
1118 zlog_err("Couldn't allocate route stream.");
1119 }
1120 return CMD_SUCCESS;
1121}
1122
1123
1124DEFUN (show_babel_route_addr,
1125 show_babel_route_addr_cmd,
1126 "show babel route A.B.C.D",
1127 SHOW_STR
1128 "Babel information\n"
f7bf422e 1129 "Babel internal routing table\n"
ca10883e
DS
1130 "IPv4 address <network>/<length>\n")
1131{
1132 struct in_addr addr;
1133 char buf[INET_ADDRSTRLEN + 8];
1134 struct route_stream *routes = NULL;
1135 struct xroute_stream *xroutes = NULL;
1136 struct prefix prefix;
1137 int ret;
1138
1139 ret = inet_aton (argv[3]->arg, &addr);
1140 if (ret <= 0) {
5c7571d4 1141 vty_out (vty, "%% Malformed address\n");
ca10883e
DS
1142 return CMD_WARNING;
1143 }
1144
1145 /* Quagga has no convenient prefix constructors. */
1146 snprintf(buf, sizeof(buf), "%s/%d", inet_ntoa(addr), 32);
1147
1148 ret = str2prefix(buf, &prefix);
1149 if (ret == 0) {
5c7571d4 1150 vty_out (vty, "%% Parse error -- this shouldn't happen\n");
ca10883e
DS
1151 return CMD_WARNING;
1152 }
1153
1154 routes = route_stream(0);
1155 if(routes) {
1156 while(1) {
1157 struct babel_route *route = route_stream_next(routes);
1158 if(route == NULL)
1159 break;
1160 show_babel_routes_sub(route, vty, &prefix);
1161 }
1162 route_stream_done(routes);
1163 } else {
1164 zlog_err("Couldn't allocate route stream.");
1165 }
dd15627e 1166 xroutes = xroute_stream();
ca10883e
DS
1167 if(xroutes) {
1168 while(1) {
1169 struct xroute *xroute = xroute_stream_next(xroutes);
1170 if(xroute == NULL)
1171 break;
1172 show_babel_xroutes_sub(xroute, vty, &prefix);
1173 }
1174 xroute_stream_done(xroutes);
1175 } else {
1176 zlog_err("Couldn't allocate route stream.");
1177 }
1178 return CMD_SUCCESS;
1179}
1180
1181DEFUN (show_babel_route_addr6,
1182 show_babel_route_addr6_cmd,
1183 "show babel route X:X::X:X",
1184 SHOW_STR
1185 "Babel information\n"
f7bf422e 1186 "Babel internal routing table\n"
ca10883e
DS
1187 "IPv6 address <network>/<length>\n")
1188{
1189 struct in6_addr addr;
1190 char buf1[INET6_ADDRSTRLEN];
1191 char buf[INET6_ADDRSTRLEN + 8];
1192 struct route_stream *routes = NULL;
1193 struct xroute_stream *xroutes = NULL;
1194 struct prefix prefix;
1195 int ret;
1196
1197 ret = inet_pton (AF_INET6, argv[3]->arg, &addr);
1198 if (ret <= 0) {
5c7571d4 1199 vty_out (vty, "%% Malformed address\n");
ca10883e
DS
1200 return CMD_WARNING;
1201 }
1202
1203 /* Quagga has no convenient prefix constructors. */
1204 snprintf(buf, sizeof(buf), "%s/%d",
1205 inet_ntop(AF_INET6, &addr, buf1, sizeof(buf1)), 128);
1206
1207 ret = str2prefix(buf, &prefix);
1208 if (ret == 0) {
5c7571d4 1209 vty_out (vty, "%% Parse error -- this shouldn't happen\n");
ca10883e
DS
1210 return CMD_WARNING;
1211 }
1212
1213 routes = route_stream(0);
1214 if(routes) {
1215 while(1) {
1216 struct babel_route *route = route_stream_next(routes);
1217 if(route == NULL)
1218 break;
1219 show_babel_routes_sub(route, vty, &prefix);
1220 }
1221 route_stream_done(routes);
1222 } else {
1223 zlog_err("Couldn't allocate route stream.");
1224 }
dd15627e 1225 xroutes = xroute_stream();
ca10883e
DS
1226 if(xroutes) {
1227 while(1) {
1228 struct xroute *xroute = xroute_stream_next(xroutes);
1229 if(xroute == NULL)
1230 break;
1231 show_babel_xroutes_sub(xroute, vty, &prefix);
1232 }
1233 xroute_stream_done(xroutes);
1234 } else {
1235 zlog_err("Couldn't allocate route stream.");
1236 }
1237 return CMD_SUCCESS;
1238}
1239
1240DEFUN (show_babel_parameters,
1241 show_babel_parameters_cmd,
1242 "show babel parameters",
1243 SHOW_STR
1244 "Babel information\n"
1245 "Configuration information\n")
1246{
5c7571d4 1247 vty_out (vty, " -- Babel running configuration --\n");
ca10883e 1248 show_babel_main_configuration(vty);
5c7571d4 1249 vty_out (vty, " -- distribution lists --\n");
ca10883e
DS
1250 config_show_distribute(vty);
1251
1252 return CMD_SUCCESS;
1253}
1254
1255void
1256babel_if_init ()
1257{
1258 /* initialize interface list */
ce19a04a
DL
1259 hook_register_prio(if_add, 0, babel_if_new_hook);
1260 hook_register_prio(if_del, 0, babel_if_delete_hook);
ca10883e
DS
1261
1262 babel_enable_if = vector_init (1);
1263
1264 /* install interface node and commands */
1265 install_node (&babel_interface_node, interface_config_write);
bd8d8973 1266 if_cmd_init();
ca10883e
DS
1267
1268 install_element(BABEL_NODE, &babel_network_cmd);
1269 install_element(BABEL_NODE, &no_babel_network_cmd);
1270 install_element(INTERFACE_NODE, &babel_split_horizon_cmd);
1271 install_element(INTERFACE_NODE, &no_babel_split_horizon_cmd);
1272 install_element(INTERFACE_NODE, &babel_set_wired_cmd);
1273 install_element(INTERFACE_NODE, &babel_set_wireless_cmd);
1274 install_element(INTERFACE_NODE, &babel_set_hello_interval_cmd);
1275 install_element(INTERFACE_NODE, &babel_set_update_interval_cmd);
1276 install_element(INTERFACE_NODE, &babel_set_rxcost_cmd);
1277 install_element(INTERFACE_NODE, &babel_set_channel_cmd);
1278 install_element(INTERFACE_NODE, &babel_set_rtt_decay_cmd);
1279 install_element(INTERFACE_NODE, &babel_set_rtt_min_cmd);
1280 install_element(INTERFACE_NODE, &babel_set_rtt_max_cmd);
1281 install_element(INTERFACE_NODE, &babel_set_max_rtt_penalty_cmd);
1282 install_element(INTERFACE_NODE, &babel_set_enable_timestamps_cmd);
1283 install_element(INTERFACE_NODE, &no_babel_set_enable_timestamps_cmd);
1284 install_element(INTERFACE_NODE, &babel_set_channel_interfering_cmd);
1285 install_element(INTERFACE_NODE, &babel_set_channel_noninterfering_cmd);
1286
1287 /* "show babel ..." commands */
1288 install_element(VIEW_NODE, &show_babel_interface_cmd);
1289 install_element(VIEW_NODE, &show_babel_neighbour_cmd);
1290 install_element(VIEW_NODE, &show_babel_route_cmd);
1291 install_element(VIEW_NODE, &show_babel_route_prefix_cmd);
1292 install_element(VIEW_NODE, &show_babel_route_addr_cmd);
1293 install_element(VIEW_NODE, &show_babel_route_addr6_cmd);
1294 install_element(VIEW_NODE, &show_babel_parameters_cmd);
1295}
1296
1297/* hooks: functions called respectively when struct interface is
1298 created or deleted. */
1299static int
1300babel_if_new_hook (struct interface *ifp)
1301{
1302 ifp->info = babel_interface_allocate();
1303 return 0;
1304}
1305
1306static int
1307babel_if_delete_hook (struct interface *ifp)
1308{
1309 babel_interface_free(ifp->info);
1310 ifp->info = NULL;
1311 return 0;
1312}
1313
1314/* Output an "interface" section for each of the known interfaces with
1315babeld-specific statement lines where appropriate. */
1316static int
1317interface_config_write (struct vty *vty)
1318{
f4e14fdb 1319 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
ca10883e
DS
1320 struct interface *ifp;
1321 int write = 0;
1322
f4e14fdb 1323 RB_FOREACH (ifp, if_name_head, &vrf->ifaces_by_name) {
a8b828f3 1324 vty_frame (vty, "interface %s\n",ifp->name);
ca10883e 1325 if (ifp->desc)
5c7571d4 1326 vty_out (vty, " description %s\n",ifp->desc);
ca10883e
DS
1327 babel_interface_nfo *babel_ifp = babel_get_if_nfo (ifp);
1328 /* wireless is the default*/
1329 if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED))
1330 {
5c7571d4 1331 vty_out (vty, " babel wired\n");
ca10883e
DS
1332 write++;
1333 }
1334 if (babel_ifp->hello_interval != BABEL_DEFAULT_HELLO_INTERVAL)
1335 {
5c7571d4 1336 vty_out (vty, " babel hello-interval %u\n",
96ade3ed 1337 babel_ifp->hello_interval);
ca10883e
DS
1338 write++;
1339 }
1340 if (babel_ifp->update_interval != BABEL_DEFAULT_UPDATE_INTERVAL)
1341 {
5c7571d4 1342 vty_out (vty, " babel update-interval %u\n",
96ade3ed 1343 babel_ifp->update_interval);
ca10883e
DS
1344 write++;
1345 }
1346 /* Some parameters have different defaults for wired/wireless. */
1347 if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED)) {
1348 if (!CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON)) {
5c7571d4 1349 vty_out (vty, " no babel split-horizon\n");
ca10883e
DS
1350 write++;
1351 }
1352 if (babel_ifp->cost != BABEL_DEFAULT_RXCOST_WIRED) {
5c7571d4 1353 vty_out (vty, " babel rxcost %u\n", babel_ifp->cost);
ca10883e
DS
1354 write++;
1355 }
1356 if (babel_ifp->channel == BABEL_IF_CHANNEL_INTERFERING) {
5c7571d4 1357 vty_out (vty, " babel channel interfering\n");
ca10883e
DS
1358 write++;
1359 } else if(babel_ifp->channel != BABEL_IF_CHANNEL_NONINTERFERING) {
5c7571d4 1360 vty_out (vty, " babel channel %d\n",babel_ifp->channel);
ca10883e
DS
1361 write++;
1362 }
1363 } else {
1364 if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON)) {
5c7571d4 1365 vty_out (vty, " babel split-horizon\n");
ca10883e
DS
1366 write++;
1367 }
1368 if (babel_ifp->cost != BABEL_DEFAULT_RXCOST_WIRELESS) {
5c7571d4 1369 vty_out (vty, " babel rxcost %u\n", babel_ifp->cost);
ca10883e
DS
1370 write++;
1371 }
1372 if (babel_ifp->channel == BABEL_IF_CHANNEL_NONINTERFERING) {
5c7571d4 1373 vty_out (vty, " babel channel noninterfering\n");
ca10883e
DS
1374 write++;
1375 } else if(babel_ifp->channel != BABEL_IF_CHANNEL_INTERFERING) {
5c7571d4 1376 vty_out (vty, " babel channel %d\n",babel_ifp->channel);
ca10883e
DS
1377 write++;
1378 }
1379 }
a8b828f3 1380 vty_endframe (vty, "!\n");
ca10883e
DS
1381 write++;
1382 }
1383 return write;
1384}
1385
1386/* Output a "network" statement line for each of the enabled interfaces. */
1387int
1388babel_enable_if_config_write (struct vty * vty)
1389{
1390 unsigned int i, lines = 0;
1391 char *str;
1392
1393 for (i = 0; i < vector_active (babel_enable_if); i++)
1394 if ((str = vector_slot (babel_enable_if, i)) != NULL)
1395 {
5c7571d4 1396 vty_out (vty, " network %s\n", str);
ca10883e
DS
1397 lines++;
1398 }
1399 return lines;
1400}
1401
1402/* functions to allocate or free memory for a babel_interface_nfo, filling
1403 needed fields */
1404static babel_interface_nfo *
1405babel_interface_allocate (void)
1406{
1407 babel_interface_nfo *babel_ifp;
1408 babel_ifp = XMALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo));
1409 if(babel_ifp == NULL)
1410 return NULL;
1411
1412 /* Here are set the default values for an interface. */
1413 memset(babel_ifp, 0, sizeof(babel_interface_nfo));
1414 /* All flags are unset */
1415 babel_ifp->bucket_time = babel_now.tv_sec;
1416 babel_ifp->bucket = BUCKET_TOKENS_MAX;
1417 babel_ifp->hello_seqno = (random() & 0xFFFF);
1418 babel_ifp->rtt_min = 10000;
1419 babel_ifp->rtt_max = 120000;
1420 babel_ifp->max_rtt_penalty = 150;
1421 babel_ifp->hello_interval = BABEL_DEFAULT_HELLO_INTERVAL;
1422 babel_ifp->update_interval = BABEL_DEFAULT_UPDATE_INTERVAL;
1423 babel_ifp->channel = BABEL_IF_CHANNEL_INTERFERING;
1424 babel_set_wired_internal(babel_ifp, 0);
1425
1426 return babel_ifp;
1427}
1428
1429static void
1430babel_interface_free (babel_interface_nfo *babel_ifp)
1431{
1432 XFREE(MTYPE_BABEL_IF, babel_ifp);
1433}