|
|
1.1 ! root 1: /* ! 2: * Copyright (C) 2010 Michael Brown <[email protected]>. ! 3: * ! 4: * This program is free software; you can redistribute it and/or ! 5: * modify it under the terms of the GNU General Public License as ! 6: * published by the Free Software Foundation; either version 2 of the ! 7: * License, or any later version. ! 8: * ! 9: * This program is distributed in the hope that it will be useful, but ! 10: * WITHOUT ANY WARRANTY; without even the implied warranty of ! 11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 12: * General Public License for more details. ! 13: * ! 14: * You should have received a copy of the GNU General Public License ! 15: * along with this program; if not, write to the Free Software ! 16: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ! 17: */ ! 18: ! 19: FILE_LICENCE ( GPL2_OR_LATER ); ! 20: ! 21: #include <stdlib.h> ! 22: #include <string.h> ! 23: #include <byteswap.h> ! 24: #include <errno.h> ! 25: #include <ipxe/iobuf.h> ! 26: #include <ipxe/netdevice.h> ! 27: #include <ipxe/if_ether.h> ! 28: #include <ipxe/ethernet.h> ! 29: #include <ipxe/eth_slow.h> ! 30: ! 31: /** @file ! 32: * ! 33: * Ethernet slow protocols ! 34: * ! 35: * We implement a very simple passive LACP entity, that pretends that ! 36: * each port is the only port on an individual system. We avoid the ! 37: * need for timeout logic (and retaining local state about our ! 38: * partner) by requesting the same timeout period (1s or 30s) as our ! 39: * partner requests, and then simply responding to every packet the ! 40: * partner sends us. ! 41: */ ! 42: ! 43: struct net_protocol eth_slow_protocol __net_protocol; ! 44: ! 45: /** Slow protocols multicast address */ ! 46: static const uint8_t eth_slow_address[ETH_ALEN] = ! 47: { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x02 }; ! 48: ! 49: /** ! 50: * Name LACP TLV type ! 51: * ! 52: * @v type LACP TLV type ! 53: * @ret name Name of LACP TLV type ! 54: */ ! 55: static inline __attribute__ (( always_inline )) const char * ! 56: eth_slow_lacp_tlv_name ( uint8_t type ) { ! 57: switch ( type ) { ! 58: case ETH_SLOW_TLV_TERMINATOR: return "terminator"; ! 59: case ETH_SLOW_TLV_LACP_ACTOR: return "actor"; ! 60: case ETH_SLOW_TLV_LACP_PARTNER: return "partner"; ! 61: case ETH_SLOW_TLV_LACP_COLLECTOR: return "collector"; ! 62: default: return "<invalid>"; ! 63: } ! 64: } ! 65: ! 66: /** ! 67: * Name marker TLV type ! 68: * ! 69: * @v type Marker TLV type ! 70: * @ret name Name of marker TLV type ! 71: */ ! 72: static inline __attribute__ (( always_inline )) const char * ! 73: eth_slow_marker_tlv_name ( uint8_t type ) { ! 74: switch ( type ) { ! 75: case ETH_SLOW_TLV_TERMINATOR: return "terminator"; ! 76: case ETH_SLOW_TLV_MARKER_REQUEST: return "request"; ! 77: case ETH_SLOW_TLV_MARKER_RESPONSE: return "response"; ! 78: default: return "<invalid>"; ! 79: } ! 80: } ! 81: ! 82: /** ! 83: * Name LACP state ! 84: * ! 85: * @v state LACP state ! 86: * @ret name LACP state name ! 87: */ ! 88: static const char * eth_slow_lacp_state_name ( uint8_t state ) { ! 89: static char state_chars[] = "AFGSRTLX"; ! 90: unsigned int i; ! 91: ! 92: for ( i = 0 ; i < 8 ; i++ ) { ! 93: state_chars[i] |= 0x20; ! 94: if ( state & ( 1 << i ) ) ! 95: state_chars[i] &= ~0x20; ! 96: } ! 97: return state_chars; ! 98: } ! 99: ! 100: /** ! 101: * Dump LACP packet ! 102: * ! 103: * @v iobuf I/O buffer ! 104: * @v netdev Network device ! 105: * @v label "RX" or "TX" ! 106: */ ! 107: static void eth_slow_lacp_dump ( struct io_buffer *iobuf, ! 108: struct net_device *netdev, ! 109: const char *label ) { ! 110: union eth_slow_packet *eth_slow = iobuf->data; ! 111: struct eth_slow_lacp *lacp = ð_slow->lacp; ! 112: ! 113: DBGC ( netdev, ! 114: "SLOW %s %s LACP actor (%04x,%s,%04x,%02x,%04x) [%s]\n", ! 115: netdev->name, label, ntohs ( lacp->actor.system_priority ), ! 116: eth_ntoa ( lacp->actor.system ), ! 117: ntohs ( lacp->actor.key ), ! 118: ntohs ( lacp->actor.port_priority ), ! 119: ntohs ( lacp->actor.port ), ! 120: eth_slow_lacp_state_name ( lacp->actor.state ) ); ! 121: DBGC ( netdev, ! 122: "SLOW %s %s LACP partner (%04x,%s,%04x,%02x,%04x) [%s]\n", ! 123: netdev->name, label, ntohs ( lacp->partner.system_priority ), ! 124: eth_ntoa ( lacp->partner.system ), ! 125: ntohs ( lacp->partner.key ), ! 126: ntohs ( lacp->partner.port_priority ), ! 127: ntohs ( lacp->partner.port ), ! 128: eth_slow_lacp_state_name ( lacp->partner.state ) ); ! 129: DBGC ( netdev, "SLOW %s %s LACP collector %04x (%d us)\n", ! 130: netdev->name, label, ntohs ( lacp->collector.max_delay ), ! 131: ( ntohs ( lacp->collector.max_delay ) * 10 ) ); ! 132: DBGC2_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) ); ! 133: } ! 134: ! 135: /** ! 136: * Process incoming LACP packet ! 137: * ! 138: * @v iobuf I/O buffer ! 139: * @v netdev Network device ! 140: * @ret rc Return status code ! 141: */ ! 142: static int eth_slow_lacp_rx ( struct io_buffer *iobuf, ! 143: struct net_device *netdev ) { ! 144: union eth_slow_packet *eth_slow = iobuf->data; ! 145: struct eth_slow_lacp *lacp = ð_slow->lacp; ! 146: ! 147: eth_slow_lacp_dump ( iobuf, netdev, "RX" ); ! 148: ! 149: /* Build response */ ! 150: memset ( lacp->reserved, 0, sizeof ( lacp->reserved ) ); ! 151: memset ( &lacp->terminator, 0, sizeof ( lacp->terminator ) ); ! 152: memset ( &lacp->collector, 0, sizeof ( lacp->collector ) ); ! 153: lacp->collector.tlv.type = ETH_SLOW_TLV_LACP_COLLECTOR; ! 154: lacp->collector.tlv.length = ETH_SLOW_TLV_LACP_COLLECTOR_LEN; ! 155: memcpy ( &lacp->partner, &lacp->actor, sizeof ( lacp->partner ) ); ! 156: lacp->partner.tlv.type = ETH_SLOW_TLV_LACP_PARTNER; ! 157: lacp->partner.tlv.length = ETH_SLOW_TLV_LACP_PARTNER_LEN; ! 158: memset ( &lacp->partner.reserved, 0, ! 159: sizeof ( lacp->partner.reserved ) ); ! 160: memset ( &lacp->actor, 0, sizeof ( lacp->actor ) ); ! 161: lacp->actor.tlv.type = ETH_SLOW_TLV_LACP_ACTOR; ! 162: lacp->actor.tlv.length = ETH_SLOW_TLV_LACP_ACTOR_LEN; ! 163: lacp->actor.system_priority = htons ( LACP_SYSTEM_PRIORITY_MAX ); ! 164: memcpy ( lacp->actor.system, netdev->ll_addr, ! 165: sizeof ( lacp->actor.system ) ); ! 166: lacp->actor.key = htons ( 1 ); ! 167: lacp->actor.port_priority = htons ( LACP_PORT_PRIORITY_MAX ); ! 168: lacp->actor.port = htons ( 1 ); ! 169: lacp->actor.state = ( LACP_STATE_IN_SYNC | ! 170: LACP_STATE_COLLECTING | ! 171: LACP_STATE_DISTRIBUTING | ! 172: ( lacp->partner.state & LACP_STATE_FAST ) ); ! 173: lacp->header.version = ETH_SLOW_LACP_VERSION; ! 174: ! 175: /* Send response */ ! 176: eth_slow_lacp_dump ( iobuf, netdev, "TX" ); ! 177: return net_tx ( iobuf, netdev, ð_slow_protocol, eth_slow_address, ! 178: netdev->ll_addr ); ! 179: } ! 180: ! 181: /** ! 182: * Dump marker packet ! 183: * ! 184: * @v iobuf I/O buffer ! 185: * @v netdev Network device ! 186: * @v label "RX" or "TX" ! 187: */ ! 188: static void eth_slow_marker_dump ( struct io_buffer *iobuf, ! 189: struct net_device *netdev, ! 190: const char *label ) { ! 191: union eth_slow_packet *eth_slow = iobuf->data; ! 192: struct eth_slow_marker *marker = ð_slow->marker; ! 193: ! 194: DBGC ( netdev, "SLOW %s %s marker %s port %04x system %s xact %08x\n", ! 195: netdev->name, label, ! 196: eth_slow_marker_tlv_name ( marker->marker.tlv.type ), ! 197: ntohs ( marker->marker.port ), ! 198: eth_ntoa ( marker->marker.system ), ! 199: ntohl ( marker->marker.xact ) ); ! 200: DBGC2_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) ); ! 201: } ! 202: ! 203: /** ! 204: * Process incoming marker packet ! 205: * ! 206: * @v iobuf I/O buffer ! 207: * @v netdev Network device ! 208: * @ret rc Return status code ! 209: */ ! 210: static int eth_slow_marker_rx ( struct io_buffer *iobuf, ! 211: struct net_device *netdev ) { ! 212: union eth_slow_packet *eth_slow = iobuf->data; ! 213: struct eth_slow_marker *marker = ð_slow->marker; ! 214: ! 215: eth_slow_marker_dump ( iobuf, netdev, "RX" ); ! 216: ! 217: if ( marker->marker.tlv.type == ETH_SLOW_TLV_MARKER_REQUEST ) { ! 218: /* Send marker response */ ! 219: marker->marker.tlv.type = ETH_SLOW_TLV_MARKER_RESPONSE; ! 220: eth_slow_marker_dump ( iobuf, netdev, "TX" ); ! 221: return net_tx ( iobuf, netdev, ð_slow_protocol, ! 222: eth_slow_address, netdev->ll_addr ); ! 223: } else { ! 224: /* Discard all other marker packets */ ! 225: free_iob ( iobuf ); ! 226: return -EINVAL; ! 227: } ! 228: } ! 229: ! 230: /** ! 231: * Process incoming slow packet ! 232: * ! 233: * @v iobuf I/O buffer ! 234: * @v netdev Network device ! 235: * @v ll_dest Link-layer destination address ! 236: * @v ll_source Link-layer source address ! 237: * @ret rc Return status code ! 238: */ ! 239: static int eth_slow_rx ( struct io_buffer *iobuf, ! 240: struct net_device *netdev, ! 241: const void *ll_dest __unused, ! 242: const void *ll_source __unused ) { ! 243: union eth_slow_packet *eth_slow = iobuf->data; ! 244: ! 245: /* Sanity checks */ ! 246: if ( iob_len ( iobuf ) < sizeof ( *eth_slow ) ) { ! 247: free_iob ( iobuf ); ! 248: return -EINVAL; ! 249: } ! 250: ! 251: /* Handle according to subtype */ ! 252: switch ( eth_slow->header.subtype ) { ! 253: case ETH_SLOW_SUBTYPE_LACP: ! 254: return eth_slow_lacp_rx ( iobuf, netdev ); ! 255: case ETH_SLOW_SUBTYPE_MARKER: ! 256: return eth_slow_marker_rx ( iobuf, netdev ); ! 257: default: ! 258: DBGC ( netdev, "SLOW %s RX unknown subtype %02x\n", ! 259: netdev->name, eth_slow->header.subtype ); ! 260: free_iob ( iobuf ); ! 261: return -EINVAL; ! 262: } ! 263: } ! 264: ! 265: /** Slow protocol */ ! 266: struct net_protocol eth_slow_protocol __net_protocol = { ! 267: .name = "Slow", ! 268: .net_proto = htons ( ETH_P_SLOW ), ! 269: .rx = eth_slow_rx, ! 270: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.