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