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