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