xref: /titanic_50/usr/src/lib/libdladm/common/flowattr.c (revision da14cebe459d3275048785f25bd869cb09b5307f)
1*da14cebeSEric Cheng /*
2*da14cebeSEric Cheng  * CDDL HEADER START
3*da14cebeSEric Cheng  *
4*da14cebeSEric Cheng  * The contents of this file are subject to the terms of the
5*da14cebeSEric Cheng  * Common Development and Distribution License (the "License").
6*da14cebeSEric Cheng  * You may not use this file except in compliance with the License.
7*da14cebeSEric Cheng  *
8*da14cebeSEric Cheng  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*da14cebeSEric Cheng  * or http://www.opensolaris.org/os/licensing.
10*da14cebeSEric Cheng  * See the License for the specific language governing permissions
11*da14cebeSEric Cheng  * and limitations under the License.
12*da14cebeSEric Cheng  *
13*da14cebeSEric Cheng  * When distributing Covered Code, include this CDDL HEADER in each
14*da14cebeSEric Cheng  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*da14cebeSEric Cheng  * If applicable, add the following below this CDDL HEADER, with the
16*da14cebeSEric Cheng  * fields enclosed by brackets "[]" replaced with your own identifying
17*da14cebeSEric Cheng  * information: Portions Copyright [yyyy] [name of copyright owner]
18*da14cebeSEric Cheng  *
19*da14cebeSEric Cheng  * CDDL HEADER END
20*da14cebeSEric Cheng  */
21*da14cebeSEric Cheng /*
22*da14cebeSEric Cheng  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*da14cebeSEric Cheng  * Use is subject to license terms.
24*da14cebeSEric Cheng  */
25*da14cebeSEric Cheng 
26*da14cebeSEric Cheng #include <errno.h>
27*da14cebeSEric Cheng #include <stdlib.h>
28*da14cebeSEric Cheng #include <strings.h>
29*da14cebeSEric Cheng #include <sys/mac_flow.h>
30*da14cebeSEric Cheng #include <sys/types.h>
31*da14cebeSEric Cheng #include <sys/socket.h>
32*da14cebeSEric Cheng #include <netinet/in.h>
33*da14cebeSEric Cheng #include <arpa/inet.h>
34*da14cebeSEric Cheng #include <netdb.h>
35*da14cebeSEric Cheng #include <net/if_types.h>
36*da14cebeSEric Cheng #include <net/if_dl.h>
37*da14cebeSEric Cheng #include <inet/ip.h>
38*da14cebeSEric Cheng #include <inet/ip6.h>
39*da14cebeSEric Cheng 
40*da14cebeSEric Cheng #include <libdladm.h>
41*da14cebeSEric Cheng #include <libdlflow.h>
42*da14cebeSEric Cheng #include <libdlflow_impl.h>
43*da14cebeSEric Cheng 
44*da14cebeSEric Cheng #define	V4_PART_OF_V6(v6)	((v6)._S6_un._S6_u32[3])
45*da14cebeSEric Cheng 
46*da14cebeSEric Cheng /* max port number for UDP, TCP & SCTP */
47*da14cebeSEric Cheng #define	MAX_PORT	65535
48*da14cebeSEric Cheng 
49*da14cebeSEric Cheng static fad_checkf_t do_check_local_ip;
50*da14cebeSEric Cheng static fad_checkf_t do_check_remote_ip;
51*da14cebeSEric Cheng static fad_checkf_t do_check_protocol;
52*da14cebeSEric Cheng static fad_checkf_t do_check_local_port;
53*da14cebeSEric Cheng 
54*da14cebeSEric Cheng static dladm_status_t do_check_port(char *, boolean_t, flow_desc_t *);
55*da14cebeSEric Cheng 
56*da14cebeSEric Cheng static fattr_desc_t	attr_table[] = {
57*da14cebeSEric Cheng 	{ "local_ip",	do_check_local_ip },
58*da14cebeSEric Cheng 	{ "remote_ip",	do_check_remote_ip },
59*da14cebeSEric Cheng 	{ "transport",	do_check_protocol },
60*da14cebeSEric Cheng 	{ "local_port",	do_check_local_port },
61*da14cebeSEric Cheng 	{ "dsfield",	do_check_dsfield },
62*da14cebeSEric Cheng };
63*da14cebeSEric Cheng 
64*da14cebeSEric Cheng #define	DLADM_MAX_FLOWATTRS	(sizeof (attr_table) / sizeof (fattr_desc_t))
65*da14cebeSEric Cheng 
66*da14cebeSEric Cheng static dladm_status_t
67*da14cebeSEric Cheng do_check_local_ip(char *attr_val, flow_desc_t *fdesc)
68*da14cebeSEric Cheng {
69*da14cebeSEric Cheng 	return (do_check_ip_addr(attr_val, B_TRUE, fdesc));
70*da14cebeSEric Cheng }
71*da14cebeSEric Cheng 
72*da14cebeSEric Cheng static dladm_status_t
73*da14cebeSEric Cheng do_check_remote_ip(char *attr_val, flow_desc_t *fdesc)
74*da14cebeSEric Cheng {
75*da14cebeSEric Cheng 	return (do_check_ip_addr(attr_val, B_FALSE, fdesc));
76*da14cebeSEric Cheng }
77*da14cebeSEric Cheng 
78*da14cebeSEric Cheng dladm_status_t
79*da14cebeSEric Cheng do_check_ip_addr(char *addr_str, boolean_t local, flow_desc_t *fd)
80*da14cebeSEric Cheng {
81*da14cebeSEric Cheng 	struct addrinfo	*info = NULL;
82*da14cebeSEric Cheng 	dladm_status_t	status;
83*da14cebeSEric Cheng 	int		err, prefix_max, prefix_len = 0;
84*da14cebeSEric Cheng 	char		*prefix_str, *endp = NULL;
85*da14cebeSEric Cheng 	flow_mask_t	mask;
86*da14cebeSEric Cheng 	in6_addr_t	*addr;
87*da14cebeSEric Cheng 	uchar_t		*netmask;
88*da14cebeSEric Cheng 
89*da14cebeSEric Cheng 	if ((prefix_str = strchr(addr_str, '/')) != NULL) {
90*da14cebeSEric Cheng 		*prefix_str++ = '\0';
91*da14cebeSEric Cheng 		errno = 0;
92*da14cebeSEric Cheng 		prefix_len = (int)strtol(prefix_str, &endp, 10);
93*da14cebeSEric Cheng 		if (errno != 0 || prefix_len == 0 || *endp != '\0')
94*da14cebeSEric Cheng 			return (DLADM_STATUS_INVALID_PREFIXLEN);
95*da14cebeSEric Cheng 	}
96*da14cebeSEric Cheng 
97*da14cebeSEric Cheng 	err = getaddrinfo(addr_str, NULL, NULL, &info);
98*da14cebeSEric Cheng 	if (err != 0)
99*da14cebeSEric Cheng 		return (DLADM_STATUS_INVALID_IP);
100*da14cebeSEric Cheng 
101*da14cebeSEric Cheng 	mask = FLOW_IP_VERSION;
102*da14cebeSEric Cheng 	if (local) {
103*da14cebeSEric Cheng 		mask |= FLOW_IP_LOCAL;
104*da14cebeSEric Cheng 		addr = &fd->fd_local_addr;
105*da14cebeSEric Cheng 		netmask = (uchar_t *)&fd->fd_local_netmask;
106*da14cebeSEric Cheng 	} else {
107*da14cebeSEric Cheng 		mask |= FLOW_IP_REMOTE;
108*da14cebeSEric Cheng 		addr = &fd->fd_remote_addr;
109*da14cebeSEric Cheng 		netmask = (uchar_t *)&fd->fd_remote_netmask;
110*da14cebeSEric Cheng 	}
111*da14cebeSEric Cheng 
112*da14cebeSEric Cheng 	if (info->ai_family == AF_INET) {
113*da14cebeSEric Cheng 		IN6_INADDR_TO_V4MAPPED(&(((struct sockaddr_in *)
114*da14cebeSEric Cheng 		    (void *)info->ai_addr)->sin_addr), addr);
115*da14cebeSEric Cheng 		prefix_max = IP_ABITS;
116*da14cebeSEric Cheng 		fd->fd_ipversion = IPV4_VERSION;
117*da14cebeSEric Cheng 		netmask = (uchar_t *)
118*da14cebeSEric Cheng 		    &(V4_PART_OF_V6((*((in6_addr_t *)(void *)netmask))));
119*da14cebeSEric Cheng 	} else if (info->ai_family == AF_INET6) {
120*da14cebeSEric Cheng 		*addr = ((struct sockaddr_in6 *)
121*da14cebeSEric Cheng 		    (void *)info->ai_addr)->sin6_addr;
122*da14cebeSEric Cheng 		prefix_max = IPV6_ABITS;
123*da14cebeSEric Cheng 		fd->fd_ipversion = IPV6_VERSION;
124*da14cebeSEric Cheng 	} else {
125*da14cebeSEric Cheng 		freeaddrinfo(info);
126*da14cebeSEric Cheng 		return (DLADM_STATUS_INVALID_IP);
127*da14cebeSEric Cheng 	}
128*da14cebeSEric Cheng 
129*da14cebeSEric Cheng 	if (prefix_len == 0)
130*da14cebeSEric Cheng 		prefix_len = prefix_max;
131*da14cebeSEric Cheng 
132*da14cebeSEric Cheng 	status = dladm_prefixlen2mask(prefix_len, prefix_max, netmask);
133*da14cebeSEric Cheng 
134*da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK) {
135*da14cebeSEric Cheng 		freeaddrinfo(info);
136*da14cebeSEric Cheng 		return (DLADM_STATUS_INVALID_PREFIXLEN);
137*da14cebeSEric Cheng 	}
138*da14cebeSEric Cheng 
139*da14cebeSEric Cheng 	fd->fd_mask |= mask;
140*da14cebeSEric Cheng 	freeaddrinfo(info);
141*da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
142*da14cebeSEric Cheng }
143*da14cebeSEric Cheng 
144*da14cebeSEric Cheng dladm_status_t
145*da14cebeSEric Cheng do_check_protocol(char *attr_val, flow_desc_t *fdesc)
146*da14cebeSEric Cheng {
147*da14cebeSEric Cheng 	uint8_t	protocol;
148*da14cebeSEric Cheng 
149*da14cebeSEric Cheng 	protocol = dladm_str2proto(attr_val);
150*da14cebeSEric Cheng 
151*da14cebeSEric Cheng 	if (protocol != 0) {
152*da14cebeSEric Cheng 		fdesc->fd_mask |= FLOW_IP_PROTOCOL;
153*da14cebeSEric Cheng 		fdesc->fd_protocol = protocol;
154*da14cebeSEric Cheng 		return (DLADM_STATUS_OK);
155*da14cebeSEric Cheng 	} else {
156*da14cebeSEric Cheng 		return (DLADM_STATUS_INVALID_PROTOCOL);
157*da14cebeSEric Cheng 	}
158*da14cebeSEric Cheng }
159*da14cebeSEric Cheng 
160*da14cebeSEric Cheng dladm_status_t
161*da14cebeSEric Cheng do_check_local_port(char *attr_val, flow_desc_t *fdesc)
162*da14cebeSEric Cheng {
163*da14cebeSEric Cheng 	return (do_check_port(attr_val, B_TRUE, fdesc));
164*da14cebeSEric Cheng }
165*da14cebeSEric Cheng 
166*da14cebeSEric Cheng dladm_status_t
167*da14cebeSEric Cheng do_check_port(char *attr_val, boolean_t local, flow_desc_t *fdesc)
168*da14cebeSEric Cheng {
169*da14cebeSEric Cheng 	char	*endp = NULL;
170*da14cebeSEric Cheng 	long	val;
171*da14cebeSEric Cheng 
172*da14cebeSEric Cheng 	if (local) {
173*da14cebeSEric Cheng 		fdesc->fd_mask |= FLOW_ULP_PORT_LOCAL;
174*da14cebeSEric Cheng 		val = strtol(attr_val, &endp, 10);
175*da14cebeSEric Cheng 		if (val < 1 || val > MAX_PORT)
176*da14cebeSEric Cheng 			return (DLADM_STATUS_INVALID_PORT);
177*da14cebeSEric Cheng 		fdesc->fd_local_port = htons((uint16_t)val);
178*da14cebeSEric Cheng 	} else {
179*da14cebeSEric Cheng 		return (DLADM_STATUS_BADVAL);
180*da14cebeSEric Cheng 	}
181*da14cebeSEric Cheng 
182*da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
183*da14cebeSEric Cheng }
184*da14cebeSEric Cheng 
185*da14cebeSEric Cheng /*
186*da14cebeSEric Cheng  * Check for invalid and/or duplicate attribute specification
187*da14cebeSEric Cheng  */
188*da14cebeSEric Cheng static dladm_status_t
189*da14cebeSEric Cheng flow_attrlist_check(dladm_arg_list_t *attrlist)
190*da14cebeSEric Cheng {
191*da14cebeSEric Cheng 	int		i, j;
192*da14cebeSEric Cheng 	boolean_t	isset[DLADM_MAX_FLOWATTRS];
193*da14cebeSEric Cheng 	boolean_t	matched;
194*da14cebeSEric Cheng 
195*da14cebeSEric Cheng 	for (j = 0; j < DLADM_MAX_FLOWATTRS; j++)
196*da14cebeSEric Cheng 		isset[j] = B_FALSE;
197*da14cebeSEric Cheng 
198*da14cebeSEric Cheng 	for (i = 0; i < attrlist->al_count; i++) {
199*da14cebeSEric Cheng 		matched = B_FALSE;
200*da14cebeSEric Cheng 		for (j = 0; j < DLADM_MAX_FLOWATTRS; j++) {
201*da14cebeSEric Cheng 			if (strcmp(attrlist->al_info[i].ai_name,
202*da14cebeSEric Cheng 			    attr_table[j].ad_name) == 0) {
203*da14cebeSEric Cheng 				if (isset[j])
204*da14cebeSEric Cheng 					return (DLADM_STATUS_FLOW_INCOMPATIBLE);
205*da14cebeSEric Cheng 				else
206*da14cebeSEric Cheng 					isset[j] = B_TRUE;
207*da14cebeSEric Cheng 				matched = B_TRUE;
208*da14cebeSEric Cheng 			}
209*da14cebeSEric Cheng 		}
210*da14cebeSEric Cheng 		/*
211*da14cebeSEric Cheng 		 * if the attribute did not match any of the attribute in
212*da14cebeSEric Cheng 		 * attr_table, then it's an invalid attribute.
213*da14cebeSEric Cheng 		 */
214*da14cebeSEric Cheng 		if (!matched)
215*da14cebeSEric Cheng 			return (DLADM_STATUS_BADARG);
216*da14cebeSEric Cheng 	}
217*da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
218*da14cebeSEric Cheng }
219*da14cebeSEric Cheng 
220*da14cebeSEric Cheng /*
221*da14cebeSEric Cheng  * Convert an attribute list to a flow_desc_t using the attribute ad_check()
222*da14cebeSEric Cheng  * functions.
223*da14cebeSEric Cheng  */
224*da14cebeSEric Cheng dladm_status_t
225*da14cebeSEric Cheng dladm_flow_attrlist_extract(dladm_arg_list_t *attrlist, flow_desc_t *flowdesc)
226*da14cebeSEric Cheng {
227*da14cebeSEric Cheng 	dladm_status_t	status = DLADM_STATUS_BADARG;
228*da14cebeSEric Cheng 	int		i;
229*da14cebeSEric Cheng 
230*da14cebeSEric Cheng 	for (i = 0; i < attrlist->al_count; i++) {
231*da14cebeSEric Cheng 		dladm_arg_info_t	*aip = &attrlist->al_info[i];
232*da14cebeSEric Cheng 		int			j;
233*da14cebeSEric Cheng 
234*da14cebeSEric Cheng 		for (j = 0; j < DLADM_MAX_FLOWATTRS; j++) {
235*da14cebeSEric Cheng 			fattr_desc_t	*adp = &attr_table[j];
236*da14cebeSEric Cheng 
237*da14cebeSEric Cheng 			if (strcasecmp(aip->ai_name, adp->ad_name) != 0)
238*da14cebeSEric Cheng 				continue;
239*da14cebeSEric Cheng 
240*da14cebeSEric Cheng 			if ((aip->ai_val == NULL) || (*aip->ai_val == NULL))
241*da14cebeSEric Cheng 				return (DLADM_STATUS_BADARG);
242*da14cebeSEric Cheng 
243*da14cebeSEric Cheng 			if (adp->ad_check != NULL)
244*da14cebeSEric Cheng 				status = adp->ad_check(*aip->ai_val, flowdesc);
245*da14cebeSEric Cheng 			else
246*da14cebeSEric Cheng 				status = DLADM_STATUS_BADARG;
247*da14cebeSEric Cheng 
248*da14cebeSEric Cheng 			if (status != DLADM_STATUS_OK)
249*da14cebeSEric Cheng 				return (status);
250*da14cebeSEric Cheng 		}
251*da14cebeSEric Cheng 	}
252*da14cebeSEric Cheng 	return (status);
253*da14cebeSEric Cheng }
254*da14cebeSEric Cheng 
255*da14cebeSEric Cheng void
256*da14cebeSEric Cheng dladm_free_attrs(dladm_arg_list_t *list)
257*da14cebeSEric Cheng {
258*da14cebeSEric Cheng 	dladm_free_args(list);
259*da14cebeSEric Cheng }
260*da14cebeSEric Cheng 
261*da14cebeSEric Cheng dladm_status_t
262*da14cebeSEric Cheng dladm_parse_flow_attrs(char *str, dladm_arg_list_t **listp, boolean_t novalues)
263*da14cebeSEric Cheng {
264*da14cebeSEric Cheng 
265*da14cebeSEric Cheng 	if (dladm_parse_args(str, listp, novalues)
266*da14cebeSEric Cheng 	    != DLADM_STATUS_OK)
267*da14cebeSEric Cheng 		return (DLADM_STATUS_ATTR_PARSE_ERR);
268*da14cebeSEric Cheng 
269*da14cebeSEric Cheng 	if (flow_attrlist_check(*listp) != DLADM_STATUS_OK) {
270*da14cebeSEric Cheng 		dladm_free_attrs(*listp);
271*da14cebeSEric Cheng 		return (DLADM_STATUS_ATTR_PARSE_ERR);
272*da14cebeSEric Cheng 	}
273*da14cebeSEric Cheng 
274*da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
275*da14cebeSEric Cheng }
276*da14cebeSEric Cheng 
277*da14cebeSEric Cheng dladm_status_t
278*da14cebeSEric Cheng do_check_dsfield(char *str, flow_desc_t *fd)
279*da14cebeSEric Cheng {
280*da14cebeSEric Cheng 	char		*mask_str, *endp = NULL;
281*da14cebeSEric Cheng 	uint_t		mask = 0xff, value;
282*da14cebeSEric Cheng 
283*da14cebeSEric Cheng 	if ((mask_str = strchr(str, ':')) != NULL) {
284*da14cebeSEric Cheng 		*mask_str++ = '\0';
285*da14cebeSEric Cheng 		errno = 0;
286*da14cebeSEric Cheng 		mask = strtoul(mask_str, &endp, 16);
287*da14cebeSEric Cheng 		if (errno != 0 || mask == 0 || mask > 0xff ||
288*da14cebeSEric Cheng 		    *endp != '\0')
289*da14cebeSEric Cheng 			return (DLADM_STATUS_INVALID_DSFMASK);
290*da14cebeSEric Cheng 	}
291*da14cebeSEric Cheng 	errno = 0;
292*da14cebeSEric Cheng 	endp = NULL;
293*da14cebeSEric Cheng 	value = strtoul(str, &endp, 16);
294*da14cebeSEric Cheng 	if (errno != 0 || value == 0 || value > 0xff || *endp != '\0')
295*da14cebeSEric Cheng 		return (DLADM_STATUS_INVALID_DSF);
296*da14cebeSEric Cheng 
297*da14cebeSEric Cheng 	fd->fd_dsfield = (uint8_t)value;
298*da14cebeSEric Cheng 	fd->fd_dsfield_mask = (uint8_t)mask;
299*da14cebeSEric Cheng 	fd->fd_mask |= FLOW_IP_DSFIELD;
300*da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
301*da14cebeSEric Cheng }
302*da14cebeSEric Cheng 
303*da14cebeSEric Cheng char *
304*da14cebeSEric Cheng dladm_proto2str(uint8_t protocol)
305*da14cebeSEric Cheng {
306*da14cebeSEric Cheng 	if (protocol == IPPROTO_TCP)
307*da14cebeSEric Cheng 		return ("tcp");
308*da14cebeSEric Cheng 	if (protocol == IPPROTO_UDP)
309*da14cebeSEric Cheng 		return ("udp");
310*da14cebeSEric Cheng 	if (protocol == IPPROTO_SCTP)
311*da14cebeSEric Cheng 		return ("sctp");
312*da14cebeSEric Cheng 	if (protocol == IPPROTO_ICMPV6)
313*da14cebeSEric Cheng 		return ("icmpv6");
314*da14cebeSEric Cheng 	if (protocol == IPPROTO_ICMP)
315*da14cebeSEric Cheng 		return ("icmp");
316*da14cebeSEric Cheng 	else
317*da14cebeSEric Cheng 		return ("");
318*da14cebeSEric Cheng }
319*da14cebeSEric Cheng 
320*da14cebeSEric Cheng uint8_t
321*da14cebeSEric Cheng dladm_str2proto(const char *protostr)
322*da14cebeSEric Cheng {
323*da14cebeSEric Cheng 	if (strncasecmp(protostr, "tcp", 3) == 0)
324*da14cebeSEric Cheng 		return (IPPROTO_TCP);
325*da14cebeSEric Cheng 	else if (strncasecmp(protostr, "udp", 3) == 0)
326*da14cebeSEric Cheng 		return (IPPROTO_UDP);
327*da14cebeSEric Cheng 	else if (strncasecmp(protostr, "sctp", 4) == 0)
328*da14cebeSEric Cheng 		return (IPPROTO_SCTP);
329*da14cebeSEric Cheng 	else if (strncasecmp(protostr, "icmpv6", 6) == 0)
330*da14cebeSEric Cheng 		return (IPPROTO_ICMPV6);
331*da14cebeSEric Cheng 	else if (strncasecmp(protostr, "icmp", 4) == 0)
332*da14cebeSEric Cheng 		return (IPPROTO_ICMP);
333*da14cebeSEric Cheng 
334*da14cebeSEric Cheng 	return (0);
335*da14cebeSEric Cheng }
336*da14cebeSEric Cheng 
337*da14cebeSEric Cheng void
338*da14cebeSEric Cheng dladm_flow_attr_ip2str(dladm_flow_attr_t *attrp, char *buf, size_t buf_len)
339*da14cebeSEric Cheng {
340*da14cebeSEric Cheng 	flow_desc_t	fdesc = attrp->fa_flow_desc;
341*da14cebeSEric Cheng 	struct in_addr	ipaddr;
342*da14cebeSEric Cheng 	int		prefix_len, prefix_max;
343*da14cebeSEric Cheng 	char		*cp, abuf[INET6_ADDRSTRLEN];
344*da14cebeSEric Cheng 
345*da14cebeSEric Cheng 	if (fdesc.fd_mask & FLOW_IP_LOCAL) {
346*da14cebeSEric Cheng 		if (fdesc.fd_ipversion == IPV6_VERSION) {
347*da14cebeSEric Cheng 			(void) inet_ntop(AF_INET6, &fdesc.fd_local_addr, abuf,
348*da14cebeSEric Cheng 			    INET6_ADDRSTRLEN);
349*da14cebeSEric Cheng 			cp = abuf;
350*da14cebeSEric Cheng 			prefix_max = IPV6_ABITS;
351*da14cebeSEric Cheng 		} else {
352*da14cebeSEric Cheng 			ipaddr.s_addr = fdesc.fd_local_addr._S6_un._S6_u32[3];
353*da14cebeSEric Cheng 			cp = inet_ntoa(ipaddr);
354*da14cebeSEric Cheng 			prefix_max = IP_ABITS;
355*da14cebeSEric Cheng 		}
356*da14cebeSEric Cheng 		(void) dladm_mask2prefixlen(&fdesc.fd_local_netmask,
357*da14cebeSEric Cheng 		    prefix_max, &prefix_len);
358*da14cebeSEric Cheng 		(void) snprintf(buf, buf_len, "LCL:%s/%d  ", cp, prefix_len);
359*da14cebeSEric Cheng 	} else if (fdesc.fd_mask & FLOW_IP_REMOTE) {
360*da14cebeSEric Cheng 		if (fdesc.fd_ipversion == IPV6_VERSION) {
361*da14cebeSEric Cheng 			(void) inet_ntop(AF_INET6, &fdesc.fd_remote_addr, abuf,
362*da14cebeSEric Cheng 			    INET6_ADDRSTRLEN);
363*da14cebeSEric Cheng 			cp = abuf;
364*da14cebeSEric Cheng 			prefix_max = IPV6_ABITS;
365*da14cebeSEric Cheng 		} else {
366*da14cebeSEric Cheng 			ipaddr.s_addr = fdesc.fd_remote_addr._S6_un._S6_u32[3];
367*da14cebeSEric Cheng 			cp = inet_ntoa(ipaddr);
368*da14cebeSEric Cheng 			prefix_max = IP_ABITS;
369*da14cebeSEric Cheng 		}
370*da14cebeSEric Cheng 		(void) dladm_mask2prefixlen(&fdesc.fd_remote_netmask,
371*da14cebeSEric Cheng 		    prefix_max, &prefix_len);
372*da14cebeSEric Cheng 		(void) snprintf(buf, buf_len, "RMT:%s/%d  ", cp, prefix_len);
373*da14cebeSEric Cheng 	} else {
374*da14cebeSEric Cheng 		buf[0] = '\0';
375*da14cebeSEric Cheng 	}
376*da14cebeSEric Cheng }
377*da14cebeSEric Cheng 
378*da14cebeSEric Cheng void
379*da14cebeSEric Cheng dladm_flow_attr_proto2str(dladm_flow_attr_t *attrp, char *buf, size_t buf_len)
380*da14cebeSEric Cheng {
381*da14cebeSEric Cheng 	flow_desc_t	fdesc = attrp->fa_flow_desc;
382*da14cebeSEric Cheng 
383*da14cebeSEric Cheng 	(void) snprintf(buf, buf_len, "%s",
384*da14cebeSEric Cheng 	    dladm_proto2str(fdesc.fd_protocol));
385*da14cebeSEric Cheng }
386*da14cebeSEric Cheng 
387*da14cebeSEric Cheng void
388*da14cebeSEric Cheng dladm_flow_attr_port2str(dladm_flow_attr_t *attrp, char *buf, size_t buf_len)
389*da14cebeSEric Cheng {
390*da14cebeSEric Cheng 	flow_desc_t	fdesc = attrp->fa_flow_desc;
391*da14cebeSEric Cheng 
392*da14cebeSEric Cheng 	if (fdesc.fd_mask & FLOW_ULP_PORT_LOCAL) {
393*da14cebeSEric Cheng 		(void) snprintf(buf, buf_len, "%d",
394*da14cebeSEric Cheng 		    ntohs(fdesc.fd_local_port));
395*da14cebeSEric Cheng 	} else {
396*da14cebeSEric Cheng 		buf[0] = '\0';
397*da14cebeSEric Cheng 	}
398*da14cebeSEric Cheng }
399*da14cebeSEric Cheng 
400*da14cebeSEric Cheng void
401*da14cebeSEric Cheng dladm_flow_attr_dsfield2str(dladm_flow_attr_t *attrp, char *buf, size_t buf_len)
402*da14cebeSEric Cheng {
403*da14cebeSEric Cheng 	flow_desc_t	fdesc = attrp->fa_flow_desc;
404*da14cebeSEric Cheng 
405*da14cebeSEric Cheng 	if (fdesc.fd_mask & FLOW_IP_DSFIELD) {
406*da14cebeSEric Cheng 		(void) snprintf(buf, buf_len, "0x%x:0x%x",
407*da14cebeSEric Cheng 		    fdesc.fd_dsfield, fdesc.fd_dsfield_mask);
408*da14cebeSEric Cheng 	} else {
409*da14cebeSEric Cheng 		buf[0] = '\0';
410*da14cebeSEric Cheng 	}
411*da14cebeSEric Cheng }
412