📄 tunnel.c
字号:
DEBUG(DEBUG_FLAG, "Marking tunnel %s to %s removable\n", data->device, inet_ntoa(data->dst_addr)); data->do_not_remove = 0; } return 1;}/** * tunnel_set_remove_all: * @hash: The pointer to the tunnel hash table * @dst_addr: The remote end-point of the tunnels to be modified * * Mark all the tunnels to @dst_addr removable. */void tunnel_set_remove_all(HASH *hash, struct in_addr dst_addr){ hashtable_iterator(hash, set_remove_iter, &dst_addr);}/* Help function for tunnel_connect() */static int new_table_to_ha(char *dev){ int i; i = 0; while (i < MAX_TABLE_COUNT && DYN_BIT(table_numbers, i)) i++; if (i >= MAX_TABLE_COUNT) { LOG2(LOG_WARNING, "tunnel_connect: " "no space for a new routing table\n"); return -1; } if (dyn_ip_route_add_table(dev, i, NULL) != 0) { LOG2(LOG_WARNING, "tunnel_connect: " "dyn_ip_route_add_table failed\n"); return -1; } DEBUG(DEBUG_FLAG, "\treserving to HA table %i\n", i); DYN_SET_BIT(table_numbers, i); debug_print_bitfield("TABLE_NUMBERS", table_numbers, MAX_TABLE_INTS); return i;}/* Help function for tunnel_connect() */static int new_table_to_mn(char *dev){ int i; i = 0; while (i < MAX_TABLE_COUNT && DYN_BIT(table_numbers, i)) i++; if (i >= MAX_TABLE_COUNT) { DEBUG(DEBUG_FLAG, "\tno space for new routing table\n"); return -1; } DEBUG(DEBUG_FLAG, "\treserving to MN table %i\n", i); DYN_SET_BIT(table_numbers, i); debug_print_bitfield("TABLE_NUMBERS", table_numbers, MAX_TABLE_INTS); /* add default blackhole */ if (dyn_ip_route_add_blackhole(i) != 0) { LOG2(LOG_WARNING, "tunnel_connect: Could not " "initialize a routing table for MNs\n"); return -1; } /* add rule for MN host routes */ if (dyn_ip_rule_add_table(NULL, NULL, i, dev) != 0) { LOG2(LOG_WARNING, "tunnel_connect: " "could not add rule for the MN routing table\n"); return -1; } return i;}/** * tunnel_connect: * @up: The pointer to the upwards tunnel device * @down: The pointer to the downwards tunnel device * @mn_addr: The home address of the mobile node * @reverse: 1 = add reverse tunneling rule, 0 = no reverse tunneling * @force_route_dev: a device name forced to the routing entry (to be used * with FA decaps and encapsulating delivery) or * %NULL to not force the device name * @force_reverse_dev: a device name forced to the reverse routing rule (to be * used with MN decaps without encapsulating delivery) or * %NULL to not force the device name * * Connect two tunnels (@up and @down) to each other, i.e., set the routing * entries and rules to forward the packets between these tunnels for the * given @mn_addr. * * Returns: -1 on failure or 0 on success */inttunnel_connect(TUNNEL *up, TUNNEL *down, struct in_addr mn_addr, int reverse, char *force_route_dev, char *force_reverse_dev){ struct delayed_connection_deletion *tmp; char *dev; if (up == NULL || down == NULL) return -1; DEBUG(DEBUG_FLAG, "tunnel_connect: %s => %s\n", down->device, up->device); down->direction = TUNNEL_DOWN; up->direction = TUNNEL_UP; if (up->to_ha_table_id == -1) { /* make a default route to a tunnel device to a new routing * table */ up->to_ha_table_id = new_table_to_ha(up->device); if (up->to_ha_table_id < 0) return -1; } if (up->to_mn_table_id == -1) { /* make the routing table for MN host routes */ up->to_mn_table_id = new_table_to_mn(up->device); if (up->to_mn_table_id < 0) return -1; } /* add host route to the MN */ dev = (force_route_dev && force_route_dev[0] != '\0') ? force_route_dev : down->device; DEBUG(DEBUG_FLAG, "\troute replace: addr=%s, dev=%s, table=%i\n", inet_ntoa(mn_addr), dev, up->to_mn_table_id); if (dyn_ip_route_replace_table(mn_addr, dev, up->to_mn_table_id) == -1) { LOG2(LOG_WARNING, "tunnel_connect: could not add host route to" " the MN\n"); return -1; } /* remove the deletion of the possible replaced routing entry from the * delayed unconnect priority queue */ tmp = delayed; while (tmp != NULL) { if (tmp->delete_route && tmp->mn_addr.s_addr == mn_addr.s_addr && tmp->to_mn_table_id == up->to_mn_table_id) { DEBUG(DEBUG_FLAG, "\tremoved delayed route deletion (addr=%s, " "to_mn_table_id=%i, route_dev=%s, " "reverse_dev=%s\n", inet_ntoa(tmp->mn_addr), tmp->to_mn_table_id, tmp->route_dev, tmp->reverse_dev); tmp->delete_route = 0; } tmp = tmp->next; } if (reverse) { /* set reverse tunnel - use source routing * (MN->HA direction data) */ dev = (force_reverse_dev && force_reverse_dev[0] != '\0') ? force_reverse_dev : down->device; DEBUG(DEBUG_FLAG, "\tdyn_ip_rule_add_table: " "addr=%s, table_id=%i, dev=%s\n", inet_ntoa(mn_addr), up->to_ha_table_id, dev); if (dyn_ip_rule_add_table(&mn_addr, NULL, up->to_ha_table_id, dev) != 0) { DEBUG(DEBUG_FLAG, "\tdyn_ip_rule_add_table failed!\n"); return -1; } } return 0;}/* The local function to remove the real tunnel connection after some delay * (or immediately if the unconnect is forced) */static inttunnel_unconnect_real(struct delayed_connection_deletion *entry){ int ret = 0; if (entry == NULL) return -1; DEBUG(DEBUG_FLAG, "tunnel_unconnect_real - MN=%s, reverse=%i, " "to_ha_table_id=%i, to_mn_table_id=%i, " "route_dev=%s, reverse_dev=%s\n", inet_ntoa(entry->mn_addr), entry->reverse, entry->to_ha_table_id, entry->to_mn_table_id, entry->route_dev, entry->reverse_dev); if (entry->reverse && entry->to_ha_table_id != -1 && dyn_ip_rule_del_table(&entry->mn_addr, NULL, entry->to_ha_table_id, entry->reverse_dev) != 0) { DEBUG(DEBUG_FLAG, "tunnel_unconnect_real: could not remove " "associated rule\n"); ret = -1; } /* remove the host route from to_mn_table_id (down tunnels) */ if (entry->delete_route && entry->to_mn_table_id != -1) { DEBUG(DEBUG_FLAG, "\tdelete route: addr=%s, dev=%s, " "table=%i\n", inet_ntoa(entry->mn_addr), entry->route_dev, entry->to_mn_table_id); } if (entry->delete_route && entry->to_mn_table_id != -1 && dyn_ip_route_del_table(entry->route_dev, entry->to_mn_table_id, &entry->mn_addr) == -1) { LOG2(LOG_WARNING, "tunnel_unconnect_real: could not remove " "host route to the MN\n"); ret = -1; } return ret;}/** * tunnel_unconnect: * @up: The pointer to the upwards tunnel device * @down: The pointer to the downwards tunnel device * @mn_addr: The home address of the mobile node * @reverse: 1 = add reverse tunneling rule, 0 = no reverse tunneling * @force: 0 = delayed unconnect, 1 = forced unconnect * @force_route_dev: a device name forced to the routing entry (to be used * with FA decaps and encapsulating delivery) or * %NULL to not force the device name * @force_reverse_dev: a device name forced to the reverse routing rule (to be * used with MN decaps without encapsulating delivery) or * %NULL to not force the device name * * Unconnect the tunnels connected with tunnel_connect(). * * Returns: -1 on failure or 0 on success */inttunnel_unconnect(TUNNEL *up, TUNNEL *down, struct in_addr mn_addr, int reverse, int force, char *force_route_dev, char *force_reverse_dev){ struct delayed_connection_deletion *entry, *tmp; if (up == NULL || down == NULL) return -1; DEBUG(DEBUG_FLAG, "tunnel_unconnect - up[dev=%s,tables=%i,%i], " "down[dev=%s,tables=%i,%i], MN=%s, reverse=%i, force=%i\n", up->device, up->to_ha_table_id, up->to_mn_table_id, down->device, down->to_ha_table_id, down->to_mn_table_id, inet_ntoa(mn_addr), reverse, force); entry = (struct delayed_connection_deletion *) malloc(sizeof(struct delayed_connection_deletion)); if (entry == NULL) { LOG2(LOG_WARNING, "tunnel_unconnect - out of memory\n"); return -1; } memset(entry, 0, sizeof(struct delayed_connection_deletion)); gettimeofday(&entry->timeout, NULL); entry->timeout.tv_usec += DELAY_UNCONNECTION_USEC; if (entry->timeout.tv_usec > 999999) { entry->timeout.tv_usec += entry->timeout.tv_usec / 1000000; entry->timeout.tv_usec %= 1000000; } entry->mn_addr = mn_addr; entry->reverse = reverse; entry->delete_route = 1; entry->to_ha_table_id = up->to_ha_table_id; entry->to_mn_table_id = up->to_mn_table_id; memcpy(entry->route_dev, (force_route_dev && force_route_dev[0] != '\0') ? force_route_dev : down->device, IFNAMSIZ); memcpy(entry->reverse_dev, (force_reverse_dev && force_reverse_dev[0] != '\0') ? force_reverse_dev : down->device, IFNAMSIZ);#ifdef REMOVE_BINDING_OPTIM /* remove delayed unconnect optimization for comparison measurements */ force = 1;#endif if (force) { int ret = tunnel_unconnect_real(entry); free(entry); return ret; } /* add the entry to the priority queue to be removed after some time */ if (delayed == NULL) { /* first entry in the priority queue */ delayed = entry; return 0; } if (cmp_timeval(&delayed->timeout, &entry->timeout) > 0) { /* replaces the head of the priority queue */ entry->next = delayed; delayed = entry; return 0; } tmp = delayed; while (tmp->next != NULL && cmp_timeval(&tmp->next->timeout, &entry->timeout) <= 0) tmp = tmp->next; entry->next = tmp->next; tmp->next = entry; return 0;}/** * tunnel_check_delayed: * @hash: The pointer to the tunnel hash table * @force: * 0 = do not force the deletion, * 1 = force deletion even if the entries have not timed out yet, * 2 = force only the deletion of not yet timed out connections * * Check and remove the delayed connection and tunnel deletions that have * expired. */voidtunnel_check_delayed(HASH *hash, int force){ static time_t prev_check = 0; struct timeval now; gettimeofday(&now, NULL); /* check delayed priority queue */ while (delayed != NULL && (force || cmp_timeval(&delayed->timeout, &now) <= 0)) { struct delayed_connection_deletion *prev; DEBUG(DEBUG_FLAG, "tunnel_check_delayed - deleting entry - " "now=%li.%li, timeout=%li.%li\n", now.tv_sec, now.tv_usec, delayed->timeout.tv_sec, delayed->timeout.tv_usec); tunnel_unconnect_real(delayed); prev = delayed; delayed = delayed->next; free(prev); } /* check the tunnels if enought time has passed from the previous * check */ if (force != 1 && prev_check <= now.tv_sec && now.tv_sec < prev_check + PURGE_TUNNEL_TIME) return; prev_check = now.tv_sec; hashtable_iterator(hash, check_tunnel, force == 1 ? NULL : &now);}/** * tunnel_delete_ptr: * @data: The pointer to the tunnel entry to be deleted. * @force: 1 = the tunnel will be removed immediately, * 0 = the deletion is delayed * * Remove the given tunnel. * * Returns: -1 on error, 0 if the tunnel was not deleted * (i.e., still in use), 1 if the tunnel was deleted */int tunnel_delete_ptr(TUNNEL *data, int force){ int ret = 1; if (data == NULL) { DEBUG(DEBUG_FLAG, "tunnel_delete_ptr: no such entry\n"); return -1; } DEBUG(DEBUG_FLAG, "tunnel_delete_ptr %s,%i,%i, force=%i\n", inet_ntoa(data->dst_addr), data->type, data->key, force); DEBUG(DEBUG_FLAG, "\treference count: %i => %i\n", data->ref, data->ref - 1); data->ref--; print_tunnel_data(data); if (data->ref > 0) { DEBUG(DEBUG_FLAG, "\ttunnel not deleted\n"); return 0; }#ifdef REMOVE_TUNNEL_OPTIM force = 1;#endif if (force) { ret = tunnel_destroy(data); } else { /* Reference count is zero. Delay tunnel deletion */ gettimeofday(&data->zero_ref_tstamp, NULL); } return ret;}/** * tunnel_delete: * @hash: The pointer to the tunnel hash table * @dst_addr: The remote address of the tunnel * @force: 1 = Remove tunnel immediately if reference count is zero, * 0 = Use delayed tunnel deletion * @type: Tunnel type (IPIP / GRE) * @key: Key for GRE tunnels * * Delete tunnel from the hash table and decrease the tunnel reference count. * If the reference count is zero remove the kernel tunnel device. * * Returns: * 0 Reference count decreased, * 1 The tunnel was destroyed, * -1 Error */inttunnel_delete(HASH *hash, struct in_addr dst_addr, int force, int type, __u32 key){ TUNNEL *data; struct tunnel_key tkey; DEBUG(DEBUG_FLAG, "tunnel_delete %s,%i,%i\n", inet_ntoa(dst_addr), type, key); tkey.dst_addr = dst_addr; tkey.type = type; tkey.key = key; data = (struct tunnel *) hashtable_fetch(hash, hashfunc, &tkey, cmpfunc); return tunnel_delete_ptr(data, force);}/** * tunnel_fetch: * @hash: The pointer to the tunnel hash table * @dst_addr: The remote address ot the tunnel * @type: The tunnel type (#TUNNEL_NO_ENCAPS, #TUNNEL_IPIP, #TUNNEL_GRE) * @key: The key used with the tunnel * * Fetch the tunnel data from the hash table. * * Returns: A pointer to the tunnel entry or NULL on failure */TUNNEL *tunnel_fetch(HASH *hash, struct in_addr dst_addr, int type, __u32 key){ TUNNEL *entry; struct tunnel_key tkey; DEBUG(DEBUG_FLAG, "tunnel_fetch: %s\n", inet_ntoa(dst_addr)); tkey.dst_addr = dst_addr; tkey.type = type; tkey.key = key; entry = (TUNNEL *) hashtable_fetch(hash, hashfunc, &tkey, cmpfunc); if (entry != NULL) print_tunnel_data(entry); else DEBUG(DEBUG_FLAG, "\tno such entry\n"); return entry;}static int find_delayed(struct node *node, void *val){ int *found = (int *) val; TUNNEL *data = (struct tunnel *) node; if (data->ref > 0 || data->do_not_remove) return 1; *found = 1; return 0;}/** * tunnel_delayed_exists: * @hash: The pointer to the tunnel hash table * * Checks whether any delayed deletions exists in the tunnel hash table. * * Returns: 0 = no delayed deletions, 1 = at least one delayed deletion found */inttunnel_delayed_exists(HASH *hash){ int found; if (delayed != NULL) return 1; found = 0; hashtable_iterator(hash, find_delayed, &found); return found;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -