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