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