summaryrefslogtreecommitdiffstats
path: root/contrib/syslinux-4.02/gpxe/src/core/proto_eth_slow.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/syslinux-4.02/gpxe/src/core/proto_eth_slow.c')
-rw-r--r--contrib/syslinux-4.02/gpxe/src/core/proto_eth_slow.c406
1 files changed, 406 insertions, 0 deletions
diff --git a/contrib/syslinux-4.02/gpxe/src/core/proto_eth_slow.c b/contrib/syslinux-4.02/gpxe/src/core/proto_eth_slow.c
new file mode 100644
index 0000000..b759a71
--- /dev/null
+++ b/contrib/syslinux-4.02/gpxe/src/core/proto_eth_slow.c
@@ -0,0 +1,406 @@
+/* Copyright 2004 Linux Networx */
+#ifdef PROTO_LACP
+#if 0
+#include "nic.h"
+#include "timer.h"
+#endif
+
+#define LACP_DEBUG 0
+
+/* Structure definitions originally taken from the linux bond_3ad driver */
+
+#define SLOW_DST_MAC "\x01\x80\xc2\x00\x00\x02"
+static const char slow_dest[] = SLOW_DST_MAC;
+
+
+#define SLOW_SUBTYPE_LACP 1
+#define SLOW_SUBTYPE_MARKER 2
+
+struct slow_header {
+ uint8_t subtype;
+};
+
+struct lacp_info {
+ uint16_t system_priority;
+ uint8_t system[ETH_ALEN];
+ uint16_t key;
+ uint16_t port_priority;
+ uint16_t port;
+ uint8_t state;
+ uint8_t reserved[3];
+} PACKED;
+
+#define LACP_CMP_LEN (2 + 6 + 2 + 2 + 2)
+#define LACP_CP_LEN (2 + 6 + 2 + 2 + 2 + 1)
+
+/* Link Aggregation Control Protocol(LACP) data unit structure(43.4.2.2 in the 802.3ad standard) */
+struct slow_lacp {
+ uint8_t subtype; /* = LACP(= 0x01) */
+ uint8_t version_number;
+ uint8_t tlv_type_actor_info; /* = actor information(type/length/value) */
+#define LACP_TLV_TERMINATOR 0
+#define LACP_TLV_ACTOR 1
+#define LACP_TLV_PARTNER 2
+#define LACP_TLV_COLLECTOR 3
+ uint8_t actor_information_length; /* = 20 */
+ struct lacp_info actor;
+ uint8_t tlv_type_partner_info; /* = partner information */
+ uint8_t partner_information_length; /* = 20 */
+ struct lacp_info partner;
+ uint8_t tlv_type_collector_info; /* = collector information */
+ uint8_t collector_information_length; /* = 16 */
+ uint16_t collector_max_delay;
+ uint8_t reserved_12[12];
+ uint8_t tlv_type_terminator; /* = terminator */
+ uint8_t terminator_length; /* = 0 */
+ uint8_t reserved_50[50]; /* = 0 */
+} PACKED;
+
+/* Marker Protocol Data Unit(PDU) structure(43.5.3.2 in the 802.3ad standard) */
+struct slow_marker {
+ uint8_t subtype; /* = 0x02 (marker PDU) */
+ uint8_t version_number; /* = 0x01 */
+ uint8_t tlv_type;
+#define MARKER_TLV_TERMINATOR 0 /* marker terminator */
+#define MARKER_TLV_INFO 1 /* marker information */
+#define MARKER_TLV_RESPONSE 2 /* marker response information */
+ uint8_t marker_length; /* = 0x16 */
+ uint16_t requester_port; /* The number assigned to the port by the requester */
+ uint8_t requester_system[ETH_ALEN]; /* The requester's system id */
+ uint32_t requester_transaction_id; /* The transaction id allocated by the requester, */
+ uint16_t pad; /* = 0 */
+ uint8_t tlv_type_terminator; /* = 0x00 */
+ uint8_t terminator_length; /* = 0x00 */
+ uint8_t reserved_90[90]; /* = 0 */
+} PACKED;
+
+union slow_union {
+ struct slow_header header;
+ struct slow_lacp lacp;
+ struct slow_marker marker;
+};
+
+#define FAST_PERIODIC_TIME (1*TICKS_PER_SEC)
+#define SLOW_PERIODIC_TIME (30*TICKS_PER_SEC)
+#define SHORT_TIMEOUT_TIME (3*FAST_PERIODIC_TIME)
+#define LONG_TIMEOUT_TIME (3*SLOW_PERIODIC_TIME)
+#define CHURN_DETECTION_TIME (60*TICKS_PER_SEC)
+#define AGGREGATE_WAIT_TIME (2*TICKS_PER_SEC)
+
+#define LACP_ACTIVITY (1 << 0)
+#define LACP_TIMEOUT (1 << 1)
+#define LACP_AGGREGATION (1 << 2)
+#define LACP_SYNCHRONIZATION (1 << 3)
+#define LACP_COLLECTING (1 << 4)
+#define LACP_DISTRIBUTING (1 << 5)
+#define LACP_DEFAULTED (1 << 6)
+#define LACP_EXPIRED (1 << 7)
+
+#define UNSELECTED 0
+#define STANDBY 1
+#define SELECTED 2
+
+
+struct lacp_state {
+ struct slow_lacp pkt;
+ unsigned long current_while_timer; /* Time when the LACP information expires */
+ unsigned long periodic_timer; /* Time when I need to send my partner an update */
+};
+
+static struct lacp_state lacp;
+
+
+#if LACP_DEBUG > 0
+static void print_lacp_state(uint8_t state)
+{
+ printf("%hhx", state);
+ if (state & LACP_ACTIVITY) {
+ printf(" Activity");
+ }
+ if (state & LACP_TIMEOUT) {
+ printf(" Timeout");
+ }
+ if (state & LACP_AGGREGATION) {
+ printf(" Aggregation");
+ }
+ if (state & LACP_SYNCHRONIZATION) {
+ printf(" Syncronization");
+ }
+ if (state & LACP_COLLECTING) {
+ printf(" Collecting");
+ }
+ if (state & LACP_DISTRIBUTING) {
+ printf(" Distributing");
+ }
+ if (state & LACP_DEFAULTED) {
+ printf(" Defaulted");
+ }
+ if (state & LACP_EXPIRED) {
+ printf(" Expired");
+ }
+ printf("\n");
+}
+
+static inline void print_lacpdu(struct slow_lacp *pkt)
+{
+ printf("subtype version: %hhx %hhx\n",
+ pkt->subtype, pkt->version_number);
+ printf("actor_tlv %hhx", pkt->tlv_type_actor_info);
+ printf(" len: %hhx (\n", pkt->actor_information_length);
+ printf(" sys_pri: %hx", ntohs(pkt->actor.system_priority));
+ printf(" mac: %!", pkt->actor.system);
+ printf(" key: %hx", ntohs(pkt->actor.key));
+ printf(" port_pri: %hx", ntohs(pkt->actor.port_priority));
+ printf(" port: %hx\n", ntohs(pkt->actor.port));
+ printf(" state: ");
+ print_lacp_state(pkt->actor.state);
+#if LACP_DEBUG > 1
+ printf(" reserved: %hhx %hhx %hhx\n",
+ pkt->actor.reserved[0], pkt->actor.reserved[1], pkt->actor.reserved[2]);
+#endif
+ printf(")\n");
+ printf("partner_tlv: %hhx", pkt->tlv_type_partner_info);
+ printf(" len: %hhx (\n", pkt->partner_information_length);
+ printf(" sys_pri: %hx", ntohs(pkt->partner.system_priority));
+ printf(" mac: %!", pkt->partner.system);
+ printf(" key: %hx", ntohs(pkt->partner.key));
+ printf(" port_pri: %hx", ntohs(pkt->partner.port_priority));
+ printf(" port: %hx\n", ntohs(pkt->partner.port));
+ printf(" state: ");
+ print_lacp_state(pkt->partner.state);
+#if LACP_DEBUG > 1
+ printf(" reserved: %hhx %hhx %hhx\n",
+ pkt->partner.reserved[0], pkt->partner.reserved[1], pkt->partner.reserved[2]);
+#endif
+ printf(")\n");
+ printf("collector_tlv: %hhx ", pkt->tlv_type_collector_info);
+ printf(" len: %hhx (", pkt->collector_information_length);
+ printf(" max_delay: %hx", ntohs(pkt->collector_max_delay));
+#if LACP_DEBUG > 1
+ printf("reserved_12: %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\n",
+ pkt->reserved_12[0], pkt->reserved_12[1], pkt->reserved_12[2],
+ pkt->reserved_12[3], pkt->reserved_12[4], pkt->reserved_12[5],
+ pkt->reserved_12[6], pkt->reserved_12[7], pkt->reserved_12[8],
+ pkt->reserved_12[9], pkt->reserved_12[10], pkt->reserved_12[11]);
+#endif
+ printf(" )\n");
+ printf("terminator_tlv: %hhx", pkt->tlv_type_terminator);
+ printf(" len: %hhx ()\n", pkt->terminator_length);
+}
+
+static inline unsigned long lacp_timer_val(unsigned long now, unsigned long when)
+{
+ return when?(when - now)/TICKS_PER_SEC : 0;
+}
+static void print_lacp(const char *which, struct slow_lacp *pkt, unsigned long now)
+{
+ printf("%s\n", which);
+ print_lacpdu(pkt);
+ printf("timers: c %ds p %ds\n",
+ lacp_timer_val(now, lacp.current_while_timer),
+ lacp_timer_val(now, lacp.periodic_timer)
+ );
+ printf("\n");
+}
+#else /* LACP_DEBUG */
+#define print_lacp(which, pkt, now) do {} while(0)
+#endif /* LACP_DEBUG */
+
+static void lacp_init_state(const uint8_t *mac)
+{
+ memset(&lacp, 0, sizeof(lacp));
+
+ /* Initialize the packet constants */
+ lacp.pkt.subtype = 1;
+ lacp.pkt.version_number = 1;
+
+
+ /* The default state of my interface */
+ lacp.pkt.tlv_type_actor_info = LACP_TLV_ACTOR;
+ lacp.pkt.actor_information_length = 0x14;
+ lacp.pkt.actor.system_priority = htons(1);
+ memcpy(lacp.pkt.actor.system, mac, ETH_ALEN);
+ lacp.pkt.actor.key = htons(1);
+ lacp.pkt.actor.port = htons(1);
+ lacp.pkt.actor.port_priority = htons(1);
+ lacp.pkt.actor.state =
+ LACP_SYNCHRONIZATION |
+ LACP_COLLECTING |
+ LACP_DISTRIBUTING |
+ LACP_DEFAULTED;
+
+ /* Set my partner defaults */
+ lacp.pkt.tlv_type_partner_info = LACP_TLV_PARTNER;
+ lacp.pkt.partner_information_length = 0x14;
+ lacp.pkt.partner.system_priority = htons(1);
+ /* memset(lacp.pkt.parnter_system, 0, ETH_ALEN); */
+ lacp.pkt.partner.key = htons(1);
+ lacp.pkt.partner.port = htons(1);
+ lacp.pkt.partner.port_priority = htons(1);
+ lacp.pkt.partner.state =
+ LACP_ACTIVITY |
+ LACP_SYNCHRONIZATION |
+ LACP_COLLECTING |
+ LACP_DISTRIBUTING |
+ LACP_DEFAULTED;
+
+ lacp.pkt.tlv_type_collector_info = LACP_TLV_COLLECTOR;
+ lacp.pkt.collector_information_length = 0x10;
+ lacp.pkt.collector_max_delay = htons(0x8000); /* ???? */
+
+ lacp.pkt.tlv_type_terminator = LACP_TLV_TERMINATOR;
+ lacp.pkt.terminator_length = 0;
+}
+
+#define LACP_NTT_MASK (LACP_ACTIVITY | LACP_TIMEOUT | \
+ LACP_SYNCHRONIZATION | LACP_AGGREGATION)
+
+static inline int lacp_update_ntt(struct slow_lacp *pkt)
+{
+ int ntt = 0;
+ if ((memcmp(&pkt->partner, &lacp.pkt.actor, LACP_CMP_LEN) != 0) ||
+ ((pkt->partner.state & LACP_NTT_MASK) !=
+ (lacp.pkt.actor.state & LACP_NTT_MASK)))
+ {
+ ntt = 1;
+ }
+ return ntt;
+}
+
+static inline void lacp_record_pdu(struct slow_lacp *pkt)
+{
+ memcpy(&lacp.pkt.partner, &pkt->actor, LACP_CP_LEN);
+
+ lacp.pkt.actor.state &= ~LACP_DEFAULTED;
+ lacp.pkt.partner.state &= ~LACP_SYNCHRONIZATION;
+ if ((memcmp(&pkt->partner, &lacp.pkt.actor, LACP_CMP_LEN) == 0) &&
+ ((pkt->partner.state & LACP_AGGREGATION) ==
+ (lacp.pkt.actor.state & LACP_AGGREGATION)))
+ {
+ lacp.pkt.partner.state |= LACP_SYNCHRONIZATION;
+ }
+ if (!(pkt->actor.state & LACP_AGGREGATION)) {
+ lacp.pkt.partner.state |= LACP_SYNCHRONIZATION;
+ }
+
+ /* ACTIVITY? */
+}
+
+static inline int lacp_timer_expired(unsigned long now, unsigned long when)
+{
+ return when && (now > when);
+}
+
+static inline void lacp_start_periodic_timer(unsigned long now)
+{
+ if ((lacp.pkt.partner.state & LACP_ACTIVITY) ||
+ (lacp.pkt.actor.state & LACP_ACTIVITY)) {
+ lacp.periodic_timer = now +
+ (((lacp.pkt.partner.state & LACP_TIMEOUT)?
+ FAST_PERIODIC_TIME : SLOW_PERIODIC_TIME));
+ }
+}
+
+static inline void lacp_start_current_while_timer(unsigned long now)
+{
+ lacp.current_while_timer = now +
+ ((lacp.pkt.actor.state & LACP_TIMEOUT) ?
+ SHORT_TIMEOUT_TIME : LONG_TIMEOUT_TIME);
+
+ lacp.pkt.actor.state &= ~LACP_EXPIRED;
+}
+
+static void send_lacp_reports(unsigned long now, int ntt)
+{
+ if (memcmp(nic.node_addr, lacp.pkt.actor.system, ETH_ALEN) != 0) {
+ lacp_init_state(nic.node_addr);
+ }
+ /* If the remote information has expired I need to take action */
+ if (lacp_timer_expired(now, lacp.current_while_timer)) {
+ if (!(lacp.pkt.actor.state & LACP_EXPIRED)) {
+ lacp.pkt.partner.state &= ~LACP_SYNCHRONIZATION;
+ lacp.pkt.partner.state |= LACP_TIMEOUT;
+ lacp.pkt.actor.state |= LACP_EXPIRED;
+ lacp.current_while_timer = now + SHORT_TIMEOUT_TIME;
+ ntt = 1;
+ }
+ else {
+ lacp_init_state(nic.node_addr);
+ }
+ }
+ /* If the periodic timer has expired I need to transmit */
+ if (lacp_timer_expired(now, lacp.periodic_timer)) {
+ ntt = 1;
+ /* Reset by lacp_start_periodic_timer */
+ }
+ if (ntt) {
+ eth_transmit(slow_dest, ETH_P_SLOW, sizeof(lacp.pkt), &lacp.pkt);
+
+ /* Restart the periodic timer */
+ lacp_start_periodic_timer(now);
+
+ print_lacp("Trasmitted", &lacp.pkt, now);
+ }
+}
+
+static inline void send_eth_slow_reports(unsigned long now)
+{
+ send_lacp_reports(now, 0);
+}
+
+static inline void process_eth_slow(unsigned short ptype, unsigned long now)
+{
+ union slow_union *pkt;
+ if ((ptype != ETH_P_SLOW) ||
+ (nic.packetlen < (ETH_HLEN + sizeof(pkt->header)))) {
+ return;
+ }
+ pkt = (union slow_union *)&nic.packet[ETH_HLEN];
+ if ((pkt->header.subtype == SLOW_SUBTYPE_LACP) &&
+ (nic.packetlen >= ETH_HLEN + sizeof(pkt->lacp))) {
+ int ntt;
+ if (memcmp(nic.node_addr, lacp.pkt.actor.system, ETH_ALEN) != 0) {
+ lacp_init_state(nic.node_addr);
+ }
+ /* As long as nic.packet is 2 byte aligned all is good */
+ print_lacp("Received", &pkt->lacp, now);
+ /* I don't actually implement the MUX or SELECT
+ * machines.
+ *
+ * What logically happens when the client and I
+ * disagree about an aggregator is the current
+ * aggregtator is unselected. The MUX machine places
+ * me in DETACHED. The SELECT machine runs and
+ * reslects the same aggregator. If I go through
+ * these steps fast enough an outside observer can not
+ * notice this.
+ *
+ * Since the process will not generate any noticeable
+ * effect it does not need an implmenetation. This
+ * keeps the code simple and the code and binary
+ * size down.
+ */
+ /* lacp_update_selected(&pkt->lacp); */
+ ntt = lacp_update_ntt(&pkt->lacp);
+ lacp_record_pdu(&pkt->lacp);
+ lacp_start_current_while_timer(now);
+ send_lacp_reports(now, ntt);
+ }
+ /* If we receive a marker information packet return it */
+ else if ((pkt->header.subtype == SLOW_SUBTYPE_MARKER) &&
+ (nic.packetlen >= ETH_HLEN + sizeof(pkt->marker)) &&
+ (pkt->marker.tlv_type == MARKER_TLV_INFO) &&
+ (pkt->marker.marker_length == 0x16))
+ {
+ pkt->marker.tlv_type = MARKER_TLV_RESPONSE;
+ eth_transmit(slow_dest, ETH_P_SLOW,
+ sizeof(pkt->marker), &pkt->marker);
+ }
+
+ }
+#else
+
+#define send_eth_slow_reports(now) do {} while(0)
+#define process_eth_slow(ptype, now) do {} while(0)
+
+#endif