예제 #1
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);
}
예제 #2
0
int main (int ac, char *av[])
{
    struct idset *ids = NULL;
    struct rnode *n = NULL;

    plan (NO_PLAN);

    if (!(n = rnode_create (0, "0-3")))
        BAIL_OUT ("could not create an rnode object");
    ok (rnode_avail (n) == 4,
        "rnode_avail == 4");

    ok (rnode_alloc (n, 5, &ids) < 0 && errno == ENOSPC,
        "rnode_alloc too many cores returns errno ENOSPC");

    rnode_alloc_and_check (n, 1, "0");
    ok (rnode_avail (n) == 3,
        "rnode_avail == 3");
    rnode_avail_check (n, "1-3");

    rnode_alloc_and_check (n, 1, "1");
    ok (rnode_avail (n) == 2,
        "rnode_avail == 2");
    rnode_avail_check (n, "2-3");

    rnode_alloc_and_check (n, 2, "2-3");
    ok (rnode_avail (n) == 0,
        "rnode_avail == 0");
    rnode_avail_check (n, "");

    ok (rnode_alloc (n, 1, &ids) < 0 && errno == ENOSPC && ids == NULL,
        "rnode_alloc on empty rnode fails with ENOSPC");

    ok (rnode_free (n, "3-4") < 0 && errno == ENOENT,
        "rnode_free with invalid ids fails");
    ok (rnode_avail (n) == 0,
        "rnode_avail still is 0");
    rnode_avail_check (n, "");

    ok (rnode_free (n, "0-1") == 0,
        "rnode_free (0-1) works");
    ok (rnode_avail (n) == 2,
        "rnode_avail now is 2");
    rnode_avail_check (n, "0-1");
    ok (rnode_free (n, "0") < 0 && errno == EEXIST,
        "rnode_free of already available id fails");
    ok (rnode_avail (n) == 2,
        "rnode_avail is still 2");
    ok (rnode_free (n, "3") == 0,
        "rnode_free '3' works");
    rnode_avail_check (n, "0-1,3");

    rnode_alloc_and_check (n, 3, "0-1,3");

    rnode_destroy (n);

    n = rnode_create_count (1, 8);
    if (n == NULL)
        BAIL_OUT ("rnode_create_count failed");
    ok (n->rank == 1, "rnode rank set correctly");
    ok (n != NULL, "rnode_create_count");
    rnode_avail_check (n, "0-7");
    rnode_destroy (n);

    struct idset *idset = idset_decode ("0-3");
    n = rnode_create_idset (3, idset);
    idset_destroy (idset);
    if (n == NULL)
        BAIL_OUT ("rnode_create_idset failed");
    ok (n != NULL, "rnode_create_idset");
    ok (n->rank == 3, "rnode rank set correctly");
    rnode_avail_check (n, "0-3");

    struct idset *alloc = idset_decode ("1,3");
    ok (rnode_alloc_idset (n, alloc) == 0,
        "rnode_alloc_idset (1,3)");
    rnode_avail_check (n, "0,2");
    ok (rnode_alloc_idset (n, alloc) < 0 && errno == EEXIST,
        "rnode_alloc_idset with idset already allocated returns EEXIST");

    ok (rnode_free_idset (n, alloc) == 0,
        "rnode_free_idset (1,3)");
    rnode_avail_check (n, "0-3");

    ok (rnode_free_idset (n, alloc) < 0 && errno == EEXIST,
        "rnode_free_idset with idset already available returns EEXIST");

    idset_destroy (alloc);
    alloc = idset_decode ("4-7");
    ok (rnode_alloc_idset (n, alloc) < 0 && errno == ENOENT,
        "rnode_alloc_idset with invalid ids return ENOENT");
    ok (rnode_free_idset (n, alloc) < 0 && errno == ENOENT,
        "rnode_free_idset with invalid ids return ENOENT");

    idset_destroy (alloc);
    rnode_destroy (n);
    done_testing ();
}