]> git.proxmox.com Git - mirror_frr.git/blob - babeld/babel_interface.c
Merge pull request #4244 from donaldsharp/pim_single_interface
[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
32 #include "babel_main.h"
33 #include "util.h"
34 #include "kernel.h"
35 #include "babel_interface.h"
36 #include "message.h"
37 #include "route.h"
38 #include "babel_zebra.h"
39 #include "neighbour.h"
40 #include "route.h"
41 #include "xroute.h"
42 #include "babel_memory.h"
43 #include "babel_errors.h"
44
45 #define IS_ENABLE(ifp) (babel_enable_if_lookup(ifp->name) >= 0)
46
47 static int babel_enable_if_lookup (const char *ifname);
48 static int babel_enable_if_add (const char *ifname);
49 static int babel_enable_if_delete (const char *ifname);
50 static int interface_recalculate(struct interface *ifp);
51 static int interface_reset(struct interface *ifp);
52 static int babel_if_new_hook (struct interface *ifp);
53 static int babel_if_delete_hook (struct interface *ifp);
54 static int interface_config_write (struct vty *vty);
55 static babel_interface_nfo * babel_interface_allocate (void);
56 static void babel_interface_free (babel_interface_nfo *bi);
57
58
59 static vector babel_enable_if; /* enable interfaces (by cmd). */
60 static struct cmd_node babel_interface_node = /* babeld's interface node. */
61 {
62 INTERFACE_NODE,
63 "%s(config-if)# ",
64 1 /* VTYSH */
65 };
66
67
68 int
69 babel_interface_up (ZAPI_CALLBACK_ARGS)
70 {
71 struct stream *s = NULL;
72 struct interface *ifp = NULL;
73
74 debugf(BABEL_DEBUG_IF, "receive a 'interface up'");
75
76 s = zclient->ibuf;
77 ifp = zebra_interface_state_read(s, vrf_id); /* it updates iflist */
78
79 if (ifp == NULL) {
80 return 0;
81 }
82
83 interface_recalculate(ifp);
84 return 0;
85 }
86
87 int
88 babel_interface_down (ZAPI_CALLBACK_ARGS)
89 {
90 struct stream *s = NULL;
91 struct interface *ifp = NULL;
92
93 debugf(BABEL_DEBUG_IF, "receive a 'interface down'");
94
95 s = zclient->ibuf;
96 ifp = zebra_interface_state_read(s, vrf_id); /* it updates iflist */
97
98 if (ifp == NULL) {
99 return 0;
100 }
101
102 interface_reset(ifp);
103 return 0;
104 }
105
106 int
107 babel_interface_add (ZAPI_CALLBACK_ARGS)
108 {
109 struct interface *ifp = NULL;
110
111 debugf(BABEL_DEBUG_IF, "receive a 'interface add'");
112
113 /* read and add the interface in the iflist. */
114 ifp = zebra_interface_add_read (zclient->ibuf, vrf_id);
115
116 if (ifp == NULL) {
117 return 0;
118 }
119
120 interface_recalculate(ifp);
121 return 0;
122 }
123
124 int
125 babel_interface_delete (ZAPI_CALLBACK_ARGS)
126 {
127 struct interface *ifp;
128 struct stream *s;
129
130 debugf(BABEL_DEBUG_IF, "receive a 'interface delete'");
131
132 s = zclient->ibuf;
133 ifp = zebra_interface_state_read(s, vrf_id); /* it updates iflist */
134
135 if (ifp == NULL)
136 return 0;
137
138 if (IS_ENABLE(ifp))
139 interface_reset(ifp);
140
141 /* To support pseudo interface do not free interface structure. */
142 /* if_delete(ifp); */
143 if_set_index(ifp, IFINDEX_INTERNAL);
144
145 return 0;
146 }
147
148 int
149 babel_interface_address_add (ZAPI_CALLBACK_ARGS)
150 {
151 babel_interface_nfo *babel_ifp;
152 struct connected *ifc;
153 struct prefix *prefix;
154
155 debugf(BABEL_DEBUG_IF, "receive a 'interface address add'");
156
157 ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD,
158 zclient->ibuf, vrf_id);
159
160 if (ifc == NULL)
161 return 0;
162
163 prefix = ifc->address;
164
165 if (prefix->family == AF_INET) {
166 flush_interface_routes(ifc->ifp, 0);
167 babel_ifp = babel_get_if_nfo(ifc->ifp);
168 if (babel_ifp->ipv4 == NULL) {
169 babel_ifp->ipv4 = malloc(4);
170 if (babel_ifp->ipv4 == NULL) {
171 flog_err(EC_BABEL_MEMORY, "not enough memory");
172 } else {
173 memcpy(babel_ifp->ipv4, &prefix->u.prefix4, 4);
174 }
175 }
176 }
177
178 send_request(ifc->ifp, NULL, 0);
179 send_update(ifc->ifp, 0, NULL, 0);
180
181 return 0;
182 }
183
184 int
185 babel_interface_address_delete (ZAPI_CALLBACK_ARGS)
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_id);
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. */
218 static int
219 babel_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. */
232 static int
233 babel_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. */
252 static int
253 babel_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. */
275 DEFUN (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\n")
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\n",
294 argv[1]->arg);
295 return CMD_WARNING;
296 }
297
298 return CMD_SUCCESS;
299 }
300
301 /* [Babel Command] Babel enable on specified interface or matched network. */
302 DEFUN (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\n")
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\n",argv[2]->arg);
322 return CMD_WARNING_CONFIG_FAILED;
323 }
324
325 return CMD_SUCCESS;
326 }
327
328 /* There are a number of interface parameters that must be changed when
329 an interface becomes wired/wireless. In Quagga, they cannot be
330 configured separately. */
331
332 static void
333 babel_set_wired_internal(babel_interface_nfo *babel_ifp, int wired)
334 {
335 if(wired) {
336 babel_ifp->flags |= BABEL_IF_WIRED;
337 babel_ifp->flags |= BABEL_IF_SPLIT_HORIZON;
338 babel_ifp->cost = BABEL_DEFAULT_RXCOST_WIRED;
339 babel_ifp->channel = BABEL_IF_CHANNEL_NONINTERFERING;
340 babel_ifp->flags &= ~BABEL_IF_LQ;
341 } else {
342 babel_ifp->flags &= ~BABEL_IF_WIRED;
343 babel_ifp->flags &= ~BABEL_IF_SPLIT_HORIZON;
344 babel_ifp->cost = BABEL_DEFAULT_RXCOST_WIRELESS;
345 babel_ifp->channel = BABEL_IF_CHANNEL_INTERFERING;
346 babel_ifp->flags |= BABEL_IF_LQ;
347 }
348
349 }
350
351 /* [Interface Command] Tell the interface is wire. */
352 DEFUN (babel_set_wired,
353 babel_set_wired_cmd,
354 "babel wired",
355 "Babel interface commands\n"
356 "Enable wired optimizations\n")
357 {
358 VTY_DECLVAR_CONTEXT(interface, ifp);
359 babel_interface_nfo *babel_ifp;
360
361 babel_ifp = babel_get_if_nfo(ifp);
362
363 assert (babel_ifp != NULL);
364 babel_set_wired_internal(babel_ifp, 1);
365 return CMD_SUCCESS;
366 }
367
368 /* [Interface Command] Tell the interface is wireless (default). */
369 DEFUN (babel_set_wireless,
370 babel_set_wireless_cmd,
371 "babel wireless",
372 "Babel interface commands\n"
373 "Disable wired optimizations (assume wireless)\n")
374 {
375 VTY_DECLVAR_CONTEXT(interface, ifp);
376 babel_interface_nfo *babel_ifp;
377
378 babel_ifp = babel_get_if_nfo(ifp);
379
380 assert (babel_ifp != NULL);
381 babel_set_wired_internal(babel_ifp, 0);
382 return CMD_SUCCESS;
383 }
384
385 /* [Interface Command] Enable split horizon. */
386 DEFUN (babel_split_horizon,
387 babel_split_horizon_cmd,
388 "babel split-horizon",
389 "Babel interface commands\n"
390 "Enable split horizon processing\n")
391 {
392 VTY_DECLVAR_CONTEXT(interface, ifp);
393 babel_interface_nfo *babel_ifp;
394
395 babel_ifp = babel_get_if_nfo(ifp);
396
397 assert (babel_ifp != NULL);
398 babel_ifp->flags |= BABEL_IF_SPLIT_HORIZON;
399 return CMD_SUCCESS;
400 }
401
402 /* [Interface Command] Disable split horizon (default). */
403 DEFUN (no_babel_split_horizon,
404 no_babel_split_horizon_cmd,
405 "no babel split-horizon",
406 NO_STR
407 "Babel interface commands\n"
408 "Disable split horizon processing\n")
409 {
410 VTY_DECLVAR_CONTEXT(interface, ifp);
411 babel_interface_nfo *babel_ifp;
412
413 babel_ifp = babel_get_if_nfo(ifp);
414
415 assert (babel_ifp != NULL);
416 babel_ifp->flags &= ~BABEL_IF_SPLIT_HORIZON;
417 return CMD_SUCCESS;
418 }
419
420 /* [Interface Command]. */
421 DEFUN (babel_set_hello_interval,
422 babel_set_hello_interval_cmd,
423 "babel hello-interval (20-655340)",
424 "Babel interface commands\n"
425 "Time between scheduled hellos\n"
426 "Milliseconds\n")
427 {
428 VTY_DECLVAR_CONTEXT(interface, ifp);
429 babel_interface_nfo *babel_ifp;
430 int interval;
431
432 interval = strtoul(argv[2]->arg, NULL, 10);
433
434 babel_ifp = babel_get_if_nfo(ifp);
435 assert (babel_ifp != NULL);
436
437 babel_ifp->hello_interval = interval;
438 return CMD_SUCCESS;
439 }
440
441 /* [Interface Command]. */
442 DEFUN (babel_set_update_interval,
443 babel_set_update_interval_cmd,
444 "babel update-interval (20-655340)",
445 "Babel interface commands\n"
446 "Time between scheduled updates\n"
447 "Milliseconds\n")
448 {
449 VTY_DECLVAR_CONTEXT(interface, ifp);
450 babel_interface_nfo *babel_ifp;
451 int interval;
452
453 interval = strtoul(argv[2]->arg, NULL, 10);
454
455 babel_ifp = babel_get_if_nfo(ifp);
456 assert (babel_ifp != NULL);
457
458 babel_ifp->update_interval = interval;
459 return CMD_SUCCESS;
460 }
461
462 DEFUN (babel_set_rxcost,
463 babel_set_rxcost_cmd,
464 "babel rxcost (1-65534)",
465 "Babel interface commands\n"
466 "Rxcost multiplier\n"
467 "Units\n")
468 {
469 VTY_DECLVAR_CONTEXT(interface, ifp);
470 babel_interface_nfo *babel_ifp;
471 int rxcost;
472
473 rxcost = strtoul(argv[2]->arg, NULL, 10);
474
475 babel_ifp = babel_get_if_nfo(ifp);
476 assert (babel_ifp != NULL);
477
478 babel_ifp->cost = rxcost;
479 return CMD_SUCCESS;
480 }
481
482 DEFUN (babel_set_rtt_decay,
483 babel_set_rtt_decay_cmd,
484 "babel rtt-decay (1-256)",
485 "Babel interface commands\n"
486 "Decay factor for exponential moving average of RTT samples\n"
487 "Units of 1/256\n")
488 {
489 VTY_DECLVAR_CONTEXT(interface, ifp);
490 babel_interface_nfo *babel_ifp;
491 int decay;
492
493 decay = strtoul(argv[2]->arg, NULL, 10);
494
495 babel_ifp = babel_get_if_nfo(ifp);
496 assert (babel_ifp != NULL);
497
498 babel_ifp->rtt_decay = decay;
499 return CMD_SUCCESS;
500 }
501
502 DEFUN (babel_set_rtt_min,
503 babel_set_rtt_min_cmd,
504 "babel rtt-min (1-65535)",
505 "Babel interface commands\n"
506 "Minimum RTT starting for increasing cost\n"
507 "Milliseconds\n")
508 {
509 VTY_DECLVAR_CONTEXT(interface, ifp);
510 babel_interface_nfo *babel_ifp;
511 int rtt;
512
513 rtt = strtoul(argv[2]->arg, NULL, 10);
514
515 babel_ifp = babel_get_if_nfo(ifp);
516 assert (babel_ifp != NULL);
517
518 babel_ifp->rtt_min = rtt;
519 return CMD_SUCCESS;
520 }
521
522 DEFUN (babel_set_rtt_max,
523 babel_set_rtt_max_cmd,
524 "babel rtt-max (1-65535)",
525 "Babel interface commands\n"
526 "Maximum RTT\n"
527 "Milliseconds\n")
528 {
529 VTY_DECLVAR_CONTEXT(interface, ifp);
530 babel_interface_nfo *babel_ifp;
531 int rtt;
532
533 rtt = strtoul(argv[2]->arg, NULL, 10);
534
535 babel_ifp = babel_get_if_nfo(ifp);
536 assert (babel_ifp != NULL);
537
538 babel_ifp->rtt_max = rtt;
539 return CMD_SUCCESS;
540 }
541
542 DEFUN (babel_set_max_rtt_penalty,
543 babel_set_max_rtt_penalty_cmd,
544 "babel max-rtt-penalty (0-65535)",
545 "Babel interface commands\n"
546 "Maximum additional cost due to RTT\n"
547 "Milliseconds\n")
548 {
549 VTY_DECLVAR_CONTEXT(interface, ifp);
550 babel_interface_nfo *babel_ifp;
551 int penalty;
552
553 penalty = strtoul(argv[2]->arg, NULL, 10);
554
555 babel_ifp = babel_get_if_nfo(ifp);
556 assert (babel_ifp != NULL);
557
558 babel_ifp->max_rtt_penalty = penalty;
559 return CMD_SUCCESS;
560 }
561
562 DEFUN (babel_set_enable_timestamps,
563 babel_set_enable_timestamps_cmd,
564 "babel enable-timestamps",
565 "Babel interface commands\n"
566 "Enable timestamps\n")
567 {
568 VTY_DECLVAR_CONTEXT(interface, ifp);
569 babel_interface_nfo *babel_ifp;
570
571 babel_ifp = babel_get_if_nfo(ifp);
572 assert (babel_ifp != NULL);
573
574 babel_ifp->flags |= BABEL_IF_TIMESTAMPS;
575 return CMD_SUCCESS;
576 }
577
578 DEFUN (no_babel_set_enable_timestamps,
579 no_babel_set_enable_timestamps_cmd,
580 "no babel enable-timestamps",
581 NO_STR
582 "Babel interface commands\n"
583 "Disable timestamps\n")
584 {
585 VTY_DECLVAR_CONTEXT(interface, ifp);
586 babel_interface_nfo *babel_ifp;
587
588 babel_ifp = babel_get_if_nfo(ifp);
589 assert (babel_ifp != NULL);
590
591 babel_ifp->flags &= ~BABEL_IF_TIMESTAMPS;
592 return CMD_SUCCESS;
593 }
594
595 DEFUN (babel_set_channel,
596 babel_set_channel_cmd,
597 "babel channel (1-254)",
598 "Babel interface commands\n"
599 "Channel number for diversity routing\n"
600 "Number\n")
601 {
602 VTY_DECLVAR_CONTEXT(interface, ifp);
603 babel_interface_nfo *babel_ifp;
604 int channel;
605
606 channel = strtoul(argv[2]->arg, NULL, 10);
607
608 babel_ifp = babel_get_if_nfo(ifp);
609 assert (babel_ifp != NULL);
610
611 babel_ifp->channel = channel;
612 return CMD_SUCCESS;
613 }
614
615 DEFUN (babel_set_channel_interfering,
616 babel_set_channel_interfering_cmd,
617 "babel channel interfering",
618 "Babel interface commands\n"
619 "Channel number for diversity routing\n"
620 "Mark channel as interfering\n")
621 {
622 VTY_DECLVAR_CONTEXT(interface, ifp);
623 babel_interface_nfo *babel_ifp;
624
625 babel_ifp = babel_get_if_nfo(ifp);
626 assert (babel_ifp != NULL);
627
628 babel_ifp->channel = BABEL_IF_CHANNEL_INTERFERING;
629 return CMD_SUCCESS;
630 }
631
632 DEFUN (babel_set_channel_noninterfering,
633 babel_set_channel_noninterfering_cmd,
634 "babel channel noninterfering",
635 "Babel interface commands\n"
636 "Channel number for diversity routing\n"
637 "Mark channel as noninterfering\n")
638 {
639 VTY_DECLVAR_CONTEXT(interface, ifp);
640 babel_interface_nfo *babel_ifp;
641
642 babel_ifp = babel_get_if_nfo(ifp);
643 assert (babel_ifp != NULL);
644
645 babel_ifp->channel = BABEL_IF_CHANNEL_NONINTERFERING;
646 return CMD_SUCCESS;
647 }
648
649 /* This should be no more than half the hello interval, so that hellos
650 aren't sent late. The result is in milliseconds. */
651 unsigned
652 jitter(babel_interface_nfo *babel_ifp, int urgent)
653 {
654 unsigned interval = babel_ifp->hello_interval;
655 if(urgent)
656 interval = MIN(interval, 100);
657 else
658 interval = MIN(interval, 4000);
659 return roughly(interval) / 4;
660 }
661
662 unsigned
663 update_jitter(babel_interface_nfo *babel_ifp, int urgent)
664 {
665 unsigned interval = babel_ifp->hello_interval;
666 if(urgent)
667 interval = MIN(interval, 100);
668 else
669 interval = MIN(interval, 4000);
670 return roughly(interval);
671 }
672
673 /* calculate babeld's specific datas of an interface (change when the interface
674 change) */
675 static int
676 interface_recalculate(struct interface *ifp)
677 {
678 babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
679 unsigned char *tmp = NULL;
680 int mtu, rc;
681 struct ipv6_mreq mreq;
682
683 if (!IS_ENABLE(ifp))
684 return -1;
685
686 if (!if_is_operative(ifp) || !CHECK_FLAG(ifp->flags, IFF_RUNNING)) {
687 interface_reset(ifp);
688 return -1;
689 }
690
691 babel_ifp->flags |= BABEL_IF_IS_UP;
692
693 mtu = MIN(ifp->mtu, ifp->mtu6);
694
695 /* We need to be able to fit at least two messages into a packet,
696 so MTUs below 116 require lower layer fragmentation. */
697 /* In IPv6, the minimum MTU is 1280, and every host must be able
698 to reassemble up to 1500 bytes, but I'd rather not rely on this. */
699 if(mtu < 128) {
700 debugf(BABEL_DEBUG_IF, "Suspiciously low MTU %d on interface %s (%d).",
701 mtu, ifp->name, ifp->ifindex);
702 mtu = 128;
703 }
704
705 /* 4 for Babel header; 40 for IPv6 header, 8 for UDP header, 12 for good luck. */
706 babel_ifp->bufsize = mtu - 4 - 60;
707 tmp = babel_ifp->sendbuf;
708 babel_ifp->sendbuf = realloc(babel_ifp->sendbuf, babel_ifp->bufsize);
709 if(babel_ifp->sendbuf == NULL) {
710 flog_err(EC_BABEL_MEMORY, "Couldn't reallocate sendbuf.");
711 free(tmp);
712 babel_ifp->bufsize = 0;
713 return -1;
714 }
715 tmp = NULL;
716
717 rc = resize_receive_buffer(mtu);
718 if(rc < 0)
719 zlog_warn("couldn't resize "
720 "receive buffer for interface %s (%d) (%d bytes).\n",
721 ifp->name, ifp->ifindex, mtu);
722
723 memset(&mreq, 0, sizeof(mreq));
724 memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16);
725 mreq.ipv6mr_interface = ifp->ifindex;
726
727 rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_JOIN_GROUP,
728 (char*)&mreq, sizeof(mreq));
729 if(rc < 0) {
730 flog_err_sys(EC_LIB_SOCKET,
731 "setsockopt(IPV6_JOIN_GROUP) on interface '%s': %s",
732 ifp->name, safe_strerror(errno));
733 /* This is probably due to a missing link-local address,
734 so down this interface, and wait until the main loop
735 tries to up it again. */
736 interface_reset(ifp);
737 return -1;
738 }
739
740 set_timeout(&babel_ifp->hello_timeout, babel_ifp->hello_interval);
741 set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval);
742 send_hello(ifp);
743 send_request(ifp, NULL, 0);
744
745 update_interface_metric(ifp);
746
747 debugf(BABEL_DEBUG_COMMON,
748 "Upped interface %s (%s, cost=%d, channel=%d%s).",
749 ifp->name,
750 (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless",
751 babel_ifp->cost,
752 babel_ifp->channel,
753 babel_ifp->ipv4 ? ", IPv4" : "");
754
755 if(rc > 0)
756 send_update(ifp, 0, NULL, 0);
757
758 return 1;
759 }
760
761 /* Reset the interface as it was new: it's not removed from the interface list,
762 and may be considered as a upped interface. */
763 static int
764 interface_reset(struct interface *ifp)
765 {
766 int rc;
767 struct ipv6_mreq mreq;
768 babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
769
770 if (!(babel_ifp->flags & BABEL_IF_IS_UP))
771 return 0;
772
773 debugf(BABEL_DEBUG_IF, "interface reset: %s", ifp->name);
774 babel_ifp->flags &= ~BABEL_IF_IS_UP;
775
776 flush_interface_routes(ifp, 0);
777 babel_ifp->buffered = 0;
778 babel_ifp->bufsize = 0;
779 free(babel_ifp->sendbuf);
780 babel_ifp->num_buffered_updates = 0;
781 babel_ifp->update_bufsize = 0;
782 if(babel_ifp->buffered_updates)
783 free(babel_ifp->buffered_updates);
784 babel_ifp->buffered_updates = NULL;
785 babel_ifp->sendbuf = NULL;
786
787 if(ifp->ifindex > 0) {
788 memset(&mreq, 0, sizeof(mreq));
789 memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16);
790 mreq.ipv6mr_interface = ifp->ifindex;
791 rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
792 (char*)&mreq, sizeof(mreq));
793 if(rc < 0)
794 flog_err_sys(EC_LIB_SOCKET,
795 "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. */
811 void
812 babel_interface_close_all(void)
813 {
814 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
815 struct interface *ifp = NULL;
816
817 FOR_ALL_INTERFACES(vrf, ifp) {
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(vrf, ifp) {
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 */
842 int
843 is_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
860 static void
861 show_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\n", ifp->name,
867 ((is_up = if_is_operative(ifp)) ? "up" : "down"));
868 vty_out (vty, " ifindex %u, MTU %u bytes %s\n",
869 ifp->ifindex, MIN(ifp->mtu, ifp->mtu6), if_flag_dump(ifp->flags));
870
871 if (!IS_ENABLE(ifp))
872 {
873 vty_out (vty, " Babel protocol is not enabled on this interface\n");
874 return;
875 }
876 if (!is_up)
877 {
878 vty_out (vty,
879 " Babel protocol is enabled, but not running on this interface\n");
880 return;
881 }
882 babel_ifp = babel_get_if_nfo (ifp);
883 vty_out (vty, " Babel protocol is running on this interface\n");
884 vty_out (vty, " Operating mode is \"%s\"\n",
885 CHECK_FLAG(babel_ifp->flags, BABEL_IF_WIRED) ? "wired" : "wireless");
886 vty_out (vty, " Split horizon mode is %s\n",
887 CHECK_FLAG(babel_ifp->flags, BABEL_IF_SPLIT_HORIZON) ? "On" : "Off");
888 vty_out (vty, " Hello interval is %u ms\n", babel_ifp->hello_interval);
889 vty_out (vty, " Update interval is %u ms\n", babel_ifp->update_interval);
890 vty_out (vty, " Rxcost multiplier is %u\n", babel_ifp->cost);
891 }
892
893 DEFUN (show_babel_interface,
894 show_babel_interface_cmd,
895 "show babel interface [IFNAME]",
896 SHOW_STR
897 "Babel information\n"
898 "Interface information\n"
899 "Interface\n")
900 {
901 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
902 struct interface *ifp;
903
904 if (argc == 3)
905 {
906 FOR_ALL_INTERFACES (vrf, ifp)
907 show_babel_interface_sub (vty, ifp);
908 return CMD_SUCCESS;
909 }
910 if ((ifp = if_lookup_by_name (argv[3]->arg, VRF_DEFAULT)) == NULL)
911 {
912 vty_out (vty, "No such interface name\n");
913 return CMD_WARNING;
914 }
915 show_babel_interface_sub (vty, ifp);
916 return CMD_SUCCESS;
917 }
918
919 static void
920 show_babel_neighbour_sub (struct vty *vty, struct neighbour *neigh)
921 {
922 vty_out (vty,
923 "Neighbour %s dev %s reach %04x rxcost %d txcost %d "
924 "rtt %s rttcost %d%s.\n",
925 format_address(neigh->address),
926 neigh->ifp->name,
927 neigh->reach,
928 neighbour_rxcost(neigh),
929 neigh->txcost,
930 format_thousands(neigh->rtt),
931 neighbour_rttcost(neigh),
932 if_up(neigh->ifp) ? "" : " (down)");
933 }
934
935 DEFUN (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\n");
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
965 static int
966 babel_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
983 static void
984 show_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, "%u", 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\n",
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)" : route_feasible(route) ? " (feasible)" : "");
1028 }
1029
1030 static void
1031 show_babel_xroutes_sub (struct xroute *xroute, struct vty *vty,
1032 struct prefix *prefix)
1033 {
1034 if(prefix && !babel_prefix_eq(prefix, xroute->prefix, xroute->plen))
1035 return;
1036
1037 vty_out (vty, "%s metric %d (exported)\n",
1038 format_prefix(xroute->prefix, xroute->plen),
1039 xroute->metric);
1040 }
1041
1042 DEFUN (show_babel_route,
1043 show_babel_route_cmd,
1044 "show babel route",
1045 SHOW_STR
1046 "Babel information\n"
1047 "Babel internal routing table\n")
1048 {
1049 struct route_stream *routes = NULL;
1050 struct xroute_stream *xroutes = NULL;
1051 routes = route_stream(0);
1052 if(routes) {
1053 while(1) {
1054 struct babel_route *route = route_stream_next(routes);
1055 if(route == NULL)
1056 break;
1057 show_babel_routes_sub(route, vty, NULL);
1058 }
1059 route_stream_done(routes);
1060 } else {
1061 flog_err(EC_BABEL_MEMORY, "Couldn't allocate route stream.");
1062 }
1063 xroutes = xroute_stream();
1064 if(xroutes) {
1065 while(1) {
1066 struct xroute *xroute = xroute_stream_next(xroutes);
1067 if(xroute == NULL)
1068 break;
1069 show_babel_xroutes_sub(xroute, vty, NULL);
1070 }
1071 xroute_stream_done(xroutes);
1072 } else {
1073 flog_err(EC_BABEL_MEMORY, "Couldn't allocate route stream.");
1074 }
1075 return CMD_SUCCESS;
1076 }
1077
1078 DEFUN (show_babel_route_prefix,
1079 show_babel_route_prefix_cmd,
1080 "show babel route <A.B.C.D/M|X:X::X:X/M>",
1081 SHOW_STR
1082 "Babel information\n"
1083 "Babel internal routing table\n"
1084 "IPv4 prefix <network>/<length>\n"
1085 "IPv6 prefix <network>/<length>\n")
1086 {
1087 struct route_stream *routes = NULL;
1088 struct xroute_stream *xroutes = NULL;
1089 struct prefix prefix;
1090 int ret;
1091
1092 ret = str2prefix(argv[3]->arg, &prefix);
1093 if(ret == 0) {
1094 vty_out (vty, "%% Malformed address\n");
1095 return CMD_WARNING;
1096 }
1097
1098 routes = route_stream(0);
1099 if(routes) {
1100 while(1) {
1101 struct babel_route *route = route_stream_next(routes);
1102 if(route == NULL)
1103 break;
1104 show_babel_routes_sub(route, vty, &prefix);
1105 }
1106 route_stream_done(routes);
1107 } else {
1108 flog_err(EC_BABEL_MEMORY, "Couldn't allocate route stream.");
1109 }
1110 xroutes = xroute_stream();
1111 if(xroutes) {
1112 while(1) {
1113 struct xroute *xroute = xroute_stream_next(xroutes);
1114 if(xroute == NULL)
1115 break;
1116 show_babel_xroutes_sub(xroute, vty, &prefix);
1117 }
1118 xroute_stream_done(xroutes);
1119 } else {
1120 flog_err(EC_BABEL_MEMORY, "Couldn't allocate route stream.");
1121 }
1122 return CMD_SUCCESS;
1123 }
1124
1125
1126 DEFUN (show_babel_route_addr,
1127 show_babel_route_addr_cmd,
1128 "show babel route A.B.C.D",
1129 SHOW_STR
1130 "Babel information\n"
1131 "Babel internal routing table\n"
1132 "IPv4 address <network>/<length>\n")
1133 {
1134 struct in_addr addr;
1135 char buf[INET_ADDRSTRLEN + 8];
1136 struct route_stream *routes = NULL;
1137 struct xroute_stream *xroutes = NULL;
1138 struct prefix prefix;
1139 int ret;
1140
1141 ret = inet_aton (argv[3]->arg, &addr);
1142 if (ret <= 0) {
1143 vty_out (vty, "%% Malformed address\n");
1144 return CMD_WARNING;
1145 }
1146
1147 /* Quagga has no convenient prefix constructors. */
1148 snprintf(buf, sizeof(buf), "%s/%d", inet_ntoa(addr), 32);
1149
1150 ret = str2prefix(buf, &prefix);
1151 if (ret == 0) {
1152 vty_out (vty, "%% Parse error -- this shouldn't happen\n");
1153 return CMD_WARNING;
1154 }
1155
1156 routes = route_stream(0);
1157 if(routes) {
1158 while(1) {
1159 struct babel_route *route = route_stream_next(routes);
1160 if(route == NULL)
1161 break;
1162 show_babel_routes_sub(route, vty, &prefix);
1163 }
1164 route_stream_done(routes);
1165 } else {
1166 flog_err(EC_BABEL_MEMORY, "Couldn't allocate route stream.");
1167 }
1168 xroutes = xroute_stream();
1169 if(xroutes) {
1170 while(1) {
1171 struct xroute *xroute = xroute_stream_next(xroutes);
1172 if(xroute == NULL)
1173 break;
1174 show_babel_xroutes_sub(xroute, vty, &prefix);
1175 }
1176 xroute_stream_done(xroutes);
1177 } else {
1178 flog_err(EC_BABEL_MEMORY, "Couldn't allocate route stream.");
1179 }
1180 return CMD_SUCCESS;
1181 }
1182
1183 DEFUN (show_babel_route_addr6,
1184 show_babel_route_addr6_cmd,
1185 "show babel route X:X::X:X",
1186 SHOW_STR
1187 "Babel information\n"
1188 "Babel internal routing table\n"
1189 "IPv6 address <network>/<length>\n")
1190 {
1191 struct in6_addr addr;
1192 char buf1[INET6_ADDRSTRLEN];
1193 char buf[INET6_ADDRSTRLEN + 8];
1194 struct route_stream *routes = NULL;
1195 struct xroute_stream *xroutes = NULL;
1196 struct prefix prefix;
1197 int ret;
1198
1199 ret = inet_pton (AF_INET6, argv[3]->arg, &addr);
1200 if (ret <= 0) {
1201 vty_out (vty, "%% Malformed address\n");
1202 return CMD_WARNING;
1203 }
1204
1205 /* Quagga has no convenient prefix constructors. */
1206 snprintf(buf, sizeof(buf), "%s/%d",
1207 inet_ntop(AF_INET6, &addr, buf1, sizeof(buf1)), 128);
1208
1209 ret = str2prefix(buf, &prefix);
1210 if (ret == 0) {
1211 vty_out (vty, "%% Parse error -- this shouldn't happen\n");
1212 return CMD_WARNING;
1213 }
1214
1215 routes = route_stream(0);
1216 if(routes) {
1217 while(1) {
1218 struct babel_route *route = route_stream_next(routes);
1219 if(route == NULL)
1220 break;
1221 show_babel_routes_sub(route, vty, &prefix);
1222 }
1223 route_stream_done(routes);
1224 } else {
1225 flog_err(EC_BABEL_MEMORY, "Couldn't allocate route stream.");
1226 }
1227 xroutes = xroute_stream();
1228 if(xroutes) {
1229 while(1) {
1230 struct xroute *xroute = xroute_stream_next(xroutes);
1231 if(xroute == NULL)
1232 break;
1233 show_babel_xroutes_sub(xroute, vty, &prefix);
1234 }
1235 xroute_stream_done(xroutes);
1236 } else {
1237 flog_err(EC_BABEL_MEMORY, "Couldn't allocate route stream.");
1238 }
1239 return CMD_SUCCESS;
1240 }
1241
1242 DEFUN (show_babel_parameters,
1243 show_babel_parameters_cmd,
1244 "show babel parameters",
1245 SHOW_STR
1246 "Babel information\n"
1247 "Configuration information\n")
1248 {
1249 struct babel *babel_ctx;
1250
1251 vty_out (vty, " -- Babel running configuration --\n");
1252 show_babel_main_configuration(vty);
1253
1254 babel_ctx = babel_lookup();
1255 if (babel_ctx) {
1256 vty_out (vty, " -- distribution lists --\n");
1257 config_show_distribute(vty, babel_ctx->distribute_ctx);
1258 }
1259 return CMD_SUCCESS;
1260 }
1261
1262 void
1263 babel_if_init(void)
1264 {
1265 /* initialize interface list */
1266 hook_register_prio(if_add, 0, babel_if_new_hook);
1267 hook_register_prio(if_del, 0, babel_if_delete_hook);
1268
1269 babel_enable_if = vector_init (1);
1270
1271 /* install interface node and commands */
1272 install_node (&babel_interface_node, interface_config_write);
1273 if_cmd_init();
1274
1275 install_element(BABEL_NODE, &babel_network_cmd);
1276 install_element(BABEL_NODE, &no_babel_network_cmd);
1277 install_element(INTERFACE_NODE, &babel_split_horizon_cmd);
1278 install_element(INTERFACE_NODE, &no_babel_split_horizon_cmd);
1279 install_element(INTERFACE_NODE, &babel_set_wired_cmd);
1280 install_element(INTERFACE_NODE, &babel_set_wireless_cmd);
1281 install_element(INTERFACE_NODE, &babel_set_hello_interval_cmd);
1282 install_element(INTERFACE_NODE, &babel_set_update_interval_cmd);
1283 install_element(INTERFACE_NODE, &babel_set_rxcost_cmd);
1284 install_element(INTERFACE_NODE, &babel_set_channel_cmd);
1285 install_element(INTERFACE_NODE, &babel_set_rtt_decay_cmd);
1286 install_element(INTERFACE_NODE, &babel_set_rtt_min_cmd);
1287 install_element(INTERFACE_NODE, &babel_set_rtt_max_cmd);
1288 install_element(INTERFACE_NODE, &babel_set_max_rtt_penalty_cmd);
1289 install_element(INTERFACE_NODE, &babel_set_enable_timestamps_cmd);
1290 install_element(INTERFACE_NODE, &no_babel_set_enable_timestamps_cmd);
1291 install_element(INTERFACE_NODE, &babel_set_channel_interfering_cmd);
1292 install_element(INTERFACE_NODE, &babel_set_channel_noninterfering_cmd);
1293
1294 /* "show babel ..." commands */
1295 install_element(VIEW_NODE, &show_babel_interface_cmd);
1296 install_element(VIEW_NODE, &show_babel_neighbour_cmd);
1297 install_element(VIEW_NODE, &show_babel_route_cmd);
1298 install_element(VIEW_NODE, &show_babel_route_prefix_cmd);
1299 install_element(VIEW_NODE, &show_babel_route_addr_cmd);
1300 install_element(VIEW_NODE, &show_babel_route_addr6_cmd);
1301 install_element(VIEW_NODE, &show_babel_parameters_cmd);
1302 }
1303
1304 /* hooks: functions called respectively when struct interface is
1305 created or deleted. */
1306 static int
1307 babel_if_new_hook (struct interface *ifp)
1308 {
1309 ifp->info = babel_interface_allocate();
1310 return 0;
1311 }
1312
1313 static int
1314 babel_if_delete_hook (struct interface *ifp)
1315 {
1316 babel_interface_free(ifp->info);
1317 ifp->info = NULL;
1318 return 0;
1319 }
1320
1321 /* Output an "interface" section for each of the known interfaces with
1322 babeld-specific statement lines where appropriate. */
1323 static int
1324 interface_config_write (struct vty *vty)
1325 {
1326 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
1327 struct interface *ifp;
1328 int write = 0;
1329
1330 FOR_ALL_INTERFACES (vrf, ifp) {
1331 vty_frame (vty, "interface %s\n",ifp->name);
1332 if (ifp->desc)
1333 vty_out (vty, " description %s\n",ifp->desc);
1334 babel_interface_nfo *babel_ifp = babel_get_if_nfo (ifp);
1335 /* wireless is the default*/
1336 if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED))
1337 {
1338 vty_out (vty, " babel wired\n");
1339 write++;
1340 }
1341 if (babel_ifp->hello_interval != BABEL_DEFAULT_HELLO_INTERVAL)
1342 {
1343 vty_out (vty, " babel hello-interval %u\n",
1344 babel_ifp->hello_interval);
1345 write++;
1346 }
1347 if (babel_ifp->update_interval != BABEL_DEFAULT_UPDATE_INTERVAL)
1348 {
1349 vty_out (vty, " babel update-interval %u\n",
1350 babel_ifp->update_interval);
1351 write++;
1352 }
1353 /* Some parameters have different defaults for wired/wireless. */
1354 if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED)) {
1355 if (!CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON)) {
1356 vty_out (vty, " no babel split-horizon\n");
1357 write++;
1358 }
1359 if (babel_ifp->cost != BABEL_DEFAULT_RXCOST_WIRED) {
1360 vty_out (vty, " babel rxcost %u\n", babel_ifp->cost);
1361 write++;
1362 }
1363 if (babel_ifp->channel == BABEL_IF_CHANNEL_INTERFERING) {
1364 vty_out (vty, " babel channel interfering\n");
1365 write++;
1366 } else if(babel_ifp->channel != BABEL_IF_CHANNEL_NONINTERFERING) {
1367 vty_out (vty, " babel channel %d\n",babel_ifp->channel);
1368 write++;
1369 }
1370 } else {
1371 if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON)) {
1372 vty_out (vty, " babel split-horizon\n");
1373 write++;
1374 }
1375 if (babel_ifp->cost != BABEL_DEFAULT_RXCOST_WIRELESS) {
1376 vty_out (vty, " babel rxcost %u\n", babel_ifp->cost);
1377 write++;
1378 }
1379 if (babel_ifp->channel == BABEL_IF_CHANNEL_NONINTERFERING) {
1380 vty_out (vty, " babel channel noninterfering\n");
1381 write++;
1382 } else if(babel_ifp->channel != BABEL_IF_CHANNEL_INTERFERING) {
1383 vty_out (vty, " babel channel %d\n",babel_ifp->channel);
1384 write++;
1385 }
1386 }
1387 vty_endframe (vty, "!\n");
1388 write++;
1389 }
1390 return write;
1391 }
1392
1393 /* Output a "network" statement line for each of the enabled interfaces. */
1394 int
1395 babel_enable_if_config_write (struct vty * vty)
1396 {
1397 unsigned int i, lines = 0;
1398 char *str;
1399
1400 for (i = 0; i < vector_active (babel_enable_if); i++)
1401 if ((str = vector_slot (babel_enable_if, i)) != NULL)
1402 {
1403 vty_out (vty, " network %s\n", str);
1404 lines++;
1405 }
1406 return lines;
1407 }
1408
1409 /* functions to allocate or free memory for a babel_interface_nfo, filling
1410 needed fields */
1411 static babel_interface_nfo *
1412 babel_interface_allocate (void)
1413 {
1414 babel_interface_nfo *babel_ifp;
1415 babel_ifp = XCALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo));
1416 /* All flags are unset */
1417 babel_ifp->bucket_time = babel_now.tv_sec;
1418 babel_ifp->bucket = BUCKET_TOKENS_MAX;
1419 babel_ifp->hello_seqno = (random() & 0xFFFF);
1420 babel_ifp->rtt_min = 10000;
1421 babel_ifp->rtt_max = 120000;
1422 babel_ifp->max_rtt_penalty = 150;
1423 babel_ifp->hello_interval = BABEL_DEFAULT_HELLO_INTERVAL;
1424 babel_ifp->update_interval = BABEL_DEFAULT_UPDATE_INTERVAL;
1425 babel_ifp->channel = BABEL_IF_CHANNEL_INTERFERING;
1426 babel_set_wired_internal(babel_ifp, 0);
1427
1428 return babel_ifp;
1429 }
1430
1431 static void
1432 babel_interface_free (babel_interface_nfo *babel_ifp)
1433 {
1434 XFREE(MTYPE_BABEL_IF, babel_ifp);
1435 }