/* \brief 简单协议栈邻居子系统 * * 处理与主机邻接通信的所需的信息 * * \author Lu Qiuwen * \date 2016-10-21 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include enum neigh_state { NEIGH_IN_NONE = 0, NEIGH_IN_COMPLETE = 1, NEIGH_IN_USE = 2, NEIGH_IN_TIMEOUT = 3, NEIGH_IN_DEAD = 4 }; /* Neighbour Table Object Rule */ struct neighbour { /* 链表项 */ TAILQ_ENTRY(neighbour) next; /* IP地址 */ struct in_addr in_addr; /* 目的MAC地址 */ struct ether_addr eth_addr; /* 设备描述符 */ struct sk_dev_info * dev_info; /* 表项状态 */ enum neigh_state state; /* 转入当前状态的时间 */ time_t t_start_state; /* 上次发送ARP请求的时间 */ time_t t_last_request; /* 上次收到ARP应答的时间 */ time_t t_last_update; /* 永久标志位 */ unsigned short en_permanent; }; int neighbour_mamanger_init(struct neighbour_manager * object, const char * symbol, unsigned int max_entries, unsigned short t_timeout, unsigned int t_arp_send) { int ret = 0; char tbsymbol[MR_SYMBOL_MAX]; snprintf(tbsymbol, sizeof(tbsymbol), "NEIGH_%s", symbol); struct rte_hash_parameters hash_params = { .name = tbsymbol, .entries = max_entries, .key_len = sizeof(struct in_addr), .hash_func = NULL, .hash_func_init_val = 0, }; object->table = rte_hash_create(&hash_params); if (unlikely(object->table == NULL)) { MR_LOG(WARNING, STACK, "NeighbourManagerInit," "Cannot create hash table for %s : %s", symbol, __str_errno()); ret = -1; goto errout; } TAILQ_INIT(&object->in_none_list); rte_atomic16_init(&object->in_none_list_len); rte_rwlock_init(&object->rwlock); return 0; errout: if (object->table != NULL) rte_hash_free(object->table); return ret; } int neighbour_mamanger_deinit(struct neighbour_manager * object) { rte_hash_free(object->table); return 0; } static void __change_neigh_state(struct neighbour * neigh, enum neigh_state target_state) { if (target_state != neigh->state) { neigh->state = target_state; neigh->t_start_state = time(NULL); } } static struct neighbour * __neigh_create_and_join_hash(struct neighbour_manager * object, struct in_addr in_addr, struct ether_addr * eth_addr, struct sk_dev_info * devinfo, unsigned short en_permanent) { struct neighbour * neigh = rte_zmalloc(NULL, sizeof(struct neighbour), 0); if (unlikely(neigh == NULL)) { MR_LOG(WARNING, STACK, "Neighbour, Cannot create neigh structure : %s", __str_errno()); return NULL; } neigh->in_addr = in_addr; neigh->dev_info = devinfo; neigh->en_permanent = en_permanent; neigh->t_last_update = 0; neigh->t_last_request = 0; neigh->state = NEIGH_IN_NONE; if(eth_addr != NULL) { ether_addr_copy(eth_addr, &neigh->eth_addr); __change_neigh_state(neigh, NEIGH_IN_USE); } if(en_permanent) { neigh->en_permanent = 1; } hash_sig_t hash = rte_hash_crc(&in_addr, sizeof(in_addr), 0); int ret = rte_hash_add_key_with_hash_data(object->table, &in_addr, hash, neigh); if (unlikely(ret < 0)) { MR_LOG(WARNING, STACK, "Neighbour, Insert neigh to hash table failed : %s", __str_errno()); goto errout; } return neigh; errout: if (neigh) rte_free(neigh); return NULL; } static void __neigh_update(struct neighbour * neigh, struct in_addr in_addr, struct ether_addr * eth_addr, struct sk_dev_info * devinfo, unsigned short en_permanent) { assert(neigh != NULL); neigh->in_addr = in_addr; neigh->en_permanent = en_permanent; neigh->dev_info = devinfo; if(eth_addr != NULL) { ether_addr_copy(eth_addr, &neigh->eth_addr); __change_neigh_state(neigh, NEIGH_IN_USE); } return; } int neigh_create_or_update(struct neighbour_manager * object, struct in_addr in_addr, struct ether_addr * eth_addr, struct sk_dev_info * devinfo, unsigned short en_permanent) { rte_rwlock_write_lock(&object->rwlock); struct neighbour * neigh = NULL; hash_sig_t hash = rte_hash_crc(&in_addr, sizeof(in_addr), 0); int ret = rte_hash_lookup_with_hash_data(object->table, &in_addr, hash, (void **)&neigh); if (ret < 0) { neigh = __neigh_create_and_join_hash(object, in_addr, eth_addr, devinfo, en_permanent); } else { __neigh_update(neigh, in_addr, eth_addr, devinfo, en_permanent); } if (unlikely(neigh == NULL)) return -1; if (neigh->state == NEIGH_IN_NONE) { TAILQ_INSERT_TAIL(&object->in_none_list, neigh, next); rte_atomic16_inc(&object->in_none_list_len); } ret = 0; goto exit; exit: rte_rwlock_write_unlock(&object->rwlock); return ret; } int neigh_delete(struct neighbour_manager * object, struct in_addr in_addr) { rte_rwlock_write_lock(&object->rwlock); struct neighbour * neigh = NULL; hash_sig_t hash = rte_hash_crc(&in_addr, sizeof(in_addr), 0); int ret = rte_hash_lookup_with_hash_data(object->table, &in_addr, hash, (void **)&neigh); if (ret < 0) goto exit; // 当处于IN_NONE状态时,从IN_NONE列表中移除 if (neigh->state == NEIGH_IN_NONE) { TAILQ_REMOVE(&object->in_none_list,neigh, next); rte_atomic16_dec(&object->in_none_list_len); } rte_hash_del_key_with_hash(object->table, &in_addr, hash); rte_free(neigh); ret = 0; goto exit; exit: rte_rwlock_write_unlock(&object->rwlock); return ret; } int neigh_query(struct neighbour_manager * object, struct in_addr in_addr, struct ether_addr * out_ether_addr, struct sk_dev_info ** out_dev_info) { struct neighbour * neigh = NULL; rte_rwlock_read_lock(&object->rwlock); hash_sig_t hash = rte_hash_crc(&in_addr, sizeof(in_addr), 0); int ret = rte_hash_lookup_with_hash_data(object->table, &in_addr, hash, (void **)&neigh); // 没查到 if (ret < 0) goto exit; // 以下状态信息不全,无法对外提供查询 if (neigh->state == NEIGH_IN_NONE || neigh->state == NEIGH_IN_COMPLETE || neigh->state == NEIGH_IN_DEAD) { ret = -EFAULT; goto exit; } ether_addr_copy(&neigh->eth_addr, out_ether_addr); *out_dev_info = neigh->dev_info; ret = 0; goto exit; exit: rte_rwlock_read_unlock(&object->rwlock); return ret; } static void __neigh_handle_in_no_queue(struct sk_app_instance * app_instance, thread_id_t sid, struct neighbour_manager * object) { if (rte_atomic16_read(&object->in_none_list_len) == 0) return; rte_rwlock_write_lock(&object->rwlock); struct neighbour * neigh_iter; struct sk_dev_desc * dev_desc; // 对每一个在In-None列表中的Neigh,发ARP请求。 TAILQ_FOREACH(neigh_iter, &object->in_none_list, next) { dev_desc = sk_device_desc_lookup(app_instance, neigh_iter->dev_info->symbol); assert(dev_desc != NULL); protocol_serv_arp_request_send(dev_desc, sid, neigh_iter->in_addr); // 处理完毕,移除这一项,因哈希表中还有引用,不释放空间 TAILQ_REMOVE(&object->in_none_list, neigh_iter, next); rte_atomic16_dec(&object->in_none_list_len); } // In-None列表应当为空,数量计数应当为0 assert(rte_atomic16_read(&object->in_none_list_len) == 0); rte_rwlock_write_unlock(&object->rwlock); } void neighbour_manager_loop_entry(struct sk_app_instance * app_instance, thread_id_t sid, struct neighbour_manager * object) { __neigh_handle_in_no_queue(app_instance, sid, object); }