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