1*10946SSangeeta.Misra@Sun.COM /*
2*10946SSangeeta.Misra@Sun.COM * CDDL HEADER START
3*10946SSangeeta.Misra@Sun.COM *
4*10946SSangeeta.Misra@Sun.COM * The contents of this file are subject to the terms of the
5*10946SSangeeta.Misra@Sun.COM * Common Development and Distribution License (the "License").
6*10946SSangeeta.Misra@Sun.COM * You may not use this file except in compliance with the License.
7*10946SSangeeta.Misra@Sun.COM *
8*10946SSangeeta.Misra@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*10946SSangeeta.Misra@Sun.COM * or http://www.opensolaris.org/os/licensing.
10*10946SSangeeta.Misra@Sun.COM * See the License for the specific language governing permissions
11*10946SSangeeta.Misra@Sun.COM * and limitations under the License.
12*10946SSangeeta.Misra@Sun.COM *
13*10946SSangeeta.Misra@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
14*10946SSangeeta.Misra@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*10946SSangeeta.Misra@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
16*10946SSangeeta.Misra@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
17*10946SSangeeta.Misra@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
18*10946SSangeeta.Misra@Sun.COM *
19*10946SSangeeta.Misra@Sun.COM * CDDL HEADER END
20*10946SSangeeta.Misra@Sun.COM */
21*10946SSangeeta.Misra@Sun.COM
22*10946SSangeeta.Misra@Sun.COM /*
23*10946SSangeeta.Misra@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24*10946SSangeeta.Misra@Sun.COM * Use is subject to license terms.
25*10946SSangeeta.Misra@Sun.COM */
26*10946SSangeeta.Misra@Sun.COM
27*10946SSangeeta.Misra@Sun.COM #include <sys/types.h>
28*10946SSangeeta.Misra@Sun.COM #include <sys/cmn_err.h>
29*10946SSangeeta.Misra@Sun.COM #include <netinet/in.h>
30*10946SSangeeta.Misra@Sun.COM #include <inet/ip.h>
31*10946SSangeeta.Misra@Sun.COM #include <inet/ip6.h>
32*10946SSangeeta.Misra@Sun.COM #include <sys/crc32.h>
33*10946SSangeeta.Misra@Sun.COM
34*10946SSangeeta.Misra@Sun.COM #include <inet/ilb.h>
35*10946SSangeeta.Misra@Sun.COM #include "ilb_impl.h"
36*10946SSangeeta.Misra@Sun.COM #include "ilb_alg.h"
37*10946SSangeeta.Misra@Sun.COM
38*10946SSangeeta.Misra@Sun.COM #define HASH_IP_V4(hash, addr, size) \
39*10946SSangeeta.Misra@Sun.COM { \
40*10946SSangeeta.Misra@Sun.COM CRC32((hash), &(addr), sizeof (in_addr_t), -1U, crc32_table); \
41*10946SSangeeta.Misra@Sun.COM (hash) %= (size); \
42*10946SSangeeta.Misra@Sun.COM }
43*10946SSangeeta.Misra@Sun.COM #define HASH_IP_V6(hash, addr, size) \
44*10946SSangeeta.Misra@Sun.COM HASH_IP_V4((hash), (addr)->s6_addr32[3], (size))
45*10946SSangeeta.Misra@Sun.COM
46*10946SSangeeta.Misra@Sun.COM #define HASH_IP_PORT_V4(hash, addr, port, size) \
47*10946SSangeeta.Misra@Sun.COM { \
48*10946SSangeeta.Misra@Sun.COM uint32_t val = (addr) ^ ((port) << 16) ^ (port); \
49*10946SSangeeta.Misra@Sun.COM CRC32((hash), &val, sizeof (uint32_t), -1U, crc32_table); \
50*10946SSangeeta.Misra@Sun.COM (hash) %= (size); \
51*10946SSangeeta.Misra@Sun.COM }
52*10946SSangeeta.Misra@Sun.COM #define HASH_IP_PORT_V6(hash, addr, port, size) \
53*10946SSangeeta.Misra@Sun.COM HASH_IP_PORT_V4((hash), (addr)->s6_addr32[3], (port), (size))
54*10946SSangeeta.Misra@Sun.COM
55*10946SSangeeta.Misra@Sun.COM #define HASH_IP_VIP_V4(hash, saddr, daddr, size) \
56*10946SSangeeta.Misra@Sun.COM { \
57*10946SSangeeta.Misra@Sun.COM uint32_t val = (saddr) ^ (daddr); \
58*10946SSangeeta.Misra@Sun.COM CRC32((hash), &val, sizeof (uint32_t), -1U, crc32_table); \
59*10946SSangeeta.Misra@Sun.COM (hash) %= (size); \
60*10946SSangeeta.Misra@Sun.COM }
61*10946SSangeeta.Misra@Sun.COM #define HASH_IP_VIP_V6(hash, saddr, daddr, size) \
62*10946SSangeeta.Misra@Sun.COM HASH_IP_VIP_V4((hash), (saddr)->s6_addr32[3], (daddr)->s6_addr32[3], \
63*10946SSangeeta.Misra@Sun.COM (size))
64*10946SSangeeta.Misra@Sun.COM
65*10946SSangeeta.Misra@Sun.COM #define INIT_HASH_TBL_SIZE 10
66*10946SSangeeta.Misra@Sun.COM
67*10946SSangeeta.Misra@Sun.COM typedef struct {
68*10946SSangeeta.Misra@Sun.COM ilb_server_t *server;
69*10946SSangeeta.Misra@Sun.COM boolean_t enabled;
70*10946SSangeeta.Misra@Sun.COM } hash_server_t;
71*10946SSangeeta.Misra@Sun.COM
72*10946SSangeeta.Misra@Sun.COM /*
73*10946SSangeeta.Misra@Sun.COM * There are two hash tables. The hash_tbl holds all servers, both enabled
74*10946SSangeeta.Misra@Sun.COM * and disabled. The hash_enabled_tbl only holds enabled servers. Having
75*10946SSangeeta.Misra@Sun.COM * two tables allows the hash on a client request remains the same even when
76*10946SSangeeta.Misra@Sun.COM * some servers are disabled. If a server is disabled and a client's request
77*10946SSangeeta.Misra@Sun.COM * hashes to it, we will do another hash. This time the has is on the enabled
78*10946SSangeeta.Misra@Sun.COM * server table.
79*10946SSangeeta.Misra@Sun.COM */
80*10946SSangeeta.Misra@Sun.COM typedef struct hash_s {
81*10946SSangeeta.Misra@Sun.COM kmutex_t hash_lock;
82*10946SSangeeta.Misra@Sun.COM size_t hash_servers; /* Total # of servers */
83*10946SSangeeta.Misra@Sun.COM size_t hash_tbl_size; /* All server table size */
84*10946SSangeeta.Misra@Sun.COM size_t hash_enabled_servers; /* # of enabled servers */
85*10946SSangeeta.Misra@Sun.COM size_t hash_enabled_tbl_size; /* Enabled server table size */
86*10946SSangeeta.Misra@Sun.COM hash_server_t *hash_tbl;
87*10946SSangeeta.Misra@Sun.COM hash_server_t *hash_enabled_tbl;
88*10946SSangeeta.Misra@Sun.COM ilb_algo_impl_t hash_type;
89*10946SSangeeta.Misra@Sun.COM } hash_t;
90*10946SSangeeta.Misra@Sun.COM
91*10946SSangeeta.Misra@Sun.COM static void hash_fini(ilb_alg_data_t **);
92*10946SSangeeta.Misra@Sun.COM
93*10946SSangeeta.Misra@Sun.COM /* ARGSUSED */
94*10946SSangeeta.Misra@Sun.COM static boolean_t
hash_lb(in6_addr_t * saddr,in_port_t sport,in6_addr_t * daddr,in_port_t dport,void * alg_data,ilb_server_t ** ret_server)95*10946SSangeeta.Misra@Sun.COM hash_lb(in6_addr_t *saddr, in_port_t sport, in6_addr_t *daddr,
96*10946SSangeeta.Misra@Sun.COM in_port_t dport, void *alg_data, ilb_server_t **ret_server)
97*10946SSangeeta.Misra@Sun.COM {
98*10946SSangeeta.Misra@Sun.COM hash_t *hash_alg = (hash_t *)alg_data;
99*10946SSangeeta.Misra@Sun.COM uint32_t i;
100*10946SSangeeta.Misra@Sun.COM
101*10946SSangeeta.Misra@Sun.COM ASSERT(ret_server != NULL);
102*10946SSangeeta.Misra@Sun.COM *ret_server = NULL;
103*10946SSangeeta.Misra@Sun.COM
104*10946SSangeeta.Misra@Sun.COM mutex_enter(&hash_alg->hash_lock);
105*10946SSangeeta.Misra@Sun.COM
106*10946SSangeeta.Misra@Sun.COM if (hash_alg->hash_servers == 0) {
107*10946SSangeeta.Misra@Sun.COM mutex_exit(&hash_alg->hash_lock);
108*10946SSangeeta.Misra@Sun.COM return (B_FALSE);
109*10946SSangeeta.Misra@Sun.COM }
110*10946SSangeeta.Misra@Sun.COM
111*10946SSangeeta.Misra@Sun.COM switch (hash_alg->hash_type) {
112*10946SSangeeta.Misra@Sun.COM case ILB_ALG_IMPL_HASH_IP:
113*10946SSangeeta.Misra@Sun.COM HASH_IP_V6(i, saddr, hash_alg->hash_servers);
114*10946SSangeeta.Misra@Sun.COM break;
115*10946SSangeeta.Misra@Sun.COM case ILB_ALG_IMPL_HASH_IP_SPORT:
116*10946SSangeeta.Misra@Sun.COM HASH_IP_PORT_V6(i, saddr, sport, hash_alg->hash_servers);
117*10946SSangeeta.Misra@Sun.COM break;
118*10946SSangeeta.Misra@Sun.COM case ILB_ALG_IMPL_HASH_IP_VIP:
119*10946SSangeeta.Misra@Sun.COM HASH_IP_VIP_V6(i, saddr, daddr, hash_alg->hash_servers);
120*10946SSangeeta.Misra@Sun.COM break;
121*10946SSangeeta.Misra@Sun.COM default:
122*10946SSangeeta.Misra@Sun.COM mutex_exit(&hash_alg->hash_lock);
123*10946SSangeeta.Misra@Sun.COM return (B_FALSE);
124*10946SSangeeta.Misra@Sun.COM }
125*10946SSangeeta.Misra@Sun.COM if (hash_alg->hash_tbl[i].enabled) {
126*10946SSangeeta.Misra@Sun.COM *ret_server = hash_alg->hash_tbl[i].server;
127*10946SSangeeta.Misra@Sun.COM mutex_exit(&hash_alg->hash_lock);
128*10946SSangeeta.Misra@Sun.COM return (B_TRUE);
129*10946SSangeeta.Misra@Sun.COM }
130*10946SSangeeta.Misra@Sun.COM
131*10946SSangeeta.Misra@Sun.COM if (hash_alg->hash_enabled_servers == 0) {
132*10946SSangeeta.Misra@Sun.COM mutex_exit(&hash_alg->hash_lock);
133*10946SSangeeta.Misra@Sun.COM return (B_FALSE);
134*10946SSangeeta.Misra@Sun.COM }
135*10946SSangeeta.Misra@Sun.COM
136*10946SSangeeta.Misra@Sun.COM switch (hash_alg->hash_type) {
137*10946SSangeeta.Misra@Sun.COM case ILB_ALG_IMPL_HASH_IP:
138*10946SSangeeta.Misra@Sun.COM HASH_IP_V6(i, saddr, hash_alg->hash_enabled_servers);
139*10946SSangeeta.Misra@Sun.COM break;
140*10946SSangeeta.Misra@Sun.COM case ILB_ALG_IMPL_HASH_IP_SPORT:
141*10946SSangeeta.Misra@Sun.COM HASH_IP_PORT_V6(i, saddr, sport,
142*10946SSangeeta.Misra@Sun.COM hash_alg->hash_enabled_servers);
143*10946SSangeeta.Misra@Sun.COM break;
144*10946SSangeeta.Misra@Sun.COM case ILB_ALG_IMPL_HASH_IP_VIP:
145*10946SSangeeta.Misra@Sun.COM HASH_IP_VIP_V6(i, saddr, daddr,
146*10946SSangeeta.Misra@Sun.COM hash_alg->hash_enabled_servers);
147*10946SSangeeta.Misra@Sun.COM break;
148*10946SSangeeta.Misra@Sun.COM default:
149*10946SSangeeta.Misra@Sun.COM ASSERT(0);
150*10946SSangeeta.Misra@Sun.COM break;
151*10946SSangeeta.Misra@Sun.COM }
152*10946SSangeeta.Misra@Sun.COM *ret_server = hash_alg->hash_enabled_tbl[i].server;
153*10946SSangeeta.Misra@Sun.COM mutex_exit(&hash_alg->hash_lock);
154*10946SSangeeta.Misra@Sun.COM return (B_TRUE);
155*10946SSangeeta.Misra@Sun.COM }
156*10946SSangeeta.Misra@Sun.COM
157*10946SSangeeta.Misra@Sun.COM static boolean_t
del_server(hash_server_t * tbl,size_t hash_size,ilb_server_t * host)158*10946SSangeeta.Misra@Sun.COM del_server(hash_server_t *tbl, size_t hash_size, ilb_server_t *host)
159*10946SSangeeta.Misra@Sun.COM {
160*10946SSangeeta.Misra@Sun.COM size_t i, j;
161*10946SSangeeta.Misra@Sun.COM
162*10946SSangeeta.Misra@Sun.COM for (i = 0; i < hash_size; i++) {
163*10946SSangeeta.Misra@Sun.COM if (tbl[i].server == host) {
164*10946SSangeeta.Misra@Sun.COM if (i == hash_size - 1)
165*10946SSangeeta.Misra@Sun.COM break;
166*10946SSangeeta.Misra@Sun.COM for (j = i; j < hash_size - 1; j++)
167*10946SSangeeta.Misra@Sun.COM tbl[j] = tbl[j + 1];
168*10946SSangeeta.Misra@Sun.COM break;
169*10946SSangeeta.Misra@Sun.COM }
170*10946SSangeeta.Misra@Sun.COM }
171*10946SSangeeta.Misra@Sun.COM /* Not found... */
172*10946SSangeeta.Misra@Sun.COM if (i == hash_size)
173*10946SSangeeta.Misra@Sun.COM return (B_FALSE);
174*10946SSangeeta.Misra@Sun.COM tbl[hash_size - 1].server = NULL;
175*10946SSangeeta.Misra@Sun.COM tbl[hash_size - 1].enabled = B_FALSE;
176*10946SSangeeta.Misra@Sun.COM return (B_TRUE);
177*10946SSangeeta.Misra@Sun.COM }
178*10946SSangeeta.Misra@Sun.COM
179*10946SSangeeta.Misra@Sun.COM static int
hash_server_del(ilb_server_t * host,void * alg_data)180*10946SSangeeta.Misra@Sun.COM hash_server_del(ilb_server_t *host, void *alg_data)
181*10946SSangeeta.Misra@Sun.COM {
182*10946SSangeeta.Misra@Sun.COM hash_t *hash_alg = (hash_t *)alg_data;
183*10946SSangeeta.Misra@Sun.COM boolean_t ret;
184*10946SSangeeta.Misra@Sun.COM
185*10946SSangeeta.Misra@Sun.COM mutex_enter(&hash_alg->hash_lock);
186*10946SSangeeta.Misra@Sun.COM
187*10946SSangeeta.Misra@Sun.COM ret = del_server(hash_alg->hash_tbl, hash_alg->hash_servers, host);
188*10946SSangeeta.Misra@Sun.COM if (!ret) {
189*10946SSangeeta.Misra@Sun.COM mutex_exit(&hash_alg->hash_lock);
190*10946SSangeeta.Misra@Sun.COM return (EINVAL);
191*10946SSangeeta.Misra@Sun.COM }
192*10946SSangeeta.Misra@Sun.COM hash_alg->hash_servers--;
193*10946SSangeeta.Misra@Sun.COM
194*10946SSangeeta.Misra@Sun.COM /* The server may not be enabled. */
195*10946SSangeeta.Misra@Sun.COM ret = del_server(hash_alg->hash_enabled_tbl,
196*10946SSangeeta.Misra@Sun.COM hash_alg->hash_enabled_servers, host);
197*10946SSangeeta.Misra@Sun.COM if (ret)
198*10946SSangeeta.Misra@Sun.COM hash_alg->hash_enabled_servers--;
199*10946SSangeeta.Misra@Sun.COM
200*10946SSangeeta.Misra@Sun.COM mutex_exit(&hash_alg->hash_lock);
201*10946SSangeeta.Misra@Sun.COM ILB_SERVER_REFRELE(host);
202*10946SSangeeta.Misra@Sun.COM return (0);
203*10946SSangeeta.Misra@Sun.COM }
204*10946SSangeeta.Misra@Sun.COM
205*10946SSangeeta.Misra@Sun.COM static int
grow_tbl(hash_server_t ** hash_tbl,size_t * tbl_size)206*10946SSangeeta.Misra@Sun.COM grow_tbl(hash_server_t **hash_tbl, size_t *tbl_size)
207*10946SSangeeta.Misra@Sun.COM {
208*10946SSangeeta.Misra@Sun.COM size_t mem_size;
209*10946SSangeeta.Misra@Sun.COM hash_server_t *new_tbl;
210*10946SSangeeta.Misra@Sun.COM
211*10946SSangeeta.Misra@Sun.COM if ((new_tbl = kmem_zalloc(sizeof (hash_server_t) *
212*10946SSangeeta.Misra@Sun.COM (*tbl_size + INIT_HASH_TBL_SIZE), KM_NOSLEEP)) == NULL) {
213*10946SSangeeta.Misra@Sun.COM return (ENOMEM);
214*10946SSangeeta.Misra@Sun.COM }
215*10946SSangeeta.Misra@Sun.COM mem_size = *tbl_size * sizeof (hash_server_t);
216*10946SSangeeta.Misra@Sun.COM bcopy(*hash_tbl, new_tbl, mem_size);
217*10946SSangeeta.Misra@Sun.COM kmem_free(*hash_tbl, mem_size);
218*10946SSangeeta.Misra@Sun.COM *hash_tbl = new_tbl;
219*10946SSangeeta.Misra@Sun.COM *tbl_size += INIT_HASH_TBL_SIZE;
220*10946SSangeeta.Misra@Sun.COM return (0);
221*10946SSangeeta.Misra@Sun.COM }
222*10946SSangeeta.Misra@Sun.COM
223*10946SSangeeta.Misra@Sun.COM static int
hash_server_add(ilb_server_t * host,void * alg_data)224*10946SSangeeta.Misra@Sun.COM hash_server_add(ilb_server_t *host, void *alg_data)
225*10946SSangeeta.Misra@Sun.COM {
226*10946SSangeeta.Misra@Sun.COM hash_t *hash_alg = (hash_t *)alg_data;
227*10946SSangeeta.Misra@Sun.COM size_t new_size;
228*10946SSangeeta.Misra@Sun.COM
229*10946SSangeeta.Misra@Sun.COM mutex_enter(&hash_alg->hash_lock);
230*10946SSangeeta.Misra@Sun.COM
231*10946SSangeeta.Misra@Sun.COM /* First add the server to the hash_tbl. */
232*10946SSangeeta.Misra@Sun.COM new_size = hash_alg->hash_servers + 1;
233*10946SSangeeta.Misra@Sun.COM if (new_size > hash_alg->hash_tbl_size) {
234*10946SSangeeta.Misra@Sun.COM if (grow_tbl(&hash_alg->hash_tbl, &hash_alg->hash_tbl_size) !=
235*10946SSangeeta.Misra@Sun.COM 0) {
236*10946SSangeeta.Misra@Sun.COM mutex_exit(&hash_alg->hash_lock);
237*10946SSangeeta.Misra@Sun.COM return (ENOMEM);
238*10946SSangeeta.Misra@Sun.COM }
239*10946SSangeeta.Misra@Sun.COM }
240*10946SSangeeta.Misra@Sun.COM
241*10946SSangeeta.Misra@Sun.COM hash_alg->hash_tbl[hash_alg->hash_servers].server = host;
242*10946SSangeeta.Misra@Sun.COM hash_alg->hash_tbl[hash_alg->hash_servers].enabled = host->iser_enabled;
243*10946SSangeeta.Misra@Sun.COM hash_alg->hash_servers++;
244*10946SSangeeta.Misra@Sun.COM
245*10946SSangeeta.Misra@Sun.COM if (!host->iser_enabled) {
246*10946SSangeeta.Misra@Sun.COM mutex_exit(&hash_alg->hash_lock);
247*10946SSangeeta.Misra@Sun.COM ILB_SERVER_REFHOLD(host);
248*10946SSangeeta.Misra@Sun.COM return (0);
249*10946SSangeeta.Misra@Sun.COM }
250*10946SSangeeta.Misra@Sun.COM
251*10946SSangeeta.Misra@Sun.COM /* If the server is enabled, add it to the hasn_enabled_tbl. */
252*10946SSangeeta.Misra@Sun.COM new_size = hash_alg->hash_enabled_servers + 1;
253*10946SSangeeta.Misra@Sun.COM if (new_size > hash_alg->hash_enabled_tbl_size) {
254*10946SSangeeta.Misra@Sun.COM if (grow_tbl(&hash_alg->hash_enabled_tbl,
255*10946SSangeeta.Misra@Sun.COM &hash_alg->hash_enabled_tbl_size) != 0) {
256*10946SSangeeta.Misra@Sun.COM mutex_exit(&hash_alg->hash_lock);
257*10946SSangeeta.Misra@Sun.COM return (ENOMEM);
258*10946SSangeeta.Misra@Sun.COM }
259*10946SSangeeta.Misra@Sun.COM }
260*10946SSangeeta.Misra@Sun.COM hash_alg->hash_enabled_tbl[hash_alg->hash_enabled_servers].server =
261*10946SSangeeta.Misra@Sun.COM host;
262*10946SSangeeta.Misra@Sun.COM hash_alg->hash_enabled_tbl[hash_alg->hash_enabled_servers].enabled =
263*10946SSangeeta.Misra@Sun.COM B_TRUE;
264*10946SSangeeta.Misra@Sun.COM hash_alg->hash_enabled_servers++;
265*10946SSangeeta.Misra@Sun.COM
266*10946SSangeeta.Misra@Sun.COM mutex_exit(&hash_alg->hash_lock);
267*10946SSangeeta.Misra@Sun.COM ILB_SERVER_REFHOLD(host);
268*10946SSangeeta.Misra@Sun.COM return (0);
269*10946SSangeeta.Misra@Sun.COM }
270*10946SSangeeta.Misra@Sun.COM
271*10946SSangeeta.Misra@Sun.COM static int
hash_server_enable(ilb_server_t * host,void * alg_data)272*10946SSangeeta.Misra@Sun.COM hash_server_enable(ilb_server_t *host, void *alg_data)
273*10946SSangeeta.Misra@Sun.COM {
274*10946SSangeeta.Misra@Sun.COM hash_t *alg = (hash_t *)alg_data;
275*10946SSangeeta.Misra@Sun.COM size_t new_size, i;
276*10946SSangeeta.Misra@Sun.COM
277*10946SSangeeta.Misra@Sun.COM mutex_enter(&alg->hash_lock);
278*10946SSangeeta.Misra@Sun.COM
279*10946SSangeeta.Misra@Sun.COM for (i = 0; i < alg->hash_servers; i++) {
280*10946SSangeeta.Misra@Sun.COM if (alg->hash_tbl[i].server == host) {
281*10946SSangeeta.Misra@Sun.COM if (alg->hash_tbl[i].enabled) {
282*10946SSangeeta.Misra@Sun.COM mutex_exit(&alg->hash_lock);
283*10946SSangeeta.Misra@Sun.COM return (0);
284*10946SSangeeta.Misra@Sun.COM } else {
285*10946SSangeeta.Misra@Sun.COM break;
286*10946SSangeeta.Misra@Sun.COM }
287*10946SSangeeta.Misra@Sun.COM }
288*10946SSangeeta.Misra@Sun.COM }
289*10946SSangeeta.Misra@Sun.COM if (i == alg->hash_servers) {
290*10946SSangeeta.Misra@Sun.COM mutex_exit(&alg->hash_lock);
291*10946SSangeeta.Misra@Sun.COM return (EINVAL);
292*10946SSangeeta.Misra@Sun.COM }
293*10946SSangeeta.Misra@Sun.COM
294*10946SSangeeta.Misra@Sun.COM #if DEBUG
295*10946SSangeeta.Misra@Sun.COM /* The server should not be in the enabled tabled. */
296*10946SSangeeta.Misra@Sun.COM {
297*10946SSangeeta.Misra@Sun.COM size_t j;
298*10946SSangeeta.Misra@Sun.COM
299*10946SSangeeta.Misra@Sun.COM for (j = 0; j < alg->hash_enabled_servers; j++) {
300*10946SSangeeta.Misra@Sun.COM if (alg->hash_enabled_tbl[j].server == host) {
301*10946SSangeeta.Misra@Sun.COM cmn_err(CE_PANIC, "Corrupted ILB enabled hash "
302*10946SSangeeta.Misra@Sun.COM "table");
303*10946SSangeeta.Misra@Sun.COM }
304*10946SSangeeta.Misra@Sun.COM }
305*10946SSangeeta.Misra@Sun.COM }
306*10946SSangeeta.Misra@Sun.COM #endif
307*10946SSangeeta.Misra@Sun.COM
308*10946SSangeeta.Misra@Sun.COM new_size = alg->hash_enabled_servers + 1;
309*10946SSangeeta.Misra@Sun.COM if (new_size > alg->hash_enabled_tbl_size) {
310*10946SSangeeta.Misra@Sun.COM if (grow_tbl(&alg->hash_enabled_tbl,
311*10946SSangeeta.Misra@Sun.COM &alg->hash_enabled_tbl_size) != 0) {
312*10946SSangeeta.Misra@Sun.COM mutex_exit(&alg->hash_lock);
313*10946SSangeeta.Misra@Sun.COM return (ENOMEM);
314*10946SSangeeta.Misra@Sun.COM }
315*10946SSangeeta.Misra@Sun.COM }
316*10946SSangeeta.Misra@Sun.COM alg->hash_tbl[i].enabled = B_TRUE;
317*10946SSangeeta.Misra@Sun.COM alg->hash_enabled_tbl[alg->hash_enabled_servers].server = host;
318*10946SSangeeta.Misra@Sun.COM alg->hash_enabled_tbl[alg->hash_enabled_servers].enabled = B_TRUE;
319*10946SSangeeta.Misra@Sun.COM alg->hash_enabled_servers++;
320*10946SSangeeta.Misra@Sun.COM
321*10946SSangeeta.Misra@Sun.COM mutex_exit(&alg->hash_lock);
322*10946SSangeeta.Misra@Sun.COM return (0);
323*10946SSangeeta.Misra@Sun.COM }
324*10946SSangeeta.Misra@Sun.COM
325*10946SSangeeta.Misra@Sun.COM static int
hash_server_disable(ilb_server_t * host,void * alg_data)326*10946SSangeeta.Misra@Sun.COM hash_server_disable(ilb_server_t *host, void *alg_data)
327*10946SSangeeta.Misra@Sun.COM {
328*10946SSangeeta.Misra@Sun.COM hash_t *alg = (hash_t *)alg_data;
329*10946SSangeeta.Misra@Sun.COM size_t i;
330*10946SSangeeta.Misra@Sun.COM
331*10946SSangeeta.Misra@Sun.COM mutex_enter(&alg->hash_lock);
332*10946SSangeeta.Misra@Sun.COM
333*10946SSangeeta.Misra@Sun.COM for (i = 0; i < alg->hash_servers; i++) {
334*10946SSangeeta.Misra@Sun.COM if (alg->hash_tbl[i].server == host) {
335*10946SSangeeta.Misra@Sun.COM if (!alg->hash_tbl[i].enabled) {
336*10946SSangeeta.Misra@Sun.COM mutex_exit(&alg->hash_lock);
337*10946SSangeeta.Misra@Sun.COM return (0);
338*10946SSangeeta.Misra@Sun.COM } else {
339*10946SSangeeta.Misra@Sun.COM break;
340*10946SSangeeta.Misra@Sun.COM }
341*10946SSangeeta.Misra@Sun.COM }
342*10946SSangeeta.Misra@Sun.COM }
343*10946SSangeeta.Misra@Sun.COM if (i == alg->hash_servers) {
344*10946SSangeeta.Misra@Sun.COM mutex_exit(&alg->hash_lock);
345*10946SSangeeta.Misra@Sun.COM return (EINVAL);
346*10946SSangeeta.Misra@Sun.COM }
347*10946SSangeeta.Misra@Sun.COM
348*10946SSangeeta.Misra@Sun.COM alg->hash_tbl[i].enabled = B_FALSE;
349*10946SSangeeta.Misra@Sun.COM #if DEBUG
350*10946SSangeeta.Misra@Sun.COM ASSERT(del_server(alg->hash_enabled_tbl, alg->hash_enabled_servers,
351*10946SSangeeta.Misra@Sun.COM host));
352*10946SSangeeta.Misra@Sun.COM #else
353*10946SSangeeta.Misra@Sun.COM (void) del_server(alg->hash_enabled_tbl, alg->hash_enabled_servers,
354*10946SSangeeta.Misra@Sun.COM host);
355*10946SSangeeta.Misra@Sun.COM #endif
356*10946SSangeeta.Misra@Sun.COM alg->hash_enabled_servers--;
357*10946SSangeeta.Misra@Sun.COM
358*10946SSangeeta.Misra@Sun.COM mutex_exit(&alg->hash_lock);
359*10946SSangeeta.Misra@Sun.COM return (0);
360*10946SSangeeta.Misra@Sun.COM }
361*10946SSangeeta.Misra@Sun.COM
362*10946SSangeeta.Misra@Sun.COM /* ARGSUSED */
363*10946SSangeeta.Misra@Sun.COM ilb_alg_data_t *
ilb_alg_hash_init(ilb_rule_t * rule,const void * arg)364*10946SSangeeta.Misra@Sun.COM ilb_alg_hash_init(ilb_rule_t *rule, const void *arg)
365*10946SSangeeta.Misra@Sun.COM {
366*10946SSangeeta.Misra@Sun.COM ilb_alg_data_t *alg;
367*10946SSangeeta.Misra@Sun.COM hash_t *hash_alg;
368*10946SSangeeta.Misra@Sun.COM int flags = *(int *)arg;
369*10946SSangeeta.Misra@Sun.COM
370*10946SSangeeta.Misra@Sun.COM if ((alg = kmem_alloc(sizeof (ilb_alg_data_t), KM_NOSLEEP)) == NULL)
371*10946SSangeeta.Misra@Sun.COM return (NULL);
372*10946SSangeeta.Misra@Sun.COM if ((hash_alg = kmem_alloc(sizeof (hash_t), KM_NOSLEEP)) == NULL) {
373*10946SSangeeta.Misra@Sun.COM kmem_free(alg, sizeof (ilb_alg_data_t));
374*10946SSangeeta.Misra@Sun.COM return (NULL);
375*10946SSangeeta.Misra@Sun.COM }
376*10946SSangeeta.Misra@Sun.COM alg->ilb_alg_lb = hash_lb;
377*10946SSangeeta.Misra@Sun.COM alg->ilb_alg_server_del = hash_server_del;
378*10946SSangeeta.Misra@Sun.COM alg->ilb_alg_server_add = hash_server_add;
379*10946SSangeeta.Misra@Sun.COM alg->ilb_alg_server_enable = hash_server_enable;
380*10946SSangeeta.Misra@Sun.COM alg->ilb_alg_server_disable = hash_server_disable;
381*10946SSangeeta.Misra@Sun.COM alg->ilb_alg_fini = hash_fini;
382*10946SSangeeta.Misra@Sun.COM alg->ilb_alg_data = hash_alg;
383*10946SSangeeta.Misra@Sun.COM
384*10946SSangeeta.Misra@Sun.COM mutex_init(&hash_alg->hash_lock, NULL, MUTEX_DEFAULT, NULL);
385*10946SSangeeta.Misra@Sun.COM hash_alg->hash_type = flags;
386*10946SSangeeta.Misra@Sun.COM
387*10946SSangeeta.Misra@Sun.COM /* Table of all servers */
388*10946SSangeeta.Misra@Sun.COM hash_alg->hash_servers = 0;
389*10946SSangeeta.Misra@Sun.COM hash_alg->hash_tbl_size = INIT_HASH_TBL_SIZE;
390*10946SSangeeta.Misra@Sun.COM hash_alg->hash_tbl = kmem_zalloc(sizeof (hash_server_t) *
391*10946SSangeeta.Misra@Sun.COM INIT_HASH_TBL_SIZE, KM_NOSLEEP);
392*10946SSangeeta.Misra@Sun.COM if (hash_alg->hash_tbl == NULL) {
393*10946SSangeeta.Misra@Sun.COM kmem_free(hash_alg, sizeof (hash_t));
394*10946SSangeeta.Misra@Sun.COM kmem_free(alg, sizeof (ilb_alg_data_t));
395*10946SSangeeta.Misra@Sun.COM return (NULL);
396*10946SSangeeta.Misra@Sun.COM }
397*10946SSangeeta.Misra@Sun.COM
398*10946SSangeeta.Misra@Sun.COM /* Table of only enabled servers */
399*10946SSangeeta.Misra@Sun.COM hash_alg->hash_enabled_servers = 0;
400*10946SSangeeta.Misra@Sun.COM hash_alg->hash_enabled_tbl_size = INIT_HASH_TBL_SIZE;
401*10946SSangeeta.Misra@Sun.COM hash_alg->hash_enabled_tbl = kmem_zalloc(sizeof (hash_server_t) *
402*10946SSangeeta.Misra@Sun.COM INIT_HASH_TBL_SIZE, KM_NOSLEEP);
403*10946SSangeeta.Misra@Sun.COM if (hash_alg->hash_tbl == NULL) {
404*10946SSangeeta.Misra@Sun.COM kmem_free(hash_alg->hash_tbl, INIT_HASH_TBL_SIZE *
405*10946SSangeeta.Misra@Sun.COM sizeof (ilb_server_t *));
406*10946SSangeeta.Misra@Sun.COM kmem_free(hash_alg, sizeof (hash_t));
407*10946SSangeeta.Misra@Sun.COM kmem_free(alg, sizeof (ilb_alg_data_t));
408*10946SSangeeta.Misra@Sun.COM return (NULL);
409*10946SSangeeta.Misra@Sun.COM }
410*10946SSangeeta.Misra@Sun.COM
411*10946SSangeeta.Misra@Sun.COM return (alg);
412*10946SSangeeta.Misra@Sun.COM }
413*10946SSangeeta.Misra@Sun.COM
414*10946SSangeeta.Misra@Sun.COM static void
hash_fini(ilb_alg_data_t ** alg)415*10946SSangeeta.Misra@Sun.COM hash_fini(ilb_alg_data_t **alg)
416*10946SSangeeta.Misra@Sun.COM {
417*10946SSangeeta.Misra@Sun.COM hash_t *hash_alg;
418*10946SSangeeta.Misra@Sun.COM int i;
419*10946SSangeeta.Misra@Sun.COM
420*10946SSangeeta.Misra@Sun.COM hash_alg = (*alg)->ilb_alg_data;
421*10946SSangeeta.Misra@Sun.COM for (i = 0; i < hash_alg->hash_servers; i++)
422*10946SSangeeta.Misra@Sun.COM ILB_SERVER_REFRELE(hash_alg->hash_tbl[i].server);
423*10946SSangeeta.Misra@Sun.COM
424*10946SSangeeta.Misra@Sun.COM kmem_free(hash_alg->hash_tbl, sizeof (hash_server_t) *
425*10946SSangeeta.Misra@Sun.COM hash_alg->hash_tbl_size);
426*10946SSangeeta.Misra@Sun.COM kmem_free(hash_alg->hash_enabled_tbl, sizeof (hash_server_t) *
427*10946SSangeeta.Misra@Sun.COM hash_alg->hash_enabled_tbl_size);
428*10946SSangeeta.Misra@Sun.COM kmem_free(hash_alg, sizeof (hash_t));
429*10946SSangeeta.Misra@Sun.COM kmem_free(*alg, sizeof (ilb_alg_data_t));
430*10946SSangeeta.Misra@Sun.COM *alg = NULL;
431*10946SSangeeta.Misra@Sun.COM }
432