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 uint64_t u64; 142 boolean_t mac_fixed; 143 144 if ((status = dladm_read_conf(handle, attrp->sna_link_id, &conf)) != 145 DLADM_STATUS_OK) 146 return (status); 147 148 status = dladm_get_conf_field(handle, conf, FSIMNETTYPE, &u64, 149 sizeof (u64)); 150 if (status != DLADM_STATUS_OK) 151 goto done; 152 attrp->sna_type = (uint_t)u64; 153 154 status = dladm_get_conf_field(handle, conf, FMADDRLEN, &u64, 155 sizeof (u64)); 156 if (status != DLADM_STATUS_OK) 157 goto done; 158 attrp->sna_mac_len = (uint_t)u64; 159 160 status = dladm_get_conf_field(handle, conf, FMACADDR, macstr, 161 sizeof (macstr)); 162 if (status != DLADM_STATUS_OK) 163 goto done; 164 (void) dladm_aggr_str2macaddr(macstr, &mac_fixed, attrp->sna_mac_addr); 165 166 /* Peer field is optional and only set when peer is attached */ 167 if (dladm_get_conf_field(handle, conf, FSIMNETPEER, &u64, 168 sizeof (u64)) == DLADM_STATUS_OK) 169 attrp->sna_peer_link_id = (datalink_id_t)u64; 170 else 171 attrp->sna_peer_link_id = DATALINK_INVALID_LINKID; 172 done: 173 dladm_destroy_conf(handle, conf); 174 return (status); 175 } 176 177 dladm_status_t 178 dladm_simnet_create(dladm_handle_t handle, const char *simnetname, 179 uint_t media, uint32_t flags) 180 { 181 datalink_id_t simnet_id; 182 dladm_status_t status; 183 dladm_simnet_attr_t attr; 184 185 if (!(flags & DLADM_OPT_ACTIVE)) 186 return (DLADM_STATUS_NOTSUP); 187 188 flags &= (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 189 if ((status = dladm_create_datalink_id(handle, simnetname, 190 DATALINK_CLASS_SIMNET, media, flags, 191 &simnet_id)) != DLADM_STATUS_OK) 192 return (status); 193 194 bzero(&attr, sizeof (attr)); 195 attr.sna_link_id = simnet_id; 196 attr.sna_type = media; 197 status = i_dladm_create_simnet(handle, &attr); 198 if (status != DLADM_STATUS_OK) 199 goto done; 200 201 if (!(flags & DLADM_OPT_PERSIST)) 202 goto done; 203 204 status = dladm_simnet_persist_conf(handle, simnetname, &attr); 205 if (status != DLADM_STATUS_OK) { 206 (void) i_dladm_delete_simnet(handle, &attr); 207 goto done; 208 } 209 210 (void) dladm_set_linkprop(handle, simnet_id, NULL, NULL, 0, flags); 211 212 done: 213 if (status != DLADM_STATUS_OK) { 214 (void) dladm_destroy_datalink_id(handle, simnet_id, flags); 215 } 216 return (status); 217 } 218 219 /* Update existing simnet configuration */ 220 static dladm_status_t 221 i_dladm_simnet_update_conf(dladm_handle_t handle, datalink_id_t simnet_id, 222 datalink_id_t peer_simnet_id) 223 { 224 dladm_status_t status; 225 dladm_conf_t conf; 226 uint64_t u64; 227 228 status = dladm_read_conf(handle, simnet_id, &conf); 229 if (status != DLADM_STATUS_OK) 230 return (status); 231 232 /* First clear previous peer if any in configuration */ 233 (void) dladm_unset_conf_field(handle, conf, FSIMNETPEER); 234 if (peer_simnet_id != DATALINK_INVALID_LINKID) { 235 u64 = peer_simnet_id; 236 if ((status = dladm_datalink_id2info(handle, 237 peer_simnet_id, NULL, NULL, NULL, NULL, 238 0)) == DLADM_STATUS_OK) 239 status = dladm_set_conf_field(handle, conf, 240 FSIMNETPEER, DLADM_TYPE_UINT64, &u64); 241 if (status != DLADM_STATUS_OK) 242 goto fail; 243 } 244 245 status = dladm_write_conf(handle, conf); 246 fail: 247 dladm_destroy_conf(handle, conf); 248 return (status); 249 } 250 251 /* Modify attached simnet peer */ 252 dladm_status_t 253 dladm_simnet_modify(dladm_handle_t handle, datalink_id_t simnet_id, 254 datalink_id_t peer_simnet_id, uint32_t flags) 255 { 256 dladm_simnet_attr_t attr; 257 dladm_simnet_attr_t prevattr; 258 dladm_status_t status; 259 datalink_class_t class; 260 uint32_t linkflags; 261 uint32_t peerlinkflags; 262 263 if (!(flags & DLADM_OPT_ACTIVE)) 264 return (DLADM_STATUS_NOTSUP); 265 266 if ((dladm_datalink_id2info(handle, simnet_id, &linkflags, &class, 267 NULL, NULL, 0) != DLADM_STATUS_OK)) 268 return (DLADM_STATUS_BADARG); 269 if (class != DATALINK_CLASS_SIMNET) 270 return (DLADM_STATUS_BADARG); 271 272 if (peer_simnet_id != DATALINK_INVALID_LINKID) { 273 if (dladm_datalink_id2info(handle, peer_simnet_id, 274 &peerlinkflags, &class, NULL, NULL, 0) != DLADM_STATUS_OK) 275 return (DLADM_STATUS_BADARG); 276 if (class != DATALINK_CLASS_SIMNET) 277 return (DLADM_STATUS_BADARG); 278 /* Check to ensure the peer link has identical flags */ 279 if (peerlinkflags != linkflags) 280 return (DLADM_STATUS_BADARG); 281 } 282 283 /* Retrieve previous attrs before modification */ 284 bzero(&prevattr, sizeof (prevattr)); 285 if ((status = dladm_simnet_info(handle, simnet_id, &prevattr, 286 flags)) != DLADM_STATUS_OK) 287 return (status); 288 289 bzero(&attr, sizeof (attr)); 290 attr.sna_link_id = simnet_id; 291 attr.sna_peer_link_id = peer_simnet_id; 292 status = i_dladm_modify_simnet(handle, &attr); 293 if ((status != DLADM_STATUS_OK) || !(flags & DLADM_OPT_PERSIST)) 294 return (status); 295 296 /* First we clear link's existing peer field in config */ 297 status = i_dladm_simnet_update_conf(handle, simnet_id, 298 DATALINK_INVALID_LINKID); 299 if (status != DLADM_STATUS_OK) 300 return (status); 301 302 /* Clear the previous peer link's existing peer field in config */ 303 if (prevattr.sna_peer_link_id != DATALINK_INVALID_LINKID) { 304 status = i_dladm_simnet_update_conf(handle, 305 prevattr.sna_peer_link_id, DATALINK_INVALID_LINKID); 306 if (status != DLADM_STATUS_OK) 307 return (status); 308 } 309 310 /* Update the configuration in both simnets with any new peer link */ 311 if (peer_simnet_id != DATALINK_INVALID_LINKID) { 312 status = i_dladm_simnet_update_conf(handle, simnet_id, 313 peer_simnet_id); 314 if (status == DLADM_STATUS_OK) 315 status = i_dladm_simnet_update_conf(handle, 316 peer_simnet_id, simnet_id); 317 } 318 319 return (status); 320 } 321 322 dladm_status_t 323 dladm_simnet_delete(dladm_handle_t handle, datalink_id_t simnet_id, 324 uint32_t flags) 325 { 326 dladm_simnet_attr_t attr; 327 dladm_simnet_attr_t prevattr; 328 dladm_status_t status; 329 datalink_class_t class; 330 331 if ((dladm_datalink_id2info(handle, simnet_id, NULL, &class, 332 NULL, NULL, 0) != DLADM_STATUS_OK)) 333 return (DLADM_STATUS_BADARG); 334 335 if (class != DATALINK_CLASS_SIMNET) 336 return (DLADM_STATUS_BADARG); 337 338 /* Check current simnet attributes before deletion */ 339 flags &= (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 340 bzero(&prevattr, sizeof (prevattr)); 341 if ((status = dladm_simnet_info(handle, simnet_id, &prevattr, 342 flags)) != DLADM_STATUS_OK) 343 return (status); 344 345 bzero(&attr, sizeof (attr)); 346 attr.sna_link_id = simnet_id; 347 if (flags & DLADM_OPT_ACTIVE) { 348 status = i_dladm_delete_simnet(handle, &attr); 349 if (status == DLADM_STATUS_OK) { 350 (void) dladm_set_linkprop(handle, simnet_id, NULL, 351 NULL, 0, DLADM_OPT_ACTIVE); 352 (void) dladm_destroy_datalink_id(handle, simnet_id, 353 DLADM_OPT_ACTIVE); 354 } else if (status != DLADM_STATUS_NOTFOUND) { 355 return (status); 356 } 357 } 358 359 if (flags & DLADM_OPT_PERSIST) { 360 (void) dladm_destroy_datalink_id(handle, simnet_id, 361 DLADM_OPT_PERSIST); 362 (void) dladm_remove_conf(handle, simnet_id); 363 364 /* Update any attached peer configuration */ 365 if (prevattr.sna_peer_link_id != DATALINK_INVALID_LINKID) 366 status = i_dladm_simnet_update_conf(handle, 367 prevattr.sna_peer_link_id, DATALINK_INVALID_LINKID); 368 } 369 return (status); 370 } 371 372 /* Retrieve simnet information either active or from configuration */ 373 dladm_status_t 374 dladm_simnet_info(dladm_handle_t handle, datalink_id_t simnet_id, 375 dladm_simnet_attr_t *attrp, uint32_t flags) 376 { 377 datalink_class_t class; 378 dladm_status_t status; 379 380 if ((dladm_datalink_id2info(handle, simnet_id, NULL, &class, 381 NULL, NULL, 0) != DLADM_STATUS_OK)) 382 return (DLADM_STATUS_BADARG); 383 384 if (class != DATALINK_CLASS_SIMNET) 385 return (DLADM_STATUS_BADARG); 386 387 bzero(attrp, sizeof (attrp)); 388 attrp->sna_link_id = simnet_id; 389 390 if (flags & DLADM_OPT_ACTIVE) { 391 status = i_dladm_get_simnet_info(handle, attrp); 392 /* 393 * If no active simnet found then return any simnet 394 * from stored config if requested. 395 */ 396 if (status == DLADM_STATUS_NOTFOUND && 397 (flags & DLADM_OPT_PERSIST)) 398 return (i_dladm_get_simnet_info_persist(handle, attrp)); 399 return (status); 400 } else if (flags & DLADM_OPT_PERSIST) { 401 return (i_dladm_get_simnet_info_persist(handle, attrp)); 402 } else { 403 return (DLADM_STATUS_BADARG); 404 } 405 } 406 407 /* Bring up simnet from stored configuration */ 408 static int 409 i_dladm_simnet_up(dladm_handle_t handle, datalink_id_t simnet_id, void *arg) 410 { 411 dladm_status_t *statusp = arg; 412 dladm_status_t status; 413 dladm_simnet_attr_t attr; 414 dladm_simnet_attr_t peer_attr; 415 416 bzero(&attr, sizeof (attr)); 417 attr.sna_link_id = simnet_id; 418 status = dladm_simnet_info(handle, simnet_id, &attr, 419 DLADM_OPT_PERSIST); 420 if (status != DLADM_STATUS_OK) 421 goto done; 422 423 status = i_dladm_create_simnet(handle, &attr); 424 if (status != DLADM_STATUS_OK) 425 goto done; 426 427 /* 428 * When bringing up check if the peer link is available, if it 429 * is then modify the simnet and attach the peer link. 430 */ 431 if ((attr.sna_peer_link_id != DATALINK_INVALID_LINKID) && 432 (dladm_simnet_info(handle, attr.sna_peer_link_id, &peer_attr, 433 DLADM_OPT_ACTIVE) == DLADM_STATUS_OK)) { 434 status = i_dladm_modify_simnet(handle, &attr); 435 if (status != DLADM_STATUS_OK) 436 goto done; 437 } 438 439 if ((status = dladm_up_datalink_id(handle, simnet_id)) != 440 DLADM_STATUS_OK) { 441 (void) dladm_simnet_delete(handle, simnet_id, 442 DLADM_OPT_PERSIST); 443 goto done; 444 } 445 done: 446 *statusp = status; 447 return (DLADM_WALK_CONTINUE); 448 } 449 450 /* Bring up simnet instance(s) from configuration */ 451 /* ARGSUSED */ 452 dladm_status_t 453 dladm_simnet_up(dladm_handle_t handle, datalink_id_t simnet_id, 454 uint32_t flags) 455 { 456 dladm_status_t status; 457 458 if (simnet_id == DATALINK_ALL_LINKID) { 459 (void) dladm_walk_datalink_id(i_dladm_simnet_up, handle, 460 &status, DATALINK_CLASS_SIMNET, DATALINK_ANY_MEDIATYPE, 461 DLADM_OPT_PERSIST); 462 return (DLADM_STATUS_OK); 463 } else { 464 (void) i_dladm_simnet_up(handle, simnet_id, &status); 465 return (status); 466 } 467 } 468 469 /* Store simnet configuration */ 470 static dladm_status_t 471 dladm_simnet_persist_conf(dladm_handle_t handle, const char *name, 472 dladm_simnet_attr_t *attrp) 473 { 474 dladm_conf_t conf = DLADM_INVALID_CONF; 475 dladm_status_t status; 476 char mstr[ETHERADDRL * 3]; 477 uint64_t u64; 478 479 if ((status = dladm_create_conf(handle, name, attrp->sna_link_id, 480 DATALINK_CLASS_SIMNET, attrp->sna_type, &conf)) != DLADM_STATUS_OK) 481 return (status); 482 483 status = dladm_set_conf_field(handle, conf, FMACADDR, 484 DLADM_TYPE_STR, dladm_aggr_macaddr2str(attrp->sna_mac_addr, mstr)); 485 if (status != DLADM_STATUS_OK) 486 goto done; 487 488 u64 = attrp->sna_type; 489 status = dladm_set_conf_field(handle, conf, FSIMNETTYPE, 490 DLADM_TYPE_UINT64, &u64); 491 if (status != DLADM_STATUS_OK) 492 goto done; 493 494 u64 = attrp->sna_mac_len; 495 status = dladm_set_conf_field(handle, conf, FMADDRLEN, 496 DLADM_TYPE_UINT64, &u64); 497 if (status != DLADM_STATUS_OK) 498 goto done; 499 500 status = dladm_write_conf(handle, conf); 501 done: 502 dladm_destroy_conf(handle, conf); 503 return (status); 504 } 505