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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdio.h> 30 #include <sys/types.h> 31 #include <string.h> 32 #include <fcntl.h> 33 #include <unistd.h> 34 #include <stropts.h> 35 #include <stdlib.h> 36 #include <errno.h> 37 #include <libdevinfo.h> 38 #include <libdlpi.h> 39 #include <libdladm.h> 40 #include <sys/dld.h> 41 #include <net/if.h> 42 43 typedef struct dladm_dev { 44 char dd_name[IFNAMSIZ]; 45 struct dladm_dev *dd_next; 46 } dladm_dev_t; 47 48 typedef struct dladm_walk { 49 dladm_dev_t *dw_dev_list; 50 } dladm_walk_t; 51 52 /* 53 * Issue an ioctl to the specified file descriptor attached to the 54 * DLD control driver interface. 55 */ 56 static int 57 i_dladm_ioctl(int fd, int ic_cmd, void *ic_dp, int ic_len) 58 { 59 struct strioctl iocb; 60 61 iocb.ic_cmd = ic_cmd; 62 iocb.ic_timout = 0; 63 iocb.ic_len = ic_len; 64 iocb.ic_dp = (char *)ic_dp; 65 66 return (ioctl(fd, I_STR, &iocb)); 67 } 68 69 /* 70 * Return the attributes of the specified datalink from the DLD driver. 71 */ 72 static int 73 i_dladm_info(int fd, const char *name, dladm_attr_t *dap) 74 { 75 dld_ioc_attr_t dia; 76 77 if (strlen(name) >= IFNAMSIZ) { 78 errno = EINVAL; 79 return (-1); 80 } 81 82 (void) strlcpy(dia.dia_name, name, IFNAMSIZ); 83 84 if (i_dladm_ioctl(fd, DLDIOCATTR, &dia, sizeof (dia)) < 0) 85 return (-1); 86 87 (void) strlcpy(dap->da_dev, dia.dia_dev, MAXNAMELEN); 88 dap->da_max_sdu = dia.dia_max_sdu; 89 dap->da_port = dia.dia_port; 90 dap->da_vid = dia.dia_vid; 91 92 return (0); 93 } 94 95 /* 96 * Adds a datalink to the array corresponding to arg. 97 */ 98 static void 99 i_dladm_nt_net_add(void *arg, char *name) 100 { 101 dladm_walk_t *dwp = arg; 102 dladm_dev_t *ddp = dwp->dw_dev_list; 103 dladm_dev_t **lastp = &dwp->dw_dev_list; 104 105 while (ddp) { 106 /* 107 * Skip duplicates. 108 */ 109 if (strcmp(ddp->dd_name, name) == 0) 110 return; 111 112 lastp = &ddp->dd_next; 113 ddp = ddp->dd_next; 114 } 115 116 if ((ddp = malloc(sizeof (*ddp))) == NULL) 117 return; 118 119 (void) strlcpy(ddp->dd_name, name, IFNAMSIZ); 120 ddp->dd_next = NULL; 121 *lastp = ddp; 122 } 123 124 /* 125 * Walker callback invoked for each DDI_NT_NET node. 126 */ 127 static int 128 i_dladm_nt_net_walk(di_node_t node, di_minor_t minor, void *arg) 129 { 130 dl_info_ack_t dlia; 131 char name[IFNAMSIZ]; 132 int fd; 133 char *provider; 134 uint_t ppa; 135 136 provider = di_minor_name(minor); 137 138 if ((fd = dlpi_open(provider)) < 0) 139 return (DI_WALK_CONTINUE); 140 141 if (dlpi_info(fd, -1, &dlia, NULL, NULL, NULL, NULL, NULL, NULL) < 0) { 142 (void) dlpi_close(fd); 143 return (DI_WALK_CONTINUE); 144 } 145 146 if (dlia.dl_provider_style == DL_STYLE1) { 147 i_dladm_nt_net_add(arg, provider); 148 (void) dlpi_close(fd); 149 return (DI_WALK_CONTINUE); 150 } 151 152 ppa = di_instance(node); 153 154 if (dlpi_attach(fd, -1, ppa) < 0) { 155 (void) dlpi_close(fd); 156 return (DI_WALK_CONTINUE); 157 } 158 (void) snprintf(name, IFNAMSIZ - 1, "%s%d", provider, ppa); 159 i_dladm_nt_net_add(arg, name); 160 (void) dlpi_close(fd); 161 return (DI_WALK_CONTINUE); 162 } 163 164 /* 165 * Invoke the specified callback function for each active DDI_NT_NET 166 * node. 167 */ 168 int 169 dladm_walk(void (*fn)(void *, const char *), void *arg) 170 { 171 di_node_t root; 172 dladm_walk_t dw; 173 dladm_dev_t *ddp, *last_ddp; 174 175 if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) { 176 errno = EFAULT; 177 return (-1); 178 } 179 dw.dw_dev_list = NULL; 180 181 (void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, &dw, 182 i_dladm_nt_net_walk); 183 184 di_fini(root); 185 186 ddp = dw.dw_dev_list; 187 while (ddp) { 188 fn(arg, ddp->dd_name); 189 (void) dladm_walk_vlan(fn, arg, ddp->dd_name); 190 last_ddp = ddp; 191 ddp = ddp->dd_next; 192 free(last_ddp); 193 } 194 195 return (0); 196 } 197 198 /* 199 * Invoke the specified callback function for each vlan managed by dld 200 */ 201 int 202 dladm_walk_vlan(void (*fn)(void *, const char *), void *arg, const char *name) 203 { 204 int fd, bufsize, i; 205 int nvlan = 4094; 206 dld_ioc_vlan_t *iocp = NULL; 207 dld_vlan_info_t *dvip; 208 209 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 210 return (-1); 211 212 bufsize = sizeof (dld_ioc_vlan_t) + nvlan * sizeof (dld_vlan_info_t); 213 214 if ((iocp = (dld_ioc_vlan_t *)calloc(1, bufsize)) == NULL) 215 return (-1); 216 217 if (strncmp(name, "aggr", 4) == 0) { 218 (void) strlcpy((char *)iocp->div_name, "aggr0", IFNAMSIZ); 219 iocp->div_port = atoi(strpbrk(name, "0123456789")); 220 } else { 221 (void) strlcpy((char *)iocp->div_name, name, IFNAMSIZ); 222 iocp->div_port = 0; 223 } 224 if (i_dladm_ioctl(fd, DLDIOCVLAN, iocp, bufsize) == 0) { 225 dvip = (dld_vlan_info_t *)(iocp + 1); 226 for (i = 0; i < iocp->div_count; i++) 227 (*fn)(arg, dvip[i].dvi_name); 228 } 229 /* 230 * Note: Callers of dladm_walk_vlan() ignore the return 231 * value of this routine. So ignoring ioctl failure case 232 * and just returning 0. 233 */ 234 free(iocp); 235 (void) close(fd); 236 return (0); 237 } 238 239 240 /* 241 * Returns the current attributes of the specified datalink. 242 */ 243 int 244 dladm_info(const char *name, dladm_attr_t *dap) 245 { 246 int fd; 247 248 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 249 return (-1); 250 251 if (i_dladm_info(fd, name, dap) < 0) 252 goto failed; 253 254 (void) close(fd); 255 return (0); 256 257 failed: 258 (void) close(fd); 259 return (-1); 260 } 261