void ci_netif_filter_for_each_match(ci_netif* ni, unsigned laddr, unsigned lport, unsigned raddr, unsigned rport, unsigned protocol, int intf_i, int vlan, int (*callback)(ci_sock_cmn*, void*), void* callback_arg, ci_uint32* hash_out) { ci_netif_filter_table* tbl; unsigned hash1, hash2 = 0; unsigned first; tbl = ni->filter_table; if( hash_out != NULL ) *hash_out = tcp_hash3(tbl, laddr, lport, raddr, rport, protocol); hash1 = tcp_hash1(tbl, laddr, lport, raddr, rport, protocol); first = hash1; LOG_NV(log("%s: %s %s:%u->%s:%u hash=%u:%u at=%u", __FUNCTION__, CI_IP_PROTOCOL_STR(protocol), ip_addr_str(laddr), (unsigned) CI_BSWAP_BE16(lport), ip_addr_str(raddr), (unsigned) CI_BSWAP_BE16(rport), first, tcp_hash2(tbl, laddr, lport, raddr, rport, protocol), hash1)); while( 1 ) { int id = tbl->table[hash1].id; if(CI_LIKELY( id >= 0 )) { ci_sock_cmn* s = ID_TO_SOCK(ni, id); if( ((laddr - tbl->table[hash1].laddr) | (lport - sock_lport_be16(s) ) | (raddr - sock_raddr_be32(s) ) | (rport - sock_rport_be16(s) ) | (protocol - sock_protocol(s) )) == 0 ) if(CI_LIKELY( (s->rx_bind2dev_ifindex == CI_IFID_BAD || ci_sock_intf_check(ni, s, intf_i, vlan)) )) if( callback(s, callback_arg) != 0 ) return; } else if( id == EMPTY ) break; /* We defer calculating hash2 until it's needed, just to make the fast ** case that little bit faster. */ if( hash1 == first ) hash2 = tcp_hash2(tbl, laddr, lport, raddr, rport, protocol); hash1 = (hash1 + hash2) & tbl->table_size_mask; if( hash1 == first ) { LOG_NV(ci_log(FN_FMT "ITERATE FULL %s:%u->%s:%u hash=%u:%u", FN_PRI_ARGS(ni), ip_addr_str(laddr), lport, ip_addr_str(raddr), rport, hash1, hash2)); break; } } }
ci_fd_t ci_udp_ep_ctor(citp_socket* ep, ci_netif* netif, int domain, int type) { ci_udp_state* us; ci_fd_t fd; VERB( log(LPFIN "ctor( )" ) ); ci_assert(ep); ci_assert(netif); ci_netif_lock(netif); us = ci_udp_get_state_buf(netif); if (!us) { ci_netif_unlock(netif); LOG_E(ci_log("%s: [%d] out of socket buffers", __FUNCTION__,NI_ID(netif))); return -ENOMEM; } /* It's required to set protocol before ci_tcp_helper_sock_attach() * since it's used to determine if TCP or UDP file operations should be * attached to the file descriptor in kernel. */ sock_protocol(&us->s) = IPPROTO_UDP; /* NB: this attach will close the os_sock_fd */ fd = ci_tcp_helper_sock_attach(ci_netif_get_driver_handle(netif), SC_SP(&us->s), domain, type); if( fd < 0 ) { if( fd == -EAFNOSUPPORT ) LOG_U(ci_log("%s: ci_tcp_helper_sock_attach (domain=%d, type=%d) " "failed %d", __FUNCTION__, domain, type, fd)); else LOG_E(ci_log("%s: ci_tcp_helper_sock_attach (domain=%d, type=%d) " "failed %d", __FUNCTION__, domain, type, fd)); ci_netif_unlock(netif); return fd; } ci_assert(~us->s.b.sb_aflags & CI_SB_AFLAG_ORPHAN); us->s.rx_errno = 0; us->s.tx_errno = 0; us->s.so_error = 0; us->s.cp.sock_cp_flags |= OO_SCP_UDP_WILD; ep->s = &us->s; ep->netif = netif; CHECK_UEP(ep); ci_netif_unlock(netif); return fd; }
int ci_netif_filter_lookup(ci_netif* netif, unsigned laddr, unsigned lport, unsigned raddr, unsigned rport, unsigned protocol) { unsigned hash1, hash2 = 0; ci_netif_filter_table* tbl; unsigned first; ci_assert(netif); ci_assert(ci_netif_is_locked(netif)); ci_assert(netif->filter_table); tbl = netif->filter_table; hash1 = tcp_hash1(tbl, laddr, lport, raddr, rport, protocol); first = hash1; LOG_NV(log("tbl_lookup: %s %s:%u->%s:%u hash=%u:%u at=%u", CI_IP_PROTOCOL_STR(protocol), ip_addr_str(laddr), (unsigned) CI_BSWAP_BE16(lport), ip_addr_str(raddr), (unsigned) CI_BSWAP_BE16(rport), first, tcp_hash2(tbl, laddr, lport, raddr, rport, protocol), hash1)); while( 1 ) { int id = tbl->table[hash1].id; if( CI_LIKELY(id >= 0) ) { ci_sock_cmn* s = ID_TO_SOCK(netif, id); if( ((laddr - tbl->table[hash1].laddr) | (lport - sock_lport_be16(s) ) | (raddr - sock_raddr_be32(s) ) | (rport - sock_rport_be16(s) ) | (protocol - sock_protocol(s) )) == 0 ) return hash1; } if( id == EMPTY ) break; /* We defer calculating hash2 until it's needed, just to make the fast * case that little bit faster. */ if( hash1 == first ) hash2 = tcp_hash2(tbl, laddr, lport, raddr, rport, protocol); hash1 = (hash1 + hash2) & tbl->table_size_mask; if( hash1 == first ) { LOG_E(ci_log(FN_FMT "ERROR: LOOP %s:%u->%s:%u hash=%u:%u", FN_PRI_ARGS(netif), ip_addr_str(laddr), lport, ip_addr_str(raddr), rport, hash1, hash2)); return -ELOOP; } } return -ENOENT; }
void ci_netif_filter_dump(ci_netif* ni) { int id; unsigned i; ci_netif_filter_table* tbl; ci_assert(ni); tbl = ni->filter_table; log("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); #if CI_CFG_STATS_NETIF log(FN_FMT "size=%d n_entries=%i n_slots=%i max=%i mean=%i", FN_PRI_ARGS(ni), tbl->table_size_mask + 1, ni->state->stats.table_n_entries, ni->state->stats.table_n_slots, ni->state->stats.table_max_hops, ni->state->stats.table_mean_hops); #endif for( i = 0; i <= tbl->table_size_mask; ++i ) { id = tbl->table[i].id; if( CI_LIKELY(id >= 0) ) { ci_sock_cmn* s = ID_TO_SOCK(ni, id); unsigned laddr = tbl->table[i].laddr; int lport = sock_lport_be16(s); unsigned raddr = sock_raddr_be32(s); int rport = sock_rport_be16(s); int protocol = sock_protocol(s); unsigned hash1 = tcp_hash1(tbl, laddr, lport, raddr, rport, protocol); unsigned hash2 = tcp_hash2(tbl, laddr, lport, raddr, rport, protocol); log("%010d id=%-10d rt_ct=%d %s "CI_IP_PRINTF_FORMAT":%d " CI_IP_PRINTF_FORMAT":%d %010d:%010d", i, id, tbl->table[i].route_count, CI_IP_PROTOCOL_STR(protocol), CI_IP_PRINTF_ARGS(&laddr), CI_BSWAP_BE16(lport), CI_IP_PRINTF_ARGS(&raddr), CI_BSWAP_BE16(rport), hash1, hash2); } } log("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); }
static int efab_tcp_helper_get_info(ci_private_t *unused, void *arg) { ci_netif_info_t *info = arg; int index, rc=0; tcp_helper_resource_t* thr = NULL; ci_netif* ni = NULL; int flags = EFAB_THR_TABLE_LOOKUP_CHECK_USER | EFAB_THR_TABLE_LOOKUP_NO_WARN; #if CI_CFG_EFAB_EPLOCK_RECORD_CONTENTIONS int j; eplock_resource_t* eplock_rs; #endif info->ni_exists = 0; info->ni_no_perms_exists = 0; if( info->ni_orphan ) { flags |= EFAB_THR_TABLE_LOOKUP_NO_UL; info->ni_orphan = 0; } rc = efab_thr_table_lookup(NULL, info->ni_index, flags, &thr); if( rc == 0 ) { info->ni_exists = 1; info->ni_orphan = (thr->k_ref_count & TCP_HELPER_K_RC_NO_USERLAND); ni = &thr->netif; info->mmap_bytes = thr->mem_mmap_bytes; info->k_ref_count = thr->k_ref_count; info->rs_ref_count = oo_atomic_read(&thr->ref_count); memcpy(info->ni_name, ni->state->name, sizeof(ni->state->name)); } else if( rc == -EACCES ) { info->ni_no_perms_id = info->ni_index; if( efab_thr_get_inaccessible_stack_info(info->ni_index, &info->ni_no_perms_uid, &info->ni_no_perms_euid, &info->ni_no_perms_share_with, info->ni_no_perms_name) == 0 ) info->ni_no_perms_exists = 1; } /* sub-ops that do not need the netif to exist */ if( info->ni_subop == CI_DBG_NETIF_INFO_GET_NEXT_NETIF ) { tcp_helper_resource_t* next_thr; info->u.ni_next_ni.index = -1; for( index = info->ni_index + 1; index < 10000 /* FIXME: magic! */; ++index ) { rc = efab_thr_table_lookup(NULL, index, flags, &next_thr); if( rc == 0 ) { if( next_thr->k_ref_count & TCP_HELPER_K_RC_NO_USERLAND ) efab_tcp_helper_k_ref_count_dec(next_thr, 1); else efab_thr_release(next_thr); info->u.ni_next_ni.index = index; break; } if( rc == -EACCES ) { info->u.ni_next_ni.index = index; break; } } rc = 0; } else if( info->ni_subop == CI_DBG_NETIF_INFO_NOOP ) { rc = 0; } if (!info->ni_exists) return 0; /* sub-ops that need the netif to exist */ switch (info->ni_subop) { case CI_DBG_NETIF_INFO_GET_ENDPOINT_STATE: index = info->u.ni_endpoint.index; info->u.ni_endpoint.max = thr->netif.ep_tbl_n; if ((index < 0) || (index >= (int)thr->netif.ep_tbl_n)) { info->u.ni_endpoint.state = CI_TCP_STATE_FREE; } else { citp_waitable_obj* wo = ID_TO_WAITABLE_OBJ(ni, index); info->u.ni_endpoint.state = wo->waitable.state; if( wo->waitable.state == CI_TCP_STATE_UDP ) { ci_udp_state* us = &wo->udp; info->u.ni_endpoint.udpstate = us->udpflags; info->u.ni_endpoint.rx_pkt_ul = us->recv_q.pkts_delivered; info->u.ni_endpoint.rx_pkt_kn = us->stats.n_rx_os; } else if( wo->waitable.state & CI_TCP_STATE_TCP_CONN ) { ci_tcp_state* ts = &wo->tcp; info->u.ni_endpoint.tx_pkts_max = ts->so_sndbuf_pkts; info->u.ni_endpoint.tx_pkts_num = ts->send.num; } if( wo->waitable.state & CI_TCP_STATE_SOCKET ) { ci_sock_cmn* s = &wo->sock; info->u.ni_endpoint.protocol = (int) sock_protocol(s); info->u.ni_endpoint.laddr = sock_laddr_be32(s); info->u.ni_endpoint.lport = (int) sock_lport_be16(s); info->u.ni_endpoint.raddr = sock_raddr_be32(s); info->u.ni_endpoint.rport = (int) sock_rport_be16(s); } } break; case CI_DBG_NETIF_INFO_GET_NEXT_NETIF: /* If the current netif is found, we need to succeed */ break; case CI_DBG_NETIF_INFO_NOOP: /* Always succeeds, rc already set */ break; default: rc = -EINVAL; break; } if( thr ) { /* Lookup needs a matching efab_thr_release() in case of ordinary * stack but just a ref_count_dec in case of orphan */ if( thr->k_ref_count & TCP_HELPER_K_RC_NO_USERLAND ) efab_tcp_helper_k_ref_count_dec(thr, 1); else efab_thr_release(thr); } return rc; }