1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /* This file contains Solaris Cluster related TCP hooks and functions. */
28 
29 #include <inet/tcp.h>
30 #include <inet/tcp_impl.h>
31 #include <inet/tcp_cluster.h>
32 
33 static int cl_tcp_walk_list_stack(int (*callback)(cl_tcp_info_t *, void *),
34     void *arg, tcp_stack_t *tcps);
35 
36 /*
37  * Hook functions to enable cluster networking
38  * On non-clustered systems these vectors must always be NULL.
39  */
40 void (*cl_inet_listen)(netstackid_t stack_id, uint8_t protocol,
41 			    sa_family_t addr_family, uint8_t *laddrp,
42 			    in_port_t lport, void *args) = NULL;
43 void (*cl_inet_unlisten)(netstackid_t stack_id, uint8_t protocol,
44 			    sa_family_t addr_family, uint8_t *laddrp,
45 			    in_port_t lport, void *args) = NULL;
46 
47 int (*cl_inet_connect2)(netstackid_t stack_id, uint8_t protocol,
48 			    boolean_t is_outgoing,
49 			    sa_family_t addr_family,
50 			    uint8_t *laddrp, in_port_t lport,
51 			    uint8_t *faddrp, in_port_t fport,
52 			    void *args) = NULL;
53 void (*cl_inet_disconnect)(netstackid_t stack_id, uint8_t protocol,
54 			    sa_family_t addr_family, uint8_t *laddrp,
55 			    in_port_t lport, uint8_t *faddrp,
56 			    in_port_t fport, void *args) = NULL;
57 
58 /*
59  * Exported routine for extracting active tcp connection status.
60  *
61  * This is used by the Solaris Cluster Networking software to
62  * gather a list of connections that need to be forwarded to
63  * specific nodes in the cluster when configuration changes occur.
64  *
65  * The callback is invoked for each tcp_t structure from all netstacks,
66  * if 'stack_id' is less than 0. Otherwise, only for tcp_t structures
67  * from the netstack with the specified stack_id. Returning
68  * non-zero from the callback routine terminates the search.
69  */
70 int
cl_tcp_walk_list(netstackid_t stack_id,int (* cl_callback)(cl_tcp_info_t *,void *),void * arg)71 cl_tcp_walk_list(netstackid_t stack_id,
72     int (*cl_callback)(cl_tcp_info_t *, void *), void *arg)
73 {
74 	netstack_handle_t nh;
75 	netstack_t *ns;
76 	int ret = 0;
77 
78 	if (stack_id >= 0) {
79 		if ((ns = netstack_find_by_stackid(stack_id)) == NULL)
80 			return (EINVAL);
81 
82 		ret = cl_tcp_walk_list_stack(cl_callback, arg,
83 		    ns->netstack_tcp);
84 		netstack_rele(ns);
85 		return (ret);
86 	}
87 
88 	netstack_next_init(&nh);
89 	while ((ns = netstack_next(&nh)) != NULL) {
90 		ret = cl_tcp_walk_list_stack(cl_callback, arg,
91 		    ns->netstack_tcp);
92 		netstack_rele(ns);
93 	}
94 	netstack_next_fini(&nh);
95 	return (ret);
96 }
97 
98 static int
cl_tcp_walk_list_stack(int (* callback)(cl_tcp_info_t *,void *),void * arg,tcp_stack_t * tcps)99 cl_tcp_walk_list_stack(int (*callback)(cl_tcp_info_t *, void *), void *arg,
100     tcp_stack_t *tcps)
101 {
102 	tcp_t *tcp;
103 	cl_tcp_info_t	cl_tcpi;
104 	connf_t	*connfp;
105 	conn_t	*connp;
106 	int	i;
107 	ip_stack_t	*ipst = tcps->tcps_netstack->netstack_ip;
108 
109 	ASSERT(callback != NULL);
110 
111 	for (i = 0; i < CONN_G_HASH_SIZE; i++) {
112 		connfp = &ipst->ips_ipcl_globalhash_fanout[i];
113 		connp = NULL;
114 
115 		while ((connp =
116 		    ipcl_get_next_conn(connfp, connp, IPCL_TCPCONN)) != NULL) {
117 
118 			tcp = connp->conn_tcp;
119 			cl_tcpi.cl_tcpi_version = CL_TCPI_V1;
120 			cl_tcpi.cl_tcpi_ipversion = connp->conn_ipversion;
121 			cl_tcpi.cl_tcpi_state = tcp->tcp_state;
122 			cl_tcpi.cl_tcpi_lport = connp->conn_lport;
123 			cl_tcpi.cl_tcpi_fport = connp->conn_fport;
124 			cl_tcpi.cl_tcpi_laddr_v6 = connp->conn_laddr_v6;
125 			cl_tcpi.cl_tcpi_faddr_v6 = connp->conn_faddr_v6;
126 
127 			/*
128 			 * If the callback returns non-zero
129 			 * we terminate the traversal.
130 			 */
131 			if ((*callback)(&cl_tcpi, arg) != 0) {
132 				CONN_DEC_REF(tcp->tcp_connp);
133 				return (1);
134 			}
135 		}
136 	}
137 
138 	return (0);
139 }
140