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.
29 #include <sys/types.h>
30 #include <sys/socket.h>
34 #include <libilb_impl.h>
59 * since the difference between two uint64_ts can be greater than
60 * what a int64_t can hold, we need to cap the result at +/- INT64_MAX
61 * return: < 0: x < y, 0: x == y, > 0: x > y
64 signed_diff64(uint64_t x
, uint64_t y
)
72 /* make sure we have x < y */
82 return (INT64_MAX
* s
);
84 return ((int64_t)ud
* s
);
88 unsigned_diff64(uint64_t x
, uint64_t y
, int *sgn
)
95 /* make sure we have x < y */
107 * compare ip addresses ip1 and ip2 (as unsigned integers)
108 * return: -1: ip1 < ip2, 0: ip1 == ip2, 1: ip1 > ip2
109 * input addresses are assumed to be in network byte order
110 * diff contains the difference between the two with the same
111 * sign as the comparison result;
112 * NOTE: since ipv6 address (difference)s can be more than a 64bit
113 * value can express, the difference is capped at +/- INT64_MAX
116 i_cmp_addr_impl(void *ip1
, void *ip2
, ip_addr_type_t atype
, int64_t *diff
)
118 struct in6_addr
*a6_1
, *a6_2
;
124 if (atype
== internal
) {
125 af
= GET_AF((struct in6_addr
*)ip1
);
127 IN6_V4MAPPED_TO_IPADDR((struct in6_addr
*)ip1
, i1
);
128 IN6_V4MAPPED_TO_IPADDR((struct in6_addr
*)ip2
, i2
);
133 a6_1
= (struct in6_addr
*)ip1
;
134 a6_2
= (struct in6_addr
*)ip2
;
137 af
= ((ilb_ip_addr_t
*)ip1
)->ia_af
;
139 struct in_addr
*a1
, *a2
;
141 a1
= &((ilb_ip_addr_t
*)ip1
)->ia_v4
;
142 a2
= &((ilb_ip_addr_t
*)ip2
)->ia_v4
;
144 l1
= ntohl((uint32_t)a1
->s_addr
);
145 l2
= ntohl((uint32_t)a2
->s_addr
);
147 a6_1
= &((ilb_ip_addr_t
*)ip1
)->ia_v6
;
148 a6_2
= &((ilb_ip_addr_t
*)ip2
)->ia_v6
;
154 sgn
= sign32((int32_t)d
);
157 * we're facing the dilemma that 128-bit ipv6 addresses are
158 * larger than the largest integer type - int64_t.
159 * we handle this thus:
160 * 1. seperate high-order and low-order bits (64 each) into
161 * *h and *l variables (unsigned).
162 * 2. calculate difference for *h and *l:
165 * 3. if high-order diff == 0, we can take low-order
166 * diff, if necessary cap it, convert it to signed
168 * 4. if high-order and low-order signs are the same, the low-
169 * order bits won't significantly impact high-order
170 * difference, so we know that we've overflowed an int64_t;
171 * if high-order diff is > 1, any low-order difference won't
172 * change the overflow.
173 * 5. (dh == 1 and l_sign <= 0) or (dh == -1 and l_sign > 0),
175 * 5a. if dl < INT64_MAX, the result is still > INT64_MAX, so
177 * 5b. dl >= INT64_MAX
178 * we need to express (for dh == 1):
179 * (2^64) + x (where x < 0).
180 * Since the largest number we have is
181 * 2^64 - 1 == UINT64_MAX
185 * for dh == -1, all we have is
186 * -(2^63 - 1), so to express
188 * we first do (dl - (2^63-1)) (which is then also < 2^63),
189 * si we can then add that to -(2^63 - 1);
198 i1h
= INV6_N2H_MSB64(a6_1
);
199 i1l
= INV6_N2H_LSB64(a6_1
);
200 i2h
= INV6_N2H_MSB64(a6_2
);
201 i2l
= INV6_N2H_LSB64(a6_2
);
204 dh
= signed_diff64(i1h
, i2h
);
205 dl
= unsigned_diff64(i1l
, i2l
, &l_sign
);
214 } else if (l_sign
== sign64(dh
) || abs(dh
) > 1) {
221 if (dl
< INT64_MAX
) {
225 d
= UINT64_MAX
- dl
+ 1;
227 d
= -INT64_MAX
- (dl
- INT64_MAX
) - 1;
240 ilb_cmp_in6_addr(struct in6_addr
*ip1
, struct in6_addr
*ip2
, int64_t *diff
)
244 res
= i_cmp_addr_impl(ip1
, ip2
, internal
, diff
);
249 ilb_cmp_ipaddr(ilb_ip_addr_t
*ip1
, ilb_ip_addr_t
*ip2
, int64_t *diff
)
253 res
= i_cmp_addr_impl(ip1
, ip2
, external
, diff
);
258 * Error strings for error values returned by libilb functions
261 ilb_errstr(ilb_status_t rc
)
265 return (dgettext(TEXT_DOMAIN
, "no error"));
266 case ILB_STATUS_INTERNAL
:
267 return (dgettext(TEXT_DOMAIN
, "error internal to the library"));
268 case ILB_STATUS_EINVAL
:
269 return (dgettext(TEXT_DOMAIN
, "invalid argument(s) - see"
271 case ILB_STATUS_ENOMEM
:
272 return (dgettext(TEXT_DOMAIN
, "not enough memory"
274 case ILB_STATUS_ENOENT
:
275 return (dgettext(TEXT_DOMAIN
, "no such/no more element(s)"));
276 case ILB_STATUS_SOCKET
:
277 return (dgettext(TEXT_DOMAIN
, "socket() failed"));
278 case ILB_STATUS_READ
:
279 return (dgettext(TEXT_DOMAIN
, "read() failed"));
280 case ILB_STATUS_WRITE
:
281 return (dgettext(TEXT_DOMAIN
, "fflush() or send() failed"));
282 case ILB_STATUS_TIMER
:
283 return (dgettext(TEXT_DOMAIN
, "health check timer"
284 " create/setup error"));
285 case ILB_STATUS_INUSE
:
286 return (dgettext(TEXT_DOMAIN
, "object is in use,"
288 case ILB_STATUS_EEXIST
:
289 return (dgettext(TEXT_DOMAIN
, "object already exists"));
290 case ILB_STATUS_PERMIT
:
291 return (dgettext(TEXT_DOMAIN
, "no scf permit"));
292 case ILB_STATUS_CALLBACK
:
293 return (dgettext(TEXT_DOMAIN
, "scf callback error"));
294 case ILB_STATUS_INPROGRESS
:
295 return (dgettext(TEXT_DOMAIN
, "operation is progress"));
296 case ILB_STATUS_SEND
:
297 return (dgettext(TEXT_DOMAIN
, "send() failed"));
298 case ILB_STATUS_ENOHCINFO
:
299 return (dgettext(TEXT_DOMAIN
, "missing healthcheck info"));
300 case ILB_STATUS_INVAL_HCTESTTYPE
:
301 return (dgettext(TEXT_DOMAIN
, "invalid health check"
303 case ILB_STATUS_INVAL_CMD
:
304 return (dgettext(TEXT_DOMAIN
, "invalid command"));
305 case ILB_STATUS_DUP_RULE
:
306 return (dgettext(TEXT_DOMAIN
, "specified rule name already"
308 case ILB_STATUS_ENORULE
:
309 return (dgettext(TEXT_DOMAIN
, "specified rule does not exist"));
310 case ILB_STATUS_MISMATCHSG
:
311 return (dgettext(TEXT_DOMAIN
, "address family mismatch with"
313 case ILB_STATUS_MISMATCHH
:
314 return (dgettext(TEXT_DOMAIN
, "address family mismatch"
315 " with previous hosts in servergroup or with rule"));
316 case ILB_STATUS_SGUNAVAIL
:
317 return (dgettext(TEXT_DOMAIN
, "cannot find specified"
319 case ILB_STATUS_SGINUSE
:
320 return (dgettext(TEXT_DOMAIN
, "cannot remove server"
321 " group - its in use with other active rules"));
322 case ILB_STATUS_SGEXISTS
:
323 return (dgettext(TEXT_DOMAIN
, "servergroup already exists"));
324 case ILB_STATUS_SGFULL
:
325 return (dgettext(TEXT_DOMAIN
, "servergroup is full - cannot"
326 " add any more servers to this servergroup"));
327 case ILB_STATUS_SGEMPTY
:
328 return (dgettext(TEXT_DOMAIN
, "servergroup does not contain"
330 case ILB_STATUS_NAMETOOLONG
:
331 return (dgettext(TEXT_DOMAIN
, "servergroup name can"
332 " only contain a maximum of 14 characters"));
333 case ILB_STATUS_CFGAUTH
:
334 return (dgettext(TEXT_DOMAIN
, "user is not authorized to"
335 " execute command"));
336 case ILB_STATUS_CFGUPDATE
:
337 return (dgettext(TEXT_DOMAIN
, "a failure occurred while trying"
338 " to update persistent config. Panic?"));
339 case ILB_STATUS_BADSG
:
340 return (dgettext(TEXT_DOMAIN
, "the rule's port range"
341 " does not match that of the servers' in associated"
343 case ILB_STATUS_INVAL_SRVR
:
344 return (dgettext(TEXT_DOMAIN
, "server cannot be added to the"
345 " servergroup, as the servergroup is associated to rule(s)"
346 " with port/port range that is incompatible"
347 "with the server's port"));
348 case ILB_STATUS_INVAL_ENBSRVR
:
349 return (dgettext(TEXT_DOMAIN
, "server cannot be enabled"
350 " because it's not associated with any rule"));
351 case ILB_STATUS_BADPORT
:
352 return (dgettext(TEXT_DOMAIN
, "the rule's port value does"
353 " not match that of the servers' in"
354 " associated servergroup"));
355 case ILB_STATUS_SRVUNAVAIL
:
356 return (dgettext(TEXT_DOMAIN
, "cannot find specified server"));
357 case ILB_STATUS_RULE_NO_HC
:
358 return (dgettext(TEXT_DOMAIN
, "rule does not have health "
360 case ILB_STATUS_RULE_HC_MISMATCH
:
361 return (dgettext(TEXT_DOMAIN
, "protocol used in rule and "
362 "health check does not match"));
363 case ILB_STATUS_HANDLE_CLOSING
:
364 return (dgettext(TEXT_DOMAIN
, "handle is being closed"));
367 return (dgettext(TEXT_DOMAIN
, "unknown error"));
371 /* Allocate space for a specified request to be sent to ilbd. */
373 i_ilb_alloc_req(ilbd_cmd_t cmd
, size_t *ic_sz
)
378 sz
= sizeof (ilb_comm_t
);
381 case ILBD_CREATE_RULE
:
382 sz
+= sizeof (ilb_rule_info_t
);
385 case ILBD_RETRIEVE_RULE
:
386 case ILBD_DESTROY_RULE
:
387 case ILBD_ENABLE_RULE
:
388 case ILBD_DISABLE_RULE
:
389 case ILBD_RETRIEVE_SG_HOSTS
:
390 case ILBD_DESTROY_SERVERGROUP
:
391 case ILBD_CREATE_SERVERGROUP
:
392 case ILBD_DESTROY_HC
:
393 case ILBD_GET_HC_INFO
:
394 case ILBD_GET_HC_SRVS
:
395 sz
+= sizeof (ilbd_name_t
);
398 case ILBD_ENABLE_SERVER
:
399 case ILBD_DISABLE_SERVER
:
400 case ILBD_ADD_SERVER_TO_GROUP
:
401 case ILBD_REM_SERVER_FROM_GROUP
:
402 case ILBD_SRV_ADDR2ID
:
403 case ILBD_SRV_ID2ADDR
:
404 sz
+= sizeof (ilb_sg_info_t
) + sizeof (ilb_sg_srv_t
);
408 sz
+= sizeof (ilb_hc_info_t
);
412 /* Should not reach here. */
417 if ((ic
= calloc(1, sz
)) == NULL
)