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