/* * 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); }
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 (); }