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