Annotation of embedaddon/quagga/babeld/babel_interface.c, revision 1.1.1.1
1.1 misho 1: /*
2: * This file is free software: you may copy, redistribute and/or modify it
3: * under the terms of the GNU General Public License as published by the
4: * Free Software Foundation, either version 2 of the License, or (at your
5: * option) any later version.
6: *
7: * This file is distributed in the hope that it will be useful, but
8: * WITHOUT ANY WARRANTY; without even the implied warranty of
9: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10: * General Public License for more details.
11: *
12: * You should have received a copy of the GNU General Public License
13: * along with this program. If not, see <http://www.gnu.org/licenses/>.
14: *
15: * This file incorporates work covered by the following copyright and
16: * permission notice:
17: *
18:
19: Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
20:
21: Permission is hereby granted, free of charge, to any person obtaining a copy
22: of this software and associated documentation files (the "Software"), to deal
23: in the Software without restriction, including without limitation the rights
24: to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25: copies of the Software, and to permit persons to whom the Software is
26: furnished to do so, subject to the following conditions:
27:
28: The above copyright notice and this permission notice shall be included in
29: all copies or substantial portions of the Software.
30:
31: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34: AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35: LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
37: THE SOFTWARE.
38: */
39:
40: #include <zebra.h>
41: #include "memory.h"
42: #include "log.h"
43: #include "command.h"
44: #include "prefix.h"
45: #include "vector.h"
46: #include "distribute.h"
47:
48: #include "babel_main.h"
49: #include "util.h"
50: #include "kernel.h"
51: #include "babel_interface.h"
52: #include "message.h"
53: #include "route.h"
54: #include "babel_zebra.h"
55: #include "neighbour.h"
56: #include "route.h"
57: #include "xroute.h"
58:
59:
60: #define IS_ENABLE(ifp) (babel_enable_if_lookup(ifp->name) >= 0)
61:
62: static int babel_enable_if_lookup (const char *ifname);
63: static int babel_enable_if_add (const char *ifname);
64: static int babel_enable_if_delete (const char *ifname);
65: static int interface_recalculate(struct interface *ifp);
66: static int interface_reset(struct interface *ifp);
67: static int babel_if_new_hook (struct interface *ifp);
68: static int babel_if_delete_hook (struct interface *ifp);
69: static int interface_config_write (struct vty *vty);
70: static babel_interface_nfo * babel_interface_allocate (void);
71: static void babel_interface_free (babel_interface_nfo *bi);
72:
73:
74: static vector babel_enable_if; /* enable interfaces (by cmd). */
75: static struct cmd_node babel_interface_node = /* babeld's interface node. */
76: {
77: INTERFACE_NODE,
78: "%s(config-if)# ",
79: 1 /* VTYSH */
80: };
81:
82:
83: int
84: babel_interface_up (int cmd, struct zclient *client, zebra_size_t length)
85: {
86: struct stream *s = NULL;
87: struct interface *ifp = NULL;
88:
89: debugf(BABEL_DEBUG_IF, "receive a 'interface up'");
90:
91: s = zclient->ibuf;
92: ifp = zebra_interface_state_read(s); /* it updates iflist */
93:
94: if (ifp == NULL) {
95: return 0;
96: }
97:
98: interface_recalculate(ifp);
99: return 0;
100: }
101:
102: int
103: babel_interface_down (int cmd, struct zclient *client, zebra_size_t length)
104: {
105: struct stream *s = NULL;
106: struct interface *ifp = NULL;
107:
108: debugf(BABEL_DEBUG_IF, "receive a 'interface down'");
109:
110: s = zclient->ibuf;
111: ifp = zebra_interface_state_read(s); /* it updates iflist */
112:
113: if (ifp == NULL) {
114: return 0;
115: }
116:
117: interface_reset(ifp);
118: return 0;
119: }
120:
121: int
122: babel_interface_add (int cmd, struct zclient *client, zebra_size_t length)
123: {
124: struct interface *ifp = NULL;
125:
126: debugf(BABEL_DEBUG_IF, "receive a 'interface add'");
127:
128: /* read and add the interface in the iflist. */
129: ifp = zebra_interface_add_read (zclient->ibuf);
130:
131: if (ifp == NULL) {
132: return 0;
133: }
134:
135: interface_recalculate(ifp);
136: return 0;
137: }
138:
139: int
140: babel_interface_delete (int cmd, struct zclient *client, zebra_size_t length)
141: {
142: struct interface *ifp;
143: struct stream *s;
144:
145: debugf(BABEL_DEBUG_IF, "receive a 'interface delete'");
146:
147: s = zclient->ibuf;
148: ifp = zebra_interface_state_read(s); /* it updates iflist */
149:
150: if (ifp == NULL)
151: return 0;
152:
153: if (IS_ENABLE(ifp))
154: interface_reset(ifp);
155:
156: /* To support pseudo interface do not free interface structure. */
157: /* if_delete(ifp); */
158: ifp->ifindex = IFINDEX_INTERNAL;
159:
160: return 0;
161: }
162:
163: int
164: babel_interface_address_add (int cmd, struct zclient *client,
165: zebra_size_t length)
166: {
167: babel_interface_nfo *babel_ifp;
168: struct connected *ifc;
169: struct prefix *prefix;
170:
171: debugf(BABEL_DEBUG_IF, "receive a 'interface address add'");
172:
173: ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD,
174: zclient->ibuf);
175:
176: if (ifc == NULL)
177: return 0;
178:
179: prefix = ifc->address;
180:
181: if (prefix->family == AF_INET) {
182: flush_interface_routes(ifc->ifp, 0);
183: babel_ifp = babel_get_if_nfo(ifc->ifp);
184: if (babel_ifp->ipv4 == NULL) {
185: babel_ifp->ipv4 = malloc(4);
186: if (babel_ifp->ipv4 == NULL) {
187: zlog_err("not einough memory");
188: } else {
189: memcpy(babel_ifp->ipv4, &prefix->u.prefix4, 4);
190: }
191: }
192: }
193:
194: send_request(ifc->ifp, NULL, 0);
195: send_update(ifc->ifp, 0, NULL, 0);
196:
197: return 0;
198: }
199:
200: int
201: babel_interface_address_delete (int cmd, struct zclient *client,
202: zebra_size_t length)
203: {
204: babel_interface_nfo *babel_ifp;
205: struct connected *ifc;
206: struct prefix *prefix;
207:
208: debugf(BABEL_DEBUG_IF, "receive a 'interface address add'");
209:
210: ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD,
211: zclient->ibuf);
212:
213: if (ifc == NULL)
214: return 0;
215:
216: prefix = ifc->address;
217:
218: if (prefix->family == AF_INET) {
219: flush_interface_routes(ifc->ifp, 0);
220: babel_ifp = babel_get_if_nfo(ifc->ifp);
221: if (babel_ifp->ipv4 != NULL
222: && memcmp(babel_ifp->ipv4, &prefix->u.prefix4, 4) == 0) {
223: free(babel_ifp->ipv4);
224: babel_ifp->ipv4 = NULL;
225: }
226: }
227:
228: send_request(ifc->ifp, NULL, 0);
229: send_update(ifc->ifp, 0, NULL, 0);
230:
231: return 0;
232: }
233:
234: /* Lookup function. */
235: static int
236: babel_enable_if_lookup (const char *ifname)
237: {
238: unsigned int i;
239: char *str;
240:
241: for (i = 0; i < vector_active (babel_enable_if); i++)
242: if ((str = vector_slot (babel_enable_if, i)) != NULL)
243: if (strcmp (str, ifname) == 0)
244: return i;
245: return -1;
246: }
247:
248: /* Add interface to babel_enable_if. */
249: static int
250: babel_enable_if_add (const char *ifname)
251: {
252: int ret;
253: struct interface *ifp = NULL;
254:
255: ret = babel_enable_if_lookup (ifname);
256: if (ret >= 0)
257: return -1;
258:
259: vector_set (babel_enable_if, strdup (ifname));
260:
261: ifp = if_lookup_by_name(ifname);
262: if (ifp != NULL)
263: interface_recalculate(ifp);
264:
265: return 1;
266: }
267:
268: /* Delete interface from babel_enable_if. */
269: static int
270: babel_enable_if_delete (const char *ifname)
271: {
272: int babel_enable_if_index;
273: char *str;
274: struct interface *ifp = NULL;
275:
276: babel_enable_if_index = babel_enable_if_lookup (ifname);
277: if (babel_enable_if_index < 0)
278: return -1;
279:
280: str = vector_slot (babel_enable_if, babel_enable_if_index);
281: free (str);
282: vector_unset (babel_enable_if, babel_enable_if_index);
283:
284: ifp = if_lookup_by_name(ifname);
285: if (ifp != NULL)
286: interface_reset(ifp);
287:
288: return 1;
289: }
290:
291: /* [Babel Command] Babel enable on specified interface or matched network. */
292: DEFUN (babel_network,
293: babel_network_cmd,
294: "network IF_OR_ADDR",
295: "Enable Babel protocol on specified interface or network.\n"
296: "Interface or address")
297: {
298: int ret;
299: struct prefix p;
300:
301: ret = str2prefix (argv[0], &p);
302:
303: /* Given string is: */
304: if (ret) /* an IPv4 or v6 network */
305: return CMD_ERR_NO_MATCH; /* not implemented yet */
306: else /* an interface name */
307: ret = babel_enable_if_add (argv[0]);
308:
309: if (ret < 0) {
310: vty_out (vty, "There is same network configuration %s%s", argv[0],
311: VTY_NEWLINE);
312: return CMD_WARNING;
313: }
314:
315: return CMD_SUCCESS;
316: }
317:
318: /* [Babel Command] Babel enable on specified interface or matched network. */
319: DEFUN (no_babel_network,
320: no_babel_network_cmd,
321: "no network IF_OR_ADDR",
322: NO_STR
323: "Disable Babel protocol on specified interface or network.\n"
324: "Interface or address")
325: {
326: int ret;
327: struct prefix p;
328:
329: ret = str2prefix (argv[0], &p);
330:
331: /* Given string is: */
332: if (ret) /* an IPv4 or v6 network */
333: return CMD_ERR_NO_MATCH; /* not implemented yet */
334: else /* an interface name */
335: ret = babel_enable_if_delete (argv[0]);
336:
337: if (ret < 0) {
338: vty_out (vty, "can't find network %s%s", argv[0],
339: VTY_NEWLINE);
340: return CMD_WARNING;
341: }
342:
343: return CMD_SUCCESS;
344: }
345:
346: /* There are a number of interface parameters that must be changed when
347: an interface becomes wired/wireless. In Quagga, they cannot be
348: configured separately. */
349:
350: static void
351: babel_set_wired_internal(babel_interface_nfo *babel_ifp, int wired)
352: {
353: if(wired) {
354: babel_ifp->flags |= BABEL_IF_WIRED;
355: babel_ifp->cost = 96;
356: babel_ifp->flags &= ~BABEL_IF_LQ;
357: } else {
358: babel_ifp->flags &= ~BABEL_IF_WIRED;
359: babel_ifp->cost = 256;
360: babel_ifp->flags |= BABEL_IF_LQ;
361: }
362:
363: }
364:
365: /* [Interface Command] Tell the interface is wire. */
366: DEFUN (babel_set_wired,
367: babel_set_wired_cmd,
368: "babel wired",
369: "Babel interface commands\n"
370: "Enable wired optimisations")
371: {
372: struct interface *ifp;
373: babel_interface_nfo *babel_ifp;
374:
375: ifp = vty->index;
376: babel_ifp = babel_get_if_nfo(ifp);
377:
378: assert (babel_ifp != NULL);
379: babel_set_wired_internal(babel_ifp, 1);
380: return CMD_SUCCESS;
381: }
382:
383: /* [Interface Command] Tell the interface is wireless (default). */
384: DEFUN (babel_set_wireless,
385: babel_set_wireless_cmd,
386: "babel wireless",
387: "Babel interface commands\n"
388: "Disable wired optimiations (assume wireless)")
389: {
390: struct interface *ifp;
391: babel_interface_nfo *babel_ifp;
392:
393: ifp = vty->index;
394: babel_ifp = babel_get_if_nfo(ifp);
395:
396: assert (babel_ifp != NULL);
397: babel_set_wired_internal(babel_ifp, 0);
398: return CMD_SUCCESS;
399: }
400:
401: /* [Interface Command] Enable split horizon. */
402: DEFUN (babel_split_horizon,
403: babel_split_horizon_cmd,
404: "babel split-horizon",
405: "Babel interface commands\n"
406: "Enable split horizon processing")
407: {
408: struct interface *ifp;
409: babel_interface_nfo *babel_ifp;
410:
411: ifp = vty->index;
412: babel_ifp = babel_get_if_nfo(ifp);
413:
414: assert (babel_ifp != NULL);
415: babel_ifp->flags |= BABEL_IF_SPLIT_HORIZON;
416: return CMD_SUCCESS;
417: }
418:
419: /* [Interface Command] Disable split horizon (default). */
420: DEFUN (no_babel_split_horizon,
421: no_babel_split_horizon_cmd,
422: "no babel split-horizon",
423: NO_STR
424: "Babel interface commands\n"
425: "Disable split horizon processing")
426: {
427: struct interface *ifp;
428: babel_interface_nfo *babel_ifp;
429:
430: ifp = vty->index;
431: babel_ifp = babel_get_if_nfo(ifp);
432:
433: assert (babel_ifp != NULL);
434: babel_ifp->flags &= ~BABEL_IF_SPLIT_HORIZON;
435: return CMD_SUCCESS;
436: }
437:
438: /* [Interface Command]. */
439: DEFUN (babel_set_hello_interval,
440: babel_set_hello_interval_cmd,
441: "babel hello-interval <20-655340>",
442: "Babel interface commands\n"
443: "Time between scheduled hellos\n"
444: "Milliseconds\n")
445: {
446: struct interface *ifp;
447: babel_interface_nfo *babel_ifp;
448: int interval;
449:
450: VTY_GET_INTEGER_RANGE("milliseconds", interval, argv[0], 20, 10 * 0xFFFE);
451:
452: ifp = vty->index;
453: babel_ifp = babel_get_if_nfo(ifp);
454: assert (babel_ifp != NULL);
455:
456: babel_ifp->hello_interval = interval;
457: return CMD_SUCCESS;
458: }
459:
460: /* [Interface Command]. */
461: DEFUN (babel_set_update_interval,
462: babel_set_update_interval_cmd,
463: "babel update-interval <20-655340>",
464: "Babel interface commands\n"
465: "Time between scheduled updates\n"
466: "Milliseconds\n")
467: {
468: struct interface *ifp;
469: babel_interface_nfo *babel_ifp;
470: int interval;
471:
472: VTY_GET_INTEGER_RANGE("milliseconds", interval, argv[0], 20, 10 * 0xFFFE);
473:
474: ifp = vty->index;
475: babel_ifp = babel_get_if_nfo(ifp);
476: assert (babel_ifp != NULL);
477:
478: babel_ifp->update_interval = interval;
479: return CMD_SUCCESS;
480: }
481:
482: /* This should be no more than half the hello interval, so that hellos
483: aren't sent late. The result is in milliseconds. */
484: unsigned
485: jitter(babel_interface_nfo *babel_ifp, int urgent)
486: {
487: unsigned interval = babel_ifp->hello_interval;
488: if(urgent)
489: interval = MIN(interval, 100);
490: else
491: interval = MIN(interval, 4000);
492: return roughly(interval) / 4;
493: }
494:
495: unsigned
496: update_jitter(babel_interface_nfo *babel_ifp, int urgent)
497: {
498: unsigned interval = babel_ifp->hello_interval;
499: if(urgent)
500: interval = MIN(interval, 100);
501: else
502: interval = MIN(interval, 4000);
503: return roughly(interval);
504: }
505:
506: /* calculate babeld's specific datas of an interface (change when the interface
507: change) */
508: static int
509: interface_recalculate(struct interface *ifp)
510: {
511: babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
512: unsigned char *tmp = NULL;
513: int mtu, rc;
514: struct ipv6_mreq mreq;
515:
516: if (!IS_ENABLE(ifp))
517: return -1;
518:
519: if (!if_is_operative(ifp) || !CHECK_FLAG(ifp->flags, IFF_RUNNING)) {
520: interface_reset(ifp);
521: return -1;
522: }
523:
524: babel_ifp->flags |= BABEL_IF_IS_UP;
525:
526: mtu = MIN(ifp->mtu, ifp->mtu6);
527:
528: /* We need to be able to fit at least two messages into a packet,
529: so MTUs below 116 require lower layer fragmentation. */
530: /* In IPv6, the minimum MTU is 1280, and every host must be able
531: to reassemble up to 1500 bytes, but I'd rather not rely on this. */
532: if(mtu < 128) {
533: debugf(BABEL_DEBUG_IF, "Suspiciously low MTU %d on interface %s (%d).",
534: mtu, ifp->name, ifp->ifindex);
535: mtu = 128;
536: }
537:
538: /* 40 for IPv6 header, 8 for UDP header, 12 for good luck. */
539: babel_ifp->bufsize = mtu - sizeof(packet_header) - 60;
540: tmp = babel_ifp->sendbuf;
541: babel_ifp->sendbuf = realloc(babel_ifp->sendbuf, babel_ifp->bufsize);
542: if(babel_ifp->sendbuf == NULL) {
543: zlog_err("Couldn't reallocate sendbuf.");
544: free(tmp);
545: babel_ifp->bufsize = 0;
546: return -1;
547: }
548: tmp = NULL;
549:
550: resize_receive_buffer(mtu);
551:
552: memset(&mreq, 0, sizeof(mreq));
553: memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16);
554: mreq.ipv6mr_interface = ifp->ifindex;
555:
556: rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_JOIN_GROUP,
557: (char*)&mreq, sizeof(mreq));
558: if(rc < 0) {
559: zlog_err("setsockopt(IPV6_JOIN_GROUP) on interface '%s': %s",
560: ifp->name, safe_strerror(errno));
561: /* This is probably due to a missing link-local address,
562: so down this interface, and wait until the main loop
563: tries to up it again. */
564: interface_reset(ifp);
565: return -1;
566: }
567:
568: set_timeout(&babel_ifp->hello_timeout, babel_ifp->hello_interval);
569: set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval);
570: send_hello(ifp);
571: send_request(ifp, NULL, 0);
572:
573: update_interface_metric(ifp);
574:
575: debugf(BABEL_DEBUG_COMMON,
576: "Upped interface %s (%s, cost=%d, channel=%d%s).",
577: ifp->name,
578: (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless",
579: babel_ifp->cost,
580: babel_ifp->channel,
581: babel_ifp->ipv4 ? ", IPv4" : "");
582:
583: if(rc > 0)
584: send_update(ifp, 0, NULL, 0);
585:
586: return 1;
587: }
588:
589: /* Reset the interface as it was new: it's not removed from the interface list,
590: and may be considered as a upped interface. */
591: static int
592: interface_reset(struct interface *ifp)
593: {
594: int rc;
595: struct ipv6_mreq mreq;
596: babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
597:
598: if (!(babel_ifp->flags & BABEL_IF_IS_UP))
599: return 0;
600:
601: debugf(BABEL_DEBUG_IF, "interface reset: %s", ifp->name);
602: babel_ifp->flags &= ~BABEL_IF_IS_UP;
603:
604: flush_interface_routes(ifp, 0);
605: babel_ifp->buffered = 0;
606: babel_ifp->bufsize = 0;
607: free(babel_ifp->sendbuf);
608: babel_ifp->num_buffered_updates = 0;
609: babel_ifp->update_bufsize = 0;
610: if(babel_ifp->buffered_updates)
611: free(babel_ifp->buffered_updates);
612: babel_ifp->buffered_updates = NULL;
613: babel_ifp->sendbuf = NULL;
614:
615: if(ifp->ifindex > 0) {
616: memset(&mreq, 0, sizeof(mreq));
617: memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16);
618: mreq.ipv6mr_interface = ifp->ifindex;
619: rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
620: (char*)&mreq, sizeof(mreq));
621: if(rc < 0)
622: zlog_err("setsockopt(IPV6_LEAVE_GROUP) on interface '%s': %s",
623: ifp->name, safe_strerror(errno));
624: }
625:
626: update_interface_metric(ifp);
627:
628: debugf(BABEL_DEBUG_COMMON,"Upped network %s (%s, cost=%d%s).",
629: ifp->name,
630: (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless",
631: babel_ifp->cost,
632: babel_ifp->ipv4 ? ", IPv4" : "");
633:
634: return 1;
635: }
636:
637: /* Send retraction to all, and reset all interfaces statistics. */
638: void
639: babel_interface_close_all(void)
640: {
641: struct interface *ifp = NULL;
642: struct listnode *linklist_node = NULL;
643:
644: FOR_ALL_INTERFACES(ifp, linklist_node) {
645: if(!if_up(ifp))
646: continue;
647: send_wildcard_retraction(ifp);
648: /* Make sure that we expire quickly from our neighbours'
649: association caches. */
650: send_hello_noupdate(ifp, 10);
651: flushbuf(ifp);
652: usleep(roughly(1000));
653: gettime(&babel_now);
654: }
655: FOR_ALL_INTERFACES(ifp, linklist_node) {
656: if(!if_up(ifp))
657: continue;
658: /* Make sure they got it. */
659: send_wildcard_retraction(ifp);
660: send_hello_noupdate(ifp, 1);
661: flushbuf(ifp);
662: usleep(roughly(10000));
663: gettime(&babel_now);
664: interface_reset(ifp);
665: }
666: }
667:
668: /* return "true" if address is one of our ipv6 addresses */
669: int
670: is_interface_ll_address(struct interface *ifp, const unsigned char *address)
671: {
672: struct connected *connected;
673: struct listnode *node;
674:
675: if(!if_up(ifp))
676: return 0;
677:
678: FOR_ALL_INTERFACES_ADDRESSES(ifp, connected, node) {
679: if(connected->address->family == AF_INET6 &&
680: memcmp(&connected->address->u.prefix6, address, 16) == 0)
681: return 1;
682: }
683:
684: return 0;
685: }
686:
687: static void
688: show_babel_interface_sub (struct vty *vty, struct interface *ifp)
689: {
690: int is_up;
691: babel_interface_nfo *babel_ifp;
692:
693: vty_out (vty, "%s is %s%s", ifp->name,
694: ((is_up = if_is_operative(ifp)) ? "up" : "down"), VTY_NEWLINE);
695: vty_out (vty, " ifindex %u, MTU %u bytes %s%s",
696: ifp->ifindex, ifp->mtu, if_flag_dump(ifp->flags), VTY_NEWLINE);
697:
698: if (babel_enable_if_lookup (ifp->name) < 0)
699: {
700: vty_out (vty, " Babel protocol is not enabled on this interface%s", VTY_NEWLINE);
701: return;
702: }
703: if (!is_up)
704: {
705: vty_out (vty, " Babel protocol is enabled, but not running on this interface%s", VTY_NEWLINE);
706: return;
707: }
708: babel_ifp = babel_get_if_nfo (ifp);
709: vty_out (vty, " Babel protocol is running on this interface%s", VTY_NEWLINE);
710: vty_out (vty, " Operating mode is \"%s\"%s",
711: CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED) ? "wired" : "wireless", VTY_NEWLINE);
712: vty_out (vty, " Split horizon mode is %s%s",
713: CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON) ? "On" : "Off", VTY_NEWLINE);
714: vty_out (vty, " Hello interval is %u ms%s", babel_ifp->hello_interval, VTY_NEWLINE);
715: vty_out (vty, " Update interval is %u ms%s", babel_ifp->update_interval, VTY_NEWLINE);
716: }
717:
718: DEFUN (show_babel_interface,
719: show_babel_interface_cmd,
720: "show babel interface [INTERFACE]",
721: SHOW_STR
722: IP_STR
723: "Babel information\n"
724: "Interface information\n"
725: "Interface name\n")
726: {
727: struct interface *ifp;
728: struct listnode *node;
729:
730: if (argc == 0)
731: {
732: for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
733: show_babel_interface_sub (vty, ifp);
734: return CMD_SUCCESS;
735: }
736: if ((ifp = if_lookup_by_name (argv[0])) == NULL)
737: {
738: vty_out (vty, "No such interface name%s", VTY_NEWLINE);
739: return CMD_WARNING;
740: }
741: show_babel_interface_sub (vty, ifp);
742: return CMD_SUCCESS;
743: }
744:
745: static void
746: show_babel_neighbour_sub (struct vty *vty, struct neighbour *neigh)
747: {
748: vty_out (vty,
749: "Neighbour %s dev %s reach %04x rxcost %d txcost %d %s.%s",
750: format_address(neigh->address),
751: neigh->ifp->name,
752: neigh->reach,
753: neighbour_rxcost(neigh),
754: neigh->txcost,
755: if_up(neigh->ifp) ? "" : " (down)",
756: VTY_NEWLINE);
757: }
758:
759: DEFUN (show_babel_neighbour,
760: show_babel_neighbour_cmd,
761: "show babel neighbour [INTERFACE]",
762: SHOW_STR
763: IP_STR
764: "Babel information\n"
765: "Print neighbours\n"
766: "Interface name\n")
767: {
768: struct neighbour *neigh;
769: struct interface *ifp;
770:
771: if (argc == 0) {
772: FOR_ALL_NEIGHBOURS(neigh) {
773: show_babel_neighbour_sub(vty, neigh);
774: }
775: return CMD_SUCCESS;
776: }
777: if ((ifp = if_lookup_by_name (argv[0])) == NULL)
778: {
779: vty_out (vty, "No such interface name%s", VTY_NEWLINE);
780: return CMD_WARNING;
781: }
782: FOR_ALL_NEIGHBOURS(neigh) {
783: if(ifp->ifindex == neigh->ifp->ifindex) {
784: show_babel_neighbour_sub(vty, neigh);
785: }
786: }
787: return CMD_SUCCESS;
788: }
789:
790: static void
791: show_babel_routes_sub (struct babel_route *route, void *closure)
792: {
793: struct vty *vty = (struct vty*) closure;
794: const unsigned char *nexthop =
795: memcmp(route->nexthop, route->neigh->address, 16) == 0 ?
796: NULL : route->nexthop;
797: char channels[100];
798:
799: if(route->channels[0] == 0)
800: channels[0] = '\0';
801: else {
802: int k, j = 0;
803: snprintf(channels, 100, " chan (");
804: j = strlen(channels);
805: for(k = 0; k < DIVERSITY_HOPS; k++) {
806: if(route->channels[k] == 0)
807: break;
808: if(k > 0)
809: channels[j++] = ',';
810: snprintf(channels + j, 100 - j, "%d", route->channels[k]);
811: j = strlen(channels);
812: }
813: snprintf(channels + j, 100 - j, ")");
814: if(k == 0)
815: channels[0] = '\0';
816: }
817:
818: vty_out(vty,
819: "%s metric %d refmetric %d id %s seqno %d%s age %d "
820: "via %s neigh %s%s%s%s%s",
821: format_prefix(route->src->prefix, route->src->plen),
822: route_metric(route), route->refmetric,
823: format_eui64(route->src->id),
824: (int)route->seqno,
825: channels,
826: (int)(babel_now.tv_sec - route->time),
827: route->neigh->ifp->name,
828: format_address(route->neigh->address),
829: nexthop ? " nexthop " : "",
830: nexthop ? format_address(nexthop) : "",
831: route->installed ? " (installed)" :
832: route_feasible(route) ? " (feasible)" : "",
833: VTY_NEWLINE);
834: }
835:
836: static void
837: show_babel_xroutes_sub (struct xroute *xroute, void *closure)
838: {
839: struct vty *vty = (struct vty *) closure;
840: vty_out(vty, "%s metric %d (exported)%s",
841: format_prefix(xroute->prefix, xroute->plen),
842: xroute->metric,
843: VTY_NEWLINE);
844: }
845:
846: DEFUN (show_babel_database,
847: show_babel_database_cmd,
848: "show babel database",
849: SHOW_STR
850: IP_STR
851: "Babel information\n"
852: "Database information\n"
853: "No attributes\n")
854: {
855: for_all_routes(show_babel_routes_sub, vty);
856: for_all_xroutes(show_babel_xroutes_sub, vty);
857: return CMD_SUCCESS;
858: }
859:
860: DEFUN (show_babel_parameters,
861: show_babel_parameters_cmd,
862: "show babel parameters",
863: SHOW_STR
864: IP_STR
865: "Babel information\n"
866: "Configuration information\n"
867: "No attributes\n")
868: {
869: vty_out(vty, " -- Babel running configuration --%s", VTY_NEWLINE);
870: show_babel_main_configuration(vty);
871: vty_out(vty, " -- distribution lists --%s", VTY_NEWLINE);
872: config_show_distribute(vty);
873:
874: return CMD_SUCCESS;
875: }
876:
877: void
878: babel_if_init ()
879: {
880: /* initialize interface list */
881: if_init();
882: if_add_hook (IF_NEW_HOOK, babel_if_new_hook);
883: if_add_hook (IF_DELETE_HOOK, babel_if_delete_hook);
884:
885: babel_enable_if = vector_init (1);
886:
887: /* install interface node and commands */
888: install_element (CONFIG_NODE, &interface_cmd);
889: install_element (CONFIG_NODE, &no_interface_cmd);
890: install_node (&babel_interface_node, interface_config_write);
891: install_default(INTERFACE_NODE);
892: install_element(INTERFACE_NODE, &interface_cmd);
893: install_element(INTERFACE_NODE, &no_interface_cmd);
894:
895: install_element(BABEL_NODE, &babel_network_cmd);
896: install_element(BABEL_NODE, &no_babel_network_cmd);
897: install_element(INTERFACE_NODE, &babel_split_horizon_cmd);
898: install_element(INTERFACE_NODE, &no_babel_split_horizon_cmd);
899: install_element(INTERFACE_NODE, &babel_set_wired_cmd);
900: install_element(INTERFACE_NODE, &babel_set_wireless_cmd);
901: install_element(INTERFACE_NODE, &babel_set_hello_interval_cmd);
902: install_element(INTERFACE_NODE, &babel_set_update_interval_cmd);
903:
904: /* "show babel ..." commands */
905: install_element(VIEW_NODE, &show_babel_interface_cmd);
906: install_element(ENABLE_NODE, &show_babel_interface_cmd);
907: install_element(VIEW_NODE, &show_babel_neighbour_cmd);
908: install_element(ENABLE_NODE, &show_babel_neighbour_cmd);
909: install_element(VIEW_NODE, &show_babel_database_cmd);
910: install_element(ENABLE_NODE, &show_babel_database_cmd);
911: install_element(VIEW_NODE, &show_babel_parameters_cmd);
912: install_element(ENABLE_NODE, &show_babel_parameters_cmd);
913: }
914:
915: /* hooks: functions called respectively when struct interface is
916: created or deleted. */
917: static int
918: babel_if_new_hook (struct interface *ifp)
919: {
920: ifp->info = babel_interface_allocate();
921: return 0;
922: }
923:
924: static int
925: babel_if_delete_hook (struct interface *ifp)
926: {
927: babel_interface_free(ifp->info);
928: ifp->info = NULL;
929: return 0;
930: }
931:
932: /* Output an "interface" section for each of the known interfaces with
933: babeld-specific statement lines where appropriate. */
934: static int
935: interface_config_write (struct vty *vty)
936: {
937: struct listnode *node;
938: struct interface *ifp;
939: int write = 0;
940:
941: for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) {
942: vty_out (vty, "interface %s%s", ifp->name,
943: VTY_NEWLINE);
944: if (ifp->desc)
945: vty_out (vty, " description %s%s", ifp->desc,
946: VTY_NEWLINE);
947: if (IS_ENABLE (ifp))
948: {
949: babel_interface_nfo *babel_ifp = babel_get_if_nfo (ifp);
950: /* wireless/no split-horizon is the default */
951: if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED))
952: {
953: vty_out (vty, " babel wired%s", VTY_NEWLINE);
954: write++;
955: }
956: if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON))
957: {
958: vty_out (vty, " babel split-horizon%s", VTY_NEWLINE);
959: write++;
960: }
961: if (babel_ifp->hello_interval != BABEL_DEFAULT_HELLO_INTERVAL)
962: {
963: vty_out (vty, " babel hello-interval %u%s", babel_ifp->hello_interval, VTY_NEWLINE);
964: write++;
965: }
966: if (babel_ifp->update_interval != BABEL_DEFAULT_UPDATE_INTERVAL)
967: {
968: vty_out (vty, " babel update-interval %u%s", babel_ifp->update_interval, VTY_NEWLINE);
969: write++;
970: }
971: }
972: vty_out (vty, "!%s", VTY_NEWLINE);
973: write++;
974: }
975: return write;
976: }
977:
978: /* Output a "network" statement line for each of the enabled interfaces. */
979: int
980: babel_enable_if_config_write (struct vty * vty)
981: {
982: unsigned int i, lines = 0;
983: char *str;
984:
985: for (i = 0; i < vector_active (babel_enable_if); i++)
986: if ((str = vector_slot (babel_enable_if, i)) != NULL)
987: {
988: vty_out (vty, " network %s%s", str, VTY_NEWLINE);
989: lines++;
990: }
991: return lines;
992: }
993:
994: /* functions to allocate or free memory for a babel_interface_nfo, filling
995: needed fields */
996: static babel_interface_nfo *
997: babel_interface_allocate (void)
998: {
999: babel_interface_nfo *babel_ifp;
1000: babel_ifp = XMALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo));
1001: if(babel_ifp == NULL)
1002: return NULL;
1003:
1004: /* Here are set the default values for an interface. */
1005: memset(babel_ifp, 0, sizeof(babel_interface_nfo));
1006: /* All flags are unset */
1007: babel_ifp->bucket_time = babel_now.tv_sec;
1008: babel_ifp->bucket = BUCKET_TOKENS_MAX;
1009: babel_ifp->hello_seqno = (random() & 0xFFFF);
1010: babel_ifp->hello_interval = BABEL_DEFAULT_HELLO_INTERVAL;
1011: babel_ifp->update_interval = BABEL_DEFAULT_UPDATE_INTERVAL;
1012: babel_ifp->channel = BABEL_IF_CHANNEL_INTERFERING;
1013: babel_set_wired_internal(babel_ifp, 0);
1014:
1015: return babel_ifp;
1016: }
1017:
1018: static void
1019: babel_interface_free (babel_interface_nfo *babel_ifp)
1020: {
1021: XFREE(MTYPE_BABEL_IF, babel_ifp);
1022: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>