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