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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * RCM module to prevent plumbed IP addresses from being removed.
42 #include <sys/param.h>
44 #include <sys/types.h>
47 #include <sys/ioctl.h>
48 #include <sys/socket.h>
49 #include <sys/sockio.h>
52 #include <netinet/in.h>
53 #include <arpa/inet.h>
54 #include <netinet/ip6.h>
57 #include <libinetutil.h>
59 #include "rcm_module.h"
61 #define SUNW_IP "SUNW_ip/"
62 #define IP_REG_SIZE (9 + INET6_ADDRSTRLEN)
63 #define IP_ANON_USAGE gettext("Plumbed IP Address")
64 #define IP_SUSPEND_ERR gettext("Plumbed IP Addresses cannot be suspended")
65 #define IP_OFFLINE_ERR gettext("Invalid operation: IP cannot be offlined")
66 #define IP_REMOVE_ERR gettext("Invalid operation: IP cannot be removed")
67 #define IP_REG_FAIL gettext("Registration Failed")
69 #define IP_FLAG_NEW 0x00
70 #define IP_FLAG_REG 0x01
71 #define IP_FLAG_CL 0x02
72 #define IP_FLAG_IGNORE 0x04
73 #define IP_FLAG_DELETE 0x08
75 static int ip_anon_register(rcm_handle_t
*);
76 static int ip_anon_unregister(rcm_handle_t
*);
77 static int ip_anon_getinfo(rcm_handle_t
*, char *, id_t
, uint_t
,
78 char **, char **, nvlist_t
*, rcm_info_t
**);
79 static int ip_anon_suspend(rcm_handle_t
*, char *, id_t
,
80 timespec_t
*, uint_t
, char **, rcm_info_t
**);
81 static int ip_anon_resume(rcm_handle_t
*, char *, id_t
, uint_t
,
82 char **, rcm_info_t
**);
83 static int ip_anon_offline(rcm_handle_t
*, char *, id_t
, uint_t
,
84 char **, rcm_info_t
**);
85 static int ip_anon_online(rcm_handle_t
*, char *, id_t
, uint_t
,
86 char **, rcm_info_t
**);
87 static int ip_anon_remove(rcm_handle_t
*, char *, id_t
, uint_t
,
88 char **, rcm_info_t
**);
90 typedef struct ip_status
{
92 char device
[IP_REG_SIZE
];
93 struct ip_status
*next
;
96 static ip_status_t
*findreg(char *reg
);
97 static ip_status_t
*addreg(char *reg
);
98 static int deletereg(ip_status_t
*entry
);
100 static ip_status_t
*ip_list
= NULL
;
101 static mutex_t ip_list_lock
;
103 static struct rcm_mod_ops ip_anon_ops
=
122 return (&ip_anon_ops
);
128 return ("RCM IP address module 1.4");
136 /* free the registration list */
138 (void) mutex_lock(&ip_list_lock
);
139 while (ip_list
!= NULL
) {
140 tlist
= ip_list
->next
;
144 (void) mutex_unlock(&ip_list_lock
);
146 (void) mutex_destroy(&ip_list_lock
);
147 return (RCM_SUCCESS
);
151 ip_anon_register(rcm_handle_t
*hdl
)
153 struct ifaddrlist
*al
= NULL
, *al6
= NULL
;
154 char errbuf
[ERRBUFSIZE
];
155 char treg
[IP_REG_SIZE
], tstr
[IP_REG_SIZE
];
156 int num_ifs
, num_ifs6
, i
;
157 ip_status_t
*tlist
, *tentry
;
159 (void) mutex_lock(&ip_list_lock
);
161 rcm_log_message(RCM_DEBUG
, "ip_anon: registration refresh.\n");
163 /* obtain a list of all IPv4 and IPv6 addresses in the system */
165 rcm_log_message(RCM_DEBUG
,
166 "ip_anon: obtaining list of IPv4 addresses.\n");
167 num_ifs
= ifaddrlist(&al
, AF_INET
, LIFC_UNDER_IPMP
, errbuf
);
169 rcm_log_message(RCM_ERROR
,
170 gettext("cannot get IPv4 address list errno=%d (%s)\n"),
172 (void) mutex_unlock(&ip_list_lock
);
173 return (RCM_FAILURE
);
176 rcm_log_message(RCM_DEBUG
,
177 "ip_anon: obtaining list of IPv6 addresses.\n");
179 num_ifs6
= ifaddrlist(&al6
, AF_INET6
, LIFC_UNDER_IPMP
, errbuf
);
180 if (num_ifs6
== -1) {
181 rcm_log_message(RCM_ERROR
,
182 gettext("cannot get IPv6 address list errno=%d (%s)\n"),
185 (void) mutex_unlock(&ip_list_lock
);
186 return (RCM_FAILURE
);
189 /* check the state of outstanding registrations against the list */
191 rcm_log_message(RCM_DEBUG
,
192 "ip_anon: checking outstanding registrations.\n");
195 while (tlist
!= NULL
) {
196 tlist
->flags
|= IP_FLAG_DELETE
;
202 rcm_log_message(RCM_DEBUG
, "ip_anon: checking IPv4 addresses.\n");
204 for (i
= 0; i
< num_ifs
; i
++) {
205 (void) inet_ntop(AF_INET
, &al
[i
].addr
.addr
, tstr
,
207 (void) strcpy(treg
, SUNW_IP
);
208 (void) strcat(treg
, tstr
);
210 if ((tlist
= findreg(treg
)) == NULL
)
211 tlist
= addreg(treg
);
213 tlist
->flags
&= (~IP_FLAG_DELETE
);
216 rcm_log_message(RCM_ERROR
,
217 gettext("out of memory\n"));
220 (void) mutex_unlock(&ip_list_lock
);
221 return (RCM_FAILURE
);
227 rcm_log_message(RCM_DEBUG
, "ip_anon: checking IPv6 addresses.\n");
229 for (i
= 0; i
< num_ifs6
; i
++) {
230 (void) inet_ntop(AF_INET6
, &al6
[i
].addr
.addr
, tstr
,
232 (void) strcpy(treg
, SUNW_IP
);
233 (void) strcat(treg
, tstr
);
235 if ((tlist
= findreg(treg
)) == NULL
)
236 tlist
= addreg(treg
);
238 tlist
->flags
&= (~IP_FLAG_DELETE
);
241 rcm_log_message(RCM_ERROR
,
242 gettext("out of memory\n"));
245 (void) mutex_unlock(&ip_list_lock
);
246 return (RCM_FAILURE
);
250 rcm_log_message(RCM_DEBUG
, "ip_anon: updating reg. state.\n");
252 /* examine the list of ip address registrations and their state */
255 while (tlist
!= NULL
) {
259 if (tentry
->flags
& IP_FLAG_DELETE
) {
260 if (tentry
->flags
& IP_FLAG_REG
) {
261 rcm_log_message(RCM_DEBUG
,
262 "ip_anon: unregistering interest in %s\n",
264 if (rcm_unregister_interest(hdl
,
265 tentry
->device
, 0) != 0) {
266 rcm_log_message(RCM_ERROR
,
267 gettext("failed to unregister"));
270 (void) deletereg(tentry
);
271 } else if (!(tentry
->flags
& IP_FLAG_IGNORE
)) {
273 * If the registration is not a clustered devices and
274 * not already registered, then RCM doesn't
275 * currently know about it.
277 if (!(tentry
->flags
& IP_FLAG_CL
) &&
278 !(tentry
->flags
& IP_FLAG_REG
)) {
279 tentry
->flags
|= IP_FLAG_REG
;
280 rcm_log_message(RCM_DEBUG
,
281 "ip_anon: registering interest in %s\n",
283 if (rcm_register_interest(hdl
,
284 tentry
->device
, 0, NULL
) !=
286 rcm_log_message(RCM_ERROR
,
290 (void) mutex_unlock(&ip_list_lock
);
291 return (RCM_FAILURE
);
293 rcm_log_message(RCM_DEBUG
,
294 "ip_anon: registered %s\n",
300 * If the entry is registered and clustered, then
301 * the configuration has been changed and it
302 * should be unregistered.
304 if ((tentry
->flags
& IP_FLAG_REG
) &
305 (tentry
->flags
& IP_FLAG_CL
)) {
306 rcm_log_message(RCM_DEBUG
,
307 "ip_anon: unregistering in %s\n",
309 if (rcm_unregister_interest(hdl
,
310 tentry
->device
, 0) != 0) {
311 rcm_log_message(RCM_ERROR
,
312 gettext("failed to unregister"));
314 tentry
->flags
&= (~IP_FLAG_REG
);
320 while (tlist
!= NULL
) {
321 rcm_log_message(RCM_DEBUG
, "ip_anon: %s (%Xh)\n",
322 tlist
->device
, tlist
->flags
);
325 rcm_log_message(RCM_DEBUG
, "ip_anon: registration complete.\n");
329 (void) mutex_unlock(&ip_list_lock
);
330 return (RCM_SUCCESS
);
334 ip_anon_unregister(rcm_handle_t
*hdl
)
338 (void) mutex_lock(&ip_list_lock
);
341 while (tlist
!= NULL
) {
342 if ((tlist
->flags
& IP_FLAG_REG
)) {
343 if (rcm_unregister_interest(hdl
,
344 tlist
->device
, 0) != 0) {
345 rcm_log_message(RCM_ERROR
,
346 gettext("failed to unregister"));
348 tlist
->flags
&= (~IP_FLAG_REG
);
353 (void) mutex_unlock(&ip_list_lock
);
355 return (RCM_SUCCESS
);
360 ip_anon_getinfo(rcm_handle_t
*hdl
, char *rsrcname
, id_t id
, uint_t flags
,
361 char **infostr
, char **errstr
, nvlist_t
*props
, rcm_info_t
**dependent
)
364 assert(rsrcname
!= NULL
&& infostr
!= NULL
);
366 if ((*infostr
= strdup(IP_ANON_USAGE
)) == NULL
)
367 rcm_log_message(RCM_ERROR
, gettext("strdup failure\n"));
369 return (RCM_SUCCESS
);
374 ip_anon_suspend(rcm_handle_t
*hdl
, char *rsrcname
, id_t id
,
375 timespec_t
*interval
, uint_t flags
, char **errstr
,
376 rcm_info_t
**dependent
)
378 if ((*errstr
= strdup(IP_SUSPEND_ERR
)) == NULL
)
379 rcm_log_message(RCM_ERROR
, gettext("strdup failure\n"));
381 return (RCM_FAILURE
);
386 ip_anon_resume(rcm_handle_t
*hdl
, char *rsrcname
, id_t id
, uint_t flags
,
387 char **errstr
, rcm_info_t
**dependent
)
389 return (RCM_SUCCESS
);
394 ip_anon_offline(rcm_handle_t
*hdl
, char *rsrcname
, id_t id
, uint_t flags
,
395 char **errstr
, rcm_info_t
**dependent
)
397 if ((*errstr
= strdup(IP_OFFLINE_ERR
)) == NULL
)
398 rcm_log_message(RCM_ERROR
, gettext("strdup failure\n"));
400 return (RCM_FAILURE
);
405 ip_anon_online(rcm_handle_t
*hdl
, char *rsrcname
, id_t id
, uint_t flags
,
406 char **errstr
, rcm_info_t
**dependent
)
408 return (RCM_SUCCESS
);
413 ip_anon_remove(rcm_handle_t
*hdl
, char *rsrcname
, id_t id
, uint_t flags
,
414 char **errstr
, rcm_info_t
**dependent
)
416 if ((*errstr
= strdup(IP_REMOVE_ERR
)) == NULL
)
417 rcm_log_message(RCM_ERROR
, gettext("strdup failure\n"));
419 return (RCM_FAILURE
);
423 * Call with ip_list_lock held.
434 while ((tlist
!= NULL
) && (!done
)) {
435 if (strcmp(tlist
->device
, reg
) == 0)
447 ip_status_t
*tlist
, *tentry
;
449 tentry
= (ip_status_t
*)malloc(sizeof (ip_status_t
));
453 tentry
->flags
= IP_FLAG_NEW
;
455 (void) strcpy(tentry
->device
, reg
);
461 while (tlist
->next
!= NULL
)
463 tlist
->next
= tentry
;
470 deletereg(ip_status_t
*entry
)
477 if (entry
== ip_list
) {
478 ip_list
= ip_list
->next
;
482 while ((tlist
->next
!= NULL
) && (tlist
->next
!= entry
))
485 if (tlist
->next
!= entry
)
487 tlist
->next
= entry
->next
;