xref: /titanic_50/usr/src/lib/libipadm/common/ipadm_ngz.c (revision 6a634c9dca3093f3922e4b7ab826d7bdf17bf78e)
1*550b6e40SSowmini Varadhan /*
2*550b6e40SSowmini Varadhan  * CDDL HEADER START
3*550b6e40SSowmini Varadhan  *
4*550b6e40SSowmini Varadhan  * The contents of this file are subject to the terms of the
5*550b6e40SSowmini Varadhan  * Common Development and Distribution License (the "License").
6*550b6e40SSowmini Varadhan  * You may not use this file except in compliance with the License.
7*550b6e40SSowmini Varadhan  *
8*550b6e40SSowmini Varadhan  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*550b6e40SSowmini Varadhan  * or http://www.opensolaris.org/os/licensing.
10*550b6e40SSowmini Varadhan  * See the License for the specific language governing permissions
11*550b6e40SSowmini Varadhan  * and limitations under the License.
12*550b6e40SSowmini Varadhan  *
13*550b6e40SSowmini Varadhan  * When distributing Covered Code, include this CDDL HEADER in each
14*550b6e40SSowmini Varadhan  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*550b6e40SSowmini Varadhan  * If applicable, add the following below this CDDL HEADER, with the
16*550b6e40SSowmini Varadhan  * fields enclosed by brackets "[]" replaced with your own identifying
17*550b6e40SSowmini Varadhan  * information: Portions Copyright [yyyy] [name of copyright owner]
18*550b6e40SSowmini Varadhan  *
19*550b6e40SSowmini Varadhan  * CDDL HEADER END
20*550b6e40SSowmini Varadhan  */
21*550b6e40SSowmini Varadhan /*
22*550b6e40SSowmini Varadhan  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23*550b6e40SSowmini Varadhan  */
24*550b6e40SSowmini Varadhan 
25*550b6e40SSowmini Varadhan #include <errno.h>
26*550b6e40SSowmini Varadhan #include <fcntl.h>
27*550b6e40SSowmini Varadhan #include <priv_utils.h>
28*550b6e40SSowmini Varadhan #include <signal.h>
29*550b6e40SSowmini Varadhan #include <stdlib.h>
30*550b6e40SSowmini Varadhan #include <stdio.h>
31*550b6e40SSowmini Varadhan #include <strings.h>
32*550b6e40SSowmini Varadhan #include <sys/param.h>
33*550b6e40SSowmini Varadhan #include <sys/stat.h>
34*550b6e40SSowmini Varadhan #include <unistd.h>
35*550b6e40SSowmini Varadhan #include <zone.h>
36*550b6e40SSowmini Varadhan #include <libipadm.h>
37*550b6e40SSowmini Varadhan #include <libdladm.h>
38*550b6e40SSowmini Varadhan #include <libdllink.h>
39*550b6e40SSowmini Varadhan #include <net/route.h>
40*550b6e40SSowmini Varadhan #include <netinet/in.h>
41*550b6e40SSowmini Varadhan #include <net/route.h>
42*550b6e40SSowmini Varadhan #include <errno.h>
43*550b6e40SSowmini Varadhan #include <inet/ip.h>
44*550b6e40SSowmini Varadhan #include <string.h>
45*550b6e40SSowmini Varadhan #include <libinetutil.h>
46*550b6e40SSowmini Varadhan #include <unistd.h>
47*550b6e40SSowmini Varadhan #include <libipadm_impl.h>
48*550b6e40SSowmini Varadhan #include <sys/brand.h>
49*550b6e40SSowmini Varadhan 
50*550b6e40SSowmini Varadhan #define	ROUNDUP_LONG(a) \
51*550b6e40SSowmini Varadhan 	((a) > 0 ? (1 + (((a) - 1) | (sizeof (long) - 1))) : sizeof (long))
52*550b6e40SSowmini Varadhan #define	HOST_MASK	0xffffffffU
53*550b6e40SSowmini Varadhan 
54*550b6e40SSowmini Varadhan typedef struct ngz_walk_data_s {
55*550b6e40SSowmini Varadhan 	ipadm_handle_t	ngz_iph;
56*550b6e40SSowmini Varadhan 	zoneid_t	ngz_zoneid;
57*550b6e40SSowmini Varadhan 	char		*ngz_ifname;
58*550b6e40SSowmini Varadhan 	boolean_t	ngz_s10c;
59*550b6e40SSowmini Varadhan 	ipadm_status_t  ngz_ipstatus;
60*550b6e40SSowmini Varadhan 	persist_cb_t	ngz_persist_if;
61*550b6e40SSowmini Varadhan } ngz_walk_data_t;
62*550b6e40SSowmini Varadhan 
63*550b6e40SSowmini Varadhan /*
64*550b6e40SSowmini Varadhan  * Tell the kernel to add, delete or change a route
65*550b6e40SSowmini Varadhan  */
66*550b6e40SSowmini Varadhan static void
i_ipadm_rtioctl4(int rtsock,int action,in_addr_t dst,in_addr_t gate,uint_t masklen,char * ifname,uint8_t metric,int flags)67*550b6e40SSowmini Varadhan i_ipadm_rtioctl4(int rtsock,
68*550b6e40SSowmini Varadhan     int action,			/* RTM_DELETE, etc */
69*550b6e40SSowmini Varadhan     in_addr_t dst,
70*550b6e40SSowmini Varadhan     in_addr_t gate,
71*550b6e40SSowmini Varadhan     uint_t masklen,
72*550b6e40SSowmini Varadhan     char *ifname,
73*550b6e40SSowmini Varadhan     uint8_t metric,
74*550b6e40SSowmini Varadhan     int flags)
75*550b6e40SSowmini Varadhan {
76*550b6e40SSowmini Varadhan 	static int rt_sock_seqno = 0;
77*550b6e40SSowmini Varadhan 	struct {
78*550b6e40SSowmini Varadhan 		struct rt_msghdr w_rtm;
79*550b6e40SSowmini Varadhan 		struct sockaddr_in w_dst;
80*550b6e40SSowmini Varadhan 		struct sockaddr_in w_gate;
81*550b6e40SSowmini Varadhan 		uint8_t w_space[512];
82*550b6e40SSowmini Varadhan 	} w;
83*550b6e40SSowmini Varadhan 	struct sockaddr_in w_mask;
84*550b6e40SSowmini Varadhan 	struct sockaddr_dl w_ifp;
85*550b6e40SSowmini Varadhan 	uint8_t *cp;
86*550b6e40SSowmini Varadhan 	long cc;
87*550b6e40SSowmini Varadhan 
88*550b6e40SSowmini Varadhan again:
89*550b6e40SSowmini Varadhan 	(void) memset(&w, 0, sizeof (w));
90*550b6e40SSowmini Varadhan 	(void) memset(&w_mask, 0, sizeof (w_mask));
91*550b6e40SSowmini Varadhan 	(void) memset(&w_ifp, 0, sizeof (w_ifp));
92*550b6e40SSowmini Varadhan 	cp = w.w_space;
93*550b6e40SSowmini Varadhan 	w.w_rtm.rtm_msglen = sizeof (struct rt_msghdr) +
94*550b6e40SSowmini Varadhan 	    2 * ROUNDUP_LONG(sizeof (struct sockaddr_in));
95*550b6e40SSowmini Varadhan 	w.w_rtm.rtm_version = RTM_VERSION;
96*550b6e40SSowmini Varadhan 	w.w_rtm.rtm_type = action;
97*550b6e40SSowmini Varadhan 	w.w_rtm.rtm_flags = (flags | RTF_ZONE);
98*550b6e40SSowmini Varadhan 	w.w_rtm.rtm_seq = ++rt_sock_seqno;
99*550b6e40SSowmini Varadhan 	w.w_rtm.rtm_addrs = RTA_DST|RTA_GATEWAY;
100*550b6e40SSowmini Varadhan 	if (metric != 0 || action == RTM_CHANGE) {
101*550b6e40SSowmini Varadhan 		w.w_rtm.rtm_rmx.rmx_hopcount = metric;
102*550b6e40SSowmini Varadhan 		w.w_rtm.rtm_inits |= RTV_HOPCOUNT;
103*550b6e40SSowmini Varadhan 	}
104*550b6e40SSowmini Varadhan 	w.w_dst.sin_family = AF_INET;
105*550b6e40SSowmini Varadhan 	w.w_dst.sin_addr.s_addr = dst;
106*550b6e40SSowmini Varadhan 	w.w_gate.sin_family = AF_INET;
107*550b6e40SSowmini Varadhan 	w.w_gate.sin_addr.s_addr = gate;
108*550b6e40SSowmini Varadhan 	if (masklen == HOST_MASK) {
109*550b6e40SSowmini Varadhan 		w.w_rtm.rtm_flags |= RTF_HOST;
110*550b6e40SSowmini Varadhan 	} else {
111*550b6e40SSowmini Varadhan 		struct sockaddr_storage m4;
112*550b6e40SSowmini Varadhan 
113*550b6e40SSowmini Varadhan 		w.w_rtm.rtm_addrs |= RTA_NETMASK;
114*550b6e40SSowmini Varadhan 		w_mask.sin_family = AF_INET;
11564639aafSDarren Reed 		if (plen2mask(masklen, AF_INET, (struct sockaddr *)&m4) != 0) {
116*550b6e40SSowmini Varadhan 			return;
117*550b6e40SSowmini Varadhan 		}
118*550b6e40SSowmini Varadhan 		w_mask.sin_addr = ((struct sockaddr_in *)&m4)->sin_addr;
119*550b6e40SSowmini Varadhan 		(void) memmove(cp, &w_mask, sizeof (w_mask));
120*550b6e40SSowmini Varadhan 		cp += ROUNDUP_LONG(sizeof (struct sockaddr_in));
121*550b6e40SSowmini Varadhan 		w.w_rtm.rtm_msglen += ROUNDUP_LONG(sizeof (struct sockaddr_in));
122*550b6e40SSowmini Varadhan 	}
123*550b6e40SSowmini Varadhan 	w_ifp.sdl_family = AF_LINK;
124*550b6e40SSowmini Varadhan 	w.w_rtm.rtm_addrs |= RTA_IFP;
125*550b6e40SSowmini Varadhan 	w_ifp.sdl_index = if_nametoindex(ifname);
126*550b6e40SSowmini Varadhan 	(void) memmove(cp, &w_ifp, sizeof (w_ifp));
127*550b6e40SSowmini Varadhan 	w.w_rtm.rtm_msglen += ROUNDUP_LONG(sizeof (struct sockaddr_dl));
128*550b6e40SSowmini Varadhan 
129*550b6e40SSowmini Varadhan 	cc = write(rtsock, &w, w.w_rtm.rtm_msglen);
130*550b6e40SSowmini Varadhan 	if (cc < 0) {
131*550b6e40SSowmini Varadhan 		if (errno == ESRCH && (action == RTM_CHANGE ||
132*550b6e40SSowmini Varadhan 		    action == RTM_DELETE)) {
133*550b6e40SSowmini Varadhan 			if (action == RTM_CHANGE) {
134*550b6e40SSowmini Varadhan 				action = RTM_ADD;
135*550b6e40SSowmini Varadhan 				goto again;
136*550b6e40SSowmini Varadhan 			}
137*550b6e40SSowmini Varadhan 			return;
138*550b6e40SSowmini Varadhan 		}
139*550b6e40SSowmini Varadhan 		return;
140*550b6e40SSowmini Varadhan 	} else if (cc != w.w_rtm.rtm_msglen) {
141*550b6e40SSowmini Varadhan 		return;
142*550b6e40SSowmini Varadhan 	}
143*550b6e40SSowmini Varadhan }
144*550b6e40SSowmini Varadhan 
145*550b6e40SSowmini Varadhan static void
i_ipadm_rtioctl6(int rtsock,int action,in6_addr_t dst,in6_addr_t gate,uint_t prefix_length,char * ifname,int flags)146*550b6e40SSowmini Varadhan i_ipadm_rtioctl6(int rtsock,
147*550b6e40SSowmini Varadhan     int action,			/* RTM_DELETE, etc */
148*550b6e40SSowmini Varadhan     in6_addr_t dst,
149*550b6e40SSowmini Varadhan     in6_addr_t gate,
150*550b6e40SSowmini Varadhan     uint_t prefix_length,
151*550b6e40SSowmini Varadhan     char *ifname,
152*550b6e40SSowmini Varadhan     int flags)
153*550b6e40SSowmini Varadhan {
154*550b6e40SSowmini Varadhan 	static int rt_sock_seqno = 0;
155*550b6e40SSowmini Varadhan 	struct {
156*550b6e40SSowmini Varadhan 		struct rt_msghdr w_rtm;
157*550b6e40SSowmini Varadhan 		struct sockaddr_in6 w_dst;
158*550b6e40SSowmini Varadhan 		struct sockaddr_in6 w_gate;
159*550b6e40SSowmini Varadhan 		uint8_t w_space[512];
160*550b6e40SSowmini Varadhan 	} w;
161*550b6e40SSowmini Varadhan 	struct sockaddr_in6 w_mask;
162*550b6e40SSowmini Varadhan 	struct sockaddr_dl w_ifp;
163*550b6e40SSowmini Varadhan 	uint8_t *cp;
164*550b6e40SSowmini Varadhan 	long cc;
165*550b6e40SSowmini Varadhan 
166*550b6e40SSowmini Varadhan again:
167*550b6e40SSowmini Varadhan 	(void) memset(&w, 0, sizeof (w));
168*550b6e40SSowmini Varadhan 	(void) memset(&w_mask, 0, sizeof (w_mask));
169*550b6e40SSowmini Varadhan 	(void) memset(&w_ifp, 0, sizeof (w_ifp));
170*550b6e40SSowmini Varadhan 	cp = w.w_space;
171*550b6e40SSowmini Varadhan 	w.w_rtm.rtm_msglen = sizeof (struct rt_msghdr) +
172*550b6e40SSowmini Varadhan 	    2 * ROUNDUP_LONG(sizeof (struct sockaddr_in6));
173*550b6e40SSowmini Varadhan 	w.w_rtm.rtm_version = RTM_VERSION;
174*550b6e40SSowmini Varadhan 	w.w_rtm.rtm_type = action;
175*550b6e40SSowmini Varadhan 	w.w_rtm.rtm_flags = (flags | RTF_ZONE);
176*550b6e40SSowmini Varadhan 	w.w_rtm.rtm_seq = ++rt_sock_seqno;
177*550b6e40SSowmini Varadhan 	w.w_rtm.rtm_addrs = RTA_DST|RTA_GATEWAY;
178*550b6e40SSowmini Varadhan 	w.w_dst.sin6_family = AF_INET6;
179*550b6e40SSowmini Varadhan 	w.w_dst.sin6_addr = dst;
180*550b6e40SSowmini Varadhan 	w.w_gate.sin6_family = AF_INET6;
181*550b6e40SSowmini Varadhan 	w.w_gate.sin6_addr = gate;
182*550b6e40SSowmini Varadhan 	if (prefix_length == IPV6_ABITS) {
183*550b6e40SSowmini Varadhan 		w.w_rtm.rtm_flags |= RTF_HOST;
184*550b6e40SSowmini Varadhan 	} else {
185*550b6e40SSowmini Varadhan 		struct sockaddr_storage m6;
186*550b6e40SSowmini Varadhan 
187*550b6e40SSowmini Varadhan 		w.w_rtm.rtm_addrs |= RTA_NETMASK;
188*550b6e40SSowmini Varadhan 		w_mask.sin6_family = AF_INET6;
18964639aafSDarren Reed 		if (plen2mask(prefix_length, AF_INET6,
19064639aafSDarren Reed 		    (struct sockaddr *)&m6) != 0) {
191*550b6e40SSowmini Varadhan 			return;
192*550b6e40SSowmini Varadhan 		}
193*550b6e40SSowmini Varadhan 		w_mask.sin6_addr = ((struct sockaddr_in6 *)&m6)->sin6_addr;
194*550b6e40SSowmini Varadhan 		(void) memmove(cp, &w_mask, sizeof (w_mask));
195*550b6e40SSowmini Varadhan 		cp += ROUNDUP_LONG(sizeof (struct sockaddr_in6));
196*550b6e40SSowmini Varadhan 		w.w_rtm.rtm_msglen +=
197*550b6e40SSowmini Varadhan 		    ROUNDUP_LONG(sizeof (struct sockaddr_in6));
198*550b6e40SSowmini Varadhan 	}
199*550b6e40SSowmini Varadhan 	w_ifp.sdl_family = AF_LINK;
200*550b6e40SSowmini Varadhan 	w.w_rtm.rtm_addrs |= RTA_IFP;
201*550b6e40SSowmini Varadhan 	w_ifp.sdl_index = if_nametoindex(ifname);
202*550b6e40SSowmini Varadhan 	(void) memmove(cp, &w_ifp, sizeof (w_ifp));
203*550b6e40SSowmini Varadhan 	w.w_rtm.rtm_msglen += ROUNDUP_LONG(sizeof (struct sockaddr_dl));
204*550b6e40SSowmini Varadhan 
205*550b6e40SSowmini Varadhan 	cc = write(rtsock, &w, w.w_rtm.rtm_msglen);
206*550b6e40SSowmini Varadhan 	if (cc < 0) {
207*550b6e40SSowmini Varadhan 		if (errno == ESRCH && (action == RTM_CHANGE ||
208*550b6e40SSowmini Varadhan 		    action == RTM_DELETE)) {
209*550b6e40SSowmini Varadhan 			if (action == RTM_CHANGE) {
210*550b6e40SSowmini Varadhan 				action = RTM_ADD;
211*550b6e40SSowmini Varadhan 				goto again;
212*550b6e40SSowmini Varadhan 			}
213*550b6e40SSowmini Varadhan 			return;
214*550b6e40SSowmini Varadhan 		}
215*550b6e40SSowmini Varadhan 		return;
216*550b6e40SSowmini Varadhan 	} else if (cc != w.w_rtm.rtm_msglen) {
217*550b6e40SSowmini Varadhan 		return;
218*550b6e40SSowmini Varadhan 	}
219*550b6e40SSowmini Varadhan }
220*550b6e40SSowmini Varadhan 
221*550b6e40SSowmini Varadhan /*
222*550b6e40SSowmini Varadhan  * Return TRUE if running in a Solaris 10 Container.
223*550b6e40SSowmini Varadhan  */
224*550b6e40SSowmini Varadhan static boolean_t
i_ipadm_zone_is_s10c(zoneid_t zoneid)225*550b6e40SSowmini Varadhan i_ipadm_zone_is_s10c(zoneid_t zoneid)
226*550b6e40SSowmini Varadhan {
227*550b6e40SSowmini Varadhan 	char brand[MAXNAMELEN];
228*550b6e40SSowmini Varadhan 
229*550b6e40SSowmini Varadhan 	if (zone_getattr(zoneid, ZONE_ATTR_BRAND, brand, sizeof (brand)) < 0)
230*550b6e40SSowmini Varadhan 		return (B_FALSE);
231*550b6e40SSowmini Varadhan 	return (strcmp(brand, NATIVE_BRAND_NAME) != 0);
232*550b6e40SSowmini Varadhan }
233*550b6e40SSowmini Varadhan 
234*550b6e40SSowmini Varadhan /*
235*550b6e40SSowmini Varadhan  * Configure addresses on link. `buf' is a string of comma-separated
236*550b6e40SSowmini Varadhan  * IP addresses.
237*550b6e40SSowmini Varadhan  */
238*550b6e40SSowmini Varadhan static ipadm_status_t
i_ipadm_ngz_addr(ipadm_handle_t iph,char * link,char * buf)239*550b6e40SSowmini Varadhan i_ipadm_ngz_addr(ipadm_handle_t iph, char *link, char *buf)
240*550b6e40SSowmini Varadhan {
241*550b6e40SSowmini Varadhan 	ipadm_status_t ipstatus;
242*550b6e40SSowmini Varadhan 	ipadm_addrobj_t ipaddr;
243*550b6e40SSowmini Varadhan 	char *cp;
244*550b6e40SSowmini Varadhan 
245*550b6e40SSowmini Varadhan 	for (cp = strtok(buf, ","); cp != NULL; cp = strtok(NULL, ",")) {
246*550b6e40SSowmini Varadhan 		ipstatus = ipadm_create_addrobj(IPADM_ADDR_STATIC, link,
247*550b6e40SSowmini Varadhan 		    &ipaddr);
248*550b6e40SSowmini Varadhan 		if (ipstatus != IPADM_SUCCESS)
249*550b6e40SSowmini Varadhan 			return (ipstatus);
250*550b6e40SSowmini Varadhan 		/*
251*550b6e40SSowmini Varadhan 		 * ipadm_set_addr does the appropriate name resolution and
252*550b6e40SSowmini Varadhan 		 * sets up the ipadm_static_addr field.
253*550b6e40SSowmini Varadhan 		 */
254*550b6e40SSowmini Varadhan 		ipstatus = ipadm_set_addr(ipaddr, cp, AF_UNSPEC);
255*550b6e40SSowmini Varadhan 		if (ipstatus != IPADM_SUCCESS) {
256*550b6e40SSowmini Varadhan 			ipadm_destroy_addrobj(ipaddr);
257*550b6e40SSowmini Varadhan 			return (ipstatus);
258*550b6e40SSowmini Varadhan 		}
259*550b6e40SSowmini Varadhan 
260*550b6e40SSowmini Varadhan 		ipstatus = ipadm_create_addr(iph, ipaddr,
261*550b6e40SSowmini Varadhan 		    (IPADM_OPT_ACTIVE | IPADM_OPT_UP));
262*550b6e40SSowmini Varadhan 		if (ipstatus != IPADM_SUCCESS) {
263*550b6e40SSowmini Varadhan 			ipadm_destroy_addrobj(ipaddr);
264*550b6e40SSowmini Varadhan 			return (ipstatus);
265*550b6e40SSowmini Varadhan 		}
266*550b6e40SSowmini Varadhan 		ipadm_destroy_addrobj(ipaddr);
267*550b6e40SSowmini Varadhan 	}
268*550b6e40SSowmini Varadhan 	return (IPADM_SUCCESS);
269*550b6e40SSowmini Varadhan }
270*550b6e40SSowmini Varadhan 
271*550b6e40SSowmini Varadhan /*
272*550b6e40SSowmini Varadhan  * The (*persist_if)() will set up persistent information for the interface,
273*550b6e40SSowmini Varadhan  * based on what interface families are required, so just resolve the
274*550b6e40SSowmini Varadhan  * address and inform the callback about the linkname, and required address
275*550b6e40SSowmini Varadhan  * families.
276*550b6e40SSowmini Varadhan  */
277*550b6e40SSowmini Varadhan static ipadm_status_t
i_ipadm_ngz_persist_if(char * link,char * buf,void (* ngz_persist_if)(char *,boolean_t,boolean_t))278*550b6e40SSowmini Varadhan i_ipadm_ngz_persist_if(char *link, char *buf,
279*550b6e40SSowmini Varadhan     void (*ngz_persist_if)(char *, boolean_t, boolean_t))
280*550b6e40SSowmini Varadhan {
281*550b6e40SSowmini Varadhan 	char *cp, *slashp, addr[INET6_ADDRSTRLEN];
282*550b6e40SSowmini Varadhan 	ipadm_status_t ipstatus;
283*550b6e40SSowmini Varadhan 	struct sockaddr_storage ss;
284*550b6e40SSowmini Varadhan 	boolean_t v4 = B_FALSE;
285*550b6e40SSowmini Varadhan 	boolean_t v6 = B_FALSE;
286*550b6e40SSowmini Varadhan 
287*550b6e40SSowmini Varadhan 	for (cp = strtok(buf, ","); cp != NULL; cp = strtok(NULL, ",")) {
288*550b6e40SSowmini Varadhan 		/* remove the /<masklen> that's always added by zoneadmd */
289*550b6e40SSowmini Varadhan 		slashp = strchr(cp, '/');
290*550b6e40SSowmini Varadhan 		(void) strlcpy(addr, cp, (slashp - cp + 1));
291*550b6e40SSowmini Varadhan 
292*550b6e40SSowmini Varadhan 		/* resolve the address to find the family */
293*550b6e40SSowmini Varadhan 		bzero(&ss, sizeof (ss));
294*550b6e40SSowmini Varadhan 		ipstatus = i_ipadm_resolve_addr(addr, AF_UNSPEC, &ss);
295*550b6e40SSowmini Varadhan 		if (ipstatus != IPADM_SUCCESS)
296*550b6e40SSowmini Varadhan 			return (ipstatus);
297*550b6e40SSowmini Varadhan 		switch (ss.ss_family) {
298*550b6e40SSowmini Varadhan 		case AF_INET:
299*550b6e40SSowmini Varadhan 			v4 = B_TRUE;
300*550b6e40SSowmini Varadhan 			break;
301*550b6e40SSowmini Varadhan 		case AF_INET6:
302*550b6e40SSowmini Varadhan 			v6 = B_TRUE;
303*550b6e40SSowmini Varadhan 			break;
304*550b6e40SSowmini Varadhan 		default:
305*550b6e40SSowmini Varadhan 			return (IPADM_BAD_ADDR);
306*550b6e40SSowmini Varadhan 		}
307*550b6e40SSowmini Varadhan 	}
308*550b6e40SSowmini Varadhan 	(*ngz_persist_if)(link, v4, v6);
309*550b6e40SSowmini Varadhan 	return (IPADM_SUCCESS);
310*550b6e40SSowmini Varadhan }
311*550b6e40SSowmini Varadhan 
312*550b6e40SSowmini Varadhan static void
i_ipadm_create_ngz_route(int rtsock,char * link,uint8_t * buf,size_t buflen)313*550b6e40SSowmini Varadhan i_ipadm_create_ngz_route(int rtsock, char *link, uint8_t *buf, size_t buflen)
314*550b6e40SSowmini Varadhan {
315*550b6e40SSowmini Varadhan 	struct in6_addr defrouter;
316*550b6e40SSowmini Varadhan 	boolean_t isv6;
317*550b6e40SSowmini Varadhan 	struct in_addr gw4;
318*550b6e40SSowmini Varadhan 	uint8_t *cp;
319*550b6e40SSowmini Varadhan 	const in6_addr_t ipv6_all_zeros = { 0, 0, 0, 0 };
320*550b6e40SSowmini Varadhan 
321*550b6e40SSowmini Varadhan 	if (rtsock == -1)
322*550b6e40SSowmini Varadhan 		return;
323*550b6e40SSowmini Varadhan 
324*550b6e40SSowmini Varadhan 	for (cp = buf; cp < buf + buflen; cp += sizeof (defrouter)) {
325*550b6e40SSowmini Varadhan 		bcopy(cp, &defrouter, sizeof (defrouter));
326*550b6e40SSowmini Varadhan 		if (IN6_IS_ADDR_UNSPECIFIED(&defrouter))
327*550b6e40SSowmini Varadhan 			break;
328*550b6e40SSowmini Varadhan 		isv6 = !IN6_IS_ADDR_V4MAPPED(&defrouter);
329*550b6e40SSowmini Varadhan 		if (isv6) {
330*550b6e40SSowmini Varadhan 			i_ipadm_rtioctl6(rtsock, RTM_ADD, ipv6_all_zeros,
331*550b6e40SSowmini Varadhan 			    defrouter, 0, link, RTF_GATEWAY);
332*550b6e40SSowmini Varadhan 		} else {
333*550b6e40SSowmini Varadhan 			IN6_V4MAPPED_TO_INADDR(&defrouter, &gw4);
334*550b6e40SSowmini Varadhan 			i_ipadm_rtioctl4(rtsock, RTM_ADD, INADDR_ANY,
335*550b6e40SSowmini Varadhan 			    gw4.s_addr, 0, link, 0, RTF_GATEWAY);
336*550b6e40SSowmini Varadhan 		}
337*550b6e40SSowmini Varadhan 	}
338*550b6e40SSowmini Varadhan }
339*550b6e40SSowmini Varadhan 
340*550b6e40SSowmini Varadhan /*
341*550b6e40SSowmini Varadhan  * Wrapper function to zone_getattr() for retrieving from-gz attributes that
342*550b6e40SSowmini Varadhan  * were made availabe for exclusive IP non-global zones by zoneadmd from teh
343*550b6e40SSowmini Varadhan  * global zone.
344*550b6e40SSowmini Varadhan  */
345*550b6e40SSowmini Varadhan static ipadm_status_t
i_ipadm_zone_get_network(zoneid_t zoneid,datalink_id_t linkid,int type,void * buf,size_t * bufsize)346*550b6e40SSowmini Varadhan i_ipadm_zone_get_network(zoneid_t zoneid, datalink_id_t linkid, int type,
347*550b6e40SSowmini Varadhan     void *buf, size_t *bufsize)
348*550b6e40SSowmini Varadhan {
349*550b6e40SSowmini Varadhan 	zone_net_data_t *zndata;
350*550b6e40SSowmini Varadhan 
351*550b6e40SSowmini Varadhan 	zndata = calloc(1, sizeof (*zndata) + *bufsize);
352*550b6e40SSowmini Varadhan 	if (zndata == NULL)
353*550b6e40SSowmini Varadhan 		return (IPADM_NO_MEMORY);
354*550b6e40SSowmini Varadhan 	zndata->zn_type = type;
355*550b6e40SSowmini Varadhan 	zndata->zn_linkid = linkid;
356*550b6e40SSowmini Varadhan 	zndata->zn_len = *bufsize;
357*550b6e40SSowmini Varadhan 
358*550b6e40SSowmini Varadhan 	if (zone_getattr(zoneid, ZONE_ATTR_NETWORK, zndata,
359*550b6e40SSowmini Varadhan 	    sizeof (*zndata) + *bufsize) < 0) {
360*550b6e40SSowmini Varadhan 		return (ipadm_errno2status(errno));
361*550b6e40SSowmini Varadhan 	}
362*550b6e40SSowmini Varadhan 	*bufsize = zndata->zn_len;
363*550b6e40SSowmini Varadhan 	bcopy(zndata->zn_val, buf, *bufsize);
364*550b6e40SSowmini Varadhan 	return (IPADM_SUCCESS);
365*550b6e40SSowmini Varadhan }
366*550b6e40SSowmini Varadhan 
367*550b6e40SSowmini Varadhan /*
368*550b6e40SSowmini Varadhan  * Callback function that configures a single datalink in a non-global zone.
369*550b6e40SSowmini Varadhan  */
370*550b6e40SSowmini Varadhan static int
i_ipadm_zone_network_attr(dladm_handle_t dh,datalink_id_t linkid,void * arg)371*550b6e40SSowmini Varadhan i_ipadm_zone_network_attr(dladm_handle_t dh, datalink_id_t linkid, void *arg)
372*550b6e40SSowmini Varadhan {
373*550b6e40SSowmini Varadhan 	ngz_walk_data_t *nwd = arg;
374*550b6e40SSowmini Varadhan 	zoneid_t zoneid = nwd->ngz_zoneid;
375*550b6e40SSowmini Varadhan 	uint8_t buf[PIPE_BUF];
376*550b6e40SSowmini Varadhan 	dladm_status_t dlstatus;
377*550b6e40SSowmini Varadhan 	ipadm_status_t ipstatus;
378*550b6e40SSowmini Varadhan 	char link[MAXLINKNAMELEN];
379*550b6e40SSowmini Varadhan 	ipadm_handle_t iph = nwd->ngz_iph;
380*550b6e40SSowmini Varadhan 	int rtsock = iph->iph_rtsock;
381*550b6e40SSowmini Varadhan 	char *ifname = nwd->ngz_ifname;
382*550b6e40SSowmini Varadhan 	boolean_t s10c = nwd->ngz_s10c;
383*550b6e40SSowmini Varadhan 	boolean_t is_ipmgmtd = (iph->iph_flags & IPH_IPMGMTD);
384*550b6e40SSowmini Varadhan 	size_t bufsize = sizeof (buf);
385*550b6e40SSowmini Varadhan 
386*550b6e40SSowmini Varadhan 	bzero(buf, bufsize);
387*550b6e40SSowmini Varadhan 	ipstatus = i_ipadm_zone_get_network(zoneid, linkid,
388*550b6e40SSowmini Varadhan 	    ZONE_NETWORK_ADDRESS, buf, &bufsize);
389*550b6e40SSowmini Varadhan 	if (ipstatus != IPADM_SUCCESS)
390*550b6e40SSowmini Varadhan 		goto fail;
391*550b6e40SSowmini Varadhan 
392*550b6e40SSowmini Varadhan 	dlstatus = dladm_datalink_id2info(dh, linkid, NULL, NULL,
393*550b6e40SSowmini Varadhan 	    NULL, link, sizeof (link));
394*550b6e40SSowmini Varadhan 	if (dlstatus != DLADM_STATUS_OK)
395*550b6e40SSowmini Varadhan 		return (DLADM_WALK_CONTINUE);
396*550b6e40SSowmini Varadhan 
397*550b6e40SSowmini Varadhan 	/*
398*550b6e40SSowmini Varadhan 	 * if ifname has been specified, then skip interfaces that don't match
399*550b6e40SSowmini Varadhan 	 */
400*550b6e40SSowmini Varadhan 	if (ifname != NULL && strcmp(ifname, link) != 0)
401*550b6e40SSowmini Varadhan 		return (DLADM_WALK_CONTINUE);
402*550b6e40SSowmini Varadhan 
403*550b6e40SSowmini Varadhan 	/*
404*550b6e40SSowmini Varadhan 	 * Plumb the interface and configure addresses on for S10 Containers.
405*550b6e40SSowmini Varadhan 	 * We need to always do this for S10C because ipadm persistent
406*550b6e40SSowmini Varadhan 	 * configuration is not available in S10C. For ipkg zones,
407*550b6e40SSowmini Varadhan 	 * we skip the actual plumbing/configuration, but will call the
408*550b6e40SSowmini Varadhan 	 * (*ngz_persist_if)() callback to create the persistent state for the
409*550b6e40SSowmini Varadhan 	 * interface. The interface will be configured in ipkg zones when
410*550b6e40SSowmini Varadhan 	 * ipadm_enable_if() is invoked to restore persistent configuration.
411*550b6e40SSowmini Varadhan 	 */
412*550b6e40SSowmini Varadhan 	if (is_ipmgmtd && !s10c) {
413*550b6e40SSowmini Varadhan 		(void) i_ipadm_ngz_persist_if(link, (char *)buf,
414*550b6e40SSowmini Varadhan 		    nwd->ngz_persist_if);
415*550b6e40SSowmini Varadhan 		return (DLADM_WALK_CONTINUE);
416*550b6e40SSowmini Varadhan 	}
417*550b6e40SSowmini Varadhan 	ipstatus = i_ipadm_ngz_addr(iph, link, (char *)buf);
418*550b6e40SSowmini Varadhan 	if (ipstatus != IPADM_SUCCESS)
419*550b6e40SSowmini Varadhan 		goto fail;
420*550b6e40SSowmini Varadhan 
421*550b6e40SSowmini Varadhan 	/* apply any default router information.  */
422*550b6e40SSowmini Varadhan 	bufsize = sizeof (buf);
423*550b6e40SSowmini Varadhan 	bzero(buf, bufsize);
424*550b6e40SSowmini Varadhan 	ipstatus = i_ipadm_zone_get_network(zoneid, linkid,
425*550b6e40SSowmini Varadhan 	    ZONE_NETWORK_DEFROUTER, buf, &bufsize);
426*550b6e40SSowmini Varadhan 	if (ipstatus != IPADM_SUCCESS)
427*550b6e40SSowmini Varadhan 		goto fail;
428*550b6e40SSowmini Varadhan 
429*550b6e40SSowmini Varadhan 	i_ipadm_create_ngz_route(rtsock, link, buf, bufsize);
430*550b6e40SSowmini Varadhan 
431*550b6e40SSowmini Varadhan 	return (DLADM_WALK_CONTINUE);
432*550b6e40SSowmini Varadhan fail:
433*550b6e40SSowmini Varadhan 	if (ifname != NULL) {
434*550b6e40SSowmini Varadhan 		nwd->ngz_ipstatus = ipstatus;
435*550b6e40SSowmini Varadhan 		return (DLADM_WALK_TERMINATE);
436*550b6e40SSowmini Varadhan 	}
437*550b6e40SSowmini Varadhan 	return (DLADM_WALK_CONTINUE);
438*550b6e40SSowmini Varadhan }
439*550b6e40SSowmini Varadhan 
440*550b6e40SSowmini Varadhan /*
441*550b6e40SSowmini Varadhan  * ipmgmt_net_from_gz_init() initializes exclusive-IP stack non-global zones by
442*550b6e40SSowmini Varadhan  * extracting configuration that has been saved in the kernel and applying
443*550b6e40SSowmini Varadhan  * that information to the appropriate datalinks for the zone. If an ifname
444*550b6e40SSowmini Varadhan  * argument is passed in, only the selected IP interface corresponding to
445*550b6e40SSowmini Varadhan  * datalink will be initialized, otherwise all datalinks will be plumbed for IP
446*550b6e40SSowmini Varadhan  * and IP address and route information will be configured.
447*550b6e40SSowmini Varadhan  */
448*550b6e40SSowmini Varadhan ipadm_status_t
ipadm_init_net_from_gz(ipadm_handle_t iph,char * ifname,void (* persist_if)(char *,boolean_t,boolean_t))449*550b6e40SSowmini Varadhan ipadm_init_net_from_gz(ipadm_handle_t iph, char *ifname,
450*550b6e40SSowmini Varadhan 	void (*persist_if)(char *, boolean_t, boolean_t))
451*550b6e40SSowmini Varadhan {
452*550b6e40SSowmini Varadhan 	ngz_walk_data_t nwd;
453*550b6e40SSowmini Varadhan 	uint64_t flags;
454*550b6e40SSowmini Varadhan 	dladm_handle_t dlh = iph->iph_dlh;
455*550b6e40SSowmini Varadhan 	datalink_id_t linkid;
456*550b6e40SSowmini Varadhan 
457*550b6e40SSowmini Varadhan 	if (iph->iph_zoneid == GLOBAL_ZONEID)
458*550b6e40SSowmini Varadhan 		return (IPADM_NOTSUP);
459*550b6e40SSowmini Varadhan 
460*550b6e40SSowmini Varadhan 	if (ifname != NULL &&
461*550b6e40SSowmini Varadhan 	    i_ipadm_get_flags(iph, ifname, AF_INET, &flags) != IPADM_SUCCESS &&
462*550b6e40SSowmini Varadhan 	    i_ipadm_get_flags(iph, ifname, AF_INET6, &flags) != IPADM_SUCCESS)
463*550b6e40SSowmini Varadhan 		return (IPADM_ENXIO);
464*550b6e40SSowmini Varadhan 
465*550b6e40SSowmini Varadhan 	if (ifname != NULL && !(flags & IFF_L3PROTECT))
466*550b6e40SSowmini Varadhan 		return (IPADM_SUCCESS); /* nothing to initialize */
467*550b6e40SSowmini Varadhan 
468*550b6e40SSowmini Varadhan 	nwd.ngz_iph = iph;
469*550b6e40SSowmini Varadhan 	nwd.ngz_zoneid = iph->iph_zoneid;
470*550b6e40SSowmini Varadhan 	nwd.ngz_ifname = ifname;
471*550b6e40SSowmini Varadhan 	nwd.ngz_persist_if = persist_if;
472*550b6e40SSowmini Varadhan 	nwd.ngz_s10c = i_ipadm_zone_is_s10c(iph->iph_zoneid);
473*550b6e40SSowmini Varadhan 	nwd.ngz_ipstatus = IPADM_SUCCESS;
474*550b6e40SSowmini Varadhan 	if (ifname != NULL) {
475*550b6e40SSowmini Varadhan 		if (dladm_name2info(dlh, ifname, &linkid, NULL, NULL,
476*550b6e40SSowmini Varadhan 		    NULL) != DLADM_STATUS_OK) {
477*550b6e40SSowmini Varadhan 			return (IPADM_ENXIO);
478*550b6e40SSowmini Varadhan 		}
479*550b6e40SSowmini Varadhan 		(void) i_ipadm_zone_network_attr(dlh, linkid, &nwd);
480*550b6e40SSowmini Varadhan 	} else {
481*550b6e40SSowmini Varadhan 		(void) dladm_walk_datalink_id(i_ipadm_zone_network_attr, dlh,
482*550b6e40SSowmini Varadhan 		    &nwd, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
483*550b6e40SSowmini Varadhan 		    DLADM_OPT_PERSIST);
484*550b6e40SSowmini Varadhan 	}
485*550b6e40SSowmini Varadhan 	return (nwd.ngz_ipstatus);
486*550b6e40SSowmini Varadhan }
487