]> git.proxmox.com Git - mirror_frr.git/blame - babeld/babel_interface.c
bgpd: Make sure we can use `no bgp listen range ...`
[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"
42#include "babel_memory.h"
f135ba52 43#include "babel_errors.h"
ca10883e
DS
44
45#define IS_ENABLE(ifp) (babel_enable_if_lookup(ifp->name) >= 0)
46
47static int babel_enable_if_lookup (const char *ifname);
48static int babel_enable_if_add (const char *ifname);
49static int babel_enable_if_delete (const char *ifname);
50static int interface_recalculate(struct interface *ifp);
51static int interface_reset(struct interface *ifp);
52static int babel_if_new_hook (struct interface *ifp);
53static int babel_if_delete_hook (struct interface *ifp);
54static int interface_config_write (struct vty *vty);
55static babel_interface_nfo * babel_interface_allocate (void);
56static void babel_interface_free (babel_interface_nfo *bi);
57
58
59static vector babel_enable_if; /* enable interfaces (by cmd). */
60static struct cmd_node babel_interface_node = /* babeld's interface node. */
61{
62 INTERFACE_NODE,
63 "%s(config-if)# ",
64 1 /* VTYSH */
65};
66
67
68int
121f9dee 69babel_interface_up (ZAPI_CALLBACK_ARGS)
ca10883e
DS
70{
71 struct stream *s = NULL;
72 struct interface *ifp = NULL;
73
74 debugf(BABEL_DEBUG_IF, "receive a 'interface up'");
75
76 s = zclient->ibuf;
121f9dee 77 ifp = zebra_interface_state_read(s, vrf_id); /* it updates iflist */
ca10883e
DS
78
79 if (ifp == NULL) {
80 return 0;
81 }
82
83 interface_recalculate(ifp);
84 return 0;
85}
86
87int
121f9dee 88babel_interface_down (ZAPI_CALLBACK_ARGS)
ca10883e
DS
89{
90 struct stream *s = NULL;
91 struct interface *ifp = NULL;
92
93 debugf(BABEL_DEBUG_IF, "receive a 'interface down'");
94
95 s = zclient->ibuf;
121f9dee 96 ifp = zebra_interface_state_read(s, vrf_id); /* it updates iflist */
ca10883e
DS
97
98 if (ifp == NULL) {
99 return 0;
100 }
101
102 interface_reset(ifp);
103 return 0;
104}
105
106int
121f9dee 107babel_interface_add (ZAPI_CALLBACK_ARGS)
ca10883e
DS
108{
109 struct interface *ifp = NULL;
110
111 debugf(BABEL_DEBUG_IF, "receive a 'interface add'");
112
113 /* read and add the interface in the iflist. */
121f9dee 114 ifp = zebra_interface_add_read (zclient->ibuf, vrf_id);
ca10883e
DS
115
116 if (ifp == NULL) {
117 return 0;
118 }
119
120 interface_recalculate(ifp);
121 return 0;
122}
123
124int
121f9dee 125babel_interface_delete (ZAPI_CALLBACK_ARGS)
ca10883e
DS
126{
127 struct interface *ifp;
128 struct stream *s;
129
130 debugf(BABEL_DEBUG_IF, "receive a 'interface delete'");
131
132 s = zclient->ibuf;
121f9dee 133 ifp = zebra_interface_state_read(s, vrf_id); /* it updates iflist */
ca10883e
DS
134
135 if (ifp == NULL)
136 return 0;
137
138 if (IS_ENABLE(ifp))
139 interface_reset(ifp);
140
141 /* To support pseudo interface do not free interface structure. */
142 /* if_delete(ifp); */
ff880b78 143 if_set_index(ifp, IFINDEX_INTERNAL);
ca10883e
DS
144
145 return 0;
146}
147
148int
121f9dee 149babel_interface_address_add (ZAPI_CALLBACK_ARGS)
ca10883e
DS
150{
151 babel_interface_nfo *babel_ifp;
152 struct connected *ifc;
153 struct prefix *prefix;
154
155 debugf(BABEL_DEBUG_IF, "receive a 'interface address add'");
156
157 ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD,
121f9dee 158 zclient->ibuf, vrf_id);
ca10883e
DS
159
160 if (ifc == NULL)
161 return 0;
162
163 prefix = ifc->address;
164
165 if (prefix->family == AF_INET) {
166 flush_interface_routes(ifc->ifp, 0);
167 babel_ifp = babel_get_if_nfo(ifc->ifp);
168 if (babel_ifp->ipv4 == NULL) {
169 babel_ifp->ipv4 = malloc(4);
170 if (babel_ifp->ipv4 == NULL) {
5b003f31 171 flog_err(EC_BABEL_MEMORY, "not enough memory");
ca10883e
DS
172 } else {
173 memcpy(babel_ifp->ipv4, &prefix->u.prefix4, 4);
174 }
175 }
176 }
177
178 send_request(ifc->ifp, NULL, 0);
179 send_update(ifc->ifp, 0, NULL, 0);
180
181 return 0;
182}
183
184int
121f9dee 185babel_interface_address_delete (ZAPI_CALLBACK_ARGS)
ca10883e
DS
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,
121f9dee 194 zclient->ibuf, vrf_id);
ca10883e
DS
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) {
5b003f31 710 flog_err(EC_BABEL_MEMORY, "Couldn't reallocate sendbuf.");
ca10883e
DS
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) {
450971aa 730 flog_err_sys(EC_LIB_SOCKET,
f135ba52
DS
731 "setsockopt(IPV6_JOIN_GROUP) on interface '%s': %s",
732 ifp->name, safe_strerror(errno));
ca10883e
DS
733 /* This is probably due to a missing link-local address,
734 so down this interface, and wait until the main loop
735 tries to up it again. */
736 interface_reset(ifp);
737 return -1;
738 }
739
740 set_timeout(&babel_ifp->hello_timeout, babel_ifp->hello_interval);
741 set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval);
742 send_hello(ifp);
743 send_request(ifp, NULL, 0);
744
745 update_interface_metric(ifp);
746
747 debugf(BABEL_DEBUG_COMMON,
748 "Upped interface %s (%s, cost=%d, channel=%d%s).",
749 ifp->name,
750 (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless",
751 babel_ifp->cost,
752 babel_ifp->channel,
753 babel_ifp->ipv4 ? ", IPv4" : "");
754
755 if(rc > 0)
756 send_update(ifp, 0, NULL, 0);
757
758 return 1;
759}
760
761/* Reset the interface as it was new: it's not removed from the interface list,
762 and may be considered as a upped interface. */
763static int
764interface_reset(struct interface *ifp)
765{
766 int rc;
767 struct ipv6_mreq mreq;
768 babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
769
770 if (!(babel_ifp->flags & BABEL_IF_IS_UP))
771 return 0;
772
773 debugf(BABEL_DEBUG_IF, "interface reset: %s", ifp->name);
774 babel_ifp->flags &= ~BABEL_IF_IS_UP;
775
776 flush_interface_routes(ifp, 0);
777 babel_ifp->buffered = 0;
778 babel_ifp->bufsize = 0;
779 free(babel_ifp->sendbuf);
780 babel_ifp->num_buffered_updates = 0;
781 babel_ifp->update_bufsize = 0;
782 if(babel_ifp->buffered_updates)
783 free(babel_ifp->buffered_updates);
784 babel_ifp->buffered_updates = NULL;
785 babel_ifp->sendbuf = NULL;
786
787 if(ifp->ifindex > 0) {
788 memset(&mreq, 0, sizeof(mreq));
789 memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16);
790 mreq.ipv6mr_interface = ifp->ifindex;
791 rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
792 (char*)&mreq, sizeof(mreq));
793 if(rc < 0)
450971aa 794 flog_err_sys(EC_LIB_SOCKET,
f135ba52
DS
795 "setsockopt(IPV6_LEAVE_GROUP) on interface '%s': %s",
796 ifp->name, safe_strerror(errno));
ca10883e
DS
797 }
798
799 update_interface_metric(ifp);
800
801 debugf(BABEL_DEBUG_COMMON,"Upped network %s (%s, cost=%d%s).",
802 ifp->name,
803 (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless",
804 babel_ifp->cost,
805 babel_ifp->ipv4 ? ", IPv4" : "");
806
807 return 1;
808}
809
810/* Send retraction to all, and reset all interfaces statistics. */
811void
812babel_interface_close_all(void)
813{
f4e14fdb 814 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
ca10883e 815 struct interface *ifp = NULL;
ca10883e 816
f4e14fdb 817 FOR_ALL_INTERFACES(vrf, ifp) {
ca10883e
DS
818 if(!if_up(ifp))
819 continue;
820 send_wildcard_retraction(ifp);
821 /* Make sure that we expire quickly from our neighbours'
822 association caches. */
823 send_hello_noupdate(ifp, 10);
824 flushbuf(ifp);
825 usleep(roughly(1000));
826 gettime(&babel_now);
827 }
f4e14fdb 828 FOR_ALL_INTERFACES(vrf, ifp) {
ca10883e
DS
829 if(!if_up(ifp))
830 continue;
831 /* Make sure they got it. */
832 send_wildcard_retraction(ifp);
833 send_hello_noupdate(ifp, 1);
834 flushbuf(ifp);
835 usleep(roughly(10000));
836 gettime(&babel_now);
837 interface_reset(ifp);
838 }
839}
840
841/* return "true" if address is one of our ipv6 addresses */
842int
843is_interface_ll_address(struct interface *ifp, const unsigned char *address)
844{
845 struct connected *connected;
846 struct listnode *node;
847
848 if(!if_up(ifp))
849 return 0;
850
851 FOR_ALL_INTERFACES_ADDRESSES(ifp, connected, node) {
852 if(connected->address->family == AF_INET6 &&
853 memcmp(&connected->address->u.prefix6, address, 16) == 0)
854 return 1;
855 }
856
857 return 0;
858}
859
860static void
861show_babel_interface_sub (struct vty *vty, struct interface *ifp)
862{
863 int is_up;
864 babel_interface_nfo *babel_ifp;
865
5c7571d4 866 vty_out (vty, "%s is %s\n", ifp->name,
96ade3ed 867 ((is_up = if_is_operative(ifp)) ? "up" : "down"));
5c7571d4 868 vty_out (vty, " ifindex %u, MTU %u bytes %s\n",
96ade3ed 869 ifp->ifindex, MIN(ifp->mtu, ifp->mtu6), if_flag_dump(ifp->flags));
ca10883e
DS
870
871 if (!IS_ENABLE(ifp))
872 {
5c7571d4 873 vty_out (vty, " Babel protocol is not enabled on this interface\n");
ca10883e
DS
874 return;
875 }
876 if (!is_up)
877 {
5c7571d4
DL
878 vty_out (vty,
879 " Babel protocol is enabled, but not running on this interface\n");
ca10883e
DS
880 return;
881 }
882 babel_ifp = babel_get_if_nfo (ifp);
5c7571d4 883 vty_out (vty, " Babel protocol is running on this interface\n");
181039f3 884 vty_out (vty, " Operating mode is \"%s\"\n",
96ade3ed 885 CHECK_FLAG(babel_ifp->flags, BABEL_IF_WIRED) ? "wired" : "wireless");
5c7571d4 886 vty_out (vty, " Split horizon mode is %s\n",
96ade3ed 887 CHECK_FLAG(babel_ifp->flags, BABEL_IF_SPLIT_HORIZON) ? "On" : "Off");
5c7571d4
DL
888 vty_out (vty, " Hello interval is %u ms\n", babel_ifp->hello_interval);
889 vty_out (vty, " Update interval is %u ms\n", babel_ifp->update_interval);
890 vty_out (vty, " Rxcost multiplier is %u\n", babel_ifp->cost);
ca10883e
DS
891}
892
893DEFUN (show_babel_interface,
894 show_babel_interface_cmd,
895 "show babel interface [IFNAME]",
896 SHOW_STR
897 "Babel information\n"
898 "Interface information\n"
899 "Interface\n")
900{
f4e14fdb 901 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
ca10883e 902 struct interface *ifp;
ca10883e
DS
903
904 if (argc == 3)
905 {
451fda4f 906 FOR_ALL_INTERFACES (vrf, ifp)
ca10883e
DS
907 show_babel_interface_sub (vty, ifp);
908 return CMD_SUCCESS;
909 }
910 if ((ifp = if_lookup_by_name (argv[3]->arg, VRF_DEFAULT)) == NULL)
911 {
5c7571d4 912 vty_out (vty, "No such interface name\n");
ca10883e
DS
913 return CMD_WARNING;
914 }
915 show_babel_interface_sub (vty, ifp);
916 return CMD_SUCCESS;
917}
918
919static void
920show_babel_neighbour_sub (struct vty *vty, struct neighbour *neigh)
921{
181039f3 922 vty_out (vty,
ca10883e 923 "Neighbour %s dev %s reach %04x rxcost %d txcost %d "
181039f3 924 "rtt %s rttcost %d%s.\n",
ca10883e
DS
925 format_address(neigh->address),
926 neigh->ifp->name,
927 neigh->reach,
928 neighbour_rxcost(neigh),
929 neigh->txcost,
930 format_thousands(neigh->rtt),
931 neighbour_rttcost(neigh),
96ade3ed 932 if_up(neigh->ifp) ? "" : " (down)");
ca10883e
DS
933}
934
935DEFUN (show_babel_neighbour,
936 show_babel_neighbour_cmd,
937 "show babel neighbor [IFNAME]",
938 SHOW_STR
939 "Babel information\n"
940 "Print neighbors\n"
941 "Interface\n")
942{
943 struct neighbour *neigh;
944 struct interface *ifp;
945
946 if (argc == 3) {
947 FOR_ALL_NEIGHBOURS(neigh) {
948 show_babel_neighbour_sub(vty, neigh);
949 }
950 return CMD_SUCCESS;
951 }
952 if ((ifp = if_lookup_by_name (argv[3]->arg, VRF_DEFAULT)) == NULL)
953 {
5c7571d4 954 vty_out (vty, "No such interface name\n");
ca10883e
DS
955 return CMD_WARNING;
956 }
957 FOR_ALL_NEIGHBOURS(neigh) {
958 if(ifp->ifindex == neigh->ifp->ifindex) {
959 show_babel_neighbour_sub(vty, neigh);
960 }
961 }
962 return CMD_SUCCESS;
963}
964
965static int
966babel_prefix_eq(struct prefix *prefix, unsigned char *p, int plen)
967{
968 if(prefix->family == AF_INET6) {
969 if(prefix->prefixlen != plen ||
970 memcmp(&prefix->u.prefix6, p, 16) != 0)
971 return 0;
972 } else if(prefix->family == AF_INET) {
973 if(plen < 96 || !v4mapped(p) || prefix->prefixlen != plen - 96 ||
974 memcmp(&prefix->u.prefix4, p + 12, 4) != 0)
975 return 0;
976 } else {
977 return 0;
978 }
979
980 return 1;
981}
982
983static void
984show_babel_routes_sub(struct babel_route *route, struct vty *vty,
985 struct prefix *prefix)
986{
987 const unsigned char *nexthop =
988 memcmp(route->nexthop, route->neigh->address, 16) == 0 ?
989 NULL : route->nexthop;
990 char channels[100];
991
992 if(prefix && !babel_prefix_eq(prefix, route->src->prefix, route->src->plen))
993 return;
994
995 if(route->channels[0] == 0)
996 channels[0] = '\0';
997 else {
998 int k, j = 0;
999 snprintf(channels, 100, " chan (");
1000 j = strlen(channels);
1001 for(k = 0; k < DIVERSITY_HOPS; k++) {
1002 if(route->channels[k] == 0)
1003 break;
1004 if(k > 0)
1005 channels[j++] = ',';
2ec42b85 1006 snprintf(channels + j, 100 - j, "%u", route->channels[k]);
ca10883e
DS
1007 j = strlen(channels);
1008 }
1009 snprintf(channels + j, 100 - j, ")");
1010 if(k == 0)
1011 channels[0] = '\0';
1012 }
1013
181039f3 1014 vty_out (vty,
ca10883e 1015 "%s metric %d refmetric %d id %s seqno %d%s age %d "
181039f3 1016 "via %s neigh %s%s%s%s\n",
ca10883e
DS
1017 format_prefix(route->src->prefix, route->src->plen),
1018 route_metric(route), route->refmetric,
1019 format_eui64(route->src->id),
1020 (int)route->seqno,
1021 channels,
1022 (int)(babel_now.tv_sec - route->time),
1023 route->neigh->ifp->name,
1024 format_address(route->neigh->address),
1025 nexthop ? " nexthop " : "",
1026 nexthop ? format_address(nexthop) : "",
96ade3ed 1027 route->installed ? " (installed)" : route_feasible(route) ? " (feasible)" : "");
ca10883e
DS
1028}
1029
1030static void
1031show_babel_xroutes_sub (struct xroute *xroute, struct vty *vty,
1032 struct prefix *prefix)
1033{
1034 if(prefix && !babel_prefix_eq(prefix, xroute->prefix, xroute->plen))
1035 return;
1036
5c7571d4 1037 vty_out (vty, "%s metric %d (exported)\n",
ca10883e 1038 format_prefix(xroute->prefix, xroute->plen),
96ade3ed 1039 xroute->metric);
ca10883e
DS
1040}
1041
1042DEFUN (show_babel_route,
1043 show_babel_route_cmd,
1044 "show babel route",
1045 SHOW_STR
1046 "Babel information\n"
1047 "Babel internal routing table\n")
1048{
1049 struct route_stream *routes = NULL;
1050 struct xroute_stream *xroutes = NULL;
1051 routes = route_stream(0);
1052 if(routes) {
1053 while(1) {
1054 struct babel_route *route = route_stream_next(routes);
1055 if(route == NULL)
1056 break;
1057 show_babel_routes_sub(route, vty, NULL);
1058 }
1059 route_stream_done(routes);
1060 } else {
5b003f31 1061 flog_err(EC_BABEL_MEMORY, "Couldn't allocate route stream.");
ca10883e 1062 }
dd15627e 1063 xroutes = xroute_stream();
ca10883e
DS
1064 if(xroutes) {
1065 while(1) {
1066 struct xroute *xroute = xroute_stream_next(xroutes);
1067 if(xroute == NULL)
1068 break;
1069 show_babel_xroutes_sub(xroute, vty, NULL);
1070 }
1071 xroute_stream_done(xroutes);
1072 } else {
5b003f31 1073 flog_err(EC_BABEL_MEMORY, "Couldn't allocate route stream.");
ca10883e
DS
1074 }
1075 return CMD_SUCCESS;
1076}
1077
1078DEFUN (show_babel_route_prefix,
1079 show_babel_route_prefix_cmd,
1080 "show babel route <A.B.C.D/M|X:X::X:X/M>",
1081 SHOW_STR
1082 "Babel information\n"
f7bf422e 1083 "Babel internal routing table\n"
ca10883e
DS
1084 "IPv4 prefix <network>/<length>\n"
1085 "IPv6 prefix <network>/<length>\n")
1086{
1087 struct route_stream *routes = NULL;
1088 struct xroute_stream *xroutes = NULL;
1089 struct prefix prefix;
1090 int ret;
1091
1092 ret = str2prefix(argv[3]->arg, &prefix);
1093 if(ret == 0) {
5c7571d4 1094 vty_out (vty, "%% Malformed address\n");
ca10883e
DS
1095 return CMD_WARNING;
1096 }
1097
1098 routes = route_stream(0);
1099 if(routes) {
1100 while(1) {
1101 struct babel_route *route = route_stream_next(routes);
1102 if(route == NULL)
1103 break;
1104 show_babel_routes_sub(route, vty, &prefix);
1105 }
1106 route_stream_done(routes);
1107 } else {
5b003f31 1108 flog_err(EC_BABEL_MEMORY, "Couldn't allocate route stream.");
ca10883e 1109 }
dd15627e 1110 xroutes = xroute_stream();
ca10883e
DS
1111 if(xroutes) {
1112 while(1) {
1113 struct xroute *xroute = xroute_stream_next(xroutes);
1114 if(xroute == NULL)
1115 break;
1116 show_babel_xroutes_sub(xroute, vty, &prefix);
1117 }
1118 xroute_stream_done(xroutes);
1119 } else {
5b003f31 1120 flog_err(EC_BABEL_MEMORY, "Couldn't allocate route stream.");
ca10883e
DS
1121 }
1122 return CMD_SUCCESS;
1123}
1124
1125
1126DEFUN (show_babel_route_addr,
1127 show_babel_route_addr_cmd,
1128 "show babel route A.B.C.D",
1129 SHOW_STR
1130 "Babel information\n"
f7bf422e 1131 "Babel internal routing table\n"
ca10883e
DS
1132 "IPv4 address <network>/<length>\n")
1133{
1134 struct in_addr addr;
1135 char buf[INET_ADDRSTRLEN + 8];
1136 struct route_stream *routes = NULL;
1137 struct xroute_stream *xroutes = NULL;
1138 struct prefix prefix;
1139 int ret;
1140
1141 ret = inet_aton (argv[3]->arg, &addr);
1142 if (ret <= 0) {
5c7571d4 1143 vty_out (vty, "%% Malformed address\n");
ca10883e
DS
1144 return CMD_WARNING;
1145 }
1146
1147 /* Quagga has no convenient prefix constructors. */
1148 snprintf(buf, sizeof(buf), "%s/%d", inet_ntoa(addr), 32);
1149
1150 ret = str2prefix(buf, &prefix);
1151 if (ret == 0) {
5c7571d4 1152 vty_out (vty, "%% Parse error -- this shouldn't happen\n");
ca10883e
DS
1153 return CMD_WARNING;
1154 }
1155
1156 routes = route_stream(0);
1157 if(routes) {
1158 while(1) {
1159 struct babel_route *route = route_stream_next(routes);
1160 if(route == NULL)
1161 break;
1162 show_babel_routes_sub(route, vty, &prefix);
1163 }
1164 route_stream_done(routes);
1165 } else {
5b003f31 1166 flog_err(EC_BABEL_MEMORY, "Couldn't allocate route stream.");
ca10883e 1167 }
dd15627e 1168 xroutes = xroute_stream();
ca10883e
DS
1169 if(xroutes) {
1170 while(1) {
1171 struct xroute *xroute = xroute_stream_next(xroutes);
1172 if(xroute == NULL)
1173 break;
1174 show_babel_xroutes_sub(xroute, vty, &prefix);
1175 }
1176 xroute_stream_done(xroutes);
1177 } else {
5b003f31 1178 flog_err(EC_BABEL_MEMORY, "Couldn't allocate route stream.");
ca10883e
DS
1179 }
1180 return CMD_SUCCESS;
1181}
1182
1183DEFUN (show_babel_route_addr6,
1184 show_babel_route_addr6_cmd,
1185 "show babel route X:X::X:X",
1186 SHOW_STR
1187 "Babel information\n"
f7bf422e 1188 "Babel internal routing table\n"
ca10883e
DS
1189 "IPv6 address <network>/<length>\n")
1190{
1191 struct in6_addr addr;
1192 char buf1[INET6_ADDRSTRLEN];
1193 char buf[INET6_ADDRSTRLEN + 8];
1194 struct route_stream *routes = NULL;
1195 struct xroute_stream *xroutes = NULL;
1196 struct prefix prefix;
1197 int ret;
1198
1199 ret = inet_pton (AF_INET6, argv[3]->arg, &addr);
1200 if (ret <= 0) {
5c7571d4 1201 vty_out (vty, "%% Malformed address\n");
ca10883e
DS
1202 return CMD_WARNING;
1203 }
1204
1205 /* Quagga has no convenient prefix constructors. */
1206 snprintf(buf, sizeof(buf), "%s/%d",
1207 inet_ntop(AF_INET6, &addr, buf1, sizeof(buf1)), 128);
1208
1209 ret = str2prefix(buf, &prefix);
1210 if (ret == 0) {
5c7571d4 1211 vty_out (vty, "%% Parse error -- this shouldn't happen\n");
ca10883e
DS
1212 return CMD_WARNING;
1213 }
1214
1215 routes = route_stream(0);
1216 if(routes) {
1217 while(1) {
1218 struct babel_route *route = route_stream_next(routes);
1219 if(route == NULL)
1220 break;
1221 show_babel_routes_sub(route, vty, &prefix);
1222 }
1223 route_stream_done(routes);
1224 } else {
5b003f31 1225 flog_err(EC_BABEL_MEMORY, "Couldn't allocate route stream.");
ca10883e 1226 }
dd15627e 1227 xroutes = xroute_stream();
ca10883e
DS
1228 if(xroutes) {
1229 while(1) {
1230 struct xroute *xroute = xroute_stream_next(xroutes);
1231 if(xroute == NULL)
1232 break;
1233 show_babel_xroutes_sub(xroute, vty, &prefix);
1234 }
1235 xroute_stream_done(xroutes);
1236 } else {
5b003f31 1237 flog_err(EC_BABEL_MEMORY, "Couldn't allocate route stream.");
ca10883e
DS
1238 }
1239 return CMD_SUCCESS;
1240}
1241
1242DEFUN (show_babel_parameters,
1243 show_babel_parameters_cmd,
1244 "show babel parameters",
1245 SHOW_STR
1246 "Babel information\n"
1247 "Configuration information\n")
1248{
03a38493
PG
1249 struct babel *babel_ctx;
1250
5c7571d4 1251 vty_out (vty, " -- Babel running configuration --\n");
ca10883e 1252 show_babel_main_configuration(vty);
ca10883e 1253
03a38493
PG
1254 babel_ctx = babel_lookup();
1255 if (babel_ctx) {
1256 vty_out (vty, " -- distribution lists --\n");
1257 config_show_distribute(vty, babel_ctx->distribute_ctx);
1258 }
ca10883e
DS
1259 return CMD_SUCCESS;
1260}
1261
1262void
4d762f26 1263babel_if_init(void)
ca10883e
DS
1264{
1265 /* initialize interface list */
ce19a04a
DL
1266 hook_register_prio(if_add, 0, babel_if_new_hook);
1267 hook_register_prio(if_del, 0, babel_if_delete_hook);
ca10883e
DS
1268
1269 babel_enable_if = vector_init (1);
1270
1271 /* install interface node and commands */
1272 install_node (&babel_interface_node, interface_config_write);
bd8d8973 1273 if_cmd_init();
ca10883e
DS
1274
1275 install_element(BABEL_NODE, &babel_network_cmd);
1276 install_element(BABEL_NODE, &no_babel_network_cmd);
1277 install_element(INTERFACE_NODE, &babel_split_horizon_cmd);
1278 install_element(INTERFACE_NODE, &no_babel_split_horizon_cmd);
1279 install_element(INTERFACE_NODE, &babel_set_wired_cmd);
1280 install_element(INTERFACE_NODE, &babel_set_wireless_cmd);
1281 install_element(INTERFACE_NODE, &babel_set_hello_interval_cmd);
1282 install_element(INTERFACE_NODE, &babel_set_update_interval_cmd);
1283 install_element(INTERFACE_NODE, &babel_set_rxcost_cmd);
1284 install_element(INTERFACE_NODE, &babel_set_channel_cmd);
1285 install_element(INTERFACE_NODE, &babel_set_rtt_decay_cmd);
1286 install_element(INTERFACE_NODE, &babel_set_rtt_min_cmd);
1287 install_element(INTERFACE_NODE, &babel_set_rtt_max_cmd);
1288 install_element(INTERFACE_NODE, &babel_set_max_rtt_penalty_cmd);
1289 install_element(INTERFACE_NODE, &babel_set_enable_timestamps_cmd);
1290 install_element(INTERFACE_NODE, &no_babel_set_enable_timestamps_cmd);
1291 install_element(INTERFACE_NODE, &babel_set_channel_interfering_cmd);
1292 install_element(INTERFACE_NODE, &babel_set_channel_noninterfering_cmd);
1293
1294 /* "show babel ..." commands */
1295 install_element(VIEW_NODE, &show_babel_interface_cmd);
1296 install_element(VIEW_NODE, &show_babel_neighbour_cmd);
1297 install_element(VIEW_NODE, &show_babel_route_cmd);
1298 install_element(VIEW_NODE, &show_babel_route_prefix_cmd);
1299 install_element(VIEW_NODE, &show_babel_route_addr_cmd);
1300 install_element(VIEW_NODE, &show_babel_route_addr6_cmd);
1301 install_element(VIEW_NODE, &show_babel_parameters_cmd);
1302}
1303
1304/* hooks: functions called respectively when struct interface is
1305 created or deleted. */
1306static int
1307babel_if_new_hook (struct interface *ifp)
1308{
1309 ifp->info = babel_interface_allocate();
1310 return 0;
1311}
1312
1313static int
1314babel_if_delete_hook (struct interface *ifp)
1315{
1316 babel_interface_free(ifp->info);
1317 ifp->info = NULL;
1318 return 0;
1319}
1320
1321/* Output an "interface" section for each of the known interfaces with
1322babeld-specific statement lines where appropriate. */
1323static int
1324interface_config_write (struct vty *vty)
1325{
f4e14fdb 1326 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
ca10883e
DS
1327 struct interface *ifp;
1328 int write = 0;
1329
451fda4f 1330 FOR_ALL_INTERFACES (vrf, ifp) {
a8b828f3 1331 vty_frame (vty, "interface %s\n",ifp->name);
ca10883e 1332 if (ifp->desc)
5c7571d4 1333 vty_out (vty, " description %s\n",ifp->desc);
ca10883e
DS
1334 babel_interface_nfo *babel_ifp = babel_get_if_nfo (ifp);
1335 /* wireless is the default*/
1336 if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED))
1337 {
5c7571d4 1338 vty_out (vty, " babel wired\n");
ca10883e
DS
1339 write++;
1340 }
1341 if (babel_ifp->hello_interval != BABEL_DEFAULT_HELLO_INTERVAL)
1342 {
5c7571d4 1343 vty_out (vty, " babel hello-interval %u\n",
96ade3ed 1344 babel_ifp->hello_interval);
ca10883e
DS
1345 write++;
1346 }
1347 if (babel_ifp->update_interval != BABEL_DEFAULT_UPDATE_INTERVAL)
1348 {
5c7571d4 1349 vty_out (vty, " babel update-interval %u\n",
96ade3ed 1350 babel_ifp->update_interval);
ca10883e
DS
1351 write++;
1352 }
1353 /* Some parameters have different defaults for wired/wireless. */
1354 if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED)) {
1355 if (!CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON)) {
5c7571d4 1356 vty_out (vty, " no babel split-horizon\n");
ca10883e
DS
1357 write++;
1358 }
1359 if (babel_ifp->cost != BABEL_DEFAULT_RXCOST_WIRED) {
5c7571d4 1360 vty_out (vty, " babel rxcost %u\n", babel_ifp->cost);
ca10883e
DS
1361 write++;
1362 }
1363 if (babel_ifp->channel == BABEL_IF_CHANNEL_INTERFERING) {
5c7571d4 1364 vty_out (vty, " babel channel interfering\n");
ca10883e
DS
1365 write++;
1366 } else if(babel_ifp->channel != BABEL_IF_CHANNEL_NONINTERFERING) {
5c7571d4 1367 vty_out (vty, " babel channel %d\n",babel_ifp->channel);
ca10883e
DS
1368 write++;
1369 }
1370 } else {
1371 if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON)) {
5c7571d4 1372 vty_out (vty, " babel split-horizon\n");
ca10883e
DS
1373 write++;
1374 }
1375 if (babel_ifp->cost != BABEL_DEFAULT_RXCOST_WIRELESS) {
5c7571d4 1376 vty_out (vty, " babel rxcost %u\n", babel_ifp->cost);
ca10883e
DS
1377 write++;
1378 }
1379 if (babel_ifp->channel == BABEL_IF_CHANNEL_NONINTERFERING) {
5c7571d4 1380 vty_out (vty, " babel channel noninterfering\n");
ca10883e
DS
1381 write++;
1382 } else if(babel_ifp->channel != BABEL_IF_CHANNEL_INTERFERING) {
5c7571d4 1383 vty_out (vty, " babel channel %d\n",babel_ifp->channel);
ca10883e
DS
1384 write++;
1385 }
1386 }
a8b828f3 1387 vty_endframe (vty, "!\n");
ca10883e
DS
1388 write++;
1389 }
1390 return write;
1391}
1392
1393/* Output a "network" statement line for each of the enabled interfaces. */
1394int
1395babel_enable_if_config_write (struct vty * vty)
1396{
1397 unsigned int i, lines = 0;
1398 char *str;
1399
1400 for (i = 0; i < vector_active (babel_enable_if); i++)
1401 if ((str = vector_slot (babel_enable_if, i)) != NULL)
1402 {
5c7571d4 1403 vty_out (vty, " network %s\n", str);
ca10883e
DS
1404 lines++;
1405 }
1406 return lines;
1407}
1408
1409/* functions to allocate or free memory for a babel_interface_nfo, filling
1410 needed fields */
1411static babel_interface_nfo *
1412babel_interface_allocate (void)
1413{
1414 babel_interface_nfo *babel_ifp;
aa406bbc 1415 babel_ifp = XCALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo));
ca10883e
DS
1416 /* All flags are unset */
1417 babel_ifp->bucket_time = babel_now.tv_sec;
1418 babel_ifp->bucket = BUCKET_TOKENS_MAX;
1419 babel_ifp->hello_seqno = (random() & 0xFFFF);
1420 babel_ifp->rtt_min = 10000;
1421 babel_ifp->rtt_max = 120000;
1422 babel_ifp->max_rtt_penalty = 150;
1423 babel_ifp->hello_interval = BABEL_DEFAULT_HELLO_INTERVAL;
1424 babel_ifp->update_interval = BABEL_DEFAULT_UPDATE_INTERVAL;
1425 babel_ifp->channel = BABEL_IF_CHANNEL_INTERFERING;
1426 babel_set_wired_internal(babel_ifp, 0);
1427
1428 return babel_ifp;
1429}
1430
1431static void
1432babel_interface_free (babel_interface_nfo *babel_ifp)
1433{
1434 XFREE(MTYPE_BABEL_IF, babel_ifp);
1435}