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