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