3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 #include <errno.h>
26 #include <sys/sockio.h>
27 #include <string.h>
28 #include <assert.h>
29 #include <unistd.h>
30 #include <stropts.h>
31 #include <strings.h>
32 #include <libdlpi.h>
33 #include <libdllink.h>
34 #include <libinetutil.h>
35 #include <inet/ip.h>
36 #include <limits.h>
37 #include <zone.h>
38 #include <ipadm_ndpd.h>
39 #include "libipadm_impl.h"
40
41 static ipadm_status_t i_ipadm_slifname_arp(char *, uint64_t, int);
42 static ipadm_status_t i_ipadm_slifname(ipadm_handle_t, char *, char *,
43 uint64_t, int, uint32_t);
44 static ipadm_status_t i_ipadm_create_ipmp_peer(ipadm_handle_t, char *,
45 sa_family_t);
46 static ipadm_status_t i_ipadm_persist_if(ipadm_handle_t, const char *,
47 sa_family_t);
48
49 /*
50 * Returns B_FALSE if the interface in `ifname' has at least one address that is
51 * IFF_UP in the addresses in `ifa'.
52 */
53 static boolean_t
54 i_ipadm_is_if_down(char *ifname, struct ifaddrs *ifa)
55 {
56 struct ifaddrs *ifap;
57 char cifname[LIFNAMSIZ];
58 char *sep;
59
60 for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
61 (void) strlcpy(cifname, ifap->ifa_name, sizeof (cifname));
62 if ((sep = strrchr(cifname, IPADM_LOGICAL_SEP)) != NULL)
63 *sep = '\0';
64 /*
65 * If this condition is true, there is at least one
66 * address that is IFF_UP. So, we need to return B_FALSE.
67 */
105 for (n = 0; n < numifs; n++, lifrp++) {
106 /* Skip interfaces with logical num != 0 */
107 if (i_ipadm_get_lnum(lifrp->lifr_name) != 0)
108 continue;
109 /*
110 * Skip the current interface if a specific `ifname' has
111 * been requested and current interface does not match
112 * `ifname'.
113 */
114 if (ifname != NULL && strcmp(lifrp->lifr_name, ifname) != 0)
115 continue;
116 /*
117 * Check if the interface already exists in our list.
118 * If it already exists, we need to update its flags.
119 */
120 for (ifp = *if_info; ifp != NULL; ifp = ifp->ifi_next) {
121 if (strcmp(lifrp->lifr_name, ifp->ifi_name) == 0)
122 break;
123 }
124 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 }
130 (void) strlcpy(ifp->ifi_name, lifrp->lifr_name,
131 sizeof (ifp->ifi_name));
132 /* Update the `ifi_next' pointer for this new node */
133 if (*if_info == NULL)
134 *if_info = ifp;
135 else
136 last->ifi_next = ifp;
137 last = ifp;
138 }
139
140 /*
141 * Retrieve the flags for the interface by doing a
142 * SIOCGLIFFLAGS to populate the `ifi_cflags' field.
143 */
144 (void) strlcpy(lifrl.lifr_name,
145 lifrp->lifr_name, sizeof (lifrl.lifr_name));
146 s = (lifrp->lifr_addr.ss_family == AF_INET) ?
147 iph->iph_sock : iph->iph_sock6;
148 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0)
149 continue;
150 if (lifrl.lifr_flags & IFF_BROADCAST)
151 ifp->ifi_cflags |= IFIF_BROADCAST;
152 if (lifrl.lifr_flags & IFF_MULTICAST)
153 ifp->ifi_cflags |= IFIF_MULTICAST;
154 if (lifrl.lifr_flags & IFF_POINTOPOINT)
155 ifp->ifi_cflags |= IFIF_POINTOPOINT;
156 if (lifrl.lifr_flags & IFF_VIRTUAL)
157 ifp->ifi_cflags |= IFIF_VIRTUAL;
158 if (lifrl.lifr_flags & IFF_IPMP)
159 ifp->ifi_cflags |= IFIF_IPMP;
160 if (lifrl.lifr_flags & IFF_STANDBY)
161 ifp->ifi_cflags |= IFIF_STANDBY;
162 if (lifrl.lifr_flags & IFF_INACTIVE)
163 ifp->ifi_cflags |= IFIF_INACTIVE;
164 if (lifrl.lifr_flags & IFF_VRRP)
165 ifp->ifi_cflags |= IFIF_VRRP;
166 if (lifrl.lifr_flags & IFF_NOACCEPT)
167 ifp->ifi_cflags |= IFIF_NOACCEPT;
168 if (lifrl.lifr_flags & IFF_IPV4)
169 ifp->ifi_cflags |= IFIF_IPV4;
170 if (lifrl.lifr_flags & IFF_IPV6)
171 ifp->ifi_cflags |= IFIF_IPV6;
172 if (lifrl.lifr_flags & IFF_L3PROTECT)
173 ifp->ifi_cflags |= IFIF_L3PROTECT;
174 }
175 free(buf);
176 return (IPADM_SUCCESS);
177 fail:
178 free(buf);
179 ipadm_free_if_info(*if_info);
180 *if_info = NULL;
181 return (status);
182 }
183
184 /*
185 * Returns the interface information for `ifname' in `if_info' from persistent
186 * config if `ifname' is non-null. Otherwise, it returns all the interfaces
187 * from persistent config in `if_info'.
188 */
189 static ipadm_status_t
190 i_ipadm_persist_if_info(ipadm_handle_t iph, const char *ifname,
191 ipadm_if_info_t **if_info)
192 {
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;
198
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 *if_info = NULL;
205
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 }
219
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);
226 break;
227 }
228 (void) bcopy(ifp, curr, sizeof (*curr));
229 curr->ifi_next = prev;
230 prev = curr;
231 }
232 *if_info = curr;
233 free(rvalp);
234 return (status);
235 }
236
237 /*
238 * Collects information for `ifname' if one is specified from both
239 * active and persistent config in `if_info'. If no `ifname' is specified,
240 * this returns all the interfaces in active and persistent config in
241 * `if_info'.
242 */
243 ipadm_status_t
244 i_ipadm_get_all_if_info(ipadm_handle_t iph, const char *ifname,
245 ipadm_if_info_t **if_info, int64_t lifc_flags)
246 {
247 ipadm_status_t status;
248 ipadm_if_info_t *aifinfo = NULL;
249 ipadm_if_info_t *pifinfo = NULL;
250 ipadm_if_info_t *aifp;
251 ipadm_if_info_t *pifp;
252 ipadm_if_info_t *last = NULL;
253 struct ifaddrs *ifa;
254 struct ifaddrs *ifap;
307 /*
308 * Get the persistent interface information in `pifinfo'.
309 */
310 status = i_ipadm_persist_if_info(iph, ifname, &pifinfo);
311 if (status == IPADM_NOTFOUND) {
312 *if_info = aifinfo;
313 return (IPADM_SUCCESS);
314 }
315 if (status != IPADM_SUCCESS)
316 goto fail;
317 /*
318 * If a persistent interface is also found in `aifinfo', update
319 * its entry in `aifinfo' with the persistent information from
320 * `pifinfo'. If an interface is found in `pifinfo', but not in
321 * `aifinfo', it means that this interface was disabled. We should
322 * add this interface to `aifinfo' and set it state to IFIF_DISABLED.
323 */
324 for (pifp = pifinfo; pifp != NULL; pifp = pifp->ifi_next) {
325 for (aifp = aifinfo; aifp != NULL; aifp = aifp->ifi_next) {
326 if (strcmp(aifp->ifi_name, pifp->ifi_name) == 0) {
327 aifp->ifi_pflags = pifp->ifi_pflags;
328 break;
329 }
330 }
331 if (aifp == NULL) {
332 aifp = malloc(sizeof (ipadm_if_info_t));
333 if (aifp == NULL) {
334 status = ipadm_errno2status(errno);
335 goto fail;
336 }
337 *aifp = *pifp;
338 aifp->ifi_next = NULL;
339 aifp->ifi_state = IFIS_DISABLED;
340 if (last != NULL)
341 last->ifi_next = aifp;
342 else
343 aifinfo = aifp;
344 last = aifp;
345 }
346 }
347 *if_info = aifinfo;
348 ipadm_free_if_info(pifinfo);
349 return (IPADM_SUCCESS);
350 fail:
351 *if_info = NULL;
352 ipadm_free_if_info(aifinfo);
353 ipadm_free_if_info(pifinfo);
354 return (status);
355 }
356
357 int
358 i_ipadm_get_lnum(const char *ifname)
359 {
360 char *num = strrchr(ifname, IPADM_LOGICAL_SEP);
361
362 if (num == NULL)
363 return (0);
364
365 return (atoi(++num));
366 }
367
368 /*
369 * Sets the output argument `exists' to true or false based on whether
370 * any persistent configuration is available for `ifname' and returns
371 * IPADM_SUCCESS as status. If the persistent information cannot be retrieved,
372 * `exists' is unmodified and an error status is returned.
373 */
374 ipadm_status_t
375 i_ipadm_if_pexists(ipadm_handle_t iph, const char *ifname, sa_family_t af,
376 boolean_t *exists)
377 {
378 ipadm_if_info_t *ifinfo;
379 ipadm_status_t status;
380
381 /*
382 * if IPH_IPMGMTD is set, we know that the caller (ipmgmtd) already
383 * knows about persistent configuration in the first place, so we
384 * just return success.
385 */
386 if (iph->iph_flags & IPH_IPMGMTD) {
387 *exists = B_FALSE;
388 return (IPADM_SUCCESS);
389 }
390 status = i_ipadm_persist_if_info(iph, ifname, &ifinfo);
391 if (status == IPADM_SUCCESS) {
392 *exists = ((af == AF_INET &&
393 (ifinfo->ifi_pflags & IFIF_IPV4)) ||
394 (af == AF_INET6 &&
395 (ifinfo->ifi_pflags & IFIF_IPV6)));
396 free(ifinfo);
397 } else if (status == IPADM_NOTFOUND) {
398 status = IPADM_SUCCESS;
399 *exists = B_FALSE;
400 }
401 return (status);
402 }
403
404 /*
405 * Open "/dev/udp{,6}" for use as a multiplexor to PLINK the interface stream
406 * under. We use "/dev/udp" instead of "/dev/ip" since STREAMS will not let
407 * you PLINK a driver under itself, and "/dev/ip" is typically the driver at
408 * the bottom of the stream for tunneling interfaces.
409 */
410 ipadm_status_t
411 ipadm_open_arp_on_udp(const char *udp_dev_name, int *fd)
412 {
413 int err;
414
415 if ((*fd = open(udp_dev_name, O_RDWR)) == -1)
416 return (ipadm_errno2status(errno));
715 if (af == AF_INET)
716 sock = iph->iph_sock;
717 else
718 sock = iph->iph_sock6;
719 if (islo && ioctl(sock, SIOCGLIFADDR, (caddr_t)&lifr) >= 0)
720 return (IPADM_IF_EXISTS);
721 if (ioctl(sock, SIOCLIFADDIF, (caddr_t)&lifr) < 0)
722 return (ipadm_errno2status(errno));
723
724 /*
725 * By default, kernel configures 127.0.0.1 on the loopback
726 * interface. Replace this with 0.0.0.0 to be consistent
727 * with interface creation on other physical interfaces.
728 */
729 if (islo && !legacy) {
730 bzero(&lifr.lifr_addr, sizeof (lifr.lifr_addr));
731 lifr.lifr_addr.ss_family = af;
732 if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
733 return (ipadm_errno2status(errno));
734 if (is_persistent) {
735 status = i_ipadm_persist_if(iph, ifname, af);
736 if (status != IPADM_SUCCESS) {
737 (void) i_ipadm_delete_if(iph, ifname,
738 af, IPADM_OPT_ACTIVE);
739 }
740 }
741 }
742 return (status);
743 }
744
745 dlpi_flags = DLPI_NOATTACH;
746
747 /*
748 * If IPADM_OPT_IPMP is specified, then this is a request
749 * to create an IPMP interface atop /dev/ipmpstub0. (We can't simply
750 * pass "ipmpstub0" as devname since an admin *could* have a normal
751 * vanity-named link named "ipmpstub0" that they'd like to plumb.)
752 */
753 if (ipadm_flags & IPADM_OPT_IPMP) {
754 dlpi_flags |= DLPI_DEVONLY;
755 linkname = "ipmpstub0";
896 status = i_ipadm_set_flags(iph, lifname, af,
897 IFF_UP, 0);
898 if (status != IPADM_SUCCESS)
899 return (status);
900 } else {
901 /*
902 * Prevent static IPv6 addresses from triggering
903 * autoconf. This does not have to be done for
904 * 6to4 tunnel interfaces, since in.ndpd will
905 * not autoconfigure those interfaces.
906 */
907 if (af == AF_INET6 && !legacy)
908 (void) i_ipadm_disable_autoconf(newif);
909 }
910
911 /*
912 * If IPADM_OPT_PERSIST was set in flags, store the
913 * interface in persistent DB.
914 */
915 if (is_persistent) {
916 status = i_ipadm_persist_if(iph, newif, af);
917 if (status != IPADM_SUCCESS) {
918 (void) i_ipadm_delete_if(iph, newif, af,
919 IPADM_OPT_ACTIVE);
920 }
921 }
922 }
923 if (status == IPADM_EXISTS)
924 status = IPADM_IF_EXISTS;
925 return (status);
926 }
927
928 /*
929 * Unplumbs the interface in `ifname' of family `af'.
930 */
931 ipadm_status_t
932 i_ipadm_unplumb_if(ipadm_handle_t iph, const char *ifname, sa_family_t af)
933 {
934 int ip_muxid, arp_muxid;
935 int mux_fd = -1;
936 int muxid_fd = -1;
1129 if (af == AF_INET6 && ret == IPADM_SUCCESS) {
1130 /*
1131 * in.ndpd maintains the phyints in its memory even after
1132 * the interface is plumbed, so that it can be reused when
1133 * the interface gets plumbed again. The default behavior
1134 * of in.ndpd is to start autoconfiguration for an interface
1135 * that gets plumbed. We need to send the
1136 * message IPADM_ENABLE_AUTOCONF to in.ndpd to restore this
1137 * default behavior on replumb.
1138 */
1139 (void) i_ipadm_enable_autoconf(ifname);
1140 }
1141 return (ret);
1142 }
1143
1144 /*
1145 * Saves the given interface name `ifname' with address family `af' in
1146 * persistent DB.
1147 */
1148 static ipadm_status_t
1149 i_ipadm_persist_if(ipadm_handle_t iph, const char *ifname, sa_family_t af)
1150 {
1151 ipmgmt_if_arg_t ifarg;
1152 int err;
1153
1154 (void) strlcpy(ifarg.ia_ifname, ifname, sizeof (ifarg.ia_ifname));
1155 ifarg.ia_family = af;
1156 ifarg.ia_cmd = IPMGMT_CMD_SETIF;
1157 ifarg.ia_flags = IPMGMT_PERSIST;
1158 err = ipadm_door_call(iph, &ifarg, sizeof (ifarg), NULL, 0, B_FALSE);
1159 return (ipadm_errno2status(err));
1160 }
1161
1162 /*
1163 * Remove the IP interface from active configuration. If IPADM_OPT_PERSIST
1164 * is set in `ipadm_flags', it is also removed from persistent configuration.
1165 */
1166 ipadm_status_t
1167 i_ipadm_delete_if(ipadm_handle_t iph, const char *ifname, sa_family_t af,
1168 uint32_t ipadm_flags)
1169 {
1170 ipadm_status_t ret = IPADM_SUCCESS;
1171 ipadm_status_t db_status;
1172 char tmp_ifname[LIFNAMSIZ];
1173 char *cp;
1174 struct ipadm_addrobj_s ipaddr;
1175 boolean_t is_persistent =
1246 * Create the interface by plumbing it for IP.
1247 * This function will check if there is saved configuration information
1248 * for `ifname' and return IPADM_OP_DISABLE_OBJ if the name-space
1249 * for `ifname' is taken.
1250 */
1251 ipadm_status_t
1252 i_ipadm_create_if(ipadm_handle_t iph, char *ifname, sa_family_t af,
1253 uint32_t ipadm_flags)
1254 {
1255 ipadm_status_t status;
1256 boolean_t p_exists;
1257 sa_family_t other_af;
1258
1259 /*
1260 * Return error, if the interface already exists in either the active
1261 * or the persistent configuration.
1262 */
1263 if (ipadm_if_enabled(iph, ifname, af))
1264 return (IPADM_IF_EXISTS);
1265
1266 if (!(iph->iph_flags & IPH_LEGACY)) {
1267 status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
1268 if (status != IPADM_SUCCESS)
1269 return (status);
1270 other_af = (af == AF_INET ? AF_INET6 : AF_INET);
1271 if (p_exists) {
1272 if (!ipadm_if_enabled(iph, ifname, other_af))
1273 return (IPADM_OP_DISABLE_OBJ);
1274 else
1275 ipadm_flags &= ~IPADM_OPT_PERSIST;
1276 }
1277 }
1278
1279 return (i_ipadm_plumb_if(iph, ifname, af, ipadm_flags));
1280 }
1281
1282 /*
1283 * Plumbs an interface. Creates both IPv4 and IPv6 interfaces by
1284 * default, unless a value in `af' is specified. The interface may be plumbed
1285 * only if there is no previously saved persistent configuration information
1286 * for the interface (in which case the ipadm_enable_if() function must
1287 * be used to enable the interface).
1288 *
1289 * Returns: IPADM_SUCCESS, IPADM_FAILURE, IPADM_IF_EXISTS,
1290 * IPADM_IF_PERSIST_EXISTS, IPADM_DLPI_FAILURE,
1291 * or appropriate ipadm_status_t corresponding to the errno.
1292 *
1293 * `ifname' must point to memory that can hold upto LIFNAMSIZ chars. It may
1294 * be over-written with the actual interface name when a PPA has to be
1295 * internally generated by the library.
1296 */
1297 ipadm_status_t
1298 ipadm_create_if(ipadm_handle_t iph, char *ifname, sa_family_t af,
1328 !i_ipadm_is_6to4(iph, ifname)) {
1329 status = i_ipadm_create_if(iph, ifname, AF_INET, flags);
1330 if (status != IPADM_SUCCESS)
1331 return (status);
1332 created_v4 = B_TRUE;
1333 }
1334 if (af == AF_INET6 || af == AF_UNSPEC) {
1335 status = i_ipadm_create_if(iph, ifname, AF_INET6, flags);
1336 if (status != IPADM_SUCCESS) {
1337 if (created_v4) {
1338 (void) i_ipadm_delete_if(iph, ifname, AF_INET,
1339 IPADM_OPT_ACTIVE);
1340 }
1341 return (status);
1342 }
1343 }
1344
1345 return (IPADM_SUCCESS);
1346 }
1347
1348 /*
1349 * Deletes the interface in `ifname'. Removes both IPv4 and IPv6 interfaces
1350 * when `af' = AF_UNSPEC.
1351 */
1352 ipadm_status_t
1353 ipadm_delete_if(ipadm_handle_t iph, const char *ifname, sa_family_t af,
1354 uint32_t flags)
1355 {
1356 ipadm_status_t status1 = IPADM_SUCCESS;
1357 ipadm_status_t status2 = IPADM_SUCCESS;
1358 ipadm_status_t other;
1359
1360 /* Check for the required authorization */
1361 if (!ipadm_check_auth())
1362 return (IPADM_EAUTH);
1363
1364 /* Validate the `ifname' for any logical interface. */
1365 if (flags == 0 || (flags & ~(IPADM_COMMON_OPT_MASK)) ||
1366 !i_ipadm_validate_ifname(iph, ifname))
1367 return (IPADM_INVALID_ARG);
1368
1431
1432 status = i_ipadm_get_all_if_info(iph, ifname, if_info, lifc_flags);
1433 if (status != IPADM_SUCCESS)
1434 return (status);
1435 if (ifname != NULL && *if_info == NULL)
1436 return (IPADM_ENXIO);
1437
1438 return (IPADM_SUCCESS);
1439 }
1440
1441 /*
1442 * Frees the linked list allocated by ipadm_if_info().
1443 */
1444 void
1445 ipadm_free_if_info(ipadm_if_info_t *ifinfo)
1446 {
1447 ipadm_if_info_t *ifinfo_next;
1448
1449 for (; ifinfo != NULL; ifinfo = ifinfo_next) {
1450 ifinfo_next = ifinfo->ifi_next;
1451 free(ifinfo);
1452 }
1453 }
1454
1455 /*
1456 * Re-enable the interface `ifname' based on the saved configuration
1457 * for `ifname'.
1458 */
1459 ipadm_status_t
1460 ipadm_enable_if(ipadm_handle_t iph, const char *ifname, uint32_t flags)
1461 {
1462 nvlist_t *ifnvl;
1463 ipadm_status_t status;
1464 ifspec_t ifsp;
1465
1466 /* Check for the required authorization */
1467 if (!ipadm_check_auth())
1468 return (IPADM_EAUTH);
1469
1470 /* Check for logical interfaces. */
1471 if (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)
1472 return (IPADM_INVALID_ARG);
1473
1474 /* Enabling an interface persistently is not supported. */
1543 } else {
1544 return (IPADM_FAILURE);
1545 }
1546 }
1547
1548 /*
1549 * This workaround is until libipadm supports IPMP and is required whenever an
1550 * interface is moved into an IPMP group. Since libipadm doesn't support IPMP
1551 * yet, we will have to update the daemon's in-memory mapping of
1552 * `aobjname' to 'lifnum'.
1553 *
1554 * For `IPMGMT_ACTIVE' case, i_ipadm_delete_ifobj() would only fail if
1555 * door_call(3C) fails. Also, there is no use in returning error because
1556 * `ifname' would have been successfuly moved into IPMP group, by this time.
1557 */
1558 void
1559 ipadm_if_move(ipadm_handle_t iph, const char *ifname)
1560 {
1561 (void) i_ipadm_delete_ifobj(iph, ifname, AF_INET, B_FALSE);
1562 (void) i_ipadm_delete_ifobj(iph, ifname, AF_INET6, B_FALSE);
1563 }
|
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
24 */
25
26 #include <errno.h>
27 #include <sys/sockio.h>
28 #include <sys/list.h>
29 #include <string.h>
30 #include <assert.h>
31 #include <unistd.h>
32 #include <stropts.h>
33 #include <strings.h>
34 #include <libdlpi.h>
35 #include <libdllink.h>
36 #include <libinetutil.h>
37 #include <inet/ip.h>
38 #include <limits.h>
39 #include <zone.h>
40 #include <ipadm_ndpd.h>
41 #include <ipmp_query.h>
42 #include "libipadm_impl.h"
43
44 static ipadm_status_t i_ipadm_slifname_arp(char *, uint64_t, int);
45 static ipadm_status_t i_ipadm_slifname(ipadm_handle_t, char *, char *,
46 uint64_t, int, uint32_t);
47 static ipadm_status_t i_ipadm_create_ipmp_peer(ipadm_handle_t, char *,
48 sa_family_t);
49 static ipadm_status_t i_ipadm_persist_if(ipadm_handle_t, const char *,
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);
66
67 /*
68 * Returns B_FALSE if the interface in `ifname' has at least one address that is
69 * IFF_UP in the addresses in `ifa'.
70 */
71 static boolean_t
72 i_ipadm_is_if_down(char *ifname, struct ifaddrs *ifa)
73 {
74 struct ifaddrs *ifap;
75 char cifname[LIFNAMSIZ];
76 char *sep;
77
78 for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
79 (void) strlcpy(cifname, ifap->ifa_name, sizeof (cifname));
80 if ((sep = strrchr(cifname, IPADM_LOGICAL_SEP)) != NULL)
81 *sep = '\0';
82 /*
83 * If this condition is true, there is at least one
84 * address that is IFF_UP. So, we need to return B_FALSE.
85 */
123 for (n = 0; n < numifs; n++, lifrp++) {
124 /* Skip interfaces with logical num != 0 */
125 if (i_ipadm_get_lnum(lifrp->lifr_name) != 0)
126 continue;
127 /*
128 * Skip the current interface if a specific `ifname' has
129 * been requested and current interface does not match
130 * `ifname'.
131 */
132 if (ifname != NULL && strcmp(lifrp->lifr_name, ifname) != 0)
133 continue;
134 /*
135 * Check if the interface already exists in our list.
136 * If it already exists, we need to update its flags.
137 */
138 for (ifp = *if_info; ifp != NULL; ifp = ifp->ifi_next) {
139 if (strcmp(lifrp->lifr_name, ifp->ifi_name) == 0)
140 break;
141 }
142 if (ifp == NULL) {
143 if ((status =
144 i_ipadm_allocate_ifinfo(&ifp)) != IPADM_SUCCESS)
145 break;
146
147 (void) strlcpy(ifp->ifi_name, lifrp->lifr_name,
148 sizeof (ifp->ifi_name));
149 /* Update the `ifi_next' pointer for this new node */
150 if (*if_info == NULL)
151 *if_info = ifp;
152 else
153 last->ifi_next = ifp;
154 last = ifp;
155 }
156
157 /*
158 * Retrieve the flags for the interface by doing a
159 * SIOCGLIFFLAGS to populate the `ifi_cflags' field.
160 */
161 (void) strlcpy(lifrl.lifr_name,
162 lifrp->lifr_name, sizeof (lifrl.lifr_name));
163 s = (lifrp->lifr_addr.ss_family == AF_INET) ?
164 iph->iph_sock : iph->iph_sock6;
165 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0)
166 continue;
167
168 /* a regular interface by default */
169 ifp->ifi_class = IPADM_IF_CLASS_REGULAR;
170
171 if (lifrl.lifr_flags & IFF_BROADCAST)
172 ifp->ifi_cflags |= IFIF_BROADCAST;
173 if (lifrl.lifr_flags & IFF_MULTICAST)
174 ifp->ifi_cflags |= IFIF_MULTICAST;
175 if (lifrl.lifr_flags & IFF_POINTOPOINT)
176 ifp->ifi_cflags |= IFIF_POINTOPOINT;
177 if (lifrl.lifr_flags & IFF_VIRTUAL) {
178 ifp->ifi_cflags |= IFIF_VIRTUAL;
179 ifp->ifi_class = IPADM_IF_CLASS_VIRTUAL;
180 }
181 if (lifrl.lifr_flags & IFF_IPMP) {
182 ifp->ifi_cflags |= IFIF_IPMP;
183 ifp->ifi_class = IPADM_IF_CLASS_IPMP;
184 }
185 if (lifrl.lifr_flags & IFF_STANDBY)
186 ifp->ifi_cflags |= IFIF_STANDBY;
187 if (lifrl.lifr_flags & IFF_INACTIVE)
188 ifp->ifi_cflags |= IFIF_INACTIVE;
189 if (lifrl.lifr_flags & IFF_VRRP)
190 ifp->ifi_cflags |= IFIF_VRRP;
191 if (lifrl.lifr_flags & IFF_NOACCEPT)
192 ifp->ifi_cflags |= IFIF_NOACCEPT;
193 if (lifrl.lifr_flags & IFF_IPV4)
194 ifp->ifi_cflags |= IFIF_IPV4;
195 if (lifrl.lifr_flags & IFF_IPV6)
196 ifp->ifi_cflags |= IFIF_IPV6;
197 if (lifrl.lifr_flags & IFF_L3PROTECT)
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 }
213 }
214 free(buf);
215 if (status != IPADM_SUCCESS) {
216 ipadm_free_if_info(*if_info);
217 *if_info = NULL;
218 }
219 return (status);
220 }
221
222 /*
223 * Returns the interface information for `ifname' in `if_info' from persistent
224 * config if `ifname' is non-null. Otherwise, it returns all the interfaces
225 * from persistent config in `if_info'.
226 */
227 static ipadm_status_t
228 i_ipadm_persist_if_info(ipadm_handle_t iph, const char *ifname,
229 ipadm_if_info_t **if_info)
230 {
231 ipadm_status_t status = IPADM_SUCCESS;
232 nvlist_t *ifs_info_nvl;
233
234 *if_info = NULL;
235
236 if ((status = i_ipadm_get_db_if(iph,
237 ifname, &ifs_info_nvl)) != IPADM_SUCCESS)
238 return (status);
239
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);
264 break;
265 }
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;
304 }
305
306 nvlist_free(ifs_info_nvl);
307 return (status);
308 }
309
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 /*
382 * Collects information for `ifname' if one is specified from both
383 * active and persistent config in `if_info'. If no `ifname' is specified,
384 * this returns all the interfaces in active and persistent config in
385 * `if_info'.
386 */
387 ipadm_status_t
388 i_ipadm_get_all_if_info(ipadm_handle_t iph, const char *ifname,
389 ipadm_if_info_t **if_info, int64_t lifc_flags)
390 {
391 ipadm_status_t status;
392 ipadm_if_info_t *aifinfo = NULL;
393 ipadm_if_info_t *pifinfo = NULL;
394 ipadm_if_info_t *aifp;
395 ipadm_if_info_t *pifp;
396 ipadm_if_info_t *last = NULL;
397 struct ifaddrs *ifa;
398 struct ifaddrs *ifap;
451 /*
452 * Get the persistent interface information in `pifinfo'.
453 */
454 status = i_ipadm_persist_if_info(iph, ifname, &pifinfo);
455 if (status == IPADM_NOTFOUND) {
456 *if_info = aifinfo;
457 return (IPADM_SUCCESS);
458 }
459 if (status != IPADM_SUCCESS)
460 goto fail;
461 /*
462 * If a persistent interface is also found in `aifinfo', update
463 * its entry in `aifinfo' with the persistent information from
464 * `pifinfo'. If an interface is found in `pifinfo', but not in
465 * `aifinfo', it means that this interface was disabled. We should
466 * add this interface to `aifinfo' and set it state to IFIF_DISABLED.
467 */
468 for (pifp = pifinfo; pifp != NULL; pifp = pifp->ifi_next) {
469 for (aifp = aifinfo; aifp != NULL; aifp = aifp->ifi_next) {
470 if (strcmp(aifp->ifi_name, pifp->ifi_name) == 0) {
471 break;
472 }
473 }
474
475 if (aifp == NULL) {
476 if ((status =
477 i_ipadm_allocate_ifinfo(&aifp)) != IPADM_SUCCESS)
478 goto fail;
479
480 (void) strlcpy(aifp->ifi_name, pifp->ifi_name,
481 sizeof (aifp->ifi_name));
482
483 aifp->ifi_next = NULL;
484 aifp->ifi_state = IFIS_DISABLED;
485 if (last != NULL)
486 last->ifi_next = aifp;
487 else
488 aifinfo = aifp;
489 last = aifp;
490 }
491
492 if ((status = i_ipadm_add_persistent_if_info(aifp,
493 pifp)) != IPADM_SUCCESS)
494 goto fail;
495 }
496 *if_info = aifinfo;
497 ipadm_free_if_info(pifinfo);
498 return (IPADM_SUCCESS);
499 fail:
500 *if_info = NULL;
501 ipadm_free_if_info(aifinfo);
502 ipadm_free_if_info(pifinfo);
503 return (status);
504 }
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
575 int
576 i_ipadm_get_lnum(const char *ifname)
577 {
578 char *num = strrchr(ifname, IPADM_LOGICAL_SEP);
579
580 if (num == NULL)
581 return (0);
582
583 return (atoi(++num));
584 }
585
586 /*
587 * Sets the output argument `exists' to true or false based on whether
588 * any persistent configuration is available for `ifname' and returns
589 * IPADM_SUCCESS as status. If the persistent information cannot be retrieved,
590 * `exists' is unmodified and an error status is returned.
591 */
592 ipadm_status_t
593 i_ipadm_if_pexists(ipadm_handle_t iph, const char *ifname, sa_family_t af,
594 boolean_t *exists)
595 {
596 ipadm_if_info_t *ifinfo;
597 ipadm_status_t status;
598
599 /*
600 * if IPH_IPMGMTD is set, we know that the caller (ipmgmtd) already
601 * knows about persistent configuration in the first place, so we
602 * just return success.
603 */
604 if (iph->iph_flags & IPH_IPMGMTD) {
605 *exists = B_FALSE;
606 return (IPADM_SUCCESS);
607 }
608 status = i_ipadm_persist_if_info(iph, ifname, &ifinfo);
609 if (status == IPADM_SUCCESS) {
610 *exists = ((af == AF_INET &&
611 (ifinfo->ifi_pflags & IFIF_IPV4)) ||
612 (af == AF_INET6 &&
613 (ifinfo->ifi_pflags & IFIF_IPV6)));
614 ipadm_free_if_info(ifinfo);
615 } else if (status == IPADM_NOTFOUND) {
616 status = IPADM_SUCCESS;
617 *exists = B_FALSE;
618 }
619 return (status);
620 }
621
622 /*
623 * Open "/dev/udp{,6}" for use as a multiplexor to PLINK the interface stream
624 * under. We use "/dev/udp" instead of "/dev/ip" since STREAMS will not let
625 * you PLINK a driver under itself, and "/dev/ip" is typically the driver at
626 * the bottom of the stream for tunneling interfaces.
627 */
628 ipadm_status_t
629 ipadm_open_arp_on_udp(const char *udp_dev_name, int *fd)
630 {
631 int err;
632
633 if ((*fd = open(udp_dev_name, O_RDWR)) == -1)
634 return (ipadm_errno2status(errno));
933 if (af == AF_INET)
934 sock = iph->iph_sock;
935 else
936 sock = iph->iph_sock6;
937 if (islo && ioctl(sock, SIOCGLIFADDR, (caddr_t)&lifr) >= 0)
938 return (IPADM_IF_EXISTS);
939 if (ioctl(sock, SIOCLIFADDIF, (caddr_t)&lifr) < 0)
940 return (ipadm_errno2status(errno));
941
942 /*
943 * By default, kernel configures 127.0.0.1 on the loopback
944 * interface. Replace this with 0.0.0.0 to be consistent
945 * with interface creation on other physical interfaces.
946 */
947 if (islo && !legacy) {
948 bzero(&lifr.lifr_addr, sizeof (lifr.lifr_addr));
949 lifr.lifr_addr.ss_family = af;
950 if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
951 return (ipadm_errno2status(errno));
952 if (is_persistent) {
953 status = i_ipadm_persist_if(iph,
954 ifname, af, ipadm_flags);
955 if (status != IPADM_SUCCESS) {
956 (void) i_ipadm_delete_if(iph, ifname,
957 af, IPADM_OPT_ACTIVE);
958 }
959 }
960 }
961 return (status);
962 }
963
964 dlpi_flags = DLPI_NOATTACH;
965
966 /*
967 * If IPADM_OPT_IPMP is specified, then this is a request
968 * to create an IPMP interface atop /dev/ipmpstub0. (We can't simply
969 * pass "ipmpstub0" as devname since an admin *could* have a normal
970 * vanity-named link named "ipmpstub0" that they'd like to plumb.)
971 */
972 if (ipadm_flags & IPADM_OPT_IPMP) {
973 dlpi_flags |= DLPI_DEVONLY;
974 linkname = "ipmpstub0";
1115 status = i_ipadm_set_flags(iph, lifname, af,
1116 IFF_UP, 0);
1117 if (status != IPADM_SUCCESS)
1118 return (status);
1119 } else {
1120 /*
1121 * Prevent static IPv6 addresses from triggering
1122 * autoconf. This does not have to be done for
1123 * 6to4 tunnel interfaces, since in.ndpd will
1124 * not autoconfigure those interfaces.
1125 */
1126 if (af == AF_INET6 && !legacy)
1127 (void) i_ipadm_disable_autoconf(newif);
1128 }
1129
1130 /*
1131 * If IPADM_OPT_PERSIST was set in flags, store the
1132 * interface in persistent DB.
1133 */
1134 if (is_persistent) {
1135 status = i_ipadm_persist_if(iph,
1136 newif, af, ipadm_flags);
1137 if (status != IPADM_SUCCESS) {
1138 (void) i_ipadm_delete_if(iph, newif, af,
1139 IPADM_OPT_ACTIVE);
1140 }
1141 }
1142 }
1143 if (status == IPADM_EXISTS)
1144 status = IPADM_IF_EXISTS;
1145 return (status);
1146 }
1147
1148 /*
1149 * Unplumbs the interface in `ifname' of family `af'.
1150 */
1151 ipadm_status_t
1152 i_ipadm_unplumb_if(ipadm_handle_t iph, const char *ifname, sa_family_t af)
1153 {
1154 int ip_muxid, arp_muxid;
1155 int mux_fd = -1;
1156 int muxid_fd = -1;
1349 if (af == AF_INET6 && ret == IPADM_SUCCESS) {
1350 /*
1351 * in.ndpd maintains the phyints in its memory even after
1352 * the interface is plumbed, so that it can be reused when
1353 * the interface gets plumbed again. The default behavior
1354 * of in.ndpd is to start autoconfiguration for an interface
1355 * that gets plumbed. We need to send the
1356 * message IPADM_ENABLE_AUTOCONF to in.ndpd to restore this
1357 * default behavior on replumb.
1358 */
1359 (void) i_ipadm_enable_autoconf(ifname);
1360 }
1361 return (ret);
1362 }
1363
1364 /*
1365 * Saves the given interface name `ifname' with address family `af' in
1366 * persistent DB.
1367 */
1368 static ipadm_status_t
1369 i_ipadm_persist_if(ipadm_handle_t iph,
1370 const char *ifname, sa_family_t af, uint32_t ipadm_flags)
1371 {
1372 ipmgmt_if_arg_t ifarg;
1373 int err;
1374
1375 (void) strlcpy(ifarg.ia_ifname, ifname, sizeof (ifarg.ia_ifname));
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 }
1382 ifarg.ia_cmd = IPMGMT_CMD_SETIF;
1383 ifarg.ia_flags = IPMGMT_PERSIST;
1384 err = ipadm_door_call(iph, &ifarg, sizeof (ifarg), NULL, 0, B_FALSE);
1385 return (ipadm_errno2status(err));
1386 }
1387
1388 /*
1389 * Remove the IP interface from active configuration. If IPADM_OPT_PERSIST
1390 * is set in `ipadm_flags', it is also removed from persistent configuration.
1391 */
1392 ipadm_status_t
1393 i_ipadm_delete_if(ipadm_handle_t iph, const char *ifname, sa_family_t af,
1394 uint32_t ipadm_flags)
1395 {
1396 ipadm_status_t ret = IPADM_SUCCESS;
1397 ipadm_status_t db_status;
1398 char tmp_ifname[LIFNAMSIZ];
1399 char *cp;
1400 struct ipadm_addrobj_s ipaddr;
1401 boolean_t is_persistent =
1472 * Create the interface by plumbing it for IP.
1473 * This function will check if there is saved configuration information
1474 * for `ifname' and return IPADM_OP_DISABLE_OBJ if the name-space
1475 * for `ifname' is taken.
1476 */
1477 ipadm_status_t
1478 i_ipadm_create_if(ipadm_handle_t iph, char *ifname, sa_family_t af,
1479 uint32_t ipadm_flags)
1480 {
1481 ipadm_status_t status;
1482 boolean_t p_exists;
1483 sa_family_t other_af;
1484
1485 /*
1486 * Return error, if the interface already exists in either the active
1487 * or the persistent configuration.
1488 */
1489 if (ipadm_if_enabled(iph, ifname, af))
1490 return (IPADM_IF_EXISTS);
1491
1492 #if 0
1493 if (!(iph->iph_flags & IPH_LEGACY)) {
1494 status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
1495 if (status != IPADM_SUCCESS)
1496 return (status);
1497 other_af = (af == AF_INET ? AF_INET6 : AF_INET);
1498 if (p_exists) {
1499 if (!ipadm_if_enabled(iph, ifname, other_af))
1500 return (IPADM_OP_DISABLE_OBJ);
1501 else
1502 ipadm_flags &= ~IPADM_OPT_PERSIST;
1503 }
1504 }
1505 #endif
1506 return (i_ipadm_plumb_if(iph, ifname, af, ipadm_flags));
1507 }
1508
1509 /*
1510 * Plumbs an interface. Creates both IPv4 and IPv6 interfaces by
1511 * default, unless a value in `af' is specified. The interface may be plumbed
1512 * only if there is no previously saved persistent configuration information
1513 * for the interface (in which case the ipadm_enable_if() function must
1514 * be used to enable the interface).
1515 *
1516 * Returns: IPADM_SUCCESS, IPADM_FAILURE, IPADM_IF_EXISTS,
1517 * IPADM_IF_PERSIST_EXISTS, IPADM_DLPI_FAILURE,
1518 * or appropriate ipadm_status_t corresponding to the errno.
1519 *
1520 * `ifname' must point to memory that can hold upto LIFNAMSIZ chars. It may
1521 * be over-written with the actual interface name when a PPA has to be
1522 * internally generated by the library.
1523 */
1524 ipadm_status_t
1525 ipadm_create_if(ipadm_handle_t iph, char *ifname, sa_family_t af,
1555 !i_ipadm_is_6to4(iph, ifname)) {
1556 status = i_ipadm_create_if(iph, ifname, AF_INET, flags);
1557 if (status != IPADM_SUCCESS)
1558 return (status);
1559 created_v4 = B_TRUE;
1560 }
1561 if (af == AF_INET6 || af == AF_UNSPEC) {
1562 status = i_ipadm_create_if(iph, ifname, AF_INET6, flags);
1563 if (status != IPADM_SUCCESS) {
1564 if (created_v4) {
1565 (void) i_ipadm_delete_if(iph, ifname, AF_INET,
1566 IPADM_OPT_ACTIVE);
1567 }
1568 return (status);
1569 }
1570 }
1571
1572 return (IPADM_SUCCESS);
1573 }
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
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 /*
1705 * Deletes the interface in `ifname'. Removes both IPv4 and IPv6 interfaces
1706 * when `af' = AF_UNSPEC.
1707 */
1708 ipadm_status_t
1709 ipadm_delete_if(ipadm_handle_t iph, const char *ifname, sa_family_t af,
1710 uint32_t flags)
1711 {
1712 ipadm_status_t status1 = IPADM_SUCCESS;
1713 ipadm_status_t status2 = IPADM_SUCCESS;
1714 ipadm_status_t other;
1715
1716 /* Check for the required authorization */
1717 if (!ipadm_check_auth())
1718 return (IPADM_EAUTH);
1719
1720 /* Validate the `ifname' for any logical interface. */
1721 if (flags == 0 || (flags & ~(IPADM_COMMON_OPT_MASK)) ||
1722 !i_ipadm_validate_ifname(iph, ifname))
1723 return (IPADM_INVALID_ARG);
1724
1787
1788 status = i_ipadm_get_all_if_info(iph, ifname, if_info, lifc_flags);
1789 if (status != IPADM_SUCCESS)
1790 return (status);
1791 if (ifname != NULL && *if_info == NULL)
1792 return (IPADM_ENXIO);
1793
1794 return (IPADM_SUCCESS);
1795 }
1796
1797 /*
1798 * Frees the linked list allocated by ipadm_if_info().
1799 */
1800 void
1801 ipadm_free_if_info(ipadm_if_info_t *ifinfo)
1802 {
1803 ipadm_if_info_t *ifinfo_next;
1804
1805 for (; ifinfo != NULL; ifinfo = ifinfo_next) {
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);
1809 free(ifinfo);
1810 }
1811 }
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
1824 /*
1825 * Re-enable the interface `ifname' based on the saved configuration
1826 * for `ifname'.
1827 */
1828 ipadm_status_t
1829 ipadm_enable_if(ipadm_handle_t iph, const char *ifname, uint32_t flags)
1830 {
1831 nvlist_t *ifnvl;
1832 ipadm_status_t status;
1833 ifspec_t ifsp;
1834
1835 /* Check for the required authorization */
1836 if (!ipadm_check_auth())
1837 return (IPADM_EAUTH);
1838
1839 /* Check for logical interfaces. */
1840 if (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)
1841 return (IPADM_INVALID_ARG);
1842
1843 /* Enabling an interface persistently is not supported. */
1912 } else {
1913 return (IPADM_FAILURE);
1914 }
1915 }
1916
1917 /*
1918 * This workaround is until libipadm supports IPMP and is required whenever an
1919 * interface is moved into an IPMP group. Since libipadm doesn't support IPMP
1920 * yet, we will have to update the daemon's in-memory mapping of
1921 * `aobjname' to 'lifnum'.
1922 *
1923 * For `IPMGMT_ACTIVE' case, i_ipadm_delete_ifobj() would only fail if
1924 * door_call(3C) fails. Also, there is no use in returning error because
1925 * `ifname' would have been successfuly moved into IPMP group, by this time.
1926 */
1927 void
1928 ipadm_if_move(ipadm_handle_t iph, const char *ifname)
1929 {
1930 (void) i_ipadm_delete_ifobj(iph, ifname, AF_INET, B_FALSE);
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);
2009 }
|