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 *
18Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
19
20Permission is hereby granted, free of charge, to any person obtaining a copy
21of this software and associated documentation files (the "Software"), to deal
22in the Software without restriction, including without limitation the rights
23to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24copies of the Software, and to permit persons to whom the Software is
25furnished to do so, subject to the following conditions:
26
27The above copyright notice and this permission notice shall be included in
28all copies or substantial portions of the Software.
29
30THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
33AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
36THE SOFTWARE.
37*/
38
39/* quagga's includes */
40#include <zebra.h>
41#include "command.h"
42#include "zclient.h"
43#include "stream.h"
44
45/* babel's includes*/
46#include "babel_zebra.h"
47#include "babel_interface.h"
48#include "xroute.h"
49#include "util.h"
50
51void babelz_zebra_init(void);
52
53
54/* we must use a pointer because of zclient.c's functions (new, free). */
55struct zclient *zclient;
56static int zebra_config_write (struct vty *vty);
57
58/* Debug types */
59static struct {
60    int type;
61    int str_min_len;
62    const char *str;
63} debug_type[] = {
64    {BABEL_DEBUG_COMMON,  1, "common"},
65    {BABEL_DEBUG_KERNEL,  1, "kernel"},
66    {BABEL_DEBUG_FILTER,  1, "filter"},
67    {BABEL_DEBUG_TIMEOUT, 1, "timeout"},
68    {BABEL_DEBUG_IF,      1, "interface"},
69    {BABEL_DEBUG_ROUTE,   1, "route"},
70    {BABEL_DEBUG_ALL,     1, "all"},
71    {0, 0, NULL}
72};
73
74/* Zebra node structure. */
75struct cmd_node zebra_node =
76{
77    ZEBRA_NODE,
78    "%s(config-router)# ",
79    1 /* vtysh? yes */
80};
81
82
83/* Zebra route add and delete treatment (ipv6). */
84static int
85babel_zebra_read_ipv6 (int command, struct zclient *zclient,
86		       zebra_size_t length)
87{
88    struct stream *s;
89    struct zapi_ipv6 api;
90    unsigned long ifindex = -1;
91    struct in6_addr nexthop;
92    struct prefix_ipv6 prefix;
93
94    s = zclient->ibuf;
95    ifindex = 0;
96    memset (&nexthop, 0, sizeof (struct in6_addr));
97    memset (&api, 0, sizeof(struct zapi_ipv6));
98    memset (&prefix, 0, sizeof (struct prefix_ipv6));
99
100    /* Type, flags, message. */
101    api.type = stream_getc (s);
102    api.flags = stream_getc (s);
103    api.message = stream_getc (s);
104
105    /* IPv6 prefix. */
106    prefix.family = AF_INET6;
107    prefix.prefixlen = stream_getc (s);
108    stream_get (&prefix.prefix, s, PSIZE (prefix.prefixlen));
109
110    /* Nexthop, ifindex, distance, metric. */
111    if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) {
112        api.nexthop_num = stream_getc (s);
113        stream_get (&nexthop, s, sizeof(nexthop));
114    }
115    if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) {
116        api.ifindex_num = stream_getc (s);
117        ifindex = stream_getl (s);
118    }
119    if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
120        api.distance = stream_getc (s);
121    else
122        api.distance = 0;
123    if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
124        api.metric = stream_getl (s);
125    else
126        api.metric = 0;
127
128    if (command == ZEBRA_IPV6_ROUTE_ADD)
129        babel_ipv6_route_add(&api, &prefix, ifindex, &nexthop);
130    else
131        babel_ipv6_route_delete(&api, &prefix, ifindex);
132
133    return 0;
134}
135
136static int
137babel_zebra_read_ipv4 (int command, struct zclient *zclient,
138		       zebra_size_t length)
139{
140    struct stream *s;
141    struct zapi_ipv4 api;
142    unsigned long ifindex = -1;
143    struct in_addr nexthop;
144    struct prefix_ipv4 prefix;
145
146    s = zclient->ibuf;
147    ifindex = 0;
148    memset (&nexthop, 0, sizeof (struct in_addr));
149    memset (&api, 0, sizeof(struct zapi_ipv4));
150    memset (&prefix, 0, sizeof (struct prefix_ipv4));
151
152    /* Type, flags, message. */
153    api.type = stream_getc (s);
154    api.flags = stream_getc (s);
155    api.message = stream_getc (s);
156
157    /* IPv6 prefix. */
158    prefix.family = AF_INET;
159    prefix.prefixlen = stream_getc (s);
160    stream_get (&prefix.prefix, s, PSIZE (prefix.prefixlen));
161
162    /* Nexthop, ifindex, distance, metric. */
163    if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) {
164        api.nexthop_num = stream_getc (s);
165        stream_get (&nexthop, s, sizeof(nexthop));
166    }
167    if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) {
168        api.ifindex_num = stream_getc (s);
169        ifindex = stream_getl (s);
170    }
171    if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
172        api.distance = stream_getc (s);
173    else
174        api.distance = 0;
175    if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
176        api.metric = stream_getl (s);
177    else
178        api.metric = 0;
179
180    if (command == ZEBRA_IPV6_ROUTE_ADD) {
181        babel_ipv4_route_add(&api, &prefix, ifindex, &nexthop);
182    } else {
183        babel_ipv4_route_delete(&api, &prefix, ifindex);
184    }
185
186    return 0;
187}
188
189/* [Babel Command] */
190DEFUN (babel_redistribute_type,
191       babel_redistribute_type_cmd,
192       "redistribute " QUAGGA_REDIST_STR_BABELD,
193       "Redistribute\n"
194       QUAGGA_REDIST_HELP_STR_BABELD)
195{
196    int type;
197
198    type = proto_redistnum(AFI_IP6, argv[0]);
199
200    if (type < 0)
201        type = proto_redistnum(AFI_IP, argv[0]);
202
203    if (type < 0) {
204        vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE);
205        return CMD_WARNING;
206    }
207
208    zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type);
209    return CMD_SUCCESS;
210}
211
212/* [Babel Command] */
213DEFUN (no_babel_redistribute_type,
214       no_babel_redistribute_type_cmd,
215       "no redistribute " QUAGGA_REDIST_STR_BABELD,
216       NO_STR
217       "Redistribute\n"
218       QUAGGA_REDIST_HELP_STR_BABELD)
219{
220    int type;
221
222    type = proto_redistnum(AFI_IP6, argv[0]);
223
224    if (type < 0)
225        type = proto_redistnum(AFI_IP, argv[0]);
226
227    if (type < 0) {
228        vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE);
229        return CMD_WARNING;
230    }
231
232    zclient_redistribute (ZEBRA_REDISTRIBUTE_DELETE, zclient, type);
233    /* perhaps should we remove xroutes having the same type... */
234    return CMD_SUCCESS;
235}
236
237#ifndef NO_DEBUG
238/* [Babel Command] */
239DEFUN (debug_babel,
240       debug_babel_cmd,
241       "debug babel (common|kernel|filter|timeout|interface|route|all)",
242       "Enable debug messages for specific or all part.\n"
243       "Babel information\n"
244       "Common messages (default)\n"
245       "Kernel messages\n"
246       "Filter messages\n"
247       "Timeout messages\n"
248       "Interface messages\n"
249       "Route messages\n"
250       "All messages\n")
251{
252    int i;
253
254    for(i = 0; debug_type[i].str != NULL; i++) {
255        if (strncmp (debug_type[i].str, argv[0],
256                     debug_type[i].str_min_len) == 0) {
257            debug |= debug_type[i].type;
258            return CMD_SUCCESS;
259        }
260    }
261
262    vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE);
263
264    return CMD_WARNING;
265}
266
267/* [Babel Command] */
268DEFUN (no_debug_babel,
269       no_debug_babel_cmd,
270       "no debug babel (common|kernel|filter|timeout|interface|route|all)",
271       NO_STR
272       "Disable debug messages for specific or all part.\n"
273       "Babel information\n"
274       "Common messages (default)\n"
275       "Kernel messages\n"
276       "Filter messages\n"
277       "Timeout messages\n"
278       "Interface messages\n"
279       "Route messages\n"
280       "All messages\n")
281{
282    int i;
283
284    for (i = 0; debug_type[i].str; i++) {
285        if (strncmp(debug_type[i].str, argv[0],
286                    debug_type[i].str_min_len) == 0) {
287            debug &= ~debug_type[i].type;
288            return CMD_SUCCESS;
289        }
290    }
291
292    vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE);
293
294    return CMD_WARNING;
295}
296#endif /* NO_DEBUG */
297
298/* Output "debug" statement lines, if necessary. */
299int
300debug_babel_config_write (struct vty * vty)
301{
302#ifdef NO_DEBUG
303    return 0;
304#else
305    int i, lines = 0;
306
307    if (debug == BABEL_DEBUG_ALL)
308    {
309        vty_out (vty, "debug babel all%s", VTY_NEWLINE);
310        lines++;
311    }
312    else
313        for (i = 0; debug_type[i].str != NULL; i++)
314            if
315            (
316                debug_type[i].type != BABEL_DEBUG_ALL
317                && CHECK_FLAG (debug, debug_type[i].type)
318            )
319            {
320                vty_out (vty, "debug babel %s%s", debug_type[i].str, VTY_NEWLINE);
321                lines++;
322            }
323    if (lines)
324    {
325        vty_out (vty, "!%s", VTY_NEWLINE);
326        lines++;
327    }
328    return lines;
329#endif /* NO_DEBUG */
330}
331
332void babelz_zebra_init(void)
333{
334    zclient = zclient_new();
335    zclient_init(zclient, ZEBRA_ROUTE_BABEL);
336
337    zclient->interface_add = babel_interface_add;
338    zclient->interface_delete = babel_interface_delete;
339    zclient->interface_up = babel_interface_up;
340    zclient->interface_down = babel_interface_down;
341    zclient->interface_address_add = babel_interface_address_add;
342    zclient->interface_address_delete = babel_interface_address_delete;
343    zclient->ipv4_route_add = babel_zebra_read_ipv4;
344    zclient->ipv4_route_delete = babel_zebra_read_ipv4;
345    zclient->ipv6_route_add = babel_zebra_read_ipv6;
346    zclient->ipv6_route_delete = babel_zebra_read_ipv6;
347
348    install_node (&zebra_node, zebra_config_write);
349    install_element(BABEL_NODE, &babel_redistribute_type_cmd);
350    install_element(BABEL_NODE, &no_babel_redistribute_type_cmd);
351    install_element(ENABLE_NODE, &debug_babel_cmd);
352    install_element(ENABLE_NODE, &no_debug_babel_cmd);
353    install_element(CONFIG_NODE, &debug_babel_cmd);
354    install_element(CONFIG_NODE, &no_debug_babel_cmd);
355}
356
357static int
358zebra_config_write (struct vty *vty)
359{
360    if (! zclient->enable)
361    {
362        vty_out (vty, "no router zebra%s", VTY_NEWLINE);
363        return 1;
364    }
365    else if (! zclient->redist[ZEBRA_ROUTE_BABEL])
366    {
367        vty_out (vty, "router zebra%s", VTY_NEWLINE);
368        vty_out (vty, " no redistribute babel%s", VTY_NEWLINE);
369        return 1;
370    }
371    return 0;
372}
373
374void
375babel_zebra_close_connexion(void)
376{
377    zclient_stop(zclient);
378}
379