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