netsukuku/src/route.c
Kirill Sotnikov f1761cad9a git repo init
2013-09-16 13:53:25 +04:00

877 lines
25 KiB
C

/* 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((u_int)int_map, (u_int)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((u_int)me.int_map, (u_int)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((u_int)me.int_map, (u_int)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((u_int)me.int_map, (u_int)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);
}