1*36589d6bSRobert Mustacchi /*
2*36589d6bSRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*36589d6bSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*36589d6bSRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*36589d6bSRobert Mustacchi  * 1.0 of the CDDL.
6*36589d6bSRobert Mustacchi  *
7*36589d6bSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*36589d6bSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*36589d6bSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*36589d6bSRobert Mustacchi  */
11*36589d6bSRobert Mustacchi 
12*36589d6bSRobert Mustacchi /*
13*36589d6bSRobert Mustacchi  * Copyright 2016 Joyent, Inc.
14*36589d6bSRobert Mustacchi  */
15*36589d6bSRobert Mustacchi 
16*36589d6bSRobert Mustacchi /*
17*36589d6bSRobert Mustacchi  * Point to point plug-in for varpd.
18*36589d6bSRobert Mustacchi  *
19*36589d6bSRobert Mustacchi  * This plugin implements a simple point to point plugin for a packet. It
20*36589d6bSRobert Mustacchi  * represents the traditional tunnel, just in overlay form. As such, the only
21*36589d6bSRobert Mustacchi  * properties it needs are those to determine where to send everything. At this
22*36589d6bSRobert Mustacchi  * time, we don't allow a multicast address; however, there's no reason that the
23*36589d6bSRobert Mustacchi  * direct plugin shouldn't in theory support multicast, though when implementing
24*36589d6bSRobert Mustacchi  * it the best path will become clear.
25*36589d6bSRobert Mustacchi  *
26*36589d6bSRobert Mustacchi  * In general this module has been designed to make it easy to support a
27*36589d6bSRobert Mustacchi  * destination of either IP or IP and port; however, we restrict it to the
28*36589d6bSRobert Mustacchi  * latter as we don't currently have an implementation that would allow us to
29*36589d6bSRobert Mustacchi  * test that.
30*36589d6bSRobert Mustacchi  */
31*36589d6bSRobert Mustacchi 
32*36589d6bSRobert Mustacchi #include <libvarpd_provider.h>
33*36589d6bSRobert Mustacchi #include <umem.h>
34*36589d6bSRobert Mustacchi #include <errno.h>
35*36589d6bSRobert Mustacchi #include <thread.h>
36*36589d6bSRobert Mustacchi #include <synch.h>
37*36589d6bSRobert Mustacchi #include <strings.h>
38*36589d6bSRobert Mustacchi #include <assert.h>
39*36589d6bSRobert Mustacchi #include <limits.h>
40*36589d6bSRobert Mustacchi #include <sys/types.h>
41*36589d6bSRobert Mustacchi #include <sys/socket.h>
42*36589d6bSRobert Mustacchi #include <netinet/in.h>
43*36589d6bSRobert Mustacchi #include <arpa/inet.h>
44*36589d6bSRobert Mustacchi #include <libnvpair.h>
45*36589d6bSRobert Mustacchi 
46*36589d6bSRobert Mustacchi typedef struct varpd_direct {
47*36589d6bSRobert Mustacchi 	overlay_plugin_dest_t	vad_dest;	/* RO */
48*36589d6bSRobert Mustacchi 	mutex_t			vad_lock;	/* Protects the rest */
49*36589d6bSRobert Mustacchi 	boolean_t		vad_hip;
50*36589d6bSRobert Mustacchi 	boolean_t		vad_hport;
51*36589d6bSRobert Mustacchi 	struct in6_addr		vad_ip;
52*36589d6bSRobert Mustacchi 	uint16_t		vad_port;
53*36589d6bSRobert Mustacchi } varpd_direct_t;
54*36589d6bSRobert Mustacchi 
55*36589d6bSRobert Mustacchi static const char *varpd_direct_props[] = {
56*36589d6bSRobert Mustacchi 	"direct/dest_ip",
57*36589d6bSRobert Mustacchi 	"direct/dest_port"
58*36589d6bSRobert Mustacchi };
59*36589d6bSRobert Mustacchi 
60*36589d6bSRobert Mustacchi static boolean_t
varpd_direct_valid_dest(overlay_plugin_dest_t dest)61*36589d6bSRobert Mustacchi varpd_direct_valid_dest(overlay_plugin_dest_t dest)
62*36589d6bSRobert Mustacchi {
63*36589d6bSRobert Mustacchi 	if (dest & ~(OVERLAY_PLUGIN_D_IP | OVERLAY_PLUGIN_D_PORT))
64*36589d6bSRobert Mustacchi 		return (B_FALSE);
65*36589d6bSRobert Mustacchi 
66*36589d6bSRobert Mustacchi 	if (!(dest & (OVERLAY_PLUGIN_D_IP | OVERLAY_PLUGIN_D_PORT)))
67*36589d6bSRobert Mustacchi 		return (B_FALSE);
68*36589d6bSRobert Mustacchi 
69*36589d6bSRobert Mustacchi 	return (B_TRUE);
70*36589d6bSRobert Mustacchi }
71*36589d6bSRobert Mustacchi 
72*36589d6bSRobert Mustacchi /* ARGSUSED */
73*36589d6bSRobert Mustacchi static int
varpd_direct_create(varpd_provider_handle_t * hdl,void ** outp,overlay_plugin_dest_t dest)74*36589d6bSRobert Mustacchi varpd_direct_create(varpd_provider_handle_t *hdl, void **outp,
75*36589d6bSRobert Mustacchi     overlay_plugin_dest_t dest)
76*36589d6bSRobert Mustacchi {
77*36589d6bSRobert Mustacchi 	int ret;
78*36589d6bSRobert Mustacchi 	varpd_direct_t *vdp;
79*36589d6bSRobert Mustacchi 
80*36589d6bSRobert Mustacchi 	if (varpd_direct_valid_dest(dest) == B_FALSE)
81*36589d6bSRobert Mustacchi 		return (ENOTSUP);
82*36589d6bSRobert Mustacchi 
83*36589d6bSRobert Mustacchi 	vdp = umem_alloc(sizeof (varpd_direct_t), UMEM_DEFAULT);
84*36589d6bSRobert Mustacchi 	if (vdp == NULL)
85*36589d6bSRobert Mustacchi 		return (ENOMEM);
86*36589d6bSRobert Mustacchi 
87*36589d6bSRobert Mustacchi 	if ((ret = mutex_init(&vdp->vad_lock, USYNC_THREAD | LOCK_ERRORCHECK,
88*36589d6bSRobert Mustacchi 	    NULL)) != 0) {
89*36589d6bSRobert Mustacchi 		umem_free(vdp, sizeof (varpd_direct_t));
90*36589d6bSRobert Mustacchi 		return (ret);
91*36589d6bSRobert Mustacchi 	}
92*36589d6bSRobert Mustacchi 
93*36589d6bSRobert Mustacchi 	vdp->vad_dest = dest;
94*36589d6bSRobert Mustacchi 	vdp->vad_hip = B_FALSE;
95*36589d6bSRobert Mustacchi 	vdp->vad_hport = B_FALSE;
96*36589d6bSRobert Mustacchi 	*outp = vdp;
97*36589d6bSRobert Mustacchi 	return (0);
98*36589d6bSRobert Mustacchi }
99*36589d6bSRobert Mustacchi 
100*36589d6bSRobert Mustacchi static int
varpd_direct_start(void * arg)101*36589d6bSRobert Mustacchi varpd_direct_start(void *arg)
102*36589d6bSRobert Mustacchi {
103*36589d6bSRobert Mustacchi 	varpd_direct_t *vdp = arg;
104*36589d6bSRobert Mustacchi 
105*36589d6bSRobert Mustacchi 	mutex_enter(&vdp->vad_lock);
106*36589d6bSRobert Mustacchi 	if (vdp->vad_hip == B_FALSE ||((vdp->vad_dest & OVERLAY_PLUGIN_D_IP) &&
107*36589d6bSRobert Mustacchi 	    vdp->vad_hport == B_FALSE)) {
108*36589d6bSRobert Mustacchi 		mutex_exit(&vdp->vad_lock);
109*36589d6bSRobert Mustacchi 		return (EAGAIN);
110*36589d6bSRobert Mustacchi 	}
111*36589d6bSRobert Mustacchi 	mutex_exit(&vdp->vad_lock);
112*36589d6bSRobert Mustacchi 
113*36589d6bSRobert Mustacchi 	return (0);
114*36589d6bSRobert Mustacchi }
115*36589d6bSRobert Mustacchi 
116*36589d6bSRobert Mustacchi /* ARGSUSED */
117*36589d6bSRobert Mustacchi static void
varpd_direct_stop(void * arg)118*36589d6bSRobert Mustacchi varpd_direct_stop(void *arg)
119*36589d6bSRobert Mustacchi {
120*36589d6bSRobert Mustacchi }
121*36589d6bSRobert Mustacchi 
122*36589d6bSRobert Mustacchi static void
varpd_direct_destroy(void * arg)123*36589d6bSRobert Mustacchi varpd_direct_destroy(void *arg)
124*36589d6bSRobert Mustacchi {
125*36589d6bSRobert Mustacchi 	varpd_direct_t *vdp = arg;
126*36589d6bSRobert Mustacchi 
127*36589d6bSRobert Mustacchi 	if (mutex_destroy(&vdp->vad_lock) != 0)
128*36589d6bSRobert Mustacchi 		abort();
129*36589d6bSRobert Mustacchi 	umem_free(vdp, sizeof (varpd_direct_t));
130*36589d6bSRobert Mustacchi }
131*36589d6bSRobert Mustacchi 
132*36589d6bSRobert Mustacchi static int
varpd_direct_default(void * arg,overlay_target_point_t * otp)133*36589d6bSRobert Mustacchi varpd_direct_default(void *arg, overlay_target_point_t *otp)
134*36589d6bSRobert Mustacchi {
135*36589d6bSRobert Mustacchi 	varpd_direct_t *vdp = arg;
136*36589d6bSRobert Mustacchi 
137*36589d6bSRobert Mustacchi 	mutex_enter(&vdp->vad_lock);
138*36589d6bSRobert Mustacchi 	bcopy(&vdp->vad_ip, &otp->otp_ip, sizeof (struct in6_addr));
139*36589d6bSRobert Mustacchi 	otp->otp_port = vdp->vad_port;
140*36589d6bSRobert Mustacchi 	mutex_exit(&vdp->vad_lock);
141*36589d6bSRobert Mustacchi 
142*36589d6bSRobert Mustacchi 	return (VARPD_LOOKUP_OK);
143*36589d6bSRobert Mustacchi }
144*36589d6bSRobert Mustacchi 
145*36589d6bSRobert Mustacchi static int
varpd_direct_nprops(void * arg,uint_t * nprops)146*36589d6bSRobert Mustacchi varpd_direct_nprops(void *arg, uint_t *nprops)
147*36589d6bSRobert Mustacchi {
148*36589d6bSRobert Mustacchi 	const varpd_direct_t *vdp = arg;
149*36589d6bSRobert Mustacchi 
150*36589d6bSRobert Mustacchi 	*nprops = 0;
151*36589d6bSRobert Mustacchi 	if (vdp->vad_dest & OVERLAY_PLUGIN_D_ETHERNET)
152*36589d6bSRobert Mustacchi 		*nprops += 1;
153*36589d6bSRobert Mustacchi 
154*36589d6bSRobert Mustacchi 	if (vdp->vad_dest & OVERLAY_PLUGIN_D_IP)
155*36589d6bSRobert Mustacchi 		*nprops += 1;
156*36589d6bSRobert Mustacchi 
157*36589d6bSRobert Mustacchi 	if (vdp->vad_dest & OVERLAY_PLUGIN_D_PORT)
158*36589d6bSRobert Mustacchi 		*nprops += 1;
159*36589d6bSRobert Mustacchi 
160*36589d6bSRobert Mustacchi 	assert(*nprops == 1 || *nprops == 2);
161*36589d6bSRobert Mustacchi 
162*36589d6bSRobert Mustacchi 	return (0);
163*36589d6bSRobert Mustacchi }
164*36589d6bSRobert Mustacchi 
165*36589d6bSRobert Mustacchi static int
varpd_direct_propinfo(void * arg,uint_t propid,varpd_prop_handle_t * vph)166*36589d6bSRobert Mustacchi varpd_direct_propinfo(void *arg, uint_t propid, varpd_prop_handle_t *vph)
167*36589d6bSRobert Mustacchi {
168*36589d6bSRobert Mustacchi 	varpd_direct_t *vdp = arg;
169*36589d6bSRobert Mustacchi 
170*36589d6bSRobert Mustacchi 	/*
171*36589d6bSRobert Mustacchi 	 * Because we only support IP + port combos right now, prop 0 should
172*36589d6bSRobert Mustacchi 	 * always be the IP. We don't support a port without an IP.
173*36589d6bSRobert Mustacchi 	 */
174*36589d6bSRobert Mustacchi 	assert(vdp->vad_dest & OVERLAY_PLUGIN_D_IP);
175*36589d6bSRobert Mustacchi 	if (propid == 0) {
176*36589d6bSRobert Mustacchi 		libvarpd_prop_set_name(vph, varpd_direct_props[0]);
177*36589d6bSRobert Mustacchi 		libvarpd_prop_set_prot(vph, OVERLAY_PROP_PERM_RRW);
178*36589d6bSRobert Mustacchi 		libvarpd_prop_set_type(vph, OVERLAY_PROP_T_IP);
179*36589d6bSRobert Mustacchi 		libvarpd_prop_set_nodefault(vph);
180*36589d6bSRobert Mustacchi 		return (0);
181*36589d6bSRobert Mustacchi 	}
182*36589d6bSRobert Mustacchi 
183*36589d6bSRobert Mustacchi 	if (propid == 1 && vdp->vad_dest & OVERLAY_PLUGIN_D_PORT) {
184*36589d6bSRobert Mustacchi 		libvarpd_prop_set_name(vph, varpd_direct_props[1]);
185*36589d6bSRobert Mustacchi 		libvarpd_prop_set_prot(vph, OVERLAY_PROP_PERM_RRW);
186*36589d6bSRobert Mustacchi 		libvarpd_prop_set_type(vph, OVERLAY_PROP_T_UINT);
187*36589d6bSRobert Mustacchi 		libvarpd_prop_set_nodefault(vph);
188*36589d6bSRobert Mustacchi 		libvarpd_prop_set_range_uint32(vph, 1, UINT16_MAX);
189*36589d6bSRobert Mustacchi 		return (0);
190*36589d6bSRobert Mustacchi 	}
191*36589d6bSRobert Mustacchi 
192*36589d6bSRobert Mustacchi 	return (EINVAL);
193*36589d6bSRobert Mustacchi }
194*36589d6bSRobert Mustacchi 
195*36589d6bSRobert Mustacchi static int
varpd_direct_getprop(void * arg,const char * pname,void * buf,uint32_t * sizep)196*36589d6bSRobert Mustacchi varpd_direct_getprop(void *arg, const char *pname, void *buf, uint32_t *sizep)
197*36589d6bSRobert Mustacchi {
198*36589d6bSRobert Mustacchi 	varpd_direct_t *vdp = arg;
199*36589d6bSRobert Mustacchi 
200*36589d6bSRobert Mustacchi 	/* direct/dest_ip */
201*36589d6bSRobert Mustacchi 	if (strcmp(pname, varpd_direct_props[0]) == 0) {
202*36589d6bSRobert Mustacchi 		if (*sizep < sizeof (struct in6_addr))
203*36589d6bSRobert Mustacchi 			return (EOVERFLOW);
204*36589d6bSRobert Mustacchi 		mutex_enter(&vdp->vad_lock);
205*36589d6bSRobert Mustacchi 		if (vdp->vad_hip == B_FALSE) {
206*36589d6bSRobert Mustacchi 			*sizep = 0;
207*36589d6bSRobert Mustacchi 		} else {
208*36589d6bSRobert Mustacchi 			bcopy(&vdp->vad_ip, buf, sizeof (struct in6_addr));
209*36589d6bSRobert Mustacchi 			*sizep = sizeof (struct in6_addr);
210*36589d6bSRobert Mustacchi 		}
211*36589d6bSRobert Mustacchi 		mutex_exit(&vdp->vad_lock);
212*36589d6bSRobert Mustacchi 		return (0);
213*36589d6bSRobert Mustacchi 	}
214*36589d6bSRobert Mustacchi 
215*36589d6bSRobert Mustacchi 	/* direct/dest_port */
216*36589d6bSRobert Mustacchi 	if (strcmp(pname, varpd_direct_props[1]) == 0) {
217*36589d6bSRobert Mustacchi 		uint64_t val;
218*36589d6bSRobert Mustacchi 
219*36589d6bSRobert Mustacchi 		if (*sizep < sizeof (uint64_t))
220*36589d6bSRobert Mustacchi 			return (EOVERFLOW);
221*36589d6bSRobert Mustacchi 		mutex_enter(&vdp->vad_lock);
222*36589d6bSRobert Mustacchi 		if (vdp->vad_hport == B_FALSE) {
223*36589d6bSRobert Mustacchi 			*sizep = 0;
224*36589d6bSRobert Mustacchi 		} else {
225*36589d6bSRobert Mustacchi 			val = vdp->vad_port;
226*36589d6bSRobert Mustacchi 			bcopy(&val, buf, sizeof (uint64_t));
227*36589d6bSRobert Mustacchi 			*sizep = sizeof (uint64_t);
228*36589d6bSRobert Mustacchi 		}
229*36589d6bSRobert Mustacchi 		mutex_exit(&vdp->vad_lock);
230*36589d6bSRobert Mustacchi 		return (0);
231*36589d6bSRobert Mustacchi 	}
232*36589d6bSRobert Mustacchi 
233*36589d6bSRobert Mustacchi 	return (EINVAL);
234*36589d6bSRobert Mustacchi }
235*36589d6bSRobert Mustacchi 
236*36589d6bSRobert Mustacchi static int
varpd_direct_setprop(void * arg,const char * pname,const void * buf,const uint32_t size)237*36589d6bSRobert Mustacchi varpd_direct_setprop(void *arg, const char *pname, const void *buf,
238*36589d6bSRobert Mustacchi     const uint32_t size)
239*36589d6bSRobert Mustacchi {
240*36589d6bSRobert Mustacchi 	varpd_direct_t *vdp = arg;
241*36589d6bSRobert Mustacchi 
242*36589d6bSRobert Mustacchi 	/* direct/dest_ip */
243*36589d6bSRobert Mustacchi 	if (strcmp(pname, varpd_direct_props[0]) == 0) {
244*36589d6bSRobert Mustacchi 		const struct in6_addr *ipv6 = buf;
245*36589d6bSRobert Mustacchi 
246*36589d6bSRobert Mustacchi 		if (size < sizeof (struct in6_addr))
247*36589d6bSRobert Mustacchi 			return (EOVERFLOW);
248*36589d6bSRobert Mustacchi 
249*36589d6bSRobert Mustacchi 		if (IN6_IS_ADDR_V4COMPAT(ipv6))
250*36589d6bSRobert Mustacchi 			return (EINVAL);
251*36589d6bSRobert Mustacchi 
252*36589d6bSRobert Mustacchi 		if (IN6_IS_ADDR_6TO4(ipv6))
253*36589d6bSRobert Mustacchi 			return (EINVAL);
254*36589d6bSRobert Mustacchi 
255*36589d6bSRobert Mustacchi 		mutex_enter(&vdp->vad_lock);
256*36589d6bSRobert Mustacchi 		bcopy(buf, &vdp->vad_ip, sizeof (struct in6_addr));
257*36589d6bSRobert Mustacchi 		vdp->vad_hip = B_TRUE;
258*36589d6bSRobert Mustacchi 		mutex_exit(&vdp->vad_lock);
259*36589d6bSRobert Mustacchi 		return (0);
260*36589d6bSRobert Mustacchi 	}
261*36589d6bSRobert Mustacchi 
262*36589d6bSRobert Mustacchi 	/* direct/dest_port */
263*36589d6bSRobert Mustacchi 	if (strcmp(pname, varpd_direct_props[1]) == 0) {
264*36589d6bSRobert Mustacchi 		const uint64_t *valp = buf;
265*36589d6bSRobert Mustacchi 		if (size < sizeof (uint64_t))
266*36589d6bSRobert Mustacchi 			return (EOVERFLOW);
267*36589d6bSRobert Mustacchi 
268*36589d6bSRobert Mustacchi 		if (*valp == 0 || *valp > UINT16_MAX)
269*36589d6bSRobert Mustacchi 			return (EINVAL);
270*36589d6bSRobert Mustacchi 
271*36589d6bSRobert Mustacchi 		mutex_enter(&vdp->vad_lock);
272*36589d6bSRobert Mustacchi 		vdp->vad_port = (uint16_t)*valp;
273*36589d6bSRobert Mustacchi 		vdp->vad_hport = B_TRUE;
274*36589d6bSRobert Mustacchi 		mutex_exit(&vdp->vad_lock);
275*36589d6bSRobert Mustacchi 		return (0);
276*36589d6bSRobert Mustacchi 	}
277*36589d6bSRobert Mustacchi 
278*36589d6bSRobert Mustacchi 	return (EINVAL);
279*36589d6bSRobert Mustacchi }
280*36589d6bSRobert Mustacchi 
281*36589d6bSRobert Mustacchi static int
varpd_direct_save(void * arg,nvlist_t * nvp)282*36589d6bSRobert Mustacchi varpd_direct_save(void *arg, nvlist_t *nvp)
283*36589d6bSRobert Mustacchi {
284*36589d6bSRobert Mustacchi 	int ret;
285*36589d6bSRobert Mustacchi 	varpd_direct_t *vdp = arg;
286*36589d6bSRobert Mustacchi 
287*36589d6bSRobert Mustacchi 	mutex_enter(&vdp->vad_lock);
288*36589d6bSRobert Mustacchi 	if (vdp->vad_hport == B_TRUE) {
289*36589d6bSRobert Mustacchi 		if ((ret = nvlist_add_uint16(nvp, varpd_direct_props[1],
290*36589d6bSRobert Mustacchi 		    vdp->vad_port)) != 0) {
291*36589d6bSRobert Mustacchi 			mutex_exit(&vdp->vad_lock);
292*36589d6bSRobert Mustacchi 			return (ret);
293*36589d6bSRobert Mustacchi 		}
294*36589d6bSRobert Mustacchi 	}
295*36589d6bSRobert Mustacchi 
296*36589d6bSRobert Mustacchi 	if (vdp->vad_hip == B_TRUE) {
297*36589d6bSRobert Mustacchi 		char buf[INET6_ADDRSTRLEN];
298*36589d6bSRobert Mustacchi 
299*36589d6bSRobert Mustacchi 		if (inet_ntop(AF_INET6, &vdp->vad_ip, buf, sizeof (buf)) ==
300*36589d6bSRobert Mustacchi 		    NULL)
301*36589d6bSRobert Mustacchi 			abort();
302*36589d6bSRobert Mustacchi 		if ((ret = nvlist_add_string(nvp, varpd_direct_props[0],
303*36589d6bSRobert Mustacchi 		    buf)) != 0) {
304*36589d6bSRobert Mustacchi 			mutex_exit(&vdp->vad_lock);
305*36589d6bSRobert Mustacchi 			return (ret);
306*36589d6bSRobert Mustacchi 		}
307*36589d6bSRobert Mustacchi 	}
308*36589d6bSRobert Mustacchi 	mutex_exit(&vdp->vad_lock);
309*36589d6bSRobert Mustacchi 
310*36589d6bSRobert Mustacchi 	return (0);
311*36589d6bSRobert Mustacchi }
312*36589d6bSRobert Mustacchi 
313*36589d6bSRobert Mustacchi /* ARGSUSED */
314*36589d6bSRobert Mustacchi static int
varpd_direct_restore(nvlist_t * nvp,varpd_provider_handle_t * hdl,overlay_plugin_dest_t dest,void ** outp)315*36589d6bSRobert Mustacchi varpd_direct_restore(nvlist_t *nvp, varpd_provider_handle_t *hdl,
316*36589d6bSRobert Mustacchi     overlay_plugin_dest_t dest, void **outp)
317*36589d6bSRobert Mustacchi {
318*36589d6bSRobert Mustacchi 	int ret;
319*36589d6bSRobert Mustacchi 	char *ipstr;
320*36589d6bSRobert Mustacchi 	varpd_direct_t *vdp;
321*36589d6bSRobert Mustacchi 
322*36589d6bSRobert Mustacchi 	if (varpd_direct_valid_dest(dest) == B_FALSE)
323*36589d6bSRobert Mustacchi 		return (ENOTSUP);
324*36589d6bSRobert Mustacchi 
325*36589d6bSRobert Mustacchi 	vdp = umem_alloc(sizeof (varpd_direct_t), UMEM_DEFAULT);
326*36589d6bSRobert Mustacchi 	if (vdp == NULL)
327*36589d6bSRobert Mustacchi 		return (ENOMEM);
328*36589d6bSRobert Mustacchi 
329*36589d6bSRobert Mustacchi 	if ((ret = mutex_init(&vdp->vad_lock, USYNC_THREAD | LOCK_ERRORCHECK,
330*36589d6bSRobert Mustacchi 	    NULL)) != 0) {
331*36589d6bSRobert Mustacchi 		umem_free(vdp, sizeof (varpd_direct_t));
332*36589d6bSRobert Mustacchi 		return (ret);
333*36589d6bSRobert Mustacchi 	}
334*36589d6bSRobert Mustacchi 
335*36589d6bSRobert Mustacchi 	if ((ret = nvlist_lookup_uint16(nvp, varpd_direct_props[1],
336*36589d6bSRobert Mustacchi 	    &vdp->vad_port)) != 0) {
337*36589d6bSRobert Mustacchi 		if (ret != ENOENT) {
338*36589d6bSRobert Mustacchi 			if (mutex_destroy(&vdp->vad_lock) != 0)
339*36589d6bSRobert Mustacchi 				abort();
340*36589d6bSRobert Mustacchi 			umem_free(vdp, sizeof (varpd_direct_t));
341*36589d6bSRobert Mustacchi 			return (ret);
342*36589d6bSRobert Mustacchi 		}
343*36589d6bSRobert Mustacchi 		vdp->vad_hport = B_FALSE;
344*36589d6bSRobert Mustacchi 	} else {
345*36589d6bSRobert Mustacchi 		vdp->vad_hport = B_TRUE;
346*36589d6bSRobert Mustacchi 	}
347*36589d6bSRobert Mustacchi 
348*36589d6bSRobert Mustacchi 	if ((ret = nvlist_lookup_string(nvp, varpd_direct_props[0],
349*36589d6bSRobert Mustacchi 	    &ipstr)) != 0) {
350*36589d6bSRobert Mustacchi 		if (ret != ENOENT) {
351*36589d6bSRobert Mustacchi 			if (mutex_destroy(&vdp->vad_lock) != 0)
352*36589d6bSRobert Mustacchi 				abort();
353*36589d6bSRobert Mustacchi 			umem_free(vdp, sizeof (varpd_direct_t));
354*36589d6bSRobert Mustacchi 			return (ret);
355*36589d6bSRobert Mustacchi 		}
356*36589d6bSRobert Mustacchi 		vdp->vad_hip = B_FALSE;
357*36589d6bSRobert Mustacchi 	} else {
358*36589d6bSRobert Mustacchi 		ret = inet_pton(AF_INET6, ipstr, &vdp->vad_ip);
359*36589d6bSRobert Mustacchi 		/*
360*36589d6bSRobert Mustacchi 		 * inet_pton is only defined to return -1 with errno set to
361*36589d6bSRobert Mustacchi 		 * EAFNOSUPPORT, which really, shouldn't happen.
362*36589d6bSRobert Mustacchi 		 */
363*36589d6bSRobert Mustacchi 		if (ret == -1) {
364*36589d6bSRobert Mustacchi 			assert(errno == EAFNOSUPPORT);
365*36589d6bSRobert Mustacchi 			abort();
366*36589d6bSRobert Mustacchi 		}
367*36589d6bSRobert Mustacchi 		if (ret == 0) {
368*36589d6bSRobert Mustacchi 			if (mutex_destroy(&vdp->vad_lock) != 0)
369*36589d6bSRobert Mustacchi 				abort();
370*36589d6bSRobert Mustacchi 			umem_free(vdp, sizeof (varpd_direct_t));
371*36589d6bSRobert Mustacchi 			return (EINVAL);
372*36589d6bSRobert Mustacchi 		}
373*36589d6bSRobert Mustacchi 	}
374*36589d6bSRobert Mustacchi 
375*36589d6bSRobert Mustacchi 	*outp = vdp;
376*36589d6bSRobert Mustacchi 	return (0);
377*36589d6bSRobert Mustacchi }
378*36589d6bSRobert Mustacchi 
379*36589d6bSRobert Mustacchi static const varpd_plugin_ops_t varpd_direct_ops = {
380*36589d6bSRobert Mustacchi 	0,
381*36589d6bSRobert Mustacchi 	varpd_direct_create,
382*36589d6bSRobert Mustacchi 	varpd_direct_start,
383*36589d6bSRobert Mustacchi 	varpd_direct_stop,
384*36589d6bSRobert Mustacchi 	varpd_direct_destroy,
385*36589d6bSRobert Mustacchi 	varpd_direct_default,
386*36589d6bSRobert Mustacchi 	NULL,
387*36589d6bSRobert Mustacchi 	varpd_direct_nprops,
388*36589d6bSRobert Mustacchi 	varpd_direct_propinfo,
389*36589d6bSRobert Mustacchi 	varpd_direct_getprop,
390*36589d6bSRobert Mustacchi 	varpd_direct_setprop,
391*36589d6bSRobert Mustacchi 	varpd_direct_save,
392*36589d6bSRobert Mustacchi 	varpd_direct_restore
393*36589d6bSRobert Mustacchi };
394*36589d6bSRobert Mustacchi 
395*36589d6bSRobert Mustacchi #pragma init(varpd_direct_init)
396*36589d6bSRobert Mustacchi static void
varpd_direct_init(void)397*36589d6bSRobert Mustacchi varpd_direct_init(void)
398*36589d6bSRobert Mustacchi {
399*36589d6bSRobert Mustacchi 	int err;
400*36589d6bSRobert Mustacchi 	varpd_plugin_register_t *vpr;
401*36589d6bSRobert Mustacchi 
402*36589d6bSRobert Mustacchi 	vpr = libvarpd_plugin_alloc(VARPD_CURRENT_VERSION, &err);
403*36589d6bSRobert Mustacchi 	if (vpr == NULL)
404*36589d6bSRobert Mustacchi 		return;
405*36589d6bSRobert Mustacchi 
406*36589d6bSRobert Mustacchi 	vpr->vpr_mode = OVERLAY_TARGET_POINT;
407*36589d6bSRobert Mustacchi 	vpr->vpr_name = "direct";
408*36589d6bSRobert Mustacchi 	vpr->vpr_ops = &varpd_direct_ops;
409*36589d6bSRobert Mustacchi 	(void) libvarpd_plugin_register(vpr);
410*36589d6bSRobert Mustacchi 	libvarpd_plugin_free(vpr);
411*36589d6bSRobert Mustacchi }
412