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