1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/types.h> 27 #include <string.h> 28 #include <strings.h> 29 #include <sys/mac.h> 30 #include <sys/dls_mgmt.h> 31 #include <sys/dlpi.h> 32 #include <net/simnet.h> 33 #include <errno.h> 34 #include <unistd.h> 35 36 #include <libdladm_impl.h> 37 #include <libdllink.h> 38 #include <libdlaggr.h> 39 #include <libdlsim.h> 40 41 static dladm_status_t dladm_simnet_persist_conf(dladm_handle_t, const char *, 42 dladm_simnet_attr_t *); 43 44 /* New simnet instance creation */ 45 static dladm_status_t 46 i_dladm_create_simnet(dladm_handle_t handle, dladm_simnet_attr_t *attrp) 47 { 48 int rc; 49 dladm_status_t status = DLADM_STATUS_OK; 50 simnet_ioc_create_t ioc; 51 52 bzero(&ioc, sizeof (ioc)); 53 ioc.sic_link_id = attrp->sna_link_id; 54 ioc.sic_type = attrp->sna_type; 55 if (attrp->sna_mac_len > 0 && attrp->sna_mac_len <= MAXMACADDRLEN) { 56 ioc.sic_mac_len = attrp->sna_mac_len; 57 bcopy(attrp->sna_mac_addr, ioc.sic_mac_addr, ioc.sic_mac_len); 58 } 59 60 rc = ioctl(dladm_dld_fd(handle), SIMNET_IOC_CREATE, &ioc); 61 if (rc < 0) 62 status = dladm_errno2status(errno); 63 64 if (status != DLADM_STATUS_OK) 65 return (status); 66 67 bcopy(ioc.sic_mac_addr, attrp->sna_mac_addr, MAXMACADDRLEN); 68 attrp->sna_mac_len = ioc.sic_mac_len; 69 return (status); 70 } 71 72 /* Modify existing simnet instance */ 73 static dladm_status_t 74 i_dladm_modify_simnet(dladm_handle_t handle, dladm_simnet_attr_t *attrp) 75 { 76 int rc; 77 dladm_status_t status = DLADM_STATUS_OK; 78 simnet_ioc_modify_t ioc; 79 80 bzero(&ioc, sizeof (ioc)); 81 ioc.sim_link_id = attrp->sna_link_id; 82 ioc.sim_peer_link_id = attrp->sna_peer_link_id; 83 84 rc = ioctl(dladm_dld_fd(handle), SIMNET_IOC_MODIFY, &ioc); 85 if (rc < 0) 86 status = dladm_errno2status(errno); 87 88 return (status); 89 } 90 91 /* Delete simnet instance */ 92 static dladm_status_t 93 i_dladm_delete_simnet(dladm_handle_t handle, dladm_simnet_attr_t *attrp) 94 { 95 int rc; 96 dladm_status_t status = DLADM_STATUS_OK; 97 simnet_ioc_delete_t ioc; 98 99 bzero(&ioc, sizeof (ioc)); 100 ioc.sid_link_id = attrp->sna_link_id; 101 102 rc = ioctl(dladm_dld_fd(handle), SIMNET_IOC_DELETE, &ioc); 103 if (rc < 0) 104 status = dladm_errno2status(errno); 105 106 return (status); 107 } 108 109 /* Retrieve simnet instance information */ 110 static dladm_status_t 111 i_dladm_get_simnet_info(dladm_handle_t handle, dladm_simnet_attr_t *attrp) 112 { 113 int rc; 114 dladm_status_t status = DLADM_STATUS_OK; 115 simnet_ioc_info_t ioc; 116 117 bzero(&ioc, sizeof (ioc)); 118 ioc.sii_link_id = attrp->sna_link_id; 119 120 rc = ioctl(dladm_dld_fd(handle), SIMNET_IOC_INFO, &ioc); 121 if (rc < 0) { 122 status = dladm_errno2status(errno); 123 return (status); 124 } 125 126 bcopy(ioc.sii_mac_addr, attrp->sna_mac_addr, MAXMACADDRLEN); 127 attrp->sna_mac_len = ioc.sii_mac_len; 128 attrp->sna_peer_link_id = ioc.sii_peer_link_id; 129 attrp->sna_type = ioc.sii_type; 130 return (status); 131 } 132 133 /* Retrieve simnet configuratin */ 134 static dladm_status_t 135 i_dladm_get_simnet_info_persist(dladm_handle_t handle, 136 dladm_simnet_attr_t *attrp) 137 { 138 dladm_conf_t conf; 139 dladm_status_t status; 140 char macstr[ETHERADDRL * 3]; 141 char simnetpeer[MAXLINKNAMELEN]; 142 uint64_t u64; 143 boolean_t mac_fixed; 144 145 if ((status = dladm_read_conf(handle, attrp->sna_link_id, &conf)) != 146 DLADM_STATUS_OK) 147 return (status); 148 149 status = dladm_get_conf_field(handle, conf, FSIMNETTYPE, &u64, 150 sizeof (u64)); 151 if (status != DLADM_STATUS_OK) 152 goto done; 153 attrp->sna_type = (uint_t)u64; 154 155 status = dladm_get_conf_field(handle, conf, FMADDRLEN, &u64, 156 sizeof (u64)); 157 if (status != DLADM_STATUS_OK) 158 goto done; 159 attrp->sna_mac_len = (uint_t)u64; 160 161 status = dladm_get_conf_field(handle, conf, FMACADDR, macstr, 162 sizeof (macstr)); 163 if (status != DLADM_STATUS_OK) 164 goto done; 165 (void) dladm_aggr_str2macaddr(macstr, &mac_fixed, attrp->sna_mac_addr); 166 167 /* Peer field is optional and only set when peer is attached */ 168 if (dladm_get_conf_field(handle, conf, FSIMNETPEER, simnetpeer, 169 sizeof (simnetpeer)) == DLADM_STATUS_OK) { 170 status = dladm_name2info(handle, simnetpeer, 171 &attrp->sna_peer_link_id, NULL, NULL, NULL); 172 } else { 173 attrp->sna_peer_link_id = DATALINK_INVALID_LINKID; 174 } 175 done: 176 dladm_destroy_conf(handle, conf); 177 return (status); 178 } 179 180 dladm_status_t 181 dladm_simnet_create(dladm_handle_t handle, const char *simnetname, 182 uint_t media, uint32_t flags) 183 { 184 datalink_id_t simnet_id; 185 dladm_status_t status; 186 dladm_simnet_attr_t attr; 187 188 if (!(flags & DLADM_OPT_ACTIVE)) 189 return (DLADM_STATUS_NOTSUP); 190 191 flags &= (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 192 if ((status = dladm_create_datalink_id(handle, simnetname, 193 DATALINK_CLASS_SIMNET, media, flags, 194 &simnet_id)) != DLADM_STATUS_OK) 195 return (status); 196 197 bzero(&attr, sizeof (attr)); 198 attr.sna_link_id = simnet_id; 199 attr.sna_type = media; 200 status = i_dladm_create_simnet(handle, &attr); 201 if (status != DLADM_STATUS_OK) 202 goto done; 203 204 if (!(flags & DLADM_OPT_PERSIST)) 205 goto done; 206 207 status = dladm_simnet_persist_conf(handle, simnetname, &attr); 208 if (status != DLADM_STATUS_OK) { 209 (void) i_dladm_delete_simnet(handle, &attr); 210 goto done; 211 } 212 213 (void) dladm_set_linkprop(handle, simnet_id, NULL, NULL, 0, flags); 214 215 done: 216 if (status != DLADM_STATUS_OK) { 217 (void) dladm_destroy_datalink_id(handle, simnet_id, flags); 218 } 219 return (status); 220 } 221 222 /* Update existing simnet configuration */ 223 static dladm_status_t 224 i_dladm_simnet_update_conf(dladm_handle_t handle, datalink_id_t simnet_id, 225 datalink_id_t peer_simnet_id) 226 { 227 dladm_status_t status; 228 dladm_conf_t conf; 229 char simnetpeer[MAXLINKNAMELEN]; 230 231 status = dladm_read_conf(handle, simnet_id, &conf); 232 if (status != DLADM_STATUS_OK) 233 return (status); 234 235 /* First clear previous peer if any in configuration */ 236 (void) dladm_unset_conf_field(handle, conf, FSIMNETPEER); 237 if (peer_simnet_id != DATALINK_INVALID_LINKID) { 238 if ((status = dladm_datalink_id2info(handle, 239 peer_simnet_id, NULL, NULL, NULL, simnetpeer, 240 sizeof (simnetpeer))) == DLADM_STATUS_OK) { 241 status = dladm_set_conf_field(handle, conf, 242 FSIMNETPEER, DLADM_TYPE_STR, simnetpeer); 243 } 244 if (status != DLADM_STATUS_OK) 245 goto fail; 246 } 247 248 status = dladm_write_conf(handle, conf); 249 fail: 250 dladm_destroy_conf(handle, conf); 251 return (status); 252 } 253 254 /* Modify attached simnet peer */ 255 dladm_status_t 256 dladm_simnet_modify(dladm_handle_t handle, datalink_id_t simnet_id, 257 datalink_id_t peer_simnet_id, uint32_t flags) 258 { 259 dladm_simnet_attr_t attr; 260 dladm_simnet_attr_t prevattr; 261 dladm_status_t status; 262 datalink_class_t class; 263 uint32_t linkflags; 264 uint32_t peerlinkflags; 265 266 if (!(flags & DLADM_OPT_ACTIVE)) 267 return (DLADM_STATUS_NOTSUP); 268 269 if ((dladm_datalink_id2info(handle, simnet_id, &linkflags, &class, 270 NULL, NULL, 0) != DLADM_STATUS_OK)) 271 return (DLADM_STATUS_BADARG); 272 if (class != DATALINK_CLASS_SIMNET) 273 return (DLADM_STATUS_BADARG); 274 275 if (peer_simnet_id != DATALINK_INVALID_LINKID) { 276 if (dladm_datalink_id2info(handle, peer_simnet_id, 277 &peerlinkflags, &class, NULL, NULL, 0) != DLADM_STATUS_OK) 278 return (DLADM_STATUS_BADARG); 279 if (class != DATALINK_CLASS_SIMNET) 280 return (DLADM_STATUS_BADARG); 281 /* Check to ensure the peer link has identical flags */ 282 if (peerlinkflags != linkflags) 283 return (DLADM_STATUS_BADARG); 284 } 285 286 /* Retrieve previous attrs before modification */ 287 bzero(&prevattr, sizeof (prevattr)); 288 if ((status = dladm_simnet_info(handle, simnet_id, &prevattr, 289 flags)) != DLADM_STATUS_OK) 290 return (status); 291 292 bzero(&attr, sizeof (attr)); 293 attr.sna_link_id = simnet_id; 294 attr.sna_peer_link_id = peer_simnet_id; 295 status = i_dladm_modify_simnet(handle, &attr); 296 if ((status != DLADM_STATUS_OK) || !(flags & DLADM_OPT_PERSIST)) 297 return (status); 298 299 /* First we clear link's existing peer field in config */ 300 status = i_dladm_simnet_update_conf(handle, simnet_id, 301 DATALINK_INVALID_LINKID); 302 if (status != DLADM_STATUS_OK) 303 return (status); 304 305 /* Clear the previous peer link's existing peer field in config */ 306 if (prevattr.sna_peer_link_id != DATALINK_INVALID_LINKID) { 307 status = i_dladm_simnet_update_conf(handle, 308 prevattr.sna_peer_link_id, DATALINK_INVALID_LINKID); 309 if (status != DLADM_STATUS_OK) 310 return (status); 311 } 312 313 /* Update the configuration in both simnets with any new peer link */ 314 if (peer_simnet_id != DATALINK_INVALID_LINKID) { 315 status = i_dladm_simnet_update_conf(handle, simnet_id, 316 peer_simnet_id); 317 if (status == DLADM_STATUS_OK) 318 status = i_dladm_simnet_update_conf(handle, 319 peer_simnet_id, simnet_id); 320 } 321 322 return (status); 323 } 324 325 dladm_status_t 326 dladm_simnet_delete(dladm_handle_t handle, datalink_id_t simnet_id, 327 uint32_t flags) 328 { 329 dladm_simnet_attr_t attr; 330 dladm_simnet_attr_t prevattr; 331 dladm_status_t status; 332 datalink_class_t class; 333 334 if ((dladm_datalink_id2info(handle, simnet_id, NULL, &class, 335 NULL, NULL, 0) != DLADM_STATUS_OK)) 336 return (DLADM_STATUS_BADARG); 337 338 if (class != DATALINK_CLASS_SIMNET) 339 return (DLADM_STATUS_BADARG); 340 341 /* Check current simnet attributes before deletion */ 342 flags &= (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 343 bzero(&prevattr, sizeof (prevattr)); 344 if ((status = dladm_simnet_info(handle, simnet_id, &prevattr, 345 flags)) != DLADM_STATUS_OK) 346 return (status); 347 348 bzero(&attr, sizeof (attr)); 349 attr.sna_link_id = simnet_id; 350 if (flags & DLADM_OPT_ACTIVE) { 351 status = i_dladm_delete_simnet(handle, &attr); 352 if (status == DLADM_STATUS_OK) { 353 (void) dladm_set_linkprop(handle, simnet_id, NULL, 354 NULL, 0, DLADM_OPT_ACTIVE); 355 (void) dladm_destroy_datalink_id(handle, simnet_id, 356 DLADM_OPT_ACTIVE); 357 } else if (status != DLADM_STATUS_NOTFOUND) { 358 return (status); 359 } 360 } 361 362 if (flags & DLADM_OPT_PERSIST) { 363 (void) dladm_remove_conf(handle, simnet_id); 364 (void) dladm_destroy_datalink_id(handle, simnet_id, 365 DLADM_OPT_PERSIST); 366 367 /* Update any attached peer configuration */ 368 if (prevattr.sna_peer_link_id != DATALINK_INVALID_LINKID) 369 status = i_dladm_simnet_update_conf(handle, 370 prevattr.sna_peer_link_id, DATALINK_INVALID_LINKID); 371 } 372 return (status); 373 } 374 375 /* Retrieve simnet information either active or from configuration */ 376 dladm_status_t 377 dladm_simnet_info(dladm_handle_t handle, datalink_id_t simnet_id, 378 dladm_simnet_attr_t *attrp, uint32_t flags) 379 { 380 datalink_class_t class; 381 dladm_status_t status; 382 383 if ((dladm_datalink_id2info(handle, simnet_id, NULL, &class, 384 NULL, NULL, 0) != DLADM_STATUS_OK)) 385 return (DLADM_STATUS_BADARG); 386 387 if (class != DATALINK_CLASS_SIMNET) 388 return (DLADM_STATUS_BADARG); 389 390 bzero(attrp, sizeof (attrp)); 391 attrp->sna_link_id = simnet_id; 392 393 if (flags & DLADM_OPT_ACTIVE) { 394 status = i_dladm_get_simnet_info(handle, attrp); 395 /* 396 * If no active simnet found then return any simnet 397 * from stored config if requested. 398 */ 399 if (status == DLADM_STATUS_NOTFOUND && 400 (flags & DLADM_OPT_PERSIST)) 401 return (i_dladm_get_simnet_info_persist(handle, attrp)); 402 return (status); 403 } else if (flags & DLADM_OPT_PERSIST) { 404 return (i_dladm_get_simnet_info_persist(handle, attrp)); 405 } else { 406 return (DLADM_STATUS_BADARG); 407 } 408 } 409 410 /* Bring up simnet from stored configuration */ 411 static int 412 i_dladm_simnet_up(dladm_handle_t handle, datalink_id_t simnet_id, void *arg) 413 { 414 dladm_status_t *statusp = arg; 415 dladm_status_t status; 416 dladm_simnet_attr_t attr; 417 dladm_simnet_attr_t peer_attr; 418 419 bzero(&attr, sizeof (attr)); 420 attr.sna_link_id = simnet_id; 421 status = dladm_simnet_info(handle, simnet_id, &attr, 422 DLADM_OPT_PERSIST); 423 if (status != DLADM_STATUS_OK) 424 goto done; 425 426 status = i_dladm_create_simnet(handle, &attr); 427 if (status != DLADM_STATUS_OK) 428 goto done; 429 430 /* 431 * When bringing up check if the peer link is available, if it 432 * is then modify the simnet and attach the peer link. 433 */ 434 if ((attr.sna_peer_link_id != DATALINK_INVALID_LINKID) && 435 (dladm_simnet_info(handle, attr.sna_peer_link_id, &peer_attr, 436 DLADM_OPT_ACTIVE) == DLADM_STATUS_OK)) { 437 status = i_dladm_modify_simnet(handle, &attr); 438 if (status != DLADM_STATUS_OK) 439 goto done; 440 } 441 442 if ((status = dladm_up_datalink_id(handle, simnet_id)) != 443 DLADM_STATUS_OK) { 444 (void) dladm_simnet_delete(handle, simnet_id, 445 DLADM_OPT_PERSIST); 446 goto done; 447 } 448 done: 449 *statusp = status; 450 return (DLADM_WALK_CONTINUE); 451 } 452 453 /* Bring up simnet instance(s) from configuration */ 454 /* ARGSUSED */ 455 dladm_status_t 456 dladm_simnet_up(dladm_handle_t handle, datalink_id_t simnet_id, 457 uint32_t flags) 458 { 459 dladm_status_t status; 460 461 if (simnet_id == DATALINK_ALL_LINKID) { 462 (void) dladm_walk_datalink_id(i_dladm_simnet_up, handle, 463 &status, DATALINK_CLASS_SIMNET, DATALINK_ANY_MEDIATYPE, 464 DLADM_OPT_PERSIST); 465 return (DLADM_STATUS_OK); 466 } else { 467 (void) i_dladm_simnet_up(handle, simnet_id, &status); 468 return (status); 469 } 470 } 471 472 /* Store simnet configuration */ 473 static dladm_status_t 474 dladm_simnet_persist_conf(dladm_handle_t handle, const char *name, 475 dladm_simnet_attr_t *attrp) 476 { 477 dladm_conf_t conf = DLADM_INVALID_CONF; 478 dladm_status_t status; 479 char mstr[ETHERADDRL * 3]; 480 uint64_t u64; 481 482 if ((status = dladm_create_conf(handle, name, attrp->sna_link_id, 483 DATALINK_CLASS_SIMNET, attrp->sna_type, &conf)) != DLADM_STATUS_OK) 484 return (status); 485 486 status = dladm_set_conf_field(handle, conf, FMACADDR, 487 DLADM_TYPE_STR, dladm_aggr_macaddr2str(attrp->sna_mac_addr, mstr)); 488 if (status != DLADM_STATUS_OK) 489 goto done; 490 491 u64 = attrp->sna_type; 492 status = dladm_set_conf_field(handle, conf, FSIMNETTYPE, 493 DLADM_TYPE_UINT64, &u64); 494 if (status != DLADM_STATUS_OK) 495 goto done; 496 497 u64 = attrp->sna_mac_len; 498 status = dladm_set_conf_field(handle, conf, FMADDRLEN, 499 DLADM_TYPE_UINT64, &u64); 500 if (status != DLADM_STATUS_OK) 501 goto done; 502 503 status = dladm_write_conf(handle, conf); 504 done: 505 dladm_destroy_conf(handle, conf); 506 return (status); 507 } 508