Print this page
dccp: conn_t
*** 65,74 ****
--- 65,76 ----
* ipcl_proto_fanout: IPv4 protocol fanout
* ipcl_proto_fanout_v6: IPv6 protocol fanout
* ipcl_udp_fanout: contains all UDP connections
* ipcl_iptun_fanout: contains all IP tunnel connections
* ipcl_globalhash_fanout: contains all connections
+ *` ipcl_dccp_conn_fanout: contains all DCCP connections in CONNECTED state
+ * ipcl_dccp_bind_fanout: contains all DCCP connections in BOUND state
*
* The ipcl_globalhash_fanout is used for any walkers (like snmp and Clustering)
* which need to view all existing connections.
*
* All tables are protected by per-bucket locks. When both per-bucket lock and
*** 221,230 ****
--- 223,233 ----
* IPCL_TCPCONN indicates a TCP connection
* IPCL_SCTPCONN indicates a SCTP connection
* IPCL_UDPCONN indicates a UDP conn_t.
* IPCL_RAWIPCONN indicates a RAWIP/ICMP conn_t.
* IPCL_RTSCONN indicates a RTS conn_t.
+ * IPCL_DCCPCONN indicates a DCCP conn_t.
* IPCL_IPCCONN indicates all other connections.
*
* void ipcl_conn_destroy(connp)
*
* Destroys the connection state, removes it from the global
*** 255,264 ****
--- 258,268 ----
#include <inet/ip_ire.h>
#include <inet/ip6.h>
#include <inet/ip_ndp.h>
#include <inet/ip_impl.h>
#include <inet/udp_impl.h>
+ #include <inet/dccp_impl.h>
#include <inet/sctp_ip.h>
#include <inet/sctp/sctp_impl.h>
#include <inet/rawip_impl.h>
#include <inet/rts_impl.h>
#include <inet/iptun/iptun_impl.h>
*** 282,291 ****
--- 286,299 ----
/* bind/udp fanout table size */
uint_t ipcl_bind_fanout_size = 512;
uint_t ipcl_udp_fanout_size = 16384;
+ /* Fanout table sizes for dccp */
+ uint_t ipcl_dccp_conn_fanout_size = 512;
+ uint_t ipcl_dccp_bind_fanout_size = 512;
+
/* Raw socket fanout size. Must be a power of 2. */
uint_t ipcl_raw_fanout_size = 256;
/*
* The IPCL_IPTUN_HASH() function works best with a prime table size. We
*** 317,326 ****
--- 325,335 ----
struct kmem_cache *ip_conn_cache;
extern struct kmem_cache *sctp_conn_cache;
struct kmem_cache *udp_conn_cache;
struct kmem_cache *rawip_conn_cache;
struct kmem_cache *rts_conn_cache;
+ struct kmem_cache *dccp_conn_cache;
extern void tcp_timermp_free(tcp_t *);
extern mblk_t *tcp_timermp_alloc(int);
static int ip_conn_constructor(void *, void *, int);
*** 336,345 ****
--- 345,357 ----
static void rawip_conn_destructor(void *, void *);
static int rts_conn_constructor(void *, void *, int);
static void rts_conn_destructor(void *, void *);
+ static int dccp_conn_constructor(void *, void *, int);
+ static void dccp_conn_destructor(void *, void *);
+
/*
* Global (for all stack instances) init routine
*/
void
ipcl_g_init(void)
*** 366,375 ****
--- 378,393 ----
rts_conn_cache = kmem_cache_create("rts_conn_cache",
sizeof (itc_t) + sizeof (rts_t), CACHE_ALIGN_SIZE,
rts_conn_constructor, rts_conn_destructor,
NULL, NULL, NULL, 0);
+
+ /* XXX:DCCP reclaim */
+ dccp_conn_cache = kmem_cache_create("dccp_conn_cache",
+ sizeof (itc_t) + sizeof (dccp_t), CACHE_ALIGN_SIZE,
+ dccp_conn_constructor, dccp_conn_destructor,
+ NULL, NULL, NULL, 0);
}
/*
* ipclassifier intialization routine, sets up hash tables.
*/
*** 408,417 ****
--- 426,437 ----
ipst->ips_ipcl_conn_fanout_size = sizes[16];
}
/* Take values from /etc/system */
ipst->ips_ipcl_bind_fanout_size = ipcl_bind_fanout_size;
+ ipst->ips_ipcl_dccp_conn_fanout_size = ipcl_dccp_conn_fanout_size;
+ ipst->ips_ipcl_dccp_bind_fanout_size = ipcl_dccp_bind_fanout_size;
ipst->ips_ipcl_udp_fanout_size = ipcl_udp_fanout_size;
ipst->ips_ipcl_raw_fanout_size = ipcl_raw_fanout_size;
ipst->ips_ipcl_iptun_fanout_size = ipcl_iptun_fanout_size;
ASSERT(ipst->ips_ipcl_conn_fanout == NULL);
*** 475,494 ****
--- 495,529 ----
sizeof (connf_t) * CONN_G_HASH_SIZE, KM_SLEEP);
for (i = 0; i < CONN_G_HASH_SIZE; i++) {
mutex_init(&ipst->ips_ipcl_globalhash_fanout[i].connf_lock,
NULL, MUTEX_DEFAULT, NULL);
}
+
+ ipst->ips_ipcl_dccp_conn_fanout = kmem_zalloc(
+ ipst->ips_ipcl_dccp_conn_fanout_size * sizeof (connf_t), KM_SLEEP);
+ for (i = 0; i < ipst->ips_ipcl_dccp_conn_fanout_size; i++) {
+ mutex_init(&ipst->ips_ipcl_dccp_conn_fanout[i].connf_lock, NULL,
+ MUTEX_DEFAULT, NULL);
+ }
+
+ ipst->ips_ipcl_dccp_bind_fanout = kmem_zalloc(
+ ipst->ips_ipcl_dccp_bind_fanout_size * sizeof (connf_t), KM_SLEEP);
+ for (i = 0; i < ipst->ips_ipcl_dccp_bind_fanout_size; i++) {
+ mutex_init(&ipst->ips_ipcl_dccp_bind_fanout[i].connf_lock, NULL,
+ MUTEX_DEFAULT, NULL);
+ }
}
void
ipcl_g_destroy(void)
{
kmem_cache_destroy(ip_conn_cache);
kmem_cache_destroy(tcp_conn_cache);
kmem_cache_destroy(udp_conn_cache);
kmem_cache_destroy(rawip_conn_cache);
kmem_cache_destroy(rts_conn_cache);
+ kmem_cache_destroy(dccp_conn_cache);
}
/*
* All user-level and kernel use of the stack must be gone
* by now.
*** 560,569 ****
--- 595,620 ----
}
kmem_free(ipst->ips_ipcl_globalhash_fanout,
sizeof (connf_t) * CONN_G_HASH_SIZE);
ipst->ips_ipcl_globalhash_fanout = NULL;
+ for (i = 0; i < ipst->ips_ipcl_dccp_conn_fanout_size; i++) {
+ ASSERT(ipst->ips_ipcl_dccp_conn_fanout[i].connf_head == NULL);
+ mutex_destroy(&ipst->ips_ipcl_dccp_conn_fanout[i].connf_lock);
+ }
+ kmem_free(ipst->ips_ipcl_dccp_conn_fanout,
+ ipst->ips_ipcl_dccp_conn_fanout_size * sizeof (connf_t));
+ ipst->ips_ipcl_dccp_conn_fanout = NULL;
+
+ for (i = 0; i < ipst->ips_ipcl_dccp_bind_fanout_size; i++) {
+ ASSERT(ipst->ips_ipcl_dccp_bind_fanout[i].connf_head == NULL);
+ mutex_destroy(&ipst->ips_ipcl_dccp_bind_fanout[i].connf_lock);
+ }
+ kmem_free(ipst->ips_ipcl_dccp_bind_fanout,
+ ipst->ips_ipcl_dccp_bind_fanout_size * sizeof (connf_t));
+ ipst->ips_ipcl_dccp_bind_fanout = NULL;
+
ASSERT(ipst->ips_rts_clients->connf_head == NULL);
mutex_destroy(&ipst->ips_rts_clients->connf_lock);
kmem_free(ipst->ips_rts_clients, sizeof (connf_t));
ipst->ips_rts_clients = NULL;
}
*** 608,617 ****
--- 659,672 ----
case IPCL_IPCCONN:
conn_cache = ip_conn_cache;
break;
+ case IPCL_DCCPCONN:
+ conn_cache = dccp_conn_cache;
+ break;
+
default:
connp = NULL;
ASSERT(0);
}
*** 718,727 ****
--- 773,809 ----
ASSERT(ns != NULL);
sctp_free(connp);
return;
}
+ if (connp->conn_flags & IPCL_DCCPCONN) {
+ dccp_t *dccp = connp->conn_dccp;
+
+ cmn_err(CE_NOTE, "ipclassifier: conn_flags DCCP cache_free");
+
+ dccp_free(dccp);
+ mp = dccp->dccp_timercache;
+
+ dccp->dccp_dccps = NULL;
+
+ ipcl_conn_cleanup(connp);
+ connp->conn_flags = IPCL_DCCPCONN;
+ if (ns != NULL) {
+ ASSERT(dccp->dccps == NULL);
+ connp->conn_netstack = NULL;
+ connp->conn_ixa->ixa_ipst = NULL;
+ netstack_rele(ns);
+ }
+
+ bzero(dccp, sizeof (dccp_t));
+
+ dccp->dccp_timercache = mp;
+ dccp->dccp_connp = connp;
+ kmem_cache_free(dccp_conn_cache, connp);
+ return;
+ }
+
ipcl_conn_cleanup(connp);
if (ns != NULL) {
connp->conn_netstack = NULL;
connp->conn_ixa->ixa_ipst = NULL;
netstack_rele(ns);
*** 1234,1245 ****
--- 1316,1340 ----
break;
case IPPROTO_SCTP:
ret = ipcl_sctp_hash_insert(connp, lport);
break;
+
+ case IPPROTO_DCCP:
+ cmn_err(CE_NOTE, "ipclassifier.c: ipcl_bind_insert_v4");
+ ASSERT(connp->conn_zoneid != ALL_ZONES);
+ connfp = &ipst->ips_ipcl_dccp_bind_fanout[
+ IPCL_DCCP_BIND_HASH(lport, ipst)];
+ if (connp->conn_laddr_v4 != INADDR_ANY) {
+ IPCL_HASH_INSERT_BOUND(connfp, connp);
+ } else {
+ IPCL_HASH_INSERT_WILDCARD(connfp, connp);
+ }
+ break;
}
+
return (ret);
}
int
ipcl_bind_insert_v6(conn_t *connp)
*** 1307,1316 ****
--- 1402,1423 ----
break;
case IPPROTO_SCTP:
ret = ipcl_sctp_hash_insert(connp, lport);
break;
+
+ case IPPROTO_DCCP:
+ cmn_err(CE_NOTE, "ipclassifier.c: ipcl_bind_insert_v6");
+ ASSERT(connp->conn_zoneid != ALL_ZONES);
+ connfp = &ipst->ips_ipcl_dccp_bind_fanout[
+ IPCL_DCCP_BIND_HASH(lport, ipst)];
+ if (!IN6_IS_ADDR_UNSPECIFIED(&connp->conn_laddr_v6)) {
+ IPCL_HASH_INSERT_BOUND(connfp, connp);
+ } else {
+ IPCL_HASH_INSERT_WILDCARD(connfp, connp);
+ }
+ break;
}
return (ret);
}
*** 1391,1400 ****
--- 1498,1533 ----
*/
IPCL_HASH_REMOVE(connp);
ret = ipcl_sctp_hash_insert(connp, lport);
break;
+ case IPPROTO_DCCP:
+ cmn_err(CE_NOTE, "ipclassifier.c: ipcl_conn_insert_v4");
+ connfp = &ipst->ips_ipcl_dccp_conn_fanout[IPCL_DCCP_CONN_HASH(
+ connp->conn_faddr_v4, connp->conn_ports, ipst)];
+ mutex_enter(&connfp->connf_lock);
+ for (tconnp = connfp->connf_head; tconnp != NULL;
+ tconnp = tconnp->conn_next) {
+ if (IPCL_CONN_MATCH(tconnp, connp->conn_proto,
+ connp->conn_faddr_v4, connp->conn_laddr_v4,
+ connp->conn_ports) &&
+ IPCL_ZONE_MATCH(tconnp, connp->conn_zoneid)) {
+ /* Already have a conn. bail out */
+ mutex_exit(&connfp->connf_lock);
+ return (EADDRINUSE);
+ }
+ }
+
+ /* XXX:DCCP XTI/TLI application? */
+
+ ASSERT(connp->conn_recv != NULL);
+ ASSERT(connp->conn_recvicmp != NULL);
+
+ IPCL_HASH_INSERT_CONNECTED_LOCKED(connfp, connp);
+ mutex_exit(&connfp->connf_lock);
+ break;
+
default:
/*
* Check for conflicts among MAC exempt bindings. For
* transports with port numbers, this is done by the upper
* level per-transport binding logic. For all others, it's
*** 1486,1495 ****
--- 1619,1654 ----
case IPPROTO_SCTP:
IPCL_HASH_REMOVE(connp);
ret = ipcl_sctp_hash_insert(connp, lport);
break;
+ case IPPROTO_DCCP:
+ cmn_err(CE_NOTE, "ipclassifier.c: ipcl_conn_insert_v6");
+ connfp = &ipst->ips_ipcl_dccp_conn_fanout[
+ IPCL_DCCP_CONN_HASH_V6(connp->conn_faddr_v6,
+ connp->conn_ports, ipst)];
+ mutex_enter(&connfp->connf_lock);
+ for (tconnp = connfp->connf_head; tconnp != NULL;
+ tconnp = tconnp->conn_next) {
+ /* NOTE: need to match zoneid. Bug in onnv-gate */
+ if (IPCL_CONN_MATCH_V6(tconnp, connp->conn_proto,
+ connp->conn_faddr_v6, connp->conn_laddr_v6,
+ connp->conn_ports) &&
+ (tconnp->conn_bound_if == 0 ||
+ tconnp->conn_bound_if == ifindex) &&
+ IPCL_ZONE_MATCH(tconnp, connp->conn_zoneid)) {
+ /* Already have a conn. bail out */
+ mutex_exit(&connfp->connf_lock);
+ return (EADDRINUSE);
+ }
+ }
+
+ /* XXX:DCCP XTI/TLI? */
+ IPCL_HASH_INSERT_CONNECTED_LOCKED(connfp, connp);
+ mutex_exit(&connfp->connf_lock);
+ break;
+
default:
if (is_system_labeled() &&
check_exempt_conflict_v6(connp, ipst))
return (EADDRINUSE);
/* FALLTHROUGH */
*** 1653,1662 ****
--- 1812,1882 ----
*/
mutex_exit(&connfp->connf_lock);
break;
+ case IPPROTO_DCCP:
+ ports = *(uint32_t *)up;
+
+ /*
+ * Search for fully-bound connection.
+ */
+ connfp = &ipst->ips_ipcl_dccp_conn_fanout[IPCL_DCCP_CONN_HASH(
+ ipha->ipha_src, ports, ipst)];
+ mutex_enter(&connfp->connf_lock);
+ for (connp = connfp->connf_head; connp != NULL;
+ connp = connp->conn_next) {
+ /* XXX:DCCP */
+ if (IPCL_CONN_MATCH(connp, protocol,
+ ipha->ipha_src, ipha->ipha_dst, ports)) {
+ /* XXX */
+ cmn_err(CE_NOTE, "ipclassifier.c: fully bound connection found");
+ break;
+ }
+ }
+
+ if (connp != NULL) {
+ /*
+ * We have a fully-bound DCCP connection.
+ */
+ CONN_INC_REF(connp);
+ mutex_exit(&connfp->connf_lock);
+ return (connp);
+ }
+
+ mutex_exit(&connfp->connf_lock);
+ lport = up[1];
+
+ /*
+ * Fully-bound connection was not found, search for listener.
+ */
+ bind_connfp = &ipst->ips_ipcl_dccp_bind_fanout[
+ IPCL_DCCP_BIND_HASH(lport, ipst)];
+ mutex_enter(&bind_connfp->connf_lock);
+ for (connp = bind_connfp->connf_head; connp != NULL;
+ connp = connp->conn_next) {
+ if (IPCL_BIND_MATCH(connp, protocol, ipha->ipha_dst,
+ lport) &&
+ (connp->conn_zoneid == zoneid ||
+ connp->conn_allzones ||
+ ((connp->conn_mac_mode != CONN_MAC_DEFAULT) &&
+ (ira->ira_flags & IRAF_TX_MAC_EXEMPTABLE) &&
+ (ira->ira_flags & IRAF_TX_SHARED_ADDR))))
+ break;
+ }
+
+ if (connp != NULL) {
+ cmn_err(CE_NOTE, "ipclassifier.c: half-bound bind listener");
+ /* Have a listener at least */
+ CONN_INC_REF(connp);
+ mutex_exit(&bind_connfp->connf_lock);
+ return (connp);
+ }
+
+ mutex_exit(&bind_connfp->connf_lock);
+ break;
+
case IPPROTO_ENCAP:
case IPPROTO_IPV6:
return (ipcl_iptun_classify_v4(&ipha->ipha_src,
&ipha->ipha_dst, ipst));
}
*** 2173,2182 ****
--- 2393,2466 ----
ASSERT(connp->conn_ixa->ixa_nce == NULL);
ixa_refrele(connp->conn_ixa);
}
}
+ /* ARGSUSED */
+ static int
+ dccp_conn_constructor(void *buf, void *cdrarg, int kmflags)
+ {
+ itc_t *itc = (itc_t *)buf;
+ conn_t *connp = &itc->itc_conn;
+ dccp_t *dccp = (dccp_t *)&itc[1];
+
+ bzero(connp, sizeof (conn_t));
+ bzero(dccp, sizeof (dccp_t));
+
+ mutex_init(&connp->conn_lock, NULL, MUTEX_DEFAULT, NULL);
+ cv_init(&connp->conn_cv, NULL, CV_DEFAULT, NULL);
+ rw_init(&connp->conn_ilg_lock, NULL, RW_DEFAULT, NULL);
+
+ dccp->dccp_timercache = dccp_timermp_alloc(kmflags);
+ if (dccp->dccp_timercache == NULL) {
+ return (ENOMEM);
+ }
+
+ connp->conn_dccp = dccp;
+ connp->conn_flags = IPCL_DCCPCONN;
+ connp->conn_proto = IPPROTO_DCCP;
+ dccp->dccp_connp = connp;
+
+ connp->conn_ixa = kmem_zalloc(sizeof (ip_xmit_attr_t), kmflags);
+ if (connp->conn_ixa == NULL) {
+ return (NULL);
+ }
+
+ connp->conn_ixa->ixa_refcnt = 1;
+ connp->conn_ixa->ixa_protocol = connp->conn_proto;
+ connp->conn_ixa->ixa_xmit_hint = CONN_TO_XMIT_HINT(connp);
+
+ return (0);
+ }
+
+ /* ARGSUSED */
+ static void
+ dccp_conn_destructor(void *buf, void *cdrarg)
+ {
+ itc_t *itc = (itc_t *)buf;
+ conn_t *connp = &itc->itc_conn;
+ dccp_t *dccp = (dccp_t *)&itc[1];
+
+ ASSERT(connp->conn_flags & IPCL_DCCPCONN);
+ ASSERT(dccp->dccp_connp == connp);
+ ASSERT(connp->conn_dccp == dccp);
+
+ dccp_timermp_free(dccp);
+
+ mutex_destroy(&connp->conn_lock);
+ cv_destroy(&connp->conn_cv);
+ rw_destroy(&connp->conn_ilg_lock);
+
+ if (connp->conn_ixa != NULL) {
+ ASSERT(connp->conn_ixa->ixa_refcnt == 1);
+ ASSERT(connp->conn_ixa->ixa_ire == NULL);
+ ASSERT(connp->conn_ixa->ixa_nce == NULL);
+
+ ixa_refrele(connp->conn_ixa);
+ }
+ }
+
/*
* Called as part of ipcl_conn_destroy to assert and clear any pointers
* in the conn_t.
*
* Below we list all the pointers in the conn_t as a documentation aid.
*** 2552,2561 ****
--- 2836,2921 ----
mutex_exit(&connfp->connf_lock);
return (NULL);
}
/*
+ * Same as ipcl_tcp_lookup_reversed_ipv4.
+ */
+ conn_t *
+ ipcl_dccp_lookup_reversed_ipv4(ipha_t *ipha, dccpha_t *dccpha, int min_state,
+ ip_stack_t *ipst)
+ {
+ conn_t *tconnp;
+ connf_t *connfp;
+ uint16_t *pports;
+ uint32_t ports;
+
+ pports = (uint16_t *)&ports;
+ pports[0] = dccpha->dha_fport;
+ pports[1] = dccpha->dha_lport;
+
+ connfp = &ipst->ips_ipcl_dccp_conn_fanout[IPCL_DCCP_CONN_HASH(
+ ipha->ipha_dst, ports, ipst)];
+
+ mutex_enter(&connfp->connf_lock);
+ for (tconnp = connfp->connf_head; tconnp != NULL;
+ tconnp = tconnp->conn_next) {
+ if (IPCL_CONN_MATCH(tconnp, IPPROTO_DCCP,
+ ipha->ipha_dst, ipha->ipha_src, ports) &&
+ tconnp->conn_dccp->dccp_state >= min_state) {
+ CONN_INC_REF(tconnp);
+ mutex_exit(&connfp->connf_lock);
+ return (tconnp);
+ }
+ }
+ mutex_exit(&connfp->connf_lock);
+
+ return (NULL);
+ }
+
+ /*
+ * Same as ipcl_tcp_lookup_reversed_ipv6.
+ */
+ conn_t *
+ ipcl_dccp_lookup_reversed_ipv6(ip6_t *ip6h, dccpha_t *dccpha, int min_state,
+ uint_t ifindex, ip_stack_t *ipst)
+ {
+ conn_t *tconnp;
+ tcp_t *tcp;
+ connf_t *connfp;
+ uint32_t ports;
+ uint16_t *pports;
+
+ pports = (uint16_t *)&ports;
+ pports[0] = dccpha->dha_fport;
+ pports[1] = dccpha->dha_lport;
+ /*
+ connfp = &ipst->ips_ipcl_conn_fanout[IPCL_CONN_HASH_V6(ip6h->ip6_dst,
+ ports, ipst)];
+
+ mutex_enter(&connfp->connf_lock);
+ for (tconnp = connfp->connf_head; tconnp != NULL;
+ tconnp = tconnp->conn_next) {
+
+ tcp = tconnp->conn_tcp;
+ if (IPCL_CONN_MATCH_V6(tconnp, IPPROTO_TCP,
+ ip6h->ip6_dst, ip6h->ip6_src, ports) &&
+ tcp->tcp_state >= min_state &&
+ (tconnp->conn_bound_if == 0 ||
+ tconnp->conn_bound_if == ifindex)) {
+
+ CONN_INC_REF(tconnp);
+ mutex_exit(&connfp->connf_lock);
+ return (tconnp);
+ }
+ }
+ mutex_exit(&connfp->connf_lock);
+ */
+ return (NULL);
+ }
+
+ /*
* Finds a TCP/IPv4 listening connection; called by tcp_disconnect to locate
* a listener when changing state.
*/
conn_t *
ipcl_lookup_listener_v4(uint16_t lport, ipaddr_t laddr, zoneid_t zoneid,