1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 2311 seb * Common Development and Distribution License (the "License"). 6 2311 seb * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 0 stevel /* 22 9055 Michael * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 0 stevel * Use is subject to license terms. 24 0 stevel */ 25 0 stevel 26 0 stevel #include <unistd.h> 27 0 stevel #include <errno.h> 28 5895 yz147064 #include <ctype.h> 29 3147 xc151355 #include <fcntl.h> 30 3147 xc151355 #include <strings.h> 31 3147 xc151355 #include <dirent.h> 32 8275 Eric #include <stdlib.h> 33 10734 Eric #include <netinet/in.h> 34 10734 Eric #include <arpa/inet.h> 35 6173 yz147064 #include <sys/param.h> 36 3147 xc151355 #include <sys/stat.h> 37 8453 Anurag #include <sys/dld.h> 38 9107 james #include <sys/dld_ioc.h> 39 3147 xc151355 #include <libdladm_impl.h> 40 3184 meem #include <libintl.h> 41 5895 yz147064 #include <libdlpi.h> 42 0 stevel 43 8453 Anurag static char dladm_rootdir[MAXPATHLEN] = "/"; 44 9815 Rishi 45 9815 Rishi typedef struct media_type_desc { 46 9815 Rishi uint32_t media_type; 47 9815 Rishi #define MAX_MEDIA_TYPE_STRING 32 48 9815 Rishi const char media_type_str[MAX_MEDIA_TYPE_STRING]; 49 9815 Rishi } media_type_t; 50 9815 Rishi 51 9815 Rishi static media_type_t media_type_table[] = { 52 9815 Rishi { DL_ETHER, "Ethernet" }, 53 9815 Rishi { DL_WIFI, "WiFi" }, 54 9815 Rishi { DL_IB, "Infiniband" }, 55 9815 Rishi { DL_IPV4, "IPv4Tunnel" }, 56 9815 Rishi { DL_IPV6, "IPv6Tunnel" }, 57 10616 Sebastien { DL_6TO4, "6to4Tunnel" }, 58 9815 Rishi { DL_CSMACD, "CSMA/CD" }, 59 9815 Rishi { DL_TPB, "TokenBus" }, 60 9815 Rishi { DL_TPR, "TokenRing" }, 61 9815 Rishi { DL_METRO, "MetroNet" }, 62 9815 Rishi { DL_HDLC, "HDLC" }, 63 9815 Rishi { DL_CHAR, "SyncCharacter" }, 64 9815 Rishi { DL_CTCA, "CTCA" }, 65 9815 Rishi { DL_FDDI, "FDDI" }, 66 9815 Rishi { DL_FC, "FiberChannel" }, 67 9815 Rishi { DL_ATM, "ATM" }, 68 9815 Rishi { DL_IPATM, "ATM(ClassicIP)" }, 69 9815 Rishi { DL_X25, "X.25" }, 70 9815 Rishi { DL_IPX25, "X.25(ClassicIP)" }, 71 9815 Rishi { DL_ISDN, "ISDN" }, 72 9815 Rishi { DL_HIPPI, "HIPPI" }, 73 9815 Rishi { DL_100VG, "100BaseVGEthernet" }, 74 9815 Rishi { DL_100VGTPR, "100BaseVGTokenRing" }, 75 9815 Rishi { DL_ETH_CSMA, "IEEE802.3" }, 76 9815 Rishi { DL_100BT, "100BaseT" }, 77 9815 Rishi { DL_FRAME, "FrameRelay" }, 78 9815 Rishi { DL_MPFRAME, "MPFrameRelay" }, 79 9815 Rishi { DL_ASYNC, "AsyncCharacter" }, 80 9815 Rishi { DL_IPNET, "IPNET" }, 81 9815 Rishi { DL_OTHER, "Other" } 82 9815 Rishi }; 83 9815 Rishi #define MEDIATYPECOUNT (sizeof (media_type_table) / sizeof (media_type_t)) 84 10734 Eric 85 10734 Eric typedef struct { 86 10734 Eric uint32_t lp_type; 87 10734 Eric char *lp_name; 88 10734 Eric } link_protect_t; 89 10734 Eric 90 10734 Eric static link_protect_t link_protect_types[] = { 91 10734 Eric { MPT_MACNOSPOOF, "mac-nospoof" }, 92 10734 Eric { MPT_IPNOSPOOF, "ip-nospoof" }, 93 10734 Eric { MPT_RESTRICTED, "restricted" } 94 10734 Eric }; 95 10734 Eric #define LPTYPES (sizeof (link_protect_types) / sizeof (link_protect_t)) 96 8453 Anurag 97 8453 Anurag dladm_status_t 98 8453 Anurag dladm_open(dladm_handle_t *handle) 99 8453 Anurag { 100 8453 Anurag int dld_fd; 101 8453 Anurag 102 8453 Anurag if (handle == NULL) 103 8453 Anurag return (DLADM_STATUS_BADARG); 104 8453 Anurag 105 8453 Anurag if ((dld_fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 106 8453 Anurag return (dladm_errno2status(errno)); 107 8453 Anurag 108 8453 Anurag /* 109 8453 Anurag * Don't open DLMGMT_DOOR now. dlmgmtd(1M) is not able to 110 8453 Anurag * open the door when the dladm handle is opened because the 111 8453 Anurag * door hasn't been created yet at that time. Thus, we must 112 8453 Anurag * open it on-demand in dladm_door_fd(). Move the open() 113 8453 Anurag * to dladm_door_fd() for all cases. 114 8453 Anurag */ 115 8453 Anurag 116 8453 Anurag if ((*handle = malloc(sizeof (struct dladm_handle))) == NULL) { 117 8453 Anurag (void) close(dld_fd); 118 8453 Anurag return (DLADM_STATUS_NOMEM); 119 8453 Anurag } 120 8453 Anurag 121 8453 Anurag (*handle)->dld_fd = dld_fd; 122 8453 Anurag (*handle)->door_fd = -1; 123 8453 Anurag 124 8453 Anurag return (DLADM_STATUS_OK); 125 8453 Anurag } 126 8453 Anurag 127 8453 Anurag void 128 8453 Anurag dladm_close(dladm_handle_t handle) 129 8453 Anurag { 130 8453 Anurag if (handle != NULL) { 131 8453 Anurag (void) close(handle->dld_fd); 132 8453 Anurag if (handle->door_fd != -1) 133 8453 Anurag (void) close(handle->door_fd); 134 8453 Anurag free(handle); 135 8453 Anurag } 136 8453 Anurag } 137 8453 Anurag 138 8453 Anurag int 139 8453 Anurag dladm_dld_fd(dladm_handle_t handle) 140 8453 Anurag { 141 8453 Anurag return (handle->dld_fd); 142 8453 Anurag } 143 8453 Anurag 144 8453 Anurag /* 145 8453 Anurag * If DLMGMT_DOOR hasn't been opened in the handle yet, open it. 146 8453 Anurag */ 147 8453 Anurag dladm_status_t 148 8453 Anurag dladm_door_fd(dladm_handle_t handle, int *door_fd) 149 8453 Anurag { 150 8453 Anurag int fd; 151 8453 Anurag 152 8453 Anurag if (handle->door_fd == -1) { 153 8453 Anurag if ((fd = open(DLMGMT_DOOR, O_RDONLY)) < 0) 154 8453 Anurag return (dladm_errno2status(errno)); 155 8453 Anurag handle->door_fd = fd; 156 8453 Anurag } 157 8453 Anurag *door_fd = handle->door_fd; 158 8453 Anurag 159 8453 Anurag return (DLADM_STATUS_OK); 160 8453 Anurag } 161 3147 xc151355 162 3147 xc151355 const char * 163 3147 xc151355 dladm_status2str(dladm_status_t status, char *buf) 164 3147 xc151355 { 165 3147 xc151355 const char *s; 166 3147 xc151355 167 3147 xc151355 switch (status) { 168 3147 xc151355 case DLADM_STATUS_OK: 169 3147 xc151355 s = "ok"; 170 3147 xc151355 break; 171 3147 xc151355 case DLADM_STATUS_BADARG: 172 3147 xc151355 s = "invalid argument"; 173 3147 xc151355 break; 174 3147 xc151355 case DLADM_STATUS_FAILED: 175 3147 xc151355 s = "operation failed"; 176 3147 xc151355 break; 177 3147 xc151355 case DLADM_STATUS_TOOSMALL: 178 3147 xc151355 s = "buffer size too small"; 179 3147 xc151355 break; 180 3147 xc151355 case DLADM_STATUS_NOTSUP: 181 3147 xc151355 s = "operation not supported"; 182 3147 xc151355 break; 183 3147 xc151355 case DLADM_STATUS_NOTFOUND: 184 3147 xc151355 s = "object not found"; 185 3147 xc151355 break; 186 3147 xc151355 case DLADM_STATUS_BADVAL: 187 3147 xc151355 s = "invalid value"; 188 3147 xc151355 break; 189 3147 xc151355 case DLADM_STATUS_NOMEM: 190 3147 xc151355 s = "insufficient memory"; 191 3147 xc151355 break; 192 3147 xc151355 case DLADM_STATUS_EXIST: 193 3147 xc151355 s = "object already exists"; 194 3147 xc151355 break; 195 3147 xc151355 case DLADM_STATUS_LINKINVAL: 196 3147 xc151355 s = "invalid link"; 197 3147 xc151355 break; 198 3147 xc151355 case DLADM_STATUS_PROPRDONLY: 199 3147 xc151355 s = "read-only property"; 200 3147 xc151355 break; 201 3147 xc151355 case DLADM_STATUS_BADVALCNT: 202 3147 xc151355 s = "invalid number of values"; 203 3147 xc151355 break; 204 3147 xc151355 case DLADM_STATUS_DBNOTFOUND: 205 3147 xc151355 s = "database not found"; 206 3147 xc151355 break; 207 3147 xc151355 case DLADM_STATUS_DENIED: 208 3147 xc151355 s = "permission denied"; 209 3147 xc151355 break; 210 3147 xc151355 case DLADM_STATUS_IOERR: 211 3147 xc151355 s = "I/O error"; 212 3448 dh155122 break; 213 3448 dh155122 case DLADM_STATUS_TEMPONLY: 214 8275 Eric s = "change cannot be persistent"; 215 3871 yz147064 break; 216 3871 yz147064 case DLADM_STATUS_TIMEDOUT: 217 3871 yz147064 s = "operation timed out"; 218 3871 yz147064 break; 219 3871 yz147064 case DLADM_STATUS_ISCONN: 220 3871 yz147064 s = "already connected"; 221 3871 yz147064 break; 222 3871 yz147064 case DLADM_STATUS_NOTCONN: 223 3871 yz147064 s = "not connected"; 224 3871 yz147064 break; 225 3871 yz147064 case DLADM_STATUS_REPOSITORYINVAL: 226 3871 yz147064 s = "invalid configuration repository"; 227 3871 yz147064 break; 228 3871 yz147064 case DLADM_STATUS_MACADDRINVAL: 229 3871 yz147064 s = "invalid MAC address"; 230 3871 yz147064 break; 231 3871 yz147064 case DLADM_STATUS_KEYINVAL: 232 3871 yz147064 s = "invalid key"; 233 3147 xc151355 break; 234 5084 johnlev case DLADM_STATUS_INVALIDMACADDRLEN: 235 5084 johnlev s = "invalid MAC address length"; 236 5084 johnlev break; 237 5084 johnlev case DLADM_STATUS_INVALIDMACADDRTYPE: 238 5084 johnlev s = "invalid MAC address type"; 239 5084 johnlev break; 240 5895 yz147064 case DLADM_STATUS_LINKBUSY: 241 5895 yz147064 s = "link busy"; 242 5084 johnlev break; 243 5895 yz147064 case DLADM_STATUS_VIDINVAL: 244 5895 yz147064 s = "invalid VLAN identifier"; 245 5084 johnlev break; 246 5895 yz147064 case DLADM_STATUS_TRYAGAIN: 247 5895 yz147064 s = "try again later"; 248 5895 yz147064 break; 249 5895 yz147064 case DLADM_STATUS_NONOTIF: 250 5895 yz147064 s = "link notification is not supported"; 251 8275 Eric break; 252 8275 Eric case DLADM_STATUS_BADTIMEVAL: 253 8275 Eric s = "invalid time range"; 254 8275 Eric break; 255 8275 Eric case DLADM_STATUS_INVALIDMACADDR: 256 8275 Eric s = "invalid MAC address value"; 257 8275 Eric break; 258 8275 Eric case DLADM_STATUS_INVALIDMACADDRNIC: 259 8275 Eric s = "MAC address reserved for use by underlying data-link"; 260 8275 Eric break; 261 8275 Eric case DLADM_STATUS_INVALIDMACADDRINUSE: 262 8275 Eric s = "MAC address is already in use"; 263 8275 Eric break; 264 8275 Eric case DLADM_STATUS_MACFACTORYSLOTINVALID: 265 8275 Eric s = "invalid factory MAC address slot"; 266 8275 Eric break; 267 8275 Eric case DLADM_STATUS_MACFACTORYSLOTUSED: 268 8275 Eric s = "factory MAC address slot already used"; 269 8275 Eric break; 270 8275 Eric case DLADM_STATUS_MACFACTORYSLOTALLUSED: 271 8275 Eric s = "all factory MAC address slots are in use"; 272 8275 Eric break; 273 8275 Eric case DLADM_STATUS_MACFACTORYNOTSUP: 274 8275 Eric s = "factory MAC address slots not supported"; 275 8275 Eric break; 276 8275 Eric case DLADM_STATUS_INVALIDMACPREFIX: 277 8275 Eric s = "Invalid MAC address prefix value"; 278 8275 Eric break; 279 8275 Eric case DLADM_STATUS_INVALIDMACPREFIXLEN: 280 8275 Eric s = "Invalid MAC address prefix length"; 281 8275 Eric break; 282 8275 Eric case DLADM_STATUS_CPUMAX: 283 8275 Eric s = "non-existent processor ID"; 284 8275 Eric break; 285 8275 Eric case DLADM_STATUS_CPUERR: 286 8275 Eric s = "could not determine processor status"; 287 8275 Eric break; 288 8275 Eric case DLADM_STATUS_CPUNOTONLINE: 289 8275 Eric s = "processor not online"; 290 8275 Eric break; 291 8275 Eric case DLADM_STATUS_DB_NOTFOUND: 292 8275 Eric s = "database not found"; 293 8275 Eric break; 294 8275 Eric case DLADM_STATUS_DB_PARSE_ERR: 295 8275 Eric s = "database parse error"; 296 8275 Eric break; 297 8275 Eric case DLADM_STATUS_PROP_PARSE_ERR: 298 8275 Eric s = "property parse error"; 299 8275 Eric break; 300 8275 Eric case DLADM_STATUS_ATTR_PARSE_ERR: 301 8275 Eric s = "attribute parse error"; 302 8275 Eric break; 303 8275 Eric case DLADM_STATUS_FLOW_DB_ERR: 304 8275 Eric s = "flow database error"; 305 8275 Eric break; 306 8275 Eric case DLADM_STATUS_FLOW_DB_OPEN_ERR: 307 8275 Eric s = "flow database open error"; 308 8275 Eric break; 309 8275 Eric case DLADM_STATUS_FLOW_DB_PARSE_ERR: 310 8275 Eric s = "flow database parse error"; 311 8275 Eric break; 312 8275 Eric case DLADM_STATUS_FLOWPROP_DB_PARSE_ERR: 313 8275 Eric s = "flow property database parse error"; 314 8275 Eric break; 315 8275 Eric case DLADM_STATUS_FLOW_ADD_ERR: 316 8275 Eric s = "flow add error"; 317 8275 Eric break; 318 8275 Eric case DLADM_STATUS_FLOW_WALK_ERR: 319 8275 Eric s = "flow walk error"; 320 8275 Eric break; 321 8275 Eric case DLADM_STATUS_FLOW_IDENTICAL: 322 8275 Eric s = "a flow with identical attributes exists"; 323 8275 Eric break; 324 8275 Eric case DLADM_STATUS_FLOW_INCOMPATIBLE: 325 8275 Eric s = "flow(s) with incompatible attributes exists"; 326 8275 Eric break; 327 8275 Eric case DLADM_STATUS_FLOW_EXISTS: 328 8275 Eric s = "link still has flows"; 329 8275 Eric break; 330 8275 Eric case DLADM_STATUS_PERSIST_FLOW_EXISTS: 331 8275 Eric s = "persistent flow with the same name exists"; 332 8275 Eric break; 333 8275 Eric case DLADM_STATUS_INVALID_IP: 334 8275 Eric s = "invalid IP address"; 335 8275 Eric break; 336 8275 Eric case DLADM_STATUS_INVALID_PREFIXLEN: 337 8275 Eric s = "invalid IP prefix length"; 338 8275 Eric break; 339 8275 Eric case DLADM_STATUS_INVALID_PROTOCOL: 340 8275 Eric s = "invalid IP protocol"; 341 8275 Eric break; 342 8275 Eric case DLADM_STATUS_INVALID_PORT: 343 8275 Eric s = "invalid port number"; 344 8275 Eric break; 345 8275 Eric case DLADM_STATUS_INVALID_DSF: 346 8275 Eric s = "invalid dsfield"; 347 8275 Eric break; 348 8275 Eric case DLADM_STATUS_INVALID_DSFMASK: 349 8275 Eric s = "invalid dsfield mask"; 350 8275 Eric break; 351 8275 Eric case DLADM_STATUS_INVALID_MACMARGIN: 352 8275 Eric s = "MTU check failed, use lower MTU or -f option"; 353 8275 Eric break; 354 8275 Eric case DLADM_STATUS_BADPROP: 355 8275 Eric s = "invalid property"; 356 8275 Eric break; 357 8275 Eric case DLADM_STATUS_MINMAXBW: 358 8275 Eric s = "minimum value for maxbw is 1.2M"; 359 8275 Eric break; 360 8275 Eric case DLADM_STATUS_NO_HWRINGS: 361 8275 Eric s = "request hw rings failed"; 362 5084 johnlev break; 363 10491 Rishi case DLADM_STATUS_PERMONLY: 364 10491 Rishi s = "change must be persistent"; 365 10491 Rishi break; 366 10491 Rishi case DLADM_STATUS_OPTMISSING: 367 10491 Rishi s = "optional software not installed"; 368 10491 Rishi break; 369 10616 Sebastien case DLADM_STATUS_IPTUNTYPE: 370 10616 Sebastien s = "invalid IP tunnel type"; 371 10616 Sebastien break; 372 10616 Sebastien case DLADM_STATUS_IPTUNTYPEREQD: 373 10616 Sebastien s = "IP tunnel type required"; 374 10616 Sebastien break; 375 10616 Sebastien case DLADM_STATUS_BADIPTUNLADDR: 376 10616 Sebastien s = "invalid local IP tunnel address"; 377 10616 Sebastien break; 378 10616 Sebastien case DLADM_STATUS_BADIPTUNRADDR: 379 10616 Sebastien s = "invalid remote IP tunnel address"; 380 10616 Sebastien break; 381 10616 Sebastien case DLADM_STATUS_ADDRINUSE: 382 10616 Sebastien s = "address already in use"; 383 10616 Sebastien break; 384 3147 xc151355 default: 385 3184 meem s = "<unknown error>"; 386 3184 meem break; 387 3147 xc151355 } 388 3184 meem (void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s)); 389 3147 xc151355 return (buf); 390 3147 xc151355 } 391 3147 xc151355 392 3147 xc151355 /* 393 3147 xc151355 * Convert a unix errno to a dladm_status_t. 394 3147 xc151355 * We only convert errnos that are likely to be encountered. All others 395 3147 xc151355 * are mapped to DLADM_STATUS_FAILED. 396 3147 xc151355 */ 397 3147 xc151355 dladm_status_t 398 3147 xc151355 dladm_errno2status(int err) 399 3147 xc151355 { 400 3147 xc151355 switch (err) { 401 5903 sowmini case 0: 402 5903 sowmini return (DLADM_STATUS_OK); 403 3147 xc151355 case EINVAL: 404 3147 xc151355 return (DLADM_STATUS_BADARG); 405 3147 xc151355 case EEXIST: 406 3147 xc151355 return (DLADM_STATUS_EXIST); 407 3147 xc151355 case ENOENT: 408 3147 xc151355 return (DLADM_STATUS_NOTFOUND); 409 3147 xc151355 case ENOSPC: 410 3147 xc151355 return (DLADM_STATUS_TOOSMALL); 411 3147 xc151355 case ENOMEM: 412 3147 xc151355 return (DLADM_STATUS_NOMEM); 413 3147 xc151355 case ENOTSUP: 414 3147 xc151355 return (DLADM_STATUS_NOTSUP); 415 5895 yz147064 case ENETDOWN: 416 5895 yz147064 return (DLADM_STATUS_NONOTIF); 417 3147 xc151355 case EACCES: 418 7408 Sebastien case EPERM: 419 3147 xc151355 return (DLADM_STATUS_DENIED); 420 3147 xc151355 case EIO: 421 3147 xc151355 return (DLADM_STATUS_IOERR); 422 5084 johnlev case EBUSY: 423 5895 yz147064 return (DLADM_STATUS_LINKBUSY); 424 5895 yz147064 case EAGAIN: 425 5895 yz147064 return (DLADM_STATUS_TRYAGAIN); 426 8275 Eric case ENOTEMPTY: 427 8275 Eric return (DLADM_STATUS_FLOW_EXISTS); 428 8275 Eric case EOPNOTSUPP: 429 8275 Eric return (DLADM_STATUS_FLOW_INCOMPATIBLE); 430 8275 Eric case EALREADY: 431 8275 Eric return (DLADM_STATUS_FLOW_IDENTICAL); 432 10616 Sebastien case EADDRINUSE: 433 10616 Sebastien return (DLADM_STATUS_ADDRINUSE); 434 3147 xc151355 default: 435 3147 xc151355 return (DLADM_STATUS_FAILED); 436 3147 xc151355 } 437 9055 Michael } 438 9055 Michael 439 9055 Michael boolean_t 440 9055 Michael dladm_str2interval(char *oarg, uint32_t *interval) 441 9055 Michael { 442 9055 Michael int val; 443 9055 Michael char *endp = NULL; 444 9055 Michael 445 9055 Michael errno = 0; 446 9055 Michael val = strtol(oarg, &endp, 10); 447 9055 Michael if (errno != 0 || val <= 0 || *endp != '\0') 448 9055 Michael return (B_FALSE); 449 9055 Michael 450 9055 Michael *interval = val; 451 9055 Michael 452 9055 Michael return (B_TRUE); 453 8275 Eric } 454 8275 Eric 455 8275 Eric dladm_status_t 456 8275 Eric dladm_str2bw(char *oarg, uint64_t *bw) 457 8275 Eric { 458 8275 Eric char *endp = NULL; 459 8275 Eric int64_t n; 460 8275 Eric int mult = 1; 461 8275 Eric 462 8275 Eric n = strtoull(oarg, &endp, 10); 463 8275 Eric 464 8275 Eric if ((errno != 0) || (strlen(endp) > 1)) 465 8275 Eric return (DLADM_STATUS_BADARG); 466 8275 Eric 467 8275 Eric if (n < 0) 468 8275 Eric return (DLADM_STATUS_BADVAL); 469 8275 Eric 470 8275 Eric switch (*endp) { 471 8275 Eric case 'k': 472 8275 Eric case 'K': 473 8275 Eric mult = 1000; 474 8275 Eric break; 475 8275 Eric case 'm': 476 8275 Eric case 'M': 477 8275 Eric case '\0': 478 8275 Eric mult = 1000000; 479 8275 Eric break; 480 8275 Eric case 'g': 481 8275 Eric case 'G': 482 8275 Eric mult = 1000000000; 483 8275 Eric break; 484 8275 Eric case '%': 485 8275 Eric /* 486 8275 Eric * percentages not supported for now, 487 8275 Eric * see RFE 6540675 488 8275 Eric */ 489 8275 Eric return (DLADM_STATUS_NOTSUP); 490 8275 Eric default: 491 8275 Eric return (DLADM_STATUS_BADVAL); 492 8275 Eric } 493 8275 Eric 494 8275 Eric *bw = n * mult; 495 8275 Eric 496 8275 Eric /* check for overflow */ 497 8275 Eric if (*bw / mult != n) 498 8275 Eric return (DLADM_STATUS_BADARG); 499 8275 Eric 500 8275 Eric return (DLADM_STATUS_OK); 501 8275 Eric } 502 8275 Eric 503 8275 Eric /* 504 8275 Eric * Convert bandwidth in bps to a string in mpbs. For values greater 505 8275 Eric * than 1mbps or 1000000, print a whole mbps value. For values that 506 8275 Eric * have fractional Mbps in whole Kbps , print the bandwidth in a manner 507 8275 Eric * simlilar to a floating point format. 508 8275 Eric * 509 8275 Eric * bps string 510 8275 Eric * 0 0 511 8275 Eric * 100 0 512 8275 Eric * 2000 0.002 513 8275 Eric * 431000 0.431 514 8275 Eric * 1000000 1 515 8275 Eric * 1030000 1.030 516 8275 Eric * 100000000 100 517 8275 Eric */ 518 8275 Eric const char * 519 8275 Eric dladm_bw2str(int64_t bw, char *buf) 520 8275 Eric { 521 8275 Eric int kbps, mbps; 522 8275 Eric 523 8275 Eric kbps = (bw%1000000)/1000; 524 8275 Eric mbps = bw/1000000; 525 8275 Eric if (kbps != 0) { 526 8275 Eric if (mbps == 0) 527 8275 Eric (void) snprintf(buf, DLADM_STRSIZE, "0.%03u", kbps); 528 8275 Eric else 529 8275 Eric (void) snprintf(buf, DLADM_STRSIZE, "%5u.%03u", mbps, 530 8275 Eric kbps); 531 8275 Eric } else { 532 8275 Eric (void) snprintf(buf, DLADM_STRSIZE, "%5u", mbps); 533 8275 Eric } 534 8275 Eric 535 8275 Eric return (buf); 536 3147 xc151355 } 537 3147 xc151355 538 5895 yz147064 #define LOCK_DB_PERMS S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH 539 3147 xc151355 540 3147 xc151355 static int 541 3147 xc151355 i_dladm_lock_db(const char *lock_file, short type) 542 3147 xc151355 { 543 3147 xc151355 int lock_fd; 544 5895 yz147064 struct flock lock; 545 3147 xc151355 546 3147 xc151355 if ((lock_fd = open(lock_file, O_RDWR | O_CREAT | O_TRUNC, 547 3147 xc151355 LOCK_DB_PERMS)) < 0) 548 3147 xc151355 return (-1); 549 3147 xc151355 550 3147 xc151355 lock.l_type = type; 551 3147 xc151355 lock.l_whence = SEEK_SET; 552 3147 xc151355 lock.l_start = 0; 553 3147 xc151355 lock.l_len = 0; 554 3147 xc151355 555 3147 xc151355 if (fcntl(lock_fd, F_SETLKW, &lock) < 0) { 556 3147 xc151355 int err = errno; 557 3147 xc151355 558 3147 xc151355 (void) close(lock_fd); 559 3147 xc151355 (void) unlink(lock_file); 560 3147 xc151355 errno = err; 561 3147 xc151355 return (-1); 562 3147 xc151355 } 563 3147 xc151355 return (lock_fd); 564 3147 xc151355 } 565 3147 xc151355 566 3147 xc151355 static void 567 3147 xc151355 i_dladm_unlock_db(const char *lock_file, int fd) 568 3147 xc151355 { 569 3147 xc151355 struct flock lock; 570 3147 xc151355 571 3147 xc151355 if (fd < 0) 572 3147 xc151355 return; 573 3147 xc151355 574 3147 xc151355 lock.l_type = F_UNLCK; 575 3147 xc151355 lock.l_whence = SEEK_SET; 576 3147 xc151355 lock.l_start = 0; 577 3147 xc151355 lock.l_len = 0; 578 3147 xc151355 579 3147 xc151355 (void) fcntl(fd, F_SETLKW, &lock); 580 3147 xc151355 (void) close(fd); 581 3147 xc151355 (void) unlink(lock_file); 582 5895 yz147064 } 583 5895 yz147064 584 5895 yz147064 /* 585 5895 yz147064 * Given a link class, returns its class string. 586 5895 yz147064 */ 587 5895 yz147064 const char * 588 5895 yz147064 dladm_class2str(datalink_class_t class, char *buf) 589 5895 yz147064 { 590 5895 yz147064 const char *s; 591 5895 yz147064 592 5895 yz147064 switch (class) { 593 5895 yz147064 case DATALINK_CLASS_PHYS: 594 5895 yz147064 s = "phys"; 595 5895 yz147064 break; 596 5895 yz147064 case DATALINK_CLASS_VLAN: 597 5895 yz147064 s = "vlan"; 598 5895 yz147064 break; 599 5895 yz147064 case DATALINK_CLASS_AGGR: 600 5895 yz147064 s = "aggr"; 601 5895 yz147064 break; 602 5895 yz147064 case DATALINK_CLASS_VNIC: 603 5895 yz147064 s = "vnic"; 604 8275 Eric break; 605 8275 Eric case DATALINK_CLASS_ETHERSTUB: 606 8275 Eric s = "etherstub"; 607 10616 Sebastien break; 608 10616 Sebastien case DATALINK_CLASS_IPTUN: 609 10616 Sebastien s = "iptun"; 610 5895 yz147064 break; 611 9815 Rishi case DATALINK_CLASS_SIMNET: 612 9815 Rishi s = "simnet"; 613 10491 Rishi break; 614 10491 Rishi case DATALINK_CLASS_BRIDGE: 615 10491 Rishi s = "bridge"; 616 9815 Rishi break; 617 5895 yz147064 default: 618 5895 yz147064 s = "unknown"; 619 5895 yz147064 break; 620 5895 yz147064 } 621 5895 yz147064 622 5895 yz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 623 5895 yz147064 return (buf); 624 5895 yz147064 } 625 5895 yz147064 626 5895 yz147064 /* 627 5895 yz147064 * Given a physical link media type, returns its media type string. 628 5895 yz147064 */ 629 5895 yz147064 const char * 630 5895 yz147064 dladm_media2str(uint32_t media, char *buf) 631 5895 yz147064 { 632 9815 Rishi const char *s = "--"; 633 9815 Rishi media_type_t *mt; 634 9815 Rishi int idx; 635 5895 yz147064 636 9815 Rishi for (idx = 0; idx < MEDIATYPECOUNT; idx++) { 637 9815 Rishi mt = media_type_table + idx; 638 9815 Rishi if (mt->media_type == media) { 639 9815 Rishi s = mt->media_type_str; 640 9815 Rishi break; 641 9815 Rishi } 642 5895 yz147064 } 643 5895 yz147064 644 5895 yz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 645 5895 yz147064 return (buf); 646 9815 Rishi } 647 9815 Rishi 648 9815 Rishi /* 649 9815 Rishi * Given a physical link media type string, returns its media type constant. 650 9815 Rishi */ 651 9815 Rishi uint32_t 652 9815 Rishi dladm_str2media(const char *buf) 653 9815 Rishi { 654 9815 Rishi media_type_t *mt; 655 9815 Rishi int idx; 656 9815 Rishi 657 9815 Rishi for (idx = 0; idx < MEDIATYPECOUNT; idx++) { 658 9815 Rishi mt = media_type_table + idx; 659 9815 Rishi if (strcasecmp(buf, mt->media_type_str) == 0) 660 9815 Rishi return (mt->media_type); 661 9815 Rishi } 662 9815 Rishi 663 9815 Rishi return (DL_OTHER); 664 3147 xc151355 } 665 3147 xc151355 666 3147 xc151355 dladm_status_t 667 8453 Anurag i_dladm_rw_db(dladm_handle_t handle, const char *db_file, mode_t db_perms, 668 8453 Anurag dladm_status_t (*process_db)(dladm_handle_t, void *, FILE *, FILE *), 669 3147 xc151355 void *arg, boolean_t writeop) 670 3147 xc151355 { 671 3147 xc151355 dladm_status_t status = DLADM_STATUS_OK; 672 3147 xc151355 FILE *fp, *nfp = NULL; 673 3147 xc151355 char lock[MAXPATHLEN]; 674 3147 xc151355 char file[MAXPATHLEN]; 675 3147 xc151355 char newfile[MAXPATHLEN]; 676 3147 xc151355 char *db_basename; 677 3147 xc151355 int nfd, lock_fd; 678 3147 xc151355 679 3147 xc151355 /* 680 3147 xc151355 * If we are called from a boot script such as net-physical, 681 3147 xc151355 * it's quite likely that the root fs is still not writable. 682 3147 xc151355 * For this case, it's ok for the lock creation to fail since 683 3147 xc151355 * no one else could be accessing our configuration file. 684 3147 xc151355 */ 685 3147 xc151355 db_basename = strrchr(db_file, '/'); 686 3147 xc151355 if (db_basename == NULL || db_basename[1] == '\0') 687 3147 xc151355 return (dladm_errno2status(EINVAL)); 688 3147 xc151355 db_basename++; 689 3147 xc151355 (void) snprintf(lock, MAXPATHLEN, "/tmp/%s.lock", db_basename); 690 3147 xc151355 if ((lock_fd = i_dladm_lock_db 691 3147 xc151355 (lock, (writeop ? F_WRLCK : F_RDLCK))) < 0 && errno != EROFS) 692 3147 xc151355 return (dladm_errno2status(errno)); 693 3147 xc151355 694 3147 xc151355 (void) snprintf(file, MAXPATHLEN, "%s/%s", dladm_rootdir, db_file); 695 3147 xc151355 if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL) { 696 3147 xc151355 int err = errno; 697 3147 xc151355 698 3147 xc151355 i_dladm_unlock_db(lock, lock_fd); 699 3147 xc151355 if (err == ENOENT) 700 3147 xc151355 return (DLADM_STATUS_DBNOTFOUND); 701 3147 xc151355 702 3147 xc151355 return (dladm_errno2status(err)); 703 3147 xc151355 } 704 3147 xc151355 705 3147 xc151355 if (writeop) { 706 3147 xc151355 (void) snprintf(newfile, MAXPATHLEN, "%s/%s.new", 707 3147 xc151355 dladm_rootdir, db_file); 708 3147 xc151355 if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC, 709 3147 xc151355 db_perms)) < 0) { 710 3147 xc151355 (void) fclose(fp); 711 3147 xc151355 i_dladm_unlock_db(lock, lock_fd); 712 3147 xc151355 return (dladm_errno2status(errno)); 713 3147 xc151355 } 714 3147 xc151355 715 3147 xc151355 if ((nfp = fdopen(nfd, "w")) == NULL) { 716 3147 xc151355 (void) close(nfd); 717 3147 xc151355 (void) fclose(fp); 718 3147 xc151355 (void) unlink(newfile); 719 3147 xc151355 i_dladm_unlock_db(lock, lock_fd); 720 3147 xc151355 return (dladm_errno2status(errno)); 721 3147 xc151355 } 722 3147 xc151355 } 723 8453 Anurag status = (*process_db)(handle, arg, fp, nfp); 724 3147 xc151355 if (!writeop || status != DLADM_STATUS_OK) 725 3147 xc151355 goto done; 726 3147 xc151355 727 3147 xc151355 /* 728 3147 xc151355 * Configuration files need to be owned by the 'dladm' user. 729 3147 xc151355 * If we are invoked by root, the file ownership needs to be fixed. 730 3147 xc151355 */ 731 3147 xc151355 if (getuid() == 0 || geteuid() == 0) { 732 6173 yz147064 if (fchown(nfd, UID_DLADM, GID_SYS) < 0) { 733 3147 xc151355 status = dladm_errno2status(errno); 734 3147 xc151355 goto done; 735 3147 xc151355 } 736 3147 xc151355 } 737 3147 xc151355 738 3147 xc151355 if (fflush(nfp) == EOF) { 739 3147 xc151355 status = dladm_errno2status(errno); 740 3147 xc151355 goto done; 741 3147 xc151355 } 742 3147 xc151355 (void) fclose(fp); 743 3147 xc151355 (void) fclose(nfp); 744 3147 xc151355 745 3147 xc151355 if (rename(newfile, file) < 0) { 746 3147 xc151355 (void) unlink(newfile); 747 3147 xc151355 i_dladm_unlock_db(lock, lock_fd); 748 3147 xc151355 return (dladm_errno2status(errno)); 749 3147 xc151355 } 750 3147 xc151355 751 3147 xc151355 i_dladm_unlock_db(lock, lock_fd); 752 3147 xc151355 return (DLADM_STATUS_OK); 753 3147 xc151355 754 3147 xc151355 done: 755 3147 xc151355 if (nfp != NULL) { 756 3147 xc151355 (void) fclose(nfp); 757 3147 xc151355 if (status != DLADM_STATUS_OK) 758 3147 xc151355 (void) unlink(newfile); 759 3147 xc151355 } 760 3147 xc151355 (void) fclose(fp); 761 3147 xc151355 i_dladm_unlock_db(lock, lock_fd); 762 3147 xc151355 return (status); 763 3147 xc151355 } 764 3147 xc151355 765 3147 xc151355 dladm_status_t 766 3147 xc151355 dladm_set_rootdir(const char *rootdir) 767 3147 xc151355 { 768 3147 xc151355 DIR *dp; 769 3147 xc151355 770 3147 xc151355 if (rootdir == NULL || *rootdir != '/' || 771 3147 xc151355 (dp = opendir(rootdir)) == NULL) 772 3147 xc151355 return (DLADM_STATUS_BADARG); 773 3147 xc151355 774 3147 xc151355 (void) strncpy(dladm_rootdir, rootdir, MAXPATHLEN); 775 3147 xc151355 (void) closedir(dp); 776 3147 xc151355 return (DLADM_STATUS_OK); 777 3147 xc151355 } 778 5895 yz147064 779 5895 yz147064 boolean_t 780 5895 yz147064 dladm_valid_linkname(const char *link) 781 5895 yz147064 { 782 5895 yz147064 size_t len = strlen(link); 783 5895 yz147064 const char *cp; 784 5895 yz147064 785 10616 Sebastien if (len >= MAXLINKNAMELEN) 786 5895 yz147064 return (B_FALSE); 787 5895 yz147064 788 5895 yz147064 /* 789 5895 yz147064 * The link name cannot start with a digit and must end with a digit. 790 5895 yz147064 */ 791 5895 yz147064 if ((isdigit(link[0]) != 0) || (isdigit(link[len - 1]) == 0)) 792 5895 yz147064 return (B_FALSE); 793 5895 yz147064 794 5895 yz147064 /* 795 5895 yz147064 * The legal characters in a link name are: 796 10616 Sebastien * alphanumeric (a-z, A-Z, 0-9), underscore ('_'), and '.'. 797 5895 yz147064 */ 798 5895 yz147064 for (cp = link; *cp != '\0'; cp++) { 799 10616 Sebastien if ((isalnum(*cp) == 0) && (*cp != '_') && (*cp != '.')) 800 5895 yz147064 return (B_FALSE); 801 5895 yz147064 } 802 5895 yz147064 803 5895 yz147064 return (B_TRUE); 804 5895 yz147064 } 805 8275 Eric 806 8275 Eric /* 807 8275 Eric * Convert priority string to a value. 808 8275 Eric */ 809 8275 Eric dladm_status_t 810 8275 Eric dladm_str2pri(char *token, mac_priority_level_t *pri) 811 8275 Eric { 812 8275 Eric if (strlen(token) == strlen("low") && 813 8275 Eric strncasecmp(token, "low", strlen("low")) == 0) { 814 8275 Eric *pri = MPL_LOW; 815 8275 Eric } else if (strlen(token) == strlen("medium") && 816 8275 Eric strncasecmp(token, "medium", strlen("medium")) == 0) { 817 8275 Eric *pri = MPL_MEDIUM; 818 8275 Eric } else if (strlen(token) == strlen("high") && 819 8275 Eric strncasecmp(token, "high", strlen("high")) == 0) { 820 8275 Eric *pri = MPL_HIGH; 821 8275 Eric } else { 822 8275 Eric return (DLADM_STATUS_BADVAL); 823 8275 Eric } 824 8275 Eric return (DLADM_STATUS_OK); 825 8275 Eric } 826 8275 Eric 827 8275 Eric /* 828 8275 Eric * Convert priority value to a string. 829 8275 Eric */ 830 8275 Eric const char * 831 8275 Eric dladm_pri2str(mac_priority_level_t pri, char *buf) 832 8275 Eric { 833 8275 Eric const char *s; 834 8275 Eric 835 8275 Eric switch (pri) { 836 8275 Eric case MPL_LOW: 837 8275 Eric s = "low"; 838 8275 Eric break; 839 8275 Eric case MPL_MEDIUM: 840 8275 Eric s = "medium"; 841 8275 Eric break; 842 8275 Eric case MPL_HIGH: 843 8275 Eric s = "high"; 844 8275 Eric break; 845 8275 Eric default: 846 8275 Eric s = "--"; 847 8275 Eric break; 848 8275 Eric } 849 8275 Eric (void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s)); 850 8275 Eric return (buf); 851 8275 Eric } 852 8275 Eric 853 10734 Eric /* 854 10734 Eric * Convert protect string to a value. 855 10734 Eric */ 856 10734 Eric dladm_status_t 857 10734 Eric dladm_str2protect(char *token, uint32_t *ptype) 858 10734 Eric { 859 10734 Eric link_protect_t *lp; 860 10734 Eric int i; 861 10734 Eric 862 10734 Eric for (i = 0; i < LPTYPES; i++) { 863 10734 Eric lp = &link_protect_types[i]; 864 10734 Eric if (strcmp(token, lp->lp_name) == 0) { 865 10734 Eric *ptype = lp->lp_type; 866 10734 Eric return (DLADM_STATUS_OK); 867 10734 Eric } 868 10734 Eric } 869 10734 Eric return (DLADM_STATUS_BADVAL); 870 10734 Eric } 871 10734 Eric 872 10734 Eric /* 873 10734 Eric * Convert protect value to a string. 874 10734 Eric */ 875 10734 Eric const char * 876 10734 Eric dladm_protect2str(uint32_t ptype, char *buf) 877 10734 Eric { 878 10734 Eric const char *s = "--"; 879 10734 Eric link_protect_t *lp; 880 10734 Eric int i; 881 10734 Eric 882 10734 Eric for (i = 0; i < LPTYPES; i++) { 883 10734 Eric lp = &link_protect_types[i]; 884 10734 Eric if (lp->lp_type == ptype) { 885 10734 Eric s = lp->lp_name; 886 10734 Eric break; 887 10734 Eric } 888 10734 Eric } 889 10734 Eric (void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s)); 890 10734 Eric return (buf); 891 10734 Eric } 892 10734 Eric 893 10734 Eric /* 894 10734 Eric * Convert an IPv4 address to/from a string. 895 10734 Eric */ 896 10734 Eric const char * 897 10734 Eric dladm_ipv4addr2str(void *addr, char *buf) 898 10734 Eric { 899 10734 Eric if (inet_ntop(AF_INET, addr, buf, INET_ADDRSTRLEN) == NULL) 900 10734 Eric buf[0] = 0; 901 10734 Eric 902 10734 Eric return (buf); 903 10734 Eric } 904 10734 Eric 905 10734 Eric dladm_status_t 906 10734 Eric dladm_str2ipv4addr(char *token, void *addr) 907 10734 Eric { 908 10734 Eric return (inet_pton(AF_INET, token, addr) == 1 ? 909 10734 Eric DLADM_STATUS_OK : DLADM_STATUS_INVALID_IP); 910 10734 Eric } 911 10734 Eric 912 10734 Eric /* 913 10734 Eric * Find the set bits in a mask. 914 10734 Eric * This is used for expanding a bitmask into individual sub-masks 915 10734 Eric * which can be used for further processing. 916 10734 Eric */ 917 10734 Eric void 918 10734 Eric dladm_find_setbits32(uint32_t mask, uint32_t *list, uint32_t *cnt) 919 10734 Eric { 920 10734 Eric int i, c = 0; 921 10734 Eric 922 10734 Eric for (i = 0; i < 32; i++) { 923 10734 Eric if (((1 << i) & mask) != 0) 924 10734 Eric list[c++] = 1 << i; 925 10734 Eric } 926 10734 Eric *cnt = c; 927 10734 Eric } 928 10734 Eric 929 8275 Eric void 930 8275 Eric dladm_free_args(dladm_arg_list_t *list) 931 8275 Eric { 932 8275 Eric if (list != NULL) { 933 8275 Eric free(list->al_buf); 934 8275 Eric free(list); 935 8275 Eric } 936 8275 Eric } 937 8275 Eric 938 8275 Eric dladm_status_t 939 8275 Eric dladm_parse_args(char *str, dladm_arg_list_t **listp, boolean_t novalues) 940 8275 Eric { 941 8275 Eric dladm_arg_list_t *list; 942 8275 Eric dladm_arg_info_t *aip; 943 8275 Eric char *buf, *curr; 944 8275 Eric int len, i; 945 8275 Eric 946 9055 Michael if (str == NULL) 947 9055 Michael return (DLADM_STATUS_BADVAL); 948 9055 Michael 949 9055 Michael if (str[0] == '\0') 950 9055 Michael return (DLADM_STATUS_OK); 951 9055 Michael 952 8275 Eric list = malloc(sizeof (dladm_arg_list_t)); 953 8275 Eric if (list == NULL) 954 8275 Eric return (dladm_errno2status(errno)); 955 8275 Eric 956 8275 Eric list->al_count = 0; 957 8275 Eric list->al_buf = buf = strdup(str); 958 8275 Eric if (buf == NULL) 959 8275 Eric return (dladm_errno2status(errno)); 960 8275 Eric 961 8275 Eric curr = buf; 962 8275 Eric len = strlen(buf); 963 8275 Eric aip = NULL; 964 8275 Eric for (i = 0; i < len; i++) { 965 8275 Eric char c = buf[i]; 966 8275 Eric boolean_t match = (c == '=' || c == ','); 967 8275 Eric 968 8275 Eric if (!match && i != len - 1) 969 8275 Eric continue; 970 8275 Eric 971 8275 Eric if (match) { 972 8275 Eric buf[i] = '\0'; 973 8275 Eric if (*curr == '\0') 974 8275 Eric goto fail; 975 8275 Eric } 976 8275 Eric 977 8275 Eric if (aip != NULL && c != '=') { 978 8275 Eric if (aip->ai_count > DLADM_MAX_ARG_VALS) 979 8275 Eric goto fail; 980 8275 Eric 981 8275 Eric if (novalues) 982 8275 Eric goto fail; 983 8275 Eric 984 8275 Eric aip->ai_val[aip->ai_count] = curr; 985 8275 Eric aip->ai_count++; 986 8275 Eric } else { 987 8275 Eric if (list->al_count > DLADM_MAX_ARG_VALS) 988 8275 Eric goto fail; 989 8275 Eric 990 8275 Eric aip = &list->al_info[list->al_count]; 991 8275 Eric aip->ai_name = curr; 992 8275 Eric aip->ai_count = 0; 993 8275 Eric list->al_count++; 994 8275 Eric if (c == ',') 995 8275 Eric aip = NULL; 996 8275 Eric } 997 8275 Eric curr = buf + i + 1; 998 8275 Eric } 999 8275 Eric 1000 8275 Eric *listp = list; 1001 8275 Eric return (DLADM_STATUS_OK); 1002 8275 Eric 1003 8275 Eric fail: 1004 8275 Eric dladm_free_args(list); 1005 8275 Eric return (DLADM_STATUS_FAILED); 1006 8275 Eric } 1007