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 (c) 2007, 2008 by Juliusz Chroboczek
19Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
20
21Permission is hereby granted, free of charge, to any person obtaining a copy
22of this software and associated documentation files (the "Software"), to deal
23in the Software without restriction, including without limitation the rights
24to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25copies of the Software, and to permit persons to whom the Software is
26furnished to do so, subject to the following conditions:
27
28The above copyright notice and this permission notice shall be included in
29all copies or substantial portions of the Software.
30
31THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
34AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
37THE SOFTWARE.
38*/
39
40#include <zebra.h>
41#include "if.h"
42#include "log.h"
43
44#include "babeld.h"
45#include "kernel.h"
46#include "neighbour.h"
47#include "message.h"
48#include "route.h"
49#include "xroute.h"
50#include "util.h"
51#include "babel_interface.h"
52
53static int xroute_add_new_route(unsigned char prefix[16], unsigned char plen,
54                                unsigned short metric, unsigned int ifindex,
55                                int proto, int send_updates);
56
57static struct xroute *xroutes;
58static int numxroutes = 0, maxxroutes = 0;
59
60/* Add redistributed route to Babel table. */
61int
62babel_ipv4_route_add (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix,
63                      unsigned int ifindex, struct in_addr *nexthop)
64{
65    unsigned char uchar_prefix[16];
66
67    inaddr_to_uchar(uchar_prefix, &prefix->prefix);
68    debugf(BABEL_DEBUG_ROUTE, "Adding new ipv4 route comming from Zebra.");
69    xroute_add_new_route(uchar_prefix, prefix->prefixlen + 96,
70                         api->metric, ifindex, 0, 1);
71    return 0;
72}
73
74/* Remove redistributed route from Babel table. */
75int
76babel_ipv4_route_delete (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix,
77                         unsigned int ifindex)
78{
79    unsigned char uchar_prefix[16];
80    struct xroute *xroute = NULL;
81
82    inaddr_to_uchar(uchar_prefix, &prefix->prefix);
83    xroute = find_xroute(uchar_prefix, prefix->prefixlen + 96);
84    if (xroute != NULL) {
85        debugf(BABEL_DEBUG_ROUTE, "Removing ipv4 route (from zebra).");
86        flush_xroute(xroute);
87    }
88    return 0;
89}
90
91/* Add redistributed route to Babel table. */
92int
93babel_ipv6_route_add (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix,
94                      unsigned int ifindex, struct in6_addr *nexthop)
95{
96    unsigned char uchar_prefix[16];
97
98    in6addr_to_uchar(uchar_prefix, &prefix->prefix);
99    debugf(BABEL_DEBUG_ROUTE, "Adding new route comming from Zebra.");
100    xroute_add_new_route(uchar_prefix, prefix->prefixlen, api->metric, ifindex,
101                         0, 1);
102    return 0;
103}
104
105/* Remove redistributed route from Babel table. */
106int
107babel_ipv6_route_delete (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix,
108                         unsigned int ifindex)
109{
110    unsigned char uchar_prefix[16];
111    struct xroute *xroute = NULL;
112
113    in6addr_to_uchar(uchar_prefix, &prefix->prefix);
114    xroute = find_xroute(uchar_prefix, prefix->prefixlen);
115    if (xroute != NULL) {
116        debugf(BABEL_DEBUG_ROUTE, "Removing route (from zebra).");
117        flush_xroute(xroute);
118    }
119    return 0;
120}
121
122struct xroute *
123find_xroute(const unsigned char *prefix, unsigned char plen)
124{
125    int i;
126    for(i = 0; i < numxroutes; i++) {
127        if(xroutes[i].plen == plen &&
128           memcmp(xroutes[i].prefix, prefix, 16) == 0)
129            return &xroutes[i];
130    }
131    return NULL;
132}
133
134void
135flush_xroute(struct xroute *xroute)
136{
137    int i;
138
139    i = xroute - xroutes;
140    assert(i >= 0 && i < numxroutes);
141
142    if(i != numxroutes - 1)
143        memcpy(xroutes + i, xroutes + numxroutes - 1, sizeof(struct xroute));
144    numxroutes--;
145    VALGRIND_MAKE_MEM_UNDEFINED(xroutes + numxroutes, sizeof(struct xroute));
146
147    if(numxroutes == 0) {
148        free(xroutes);
149        xroutes = NULL;
150        maxxroutes = 0;
151    } else if(maxxroutes > 8 && numxroutes < maxxroutes / 4) {
152        struct xroute *new_xroutes;
153        int n = maxxroutes / 2;
154        new_xroutes = realloc(xroutes, n * sizeof(struct xroute));
155        if(new_xroutes == NULL)
156            return;
157        xroutes = new_xroutes;
158        maxxroutes = n;
159    }
160}
161
162static int
163add_xroute(unsigned char prefix[16], unsigned char plen,
164           unsigned short metric, unsigned int ifindex, int proto)
165{
166    struct xroute *xroute = find_xroute(prefix, plen);
167    if(xroute) {
168        if(xroute->metric <= metric)
169            return 0;
170        xroute->metric = metric;
171        return 1;
172    }
173
174    if(numxroutes >= maxxroutes) {
175        struct xroute *new_xroutes;
176        int n = maxxroutes < 1 ? 8 : 2 * maxxroutes;
177        new_xroutes = xroutes == NULL ?
178            malloc(n * sizeof(struct xroute)) :
179            realloc(xroutes, n * sizeof(struct xroute));
180        if(new_xroutes == NULL)
181            return -1;
182        maxxroutes = n;
183        xroutes = new_xroutes;
184    }
185
186    memcpy(xroutes[numxroutes].prefix, prefix, 16);
187    xroutes[numxroutes].plen = plen;
188    xroutes[numxroutes].metric = metric;
189    xroutes[numxroutes].ifindex = ifindex;
190    xroutes[numxroutes].proto = proto;
191    numxroutes++;
192    return 1;
193}
194
195/* Returns an overestimate of the number of xroutes. */
196int
197xroutes_estimate()
198{
199    return numxroutes;
200}
201
202void
203for_all_xroutes(void (*f)(struct xroute*, void*), void *closure)
204{
205    int i;
206
207    for(i = 0; i < numxroutes; i++)
208        (*f)(&xroutes[i], closure);
209}
210
211/* add an xroute, verifying some conditions; return 0 if there is no changes */
212static int
213xroute_add_new_route(unsigned char prefix[16], unsigned char plen,
214                     unsigned short metric, unsigned int ifindex,
215                     int proto, int send_updates)
216{
217    int rc;
218    if(martian_prefix(prefix, plen))
219        return 0;
220    metric = redistribute_filter(prefix, plen, ifindex, proto);
221    if(metric < INFINITY) {
222        rc = add_xroute(prefix, plen, metric, ifindex, proto);
223        if(rc > 0) {
224            struct babel_route *route;
225            route = find_installed_route(prefix, plen);
226            if(route) {
227                if(allow_duplicates < 0 ||
228                   metric < allow_duplicates)
229                    uninstall_route(route);
230            }
231            if(send_updates)
232                send_update(NULL, 0, prefix, plen);
233            return 1;
234        }
235    }
236    return 0;
237}
238