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