예제 #1
0
파일: gmap.c 프로젝트: Netsukuku/netsukuku
void
reset_extmap(map_gnode ** ext_map, u_char levels, int groups)
{
	int i;

	for (i = 1; i < levels; i++)
		reset_gmap(ext_map[_EL(i)], groups);
	gmap_node_del(&ext_map[_EL(levels)][0]);
}
예제 #2
0
파일: gmap.c 프로젝트: Netsukuku/netsukuku
/*
 * gnode_dec_seeds
 *
 * the same of gnode_inc_seeds, but it decrements instead.
 */
void
gnode_dec_seeds(quadro_group * qg, int level)
{
	if (level >= qg->levels - 1)
		return;

	if (qg->gnode[_EL(level + 1)]->seeds - 1 >= 0)
		qg->gnode[_EL(level + 1)]->seeds--;
	qg->gnode[_EL(level + 1)]->flags &= ~GMAP_FULL;
}
예제 #3
0
파일: gmap.c 프로젝트: Netsukuku/netsukuku
/*
 * gnode_inc_seeds
 *
 * it increments the seeds counter in the `qg'->gnode[_EL(`level'-1)] gnode,
 * setting the appropriate flag if the gnodes is full.
 */
void
gnode_inc_seeds(quadro_group * qg, int level)
{
	if (level >= qg->levels - 1)
		return;

	if (qg->gnode[_EL(level + 1)]->seeds == MAXGROUPNODE - 1)
		qg->gnode[_EL(level + 1)]->flags |= GMAP_FULL;
	else
		qg->gnode[_EL(level + 1)]->seeds++;
}
예제 #4
0
파일: gmap.c 프로젝트: Netsukuku/netsukuku
/* extmap_find_level: It returns the position of the gnode map which contains
 * the 'gnode`. This position corresponds to the level of that gmap.
 * The ext_map is given in `ext_map`. `max_level' is the maximum number of level
 * present in the `ext_map'.
 * ex: if gnode is in ext_map[i] it will return i;
 * On failure -1 is returned.*/
int
extmap_find_level(map_gnode ** ext_map, map_gnode * gnode,
				  u_char max_level)
{
	int i, a, b, c;

	for (i = 1; i < max_level; i++) {
		a = (int) gnode;
		b = (int) &ext_map[_EL(i)][0];
		c = (int) &ext_map[_EL(i)][MAXGROUPNODE - 1];

		if (a >= b && a <= c)
			return i;
	}
	return -1;
}
예제 #5
0
파일: igs.c 프로젝트: Netsukuku/netsukuku
/*
 * init_my_igws
 *
 * initialiases the `my_igws' array. This list keeps inet_gw structs which
 * points to our (g)nodes, for example:
 * my_igws[0]->node == me.cur_node,
 * my_igws[1]->node == &me.cur_quadg.gnode[_EL(1)]->g,
 * ...
 */
void
init_my_igws(inet_gw ** igws, int *igws_counter,
			 inet_gw *** my_new_igws, u_char my_bandwidth,
			 map_node * cur_node, quadro_group * qg)
{
	inet_gw *igw, **my_igws;
	map_node *node;
	int i = 0, e, bw_mean;

	init_igws(&my_igws, 0, qg->levels);

	for (i = 0; i < qg->levels; i++) {
		if (!i) {
			node = cur_node;
			bw_mean = my_bandwidth;
		} else {
			node = &qg->gnode[_EL(i)]->g;

			bw_mean = e = 0;
			igw = igws[i - 1];
			list_for(igw) {
				bw_mean += igw->bandwidth;
				e++;
			}
			bw_mean /= e;
		}

		igw = igw_add_node(igws, igws_counter, i, qg->gid[i],
						   node, (int *) qg->ipstart[0].data,
						   (u_char) bw_mean);
		my_igws[i] = igw;
	}

	*my_new_igws = my_igws;
}
예제 #6
0
/*
 * radar_update_bmap
 *
 * updates the bnode map of the given `level' the root_node bnode in the bmap
 * will also point to the gnode of level `gnode_level'+1 that is
 * `rq'->quadg.gnode[_EL(gnode_level+1)].
 */
void
radar_update_bmap(struct radar_queue *rq, int level, int gnode_level)
{
    map_gnode *gnode;
    map_node *root_node;
    map_rnode *rnode, rn;
    int bm, rnode_pos, root_node_pos;
    void *void_map;

    if (level == me.cur_quadg.levels - 1)
        return;

    qspn_set_map_vars(level, 0, &root_node, &root_node_pos, 0);
    void_map = me.ext_map;
    gnode = rq->quadg.gnode[_EL(gnode_level + 1)];

    bm = map_find_bnode(me.bnode_map[level], me.bmap_nodes[level],
                        root_node_pos);
    if (bm == -1) {
        bm = map_add_bnode(&me.bnode_map[level], &me.bmap_nodes[level],
                           root_node_pos, 0);
        rnode_pos = -1;
    } else
        rnode_pos = rnode_find(&me.bnode_map[level][bm], &gnode->g);

    if (rnode_pos == -1) {
        setzero(&rn, sizeof(map_rnode));
        rn.r_node = (int *) &gnode->g;
        rnode_add(&me.bnode_map[level][bm], &rn);
        rnode_pos = 0;
    }

    rnode = &me.bnode_map[level][bm].r_node[rnode_pos];
    rnode->trtt = MILLISEC(rq->final_rtt);
}
예제 #7
0
파일: gmap.c 프로젝트: Netsukuku/netsukuku
void
quadg_setflags(quadro_group * qg, char flags)
{
	map_gnode *gnode;
	int i;

	for (i = 1; i < qg->levels; i++)
		if ((gnode = qg->gnode[_EL(i)]))
			gnode->g.flags |= flags;
}
예제 #8
0
파일: qspn.c 프로젝트: StrangeTcy/netsukuku
void qspn_set_map_vars(u_char level, map_node **map, map_node **root_node, 
		int *root_node_pos, map_gnode **gmap)
{
	if(!level) {
		if(map)
			*map=me.int_map;
		if(root_node)
			*root_node=me.cur_node;
		if(root_node_pos)
			*root_node_pos=pos_from_node(me.cur_node, me.int_map);
	} else {
		if(map)
			*map=(map_node *)me.ext_map[_EL(level)];
		if(gmap)
			*gmap=me.ext_map[_EL(level)];
		if(root_node)
			*root_node=&me.cur_quadg.gnode[_EL(level)]->g;
		if(root_node_pos)
			*root_node_pos=me.cur_quadg.gid[level];
	}
}
예제 #9
0
파일: gmap.c 프로젝트: Netsukuku/netsukuku
/*
 * erc_find_gnode; Returns the first ext_rnode_cache having
 * erc->e->quadg.gnode[_EL( `level' )] == `gnode'
 */
ext_rnode_cache *
erc_find_gnode(ext_rnode_cache * erc, map_gnode * gnode, u_char level)
{
	ext_rnode_cache *p = erc;

	if (!erc || !level)
		return 0;

	list_for(p) {
		if (!p->e)
			continue;

		if (p->e->quadg.gnode[_EL(level)] == gnode)
			return p;
	}

	return 0;
}
예제 #10
0
파일: gmap.c 프로젝트: Netsukuku/netsukuku
/*
 * random_ip
 *
 * It generates a new random ip.
 * If `ipstart' is not NULL the new ip is restricted in the `final_gid' of
 * `final_level', so it'll be taken inside this range:
 * 	A=ipstart + (MAXGROUPNODE^( final_level + 1)) * final_gid;
 * 	B=ipstart + (MAXGROUPNODE^( final_level + 1)) * (final_gid + 1);
 * 		A <= x <= B
 * If `ipstart' is NULL a completely random ip is generated.
 * `total_levels' is the maximum number of levels.
 * `ext_map' is an external map.
 * If `only_free_gnode' is not 0, only the available and empty gnode are chosen.
 * In this case -1 may be returned if there aren't any free gnode to choose.
 * The new ip is stored in `new_ip' and on success 0 is returned.
 */
int
random_ip(inet_prefix * ipstart, int final_level, int final_gid,
		  int total_levels, map_gnode ** ext_map, int only_free_gnode,
		  inet_prefix * new_ip, int my_family)
{
	int i, e, x, level, levels;
	int gid[total_levels];
	quadro_group qg;

	setzero(new_ip, sizeof(inet_prefix));

	if (!ipstart || final_level == total_levels) {
		u_int idata[MAX_IP_INT] = { 0, 0, 0, 0 };

		for (;;) {
			/*
			 * Let's choose a completely random ip.
			 */
			levels = total_levels;
			if (my_family == AF_INET)
				idata[0] = rand();
			else {
				idata[0] = rand();
				idata[1] = rand();
				idata[2] = rand();
				idata[3] = rand();
			}

			inet_setip(new_ip, idata, my_family);

			if (!inet_validate_ip(*new_ip))
				break;
		}
		return 0;
	}

	/*
	 * We can choose only a random ip which is inside the final_gid.
	 * `final_gid' is a gnode of the `final_level' level.
	 * `final_level' has its `ipstart'; with it we determine
	 * its higher levels.
	 * The work is done in this way:
	 *   - ipstart is splitted in gnode_ids and they are placed in qg.gid.
	 *   - The final_level gid is set to `final_gid'.
	 *   - The gids of levels lower than `final_level' are chosen
	 *     randomly.
	 *   - The gids of levels higher than `final_level' are set to the
	 *     gids of qg.gid[x >= final_level].
	 * - The ipstart is recomposed from the gids.
	 */
	levels = final_level;
	iptoquadg(*ipstart, ext_map, &qg, QUADG_GID);
	gid[levels] = final_gid;
	for (i = final_level + 1; i < total_levels; i++)
		gid[i] = qg.gid[i];

	/* Change the gids if some of them point to full gnodes */
	free_gids(&qg, final_level + 1, ext_map, 0);

	/*
	 * Now we choose random gids for each level so we'll have a random ip
	 * with gidtoipstart();
	 */
	for (level = levels - 1; level >= 0; level--) {
		gid[level] = rand_range(0, MAXGROUPNODE - 1);

		if (level && only_free_gnode) {
			/*
			 * We have to be sure that we're not picking a gnode
			 * already used in the ext_map. Generally when we hook
			 * we have loaded the old ext_map, so skipping the
			 * taken gnodes we increase the possibility to create a
			 * brand new, and not already used, gnode.
			 */
			if (!(ext_map[_EL(level)][gid[level]].flags & GMAP_VOID)) {

				/* Take a random position and loop trough the
				 * map */
				i = rand_range(0, MAXGROUPNODE - 1);

				for (x = 0, e = i; e < MAXGROUPNODE; e++) {
					if (is_group_invalid(gid, e, level, my_family))
						continue;

					if (ext_map[_EL(level)][e].flags & GMAP_VOID) {
						gid[level] = e;
						x = 1;
						break;
					}
				}
				if (!x) {
					for (x = 0; i >= 0; i--) {
						if (is_group_invalid(gid, i, level, my_family))
							continue;

						if (ext_map[_EL(level)][i].flags & GMAP_VOID) {
							gid[level] = i;
							x = 1;
							break;
						}
					}
				}
				if (!x)
					/* not a single free gnode was found */
					return -1;
			}
		}
	}

	/*
	 * Ok, we've set the gids of each level so we recompose them in the
	 * new_ip.
	 */
	gidtoipstart(gid, total_levels, total_levels, my_family, new_ip);

	return 0;
}
예제 #11
0
파일: gmap.c 프로젝트: Netsukuku/netsukuku
/*
 * increment_gids
 *
 * It increments the members of the `qg'->gid array until all its
 * gids point to gnodes present in the ext_map, which don't have
 * a particular gnode->flag or node->flag set.
 *
 * In order to verify that a gnode doesn't have the flag set the
 * `is_gnode_flag_set' function is called, the same is done for the nodes with
 * the `is_node_flag_set' function.
 * `is_gnode_flag_set' returns 1 if the flag is set.
 *
 * increment_gids() starts from the qg->gid[`level'] member and finishes to
 * qg->gid[qg->levels-1].
 * If all the gids point to gnodes, which have the gnode->flag set, -1 is
 * returned.
 * It's assumed that `ext_map' and `int_map' are the maps relative to the
 * `qg' quadro_group.
 */
int
increment_gids(quadro_group * qg, int level, map_gnode ** ext_map,
			   map_node * int_map,
			   int (*is_gnode_flag_set) (map_gnode * gnode),
			   int (*is_node_flag_set) (map_node * node))
{
	int g, groups, gid, i, e = 0, family;

	if (level >= qg->levels)
		return -1;

	family = qg->ipstart[level].family;

	g = level == qg->levels ? 0 : qg->gid[level];
	groups = get_groups(qg->levels, level);
	gid = qg->gid[level];

	if ((!level && !is_node_flag_set(&int_map[gid])) ||
		(level && is_gnode_flag_set(&ext_map[_EL(level)][g]))) {

		/*
		 * find a gid in this `level' which isn't full
		 */
		for (i = 0, e = 0; i < groups; i++) {
			qg->gid[level] = (gid + i) % groups;

			if (is_group_invalid(qg->gid, qg->gid[level], level, family))
				continue;

			if ((!level && is_node_flag_set(&int_map[qg->gid[level]])) ||
				(level
				 &&
				 !is_gnode_flag_set(&ext_map[_EL(level)][qg->gid[level]])))
			{
				e = 1;
				break;
			}
		}

		/*
		 * not a single free gid was found
		 */
		if (!e) {
			g = level + 1 == qg->levels ? 0 : qg->gid[level + 1];

			if ((is_gmap_full_flag_set == is_gnode_flag_set) &&
				!(ext_map[_EL(level + 1)][g].flags & GMAP_FULL)) {
				/*
				 * There is a logical contradiction here:
				 * we didn't find any free (g)nodes in this
				 * level, but the upper gnode at level+1,
				 * which is the parent of this level, isn't
				 * marked as full! So what's happening here?
				 * Ignore this absurd and mark it as full -_-
				 */
				ext_map[_EL(level + 1)][g].flags |= GMAP_FULL;
				debug(DBG_NORMAL, ERROR_MSG "logical "
					  "contradiction detected", ERROR_POS);
			}

			/*
			 * Recurse by leveling up
			 */
			if (!increment_gids(qg, level + 1, ext_map, int_map,
								is_gnode_flag_set, is_node_flag_set))
				/*
				 * We changed one of our upper gid, we can
				 * retake the old gid we had at this `level'
				 */
				qg->gid[level] = gid;
			else
				/*
				 * It's all full!
				 */
				return -1;
		}
	}

	return 0;
}
예제 #12
0
/*
 * radar_update_map
 *
 * it updates the int_map and the ext_map if any bnodes are found.
 * Note that the rnodes in the map are held in a different way. First of all the qspn
 * is not applied to them (we already know how to reach them ;) and they have only
 * one rnode... ME. So me.cur_node->r_node[x].r_node->r_node[0] == me.cur_node.
 * Gotcha?
 */
void
radar_update_map(void)
{
    struct qspn_buffer *qb;
    struct radar_queue *rq;
    ext_rnode_cache *erc;
    map_gnode *gnode = 0;
    map_node *node, *root_node;
    map_rnode rnn, *new_root_rnode;
    ext_rnode *e_rnode;

    int i, diff, rnode_pos;
    u_char rnode_added[MAX_LEVELS / 8], rnode_deleted[MAX_LEVELS / 8];
    int level, external_node, total_levels, root_node_pos, node_update;
    void *void_map;
    const char *ntop;
    char updated_rnodes, routes_update, devs_update;

    updated_rnodes = routes_update = devs_update = 0;
    setzero(rnode_added, sizeof(rnode_added));
    setzero(rnode_deleted, sizeof(rnode_deleted));

    /**
     * Let's consider all our rnodes void, in this way we'll know what
     * rnodes will remain void after the update.
     */
    for (i = 0; i < me.cur_node->links; i++) {
        node = (map_node *) me.cur_node->r_node[i].r_node;
        node->flags |= MAP_VOID | MAP_UPDATE;
    }
    /**/ rq = radar_q;
    list_for(rq) {
        if (!rq->node)
            continue;
        if (!(me.cur_node->flags & MAP_HNODE) && (rq->flags & MAP_HNODE))
            continue;

        /*
         * We need to know if it is a node which is not in the gnode
         * where we are (external_rnode).
         */
        if ((int) rq->node == RADQ_EXT_RNODE) {
            external_node = 1;
            total_levels = rq->quadg.levels;
        } else {
            external_node = 0;
            total_levels = 1;
        }

        for (level = total_levels - 1; level >= 0; level--) {
            qspn_set_map_vars(level, 0, &root_node, &root_node_pos, 0);
            node_update = devs_update = 0;

            if (!level) {
                void_map = me.int_map;
                node = rq->node;
            } else {
                /* Skip the levels where the ext_rnode belongs
                 * to our same gids */
                if (!quadg_gids_cmp(rq->quadg, me.cur_quadg, level))
                    continue;

                /* Update only the gnodes which belongs to
                 * our same gid of the upper level, because
                 * we don't keep the internal info of the
                 * extern gnodes. */
                if ((level < rq->quadg.levels - 1) &&
                        quadg_gids_cmp(rq->quadg, me.cur_quadg, level + 1)) {
                    rq->quadg.gnode[_EL(level)] = 0;
                    continue;
                }

                /* Ehi, we are a bnode */
                root_node->flags |= MAP_BNODE;
                me.cur_node->flags |= MAP_BNODE;

                void_map = me.ext_map;
                gnode = rq->quadg.gnode[_EL(level)];
                node = &gnode->g;
            }

            if (external_node && !level && me.cur_erc_counter) {
                erc = e_rnode_find(me.cur_erc, &rq->quadg, 0);
                if (!erc)
                    rnode_pos = -1;
                else {
                    rnode_pos = erc->rnode_pos;
                    node = (map_node *) erc->e;
                }
            } else
                rnode_pos = rnode_find(root_node, node);

            if (rnode_pos == -1) {	/* W00t, we've found a new rnode! */
                node_update = 1;
                rnode_pos = root_node->links;

                ntop = inet_to_str(rq->quadg.ipstart[level]);
                if (server_opt.dbg_lvl || !level)
                    loginfo
                    ("Radar: New node found: %s, ext: %d, level: %d",
                     ntop, external_node, level);

                if (external_node && !level) {
                    /*
                     * If this node we are processing is external, at level 0,
                     * in the root_node's rnodes we add a rnode which point
                     * to a ext_rnode struct.
                     */

                    setzero(&rnn, sizeof(map_rnode));
                    e_rnode = xzalloc(sizeof(ext_rnode));

                    memcpy(&e_rnode->quadg, &rq->quadg,
                           sizeof(quadro_group));
                    e_rnode->node.flags =
                        MAP_BNODE | MAP_GNODE | MAP_RNODE | MAP_ERNODE;
                    rnn.r_node = (int *) e_rnode;
                    node = rq->node = &e_rnode->node;
                    new_root_rnode = &rnn;

                    /* Update the external_rnode_cache list */
                    e_rnode_add(&me.cur_erc, e_rnode, rnode_pos,
                                &me.cur_erc_counter);
                } else {
                    /*We purge all the node's rnodes. */
                    rnode_destroy(node);

                    /*
                     * This node has only one rnode,
                     * and that is the root_node.
                     */
                    setzero(&rnn, sizeof(map_rnode));
                    rnn.r_node = (int *) root_node;
                    rnode_add(node, &rnn);

                    /* It is a border node */
                    if (level)
                        node->flags |= MAP_BNODE | MAP_GNODE;
                    node->flags |= MAP_RNODE;

                    /*
                     * Fill the rnode to be added in the
                     * root_node.
                     */
                    setzero(&rnn, sizeof(map_rnode));
                    rnn.r_node = (int *) node;
                    new_root_rnode = &rnn;
                }

                /*
                 * The new node is added in the root_node's
                 * rnodes.
                 */
                rnode_add(root_node, new_root_rnode);


                /* Update the qspn_buffer */
                if (!external_node || level) {
                    qb = xzalloc(sizeof(struct qspn_buffer));
                    qb->rnode = node;
                    qspn_b[level] = list_add(qspn_b[level], qb);

                    send_qspn_now[level] = 1;
                }

                /* If the new rnode wasn't present in the map,
                 * then it is also a new node in the map, so
                 * update the seeds counter too */
                if (!level && !external_node && (node->flags & MAP_VOID)) {
                    gnode_inc_seeds(&me.cur_quadg, level);
                    qspn_inc_gcount(qspn_gnode_count, level + 1, 1);
                }

                SET_BIT(rnode_added, level);
            } else {
                /*
                 * Nah, We have the node in the map. Let's see if
                 * its rtt is changed
                 */

                if (!send_qspn_now[level] && node->links) {
                    diff = abs(root_node->r_node[rnode_pos].trtt -
                               MILLISEC(rq->final_rtt));
                    if (diff >= RTT_DELTA) {
                        node_update = 1;
                        send_qspn_now[level] = 1;
                        debug(DBG_NOISE, "node %s rtt changed, diff: %d",
                              inet_to_str(rq->ip), diff);
                    }
                }
            }

            /* Restore the flags */
            if (level)
                gnode->flags &= ~GMAP_VOID;
            node->flags &= ~MAP_VOID & ~MAP_UPDATE & ~QSPN_OLD;


            /*
             * Update the devices list of the rnode
             */
            if (!level) {
                devs_update = rnl_update_devs(&rlist, &rlist_counter,
                                              node, rq->dev, rq->dev_n);
                if (devs_update)
                    routes_update++;
            }


            /* Nothing is really changed */
            if (!node_update)
                continue;

            /* Update the rtt */
            root_node->r_node[rnode_pos].trtt = MILLISEC(rq->final_rtt);

            /* Bnode map stuff */
            if (external_node && level) {
                /*
                 * All the root_node bnodes which are in the
                 * bmaps of level smaller than `level' points to
                 * the same gnode which is rq->quadg.gnode[_EL(level-1+1)].
                 * This is because the inferior levels cannot
                 * have knowledge about the bordering gnode
                 * which is in an upper level, but it's necessary that
                 * they know which who the root_node borders on,
                 * so the get_route algorithm can descend to
                 * the inferior levels and it will still know
                 * what is the border node which is linked
                 * to the target gnode.
                 */
                for (i = 0; i < level; i++)
                    radar_update_bmap(rq, i, level - 1);
                send_qspn_now[level - 1] = 1;
            }

            if (node_update || devs_update)
                node->flags |= MAP_UPDATE;

        }						/*for(level=0, ...) */

        updated_rnodes++;
    }							/*list_for(rq) */

    /* Burn the deads */
    if (updated_rnodes < me.cur_node->links)
        radar_remove_old_rnodes((char *) rnode_deleted);

    /* <<keep your room tidy... order, ORDER>> */
    if (!is_bufzero(rnode_added, sizeof(rnode_added)) ||
            !is_bufzero(rnode_deleted, sizeof(rnode_deleted))) {

        /***
         * qsort the rnodes of me.cur_node and me.cur_quadg comparing
         * their trtt */
        rnode_trtt_order(me.cur_node);

        for (i = 1; i < me.cur_quadg.levels; i++)
            if (TEST_BIT(rnode_added, i) || TEST_BIT(rnode_deleted, i))
                rnode_trtt_order(&me.cur_quadg.gnode[_EL(i)]->g);
        /**/
        /* adjust the rnode_pos variables in the ext_rnode_cache list */
        erc_reorder_rnodepos(&me.cur_erc, &me.cur_erc_counter,
                             me.cur_node);
    }

    /* Give a refresh to the kernel */
    if ((!is_bufzero(rnode_added, sizeof(rnode_added)) ||
            routes_update) && !(me.cur_node->flags & MAP_HNODE))
        rt_rnodes_update(1);
}
예제 #13
0
/*
 * radar_remove_old_rnodes
 *
 * It removes all the old rnodes ^_- It store in rnode_delete[level] the number
 * of deleted rnodes. This function is used by radar_update_map
 */
int
radar_remove_old_rnodes(char *rnode_deleted)
{
    map_node *node, *root_node, *broot_node;
    map_gnode *gnode;
    map_bnode *bnode;
    ext_rnode *e_rnode = 0;
    ext_rnode_cache *erc;
    struct qspn_buffer *qb;
    struct rnode_list *rnl;
    int i, e, node_pos, bm, rnode_pos, bnode_rnode_pos, root_node_pos;
    int broot_node_pos;
    int level, blevel, external_node, total_levels, first_level;
    void *void_map, *void_gnode;

    if (!me.cur_node->links)
        return 0;

    for (i = 0; i < me.cur_node->links; i++) {
        node = (map_node *) me.cur_node->r_node[i].r_node;

        if (!(node->flags & MAP_VOID))
            /* The rnode is not really dead! */
            continue;

        if (node->flags & MAP_ERNODE) {
            e_rnode = (ext_rnode *) node;
            external_node = 1;
            total_levels = e_rnode->quadg.levels;
            first_level = 1;
            quadg_setflags(&e_rnode->quadg, MAP_VOID);
        } else {
            external_node = 0;
            total_levels = 1;
            first_level = 0;
        }

        for (level = first_level; level < total_levels; level++) {
            qspn_set_map_vars(level, 0, &root_node, &root_node_pos, 0);
            blevel = level - 1;

            /* delete the rnode from the rnode_list */
            rnl = rnl_find_node(rlist, node);
            rnl_del(&rlist, &rlist_counter, rnl, 1);

            /*
             * Just delete it from all the maps.
             */

            if (!level && !external_node) {
                void_map = me.int_map;
                node_pos = pos_from_node(node, me.int_map);
                rnode_pos = i;

                debug(DBG_NORMAL, "radar: The node %d is dead", node_pos);

                /* delete it from the int_map and update the gcount */
                map_node_del(node);
                qspn_dec_gcount((int *) qspn_gnode_count, level + 1, 1);

                /* delete the route */
                rt_update_node(0, node, 0, 0, 0, level);

                send_qspn_now[level] = 1;
            } else {
                void_map = me.ext_map;
                gnode = e_rnode->quadg.gnode[_EL(level)];

                /** delete the direct route to the ext_node */
                if (level == 1)
                    rt_update_node(&e_rnode->quadg.ipstart[0],
                                   e_rnode, 0, 0, 0, /*level=0 */ 0);
                /**/ void_gnode = (void *) gnode;
                if (!void_gnode)
                    continue;

                node_pos = pos_from_gnode(gnode, me.ext_map[_EL(level)]);
                rnode_pos = g_rnode_find((map_gnode *) root_node, gnode);

                debug(DBG_NORMAL, "The ext_node (gid %d, lvl %d) is"
                      " dead", e_rnode->quadg.gid[level], level);

                /* bnode_map update */
                for (e = 0; blevel >= 0; blevel--) {
                    qspn_set_map_vars(blevel, 0, &broot_node,
                                      &broot_node_pos, 0);
                    bm = map_find_bnode(me.bnode_map[blevel],
                                        me.bmap_nodes[blevel],
                                        broot_node_pos);
                    if (bm == -1)
                        continue;

                    bnode = &me.bnode_map[blevel][bm];
                    bnode_rnode_pos = rnode_find(bnode,
                                                 (map_node *) e_rnode->
                                                 quadg.gnode[_EL(level)]);
                    if (bnode_rnode_pos != -1)
                        rnode_del(bnode, bnode_rnode_pos);

                    if (!bnode->links) {
                        me.bnode_map[blevel] =
                            map_bnode_del(me.bnode_map[blevel],
                                          &me.bmap_nodes[blevel], bnode);
                        broot_node->flags &= ~MAP_BNODE;
                    } else
                        e = 1;
                }
                if (!e)			/* We are no more a bnode */
                    me.cur_node->flags &= ~MAP_BNODE;

                /* If we were the only bnode which bordered on
                 * `gnode', delete it from the map */
                if (map_find_bnode_rnode
                        (me.bnode_map[level - 1], me.bmap_nodes[level - 1],
                         gnode) == -1) {
                    qspn_dec_gcount((int *) qspn_gnode_count, level + 1,
                                    gnode->gcount);
                    gmap_node_del(gnode);
                    gnode_dec_seeds(&me.cur_quadg, level);	/* update the seeds */
                }

                /* Delete the entries from the routing table */
                rt_update_node(0, 0, &e_rnode->quadg, 0, 0, level);

                send_qspn_now[level] = 1;
            }

            if (rnode_pos >= 0 && root_node->links > 0)
                rnode_del(root_node, rnode_pos);

            if (!root_node->links) {
                /* We are alone in the dark. Sigh. */
                qspn_time_reset(level, level, FAMILY_LVLS);
            } else if (!external_node)
                erc_update_rnodepos(me.cur_erc, root_node, rnode_pos);

            /* Now we delete it from the qspn_buffer */
            if (qspn_b[level]) {
                qb = qspn_b[level];
                qb = qspn_b_find_rnode(qb, node);
                if (qb)
                    qspn_b[level] = list_del(qspn_b[level], qb);
            }

            SET_BIT(rnode_deleted, level);
        }

        /*
         * Kick out the external_node from the root_node and destroy it
         * from the ext_rnode_cache
         */
        if (external_node) {
            /* external rnode cache update */
            erc = erc_find(me.cur_erc, e_rnode);
            if (erc)
                e_rnode_del(&me.cur_erc, &me.cur_erc_counter, erc);
            rnode_del(me.cur_node, i);
        }

        /* If the rnode we deleted from the root_node was swapped with
         * the last rnodes, we have to inspect again the same
         * root_node->r_node[ `i' ] rnode, because now it is another
         * rnode */
        if (i != (me.cur_node->links + 1) - 1)
            i--;
    }

    if (!me.cur_node->links) {
        /* - Diary -
         * Tue Mar 14 07:29:58 CET 2006
         * Damn! All my rnodes died, I am the last survivor in this
         * great lone land... I have to reset my memory... farewell!
         */
        qspn_reset_counters(FAMILY_LVLS);
    }

    return 0;
}