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