1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2016 Nexenta Systems, Inc.
25 */
26
27 #include <errno.h>
28 #include <sys/sockio.h>
29 #include <sys/list.h>
30 #include <string.h>
31 #include <assert.h>
32 #include <unistd.h>
33 #include <stropts.h>
34 #include <strings.h>
35 #include <libdlpi.h>
36 #include <libdllink.h>
37 #include <libinetutil.h>
38 #include <inet/ip.h>
39 #include <limits.h>
40 #include <zone.h>
41 #include <ipadm_ndpd.h>
42 #include <ipmp_query.h>
43 #include "libipadm_impl.h"
44
45 static ipadm_status_t i_ipadm_slifname_arp(char *, uint64_t, int);
46 static ipadm_status_t i_ipadm_slifname(ipadm_handle_t, char *, char *,
47 uint64_t, int, uint32_t);
48 static ipadm_status_t i_ipadm_create_ipmp_peer(ipadm_handle_t, char *,
49 sa_family_t);
50 static ipadm_status_t i_ipadm_persist_if(ipadm_handle_t, const char *,
51 sa_family_t, uint32_t);
52 static ipadm_status_t i_ipadm_allocate_ifinfo(ipadm_if_info_t **);
53 static ipadm_status_t i_ipadm_get_db_if(ipadm_handle_t, const char *,
54 nvlist_t **);
55 static ipadm_status_t i_ipadm_nvl2ifinfo(nvlist_t *, ipadm_if_info_t **);
56 static ipadm_status_t i_ipadm_fill_cmembers(char *, ipadm_ipmp_members_t *);
57 static ipadm_status_t i_ipadm_fill_pmembers(nvlist_t *, ipadm_ipmp_members_t *);
58 static ipadm_status_t i_ipadm_add_persistent_if_info(ipadm_if_info_t *,
59 ipadm_if_info_t *);
60 static void i_ipadm_free_ipmp_members(ipadm_ipmp_members_t *);
61 static ipadm_status_t i_ipadm_persist_update_ipmp(ipadm_handle_t, const char *,
62 const char *,
63 ipadm_ipmp_op_t);
64 static ipadm_status_t i_ipadm_update_ipmp(ipadm_handle_t, const char *,
65 const char *, uint32_t,
66 ipadm_ipmp_op_t);
67
68 /*
69 * Returns B_FALSE if the interface in `ifname' has at least one address that is
70 * IFF_UP in the addresses in `ifa'.
71 */
72 static boolean_t
73 i_ipadm_is_if_down(char *ifname, struct ifaddrs *ifa)
74 {
75 struct ifaddrs *ifap;
76 char cifname[LIFNAMSIZ];
77 char *sep;
78
79 for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
80 (void) strlcpy(cifname, ifap->ifa_name, sizeof (cifname));
81 if ((sep = strrchr(cifname, IPADM_LOGICAL_SEP)) != NULL)
82 *sep = '\0';
83 /*
84 * If this condition is true, there is at least one
85 * address that is IFF_UP. So, we need to return B_FALSE.
86 */
87 if (strcmp(cifname, ifname) == 0 &&
88 (ifap->ifa_flags & IFF_UP)) {
89 return (B_FALSE);
90 }
91 }
92 /* We did not find any IFF_UP addresses. */
93 return (B_TRUE);
94 }
95
96 /*
97 * Retrieves the information for the interface `ifname' from active
98 * config if `ifname' is specified and returns the result in the list `if_info'.
99 * Otherwise, it retrieves the information for all the interfaces in
100 * the active config and returns the result in the list `if_info'.
101 */
102 static ipadm_status_t
103 i_ipadm_active_if_info(ipadm_handle_t iph, const char *ifname,
104 ipadm_if_info_t **if_info, int64_t lifc_flags)
105 {
106 struct lifreq *buf;
107 struct lifreq *lifrp;
108 struct lifreq lifrl;
109 ipadm_if_info_t *last = NULL;
110 ipadm_if_info_t *ifp;
111 int s;
112 int n;
113 int numifs;
114 ipadm_status_t status;
115
116 *if_info = NULL;
117 /*
118 * Get information for all interfaces.
119 */
120 if (getallifs(iph->iph_sock, 0, &buf, &numifs, lifc_flags) != 0)
121 return (ipadm_errno2status(errno));
122
123 lifrp = buf;
124 for (n = 0; n < numifs; n++, lifrp++) {
125 /* Skip interfaces with logical num != 0 */
126 if (i_ipadm_get_lnum(lifrp->lifr_name) != 0)
127 continue;
128 /*
129 * Skip the current interface if a specific `ifname' has
130 * been requested and current interface does not match
131 * `ifname'.
132 */
133 if (ifname != NULL && strcmp(lifrp->lifr_name, ifname) != 0)
134 continue;
135 /*
136 * Check if the interface already exists in our list.
137 * If it already exists, we need to update its flags.
138 */
139 for (ifp = *if_info; ifp != NULL; ifp = ifp->ifi_next) {
140 if (strcmp(lifrp->lifr_name, ifp->ifi_name) == 0)
141 break;
142 }
143 if (ifp == NULL) {
144 if ((status =
145 i_ipadm_allocate_ifinfo(&ifp)) != IPADM_SUCCESS)
146 break;
147
148 (void) strlcpy(ifp->ifi_name, lifrp->lifr_name,
149 sizeof (ifp->ifi_name));
150 /* Update the `ifi_next' pointer for this new node */
151 if (*if_info == NULL)
152 *if_info = ifp;
153 else
154 last->ifi_next = ifp;
155 last = ifp;
156 }
157
158 /*
159 * Retrieve the flags for the interface by doing a
160 * SIOCGLIFFLAGS to populate the `ifi_cflags' field.
161 */
162 (void) strlcpy(lifrl.lifr_name,
163 lifrp->lifr_name, sizeof (lifrl.lifr_name));
164 s = (lifrp->lifr_addr.ss_family == AF_INET) ?
165 iph->iph_sock : iph->iph_sock6;
166 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0)
167 continue;
168
169 /* a regular interface by default */
170 ifp->ifi_class = IPADM_IF_CLASS_REGULAR;
171
172 if (lifrl.lifr_flags & IFF_BROADCAST)
173 ifp->ifi_cflags |= IFIF_BROADCAST;
174 if (lifrl.lifr_flags & IFF_MULTICAST)
175 ifp->ifi_cflags |= IFIF_MULTICAST;
176 if (lifrl.lifr_flags & IFF_POINTOPOINT)
177 ifp->ifi_cflags |= IFIF_POINTOPOINT;
178 if (lifrl.lifr_flags & IFF_VIRTUAL) {
179 ifp->ifi_cflags |= IFIF_VIRTUAL;
180 ifp->ifi_class = IPADM_IF_CLASS_VIRTUAL;
181 }
182 if (lifrl.lifr_flags & IFF_IPMP) {
183 ifp->ifi_cflags |= IFIF_IPMP;
184 ifp->ifi_class = IPADM_IF_CLASS_IPMP;
185 }
186 if (lifrl.lifr_flags & IFF_STANDBY)
187 ifp->ifi_cflags |= IFIF_STANDBY;
188 if (lifrl.lifr_flags & IFF_INACTIVE)
189 ifp->ifi_cflags |= IFIF_INACTIVE;
190 if (lifrl.lifr_flags & IFF_VRRP)
191 ifp->ifi_cflags |= IFIF_VRRP;
192 if (lifrl.lifr_flags & IFF_NOACCEPT)
193 ifp->ifi_cflags |= IFIF_NOACCEPT;
194 if (lifrl.lifr_flags & IFF_IPV4)
195 ifp->ifi_cflags |= IFIF_IPV4;
196 if (lifrl.lifr_flags & IFF_IPV6)
197 ifp->ifi_cflags |= IFIF_IPV6;
198 if (lifrl.lifr_flags & IFF_L3PROTECT)
199 ifp->ifi_cflags |= IFIF_L3PROTECT;
200
201 /* Retrieve active IPMP members */
202 if (ifp->ifi_class == IPADM_IF_CLASS_IPMP) {
203 if (ioctl(s, SIOCGLIFGROUPNAME,
204 (caddr_t)&lifrl) < 0) {
205 status = ipadm_errno2status(errno);
206 break;
207 }
208
209 if ((status = i_ipadm_fill_cmembers(
210 lifrl.lifr_groupname,
211 &ifp->ifi_ipmp_cmembers)) != IPADM_SUCCESS)
212 break;
213 }
214 }
215 free(buf);
216 if (status != IPADM_SUCCESS) {
217 ipadm_free_if_info(*if_info);
218 *if_info = NULL;
219 }
220 return (status);
221 }
222
223 /*
224 * Returns the interface information for `ifname' in `if_info' from persistent
225 * config if `ifname' is non-null. Otherwise, it returns all the interfaces
226 * from persistent config in `if_info'.
227 */
228 static ipadm_status_t
229 i_ipadm_persist_if_info(ipadm_handle_t iph, const char *ifname,
230 ipadm_if_info_t **if_info)
231 {
232 ipadm_status_t status = IPADM_SUCCESS;
233 nvlist_t *ifs_info_nvl;
234
235 *if_info = NULL;
236
237 if ((status = i_ipadm_get_db_if(iph,
238 ifname, &ifs_info_nvl)) != IPADM_SUCCESS)
239 return (status);
240
241 assert(ifs_info_nvl != NULL);
242
243 return (i_ipadm_nvl2ifinfo(ifs_info_nvl, if_info));
244 }
245
246 static ipadm_status_t
247 i_ipadm_nvl2ifinfo(nvlist_t *ifs_info_nvl, ipadm_if_info_t **if_info)
248 {
249 ipadm_if_info_t *ific = NULL, *ifil = NULL;
250 nvlist_t *if_info_nvl;
251 nvpair_t *nvp;
252 char *strval;
253 ipadm_status_t status = IPADM_SUCCESS;
254 uint16_t *families;
255 uint_t nelem = 0;
256
257 for (nvp = nvlist_next_nvpair(ifs_info_nvl, NULL); nvp != NULL;
258 nvp = nvlist_next_nvpair(ifs_info_nvl, nvp)) {
259 if (nvpair_value_nvlist(nvp, &if_info_nvl) != 0)
260 continue;
261
262 status = i_ipadm_allocate_ifinfo(&ific);
263 if (status != IPADM_SUCCESS) {
264 ipadm_free_if_info(*if_info);
265 break;
266 }
267 if (nvlist_lookup_string(if_info_nvl, IPADM_NVP_IFNAME,
268 &strval) != 0) {
269 ipadm_free_if_info(ific);
270 ific = NULL;
271 continue;
272 }
273 (void) strlcpy(ific->ifi_name, strval,
274 sizeof (ific->ifi_name));
275
276 if (nvlist_lookup_uint16_array(if_info_nvl,
277 IPADM_NVP_FAMILIES, &families, &nelem) == 0) {
278 while (nelem-- > 0) {
279 if (families[nelem] == AF_INET)
280 ific->ifi_pflags |= IFIF_IPV4;
281 else if (families[nelem] == AF_INET6)
282 ific->ifi_pflags |= IFIF_IPV6;
283 }
284 }
285
286 if (nvlist_lookup_string(if_info_nvl,
287 IPADM_NVP_IFCLASS, &strval) == 0)
288 ific->ifi_class = atoi(strval);
289 else
290 ific->ifi_class = IPADM_IF_CLASS_REGULAR;
291
292 if (ific->ifi_class == IPADM_IF_CLASS_IPMP)
293 /* do not expect any failures there */
294 (void) i_ipadm_fill_pmembers(if_info_nvl,
295 &ific->ifi_ipmp_pmembers);
296
297 if (*if_info == NULL)
298 *if_info = ific;
299 else
300 ifil->ifi_next = ific;
301 ifil = ific;
302 }
303
304 nvlist_free(ifs_info_nvl);
305 return (status);
306 }
307
308 /*
309 * Fill the ipadm_if_info_t->ifi_ipmp_pmembers by info from
310 * ipadm DB
311 */
312 static ipadm_status_t
313 i_ipadm_fill_pmembers(nvlist_t *if_info_nvl, ipadm_ipmp_members_t *pmembers)
314 {
315 uint_t nelem = 0;
316 char **members;
317 ipadm_ipmp_member_t *ipmp_member;
318
319 if (nvlist_lookup_string_array(if_info_nvl, IPADM_NVP_MIFNAMES,
320 &members, &nelem) != 0)
321 return (IPADM_SUCCESS);
322
323 while (nelem-- > 0) {
324 if ((ipmp_member = calloc(1,
325 sizeof (ipadm_ipmp_member_t))) == NULL)
326 return (ipadm_errno2status(errno));
327
328 (void) strlcpy(ipmp_member->if_name, members[nelem],
329 sizeof (ipmp_member->if_name));
330 list_insert_tail(pmembers, ipmp_member);
331 }
332 return (IPADM_SUCCESS);
333 }
334
335 /*
336 * Fill the ipadm_if_info_t->ifi_ipmp_cmembers by info from
337 * kernel (libipmp is used to retrieve the required info)
338 */
339 static ipadm_status_t
340 i_ipadm_fill_cmembers(char *grname, ipadm_ipmp_members_t *cmembers)
341 {
342 ipmp_handle_t ipmp_handle;
343 ipmp_groupinfo_t *grinfo;
344 ipmp_iflist_t *iflistp;
345 ipadm_ipmp_member_t *ipmp_member;
346 ipadm_status_t ipadm_status = IPADM_SUCCESS;
347 int i;
348
349 if (ipmp_open(&ipmp_handle) != IPMP_SUCCESS)
350 return (IPADM_FAILURE);
351
352 if (ipmp_getgroupinfo(ipmp_handle, grname, &grinfo) != IPMP_SUCCESS) {
353 ipadm_status = IPADM_FAILURE;
354 goto fail2;
355 }
356
357 iflistp = grinfo->gr_iflistp;
358 for (i = 0; i < iflistp->il_nif; i++) {
359 if ((ipmp_member = calloc(1,
360 sizeof (ipadm_ipmp_member_t))) == NULL) {
361 ipadm_status = ipadm_errno2status(errno);
362 goto fail1;
363 }
364 (void) strlcpy(ipmp_member->if_name, iflistp->il_ifs[i],
365 sizeof (ipmp_member->if_name));
366 list_insert_tail(cmembers, ipmp_member);
367 }
368
369 fail1:
370 ipmp_freegroupinfo(grinfo);
371 fail2:
372 ipmp_close(ipmp_handle);
373 return (ipadm_status);
374 }
375
376 /*
377 * Collects information for `ifname' if one is specified from both
378 * active and persistent config in `if_info'. If no `ifname' is specified,
379 * this returns all the interfaces in active and persistent config in
380 * `if_info'.
381 */
382 ipadm_status_t
383 i_ipadm_get_all_if_info(ipadm_handle_t iph, const char *ifname,
384 ipadm_if_info_t **if_info, int64_t lifc_flags)
385 {
386 ipadm_status_t status;
387 ipadm_if_info_t *aifinfo = NULL;
388 ipadm_if_info_t *pifinfo = NULL;
389 ipadm_if_info_t *aifp;
390 ipadm_if_info_t *pifp;
391 ipadm_if_info_t *last = NULL;
392 struct ifaddrs *ifa;
393 struct ifaddrs *ifap;
394
395 /*
396 * Retrive the information for the requested `ifname' or all
397 * interfaces from active configuration.
398 */
399 retry:
400 status = i_ipadm_active_if_info(iph, ifname, &aifinfo, lifc_flags);
401 if (status != IPADM_SUCCESS)
402 return (status);
403 /* Get the interface state for each interface in `aifinfo'. */
404 if (aifinfo != NULL) {
405 /* We need all addresses to get the interface state */
406 if (getallifaddrs(AF_UNSPEC, &ifa, (LIFC_NOXMIT|LIFC_TEMPORARY|
407 LIFC_ALLZONES|LIFC_UNDER_IPMP)) != 0) {
408 status = ipadm_errno2status(errno);
409 goto fail;
410 }
411 for (aifp = aifinfo; aifp != NULL; aifp = aifp->ifi_next) {
412 /*
413 * Find the `ifaddrs' structure from `ifa'
414 * for this interface. We need the IFF_* flags
415 * to find the interface state.
416 */
417 for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
418 if (strcmp(ifap->ifa_name, aifp->ifi_name) == 0)
419 break;
420 }
421 if (ifap == NULL) {
422 /*
423 * The interface might have been removed
424 * from kernel. Retry getting all the active
425 * interfaces.
426 */
427 freeifaddrs(ifa);
428 ipadm_free_if_info(aifinfo);
429 aifinfo = NULL;
430 goto retry;
431 }
432 if (!(ifap->ifa_flags & IFF_RUNNING) ||
433 (ifap->ifa_flags & IFF_FAILED))
434 aifp->ifi_state = IFIS_FAILED;
435 else if (ifap->ifa_flags & IFF_OFFLINE)
436 aifp->ifi_state = IFIS_OFFLINE;
437 else if (i_ipadm_is_if_down(aifp->ifi_name, ifa))
438 aifp->ifi_state = IFIS_DOWN;
439 else
440 aifp->ifi_state = IFIS_OK;
441 if (aifp->ifi_next == NULL)
442 last = aifp;
443 }
444 freeifaddrs(ifa);
445 }
446 /*
447 * Get the persistent interface information in `pifinfo'.
448 */
449 status = i_ipadm_persist_if_info(iph, ifname, &pifinfo);
450 if (status == IPADM_NOTFOUND) {
451 *if_info = aifinfo;
452 return (IPADM_SUCCESS);
453 }
454 if (status != IPADM_SUCCESS)
455 goto fail;
456 /*
457 * If a persistent interface is also found in `aifinfo', update
458 * its entry in `aifinfo' with the persistent information from
459 * `pifinfo'. If an interface is found in `pifinfo', but not in
460 * `aifinfo', it means that this interface was disabled. We should
461 * add this interface to `aifinfo' and set it state to IFIF_DISABLED.
462 */
463 for (pifp = pifinfo; pifp != NULL; pifp = pifp->ifi_next) {
464 for (aifp = aifinfo; aifp != NULL; aifp = aifp->ifi_next) {
465 if (strcmp(aifp->ifi_name, pifp->ifi_name) == 0) {
466 break;
467 }
468 }
469
470 if (aifp == NULL) {
471 if ((status =
472 i_ipadm_allocate_ifinfo(&aifp)) != IPADM_SUCCESS)
473 goto fail;
474
475 (void) strlcpy(aifp->ifi_name, pifp->ifi_name,
476 sizeof (aifp->ifi_name));
477
478 aifp->ifi_next = NULL;
479 aifp->ifi_state = IFIS_DISABLED;
480 if (last != NULL)
481 last->ifi_next = aifp;
482 else
483 aifinfo = aifp;
484 last = aifp;
485 }
486
487 if ((status = i_ipadm_add_persistent_if_info(aifp,
488 pifp)) != IPADM_SUCCESS)
489 goto fail;
490 }
491 *if_info = aifinfo;
492 ipadm_free_if_info(pifinfo);
493 return (IPADM_SUCCESS);
494 fail:
495 *if_info = NULL;
496 ipadm_free_if_info(aifinfo);
497 ipadm_free_if_info(pifinfo);
498 return (status);
499 }
500
501 /*
502 * Updates active if_info by data from persistent if_info
503 */
504 static ipadm_status_t
505 i_ipadm_add_persistent_if_info(ipadm_if_info_t *aifp, ipadm_if_info_t *pifp)
506 {
507 ipadm_ipmp_member_t *pp_ipmp_member, *ap_ipmp_member;
508
509 ipadm_ipmp_members_t *apmembers = &aifp->ifi_ipmp_pmembers;
510 ipadm_ipmp_members_t *ppmembers = &pifp->ifi_ipmp_pmembers;
511
512 aifp->ifi_pflags = pifp->ifi_pflags;
513 aifp->ifi_class = pifp->ifi_class;
514
515 for (pp_ipmp_member = list_head(ppmembers); pp_ipmp_member;
516 pp_ipmp_member = list_next(ppmembers, pp_ipmp_member)) {
517 if ((ap_ipmp_member = calloc(1,
518 sizeof (ipadm_ipmp_member_t))) == NULL)
519 return (ipadm_errno2status(errno));
520
521 (void) strlcpy(ap_ipmp_member->if_name,
522 pp_ipmp_member->if_name,
523 sizeof (ap_ipmp_member->if_name));
524
525 list_insert_tail(apmembers, ap_ipmp_member);
526 }
527 return (IPADM_SUCCESS);
528 }
529
530 static ipadm_status_t
531 i_ipadm_allocate_ifinfo(ipadm_if_info_t **if_info)
532 {
533 *if_info = calloc(1, sizeof (ipadm_if_info_t));
534 if (*if_info == NULL)
535 return (ipadm_errno2status(errno));
536
537 /* List of active (current) members */
538 list_create(&((*if_info)->ifi_ipmp_cmembers),
539 sizeof (ipadm_ipmp_member_t),
540 offsetof(ipadm_ipmp_member_t, node));
541
542 /* List of persistent members */
543 list_create(&((*if_info)->ifi_ipmp_pmembers),
544 sizeof (ipadm_ipmp_member_t),
545 offsetof(ipadm_ipmp_member_t, node));
546
547 return (IPADM_SUCCESS);
548 }
549
550 /*
551 * Reads all the interface lines from the persistent DB into the nvlist `onvl',
552 * when `ifname' is NULL.
553 * If an `ifname' is specified, then the interface line corresponding to
554 * that name will be returned.
555 */
556 static ipadm_status_t
557 i_ipadm_get_db_if(ipadm_handle_t iph, const char *ifname, nvlist_t **onvl)
558 {
559 ipmgmt_getif_arg_t garg;
560
561 /* Populate the door_call argument structure */
562 bzero(&garg, sizeof (garg));
563 garg.ia_cmd = IPMGMT_CMD_GETIF;
564 if (ifname != NULL)
565 (void) strlcpy(garg.ia_ifname, ifname, sizeof (garg.ia_ifname));
566
567 return (i_ipadm_call_ipmgmtd(iph, (void *) &garg, sizeof (garg), onvl));
568 }
569
570 int
571 i_ipadm_get_lnum(const char *ifname)
572 {
573 char *num = strrchr(ifname, IPADM_LOGICAL_SEP);
574
575 if (num == NULL)
576 return (0);
577
578 return (atoi(++num));
579 }
580
581 /*
582 * Sets the output argument `exists' to true or false based on whether
583 * any persistent configuration is available for `ifname' and returns
584 * IPADM_SUCCESS as status. If the persistent information cannot be retrieved,
585 * `exists' is unmodified and an error status is returned.
586 */
587 ipadm_status_t
588 i_ipadm_if_pexists(ipadm_handle_t iph, const char *ifname, sa_family_t af,
589 boolean_t *exists)
590 {
591 ipadm_if_info_t *ifinfo;
592 ipadm_status_t status;
593
594 /*
595 * if IPH_IPMGMTD is set, we know that the caller (ipmgmtd) already
596 * knows about persistent configuration in the first place, so we
597 * just return success.
598 */
599 if (iph->iph_flags & IPH_IPMGMTD) {
600 *exists = B_FALSE;
601 return (IPADM_SUCCESS);
602 }
603 status = i_ipadm_persist_if_info(iph, ifname, &ifinfo);
604 if (status == IPADM_SUCCESS) {
605 *exists = ((af == AF_INET &&
606 (ifinfo->ifi_pflags & IFIF_IPV4)) ||
607 (af == AF_INET6 &&
608 (ifinfo->ifi_pflags & IFIF_IPV6)));
609 ipadm_free_if_info(ifinfo);
610 } else if (status == IPADM_NOTFOUND) {
611 status = IPADM_SUCCESS;
612 *exists = B_FALSE;
613 }
614 return (status);
615 }
616
617 /*
618 * Open "/dev/udp{,6}" for use as a multiplexor to PLINK the interface stream
619 * under. We use "/dev/udp" instead of "/dev/ip" since STREAMS will not let
620 * you PLINK a driver under itself, and "/dev/ip" is typically the driver at
621 * the bottom of the stream for tunneling interfaces.
622 */
623 ipadm_status_t
624 ipadm_open_arp_on_udp(const char *udp_dev_name, int *fd)
625 {
626 int err;
627
628 if ((*fd = open(udp_dev_name, O_RDWR)) == -1)
629 return (ipadm_errno2status(errno));
630
631 /*
632 * Pop off all undesired modules (note that the user may have
633 * configured autopush to add modules above udp), and push the
634 * arp module onto the resulting stream. This is used to make
635 * IP+ARP be able to atomically track the muxid for the I_PLINKed
636 * STREAMS, thus it isn't related to ARP running the ARP protocol.
637 */
638 while (ioctl(*fd, I_POP, 0) != -1)
639 ;
640 if (errno == EINVAL && ioctl(*fd, I_PUSH, ARP_MOD_NAME) != -1)
641 return (IPADM_SUCCESS);
642 err = errno;
643 (void) close(*fd);
644
645 return (ipadm_errno2status(err));
646 }
647
648 /*
649 * i_ipadm_create_ipmp() is called from i_ipadm_create_ipmp_peer() when an
650 * underlying interface in an ipmp group G is plumbed for an address family,
651 * but the meta-interface for the other address family `af' does not exist
652 * yet for the group G. If `af' is IPv6, we need to bring up the
653 * link-local address.
654 */
655 static ipadm_status_t
656 i_ipadm_create_ipmp(ipadm_handle_t iph, char *ifname, sa_family_t af,
657 const char *grname, uint32_t ipadm_flags)
658 {
659 ipadm_status_t status;
660 struct lifreq lifr;
661 int sock;
662 int err;
663
664 assert(ipadm_flags & IPADM_OPT_IPMP);
665
666 /* Create the ipmp underlying interface */
667 status = i_ipadm_create_if(iph, ifname, af, ipadm_flags);
668 if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS)
669 return (status);
670
671 /*
672 * To preserve backward-compatibility, always bring up the link-local
673 * address for implicitly-created IPv6 IPMP interfaces.
674 */
675 if (af == AF_INET6)
676 (void) i_ipadm_set_flags(iph, ifname, AF_INET6, IFF_UP, 0);
677
678 sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
679 /*
680 * If the caller requested a different group name, issue a
681 * SIOCSLIFGROUPNAME on the new IPMP interface.
682 */
683 bzero(&lifr, sizeof (lifr));
684 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
685 if (strcmp(lifr.lifr_name, grname) != 0) {
686 (void) strlcpy(lifr.lifr_groupname, grname, LIFGRNAMSIZ);
687 if (ioctl(sock, SIOCSLIFGROUPNAME, &lifr) == -1) {
688 err = errno;
689 /* Remove the interface we created. */
690 if (status == IPADM_SUCCESS) {
691 (void) i_ipadm_delete_if(iph, ifname, af,
692 ipadm_flags);
693 }
694 return (ipadm_errno2status(err));
695 }
696 }
697
698 return (IPADM_SUCCESS);
699 }
700
701 /*
702 * Checks if `ifname' is plumbed and in an IPMP group on its "other" address
703 * family. If so, create a matching IPMP group for address family `af'.
704 */
705 static ipadm_status_t
706 i_ipadm_create_ipmp_peer(ipadm_handle_t iph, char *ifname, sa_family_t af)
707 {
708 lifgroupinfo_t lifgr;
709 ipadm_status_t status = IPADM_SUCCESS;
710 struct lifreq lifr;
711 int other_af_sock;
712
713 assert(af == AF_INET || af == AF_INET6);
714
715 other_af_sock = (af == AF_INET ? iph->iph_sock6 : iph->iph_sock);
716
717 /*
718 * iph is the handle for the interface that we are trying to plumb.
719 * other_af_sock is the socket for the "other" address family.
720 */
721 bzero(&lifr, sizeof (lifr));
722 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
723 if (ioctl(other_af_sock, SIOCGLIFGROUPNAME, &lifr) != 0)
724 return (IPADM_SUCCESS);
725
726 (void) strlcpy(lifgr.gi_grname, lifr.lifr_groupname, LIFGRNAMSIZ);
727 if (ioctl(other_af_sock, SIOCGLIFGROUPINFO, &lifgr) != 0)
728 return (IPADM_SUCCESS);
729
730 /*
731 * If `ifname' *is* the IPMP group interface, or if the relevant
732 * address family is already configured, then there's nothing to do.
733 */
734 if (strcmp(lifgr.gi_grifname, ifname) == 0 ||
735 (af == AF_INET && lifgr.gi_v4) || (af == AF_INET6 && lifgr.gi_v6)) {
736 return (IPADM_SUCCESS);
737 }
738
739 status = i_ipadm_create_ipmp(iph, lifgr.gi_grifname, af,
740 lifgr.gi_grname, IPADM_OPT_ACTIVE|IPADM_OPT_IPMP);
741 return (status);
742 }
743
744 /*
745 * Issues the ioctl SIOCSLIFNAME to kernel on the given ARP stream fd.
746 */
747 static ipadm_status_t
748 i_ipadm_slifname_arp(char *ifname, uint64_t flags, int fd)
749 {
750 struct lifreq lifr;
751 ifspec_t ifsp;
752
753 bzero(&lifr, sizeof (lifr));
754 (void) ifparse_ifspec(ifname, &ifsp);
755 lifr.lifr_ppa = ifsp.ifsp_ppa;
756 lifr.lifr_flags = flags;
757 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
758 /*
759 * Tell ARP the name and unit number for this interface.
760 * Note that arp has no support for transparent ioctls.
761 */
762 if (i_ipadm_strioctl(fd, SIOCSLIFNAME, (char *)&lifr,
763 sizeof (lifr)) == -1) {
764 return (ipadm_errno2status(errno));
765 }
766 return (IPADM_SUCCESS);
767 }
768
769 /*
770 * Issues the ioctl SIOCSLIFNAME to kernel. If IPADM_OPT_GENPPA is set in
771 * `ipadm_flags', then a ppa will be generated. `newif' will be updated
772 * with the generated ppa.
773 */
774 static ipadm_status_t
775 i_ipadm_slifname(ipadm_handle_t iph, char *ifname, char *newif, uint64_t flags,
776 int fd, uint32_t ipadm_flags)
777 {
778 struct lifreq lifr;
779 ipadm_status_t status = IPADM_SUCCESS;
780 int err = 0;
781 sa_family_t af;
782 int ppa;
783 ifspec_t ifsp;
784 boolean_t valid_if;
785
786 bzero(&lifr, sizeof (lifr));
787 if (ipadm_flags & IPADM_OPT_GENPPA) {
788 /*
789 * We'd like to just set lifr_ppa to UINT_MAX and have the
790 * kernel pick a PPA. Unfortunately, that would mishandle
791 * two cases:
792 *
793 * 1. If the PPA is available but the groupname is taken
794 * (e.g., the "ipmp2" IP interface name is available
795 * but the "ipmp2" groupname is taken) then the
796 * auto-assignment by the kernel will fail.
797 *
798 * 2. If we're creating (e.g.) an IPv6-only IPMP
799 * interface, and there's already an IPv4-only IPMP
800 * interface, the kernel will allow us to accidentally
801 * reuse the IPv6 IPMP interface name (since
802 * SIOCSLIFNAME uniqueness is per-interface-type).
803 * This will cause administrative confusion.
804 *
805 * Thus, we instead take a brute-force approach of checking
806 * whether the IPv4 or IPv6 name is already in-use before
807 * attempting the SIOCSLIFNAME. As per (1) above, the
808 * SIOCSLIFNAME may still fail, in which case we just proceed
809 * to the next one. If this approach becomes too slow, we
810 * can add a new SIOC* to handle this case in the kernel.
811 */
812 for (ppa = 0; ppa < UINT_MAX; ppa++) {
813 (void) snprintf(lifr.lifr_name, LIFNAMSIZ, "%s%d",
814 ifname, ppa);
815
816 if (ioctl(iph->iph_sock, SIOCGLIFFLAGS, &lifr) != -1 ||
817 errno != ENXIO)
818 continue;
819
820 if (ioctl(iph->iph_sock6, SIOCGLIFFLAGS, &lifr) != -1 ||
821 errno != ENXIO)
822 continue;
823
824 lifr.lifr_ppa = ppa;
825 lifr.lifr_flags = flags;
826
827 err = ioctl(fd, SIOCSLIFNAME, &lifr);
828 if (err != -1 || errno != EEXIST)
829 break;
830 }
831 if (err == -1) {
832 status = ipadm_errno2status(errno);
833 } else {
834 /*
835 * PPA has been successfully established.
836 * Update `newif' with the ppa.
837 */
838 assert(newif != NULL);
839 if (snprintf(newif, LIFNAMSIZ, "%s%d", ifname,
840 ppa) >= LIFNAMSIZ)
841 return (IPADM_INVALID_ARG);
842 }
843 } else {
844 /* We should have already validated the interface name. */
845 valid_if = ifparse_ifspec(ifname, &ifsp);
846 assert(valid_if);
847
848 /*
849 * Before we call SIOCSLIFNAME, ensure that the IPMP group
850 * interface for this address family exists. Otherwise, the
851 * kernel will kick the interface out of the group when we do
852 * the SIOCSLIFNAME.
853 *
854 * Example: suppose bge0 is plumbed for IPv4 and in group "a".
855 * If we're now plumbing bge0 for IPv6, but the IPMP group
856 * interface for "a" is not plumbed for IPv6, the SIOCSLIFNAME
857 * will kick bge0 out of group "a", which is undesired.
858 */
859 if (flags & IFF_IPV4)
860 af = AF_INET;
861 else
862 af = AF_INET6;
863 status = i_ipadm_create_ipmp_peer(iph, ifname, af);
864 if (status != IPADM_SUCCESS)
865 return (status);
866 lifr.lifr_ppa = ifsp.ifsp_ppa;
867 lifr.lifr_flags = flags;
868 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
869 if (ioctl(fd, SIOCSLIFNAME, &lifr) == -1)
870 status = ipadm_errno2status(errno);
871 }
872
873 return (status);
874 }
875
876 /*
877 * Plumbs the interface `ifname' for the address family `af'. It also persists
878 * the interface for `af' if IPADM_OPT_PERSIST is set in `ipadm_flags'.
879 */
880 ipadm_status_t
881 i_ipadm_plumb_if(ipadm_handle_t iph, char *ifname, sa_family_t af,
882 uint32_t ipadm_flags)
883 {
884 int ip_muxid;
885 int mux_fd = -1, ip_fd, arp_fd;
886 char *udp_dev_name;
887 dlpi_handle_t dh_arp = NULL, dh_ip;
888 uint64_t ifflags;
889 struct lifreq lifr;
890 uint_t dlpi_flags;
891 ipadm_status_t status = IPADM_SUCCESS;
892 char *linkname;
893 boolean_t legacy = (iph->iph_flags & IPH_LEGACY);
894 zoneid_t zoneid;
895 char newif[LIFNAMSIZ];
896 char lifname[LIFNAMSIZ];
897 datalink_id_t linkid;
898 int sock;
899 boolean_t islo;
900 boolean_t is_persistent =
901 ((ipadm_flags & IPADM_OPT_PERSIST) != 0);
902 uint32_t dlflags;
903 dladm_status_t dlstatus;
904
905 if (iph->iph_dlh != NULL) {
906 dlstatus = dladm_name2info(iph->iph_dlh, ifname, &linkid,
907 &dlflags, NULL, NULL);
908 }
909 /*
910 * If we're in the global zone and we're plumbing a datalink, make
911 * sure that the datalink is not assigned to a non-global zone. Note
912 * that the non-global zones don't need this check, because zoneadm
913 * has taken care of this when the zones boot.
914 */
915 if (iph->iph_zoneid == GLOBAL_ZONEID && dlstatus == DLADM_STATUS_OK) {
916 zoneid = ALL_ZONES;
917 if (zone_check_datalink(&zoneid, linkid) == 0) {
918 /* interface is in use by a non-global zone. */
919 return (IPADM_IF_INUSE);
920 }
921 }
922
923 /* loopback interfaces are just added as logical interface */
924 bzero(&lifr, sizeof (lifr));
925 islo = i_ipadm_is_loopback(ifname);
926 if (islo || i_ipadm_get_lnum(ifname) != 0) {
927 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
928 if (af == AF_INET)
929 sock = iph->iph_sock;
930 else
931 sock = iph->iph_sock6;
932 if (islo && ioctl(sock, SIOCGLIFADDR, (caddr_t)&lifr) >= 0)
933 return (IPADM_IF_EXISTS);
934 if (ioctl(sock, SIOCLIFADDIF, (caddr_t)&lifr) < 0)
935 return (ipadm_errno2status(errno));
936
937 /*
938 * By default, kernel configures 127.0.0.1 on the loopback
939 * interface. Replace this with 0.0.0.0 to be consistent
940 * with interface creation on other physical interfaces.
941 */
942 if (islo && !legacy) {
943 bzero(&lifr.lifr_addr, sizeof (lifr.lifr_addr));
944 lifr.lifr_addr.ss_family = af;
945 if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
946 return (ipadm_errno2status(errno));
947 if (is_persistent) {
948 status = i_ipadm_persist_if(iph,
949 ifname, af, ipadm_flags);
950 if (status != IPADM_SUCCESS) {
951 (void) i_ipadm_delete_if(iph, ifname,
952 af, IPADM_OPT_ACTIVE);
953 }
954 }
955 }
956 return (status);
957 }
958
959 dlpi_flags = DLPI_NOATTACH;
960
961 /*
962 * If IPADM_OPT_IPMP is specified, then this is a request
963 * to create an IPMP interface atop /dev/ipmpstub0. (We can't simply
964 * pass "ipmpstub0" as devname since an admin *could* have a normal
965 * vanity-named link named "ipmpstub0" that they'd like to plumb.)
966 */
967 if (ipadm_flags & IPADM_OPT_IPMP) {
968 dlpi_flags |= DLPI_DEVONLY;
969 linkname = "ipmpstub0";
970 } else {
971 /*
972 * Verify that the user is not creating a persistent
973 * IP interface on a non-persistent data-link.
974 */
975 if (!i_ipadm_is_vni(ifname) && dlstatus == DLADM_STATUS_OK &&
976 is_persistent && !(dlflags & DLADM_OPT_PERSIST)) {
977 return (IPADM_TEMPORARY_OBJ);
978 }
979 linkname = ifname;
980 }
981
982 /*
983 * We use DLPI_NOATTACH because the ip module will do the attach
984 * itself for DLPI style-2 devices.
985 */
986 if (dlpi_open(linkname, &dh_ip, dlpi_flags) != DLPI_SUCCESS)
987 return (IPADM_DLPI_FAILURE);
988 ip_fd = dlpi_fd(dh_ip);
989 if (ioctl(ip_fd, I_PUSH, IP_MOD_NAME) == -1) {
990 status = ipadm_errno2status(errno);
991 goto done;
992 }
993
994 /*
995 * Set IFF_IPV4/IFF_IPV6 flags. The kernel only allows modifications
996 * to IFF_IPv4, IFF_IPV6, IFF_BROADCAST, IFF_XRESOLV, IFF_NOLINKLOCAL.
997 */
998 ifflags = 0;
999
1000 /* Set the name string and the IFF_IPV* flag */
1001 if (af == AF_INET) {
1002 ifflags = IFF_IPV4;
1003 } else {
1004 ifflags = IFF_IPV6;
1005 /*
1006 * With the legacy method, the link-local address should be
1007 * configured as part of the interface plumb, using the default
1008 * token. If IPH_LEGACY is not specified, we want to set :: as
1009 * the address and require the admin to explicitly call
1010 * ipadm_create_addr() with the address object type set to
1011 * IPADM_ADDR_IPV6_ADDRCONF to create the link-local address
1012 * as well as the autoconfigured addresses.
1013 */
1014 if (!legacy && !i_ipadm_is_6to4(iph, ifname))
1015 ifflags |= IFF_NOLINKLOCAL;
1016 }
1017 (void) strlcpy(newif, ifname, sizeof (newif));
1018 status = i_ipadm_slifname(iph, ifname, newif, ifflags, ip_fd,
1019 ipadm_flags);
1020 if (status != IPADM_SUCCESS)
1021 goto done;
1022
1023 /* Get the full set of existing flags for this stream */
1024 status = i_ipadm_get_flags(iph, newif, af, &ifflags);
1025 if (status != IPADM_SUCCESS)
1026 goto done;
1027
1028 udp_dev_name = (af == AF_INET6 ? UDP6_DEV_NAME : UDP_DEV_NAME);
1029 status = ipadm_open_arp_on_udp(udp_dev_name, &mux_fd);
1030 if (status != IPADM_SUCCESS)
1031 goto done;
1032
1033 /* Check if arp is not needed */
1034 if (ifflags & (IFF_NOARP|IFF_IPV6)) {
1035 /*
1036 * PLINK the interface stream so that the application can exit
1037 * without tearing down the stream.
1038 */
1039 if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1)
1040 status = ipadm_errno2status(errno);
1041 goto done;
1042 }
1043
1044 /*
1045 * This interface does use ARP, so set up a separate stream
1046 * from the interface to ARP.
1047 *
1048 * We use DLPI_NOATTACH because the arp module will do the attach
1049 * itself for DLPI style-2 devices.
1050 */
1051 if (dlpi_open(linkname, &dh_arp, dlpi_flags) != DLPI_SUCCESS) {
1052 status = IPADM_DLPI_FAILURE;
1053 goto done;
1054 }
1055
1056 arp_fd = dlpi_fd(dh_arp);
1057 if (ioctl(arp_fd, I_PUSH, ARP_MOD_NAME) == -1) {
1058 status = ipadm_errno2status(errno);
1059 goto done;
1060 }
1061
1062 status = i_ipadm_slifname_arp(newif, ifflags, arp_fd);
1063 if (status != IPADM_SUCCESS)
1064 goto done;
1065 /*
1066 * PLINK the IP and ARP streams so that ifconfig can exit
1067 * without tearing down the stream.
1068 */
1069 if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1) {
1070 status = ipadm_errno2status(errno);
1071 goto done;
1072 }
1073
1074 if (ioctl(mux_fd, I_PLINK, arp_fd) < 0) {
1075 status = ipadm_errno2status(errno);
1076 (void) ioctl(mux_fd, I_PUNLINK, ip_muxid);
1077 }
1078
1079 done:
1080 dlpi_close(dh_ip);
1081 if (dh_arp != NULL)
1082 dlpi_close(dh_arp);
1083
1084 if (mux_fd != -1)
1085 (void) close(mux_fd);
1086
1087 if (status == IPADM_SUCCESS) {
1088 /* copy back new ifname */
1089 (void) strlcpy(ifname, newif, LIFNAMSIZ);
1090 /*
1091 * If it is a 6to4 tunnel, create a default
1092 * addrobj name for the default address on the 0'th
1093 * logical interface and set IFF_UP in the interface flags.
1094 */
1095 if (i_ipadm_is_6to4(iph, ifname)) {
1096 struct ipadm_addrobj_s addr;
1097
1098 i_ipadm_init_addr(&addr, ifname, "", IPADM_ADDR_STATIC);
1099 addr.ipadm_af = af;
1100 status = i_ipadm_lookupadd_addrobj(iph, &addr);
1101 if (status != IPADM_SUCCESS)
1102 return (status);
1103 status = ipadm_add_aobjname(iph, ifname,
1104 af, addr.ipadm_aobjname, IPADM_ADDR_STATIC, 0);
1105 if (status != IPADM_SUCCESS)
1106 return (status);
1107 addr.ipadm_lifnum = 0;
1108 i_ipadm_addrobj2lifname(&addr, lifname,
1109 sizeof (lifname));
1110 status = i_ipadm_set_flags(iph, lifname, af,
1111 IFF_UP, 0);
1112 if (status != IPADM_SUCCESS)
1113 return (status);
1114 } else {
1115 /*
1116 * Prevent static IPv6 addresses from triggering
1117 * autoconf. This does not have to be done for
1118 * 6to4 tunnel interfaces, since in.ndpd will
1119 * not autoconfigure those interfaces.
1120 */
1121 if (af == AF_INET6 && !legacy)
1122 (void) i_ipadm_disable_autoconf(newif);
1123 }
1124
1125 /*
1126 * If IPADM_OPT_PERSIST was set in flags, store the
1127 * interface in persistent DB.
1128 */
1129 if (is_persistent) {
1130 status = i_ipadm_persist_if(iph,
1131 newif, af, ipadm_flags);
1132 if (status != IPADM_SUCCESS) {
1133 (void) i_ipadm_delete_if(iph, newif, af,
1134 IPADM_OPT_ACTIVE);
1135 }
1136 }
1137 }
1138 if (status == IPADM_EXISTS)
1139 status = IPADM_IF_EXISTS;
1140 return (status);
1141 }
1142
1143 /*
1144 * Unplumbs the interface in `ifname' of family `af'.
1145 */
1146 ipadm_status_t
1147 i_ipadm_unplumb_if(ipadm_handle_t iph, const char *ifname, sa_family_t af)
1148 {
1149 int ip_muxid, arp_muxid;
1150 int mux_fd = -1;
1151 int muxid_fd = -1;
1152 char *udp_dev_name;
1153 uint64_t flags;
1154 boolean_t changed_arp_muxid = B_FALSE;
1155 int save_errno;
1156 struct lifreq lifr;
1157 ipadm_status_t ret = IPADM_SUCCESS;
1158 int sock;
1159 lifgroupinfo_t lifgr;
1160 ifaddrlistx_t *ifaddrs, *ifaddrp;
1161 boolean_t v6 = (af == AF_INET6);
1162
1163 /* Just do SIOCLIFREMOVEIF on loopback interfaces */
1164 bzero(&lifr, sizeof (lifr));
1165 if (i_ipadm_is_loopback(ifname) ||
1166 (i_ipadm_get_lnum(ifname) != 0 && (iph->iph_flags & IPH_LEGACY))) {
1167 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
1168 if (ioctl((af == AF_INET) ? iph->iph_sock : iph->iph_sock6,
1169 SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) {
1170 return (ipadm_errno2status(errno));
1171 }
1172 return (IPADM_SUCCESS);
1173 }
1174
1175 /*
1176 * We used /dev/udp or udp6 to set up the mux. So we have to use
1177 * the same now for PUNLINK also.
1178 */
1179 if (v6) {
1180 udp_dev_name = UDP6_DEV_NAME;
1181 sock = iph->iph_sock6;
1182 } else {
1183 udp_dev_name = UDP_DEV_NAME;
1184 sock = iph->iph_sock;
1185 }
1186 if ((muxid_fd = open(udp_dev_name, O_RDWR)) == -1) {
1187 ret = ipadm_errno2status(errno);
1188 goto done;
1189 }
1190 ret = ipadm_open_arp_on_udp(udp_dev_name, &mux_fd);
1191 if (ret != IPADM_SUCCESS)
1192 goto done;
1193 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
1194 if (ioctl(muxid_fd, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
1195 ret = ipadm_errno2status(errno);
1196 goto done;
1197 }
1198 flags = lifr.lifr_flags;
1199 again:
1200 if (flags & IFF_IPMP) {
1201 /*
1202 * There are two reasons the I_PUNLINK can fail with EBUSY:
1203 * (1) if IP interfaces are in the group, or (2) if IPMP data
1204 * addresses are administratively up. For case (1), we fail
1205 * here with a specific error message. For case (2), we bring
1206 * down the addresses prior to doing the I_PUNLINK. If the
1207 * I_PUNLINK still fails with EBUSY then the configuration
1208 * must have changed after our checks, in which case we branch
1209 * back up to `again' and rerun this logic. The net effect is
1210 * that unplumbing an IPMP interface will only fail with EBUSY
1211 * if IP interfaces are in the group.
1212 */
1213 if (ioctl(sock, SIOCGLIFGROUPNAME, &lifr) == -1) {
1214 ret = ipadm_errno2status(errno);
1215 goto done;
1216 }
1217 (void) strlcpy(lifgr.gi_grname, lifr.lifr_groupname,
1218 LIFGRNAMSIZ);
1219 if (ioctl(sock, SIOCGLIFGROUPINFO, &lifgr) == -1) {
1220 ret = ipadm_errno2status(errno);
1221 goto done;
1222 }
1223 if ((v6 && lifgr.gi_nv6 != 0) || (!v6 && lifgr.gi_nv4 != 0)) {
1224 ret = IPADM_GRP_NOTEMPTY;
1225 goto done;
1226 }
1227
1228 /*
1229 * The kernel will fail the I_PUNLINK if the IPMP interface
1230 * has administratively up addresses; bring them down.
1231 */
1232 if (ifaddrlistx(ifname, IFF_UP|IFF_DUPLICATE,
1233 0, &ifaddrs) == -1) {
1234 ret = ipadm_errno2status(errno);
1235 goto done;
1236 }
1237 ifaddrp = ifaddrs;
1238 for (; ifaddrp != NULL; ifaddrp = ifaddrp->ia_next) {
1239 int sock = (ifaddrp->ia_flags & IFF_IPV4) ?
1240 iph->iph_sock : iph->iph_sock6;
1241 struct lifreq lifrl;
1242
1243 if (((ifaddrp->ia_flags & IFF_IPV6) && !v6) ||
1244 (!(ifaddrp->ia_flags & IFF_IPV6) && v6))
1245 continue;
1246
1247 bzero(&lifrl, sizeof (lifrl));
1248 (void) strlcpy(lifrl.lifr_name, ifaddrp->ia_name,
1249 sizeof (lifrl.lifr_name));
1250 if (ioctl(sock, SIOCGLIFFLAGS, &lifrl) < 0) {
1251 ret = ipadm_errno2status(errno);
1252 ifaddrlistx_free(ifaddrs);
1253 goto done;
1254 }
1255 if (lifrl.lifr_flags & IFF_UP) {
1256 ret = i_ipadm_set_flags(iph, lifrl.lifr_name,
1257 ((lifrl.lifr_flags & IFF_IPV4) ? AF_INET :
1258 AF_INET6), 0, IFF_UP);
1259 if (ret != IPADM_SUCCESS) {
1260 ifaddrlistx_free(ifaddrs);
1261 goto done;
1262 }
1263 } else if (lifrl.lifr_flags & IFF_DUPLICATE) {
1264 if (ioctl(sock, SIOCGLIFADDR, &lifrl) < 0 ||
1265 ioctl(sock, SIOCSLIFADDR, &lifrl) < 0) {
1266 ret = ipadm_errno2status(errno);
1267 ifaddrlistx_free(ifaddrs);
1268 goto done;
1269 }
1270 }
1271 }
1272 ifaddrlistx_free(ifaddrs);
1273 }
1274
1275 if (ioctl(muxid_fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) {
1276 ret = ipadm_errno2status(errno);
1277 goto done;
1278 }
1279 arp_muxid = lifr.lifr_arp_muxid;
1280 ip_muxid = lifr.lifr_ip_muxid;
1281
1282 /*
1283 * We don't have a good way of knowing whether the arp stream is
1284 * plumbed. We can't rely on IFF_NOARP because someone could
1285 * have turned it off later using "ifconfig xxx -arp".
1286 */
1287 if (arp_muxid != 0) {
1288 if (ioctl(mux_fd, I_PUNLINK, arp_muxid) < 0) {
1289 /*
1290 * See the comment before the SIOCGLIFGROUPNAME call.
1291 */
1292 if (errno == EBUSY && (flags & IFF_IPMP))
1293 goto again;
1294
1295 if ((errno == EINVAL) &&
1296 (flags & (IFF_NOARP | IFF_IPV6))) {
1297 /*
1298 * Some plumbing utilities set the muxid to
1299 * -1 or some invalid value to signify that
1300 * there is no arp stream. Set the muxid to 0
1301 * before trying to unplumb the IP stream.
1302 * IP does not allow the IP stream to be
1303 * unplumbed if it sees a non-null arp muxid,
1304 * for consistency of IP-ARP streams.
1305 */
1306 lifr.lifr_arp_muxid = 0;
1307 (void) ioctl(muxid_fd, SIOCSLIFMUXID,
1308 (caddr_t)&lifr);
1309 changed_arp_muxid = B_TRUE;
1310 }
1311 /*
1312 * In case of any other error, we continue with
1313 * the unplumb.
1314 */
1315 }
1316 }
1317
1318 if (ioctl(mux_fd, I_PUNLINK, ip_muxid) < 0) {
1319 if (changed_arp_muxid) {
1320 /*
1321 * Some error occurred, and we need to restore
1322 * everything back to what it was.
1323 */
1324 save_errno = errno;
1325 lifr.lifr_arp_muxid = arp_muxid;
1326 lifr.lifr_ip_muxid = ip_muxid;
1327 (void) ioctl(muxid_fd, SIOCSLIFMUXID, (caddr_t)&lifr);
1328 errno = save_errno;
1329 }
1330 /*
1331 * See the comment before the SIOCGLIFGROUPNAME call.
1332 */
1333 if (errno == EBUSY && (flags & IFF_IPMP))
1334 goto again;
1335
1336 ret = ipadm_errno2status(errno);
1337 }
1338 done:
1339 if (muxid_fd != -1)
1340 (void) close(muxid_fd);
1341 if (mux_fd != -1)
1342 (void) close(mux_fd);
1343
1344 if (af == AF_INET6 && ret == IPADM_SUCCESS) {
1345 /*
1346 * in.ndpd maintains the phyints in its memory even after
1347 * the interface is plumbed, so that it can be reused when
1348 * the interface gets plumbed again. The default behavior
1349 * of in.ndpd is to start autoconfiguration for an interface
1350 * that gets plumbed. We need to send the
1351 * message IPADM_ENABLE_AUTOCONF to in.ndpd to restore this
1352 * default behavior on replumb.
1353 */
1354 (void) i_ipadm_enable_autoconf(ifname);
1355 }
1356 return (ret);
1357 }
1358
1359 /*
1360 * Saves the given interface name `ifname' with address family `af' in
1361 * persistent DB.
1362 */
1363 static ipadm_status_t
1364 i_ipadm_persist_if(ipadm_handle_t iph, const char *ifname, sa_family_t af,
1365 uint32_t ipadm_flags)
1366 {
1367 ipmgmt_if_arg_t ifarg;
1368 int err;
1369
1370 (void) strlcpy(ifarg.ia_ifname, ifname, sizeof (ifarg.ia_ifname));
1371 ifarg.ia_family = af;
1372 if (ipadm_flags & IPADM_OPT_IPMP)
1373 ifarg.ia_ifclass = IPADM_IF_CLASS_IPMP;
1374 else
1375 ifarg.ia_ifclass = IPADM_IF_CLASS_REGULAR;
1376
1377 ifarg.ia_cmd = IPMGMT_CMD_SETIF;
1378 ifarg.ia_flags = IPMGMT_PERSIST;
1379 err = ipadm_door_call(iph, &ifarg, sizeof (ifarg), NULL, 0, B_FALSE);
1380 return (ipadm_errno2status(err));
1381 }
1382
1383 /*
1384 * Remove the IP interface from active configuration. If IPADM_OPT_PERSIST
1385 * is set in `ipadm_flags', it is also removed from persistent configuration.
1386 */
1387 ipadm_status_t
1388 i_ipadm_delete_if(ipadm_handle_t iph, const char *ifname, sa_family_t af,
1389 uint32_t ipadm_flags)
1390 {
1391 ipadm_status_t ret = IPADM_SUCCESS;
1392 ipadm_status_t db_status;
1393 char tmp_ifname[LIFNAMSIZ];
1394 char *cp;
1395 struct ipadm_addrobj_s ipaddr;
1396 boolean_t is_persistent =
1397 (ipadm_flags & IPADM_OPT_PERSIST);
1398
1399 ret = i_ipadm_unplumb_if(iph, ifname, af);
1400 if (ret != IPADM_SUCCESS)
1401 goto done;
1402
1403 cp = strrchr(ifname, IPADM_LOGICAL_SEP);
1404 if (cp != NULL) {
1405 assert(iph->iph_flags & IPH_LEGACY);
1406 /*
1407 * This is a non-zero logical interface.
1408 * Find the addrobj and remove it from the daemon's memory.
1409 */
1410 (void) strlcpy(tmp_ifname, ifname, sizeof (tmp_ifname));
1411 tmp_ifname[cp - ifname] = '\0';
1412 *cp++ = '\0';
1413 ipaddr.ipadm_lifnum = atoi(cp);
1414 (void) strlcpy(ipaddr.ipadm_ifname, tmp_ifname,
1415 sizeof (ipaddr.ipadm_ifname));
1416 ipaddr.ipadm_af = af;
1417 ret = i_ipadm_get_lif2addrobj(iph, &ipaddr);
1418 if (ret == IPADM_SUCCESS) {
1419 ret = i_ipadm_delete_addrobj(iph, &ipaddr,
1420 IPADM_OPT_ACTIVE);
1421 } else if (ret == IPADM_NOTFOUND) {
1422 ret = IPADM_SUCCESS;
1423 }
1424 return (ret);
1425 }
1426 done:
1427 /*
1428 * Even if interface does not exist, remove all its addresses and
1429 * properties from the persistent store. If interface does not
1430 * exist both in kernel and the persistent store, return IPADM_ENXIO.
1431 */
1432 if ((ret == IPADM_ENXIO && is_persistent) || ret == IPADM_SUCCESS) {
1433 db_status = i_ipadm_delete_ifobj(iph, ifname, af,
1434 is_persistent);
1435 if (db_status == IPADM_SUCCESS)
1436 ret = IPADM_SUCCESS;
1437 }
1438
1439 return (ret);
1440 }
1441
1442 /*
1443 * Resets all addresses on interface `ifname' with address family `af'
1444 * from ipmgmtd daemon. If is_persistent = B_TRUE, all interface properties
1445 * and address objects of `ifname' for `af' are also removed from the
1446 * persistent DB.
1447 */
1448 ipadm_status_t
1449 i_ipadm_delete_ifobj(ipadm_handle_t iph, const char *ifname, sa_family_t af,
1450 boolean_t is_persistent)
1451 {
1452 ipmgmt_if_arg_t ifarg;
1453 int err;
1454
1455 ifarg.ia_cmd = IPMGMT_CMD_RESETIF;
1456 ifarg.ia_flags = IPMGMT_ACTIVE;
1457 if (is_persistent)
1458 ifarg.ia_flags |= IPMGMT_PERSIST;
1459 ifarg.ia_family = af;
1460 (void) strlcpy(ifarg.ia_ifname, ifname, LIFNAMSIZ);
1461
1462 err = ipadm_door_call(iph, &ifarg, sizeof (ifarg), NULL, 0, B_FALSE);
1463 return (ipadm_errno2status(err));
1464 }
1465
1466 /*
1467 * Create the interface by plumbing it for IP.
1468 * This function will check if there is saved configuration information
1469 * for `ifname' and return IPADM_OP_DISABLE_OBJ if the name-space
1470 * for `ifname' is taken.
1471 */
1472 ipadm_status_t
1473 i_ipadm_create_if(ipadm_handle_t iph, char *ifname, sa_family_t af,
1474 uint32_t ipadm_flags)
1475 {
1476 ipadm_status_t status;
1477 boolean_t p_exists;
1478 sa_family_t other_af;
1479
1480 /*
1481 * Return error, if the interface already exists in either the active
1482 * or the persistent configuration.
1483 */
1484 if (ipadm_if_enabled(iph, ifname, af))
1485 return (IPADM_IF_EXISTS);
1486
1487 if (!(iph->iph_flags & IPH_LEGACY)) {
1488 status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
1489 if (status != IPADM_SUCCESS)
1490 return (status);
1491 other_af = (af == AF_INET ? AF_INET6 : AF_INET);
1492 if (p_exists) {
1493 if (!ipadm_if_enabled(iph, ifname, other_af))
1494 return (IPADM_OP_DISABLE_OBJ);
1495 else
1496 ipadm_flags &= ~IPADM_OPT_PERSIST;
1497 }
1498 }
1499
1500 return (i_ipadm_plumb_if(iph, ifname, af, ipadm_flags));
1501 }
1502
1503 /*
1504 * Plumbs an interface. Creates both IPv4 and IPv6 interfaces by
1505 * default, unless a value in `af' is specified. The interface may be plumbed
1506 * only if there is no previously saved persistent configuration information
1507 * for the interface (in which case the ipadm_enable_if() function must
1508 * be used to enable the interface).
1509 *
1510 * Returns: IPADM_SUCCESS, IPADM_FAILURE, IPADM_IF_EXISTS,
1511 * IPADM_IF_PERSIST_EXISTS, IPADM_DLPI_FAILURE,
1512 * or appropriate ipadm_status_t corresponding to the errno.
1513 *
1514 * `ifname' must point to memory that can hold upto LIFNAMSIZ chars. It may
1515 * be over-written with the actual interface name when a PPA has to be
1516 * internally generated by the library.
1517 */
1518 ipadm_status_t
1519 ipadm_create_if(ipadm_handle_t iph, char *ifname, sa_family_t af,
1520 uint32_t flags)
1521 {
1522 ipadm_status_t status;
1523 boolean_t created_v4 = B_FALSE;
1524 char newifname[LIFNAMSIZ];
1525
1526 /* Check for the required authorization */
1527 if (!ipadm_check_auth())
1528 return (IPADM_EAUTH);
1529
1530 if (flags == 0 || ((flags & IPADM_OPT_PERSIST) &&
1531 !(flags & IPADM_OPT_ACTIVE)) ||
1532 (flags & ~(IPADM_COMMON_OPT_MASK | IPADM_OPT_IPMP |
1533 IPADM_OPT_GENPPA))) {
1534 return (IPADM_INVALID_ARG);
1535 }
1536 if (flags & IPADM_OPT_GENPPA) {
1537 if (snprintf(newifname, LIFNAMSIZ, "%s0", ifname) >=
1538 LIFNAMSIZ)
1539 return (IPADM_INVALID_ARG);
1540 } else {
1541 if (strlcpy(newifname, ifname, LIFNAMSIZ) >= LIFNAMSIZ)
1542 return (IPADM_INVALID_ARG);
1543 }
1544
1545 if (!i_ipadm_validate_ifname(iph, newifname))
1546 return (IPADM_INVALID_ARG);
1547
1548 if ((af == AF_INET || af == AF_UNSPEC) &&
1549 !i_ipadm_is_6to4(iph, ifname)) {
1550 status = i_ipadm_create_if(iph, ifname, AF_INET, flags);
1551 if (status != IPADM_SUCCESS)
1552 return (status);
1553 created_v4 = B_TRUE;
1554 }
1555 if (af == AF_INET6 || af == AF_UNSPEC) {
1556 status = i_ipadm_create_if(iph, ifname, AF_INET6, flags);
1557 if (status != IPADM_SUCCESS) {
1558 if (created_v4) {
1559 (void) i_ipadm_delete_if(iph, ifname, AF_INET,
1560 IPADM_OPT_ACTIVE);
1561 }
1562 return (status);
1563 }
1564 }
1565
1566 return (IPADM_SUCCESS);
1567 }
1568
1569 ipadm_status_t
1570 ipadm_add_ipmp_member(ipadm_handle_t iph, const char *gifname,
1571 const char *mifname, uint32_t ipadm_flags)
1572 {
1573 return (i_ipadm_update_ipmp(iph, gifname, mifname,
1574 ipadm_flags, IPADM_ADD_IPMP));
1575 }
1576
1577 ipadm_status_t
1578 ipadm_remove_ipmp_member(ipadm_handle_t iph, const char *gifname,
1579 const char *mifname, uint32_t ipadm_flags)
1580 {
1581 return (i_ipadm_update_ipmp(iph, gifname, mifname,
1582 ipadm_flags, IPADM_REMOVE_IPMP));
1583 }
1584
1585 /*
1586 * Updates active IPMP configuration according to the specified
1587 * command. It also persists the configuration if IPADM_OPT_PERSIST
1588 * is set in `ipadm_flags'.
1589 */
1590 static ipadm_status_t
1591 i_ipadm_update_ipmp(ipadm_handle_t iph, const char *gifname,
1592 const char *mifname, uint32_t ipadm_flags, ipadm_ipmp_op_t op)
1593 {
1594 ipadm_status_t status;
1595 char groupname1[LIFGRNAMSIZ];
1596 char groupname2[LIFGRNAMSIZ];
1597
1598 /* Check for the required authorization */
1599 if (!ipadm_check_auth())
1600 return (IPADM_EAUTH);
1601
1602 if (!(ipadm_flags & IPADM_OPT_ACTIVE) ||
1603 gifname == NULL || mifname == NULL)
1604 return (IPADM_INVALID_ARG);
1605
1606 if (!ipadm_if_enabled(iph, gifname, AF_UNSPEC) ||
1607 !ipadm_if_enabled(iph, mifname, AF_UNSPEC))
1608 return (IPADM_OP_DISABLE_OBJ);
1609
1610 if (!i_ipadm_is_ipmp(iph, gifname))
1611 return (IPADM_INVALID_ARG);
1612
1613 if (op == IPADM_ADD_IPMP && i_ipadm_is_under_ipmp(iph, mifname))
1614 return (IPADM_IF_INUSE);
1615
1616 if ((status = i_ipadm_get_groupname_active(iph, gifname,
1617 groupname2, sizeof (groupname2))) != IPADM_SUCCESS)
1618 return (status);
1619
1620 if (op == IPADM_REMOVE_IPMP) {
1621 if ((status = i_ipadm_get_groupname_active(iph, mifname,
1622 groupname1, sizeof (groupname1))) != IPADM_SUCCESS)
1623 return (status);
1624
1625 if (groupname1[0] == '\0' ||
1626 strcmp(groupname1, groupname2) != 0)
1627 return (IPADM_INVALID_ARG);
1628
1629 groupname2[0] = '\0';
1630 }
1631
1632 if ((ipadm_flags & IPADM_OPT_PERSIST) &&
1633 (status = i_ipadm_persist_update_ipmp(iph, gifname,
1634 mifname, op)) != IPADM_SUCCESS)
1635 return (status);
1636
1637 return (i_ipadm_set_groupname_active(iph, mifname, groupname2));
1638 }
1639
1640 /*
1641 * Call the ipmgmtd to update the IPMP configuration in ipadm DB.
1642 * After this call the DB will know that mifname is under gifname and
1643 * gifname has a member, which name is mifname.
1644 */
1645 static ipadm_status_t
1646 i_ipadm_persist_update_ipmp(ipadm_handle_t iph, const char *gifname,
1647 const char *mifname, ipadm_ipmp_op_t op)
1648 {
1649 ipmgmt_ipmp_update_arg_t args;
1650 int err;
1651
1652 assert(op == IPADM_ADD_IPMP || op == IPADM_REMOVE_IPMP);
1653
1654 bzero(&args, sizeof (ipmgmt_ipmp_update_arg_t));
1655
1656 args.ia_cmd = IPMGMT_CMD_IPMP_UPDATE;
1657
1658 (void) strlcpy(args.ia_gifname, gifname, sizeof (args.ia_gifname));
1659 (void) strlcpy(args.ia_mifname, mifname, sizeof (args.ia_mifname));
1660
1661 if (op == IPADM_ADD_IPMP)
1662 args.ia_flags = IPMGMT_APPEND;
1663 else
1664 args.ia_flags = IPMGMT_REMOVE;
1665
1666 args.ia_flags |= IPMGMT_PERSIST;
1667
1668 err = ipadm_door_call(iph, &args, sizeof (args), NULL, 0, B_FALSE);
1669 return (ipadm_errno2status(err));
1670 }
1671
1672 /*
1673 * Deletes the interface in `ifname'. Removes both IPv4 and IPv6 interfaces
1674 * when `af' = AF_UNSPEC.
1675 */
1676 ipadm_status_t
1677 ipadm_delete_if(ipadm_handle_t iph, const char *ifname, sa_family_t af,
1678 uint32_t flags)
1679 {
1680 ipadm_status_t status1 = IPADM_SUCCESS;
1681 ipadm_status_t status2 = IPADM_SUCCESS;
1682 ipadm_status_t other;
1683
1684 /* Check for the required authorization */
1685 if (!ipadm_check_auth())
1686 return (IPADM_EAUTH);
1687
1688 /* Validate the `ifname' for any logical interface. */
1689 if (flags == 0 || (flags & ~(IPADM_COMMON_OPT_MASK)) ||
1690 !i_ipadm_validate_ifname(iph, ifname))
1691 return (IPADM_INVALID_ARG);
1692
1693 if (af == AF_INET || af == AF_UNSPEC)
1694 status1 = i_ipadm_delete_if(iph, ifname, AF_INET, flags);
1695 if (af == AF_INET6 || af == AF_UNSPEC)
1696 status2 = i_ipadm_delete_if(iph, ifname, AF_INET6, flags);
1697 /*
1698 * If the family has been uniquely identified, we return the
1699 * associated status, even if that is ENXIO. Calls from ifconfig
1700 * which can only unplumb one of IPv4/IPv6 at any time fall under
1701 * this category.
1702 */
1703 if (af == AF_INET)
1704 return (status1);
1705 else if (af == AF_INET6)
1706 return (status2);
1707 else if (af != AF_UNSPEC)
1708 return (IPADM_INVALID_ARG);
1709
1710 /*
1711 * If af is AF_UNSPEC, then we return the following:
1712 * status1, if status1 == status2
1713 * IPADM_SUCCESS, if either of status1 or status2 is SUCCESS
1714 * and the other status is ENXIO
1715 * IPADM_ENXIO, if both status1 and status2 are ENXIO
1716 * IPADM_FAILURE otherwise.
1717 */
1718 if (status1 == status2) {
1719 /* covers the case when both status1 and status2 are ENXIO */
1720 return (status1);
1721 } else if (status1 == IPADM_SUCCESS || status2 == IPADM_SUCCESS) {
1722 if (status1 == IPADM_SUCCESS)
1723 other = status2;
1724 else
1725 other = status1;
1726 return (other == IPADM_ENXIO ? IPADM_SUCCESS : IPADM_FAILURE);
1727 } else {
1728 return (IPADM_FAILURE);
1729 }
1730 }
1731
1732 /*
1733 * Returns information about all interfaces in both active and persistent
1734 * configuration. If `ifname' is not NULL, it returns only the interface
1735 * identified by `ifname'.
1736 *
1737 * Return values:
1738 * On success: IPADM_SUCCESS.
1739 * On error : IPADM_INVALID_ARG, IPADM_ENXIO or IPADM_FAILURE.
1740 */
1741 ipadm_status_t
1742 ipadm_if_info(ipadm_handle_t iph, const char *ifname,
1743 ipadm_if_info_t **if_info, uint32_t flags, int64_t lifc_flags)
1744 {
1745 ipadm_status_t status;
1746 ifspec_t ifsp;
1747
1748 if (if_info == NULL || iph == NULL || flags != 0)
1749 return (IPADM_INVALID_ARG);
1750
1751 if (ifname != NULL &&
1752 (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)) {
1753 return (IPADM_INVALID_ARG);
1754 }
1755
1756 status = i_ipadm_get_all_if_info(iph, ifname, if_info, lifc_flags);
1757 if (status != IPADM_SUCCESS)
1758 return (status);
1759 if (ifname != NULL && *if_info == NULL)
1760 return (IPADM_ENXIO);
1761
1762 return (IPADM_SUCCESS);
1763 }
1764
1765 /*
1766 * Frees the linked list allocated by ipadm_if_info().
1767 */
1768 void
1769 ipadm_free_if_info(ipadm_if_info_t *ifinfo)
1770 {
1771 ipadm_if_info_t *ifinfo_next;
1772
1773 for (; ifinfo != NULL; ifinfo = ifinfo_next) {
1774 ifinfo_next = ifinfo->ifi_next;
1775 i_ipadm_free_ipmp_members(&ifinfo->ifi_ipmp_cmembers);
1776 i_ipadm_free_ipmp_members(&ifinfo->ifi_ipmp_pmembers);
1777 free(ifinfo);
1778 }
1779 }
1780
1781 static void
1782 i_ipadm_free_ipmp_members(ipadm_ipmp_members_t *ipmp_members)
1783 {
1784 ipadm_ipmp_member_t *ipmp_member;
1785
1786 while ((ipmp_member = list_remove_head(ipmp_members)) != NULL)
1787 free(ipmp_member);
1788
1789 list_destroy(ipmp_members);
1790 }
1791
1792 /*
1793 * Re-enable the interface `ifname' based on the saved configuration
1794 * for `ifname'.
1795 */
1796 ipadm_status_t
1797 ipadm_enable_if(ipadm_handle_t iph, const char *ifname, uint32_t flags)
1798 {
1799 nvlist_t *ifnvl;
1800 ipadm_status_t status;
1801 ifspec_t ifsp;
1802
1803 /* Check for the required authorization */
1804 if (!ipadm_check_auth())
1805 return (IPADM_EAUTH);
1806
1807 /* Check for logical interfaces. */
1808 if (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)
1809 return (IPADM_INVALID_ARG);
1810
1811 /* Enabling an interface persistently is not supported. */
1812 if (flags & IPADM_OPT_PERSIST)
1813 return (IPADM_NOTSUP);
1814
1815 /*
1816 * Return early by checking if the interface is already enabled.
1817 */
1818 if (ipadm_if_enabled(iph, ifname, AF_INET) &&
1819 ipadm_if_enabled(iph, ifname, AF_INET6))
1820 return (IPADM_IF_EXISTS);
1821
1822 /*
1823 * Enable the interface and restore all its interface properties
1824 * and address objects.
1825 */
1826 status = i_ipadm_init_ifs(iph, ifname, &ifnvl);
1827 if (status != IPADM_SUCCESS)
1828 return (status);
1829
1830 assert(ifnvl != NULL);
1831 /*
1832 * ipadm_enable_if() does exactly what ipadm_init_ifs() does,
1833 * but only for one interface. We need to set IPH_INIT because
1834 * ipmgmtd daemon does not have to write the interface to persistent
1835 * db. The interface is already available in persistent db
1836 * and we are here to re-enable the persistent configuration.
1837 */
1838 iph->iph_flags |= IPH_INIT;
1839 status = i_ipadm_init_ifobj(iph, ifname, ifnvl);
1840 iph->iph_flags &= ~IPH_INIT;
1841
1842 nvlist_free(ifnvl);
1843 return (status);
1844 }
1845
1846 /*
1847 * Disable the interface `ifname' by removing it from the active configuration.
1848 * Error code return values follow the model in ipadm_delete_if()
1849 */
1850 ipadm_status_t
1851 ipadm_disable_if(ipadm_handle_t iph, const char *ifname, uint32_t flags)
1852 {
1853 ipadm_status_t status1, status2, other;
1854 ifspec_t ifsp;
1855
1856 /* Check for the required authorization */
1857 if (!ipadm_check_auth())
1858 return (IPADM_EAUTH);
1859
1860 /* Check for logical interfaces. */
1861 if (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)
1862 return (IPADM_INVALID_ARG);
1863
1864 /* Disabling an interface persistently is not supported. */
1865 if (flags & IPADM_OPT_PERSIST)
1866 return (IPADM_NOTSUP);
1867
1868 status1 = i_ipadm_unplumb_if(iph, ifname, AF_INET6);
1869 if (status1 == IPADM_SUCCESS)
1870 status1 = i_ipadm_delete_ifobj(iph, ifname, AF_INET6, B_FALSE);
1871 status2 = i_ipadm_unplumb_if(iph, ifname, AF_INET);
1872 if (status2 == IPADM_SUCCESS)
1873 status2 = i_ipadm_delete_ifobj(iph, ifname, AF_INET, B_FALSE);
1874 if (status1 == status2) {
1875 return (status2);
1876 } else if (status1 == IPADM_SUCCESS || status2 == IPADM_SUCCESS) {
1877 if (status1 == IPADM_SUCCESS)
1878 other = status2;
1879 else
1880 other = status1;
1881 return (other == IPADM_ENXIO ? IPADM_SUCCESS : IPADM_FAILURE);
1882 } else {
1883 return (IPADM_FAILURE);
1884 }
1885 }
1886
1887 /*
1888 * FIXME Remove this when ifconfig(1M) is updated to use IPMP support
1889 * in libipadm.
1890 */
1891 /*
1892 * This workaround is required by ifconfig(1M) whenever an
1893 * interface is moved into an IPMP group to update the daemon's
1894 * in-memory mapping of `aobjname' to 'lifnum'.
1895 *
1896 * For `IPMGMT_ACTIVE' case, i_ipadm_delete_ifobj() would only fail if
1897 * door_call(3C) fails. Also, there is no use in returning error because
1898 * `ifname' would have been successfuly moved into IPMP group, by this time.
1899 */
1900 void
1901 ipadm_if_move(ipadm_handle_t iph, const char *ifname)
1902 {
1903 (void) i_ipadm_delete_ifobj(iph, ifname, AF_INET, B_FALSE);
1904 (void) i_ipadm_delete_ifobj(iph, ifname, AF_INET6, B_FALSE);
1905 }
1906
1907 ipadm_status_t
1908 i_ipadm_set_groupname_active(ipadm_handle_t iph, const char *ifname,
1909 const char *groupname)
1910 {
1911 struct lifreq lifr;
1912 ipadm_addr_info_t *addrinfo, *ia;
1913 ipadm_status_t status = IPADM_SUCCESS;
1914
1915 (void) memset(&lifr, 0, sizeof (lifr));
1916
1917 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
1918 (void) strlcpy(lifr.lifr_groupname, groupname,
1919 sizeof (lifr.lifr_groupname));
1920
1921 /* Disable all addresses on the interface */
1922 (void) i_ipadm_active_addr_info(iph, ifname, &addrinfo,
1923 IPADM_OPT_ACTIVE, IFF_UP | IFF_DUPLICATE);
1924 for (ia = addrinfo; ia != NULL; ia = IA_NEXT(ia))
1925 (void) ipadm_disable_addr(iph, ia->ia_aobjname, 0);
1926
1927 if (ioctl(iph->iph_sock, SIOCSLIFGROUPNAME, (caddr_t)&lifr) == -1 &&
1928 ioctl(iph->iph_sock6, SIOCSLIFGROUPNAME, (caddr_t)&lifr) == -1)
1929 status = ipadm_errno2status(errno);
1930
1931 /* Enable all addresses on the interface */
1932 for (ia = addrinfo; ia != NULL; ia = IA_NEXT(ia))
1933 (void) ipadm_enable_addr(iph, ia->ia_aobjname, 0);
1934
1935 if (status == IPADM_SUCCESS) {
1936 if (groupname[0] == '\0') {
1937 /*
1938 * If interface was removed from IPMP group, unset the
1939 * DEPRECATED and NOFAILOVER flags.
1940 */
1941 (void) i_ipadm_set_flags(iph, ifname, AF_INET, 0,
1942 IFF_DEPRECATED | IFF_NOFAILOVER);
1943 (void) i_ipadm_set_flags(iph, ifname, AF_INET6, 0,
1944 IFF_DEPRECATED | IFF_NOFAILOVER);
1945 } else if (addrinfo == NULL) {
1946 /*
1947 * If interface was added to IPMP group and there are no
1948 * active addresses, explicitly bring it up to be used
1949 * for link-based IPMP configuration.
1950 */
1951 (void) i_ipadm_set_flags(iph, ifname, AF_INET,
1952 IFF_UP, 0);
1953 (void) i_ipadm_set_flags(iph, ifname, AF_INET6,
1954 IFF_UP, 0);
1955 }
1956 }
1957
1958 ipadm_free_addr_info(addrinfo);
1959
1960 return (status);
1961 }
1962
1963 ipadm_status_t
1964 i_ipadm_get_groupname_active(ipadm_handle_t iph, const char *ifname,
1965 char *groupname, size_t size)
1966 {
1967 struct lifreq lifr;
1968
1969 (void) memset(&lifr, 0, sizeof (lifr));
1970
1971 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
1972
1973 if (ioctl(iph->iph_sock, SIOCGLIFGROUPNAME, (caddr_t)&lifr) == -1 &&
1974 ioctl(iph->iph_sock6, SIOCGLIFGROUPNAME, (caddr_t)&lifr) == -1)
1975 return (ipadm_errno2status(errno));
1976
1977 (void) strlcpy(groupname, lifr.lifr_groupname, size);
1978
1979 return (IPADM_SUCCESS);
1980 }
1981
1982 /*
1983 * Returns B_TRUE if `ifname' represents an IPMP underlying interface.
1984 */
1985 boolean_t
1986 i_ipadm_is_under_ipmp(ipadm_handle_t iph, const char *ifname)
1987 {
1988
1989 char groupname[LIFGRNAMSIZ];
1990
1991 if (i_ipadm_get_groupname_active(iph, ifname, groupname,
1992 sizeof (groupname)) != IPADM_SUCCESS ||
1993 groupname[0] == '\0' ||
1994 strcmp(ifname, groupname) == 0)
1995 return (B_FALSE);
1996
1997 return (B_TRUE);
1998 }
1999
2000 /*
2001 * Returns B_TRUE if `ifname' represents an IPMP group interface.
2002 */
2003 boolean_t
2004 i_ipadm_is_ipmp(ipadm_handle_t iph, const char *ifname)
2005 {
2006 uint64_t flags, flags6;
2007
2008 if (i_ipadm_get_flags(iph, ifname, AF_INET, &flags) != IPADM_SUCCESS &&
2009 i_ipadm_get_flags(iph, ifname, AF_INET6, &flags6) != IPADM_SUCCESS)
2010 return (B_FALSE);
2011
2012 return ((flags & IFF_IPMP) != 0 || (flags6 & IFF_IPMP) != 0);
2013 }