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