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.
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.
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]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #include <sys/types.h>
36 #include "libilb_impl.h"
40 * We only allow one show nat/persist command running at any time. Note that
41 * there is no lock for this since ilbd is single threaded. And we only care
42 * about the pointer value of client, not its type.
44 * The following variables store the current client making the request.
46 static void *nat_cur_cli
;
47 static void *sticky_cur_cli
;
49 /* Maximum number of NAT/sticky entries to request from kernel. */
50 #define NUM_ENTRIES 500
53 * Clear the current requesting client. This will allow a new client
57 ilbd_show_nat_cleanup(void)
63 ilbd_show_sticky_cleanup(void)
65 sticky_cur_cli
= NULL
;
69 * To show the kernel NAT table.
71 * cli: the client pointer making the request.
72 * ic: the client request.
73 * rbuf: reply buffer to be filled in.
74 * rbufsz: reply buffer size.
77 ilbd_show_nat(void *cli
, const ilb_comm_t
*ic
, uint32_t *rbuf
, size_t *rbufsz
)
79 ilb_show_info_t
*req_si
= (ilb_show_info_t
*)&ic
->ic_data
;
80 ilb_list_nat_cmd_t
*kcmd
;
82 size_t tmp_rbufsz
, kbufsz
;
86 ilb_show_info_t
*reply
;
87 ilb_nat_info_t
*nat_ret
;
89 /* For new client request, start from the beginning of the table. */
90 if (nat_cur_cli
== NULL
) {
93 } else if (cli
== nat_cur_cli
) {
95 * Another request from client. If the client does not
96 * want to continue, reset the current client and reply OK.
98 if (ic
->ic_flags
& ILB_COMM_END
) {
99 ilbd_show_nat_cleanup();
100 ilbd_reply_ok(rbuf
, rbufsz
);
101 return (ILB_STATUS_OK
);
105 /* A request is on-going, so reject a new client. */
106 return (ILB_STATUS_INPROGRESS
);
109 tmp_rbufsz
= *rbufsz
;
110 ilbd_reply_ok(rbuf
, rbufsz
);
111 reply
= (ilb_show_info_t
*)&((ilb_comm_t
*)rbuf
)->ic_data
;
114 * Calculate the max number of ilb_nat_info_t can be fitted in the
117 *rbufsz
+= sizeof (ilb_show_info_t
*);
118 tmp_rbufsz
-= *rbufsz
;
119 max_num
= tmp_rbufsz
/ sizeof (ilb_nat_info_t
);
122 * Calculate the exact number of entries we should request from kernel.
124 max_num
= min(req_si
->sn_num
, min(NUM_ENTRIES
, max_num
));
126 kbufsz
= max_num
* sizeof (ilb_nat_entry_t
) +
127 offsetof(ilb_list_nat_cmd_t
, entries
);
128 if ((kcmd
= malloc(kbufsz
)) == NULL
) {
129 logdebug("ilbd_show_nat: malloc(cmd)");
130 ilbd_reply_err(rbuf
, rbufsz
, ILB_STATUS_ENOMEM
);
131 return (ILB_STATUS_ENOMEM
);
134 kcmd
->cmd
= ILB_LIST_NAT_TABLE
;
135 kcmd
->flags
= start
? ILB_LIST_BEGIN
: ILB_LIST_CONT
;
136 kcmd
->num_nat
= max_num
;
137 if ((ret
= do_ioctl(kcmd
, kbufsz
)) != ILB_STATUS_OK
) {
138 logperror("ilbd_show_nat: ioctl(ILB_LIST_NAT_TABLE)");
139 ilbd_reply_err(rbuf
, rbufsz
, ret
);
144 reply
->sn_num
= kcmd
->num_nat
;
145 *rbufsz
+= reply
->sn_num
* sizeof (ilb_nat_info_t
);
148 * It is the end of table, let the client know. And the transaction
151 if (kcmd
->flags
& ILB_LIST_END
) {
155 * ilbd_reply_ok() sets ic_flags to ILB_COMM_END by default.
156 * Need to clear it here.
158 ((ilb_comm_t
*)rbuf
)->ic_flags
= 0;
161 nat_ret
= (ilb_nat_info_t
*)&reply
->sn_data
;
163 for (i
= 0; i
< kcmd
->num_nat
; i
++) {
164 ilb_nat_entry_t
*nat
;
166 nat
= &kcmd
->entries
[i
];
168 nat_ret
->nat_proto
= nat
->proto
;
170 nat_ret
->nat_in_local
= nat
->in_local
;
171 nat_ret
->nat_in_global
= nat
->in_global
;
172 nat_ret
->nat_out_local
= nat
->out_local
;
173 nat_ret
->nat_out_global
= nat
->out_global
;
175 nat_ret
->nat_in_local_port
= nat
->in_local_port
;
176 nat_ret
->nat_in_global_port
= nat
->in_global_port
;
177 nat_ret
->nat_out_local_port
= nat
->out_local_port
;
178 nat_ret
->nat_out_global_port
= nat
->out_global_port
;
189 * To show the kernel sticky table.
191 * cli: the client pointer making the request.
192 * req_si: information about the show-persist request.
193 * rbuf: reply buffer to be filled in.
194 * rbufsz: reply buffer size.
197 ilbd_show_sticky(void *cli
, const ilb_comm_t
*ic
, uint32_t *rbuf
,
200 ilb_show_info_t
*req_si
= (ilb_show_info_t
*)&ic
->ic_data
;
201 ilb_list_sticky_cmd_t
*kcmd
;
203 size_t tmp_rbufsz
, kbufsz
;
207 ilb_show_info_t
*reply
;
208 ilb_persist_info_t
*st_ret
;
210 /* For new client request, start from the beginning of the table. */
211 if (sticky_cur_cli
== NULL
) {
212 sticky_cur_cli
= cli
;
214 } else if (cli
== sticky_cur_cli
) {
216 * Another request from client. If the client does not
217 * want to continue, reset the current client and reply OK.
219 if (ic
->ic_flags
& ILB_COMM_END
) {
220 ilbd_show_sticky_cleanup();
221 ilbd_reply_ok(rbuf
, rbufsz
);
222 return (ILB_STATUS_OK
);
226 /* A request is on-going, so reject a new client. */
227 return (ILB_STATUS_INPROGRESS
);
230 tmp_rbufsz
= *rbufsz
;
231 ilbd_reply_ok(rbuf
, rbufsz
);
232 reply
= (ilb_show_info_t
*)&((ilb_comm_t
*)rbuf
)->ic_data
;
235 * Calculate the max number of ilb_persist_info_t can be fitted in the
238 *rbufsz
+= sizeof (ilb_show_info_t
*);
239 tmp_rbufsz
-= *rbufsz
;
240 max_num
= tmp_rbufsz
/ sizeof (ilb_persist_info_t
);
243 * Calculate the exact number of entries we should request from kernel.
245 max_num
= min(req_si
->sn_num
, min(NUM_ENTRIES
, max_num
));
247 kbufsz
= max_num
* sizeof (ilb_sticky_entry_t
) +
248 offsetof(ilb_list_sticky_cmd_t
, entries
);
249 if ((kcmd
= malloc(kbufsz
)) == NULL
) {
250 logdebug("ilbd_show_nat: malloc(cmd)");
251 ilbd_reply_err(rbuf
, rbufsz
, ILB_STATUS_ENOMEM
);
252 return (ILB_STATUS_ENOMEM
);
255 kcmd
->cmd
= ILB_LIST_STICKY_TABLE
;
256 kcmd
->flags
= start
? ILB_LIST_BEGIN
: ILB_LIST_CONT
;
257 kcmd
->num_sticky
= max_num
;
258 if ((ret
= do_ioctl(kcmd
, kbufsz
)) != ILB_STATUS_OK
) {
259 logperror("ilbd_show_nat: ioctl(ILB_LIST_STICKY_TABLE)");
260 ilbd_reply_err(rbuf
, rbufsz
, ret
);
265 reply
->sn_num
= kcmd
->num_sticky
;
266 *rbufsz
+= reply
->sn_num
* sizeof (ilb_persist_info_t
);
268 if (kcmd
->flags
& ILB_LIST_END
) {
269 sticky_cur_cli
= NULL
;
272 * ilbd_reply_ok() sets ic_flags to ILB_COMM_END by default.
273 * Need to clear it here.
275 ((ilb_comm_t
*)rbuf
)->ic_flags
= 0;
278 st_ret
= (ilb_persist_info_t
*)&reply
->sn_data
;
280 for (i
= 0; i
< kcmd
->num_sticky
; i
++) {
281 ilb_sticky_entry_t
*st
;
283 st
= &kcmd
->entries
[i
];
285 (void) strlcpy(st_ret
->persist_rule_name
, st
->rule_name
,
287 st_ret
->persist_req_addr
= st
->req_addr
;
288 st_ret
->persist_srv_addr
= st
->srv_addr
;