123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422 |
- /* 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.
- *
- * --
- * rehook.c:
- * This code manages the rehook of gnodes, the challenges that must be solved
- * and generated in order to prove the number of nodes present in a gnode.
- */
-
- #include "includes.h"
-
- #include "common.h"
- #include "hash.h"
- #include "llist.c"
- #include "libnetlink.h"
- #include "ll_map.h"
- #include "inet.h"
- #include "if.h"
- #include "krnl_route.h"
- #include "endianness.h"
- #include "bmap.h"
- #include "route.h"
- #include "iptunnel.h"
- #include "request.h"
- #include "pkts.h"
- #include "tracer.h"
- #include "qspn.h"
- #include "andna.h"
- #include "hook.h"
- #include "rehook.h"
- #include "radar.h"
- #include "netsukuku.h"
- #include "common.h"
-
- /*
- * rehook_argv: argv for the new_rehook_thread thread
- */
- struct rehook_argv {
- int gid;
- map_gnode *gnode;
- int level;
- int gnode_count;
- };
-
- pthread_attr_t new_rehook_thread_attr;
-
- void
- rehook_init(void)
- {
- total_rehooks = 0;
- last_instance_rehook = 0;
- rehook_mutex = 0;
-
- pthread_attr_init(&new_rehook_thread_attr);
- pthread_attr_setdetachstate(&new_rehook_thread_attr,
- PTHREAD_CREATE_DETACHED);
- }
-
- /*
- * rehook_compute_new_gnode: computes the IP which shall be used to create a
- * new gnode if the we cannot rehook to any gnode.
- * The computed ip is stored in `new_ip'.
- * `old_ip' is the IP we used before the rehook was launched.
- */
- void
- rehook_compute_new_gnode(inet_prefix * old_ip, inet_prefix * new_ip,
- int hook_level)
- {
- quadro_group qg;
- int hash_gid;
-
- iptoquadg(*old_ip, me.ext_map, &qg, QUADG_GID);
-
- /*
- * Hash our gids starting from the `hook_level' level,
- * then xor the bytes of the hash merging them in a single byte.
- */
- hash_gid = fnv_32_buf(&qg.gid[hook_level],
- (FAMILY_LVLS - hook_level), FNV1_32_INIT);
- qg.gid[hook_level] = xor_int(hash_gid);
-
- /* Be sure to choose VOID gnodes */
- void_gids(&qg, hook_level, me.ext_map, me.int_map);
-
- /* Save the new ip in `new_ip' */
- gidtoipstart(qg.gid, FAMILY_LVLS, FAMILY_LVLS, my_family, new_ip);
- }
-
- int
- send_challenge(int gnode, int level, int gnode_count)
- {
- /* TODO ^_^ */
-
- return 0;
- }
-
-
- /*
- * update_rehook_time: updates the rehook_time counter. If the limits are
- * reached -1 is returned and nothing is changed, otherwise 0 is the returned
- * value. (See rehook.h for more info on the limits).
- */
- int
- update_rehook_time(int level)
- {
- time_t cur_t, sec_elapsed;
-
- cur_t = time(0);
- sec_elapsed = (cur_t - last_instance_rehook);
-
- if (total_rehooks && sec_elapsed > REHOOK_INSTANCE_TIME(level)) {
- /*
- * REHOOK_INSTANCE_TIME expired: we cannot take anymore rehooks
- * in this instance.
- */
-
- if (sec_elapsed > REHOOK_WAIT_TIME(level))
- /* REHOOK_WAIT_TIME expired: a new instance begins */
- total_rehooks = 0;
- else
- return -1;
- }
-
- if (total_rehooks > REHOOK_PER_INSTANCE)
- /* Too many rehooks in this instance */
- return -1;
-
- if (!total_rehooks)
- last_instance_rehook = cur_t;
- total_rehooks++;
-
- return 0;
- }
-
- /*
- * wait_new_rnode: it waits until we have a rnode, which belongs to
- * `rargv->gnode' or to `rk_gnode_ip'.
- */
- void
- wait_new_rnode(struct rehook_argv *rargv)
- {
- ext_rnode_cache *erc;
- int gid_a[MAX_LEVELS], gid_b[MAX_LEVELS];
- int e = 0, i, retries;
-
- debug(DBG_NOISE,
- "wait_new_rnode: waiting the %d rnode %d lvl appearance",
- rargv->gid, rargv->level);
-
- memcpy(&gid_a, me.cur_quadg.gid, sizeof(me.cur_quadg.gid));
- gid_a[rargv->level] = rargv->gid;
-
- iptogids(&rk_gnode_ip, gid_b, me.cur_quadg.levels);
-
- retries = QSPN_WAIT_ROUND_LVL(rargv->level) / MAX_RADAR_WAIT + 1;
- for (i = 0; i < retries; i++) {
- e = 0;
- erc = me.cur_erc;
- list_for(erc) {
- if (!gids_cmp(erc->e->quadg.gid, gid_a, rargv->level,
- me.cur_quadg.levels)) {
- e = 1;
- break;
- }
-
- if (!gids_cmp(erc->e->quadg.gid, gid_b, rargv->level,
- me.cur_quadg.levels)) {
- e = 1;
- break;
- }
- }
- if (e) {
- debug(DBG_NOISE, "wait_new_rnode: %d rnode %d "
- "lvl found", rargv->gid, rargv->level);
- return;
- }
- radar_wait_new_scan();
- }
-
- debug(DBG_NORMAL,
- "wait_new_rnode: not found! Anyway, trying to rehook");
- }
-
- /*
- * new_rehook_thread: a thread for each rehook() is necessary because the
- * rehook has to run without stopping the calling thread.
- */
- void *
- new_rehook_thread(void *r)
- {
- struct rehook_argv *rargv = (struct rehook_argv *) r;
- ext_rnode_cache *erc;
- map_node *root_node;
- map_gnode *gnode;
- int i;
-
- /*
- * Send a new challenge if `CHALLENGE_THRESHOLD' was exceeded
- */
- if (rargv->level && rargv->gnode_count >= CHALLENGE_THRESHOLD)
- if (send_challenge(rargv->gid, rargv->level, rargv->gnode_count))
- /* Challenge failed, do not rehook */
- goto finish;
-
- /* Store in `rk_gnode_ip' our new gnode ip to be used when the rehook
- * fails, just in case */
- rehook_compute_new_gnode(&me.cur_ip, &rk_gnode_ip, rargv->level);
-
- #if 0
- /* Before rehooking, at least one qspn_round has to be completed */
- while (!me.cur_qspn_id[rargv->level])
- usleep(505050);
- #endif
-
- /* Wait the radar_daemon, we need it up & running */
- while (!radar_daemon_ctl)
- usleep(505050);
-
- if (rargv->gid != me.cur_quadg.gid[rargv->level])
- wait_new_rnode(rargv);
-
- /*
- * Rehook now
- */
- rehook(rargv->gnode, rargv->level);
-
- if (rargv->level) {
- /* Mark all the gnodes we border on as HOOKED, in this way
- * we won't try to rehook each time */
- erc = me.cur_erc;
- list_for(erc) {
- if (!erc->e)
- continue;
- if (erc->e->quadg.gnode[_EL(rargv->level)])
- erc->e->quadg.gnode[_EL(rargv->level)]->flags |=
- GMAP_HGNODE;
- }
-
- /* Mark also rargv->gnode */
- rargv->gnode->flags |= GMAP_HGNODE;
-
- /* Mark all the gnodes which are rnodes of our gnode of the
- * `rargv->level' level. */
- root_node = &me.cur_quadg.gnode[_EL(rargv->level)]->g;
- for (i = 0; i < root_node->links; i++) {
- gnode = (map_gnode *) root_node->r_node[i].r_node;
- gnode->g.flags |= GMAP_HGNODE;
- }
- }
-
- finish:
- xfree(rargv);
- rehook_mutex = 0;
- return 0;
- }
-
- /*
- * new_rehook: takes in exam the `gnode' composed by `gnode_count'# nodes, which
- * is at level `level' and which has a gnode id equal to `gid'.
- * When `level' is 0, `gnode' is a node and gnode_count isn't considered.
- */
- void
- new_rehook(map_gnode * gnode, int gid, int level, int gnode_count)
- {
- struct rehook_argv *rargv;
- pthread_t thread;
-
- if (restricted_mode && level == me.cur_quadg.levels - 1 &&
- gid != me.cur_quadg.gid[level])
- /* We are in restricted mode. The `gnode' is too restricted.
- * Our restricted class isn't the same of `gnode', therefore
- * do nothing. The restricted class are immutable. */
- return;
-
- if (!level && gid != me.cur_quadg.gid[level])
- /* We rehook at level 0 only if we have the same gid of
- * another node, so in this case we don't have to rehook */
- return;
- else if (level) {
- if (gnode_count < qspn_gnode_count[_EL(level)])
- /* We have more nodes, we don't have to rehook! */
- return;
- else if (gnode_count == qspn_gnode_count[_EL(level)] &&
- gid < me.cur_quadg.gid[level])
- /* We have the same number of nodes, but `gid' is
- * smaller than our gnode id, so it must rehook,
- * not us */
- return;
- else if (gnode_count == qspn_gnode_count[_EL(level)] &&
- gid == me.cur_quadg.gid[level] &&
- gnode->g.flags & MAP_RNODE)
- /* If `gnode' has our same gid and it is our rnode,
- * it's alright. */
- return;
- }
-
- if (gid == me.cur_quadg.gid[level]) {
- /*
- * There is a (g)node which has our same gid, hence we rehook
- * to our gnode of the higher level (hopefully we get a new
- * gid).
- */
- if (level + 1 < me.cur_quadg.levels)
- level++;
- gid = me.cur_quadg.gid[level];
- gnode = me.cur_quadg.gnode[_EL(level)];
-
- } else if (level && gnode->flags & GMAP_HGNODE)
- /* `gnode' is marked as HOOKED, return. */
- return;
-
- debug(DBG_NORMAL,
- "new_rehook: me.gid %d, gnode %d, level %d, gnode_count %d, "
- "qspn_gcount %d, our rnode: %d", me.cur_quadg.gid[level], gid,
- level, gnode_count, qspn_gnode_count[_EL(level)],
- gnode->g.flags & MAP_RNODE);
-
- /*
- * Update the rehook time and let's see if we can take this new rehook
- */
- if (update_rehook_time(level)) {
- debug(DBG_SOFT, "new_rehook: we have to wait before accepting "
- "another rehook");
- return;
- }
-
- if (rehook_mutex)
- return;
- rehook_mutex = 1;
-
- rargv = xmalloc(sizeof(struct rehook_argv));
- rargv->gid = gid;
- rargv->gnode = gnode;
- rargv->level = level;
- rargv->gnode_count = gnode_count;
- pthread_create(&thread, &new_rehook_thread_attr, new_rehook_thread,
- (void *) rargv);
- }
-
- /*
- * rehook: resets all the global variables set during the last hook/rehook,
- * and launches the netsukuku_hook() again. All the previous map will be lost
- * if not saved, the IP will also change.
- * During the rehook, the radar_daemon and andna_maintain_hnames_active() are
- * stopped.
- * After the rehook, the andna_hook will be launched and the stopped daemon
- * reactivated.
- */
- int
- rehook(map_gnode * hook_gnode, int hook_level)
- {
- int ret = 0;
-
- /* Stop the radar_daemon */
- radar_daemon_ctl = 0;
-
- /* Wait the end of the current radar */
- radar_wait_new_scan();
-
- /* Mark ourself as hooking, this will stop
- * andna_maintain_hnames_active() daemon too. */
- me.cur_node->flags |= MAP_HNODE;
-
- /*
- * Reset the rnode list and external rnode list
- */
- rnl_reset(&rlist, &rlist_counter);
- e_rnode_free(&me.cur_erc, &me.cur_erc_counter);
-
- if (restricted_mode) {
- /*
- * Delete all the tunnels, and reset all the structs used by
- * igs.c
- */
-
- del_all_tunnel_ifs(0, 0, 0, NTK_TUNL_PREFIX);
- reset_igw_nexthop(multigw_nh);
- reset_igws(me.igws, me.igws_counter, me.cur_quadg.levels);
- reset_igw_rules();
- free_my_igws(&me.my_igws);
- }
-
- /* Andna reset */
- if (!server_opt.disable_andna) {
- andna_cache_destroy();
- counter_c_destroy();
- rh_cache_flush();
- }
-
- /* Clear the uptime */
- me.uptime = time(0);
-
- /*
- * * * REHOOK! * * *
- */
- netsukuku_hook(hook_gnode, hook_level);
-
- /* Restart the radar daemon */
- radar_daemon_ctl = 1;
-
- if (!server_opt.disable_andna) {
- /* Rehook in ANDNA and update our hostnames */
- andna_hook(0);
- andna_update_hnames(0);
- }
-
- return ret;
- }
|