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