1/* 2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * The contents of this file constitute Original Code as defined in and 7 * are subject to the Apple Public Source License Version 1.1 (the 8 * "License"). You may not use this file except in compliance with the 9 * License. Please obtain a copy of the License at 10 * http://www.apple.com/publicsource and read it before using this file. 11 * 12 * This Original Code and all software distributed under the License are 13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 17 * License for the specific language governing rights and limitations 18 * under the License. 19 * 20 * @APPLE_LICENSE_HEADER_END@ 21 */ 22 23/* 24 * ifbond.c 25 * - add and remove interfaces from a bond interface 26 */ 27 28/* 29 * Modification History: 30 * 31 * July 14, 2004 Dieter Siegmund (dieter@apple.com) 32 * - created 33 */ 34 35#include <sys/param.h> 36#include <sys/ioctl.h> 37#include <sys/socket.h> 38 39#include <stdlib.h> 40#include <unistd.h> 41 42#include <net/ethernet.h> 43#include <net/if.h> 44#include <net/if_var.h> 45#include <net/if_bond_var.h> 46 47#include <net/route.h> 48 49#include <ctype.h> 50#include <stdio.h> 51#include <string.h> 52#include <stdlib.h> 53#include <unistd.h> 54#include <err.h> 55#include <errno.h> 56 57#include "ifconfig.h" 58extern int bond_details; 59 60#define EA_FORMAT "%02x:%02x:%02x:%02x:%02x:%02x" 61#define EA_CH(e, i) ((u_char)((u_char *)(e))[(i)]) 62#define EA_LIST(ea) EA_CH(ea,0),EA_CH(ea,1),EA_CH(ea,2),EA_CH(ea,3),EA_CH(ea,4),EA_CH(ea,5) 63 64static __inline__ const char * 65selected_state_string(u_char s) 66{ 67 static const char * names[] = { "unselected", "selected", "standby" }; 68 69 if (s <= IF_BOND_STATUS_SELECTED_STATE_STANDBY) { 70 return (names[s]); 71 } 72 return ("<unknown>"); 73} 74 75static void 76bond_print_details(struct if_bond_status * ibs_p, int count) 77 78{ 79 int i; 80 struct if_bond_status * scan_p = ibs_p; 81 82 for (i = 0; i < count; i++, scan_p++) { 83 struct if_bond_partner_state * ps; 84 ps = &scan_p->ibs_partner_state; 85 printf("\tbond interface: %s priority: 0x%04x " 86 "state: 0x%02x partner system: 0x%04x," 87 EA_FORMAT " " 88 "key: 0x%04x port: 0x%04x priority: 0x%04x " 89 "state: 0x%02x\n", 90 scan_p->ibs_if_name, scan_p->ibs_port_priority, 91 scan_p->ibs_state, ps->ibps_system_priority, 92 EA_LIST(&ps->ibps_system), ps->ibps_key, 93 ps->ibps_port, ps->ibps_port_priority, 94 ps->ibps_state); 95 } 96 return; 97} 98 99void 100bond_status(int s) 101{ 102 int i; 103 struct if_bond_req ibr; 104 struct if_bond_status * ibs_p; 105 struct if_bond_status_req * ibsr_p; 106 char mode_buf[16]; 107 const char * mode_str; 108 109 bzero((char *)&ibr, sizeof(ibr)); 110 ibr.ibr_op = IF_BOND_OP_GET_STATUS; 111 ibsr_p = &ibr.ibr_ibru.ibru_status; 112 ibsr_p->ibsr_version = IF_BOND_STATUS_REQ_VERSION; 113 ifr.ifr_data = (caddr_t)&ibr; 114 115 /* how many of them are there? */ 116 if (ioctl(s, SIOCGIFBOND, (caddr_t)&ifr) < 0) { 117 return; 118 } 119 switch (ibsr_p->ibsr_mode) { 120 case IF_BOND_MODE_LACP: 121 mode_str = "lacp"; 122 break; 123 case IF_BOND_MODE_STATIC: 124 mode_str = "static"; 125 break; 126 default: 127 snprintf(mode_buf, sizeof(mode_buf), "%d", ibsr_p->ibsr_mode); 128 mode_str = mode_buf; 129 break; 130 } 131 if (ibsr_p->ibsr_total == 0) { 132 if (bond_details) { 133 printf("\tbond mode: %s\n" 134 "\tbond key: 0x%04x interfaces: <none>", 135 mode_str, ibsr_p->ibsr_key); 136 } 137 else { 138 printf("\tbond interfaces: <none>\n"); 139 } 140 return; 141 } 142 ibsr_p->ibsr_buffer 143 = (char *)malloc(sizeof(struct if_bond_status) 144 * ibsr_p->ibsr_total); 145 ibsr_p->ibsr_count = ibsr_p->ibsr_total; 146 147 /* get the list */ 148 if (ioctl(s, SIOCGIFBOND, (caddr_t)&ifr) < 0) { 149 goto done; 150 } 151 if (ibsr_p->ibsr_total > 0) { 152 if (bond_details) { 153 printf("\tbond mode: %s\n" 154 "\tbond key: 0x%04x interfaces:", 155 mode_str, ibsr_p->ibsr_key); 156 } 157 else { 158 printf("\tbond interfaces:"); 159 } 160 ibs_p = (struct if_bond_status *)ibsr_p->ibsr_buffer; 161 for (i = 0; i < ibsr_p->ibsr_total; i++, ibs_p++) { 162 printf(" %s", ibs_p->ibs_if_name); 163 if (bond_details) { 164 u_char s = ibs_p->ibs_selected_state; 165 printf(" (%s)", selected_state_string(s)); 166 } 167 } 168 printf("\n"); 169 if (bond_details) { 170 bond_print_details((struct if_bond_status *) 171 ibsr_p->ibsr_buffer, 172 ibsr_p->ibsr_total); 173 } 174 } 175 else if (bond_details) { 176 printf("\tbond mode: %s\n" 177 "\tbond key: 0x%04x interfaces: <none>\n", 178 mode_str, ibsr_p->ibsr_key); 179 } 180 else { 181 printf("\tbond interfaces: <none>\n"); 182 } 183 184 done: 185 free(ibsr_p->ibsr_buffer); 186 return; 187} 188 189static 190DECL_CMD_FUNC(setbonddev, val, d) 191{ 192 struct if_bond_req ibr; 193 194 bzero((char *)&ibr, sizeof(ibr)); 195 if ((unsigned int)snprintf(ibr.ibr_ibru.ibru_if_name, 196 sizeof(ibr.ibr_ibru.ibru_if_name), 197 "%s", val) >= IFNAMSIZ) { 198 errx(1, "interface name too long"); 199 } 200 ibr.ibr_op = IF_BOND_OP_ADD_INTERFACE; 201 ifr.ifr_data = (caddr_t)&ibr; 202 if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1) 203 err(1, "SIOCSIFBOND add interface"); 204 205 return; 206} 207 208static 209DECL_CMD_FUNC(unsetbonddev, val, d) 210{ 211 struct if_bond_req ibr; 212 213 bzero((char *)&ibr, sizeof(ibr)); 214 if ((unsigned int)snprintf(ibr.ibr_ibru.ibru_if_name, 215 sizeof(ibr.ibr_ibru.ibru_if_name), 216 "%s", val) >= IFNAMSIZ) { 217 errx(1, "interface name too long"); 218 } 219 ibr.ibr_op = IF_BOND_OP_REMOVE_INTERFACE; 220 ifr.ifr_data = (caddr_t)&ibr; 221 if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1) 222 err(1, "SIOCSIFBOND remove interface"); 223 224 return; 225} 226 227static 228DECL_CMD_FUNC(setbondmode, val, d) 229{ 230 struct if_bond_req ibr; 231 int mode; 232 233 if (strcmp(val, "lacp") == 0) { 234 mode = IF_BOND_MODE_LACP; 235 } 236 else if (strcmp(val, "static") == 0) { 237 mode = IF_BOND_MODE_STATIC; 238 } 239 else { 240 mode = strtoul(val, NULL, 0); 241 if (errno != 0) { 242 errx(1, "invalid mode value " 243 "(must be either \"lacp\" or \"static\")"); 244 } 245 } 246 247 bzero((char *)&ibr, sizeof(ibr)); 248 if ((unsigned int)snprintf(ibr.ibr_ibru.ibru_if_name, 249 sizeof(ibr.ibr_ibru.ibru_if_name), 250 "%s", val) >= IFNAMSIZ) { 251 errx(1, "interface name too long"); 252 } 253 ibr.ibr_op = IF_BOND_OP_SET_MODE; 254 ibr.ibr_ibru.ibru_int_val = mode; 255 ifr.ifr_data = (caddr_t)&ibr; 256 if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1) 257 err(1, "SIOCSIFBOND set mode"); 258 259 return; 260} 261 262static struct cmd bond_cmds[] = { 263 DEF_CLONE_CMD_ARG("bonddev", setbonddev), 264 DEF_CLONE_CMD_ARG("-bonddev", unsetbonddev), 265 DEF_CMD_ARG("bondmode", setbondmode), 266}; 267static struct afswtch af_bond = { 268 .af_name = "af_bond", 269 .af_af = AF_UNSPEC, 270 .af_other_status = bond_status, 271}; 272 273static __constructor void 274bond_ctor(void) 275{ 276#define N(a) (sizeof(a) / sizeof(a[0])) 277 int i; 278 279 for (i = 0; i < N(bond_cmds); i++) 280 cmd_register(&bond_cmds[i]); 281 af_register(&af_bond); 282#undef N 283} 284 285