static inline struct pf_cn * lookup_cn_rule(struct hash *h, const char *cn, const uint32_t cn_hash) { struct hash_element *he = hash_lookup_fast(h, hash_bucket(h, cn_hash), cn, cn_hash); if (he) { return (struct pf_cn *) he->value; } else { return NULL; } }
/** * ovs_vport_locate - find a port that has already been created * * @name: name of port to find * * Must be called with RTNL or RCU read lock. */ struct vport *ovs_vport_locate(struct net *net, const char *name) { struct hlist_head *bucket = hash_bucket(net, name); struct vport *vport; struct hlist_node *node; hlist_for_each_entry_rcu(vport, node, bucket, hash_node) if (!strcmp(name, vport->ops->get_name(vport)) && net_eq(ovs_dp_get_net(vport->dp), net)) return vport; return NULL; }
static void update_peers(struct net *net, const char *name, struct vport *vport) { struct hlist_head *bucket = hash_bucket(net, name); struct patch_vport *peer_vport; struct hlist_node *node; hlist_for_each_entry(peer_vport, node, bucket, hash_node) { struct vport *curr_vport = vport_from_priv(peer_vport); const char *peer_name; peer_name = rtnl_dereference(peer_vport->patchconf)->peer_name; if (!strcmp(peer_name, name) && net_eq(ovs_dp_get_net(curr_vport->dp), net)) rcu_assign_pointer(peer_vport->peer, vport); } }
static struct vport *patch_create(const struct vport_parms *parms) { struct vport *vport; struct patch_vport *patch_vport; const char *peer_name; struct patch_config *patchconf; struct net *net = ovs_dp_get_net(parms->dp); int err; vport = ovs_vport_alloc(sizeof(struct patch_vport), &ovs_patch_vport_ops, parms); if (IS_ERR(vport)) { err = PTR_ERR(vport); goto error; } patch_vport = patch_vport_priv(vport); strcpy(patch_vport->name, parms->name); patchconf = kmalloc(sizeof(struct patch_config), GFP_KERNEL); if (!patchconf) { err = -ENOMEM; goto error_free_vport; } err = patch_set_config(vport, parms->options, patchconf); if (err) goto error_free_patchconf; random_ether_addr(patchconf->eth_addr); rcu_assign_pointer(patch_vport->patchconf, patchconf); peer_name = patchconf->peer_name; hlist_add_head(&patch_vport->hash_node, hash_bucket(net, peer_name)); rcu_assign_pointer(patch_vport->peer, ovs_vport_locate(net, peer_name)); update_peers(net, patch_vport->name, vport); return vport; error_free_patchconf: kfree(patchconf); error_free_vport: ovs_vport_free(vport); error: return ERR_PTR(err); }
HASHDATA * hash_insert( struct hash * hp, OBJECT * key, int * found ) { ITEM * i; unsigned int keyval = hash_keyval( key ); #ifdef HASH_DEBUG_PROFILE profile_frame prof[1]; if ( DEBUG_PROFILE ) profile_enter( 0, prof ); #endif if ( !hp->items.more ) hashrehash( hp ); i = hash_search( hp, keyval, key, 0 ); if ( i ) { *found = 1; } else { ITEM * * base = hash_bucket( hp, keyval ); /* try to grab one from the free list */ if ( hp->items.free ) { i = hp->items.free; hp->items.free = i->hdr.next; assert( hash_item_key( i ) == 0 ); } else { i = (ITEM *)hp->items.next; hp->items.next += hp->items.size; } hp->items.more--; i->hdr.next = *base; *base = i; *found = 0; } #ifdef HASH_DEBUG_PROFILE if ( DEBUG_PROFILE ) profile_exit( prof ); #endif return hash_item_data( i ); }
static struct multi_instance * multi_create_instance_tcp(struct multi_context *m) { struct gc_arena gc = gc_new(); struct multi_instance *mi = NULL; struct hash *hash = m->hash; mi = multi_create_instance(m, NULL); if (mi) { struct hash_element *he; const uint32_t hv = hash_value(hash, &mi->real); struct hash_bucket *bucket = hash_bucket(hash, hv); he = hash_lookup_fast(hash, bucket, &mi->real, hv); if (he) { struct multi_instance *oldmi = (struct multi_instance *) he->value; msg(D_MULTI_LOW, "MULTI TCP: new incoming client address matches existing client address -- new client takes precedence"); oldmi->did_real_hash = false; multi_close_instance(m, oldmi, false); he->key = &mi->real; he->value = mi; } else { hash_add_fast(hash, bucket, &mi->real, hv, mi); } mi->did_real_hash = true; } #ifdef ENABLE_DEBUG if (mi) { dmsg(D_MULTI_DEBUG, "MULTI TCP: instance added: %s", mroute_addr_print(&mi->real, &gc)); } else { dmsg(D_MULTI_DEBUG, "MULTI TCP: new client instance failed"); } #endif gc_free(&gc); ASSERT(!(mi && mi->halt)); return mi; }
static ITEM * hash_search( struct hash * hp, unsigned int keyval, OBJECT * keydata, ITEM * * previous ) { ITEM * i = *hash_bucket( hp, keyval ); ITEM * p = 0; for ( ; i; i = i->next ) { if ( object_equal( hash_item_key( i ), keydata ) ) { if ( previous ) *previous = p; return i; } p = i; } return 0; }
struct multi_instance * multi_get_create_instance_udp (struct multi_context *m) { struct gc_arena gc = gc_new (); struct mroute_addr real; struct multi_instance *mi = NULL; struct hash *hash = m->hash; if (mroute_extract_openvpn_sockaddr (&real, &m->top.c2.from.dest, true)) { struct hash_element *he; const uint32_t hv = hash_value (hash, &real); struct hash_bucket *bucket = hash_bucket (hash, hv); uint8_t* ptr = BPTR(&m->top.c2.buf); uint8_t op = ptr[0] >> P_OPCODE_SHIFT; uint32_t sess_id; bool session_forged = false; if (op == P_DATA_V2) { sess_id = (*(uint32_t*)ptr) >> 8; if ((sess_id < m->max_clients) && (m->instances[sess_id])) { mi = m->instances[sess_id]; if (!link_socket_actual_match(&mi->context.c2.from, &m->top.c2.from)) { msg(D_MULTI_MEDIUM, "floating detected from %s to %s", print_link_socket_actual (&mi->context.c2.from, &gc), print_link_socket_actual (&m->top.c2.from, &gc)); /* session-id is not trusted, so check hmac */ session_forged = !(crypto_test_hmac(&m->top.c2.buf, &mi->context.c2.crypto_options)); if (session_forged) { mi = NULL; msg (D_MULTI_MEDIUM, "hmac verification failed, session forge detected!"); } else { update_floated(m, mi, real, hv); } } } } else {
/** * ovs_vport_add - add vport device (for kernel callers) * * @parms: Information about new vport. * * Creates a new vport with the specified configuration (which is dependent on * device type). ovs_mutex must be held. * * 创建并初始化 vport: * 1. 参数校验 * * 确保 params->type 在 vport_ops_list(保持所有 vport->ops->type) 中, 返回类型为 params->type 的 ops * * 确保 params->type->ops->owner 的模块是 alive 的 * 2. 调用 internal_dev_create(params) 创建 vport, 初始化各个数据成员及私有数据 * 3. 将 vport->hash_node 加入 dev_table * * 注: 没有初始化的 err_stats, detach_list */ struct vport *ovs_vport_add(const struct vport_parms *parms) { struct vport_ops *ops; struct vport *vport; //确保 params->type 在 vport_ops_list(保持所有 vport->ops->type) 中, 返回 //类型为 params->type 的 ops ops = ovs_vport_lookup(parms); if (ops) { struct hlist_head *bucket; //ops->owner 的模块是 alive 的 if (!try_module_get(ops->owner)) return ERR_PTR(-EAFNOSUPPORT); //调用 internal_dev_create 创建 vport, 初始化各个数据成员及私有数据 vport = ops->create(parms); if (IS_ERR(vport)) { // ops->owener->refcnt = ops->owener->refcnt - 1 module_put(ops->owner); return vport; } bucket = hash_bucket(ovs_dp_get_net(vport->dp), vport->ops->get_name(vport)); hlist_add_head_rcu(&vport->hash_node, bucket); return vport; } /* Unlock to attempt module load and return -EAGAIN if load * was successful as we need to restart the port addition * workflow. */ ovs_unlock(); request_module("vport-type-%d", parms->type); ovs_lock(); if (!ovs_vport_lookup(parms)) return ERR_PTR(-EAFNOSUPPORT); else return ERR_PTR(-EAGAIN); }
/** * ovs_vport_add - add vport device (for kernel callers) * * @parms: Information about new vport. * * Creates a new vport with the specified configuration (which is dependent on * device type). ovs_mutex must be held. */ struct vport *ovs_vport_add(const struct vport_parms *parms) { struct vport_ops *ops; struct vport *vport; ops = ovs_vport_lookup(parms); if (ops) { struct hlist_head *bucket; if (!try_module_get(ops->owner)) return ERR_PTR(-EAFNOSUPPORT); vport = ops->create(parms); if (IS_ERR(vport)) { module_put(ops->owner); return vport; } bucket = hash_bucket(ovs_dp_get_net(vport->dp), ovs_vport_name(vport)); hlist_add_head_rcu(&vport->hash_node, bucket); return vport; } if (parms->type == OVS_VPORT_TYPE_GRE && !compat_gre_loaded) { pr_warn("GRE protocol already loaded!\n"); return ERR_PTR(-EAFNOSUPPORT); } /* Unlock to attempt module load and return -EAGAIN if load * was successful as we need to restart the port addition * workflow. */ ovs_unlock(); request_module("vport-type-%d", parms->type); ovs_lock(); if (!ovs_vport_lookup(parms)) return ERR_PTR(-EAFNOSUPPORT); else return ERR_PTR(-EAGAIN); }
+ union { + struct item * next; + /* + * Some architectures have 32bit pointers but 64bit time_t (as used + * in file_info_t), and require natural alignement of data. + * Since we offset an aligned pointer by sizeof(hashhdr) in + * hash_item_data(item), we may cause misalignement if we do not + * make sure that sizeof(hashhdr) is properly aligned. + */ + time_t aligner; /* unused dummy for alignement */ + } h; }; typedef struct item @@ -106,7 +116,7 @@ static ITEM * hash_search( ITEM * i = *hash_bucket(hp,keyval); ITEM * p = 0; - for ( ; i; i = i->hdr.next ) + for ( ; i; i = i->hdr.h.next ) { if ( object_equal( hash_item_key( i ), keydata ) ) { @@ -153,7 +163,7 @@ HASHDATA * hash_insert( struct hash * hp if ( hp->items.free ) { i = hp->items.free; - hp->items.free = i->hdr.next; + hp->items.free = i->hdr.h.next; assert( hash_item_key( i ) == 0 ); }
struct multi_instance * multi_get_create_instance_udp (struct multi_context *m) { struct gc_arena gc = gc_new (); struct mroute_addr real; struct multi_instance *mi = NULL; struct hash *hash = m->hash; if (mroute_extract_openvpn_sockaddr (&real, &m->top.c2.from.dest, true)) { struct hash_element *he; const uint32_t hv = hash_value (hash, &real); struct hash_bucket *bucket = hash_bucket (hash, hv); he = hash_lookup_fast (hash, bucket, &real, hv); if (he) { mi = (struct multi_instance *) he->value; } else { if (!m->top.c2.tls_auth_standalone || tls_pre_decrypt_lite (m->top.c2.tls_auth_standalone, &m->top.c2.from, &m->top.c2.buf)) { if (frequency_limit_event_allowed (m->new_connection_limiter)) { mi = multi_create_instance (m, &real); if (mi) { hash_add_fast (hash, bucket, &mi->real, hv, mi); mi->did_real_hash = true; } } else { msg (D_MULTI_ERRORS, "MULTI: Connection from %s would exceed new connection frequency limit as controlled by --connect-freq", mroute_addr_print (&real, &gc)); } } } #ifdef ENABLE_DEBUG if (check_debug_level (D_MULTI_DEBUG)) { const char *status; if (he && mi) status = "[succeeded]"; else if (!he && mi) status = "[created]"; else status = "[failed]"; dmsg (D_MULTI_DEBUG, "GET INST BY REAL: %s %s", mroute_addr_print (&real, &gc), status); } #endif } gc_free (&gc); ASSERT (!(mi && mi->halt)); return mi; }
int hashitem( register struct hash *hp, HASHDATA **data, int enter ) { register ITEM *i; OBJECT *b = (*data)->key; unsigned int keyval = hash_keyval(b); #ifdef HASH_DEBUG_PROFILE profile_frame prof[1]; if ( DEBUG_PROFILE ) profile_enter( 0, prof ); #endif if ( enter && !hp->items.more ) hashrehash( hp ); if ( !enter && !hp->items.nel ) { #ifdef HASH_DEBUG_PROFILE if ( DEBUG_PROFILE ) profile_exit( prof ); #endif return 0; } i = hash_search( hp, keyval, (*data)->key, 0 ); if (i) { *data = &i->data; #ifdef HASH_DEBUG_PROFILE if ( DEBUG_PROFILE ) profile_exit( prof ); #endif return !0; } if ( enter ) { ITEM * * base = hash_bucket(hp,keyval); /* try to grab one from the free list */ if ( hp->items.free ) { i = hp->items.free; hp->items.free = i->hdr.next; assert( i->data.key == 0 ); } else { i = (ITEM *)hp->items.next; hp->items.next += hp->items.size; } hp->items.more--; memcpy( (char *)&i->data, (char *)*data, hp->items.datalen ); i->hdr.next = *base; *base = i; *data = &i->data; #ifdef OPT_BOEHM_GC if (sizeof(HASHDATA) == hp->items.datalen) { GC_REGISTER_FINALIZER(i->data.key,&hash_mem_finalizer,hp,0,0); } #endif } #ifdef HASH_DEBUG_PROFILE if ( DEBUG_PROFILE ) profile_exit( prof ); #endif return 0; }
struct multi_instance * multi_get_create_instance_udp (struct multi_context *m, bool *floated) { struct gc_arena gc = gc_new (); struct mroute_addr real; struct multi_instance *mi = NULL; struct hash *hash = m->hash; if (mroute_extract_openvpn_sockaddr (&real, &m->top.c2.from.dest, true) && m->top.c2.buf.len > 0) { struct hash_element *he; const uint32_t hv = hash_value (hash, &real); struct hash_bucket *bucket = hash_bucket (hash, hv); uint8_t* ptr = BPTR(&m->top.c2.buf); uint8_t op = ptr[0] >> P_OPCODE_SHIFT; /* make sure buffer has enough length to read opcode (1 byte) and peer-id (3 bytes) */ if (op == P_DATA_V2 && m->top.c2.buf.len >= (1 + 3)) { uint32_t peer_id = ntohl(*(uint32_t*)ptr) & 0xFFFFFF; if ((peer_id < m->max_clients) && (m->instances[peer_id])) { mi = m->instances[peer_id]; *floated = !link_socket_actual_match(&mi->context.c2.from, &m->top.c2.from); if (*floated) { /* reset prefix, since here we are not sure peer is the one it claims to be */ ungenerate_prefix(mi); msg (D_MULTI_ERRORS, "Untrusted peer %" PRIu32 " wants to float to %s", peer_id, mroute_addr_print (&real, &gc)); } } } else { he = hash_lookup_fast (hash, bucket, &real, hv); if (he) { mi = (struct multi_instance *) he->value; } } if (!mi) { if (!m->top.c2.tls_auth_standalone || tls_pre_decrypt_lite (m->top.c2.tls_auth_standalone, &m->top.c2.from, &m->top.c2.buf)) { if (frequency_limit_event_allowed (m->new_connection_limiter)) { mi = multi_create_instance (m, &real); if (mi) { int i; hash_add_fast (hash, bucket, &mi->real, hv, mi); mi->did_real_hash = true; for (i = 0; i < m->max_clients; ++i) { if (!m->instances[i]) { mi->context.c2.tls_multi->peer_id = i; m->instances[i] = mi; break; } } /* should not really end up here, since multi_create_instance returns null * if amount of clients exceeds max_clients */ ASSERT(i < m->max_clients); } } else { msg (D_MULTI_ERRORS, "MULTI: Connection from %s would exceed new connection frequency limit as controlled by --connect-freq", mroute_addr_print (&real, &gc)); } } } #ifdef ENABLE_DEBUG if (check_debug_level (D_MULTI_DEBUG)) { const char *status = mi ? "[ok]" : "[failed]"; dmsg (D_MULTI_DEBUG, "GET INST BY REAL: %s %s", mroute_addr_print (&real, &gc), status); } #endif } gc_free (&gc); ASSERT (!(mi && mi->halt)); return mi; }
my_name = sym_extract_name(name); #ifdef SYM_MULTIPLE_NAME_SPACES my_name_space = name_space; #endif #ifdef SYM_DEEP_BINDING if (scope_pointer != SYM_ROOT_SCOPE) #ifdef SYM_SCOPE_STACK_DEPTH *ptr = scope_stack + scope_pointer; #else *ptr = &scope_pointer->linked_list; #endif else #endif /* Find hash bucket */ *ptr = hash_bucket(); /* Look for binding in bucket */ return search_linked_list(ptr); } /****************************************************************************/ /* */ /* P U B L I C S T U F F */ /* */ /****************************************************************************/ /* Create new symbol table entry */ /* Return either SYMTAB_OK, SYMTAB_DUPLICATE or SYMTAB_NO_MEMORY */ #ifdef SYM_MULTIPLE_NAME_SPACES