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