123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913 |
- /* This file is part of Netsukuku
- * (c) Copyright 2005 Andrea Lo Pumo aka AlpT <alpt@freaknet.org>
- *
- * This source code is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License,
- * or (at your option) any later version.
- *
- * This source code is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * Please refer to the GNU Public License for more details.
- *
- * You should have received a copy of the GNU Public License along with
- * this source code; if not, write to:
- * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * --
- * route.c:
- * Routing table management code.
- */
-
- #include "includes.h"
-
- #include "common.h"
- #include "libnetlink.h"
- #include "inet.h"
- #include "krnl_route.h"
- #include "request.h"
- #include "endianness.h"
- #include "pkts.h"
- #include "bmap.h"
- #include "qspn.h"
- #include "radar.h"
- #include "netsukuku.h"
- #include "route.h"
-
- int get_gw_gnode_recurse(map_node *, map_gnode **, map_bnode **, u_int *,
- map_gnode *, map_gnode *, map_node *, u_char,
- u_char, void **, int, int);
-
- /*
- * get_gw_bnode_recurse: this function is part of get_gw_gnode_recurse().
- * The explanation of it's way of working is inside the get_gw_gnode()
- * function.
- */
- int
- get_gw_bnode_recurse(map_node * int_map, map_gnode ** ext_map,
- map_bnode ** bnode_map, u_int * bmap_nodes,
- map_gnode * find_gnode, map_gnode * gnode_gw,
- map_node * node_gw, u_char gnode_level,
- u_char gw_level, void **gateways, int gateways_nmembs,
- int single_gw)
- {
- map_gnode *gnode = 0;
- map_node *node, *root_node;
- ext_rnode_cache *erc;
- int i, bpos;
-
- i = gnode_level;
-
- if (i == gw_level) {
- /* Gateway found */
- gateways[0] = (void *) node_gw;
- return 0;
- } else if (!i)
- return -1;
-
- /* Find the bnode which borders on the `node_gw' gnode */
- bpos =
- map_find_bnode_rnode(bnode_map[i - 1], bmap_nodes[i - 1],
- (void *) node_gw);
- if (bpos == -1) {
- /*debug(DBG_INSANE, "get_gw: l=%d, node_gw=%x not found in bmap lvl %d",
- i, node_gw, i-1); */
- return -1;
- }
-
- if (!(i - 1))
- node = node_from_pos(bnode_map[i - 1][bpos].bnode_ptr, int_map);
- else {
- gnode = gnode_from_pos(bnode_map[i - 1][bpos].bnode_ptr,
- ext_map[_EL(i - 1)]);
- node = &gnode->g;
-
- /* If we are a bnode and the `gnode', the found bnode, is us,
- * let's check if we have `gnode_gw' in our external rnode
- * cache. If we have, the gw has been found */
- qspn_set_map_vars(i - 1, 0, &root_node, 0, 0);
- if (me.cur_node->flags & MAP_BNODE &&
- gnode == (map_gnode *) root_node) {
- /* debug(DBG_INSANE, "get_gw: bmap searching ernode for gnode 0x%x",node_gw); */
-
- erc = erc_find_gnode(me.cur_erc, gnode_gw, i);
- if (erc) {
- gateways[0] = (void *) erc->e;
- return 0;
- }
- }
- }
-
- /* debug(DBG_INSANE, "get_gw: bmap found = %x", node); */
-
- /* Descend in the lower level */
- if ((--i) >= gw_level)
- return get_gw_gnode_recurse(int_map, ext_map, bnode_map,
- bmap_nodes, find_gnode, gnode, node, i,
- gw_level, gateways, gateways_nmembs,
- single_gw);
- return -1;
- }
-
-
- /*
- * get_gw_gnode_recurse: recursive part of the get_gw_gnode function (see
- * below).
- * `gateways' is the array of pointers. which point to the found gateway
- * nodes.
- * `gateways_nmembs' is the number of members of the `gateways' array.
- */
- int
- get_gw_gnode_recurse(map_node * int_map, map_gnode ** ext_map,
- map_bnode ** bnode_map, u_int * bmap_nodes,
- map_gnode * find_gnode, map_gnode * gnode,
- map_node * node, u_char gnode_level, u_char gw_level,
- void **gateways, int gateways_nmembs, int single_gw)
- {
- map_gnode *gnode_gw = 0;
- map_node *node_gw;
- int i, pos, routes, sub_routes, e, ret;
-
- /*debug(DBG_INSANE, "get_gw: find_gnode=%x", find_gnode); */
- i = gnode_level;
-
- if (node->flags & MAP_RNODE) {
- /*
- * If `node' is an our rnode, then the gateway to reach it is
- * itself, so we set the `gnode_gw' to `node' in order to find
- * in the lower level a bnode which borders on `node'
- */
- gnode_gw = (void *) node;
- node_gw = (map_node *) gnode_gw;
- /*debug(DBG_INSANE, "get_gw: l=%d, node & MAP_RNODE. node_gw=node=%x",
- i, node); */
- } else if (node->flags & MAP_ME) {
- /*
- * If `node' is an our gnode. we reset the gnode_gw to
- * `find_gnode', in this way, in the lower level we'll find a
- * bnode which borders on `find_gnode'.
- */
- gnode_gw = (void *) find_gnode;
- node_gw = (map_node *) gnode_gw;
- /*debug(DBG_INSANE, "get_gw: l=%d, node & MAP_ME. find_gnode: %x",
- i, find_gnode); */
- } else {
-
- if (!node->links || (i && !gnode))
- /* That's no good */
- return -1;
-
- if (single_gw) {
- /* only one route is needed, do not fork */
- routes = 1;
- sub_routes = 1;
- } else {
- /* `routes': how many different links we must consider */
- routes = sub_gw_links[FAMILY_LVLS - i - 1];
- routes = routes > node->links ? node->links : routes;
-
- /* How many routes there are in each of the `routes'# links */
- sub_routes = gateways_nmembs / routes;
-
- }
-
- int old_pos[routes];
- memset(old_pos, -1, sizeof(int) * routes);
-
- ret = 0;
- for (e = 0; e < routes; e++) {
-
- /* Choose a random link, which was not chosen before */
- while (find_int
- ((pos =
- rand_range(0, node->links - 1)), old_pos, routes));
- old_pos[e] = pos;
-
- if (!i) {
- node_gw = (void *) node->r_node[pos].r_node;
- } else {
- gnode_gw = (map_gnode *) gnode->g.r_node[pos].r_node;
- node_gw = (void *) gnode_gw;
- }
-
- if (node_gw->flags & MAP_RNODE)
- find_gnode = (map_gnode *) node_gw;
- /*debug(DBG_INSANE, "get_gw: l=%d, e %d node_gw=rnode[%d].r_node=%x,"
- " find_gnode=%x", i, e, pos, node_gw, find_gnode); */
-
- ret +=
- get_gw_bnode_recurse(int_map, ext_map, bnode_map,
- bmap_nodes, find_gnode, gnode_gw,
- node_gw, i, gw_level,
- &gateways[e * sub_routes], sub_routes,
- single_gw);
- }
- return ret;
- }
-
- return get_gw_bnode_recurse(int_map, ext_map, bnode_map, bmap_nodes,
- find_gnode, gnode_gw, node_gw, i, gw_level,
- gateways, gateways_nmembs, single_gw);
- }
-
-
- /*
- * get_gw_gnode: It finds the MAX_MULTIPATH_ROUTES best gateway present in the
- * map of level `gw_level'. These gateways are the nodes to be used as gateway
- * to reach, from the `gw_level' level, the `find_gnode' gnode at the
- * `gnode_level' level.
- * If not a single gateway is found, NULL is returned, otherwise an array of
- * pointers to the gateway nodes is returned, the array has
- * MAX_MULTIPATH_ROUTES+1 nmembs. Some member of the array can be NULL, ignore
- * them. Remember to xfree the array of pointers!
- * If `single_gw' is not 0, only one gateway will be returned.
- */
- void **
- get_gw_gnode(map_node * int_map, map_gnode ** ext_map,
- map_bnode ** bnode_map, u_int * bmap_nodes,
- map_gnode * find_gnode, u_char gnode_level,
- u_char gw_level, int single_gw)
- {
- map_gnode *gnode;
- map_node *node;
- void **gateways = 0;
- int ret;
-
- if (!gnode_level || gw_level > gnode_level)
- goto error;
-
- gateways = xzalloc(sizeof(void *) * MAX_MULTIPATH_ROUTES + 1);
-
- /*
- * In order to find the gateway at level `gw_level', which will be
- * used to reach the `find_gnode' gnode at level `gnode_level',
- * firstly we find the gnode, at level `gnode_level' that can be used
- * as a gateway to reach `find_gnode', then we go down of one level
- * and we search the gateway that can be used to reach the border node
- * which borders to the previously found gateway. The same procedure
- * is done until we arrive at the desired `gw_level' level.
- *
- * Sadly this procedure can give us only one route to reach the
- * `find_gnode' gnode, in fact, there can be, at each level, multiple
- * gateways to reach the same gnode (or bnode). For this reason, at
- * each level, we must first fork at each found gateway and then we
- * can descend in the lower level. In this way each forked child will
- * try to find the gateway to reach the bnode which borders on the
- * parent gateway.
- * Each found gateway, which belongs to the `gw_level' is added to the
- * `gateways' array, but here comes another problem: if in each level
- * we find the maximum number of available gateways, there will be a
- * total of MAX_MULTIPATH_ROUTES^(gnode_level-gw_level) routes.
- * We can return only MAX_MULTIPATH_ROUTES routes, so we restrict the
- * number of forks per level. Each level has its forks number, which
- * is already stored in the `sub_gw_links' array. (For more info on
- * that array, read route.h).
- * That's all.
- *
- * To implement all that mess we use three functions, in this way:
- *
- * get_gw_gnode() is only the starting function. It sets
- * gnode=find_gnode and launches get_gw_gnode_recurse(gnode), which
- * finds the gateway to reach the given `gnode'. It then forks for
- * each gateway found and launches get_gw_bnode_recurse(gateway) which
- * searches, in the lower level, the bnode which borders on `gateway'.
- * Then get_gw_bnode_recurse() sets gnode to the found gateway and
- * launches again get_gw_gnode(gnode). The loop continues until the
- * `gw_level' is reached.
- *
- * Wow, that was a long explanation ;)
- */
- gnode = find_gnode;
- node = &gnode->g;
-
- /* The gateway to reach me is myself. */
- if (node->flags & MAP_ME) {
- gateways[0] = (void *) node;
- return gateways;
- }
-
- ret = get_gw_gnode_recurse(int_map, ext_map, bnode_map, bmap_nodes,
- find_gnode, gnode, node, gnode_level,
- gw_level, gateways, MAX_MULTIPATH_ROUTES,
- single_gw);
-
- if (ret < 0)
- goto error;
-
- return gateways;
-
- error:
- if (gateways)
- xfree(gateways);
- return 0;
- }
-
-
-
- /*
- * get_gw_ips: It's a wrapper to get_gw_gnode() that converts the found
- * gateways to IPs.
- * `gw_ip' is the array of inet_prefix structs where the converted IPs will be
- * stored. It must have MAX_MULTIPATH_ROUTES members.
- * If `single_gw' is not null, only the best gateway will be converted and it
- * is assumed that `gw_ip' has only 1 member.
- * The number of IPs stored in `gw_ip' is returned.
- * The pointer to the gateways node pointers are copied in the `gw_gnodes'
- * array, (if not null), which must have at least MAX_MULTIPATH_ROUTES members.
- * On error -1 is returned.
- */
- int
- get_gw_ips(map_node * int_map, map_gnode ** ext_map,
- map_bnode ** bnode_map, u_int * bmap_nodes,
- quadro_group * cur_quadg,
- map_gnode * find_gnode, u_char gnode_level,
- u_char gw_level, inet_prefix * gw_ip, map_node ** gw_nodes,
- int single_gw)
- {
- ext_rnode *e_rnode = 0;
- map_node **gw_node = 0;
- int i, e, gw_ip_members;
-
- gw_ip_members = single_gw ? 1 : MAX_MULTIPATH_ROUTES;
- setzero(gw_ip, sizeof(inet_prefix) * gw_ip_members);
-
- gw_node =
- (map_node **) get_gw_gnode(int_map, ext_map, bnode_map, bmap_nodes,
- find_gnode, gnode_level, gw_level,
- single_gw);
-
- if (!gw_node)
- return -1;
-
- for (i = 0, e = 0; i < MAX_MULTIPATH_ROUTES; i++) {
-
- if (!gw_node[i])
- continue;
-
- if (gw_node[i]->flags & MAP_ERNODE) {
- e_rnode = (ext_rnode *) gw_node[i];
- inet_copy(&gw_ip[e], &e_rnode->quadg.ipstart[gw_level]);
- } else
- maptoip((uintptr_t) int_map, (uintptr_t) gw_node[i],
- cur_quadg->ipstart[1], &gw_ip[e]);
-
- if (gw_nodes)
- gw_nodes[e] = gw_node[i];
-
- e++;
- }
-
- xfree(gw_node);
- return e ? e : -1;
- }
-
- /*
- * find_rnode_dev_and_retry
- *
- * Searches with rnl_get_dev() the rnode_list which points to `node'.
- * If it is not found it waits the next radar_scan. If it is not found again
- * NULL is returned, otherwise the devices list of the related rnode_list
- * struct is returned.
- */
- interface **
- find_rnode_dev_and_retry(map_node * node)
- {
- int retries;
- interface **devs = 0;
-
- for (retries = 0; !(devs = rnl_get_dev(rlist, node)) && !retries;
- retries++)
- radar_wait_new_scan();
- return devs;
- }
-
- /*
- * rt_build_nexthop_gw: returns an array of nexthop structs, which has a
- * maximum of `maxhops' members. The nexthop are all gateway which can be used
- * to reach `node' or `gnode'.
- * The array is xmallocateed.
- * On error NULL is returned.
- */
- struct nexthop *
- rt_build_nexthop_gw(map_node * node, map_gnode * gnode, int level,
- int maxhops)
- {
- map_node *tmp_node;
- struct nexthop *nh = 0;
- interface **devs;
- int n, i, ips, routes;
-
- if (!level) {
- nh = xmalloc(sizeof(struct nexthop) * (node->links + 1));
- setzero(nh, sizeof(struct nexthop) * (node->links + 1));
-
- for (i = 0, n = 0; i < node->links; i++) {
- tmp_node = (map_node *) node->r_node[i].r_node;
-
- maptoip((uintptr_t) me.int_map, (uintptr_t) tmp_node,
- me.cur_quadg.ipstart[1], &nh[n].gw);
- inet_htonl(nh[n].gw.data, nh[n].gw.family);
-
- if (!(devs = find_rnode_dev_and_retry(tmp_node)))
- continue;
- nh[n].dev = devs[0]->dev_name;
-
- nh[n].hops = node->links - i; /* multipath weigth */
- n++;
-
- if (maxhops && n >= maxhops)
- break;
- }
- nh[n].dev = 0;
- } else if (level) {
- inet_prefix gnode_gws[MAX_MULTIPATH_ROUTES];
- map_node *gw_nodes[MAX_MULTIPATH_ROUTES];
-
- routes = get_gw_ips(me.int_map, me.ext_map, me.bnode_map,
- me.bmap_nodes, &me.cur_quadg,
- gnode, level, 0, gnode_gws, gw_nodes, 0);
- if (routes < 0)
- goto finish;
-
- nh = xmalloc(sizeof(struct nexthop) * (routes + 1));
- setzero(nh, sizeof(struct nexthop) * (routes + 1));
-
- for (ips = 0, n = 0; ips < routes; ips++) {
- inet_copy(&nh[n].gw, &gnode_gws[ips]);
- inet_htonl(nh[n].gw.data, nh[n].gw.family);
-
- if (!(devs = find_rnode_dev_and_retry(gw_nodes[ips])))
- continue;
- nh[n].dev = devs[0]->dev_name;
-
- nh[n].hops = routes - ips; /* multipath weigth */
- n++;
-
- if (maxhops && n >= maxhops)
- break;
- }
-
- nh[n].dev = 0;
- }
- finish:
- return nh;
- }
-
- struct nexthop *
- rt_build_nexthop_voidgw(void *void_gw, interface ** oifs)
- {
- map_node *gw_node = 0;
- ext_rnode *e_rnode = 0;
- struct nexthop *nh;
- int dev_n, i;
-
- if (void_gw)
- gw_node = (map_node *) void_gw;
-
- if (!oifs && !(oifs = find_rnode_dev_and_retry(gw_node)))
- /* It wasn't found any suitable dev */
- return 0;
-
- for (dev_n = 0; oifs[dev_n]; dev_n++);
-
- nh = xmalloc(sizeof(struct nexthop) * (dev_n + 1));
- setzero(nh, sizeof(struct nexthop) * (dev_n + 1));
-
- if (gw_node->flags & MAP_ERNODE) {
- e_rnode = (ext_rnode *) gw_node;
- inet_copy(&nh[0].gw, &e_rnode->quadg.ipstart[0]);
- } else
- maptoip((uintptr_t) me.int_map, (uintptr_t) gw_node,
- me.cur_quadg.ipstart[1], &nh[0].gw);
- inet_htonl(nh[0].gw.data, nh[0].gw.family);
- nh[0].dev = oifs[0]->dev_name;
- nh[0].hops = 1;
-
- for (i = 1; i < dev_n; i++) {
- memcpy(&nh[i], &nh[0], sizeof(struct nexthop));
- nh[i].dev = oifs[i]->dev_name;
- nh[i].hops = 1;
- }
- nh[i].dev = 0;
-
- return nh;
- }
-
- /*
- * rt_update_node
- *
- * It adds/replaces or removes a route from the kernel's
- * table, if the node's flag is found, respectively, to be set to
- * MAP_UPDATE or set to MAP_VOID. When a route is deleted only the destination
- * arguments are required (i.e `void_gw', `oif' are not needed).
- *
- * The destination of the route can be given with `dst_ip', `dst_node' or
- * `dst_quadg'.
- *
- * If `dst_ip' is not null, the given inet_prefix struct is used, it's also
- * used the `dst_node' to retrieve the flags.
- * If the destination of the route is a node which belongs to the level 0, the
- * same node must be passed in the `dst_node' argument.
- *
- * If `level' is > 0 and `dst_quadg' is not null, then it updates the gnode
- * which is inside the `dst_quadg' struct: dst_quadg->gnode[_EL(level)]. The
- * quadro_group struct must be complete and refer to the groups of the
- * given gnode.
- *
- * If `level' is > 0 and `dst_quadg' is null, it's assumed that the gnode is passed
- * in `dst_node' and that the quadro_group for that gnode is me.cur_quadg.
- *
- * If `void_gw' is not null, it is used as the only gw to reach the destination
- * node, otherwise the gw will be calculated.
- * `oifs', if not null, will be used in conjuction with `void_gw' as the output
- * interfaces to be used in the route. `oifs' is an array of pointers of
- * maximum MAX_INTERFACES# members.
- */
- void
- rt_update_node(inet_prefix * dst_ip, void *dst_node,
- quadro_group * dst_quadg, void *void_gw, interface ** oifs,
- u_char level)
- {
- map_node *node = 0;
- map_gnode *gnode = 0;
- struct nexthop *nh = 0;
- inet_prefix to;
- int node_pos = 0, route_scope = 0;
-
- #ifdef DEBUG
- #define MAX_GW_IP_STR_SIZE (MAX_MULTIPATH_ROUTES*((INET6_ADDRSTRLEN+1)+IFNAMSIZ)+1)
- int n;
- char *to_ip = 0, gw_ip[MAX_GW_IP_STR_SIZE] = "";
- #else
- const char *to_ip = 0;
- #endif
-
- node = (map_node *) dst_node;
- gnode = (map_gnode *) dst_node;
-
- /*
- * Deduce the destination's ip
- */
- if (dst_ip)
- inet_copy(&to, dst_ip);
- else if (level) {
- if (!dst_quadg) {
- dst_quadg = &me.cur_quadg;
- node_pos = pos_from_gnode(gnode, me.ext_map[_EL(level)]);
- } else {
- gnode = dst_quadg->gnode[_EL(level)];
- node_pos = dst_quadg->gid[level];
- }
- node = &gnode->g;
- gnodetoip(dst_quadg, node_pos, level, &to);
- } else {
- node_pos = pos_from_node(node, me.int_map);
- maptoip((uintptr_t) me.int_map, (uintptr_t) node,
- me.cur_quadg.ipstart[1], &to);
- }
- #ifdef DEBUG
- to_ip = xstrdup(inet_to_str(to));
- #else
- to_ip = inet_to_str(to);
- #endif
- inet_htonl(to.data, to.family);
-
- if (node->flags & MAP_VOID)
- /* We have only to delete the route, skip to do_update */
- goto do_update;
-
- /*
- * If `node' it's a rnode of level 0, do nothing! It is already
- * directly connected to me. (If void_gw is not null, skip this check).
- */
- if (node->flags & MAP_RNODE && !level && !void_gw)
- goto finish;
-
- /* Dumb you, we don't need the route to reach ourself */
- if (node->flags & MAP_ME)
- goto finish;
-
- /*
- * Now, get the gateway to reach the destination.
- */
- if (void_gw)
- nh = rt_build_nexthop_voidgw(void_gw, oifs);
- else
- nh = rt_build_nexthop_gw(node, gnode, level, MAX_MULTIPATH_ROUTES);
- if (!nh) {
- debug(DBG_NORMAL, "Cannot get the gateway for "
- "the (g)node: %d of level: %d, ip:"
- "%s", node_pos, level, to_ip);
- goto finish;
- }
-
- do_update:
- #ifdef DEBUG
- for (n = 0; nh && nh[n].dev; n++) {
- strcat(gw_ip, inet_to_str(nh[n].gw));
- strcat(gw_ip, ":");
- strcat(gw_ip, nh[n].dev);
- if (nh[n + 1].dev)
- strcat(gw_ip, ",");
- }
- if (node->flags & MAP_VOID)
- strcpy(gw_ip, "deleted");
- debug(DBG_INSANE,
- "rt_update_node: to " PURPLE("%s/%d") " via " RED("%s"), to_ip,
- to.bits, gw_ip);
-
- #endif
- if (node->flags & MAP_RNODE && !level)
- /* The dst node is a node directly linked to us */
- route_scope = RT_SCOPE_LINK;
-
- if (node->flags & MAP_VOID) {
- /* Ok, let's delete it */
- if (route_del(RTN_UNICAST, 0, 0, &to, 0, 0, 0))
- error("WARNING: Cannot delete the route entry for the"
- "%snode %d lvl %d!", !level ? " " : " g",
- node_pos, level);
- } else if (route_replace(0, route_scope, 0, &to, nh, 0, 0))
- error("WARNING: Cannot update the route entry for the"
- "%snode %d lvl %d", !level ? " " : " g", node_pos, level);
- finish:
- #ifdef DEBUG
- if (to_ip)
- xfree(to_ip);
- #endif
- if (nh)
- xfree(nh);
- }
-
- /*
- * rt_rnodes_update
- *
- * It updates all the node which are rnodes of the root_node
- * of all the maps. If `check_update_flag' is non zero, the rnode will be
- * updated only if it has the MAP_UPDATE flag set.
- */
- void
- rt_rnodes_update(int check_update_flag)
- {
- u_short i, level;
- ext_rnode *e_rnode;
- map_node *root_node, *node, *rnode;
- map_gnode *gnode;
- interface **out_devs;
-
- /* Internal map */
- root_node = me.cur_node;
- for (i = 0; i < root_node->links; i++) {
- rnode = (map_node *) root_node->r_node[i].r_node;
- out_devs = rnl_get_dev(rlist, rnode);
-
- if (check_update_flag && !(rnode->flags & MAP_UPDATE))
- /* nothing to do for this rnode */
- continue;
-
- if (rnode->flags & MAP_ERNODE) {
- e_rnode = (ext_rnode *) rnode;
-
- rt_update_node(&e_rnode->quadg.ipstart[0], rnode, 0,
- me.cur_node, out_devs, /*level */ 0);
- rnode->flags &= ~MAP_UPDATE;
-
- for (level = 1; level < e_rnode->quadg.levels; level++) {
- if (!(gnode = e_rnode->quadg.gnode[_EL(level)]))
- continue;
-
- node = &gnode->g;
- rt_update_node(0, 0, &e_rnode->quadg,
- rnode, out_devs, level);
- node->flags &= ~MAP_UPDATE;
- }
- } else {
- rt_update_node(0, rnode, 0, me.cur_node, out_devs, /*level */
- 0);
- rnode->flags &= ~MAP_UPDATE;
- }
- }
-
- /*
- * Shall we activate it?
- * route_flush_cache(my_family);
- */
- }
-
- /*
- * rt_full_update
- *
- * It updates _ALL_ the possible routes it can get from _ALL_ the maps.
- * If `check_update_flag' is not 0, it will update only the routes of the
- * nodes with the MAP_UPDATE flag set. Note that the MAP_VOID nodes aren't
- * considered.
- */
- void
- rt_full_update(int check_update_flag)
- {
- u_short i, l;
-
- /* Update ext_maps */
- for (l = me.cur_quadg.levels - 1; l >= 1; l--)
- for (i = 0; i < MAXGROUPNODE; i++) {
- if (me.ext_map[_EL(l)][i].g.flags & MAP_VOID ||
- me.ext_map[_EL(l)][i].flags & GMAP_VOID ||
- me.ext_map[_EL(l)][i].g.flags & MAP_ME)
- continue;
-
- if (check_update_flag &&
- !(me.ext_map[_EL(l)][i].g.flags & MAP_UPDATE))
- continue;
-
- rt_update_node(0, &me.ext_map[_EL(l)][i].g, 0, 0, 0, l);
- me.ext_map[_EL(l)][i].g.flags &= ~MAP_UPDATE;
- }
-
- /* Update int_map */
- for (i = 0, l = 0; i < MAXGROUPNODE; i++) {
- if (me.int_map[i].flags & MAP_VOID || me.int_map[i].flags & MAP_ME)
- continue;
-
- if (check_update_flag && !((me.int_map[i].flags & MAP_UPDATE)))
- continue;
-
- rt_update_node(0, &me.int_map[i], 0, 0, 0, l);
- me.int_map[i].flags &= ~MAP_UPDATE;
- }
-
- route_flush_cache(my_family);
- }
-
- /*
- * rt_get_default_gw
- *
- * It stores in `gw' the IP address of the current default gw, and in
- * `dev_name' its utilised net interface. If the default gw doesn't exist
- * `gw' and `dev_name' are set to 0.
- * If an error occurred a number < 0 is returned.
- * `dev_name' must be of IFNAMSIZ# bytes.
- */
- int
- rt_get_default_gw(inet_prefix * gw, char *dev_name)
- {
- inet_prefix default_gw;
-
- inet_setip_anyaddr(&default_gw, my_family);
- default_gw.len = default_gw.bits = 0;
- return route_get_exact_prefix_dst(default_gw, gw, dev_name);
- }
-
- int
- rt_exec_gw(char *dev, inet_prefix to, inet_prefix gw,
- int (*route_function) (ROUTE_CMD_VARS), u_char table)
- {
- struct nexthop nh[2], *neho;
-
- if (to.len)
- inet_htonl(to.data, to.family);
-
- if (gw.len) {
- setzero(nh, sizeof(struct nexthop) * 2);
- inet_copy(&nh[0].gw, &gw);
- inet_htonl(nh[0].gw.data, nh[0].gw.family);
- nh[0].dev = dev;
- nh[1].dev = 0;
- neho = nh;
- } else
- neho = 0;
-
- return route_function(0, 0, 0, &to, neho, dev, table);
- }
-
- int
- rt_add_gw(char *dev, inet_prefix to, inet_prefix gw, u_char table)
- {
- return rt_exec_gw(dev, to, gw, route_add, table);
- }
-
- int
- rt_del_gw(char *dev, inet_prefix to, inet_prefix gw, u_char table)
- {
- return rt_exec_gw(dev, to, gw, route_del, table);
- }
-
- int
- rt_change_gw(char *dev, inet_prefix to, inet_prefix gw, u_char table)
- {
- return rt_exec_gw(dev, to, gw, route_change, table);
- }
-
- int
- rt_replace_gw(char *dev, inet_prefix to, inet_prefix gw, u_char table)
- {
- return rt_exec_gw(dev, to, gw, route_replace, table);
- }
-
- int
- rt_replace_def_gw(char *dev, inet_prefix gw, u_char table)
- {
- inet_prefix to;
-
- if (inet_setip_anyaddr(&to, my_family)) {
- error("rt_replace_def_gw(): Cannot use INADRR_ANY for the %d "
- "family", to.family);
- return -1;
- }
- to.len = to.bits = 0;
-
- return rt_replace_gw(dev, to, gw, table);
- }
-
- int
- rt_delete_def_gw(u_char table)
- {
- inet_prefix to;
-
- if (inet_setip_anyaddr(&to, my_family)) {
- error("rt_delete_def_gw(): Cannot use INADRR_ANY for the %d "
- "family", to.family);
- return -1;
- }
- to.len = to.bits = 0;
-
- return route_del(0, 0, 0, &to, 0, 0, table);
- }
-
- /*
- * rt_del_loopback_net:
- * We remove the loopback net, leaving only the 127.0.0.1 ip for loopback.
- * ip route del local 127.0.0.0/8 proto kernel scope host src 127.0.0.1
- * ip route del broadcast 127.255.255.255 proto kernel scope link src 127.0.0.1
- * ip route del broadcast 127.0.0.0 proto kernel scope link src 127.0.0.1
- */
- int
- rt_del_loopback_net(void)
- {
- inet_prefix to;
- char lo_dev[] = "lo";
- u_int idata[MAX_IP_INT];
-
- setzero(idata, MAX_IP_SZ);
- if (my_family != AF_INET)
- return 0;
-
- /*
- * ip route del broadcast 127.0.0.0 proto kernel scope link \
- * src 127.0.0.1
- */
- idata[0] = LOOPBACK_NET;
- inet_setip(&to, idata, my_family);
- route_del(RTN_BROADCAST, 0, 0, &to, 0, 0, RT_TABLE_LOCAL);
-
- /*
- * ip route del local 127.0.0.0/8 proto kernel scope host \
- * src 127.0.0.1
- */
- to.bits = 8;
- route_del(RTN_LOCAL, 0, 0, &to, 0, lo_dev, RT_TABLE_LOCAL);
-
- /*
- * ip route del broadcast 127.255.255.255 proto kernel scope link \
- * src 127.0.0.1
- */
- idata[0] = LOOPBACK_BCAST;
- inet_setip(&to, idata, my_family);
- route_del(RTN_BROADCAST, 0, 0, &to, 0, lo_dev, RT_TABLE_LOCAL);
-
- return 0;
- }
-
- /*
- * rt_append_subnet_src:
- * it appends the subnet relative to a `src' IP and its device in the routing
- * table, f.e. when you do "ifconfig eth0 10.2.3.1 up" the kernel
- * automatically adds this route:
- * 10.0.0.0/8 dev eth0 proto kernel scope link src 10.2.3.1
- * In this case `src'="10.2.3.1" and `dev'="eth0"
- */
- int
- rt_append_subnet_src(inet_prefix * src, char *dev)
- {
- inet_prefix to, src_htonl;
-
- if (src->family == AF_INET6)
- fatal(ERROR_MSG "Family not supported", ERROR_POS);
-
- inet_copy(&src_htonl, src);
- inet_htonl(src_htonl.data, src->family);
-
- setzero(&to, sizeof(inet_prefix));
- to.family = src->family;
- to.len = src->len;
- if (((NTK_PRIVATE_B(src_htonl.data[0])) ||
- (NTK_PRIVATE_C(src_htonl.data[0])))) {
- to.bits = 16;
- to.data[0] = htonl((src->data[0] & 0xffff0000));
- } else {
- to.bits = 8;
- to.data[0] = htonl((src->data[0] & 0xff000000));
- }
-
- return route_append(0, RT_SCOPE_LINK, &src_htonl, &to, 0, dev, 0);
- }
|