xroute.c 6.82 KB
Newer Older
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
1
/*
2
Copyright (c) 2007, 2008 by Juliusz Chroboczek
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
27
#include <assert.h>
28
#include <netinet/in.h>
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
29

30
#include "babel.h"
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
31 32
#include "kernel.h"
#include "neighbour.h"
33
#include "message.h"
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
34 35
#include "route.h"
#include "xroute.h"
36
#include "util.h"
37
#include "config.h"
38
#include "network.h"
39
#include "local.h"
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
40

41
struct xroute *xroutes;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
42
int numxroutes = 0;
43
int maxxroutes = 0;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
44 45

struct xroute *
46
find_xroute(const unsigned char *prefix, unsigned char plen)
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
47 48 49
{
    int i;
    for(i = 0; i < numxroutes; i++) {
50 51 52
        if(xroutes[i].plen == plen &&
           memcmp(xroutes[i].prefix, prefix, 16) == 0)
            return &xroutes[i];
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
53
    }
54
    return NULL;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
55 56
}

57 58 59
void
flush_xroute(struct xroute *xroute)
{
60
    int i;
61

62 63
    i = xroute - xroutes;
    assert(i >= 0 && i < numxroutes);
64

65
    local_notify_xroute(xroute, LOCAL_FLUSH);
66

67 68
    if(i != numxroutes - 1)
        memcpy(xroutes + i, xroutes + numxroutes - 1, sizeof(struct xroute));
69 70
    numxroutes--;
    VALGRIND_MAKE_MEM_UNDEFINED(xroutes + numxroutes, sizeof(struct xroute));
71

72 73 74 75 76
    if(numxroutes == 0) {
        free(xroutes);
        xroutes = NULL;
        maxxroutes = 0;
    } else if(maxxroutes > 8 && numxroutes < maxxroutes / 4) {
77 78 79 80 81 82
        struct xroute *new_xroutes;
        int n = maxxroutes / 2;
        new_xroutes = realloc(xroutes, n * sizeof(struct xroute));
        if(new_xroutes == NULL)
            return;
        xroutes = new_xroutes;
83
        maxxroutes = n;
84
    }
85 86
}

87
int
88
add_xroute(unsigned char prefix[16], unsigned char plen,
89
           unsigned short metric, unsigned int ifindex, int proto)
90
{
91 92
    struct xroute *xroute = find_xroute(prefix, plen);
    if(xroute) {
93
        if(xroute->metric <= metric)
94 95
            return 0;
        xroute->metric = metric;
96
        local_notify_xroute(xroute, LOCAL_CHANGE);
97 98
        return 1;
    }
99

100 101 102 103 104 105 106 107 108 109 110
    if(numxroutes >= maxxroutes) {
        struct xroute *new_xroutes;
        int n = maxxroutes < 1 ? 8 : 2 * maxxroutes;
        new_xroutes = xroutes == NULL ?
            malloc(n * sizeof(struct xroute)) :
            realloc(xroutes, n * sizeof(struct xroute));
        if(new_xroutes == NULL)
            return -1;
        maxxroutes = n;
        xroutes = new_xroutes;
    }
111

112 113 114 115 116 117
    memcpy(xroutes[numxroutes].prefix, prefix, 16);
    xroutes[numxroutes].plen = plen;
    xroutes[numxroutes].metric = metric;
    xroutes[numxroutes].ifindex = ifindex;
    xroutes[numxroutes].proto = proto;
    numxroutes++;
118
    local_notify_xroute(&xroutes[numxroutes - 1], LOCAL_ADD);
119 120
    return 1;
}
121

122
int
123
check_xroutes(int send_updates)
124
{
125
    int i, j, metric, export, change = 0, rc;
126
    struct kernel_route *routes;
127 128
    int numroutes;
    static int maxroutes = 8;
129
    const int maxmaxroutes = 16 * 1024;
130

131 132
    debugf("\nChecking kernel routes.\n");

133
 again:
134 135 136 137
    routes = malloc(maxroutes * sizeof(struct kernel_route));
    if(routes == NULL)
        return -1;

138
    rc = kernel_addresses(NULL, 0, routes, maxroutes);
139
    if(rc < 0) {
140
        perror("kernel_addresses");
141
        numroutes = 0;
142
    } else {
143
        numroutes = rc;
144 145
    }

146 147 148 149 150 151 152 153 154 155 156
    if(numroutes >= maxroutes)
        goto resize;

    rc = kernel_routes(routes + numroutes, maxroutes - numroutes);
    if(rc < 0)
        fprintf(stderr, "Couldn't get kernel routes.\n");
    else
        numroutes += rc;

    if(numroutes >= maxroutes)
        goto resize;
157 158

    /* Check for any routes that need to be flushed */
159

160 161
    i = 0;
    while(i < numxroutes) {
162
        export = 0;
163 164
        metric = redistribute_filter(xroutes[i].prefix, xroutes[i].plen,
                                     xroutes[i].ifindex, xroutes[i].proto);
165
        if(metric < INFINITY && metric == xroutes[i].metric) {
166 167 168 169 170 171 172 173
            for(j = 0; j < numroutes; j++) {
                if(xroutes[i].plen == routes[j].plen &&
                   memcmp(xroutes[i].prefix, routes[j].prefix, 16) == 0 &&
                   xroutes[i].ifindex == routes[j].ifindex &&
                   xroutes[i].proto == routes[j].proto) {
                    if(metric < INFINITY) {
                        export = 1;
                        break;
174 175
                    }
                }
176 177
            }
        }
178

179
        if(!export) {
180 181 182 183 184 185 186 187
            unsigned char prefix[16], plen;
            struct route *route;
            memcpy(prefix, xroutes[i].prefix, 16);
            plen = xroutes[i].plen;
            flush_xroute(&xroutes[i]);
            route = find_best_route(prefix, plen, 1, NULL);
            if(route)
                install_route(route);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
188 189
            /* send_update_resend only records the prefix, so the update
               will only be sent after we perform all of the changes. */
190
            if(send_updates)
191
                send_update_resend(NULL, prefix, plen);
192
            change = 1;
193 194 195 196 197
        } else {
            i++;
        }
    }

198 199 200
    /* Add any new routes */

    for(i = 0; i < numroutes; i++) {
201 202
        if(martian_prefix(routes[i].prefix, routes[i].plen))
            continue;
203 204 205
        metric = redistribute_filter(routes[i].prefix, routes[i].plen,
                                     routes[i].ifindex, routes[i].proto);
        if(metric < INFINITY) {
206
            rc = add_xroute(routes[i].prefix, routes[i].plen,
207
                            metric, routes[i].ifindex, routes[i].proto);
208
            if(rc) {
209 210 211 212
                struct route *route;
                route = find_installed_route(routes[i].prefix, routes[i].plen);
                if(route)
                    uninstall_route(route);
213
                change = 1;
214 215 216
                if(send_updates)
                    send_update(NULL, 0, routes[i].prefix, routes[i].plen);
            }
217 218
        }
    }
219

220
    free(routes);
221 222
    /* Set up maxroutes for the next call. */
    maxroutes = MIN(numroutes + 8, maxmaxroutes);
223
    return change;
224 225 226 227 228 229 230

 resize:
    free(routes);
    if(maxroutes >= maxmaxroutes)
        return -1;
    maxroutes = MIN(maxmaxroutes, 2 * maxroutes);
    goto again;
231
}