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