]> git.proxmox.com Git - mirror_frr.git/blame - babeld/babel_interface.c
babeld: Add missing `no` commands
[mirror_frr.git] / babeld / babel_interface.c
CommitLineData
ca10883e
DS
1/*
2Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
3
4Permission is hereby granted, free of charge, to any person obtaining a copy
5of this software and associated documentation files (the "Software"), to deal
6in the Software without restriction, including without limitation the rights
7to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8copies of the Software, and to permit persons to whom the Software is
9furnished to do so, subject to the following conditions:
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20THE 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"
f135ba52 30#include "lib_errors.h"
5920b3eb 31#include "network.h"
ca10883e
DS
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"
f135ba52 43#include "babel_errors.h"
ca10883e 44
9affd464
YZ
45#ifndef VTYSH_EXTRACT_PL
46#include "babeld/babel_interface_clippy.c"
47#endif
48
bf8d3d6a 49DEFINE_MTYPE_STATIC(BABELD, BABEL_IF, "Babel Interface");
8b7454e9 50
ca10883e
DS
51#define IS_ENABLE(ifp) (babel_enable_if_lookup(ifp->name) >= 0)
52
53static int babel_enable_if_lookup (const char *ifname);
54static int babel_enable_if_add (const char *ifname);
55static int babel_enable_if_delete (const char *ifname);
56static int interface_recalculate(struct interface *ifp);
57static int interface_reset(struct interface *ifp);
58static int babel_if_new_hook (struct interface *ifp);
59static int babel_if_delete_hook (struct interface *ifp);
60static int interface_config_write (struct vty *vty);
61static babel_interface_nfo * babel_interface_allocate (void);
62static void babel_interface_free (babel_interface_nfo *bi);
63
64
65static vector babel_enable_if; /* enable interfaces (by cmd). */
ca10883e 66
93d9b1af 67int babel_ifp_up(struct interface *ifp)
ca10883e 68{
ca10883e
DS
69 debugf(BABEL_DEBUG_IF, "receive a 'interface up'");
70
ca10883e
DS
71 interface_recalculate(ifp);
72 return 0;
73}
74
75int
b0b69e59 76babel_ifp_down(struct interface *ifp)
ca10883e 77{
ca10883e
DS
78 debugf(BABEL_DEBUG_IF, "receive a 'interface down'");
79
ca10883e
DS
80 if (ifp == NULL) {
81 return 0;
82 }
83
84 interface_reset(ifp);
85 return 0;
86}
87
ef7bd2a3 88int babel_ifp_create (struct interface *ifp)
ca10883e 89{
ca10883e
DS
90 debugf(BABEL_DEBUG_IF, "receive a 'interface add'");
91
ca10883e 92 interface_recalculate(ifp);
3c3c3252 93
ef7bd2a3
DS
94 return 0;
95 }
ca10883e
DS
96
97int
3c3c3252 98babel_ifp_destroy(struct interface *ifp)
ca10883e 99{
ca10883e
DS
100 debugf(BABEL_DEBUG_IF, "receive a 'interface delete'");
101
ca10883e
DS
102 if (IS_ENABLE(ifp))
103 interface_reset(ifp);
104
ca10883e
DS
105 return 0;
106}
107
108int
121f9dee 109babel_interface_address_add (ZAPI_CALLBACK_ARGS)
ca10883e
DS
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,
121f9dee 118 zclient->ibuf, vrf_id);
ca10883e
DS
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) {
5b003f31 131 flog_err(EC_BABEL_MEMORY, "not enough memory");
ca10883e
DS
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
144int
121f9dee 145babel_interface_address_delete (ZAPI_CALLBACK_ARGS)
ca10883e
DS
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,
121f9dee 154 zclient->ibuf, vrf_id);
ca10883e
DS
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);
8643c2e5
DA
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;
ca10883e
DS
169 }
170 }
171
172 send_request(ifc->ifp, NULL, 0);
173 send_update(ifc->ifp, 0, NULL, 0);
174
1f3255e5 175 connected_free(&ifc);
ca10883e
DS
176 return 0;
177}
178
179/* Lookup function. */
180static int
181babel_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. */
194static int
195babel_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
a36898e7 206 ifp = if_lookup_by_name(ifname, VRF_DEFAULT);
ca10883e
DS
207 if (ifp != NULL)
208 interface_recalculate(ifp);
209
210 return 1;
211}
212
213/* Delete interface from babel_enable_if. */
214static int
215babel_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
a36898e7 229 ifp = if_lookup_by_name(ifname, VRF_DEFAULT);
ca10883e
DS
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. */
237DEFUN (babel_network,
238 babel_network_cmd,
239 "network IF_OR_ADDR",
240 "Enable Babel protocol on specified interface or network.\n"
f84d11d1 241 "Interface or address\n")
ca10883e
DS
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) {
5c7571d4 255 vty_out (vty, "There is same network configuration %s\n",
96ade3ed 256 argv[1]->arg);
851fcbae 257 return CMD_WARNING;
ca10883e
DS
258 }
259
260 return CMD_SUCCESS;
261}
262
263/* [Babel Command] Babel enable on specified interface or matched network. */
264DEFUN (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"
bd8d8973 269 "Interface or address\n")
ca10883e
DS
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) {
5c7571d4 283 vty_out (vty, "can't find network %s\n",argv[2]->arg);
f1a05de9 284 return CMD_WARNING_CONFIG_FAILED;
ca10883e
DS
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
294static void
295babel_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. */
9affd464 314DEFPY (babel_set_wired,
ca10883e 315 babel_set_wired_cmd,
9affd464
YZ
316 "[no] babel wired",
317 NO_STR
ca10883e 318 "Babel interface commands\n"
bd8d8973 319 "Enable wired optimizations\n")
ca10883e
DS
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);
9affd464 327 babel_set_wired_internal(babel_ifp, no ? 0 : 1);
ca10883e
DS
328 return CMD_SUCCESS;
329}
330
331/* [Interface Command] Tell the interface is wireless (default). */
9affd464 332DEFPY (babel_set_wireless,
ca10883e 333 babel_set_wireless_cmd,
9affd464
YZ
334 "[no] babel wireless",
335 NO_STR
ca10883e 336 "Babel interface commands\n"
bd8d8973 337 "Disable wired optimizations (assume wireless)\n")
ca10883e
DS
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);
9affd464 345 babel_set_wired_internal(babel_ifp, no ? 1 : 0);
ca10883e
DS
346 return CMD_SUCCESS;
347}
348
349/* [Interface Command] Enable split horizon. */
9affd464 350DEFPY (babel_split_horizon,
ca10883e 351 babel_split_horizon_cmd,
9affd464 352 "[no] babel split-horizon",
ca10883e
DS
353 NO_STR
354 "Babel interface commands\n"
9affd464 355 "Enable split horizon processing\n")
ca10883e
DS
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);
9affd464
YZ
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);
ca10883e
DS
367 return CMD_SUCCESS;
368}
369
370/* [Interface Command]. */
9affd464 371DEFPY (babel_set_hello_interval,
ca10883e 372 babel_set_hello_interval_cmd,
9affd464
YZ
373 "[no] babel hello-interval (20-655340)",
374 NO_STR
ca10883e
DS
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;
ca10883e
DS
381
382 babel_ifp = babel_get_if_nfo(ifp);
383 assert (babel_ifp != NULL);
384
9affd464
YZ
385 babel_ifp->hello_interval = no ?
386 BABEL_DEFAULT_HELLO_INTERVAL : hello_interval;
ca10883e
DS
387 return CMD_SUCCESS;
388}
389
390/* [Interface Command]. */
9affd464 391DEFPY (babel_set_update_interval,
ca10883e 392 babel_set_update_interval_cmd,
9affd464
YZ
393 "[no] babel update-interval (20-655340)",
394 NO_STR
ca10883e
DS
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;
ca10883e
DS
401
402 babel_ifp = babel_get_if_nfo(ifp);
403 assert (babel_ifp != NULL);
404
9affd464
YZ
405 babel_ifp->update_interval = no ?
406 BABEL_DEFAULT_UPDATE_INTERVAL : update_interval;
ca10883e
DS
407 return CMD_SUCCESS;
408}
409
9affd464 410DEFPY (babel_set_rxcost,
ca10883e 411 babel_set_rxcost_cmd,
9affd464
YZ
412 "[no] babel rxcost (1-65534)",
413 NO_STR
ca10883e
DS
414 "Babel interface commands\n"
415 "Rxcost multiplier\n"
bd8d8973 416 "Units\n")
ca10883e
DS
417{
418 VTY_DECLVAR_CONTEXT(interface, ifp);
419 babel_interface_nfo *babel_ifp;
ca10883e
DS
420
421 babel_ifp = babel_get_if_nfo(ifp);
422 assert (babel_ifp != NULL);
423
9affd464
YZ
424 if (no)
425 rxcost = CHECK_FLAG(babel_ifp->flags, BABEL_IF_WIRED) ?
426 BABEL_DEFAULT_RXCOST_WIRED : BABEL_DEFAULT_RXCOST_WIRELESS;
427
ca10883e
DS
428 babel_ifp->cost = rxcost;
429 return CMD_SUCCESS;
430}
431
9affd464 432DEFPY (babel_set_rtt_decay,
ca10883e 433 babel_set_rtt_decay_cmd,
9affd464
YZ
434 "[no] babel rtt-decay (1-256)",
435 NO_STR
ca10883e
DS
436 "Babel interface commands\n"
437 "Decay factor for exponential moving average of RTT samples\n"
bd8d8973 438 "Units of 1/256\n")
ca10883e
DS
439{
440 VTY_DECLVAR_CONTEXT(interface, ifp);
441 babel_interface_nfo *babel_ifp;
ca10883e
DS
442
443 babel_ifp = babel_get_if_nfo(ifp);
444 assert (babel_ifp != NULL);
445
9affd464 446 babel_ifp->rtt_decay = no ? BABEL_DEFAULT_RTT_DECAY : rtt_decay;
ca10883e
DS
447 return CMD_SUCCESS;
448}
449
9affd464 450DEFPY (babel_set_rtt_min,
ca10883e 451 babel_set_rtt_min_cmd,
9affd464
YZ
452 "[no] babel rtt-min (1-65535)",
453 NO_STR
ca10883e
DS
454 "Babel interface commands\n"
455 "Minimum RTT starting for increasing cost\n"
bd8d8973 456 "Milliseconds\n")
ca10883e
DS
457{
458 VTY_DECLVAR_CONTEXT(interface, ifp);
459 babel_interface_nfo *babel_ifp;
ca10883e
DS
460
461 babel_ifp = babel_get_if_nfo(ifp);
462 assert (babel_ifp != NULL);
463
896cf5c5 464 /* The value is entered in milliseconds but stored as microseconds. */
9affd464 465 babel_ifp->rtt_min = no ? BABEL_DEFAULT_RTT_MIN : rtt_min * 1000;
ca10883e
DS
466 return CMD_SUCCESS;
467}
468
9affd464 469DEFPY (babel_set_rtt_max,
ca10883e 470 babel_set_rtt_max_cmd,
9affd464
YZ
471 "[no] babel rtt-max (1-65535)",
472 NO_STR
ca10883e
DS
473 "Babel interface commands\n"
474 "Maximum RTT\n"
bd8d8973 475 "Milliseconds\n")
ca10883e
DS
476{
477 VTY_DECLVAR_CONTEXT(interface, ifp);
478 babel_interface_nfo *babel_ifp;
ca10883e
DS
479
480 babel_ifp = babel_get_if_nfo(ifp);
481 assert (babel_ifp != NULL);
482
896cf5c5 483 /* The value is entered in milliseconds but stored as microseconds. */
9affd464 484 babel_ifp->rtt_max = no ? BABEL_DEFAULT_RTT_MAX : rtt_max * 1000;
ca10883e
DS
485 return CMD_SUCCESS;
486}
487
9affd464 488DEFPY (babel_set_max_rtt_penalty,
ca10883e 489 babel_set_max_rtt_penalty_cmd,
9affd464
YZ
490 "[no] babel max-rtt-penalty (0-65535)",
491 NO_STR
ca10883e
DS
492 "Babel interface commands\n"
493 "Maximum additional cost due to RTT\n"
bd8d8973 494 "Milliseconds\n")
ca10883e
DS
495{
496 VTY_DECLVAR_CONTEXT(interface, ifp);
497 babel_interface_nfo *babel_ifp;
ca10883e
DS
498
499 babel_ifp = babel_get_if_nfo(ifp);
500 assert (babel_ifp != NULL);
501
9affd464
YZ
502 babel_ifp->max_rtt_penalty = no ?
503 BABEL_DEFAULT_MAX_RTT_PENALTY : max_rtt_penalty;
ca10883e
DS
504 return CMD_SUCCESS;
505}
506
9affd464 507DEFPY (babel_set_enable_timestamps,
ca10883e 508 babel_set_enable_timestamps_cmd,
9affd464 509 "[no] babel enable-timestamps",
bd8d8973 510 NO_STR
ca10883e 511 "Babel interface commands\n"
9affd464 512 "Enable timestamps\n")
ca10883e
DS
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);
9affd464
YZ
519 if (!no)
520 SET_FLAG(babel_ifp->flags, BABEL_IF_TIMESTAMPS);
521 else
522 UNSET_FLAG(babel_ifp->flags, BABEL_IF_TIMESTAMPS);
ca10883e
DS
523 return CMD_SUCCESS;
524}
525
9affd464 526DEFPY (babel_set_channel,
ca10883e 527 babel_set_channel_cmd,
9affd464
YZ
528 "[no] babel channel <(1-254)$ch|interfering$interfering|"
529 "noninterfering$noninterfering>",
530 NO_STR
ca10883e
DS
531 "Babel interface commands\n"
532 "Channel number for diversity routing\n"
9affd464
YZ
533 "Number\n"
534 "Mark channel as interfering\n"
535 "Mark channel as noninterfering\n"
536 )
ca10883e
DS
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
9affd464
YZ
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;
ca10883e 551
9affd464 552 babel_ifp->channel = ch;
ca10883e
DS
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. */
558unsigned
559jitter(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
569unsigned
570update_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) */
582static int
583interface_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) {
5b003f31 617 flog_err(EC_BABEL_MEMORY, "Couldn't reallocate sendbuf.");
ca10883e
DS
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)
1d5453d6 626 zlog_warn("couldn't resize receive buffer for interface %s (%d) (%d bytes).",
ca10883e
DS
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) {
450971aa 636 flog_err_sys(EC_LIB_SOCKET,
f135ba52
DS
637 "setsockopt(IPV6_JOIN_GROUP) on interface '%s': %s",
638 ifp->name, safe_strerror(errno));
ca10883e
DS
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. */
669static int
670interface_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)
450971aa 700 flog_err_sys(EC_LIB_SOCKET,
f135ba52
DS
701 "setsockopt(IPV6_LEAVE_GROUP) on interface '%s': %s",
702 ifp->name, safe_strerror(errno));
ca10883e
DS
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. */
717void
718babel_interface_close_all(void)
719{
f4e14fdb 720 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
ca10883e 721 struct interface *ifp = NULL;
ca10883e 722
f4e14fdb 723 FOR_ALL_INTERFACES(vrf, ifp) {
ca10883e
DS
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 }
f4e14fdb 734 FOR_ALL_INTERFACES(vrf, ifp) {
ca10883e
DS
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 */
748int
749is_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) {
8643c2e5
DA
758 if (connected->address->family == AF_INET6
759 && memcmp(&connected->address->u.prefix6, address,
760 IPV6_MAX_BYTELEN)
761 == 0)
762 return 1;
ca10883e
DS
763 }
764
765 return 0;
766}
767
768static void
769show_babel_interface_sub (struct vty *vty, struct interface *ifp)
770{
771 int is_up;
772 babel_interface_nfo *babel_ifp;
773
5c7571d4 774 vty_out (vty, "%s is %s\n", ifp->name,
96ade3ed 775 ((is_up = if_is_operative(ifp)) ? "up" : "down"));
5c7571d4 776 vty_out (vty, " ifindex %u, MTU %u bytes %s\n",
96ade3ed 777 ifp->ifindex, MIN(ifp->mtu, ifp->mtu6), if_flag_dump(ifp->flags));
ca10883e
DS
778
779 if (!IS_ENABLE(ifp))
780 {
5c7571d4 781 vty_out (vty, " Babel protocol is not enabled on this interface\n");
ca10883e
DS
782 return;
783 }
784 if (!is_up)
785 {
5c7571d4
DL
786 vty_out (vty,
787 " Babel protocol is enabled, but not running on this interface\n");
ca10883e
DS
788 return;
789 }
790 babel_ifp = babel_get_if_nfo (ifp);
5c7571d4 791 vty_out (vty, " Babel protocol is running on this interface\n");
181039f3 792 vty_out (vty, " Operating mode is \"%s\"\n",
96ade3ed 793 CHECK_FLAG(babel_ifp->flags, BABEL_IF_WIRED) ? "wired" : "wireless");
5c7571d4 794 vty_out (vty, " Split horizon mode is %s\n",
96ade3ed 795 CHECK_FLAG(babel_ifp->flags, BABEL_IF_SPLIT_HORIZON) ? "On" : "Off");
5c7571d4
DL
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);
ca10883e
DS
799}
800
801DEFUN (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{
f4e14fdb 809 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
ca10883e 810 struct interface *ifp;
ca10883e
DS
811
812 if (argc == 3)
813 {
451fda4f 814 FOR_ALL_INTERFACES (vrf, ifp)
ca10883e
DS
815 show_babel_interface_sub (vty, ifp);
816 return CMD_SUCCESS;
817 }
a36898e7 818 if ((ifp = if_lookup_by_name (argv[3]->arg, VRF_DEFAULT)) == NULL)
ca10883e 819 {
5c7571d4 820 vty_out (vty, "No such interface name\n");
ca10883e
DS
821 return CMD_WARNING;
822 }
823 show_babel_interface_sub (vty, ifp);
824 return CMD_SUCCESS;
825}
826
827static void
828show_babel_neighbour_sub (struct vty *vty, struct neighbour *neigh)
829{
181039f3 830 vty_out (vty,
3efd0893 831 "Neighbour %s dev %s reach %04x rxcost %d txcost %d rtt %s rttcost %d%s.\n",
ca10883e
DS
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),
96ade3ed 839 if_up(neigh->ifp) ? "" : " (down)");
ca10883e
DS
840}
841
842DEFUN (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 }
a36898e7 859 if ((ifp = if_lookup_by_name (argv[3]->arg, VRF_DEFAULT)) == NULL)
ca10883e 860 {
5c7571d4 861 vty_out (vty, "No such interface name\n");
ca10883e
DS
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
872static int
873babel_prefix_eq(struct prefix *prefix, unsigned char *p, int plen)
874{
875 if(prefix->family == AF_INET6) {
8643c2e5
DA
876 if (prefix->prefixlen != plen
877 || memcmp(&prefix->u.prefix6, p, IPV6_MAX_BYTELEN) != 0)
878 return 0;
ca10883e 879 } else if(prefix->family == AF_INET) {
8643c2e5
DA
880 if (plen < 96 || !v4mapped(p) || prefix->prefixlen != plen - 96
881 || memcmp(&prefix->u.prefix4, p + 12, IPV4_MAX_BYTELEN) != 0)
882 return 0;
ca10883e
DS
883 } else {
884 return 0;
885 }
886
887 return 1;
888}
889
890static void
891show_babel_routes_sub(struct babel_route *route, struct vty *vty,
892 struct prefix *prefix)
893{
8643c2e5
DA
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';
ca10883e
DS
923 }
924
181039f3 925 vty_out (vty,
3efd0893 926 "%s metric %d refmetric %d id %s seqno %d%s age %d via %s neigh %s%s%s%s\n",
ca10883e
DS
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) : "",
96ade3ed 937 route->installed ? " (installed)" : route_feasible(route) ? " (feasible)" : "");
ca10883e
DS
938}
939
940static void
941show_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
5c7571d4 947 vty_out (vty, "%s metric %d (exported)\n",
ca10883e 948 format_prefix(xroute->prefix, xroute->plen),
96ade3ed 949 xroute->metric);
ca10883e
DS
950}
951
952DEFUN (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 {
5b003f31 971 flog_err(EC_BABEL_MEMORY, "Couldn't allocate route stream.");
ca10883e 972 }
dd15627e 973 xroutes = xroute_stream();
ca10883e
DS
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 {
5b003f31 983 flog_err(EC_BABEL_MEMORY, "Couldn't allocate route stream.");
ca10883e
DS
984 }
985 return CMD_SUCCESS;
986}
987
988DEFUN (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"
f7bf422e 993 "Babel internal routing table\n"
ca10883e
DS
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) {
5c7571d4 1004 vty_out (vty, "%% Malformed address\n");
ca10883e
DS
1005 return CMD_WARNING;
1006 }
c258527b 1007
ca10883e
DS
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 {
5b003f31 1018 flog_err(EC_BABEL_MEMORY, "Couldn't allocate route stream.");
ca10883e 1019 }
dd15627e 1020 xroutes = xroute_stream();
ca10883e
DS
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 {
5b003f31 1030 flog_err(EC_BABEL_MEMORY, "Couldn't allocate route stream.");
ca10883e
DS
1031 }
1032 return CMD_SUCCESS;
1033}
1034
1035
1036DEFUN (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"
f7bf422e 1041 "Babel internal routing table\n"
ca10883e
DS
1042 "IPv4 address <network>/<length>\n")
1043{
1044 struct in_addr addr;
1045 char buf[INET_ADDRSTRLEN + 8];
2bd8bc15 1046 char buf1[INET_ADDRSTRLEN + 8];
ca10883e
DS
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) {
5c7571d4 1054 vty_out (vty, "%% Malformed address\n");
ca10883e
DS
1055 return CMD_WARNING;
1056 }
1057
1058 /* Quagga has no convenient prefix constructors. */
2bd8bc15
MS
1059 snprintf(buf, sizeof(buf), "%s/%d",
1060 inet_ntop(AF_INET, &addr, buf1, sizeof(buf1)), 32);
ca10883e
DS
1061
1062 ret = str2prefix(buf, &prefix);
1063 if (ret == 0) {
5c7571d4 1064 vty_out (vty, "%% Parse error -- this shouldn't happen\n");
ca10883e
DS
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 {
5b003f31 1078 flog_err(EC_BABEL_MEMORY, "Couldn't allocate route stream.");
ca10883e 1079 }
dd15627e 1080 xroutes = xroute_stream();
ca10883e
DS
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 {
5b003f31 1090 flog_err(EC_BABEL_MEMORY, "Couldn't allocate route stream.");
ca10883e
DS
1091 }
1092 return CMD_SUCCESS;
1093}
1094
1095DEFUN (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"
f7bf422e 1100 "Babel internal routing table\n"
ca10883e
DS
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) {
5c7571d4 1113 vty_out (vty, "%% Malformed address\n");
ca10883e
DS
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) {
5c7571d4 1123 vty_out (vty, "%% Parse error -- this shouldn't happen\n");
ca10883e
DS
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 {
5b003f31 1137 flog_err(EC_BABEL_MEMORY, "Couldn't allocate route stream.");
ca10883e 1138 }
dd15627e 1139 xroutes = xroute_stream();
ca10883e
DS
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 {
5b003f31 1149 flog_err(EC_BABEL_MEMORY, "Couldn't allocate route stream.");
ca10883e
DS
1150 }
1151 return CMD_SUCCESS;
1152}
1153
1154DEFUN (show_babel_parameters,
1155 show_babel_parameters_cmd,
1156 "show babel parameters",
1157 SHOW_STR
1158 "Babel information\n"
1159 "Configuration information\n")
1160{
03a38493
PG
1161 struct babel *babel_ctx;
1162
5c7571d4 1163 vty_out (vty, " -- Babel running configuration --\n");
ca10883e 1164 show_babel_main_configuration(vty);
ca10883e 1165
03a38493
PG
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 }
ca10883e
DS
1171 return CMD_SUCCESS;
1172}
1173
1174void
4d762f26 1175babel_if_init(void)
ca10883e
DS
1176{
1177 /* initialize interface list */
ce19a04a
DL
1178 hook_register_prio(if_add, 0, babel_if_new_hook);
1179 hook_register_prio(if_del, 0, babel_if_delete_hook);
ca10883e
DS
1180
1181 babel_enable_if = vector_init (1);
1182
1183 /* install interface node and commands */
9da01b0b 1184 if_cmd_init(interface_config_write);
ca10883e
DS
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);
ca10883e
DS
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);
ca10883e
DS
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. */
1213static int
1214babel_if_new_hook (struct interface *ifp)
1215{
1216 ifp->info = babel_interface_allocate();
1217 return 0;
1218}
1219
1220static int
1221babel_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
1229babeld-specific statement lines where appropriate. */
1230static int
1231interface_config_write (struct vty *vty)
1232{
f4e14fdb 1233 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
ca10883e
DS
1234 struct interface *ifp;
1235 int write = 0;
1236
451fda4f 1237 FOR_ALL_INTERFACES (vrf, ifp) {
788a036f 1238 if_vty_config_start(vty, ifp);
ca10883e 1239 if (ifp->desc)
5c7571d4 1240 vty_out (vty, " description %s\n",ifp->desc);
ca10883e
DS
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 {
5c7571d4 1245 vty_out (vty, " babel wired\n");
ca10883e
DS
1246 write++;
1247 }
1248 if (babel_ifp->hello_interval != BABEL_DEFAULT_HELLO_INTERVAL)
1249 {
5c7571d4 1250 vty_out (vty, " babel hello-interval %u\n",
96ade3ed 1251 babel_ifp->hello_interval);
ca10883e
DS
1252 write++;
1253 }
1254 if (babel_ifp->update_interval != BABEL_DEFAULT_UPDATE_INTERVAL)
1255 {
5c7571d4 1256 vty_out (vty, " babel update-interval %u\n",
96ade3ed 1257 babel_ifp->update_interval);
ca10883e
DS
1258 write++;
1259 }
aa3ba071
AMR
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)) {
ca10883e 1283 if (!CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON)) {
5c7571d4 1284 vty_out (vty, " no babel split-horizon\n");
ca10883e
DS
1285 write++;
1286 }
1287 if (babel_ifp->cost != BABEL_DEFAULT_RXCOST_WIRED) {
5c7571d4 1288 vty_out (vty, " babel rxcost %u\n", babel_ifp->cost);
ca10883e
DS
1289 write++;
1290 }
1291 if (babel_ifp->channel == BABEL_IF_CHANNEL_INTERFERING) {
5c7571d4 1292 vty_out (vty, " babel channel interfering\n");
ca10883e
DS
1293 write++;
1294 } else if(babel_ifp->channel != BABEL_IF_CHANNEL_NONINTERFERING) {
5c7571d4 1295 vty_out (vty, " babel channel %d\n",babel_ifp->channel);
ca10883e
DS
1296 write++;
1297 }
1298 } else {
1299 if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON)) {
5c7571d4 1300 vty_out (vty, " babel split-horizon\n");
ca10883e
DS
1301 write++;
1302 }
1303 if (babel_ifp->cost != BABEL_DEFAULT_RXCOST_WIRELESS) {
5c7571d4 1304 vty_out (vty, " babel rxcost %u\n", babel_ifp->cost);
ca10883e
DS
1305 write++;
1306 }
1307 if (babel_ifp->channel == BABEL_IF_CHANNEL_NONINTERFERING) {
5c7571d4 1308 vty_out (vty, " babel channel noninterfering\n");
ca10883e
DS
1309 write++;
1310 } else if(babel_ifp->channel != BABEL_IF_CHANNEL_INTERFERING) {
5c7571d4 1311 vty_out (vty, " babel channel %d\n",babel_ifp->channel);
ca10883e
DS
1312 write++;
1313 }
1314 }
788a036f 1315 if_vty_config_end(vty);
ca10883e
DS
1316 write++;
1317 }
1318 return write;
1319}
1320
1321/* Output a "network" statement line for each of the enabled interfaces. */
1322int
1323babel_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 {
5c7571d4 1331 vty_out (vty, " network %s\n", str);
ca10883e
DS
1332 lines++;
1333 }
1334 return lines;
1335}
1336
1337/* functions to allocate or free memory for a babel_interface_nfo, filling
1338 needed fields */
1339static babel_interface_nfo *
1340babel_interface_allocate (void)
1341{
1342 babel_interface_nfo *babel_ifp;
aa406bbc 1343 babel_ifp = XCALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo));
ca10883e
DS
1344 /* All flags are unset */
1345 babel_ifp->bucket_time = babel_now.tv_sec;
1346 babel_ifp->bucket = BUCKET_TOKENS_MAX;
5920b3eb 1347 babel_ifp->hello_seqno = (frr_weak_random() & 0xFFFF);
aa3ba071
AMR
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;
ca10883e
DS
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
1360static void
1361babel_interface_free (babel_interface_nfo *babel_ifp)
1362{
1363 XFREE(MTYPE_BABEL_IF, babel_ifp);
1364}