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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * DL_IB MAC Type plugin for the Nemo mac module 28 */ 29 30 #include <sys/types.h> 31 #include <sys/modctl.h> 32 #include <sys/dlpi.h> 33 #include <sys/ib/clients/ibd/ibd.h> 34 #include <sys/mac.h> 35 #include <sys/mac_ib.h> 36 #include <sys/dls.h> 37 #include <sys/byteorder.h> 38 #include <sys/strsun.h> 39 #include <inet/common.h> 40 #include <sys/note.h> 41 42 static uint8_t ib_brdcst[] = { 0x00, 0xff, 0xff, 0xff, 43 0xff, 0x10, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00, 44 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff }; 45 46 static struct modlmisc mac_ib_modlmisc = { 47 &mod_miscops, 48 "Infiniband MAC Type plugin 1.0" 49 }; 50 51 static struct modlinkage mac_ib_modlinkage = { 52 MODREV_1, 53 { &mac_ib_modlmisc, 54 NULL } 55 }; 56 57 static mactype_ops_t mac_ib_type_ops; 58 59 int 60 _init(void) 61 { 62 mactype_register_t *mtrp; 63 int err; 64 65 if ((mtrp = mactype_alloc(MACTYPE_VERSION)) == NULL) 66 return (ENOTSUP); 67 mtrp->mtr_ident = MAC_PLUGIN_IDENT_IB; 68 mtrp->mtr_ops = &mac_ib_type_ops; 69 mtrp->mtr_mactype = DL_IB; 70 mtrp->mtr_nativetype = DL_IB; 71 mtrp->mtr_addrlen = IPOIB_ADDRL; 72 mtrp->mtr_brdcst_addr = ib_brdcst; 73 74 /* 75 * So far, generic stats maintained by GLDv3 are sufficient for IB. 76 */ 77 mtrp->mtr_stats = NULL; 78 mtrp->mtr_statcount = 0; 79 if ((err = mactype_register(mtrp)) == 0) { 80 if ((err = mod_install(&mac_ib_modlinkage)) != 0) 81 (void) mactype_unregister(MAC_PLUGIN_IDENT_IB); 82 } 83 mactype_free(mtrp); 84 return (err); 85 } 86 87 int 88 _fini(void) 89 { 90 int err; 91 92 if ((err = mactype_unregister(MAC_PLUGIN_IDENT_IB)) != 0) 93 return (err); 94 return (mod_remove(&mac_ib_modlinkage)); 95 } 96 97 int 98 _info(struct modinfo *modinfop) 99 { 100 return (mod_info(&mac_ib_modlinkage, modinfop)); 101 } 102 103 /* 104 * MAC Type plugin operations 105 */ 106 107 /* ARGSUSED */ 108 int 109 mac_ib_unicst_verify(const void *addr, void *mac_pdata) 110 { 111 ipoib_mac_t *ibaddr = (ipoib_mac_t *)addr; 112 113 /* 114 * The address must not be a multicast address. 115 */ 116 return (ntohl(ibaddr->ipoib_qpn) == IB_MC_QPN ? EINVAL : 0); 117 } 118 119 int 120 mac_ib_multicst_verify(const void *addr, void *mac_pdata) 121 { 122 ipoib_mac_t *ibaddr = (ipoib_mac_t *)addr; 123 uint8_t *p_gid = (uint8_t *)addr + sizeof (ipoib_mac_t) 124 - MAC_IB_GID_SIZE; 125 uint32_t bcst_gid[3] = { 0x0, 0x0, MAC_IB_BROADCAST_GID }; 126 127 _NOTE(ARGUNUSED(mac_pdata)); 128 129 /* 130 * The address must be a multicast address. 131 */ 132 if ((ntohl(ibaddr->ipoib_qpn) & IB_QPN_MASK) != IB_MC_QPN) 133 return (EINVAL); 134 135 /* 136 * The address must not be the broadcast address. 137 */ 138 if (bcmp(p_gid, (uint8_t *)bcst_gid + sizeof (bcst_gid) - 139 MAC_IB_GID_SIZE, MAC_IB_GID_SIZE) == 0) 140 return (EINVAL); 141 142 return (0); 143 } 144 145 /* 146 * Check the legality of a SAP value. The following values are 147 * allowed, as specified by PSARC 2003/150: 148 * 149 * min-ethertype-sap (256).. EtherType max(65535) ethertype semantics 150 * (0) .. max-802-sap(255) IEEE 802 semantics 151 */ 152 boolean_t 153 mac_ib_sap_verify(uint32_t sap, uint32_t *bind_sap, void *mac_pdata) 154 { 155 _NOTE(ARGUNUSED(mac_pdata)); 156 157 if (sap > MAC_IB_MAX_802_SAP && sap <= MAC_IB_ETHERTYPE_MAX) { 158 if (bind_sap != NULL) 159 *bind_sap = sap; 160 return (B_TRUE); 161 } 162 163 if (sap <= MAC_IB_MAX_802_SAP) { 164 if (bind_sap != NULL) 165 *bind_sap = DLS_SAP_LLC; 166 return (B_TRUE); 167 } 168 169 return (B_FALSE); 170 } 171 172 /* ARGSUSED */ 173 mblk_t * 174 mac_ib_header(const void *saddr, const void *daddr, uint32_t sap, 175 void *mac_pdata, mblk_t *payload, size_t extra_len) 176 { 177 ib_header_info_t *ibhp; 178 mblk_t *mp; 179 180 if (!mac_ib_sap_verify(sap, NULL, NULL)) 181 return (NULL); 182 183 mp = allocb(sizeof (ib_header_info_t) + extra_len, BPRI_HI); 184 if (mp == NULL) 185 return (NULL); 186 187 ibhp = (void *)mp->b_rptr; 188 ibhp->ipib_rhdr.ipoib_type = htons(sap); 189 ibhp->ipib_rhdr.ipoib_mbz = 0; 190 bcopy(daddr, &ibhp->ib_dst, IPOIB_ADDRL); 191 mp->b_wptr += sizeof (ib_header_info_t); 192 return (mp); 193 } 194 195 int 196 mac_ib_header_info(mblk_t *mp, void *mac_pdata, mac_header_info_t *hdr_info) 197 { 198 ib_header_info_t *ibhp; 199 uint16_t sap; 200 201 if (MBLKL(mp) < sizeof (ib_header_info_t)) 202 return (EINVAL); 203 204 ibhp = (void *)mp->b_rptr; 205 206 hdr_info->mhi_hdrsize = sizeof (ib_header_info_t); 207 hdr_info->mhi_daddr = (const uint8_t *)&(ibhp->ib_dst); 208 if (ibhp->ib_grh.ipoib_vertcflow != 0) 209 hdr_info->mhi_saddr = (const uint8_t *)&(ibhp->ib_src); 210 else 211 hdr_info->mhi_saddr = NULL; 212 213 if (mac_ib_unicst_verify(hdr_info->mhi_daddr, mac_pdata) == 0) { 214 hdr_info->mhi_dsttype = MAC_ADDRTYPE_UNICAST; 215 } else if (mac_ib_multicst_verify(hdr_info->mhi_daddr, 216 mac_pdata) == 0) { 217 hdr_info->mhi_dsttype = MAC_ADDRTYPE_MULTICAST; 218 } else { 219 hdr_info->mhi_dsttype = MAC_ADDRTYPE_BROADCAST; 220 } 221 222 sap = ntohs(ibhp->ipib_rhdr.ipoib_type); 223 hdr_info->mhi_origsap = hdr_info->mhi_bindsap = sap; 224 hdr_info->mhi_pktsize = 0; 225 226 return (0); 227 } 228 229 /* 230 * Take the provided `mp' (which is expected to have a header "dst + type"), 231 * and return a pointer to an mblk_t with a header "GRH + type". 232 * If the conversion cannot be performed, return NULL. 233 */ 234 static mblk_t * 235 mac_ib_header_cook(mblk_t *mp, void *pdata) 236 { 237 ipoib_ptxhdr_t *orig_hp; 238 mblk_t *llmp; 239 240 if (MBLKL(mp) < sizeof (ipoib_ptxhdr_t)) 241 return (NULL); 242 243 orig_hp = (void *)mp->b_rptr; 244 llmp = mac_ib_header(NULL, &orig_hp->ipoib_dest, 245 ntohs(orig_hp->ipoib_rhdr.ipoib_type), pdata, NULL, 0); 246 if (llmp == NULL) 247 return (NULL); 248 249 /* 250 * The plugin framework guarantees that we have the only reference 251 * to the mblk_t, so we can safely modify it. 252 */ 253 ASSERT(DB_REF(mp) == 1); 254 mp->b_rptr += sizeof (ipoib_ptxhdr_t); 255 llmp->b_cont = mp; 256 return (llmp); 257 } 258 259 /* 260 * Take the provided `mp' (which is expected to have a header "GRH + type"), 261 * and return a pointer to an mblk_t with a header "type". If the conversion 262 * cannot be performed, return NULL. 263 */ 264 static mblk_t * 265 mac_ib_header_uncook(mblk_t *mp, void *pdata) 266 { 267 _NOTE(ARGUNUSED(pdata)); 268 269 /* 270 * The plugin framework guarantees that we have the only reference to 271 * the mblk_t and the underlying dblk_t, so we can safely modify it. 272 */ 273 ASSERT(DB_REF(mp) == 1); 274 275 mp->b_rptr += sizeof (ib_addrs_t); 276 return (mp); 277 } 278 279 void 280 mac_ib_link_details(char *buf, size_t sz, mac_handle_t mh, void *mac_pdata) 281 { 282 uint64_t speed; 283 284 _NOTE(ARGUNUSED(mac_pdata)); 285 286 speed = mac_stat_get(mh, MAC_STAT_IFSPEED); 287 288 /* convert to Mbps */ 289 speed /= 1000000; 290 291 buf[0] = 0; 292 (void) snprintf(buf, sz, "%u Mbps", (uint32_t)speed); 293 } 294 295 static mactype_ops_t mac_ib_type_ops = { 296 MTOPS_HEADER_COOK | MTOPS_HEADER_UNCOOK | MTOPS_LINK_DETAILS, 297 mac_ib_unicst_verify, 298 mac_ib_multicst_verify, 299 mac_ib_sap_verify, 300 mac_ib_header, 301 mac_ib_header_info, 302 NULL, 303 mac_ib_header_cook, 304 mac_ib_header_uncook, 305 mac_ib_link_details 306 };