proto_eth_slow.c

Go to the documentation of this file.
00001 /* Copyright 2004 Linux Networx */
00002 #ifdef PROTO_LACP
00003 #if 0
00004 #include "nic.h"
00005 #include "timer.h"
00006 #endif
00007 
00008 #define LACP_DEBUG 0
00009 
00010 /* Structure definitions originally taken from the linux bond_3ad driver */
00011 
00012 #define SLOW_DST_MAC "\x01\x80\xc2\x00\x00\x02"
00013 static const char slow_dest[] = SLOW_DST_MAC;
00014 
00015 
00016 #define SLOW_SUBTYPE_LACP 1
00017 #define SLOW_SUBTYPE_MARKER 2
00018 
00019 struct slow_header {
00020         uint8_t subtype;
00021 };
00022 
00023 struct lacp_info {
00024         uint16_t system_priority;
00025         uint8_t  system[ETH_ALEN];
00026         uint16_t key;
00027         uint16_t port_priority;
00028         uint16_t port;
00029         uint8_t  state;
00030         uint8_t  reserved[3];
00031 } PACKED;
00032 
00033 #define LACP_CMP_LEN (2 + 6 + 2 + 2 + 2)
00034 #define LACP_CP_LEN  (2 + 6 + 2 + 2 + 2 + 1)
00035 
00036 /* Link Aggregation Control Protocol(LACP) data unit structure(43.4.2.2 in the 802.3ad standard) */
00037 struct slow_lacp {
00038         uint8_t  subtype;                      /* = LACP(= 0x01) */
00039         uint8_t  version_number;
00040         uint8_t  tlv_type_actor_info;          /* = actor information(type/length/value) */
00041 #define LACP_TLV_TERMINATOR 0
00042 #define LACP_TLV_ACTOR      1
00043 #define LACP_TLV_PARTNER    2
00044 #define LACP_TLV_COLLECTOR  3
00045         uint8_t  actor_information_length;     /* = 20 */
00046         struct lacp_info actor;
00047         uint8_t  tlv_type_partner_info;        /* = partner information */
00048         uint8_t  partner_information_length;   /* = 20 */
00049         struct lacp_info partner;
00050         uint8_t  tlv_type_collector_info;      /* = collector information */
00051         uint8_t  collector_information_length; /* = 16 */
00052         uint16_t collector_max_delay;
00053         uint8_t  reserved_12[12];
00054         uint8_t  tlv_type_terminator;          /* = terminator */
00055         uint8_t  terminator_length;            /* = 0 */ 
00056         uint8_t  reserved_50[50];              /* = 0 */
00057 } PACKED;
00058 
00059 /* Marker Protocol Data Unit(PDU) structure(43.5.3.2 in the 802.3ad standard) */
00060 struct slow_marker {
00061         uint8_t  subtype;                      /* = 0x02  (marker PDU) */
00062         uint8_t  version_number;               /* = 0x01 */
00063         uint8_t  tlv_type;
00064 #define MARKER_TLV_TERMINATOR 0                /* marker terminator */
00065 #define MARKER_TLV_INFO       1                /* marker information */
00066 #define MARKER_TLV_RESPONSE   2                /* marker response information */
00067         uint8_t  marker_length;                /* = 0x16 */
00068         uint16_t requester_port;               /* The number assigned to the port by the requester */
00069         uint8_t  requester_system[ETH_ALEN];   /* The requester's system id */
00070         uint32_t requester_transaction_id;     /* The transaction id allocated by the requester, */
00071         uint16_t pad;                          /* = 0 */
00072         uint8_t  tlv_type_terminator;          /* = 0x00 */
00073         uint8_t  terminator_length;            /* = 0x00 */
00074         uint8_t  reserved_90[90];              /* = 0 */
00075 } PACKED;
00076 
00077 union slow_union {
00078         struct slow_header header;
00079         struct slow_lacp lacp;
00080         struct slow_marker marker;
00081 };
00082 
00083 #define FAST_PERIODIC_TIME   (1*TICKS_PER_SEC)
00084 #define SLOW_PERIODIC_TIME   (30*TICKS_PER_SEC)
00085 #define SHORT_TIMEOUT_TIME   (3*FAST_PERIODIC_TIME)
00086 #define LONG_TIMEOUT_TIME    (3*SLOW_PERIODIC_TIME)
00087 #define CHURN_DETECTION_TIME (60*TICKS_PER_SEC)
00088 #define AGGREGATE_WAIT_TIME  (2*TICKS_PER_SEC)
00089 
00090 #define LACP_ACTIVITY        (1 << 0)
00091 #define LACP_TIMEOUT         (1 << 1)
00092 #define LACP_AGGREGATION     (1 << 2)
00093 #define LACP_SYNCHRONIZATION (1 << 3)
00094 #define LACP_COLLECTING      (1 << 4)
00095 #define LACP_DISTRIBUTING    (1 << 5)
00096 #define LACP_DEFAULTED       (1 << 6)
00097 #define LACP_EXPIRED         (1 << 7)
00098 
00099 #define UNSELECTED 0
00100 #define STANDBY    1
00101 #define SELECTED   2
00102 
00103 
00104 struct lacp_state {
00105         struct slow_lacp pkt;
00106         unsigned long current_while_timer; /* Time when the LACP information expires */
00107         unsigned long periodic_timer; /* Time when I need to send my partner an update */
00108 };
00109 
00110 static struct lacp_state lacp;
00111 
00112 
00113 #if LACP_DEBUG > 0
00114 static void print_lacp_state(uint8_t state)
00115 {
00116         printf("%hhx", state);
00117         if (state & LACP_ACTIVITY) {
00118                 printf(" Activity");
00119         }
00120         if (state & LACP_TIMEOUT) {
00121                 printf(" Timeout");
00122         }
00123         if (state & LACP_AGGREGATION) {
00124                 printf(" Aggregation");
00125         }
00126         if (state & LACP_SYNCHRONIZATION) {
00127                 printf(" Syncronization");
00128         }
00129         if (state & LACP_COLLECTING) {
00130                 printf(" Collecting");
00131         }
00132         if (state & LACP_DISTRIBUTING) {
00133                 printf(" Distributing");
00134         }
00135         if (state & LACP_DEFAULTED) {
00136                 printf(" Defaulted");
00137         }
00138         if (state & LACP_EXPIRED) {
00139                 printf(" Expired");
00140         }
00141         printf("\n");
00142 }
00143 
00144 static inline void print_lacpdu(struct slow_lacp *pkt)
00145 {
00146         printf("subtype version:  %hhx %hhx\n", 
00147                 pkt->subtype, pkt->version_number);
00148         printf("actor_tlv %hhx", pkt->tlv_type_actor_info);
00149         printf(" len: %hhx (\n", pkt->actor_information_length);
00150         printf(" sys_pri: %hx", ntohs(pkt->actor.system_priority));
00151         printf(" mac: %!", pkt->actor.system);
00152         printf(" key: %hx", ntohs(pkt->actor.key));
00153         printf(" port_pri: %hx", ntohs(pkt->actor.port_priority));
00154         printf(" port: %hx\n", ntohs(pkt->actor.port));
00155         printf(" state: ");
00156         print_lacp_state(pkt->actor.state);
00157 #if LACP_DEBUG > 1
00158         printf(" reserved:     %hhx %hhx %hhx\n",
00159                 pkt->actor.reserved[0], pkt->actor.reserved[1], pkt->actor.reserved[2]);
00160 #endif
00161         printf(")\n");
00162         printf("partner_tlv: %hhx", pkt->tlv_type_partner_info);
00163         printf(" len: %hhx (\n", pkt->partner_information_length);
00164         printf(" sys_pri: %hx", ntohs(pkt->partner.system_priority));
00165         printf(" mac: %!", pkt->partner.system);
00166         printf(" key: %hx", ntohs(pkt->partner.key));
00167         printf(" port_pri: %hx", ntohs(pkt->partner.port_priority));
00168         printf(" port: %hx\n", ntohs(pkt->partner.port));
00169         printf(" state: ");
00170         print_lacp_state(pkt->partner.state);
00171 #if LACP_DEBUG > 1
00172         printf(" reserved:     %hhx %hhx %hhx\n",
00173                 pkt->partner.reserved[0], pkt->partner.reserved[1], pkt->partner.reserved[2]);
00174 #endif
00175         printf(")\n");
00176         printf("collector_tlv: %hhx ", pkt->tlv_type_collector_info);
00177         printf(" len: %hhx (", pkt->collector_information_length);
00178         printf(" max_delay: %hx", ntohs(pkt->collector_max_delay));
00179 #if LACP_DEBUG > 1
00180         printf("reserved_12:      %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\n",
00181                 pkt->reserved_12[0], pkt->reserved_12[1], pkt->reserved_12[2], 
00182                 pkt->reserved_12[3], pkt->reserved_12[4], pkt->reserved_12[5], 
00183                 pkt->reserved_12[6], pkt->reserved_12[7], pkt->reserved_12[8], 
00184                 pkt->reserved_12[9], pkt->reserved_12[10], pkt->reserved_12[11]);
00185 #endif
00186         printf(" )\n");
00187         printf("terminator_tlv: %hhx", pkt->tlv_type_terminator);
00188         printf(" len: %hhx ()\n", pkt->terminator_length);
00189 }
00190 
00191 static inline unsigned long lacp_timer_val(unsigned long now, unsigned long when)
00192 {
00193         return when?(when - now)/TICKS_PER_SEC : 0;
00194 }
00195 static void print_lacp(const char *which, struct slow_lacp *pkt, unsigned long now)
00196 {
00197         printf("%s\n", which);
00198         print_lacpdu(pkt);
00199         printf("timers: c %ds p %ds\n",
00200                 lacp_timer_val(now, lacp.current_while_timer),
00201                 lacp_timer_val(now, lacp.periodic_timer)
00202                 );
00203         printf("\n");
00204 }
00205 #else /* LACP_DEBUG */
00206 #define print_lacp(which, pkt, now) do {} while(0)
00207 #endif /* LACP_DEBUG */
00208 
00209 static void lacp_init_state(const uint8_t *mac)
00210 {
00211         memset(&lacp, 0, sizeof(lacp));
00212 
00213         /* Initialize the packet constants */
00214         lacp.pkt.subtype               = 1;
00215         lacp.pkt.version_number        = 1;
00216 
00217 
00218         /* The default state of my interface */
00219         lacp.pkt.tlv_type_actor_info      = LACP_TLV_ACTOR;
00220         lacp.pkt.actor_information_length = 0x14;
00221         lacp.pkt.actor.system_priority    = htons(1);
00222         memcpy(lacp.pkt.actor.system, mac, ETH_ALEN);
00223         lacp.pkt.actor.key                = htons(1);
00224         lacp.pkt.actor.port               = htons(1);
00225         lacp.pkt.actor.port_priority      = htons(1);
00226         lacp.pkt.actor.state = 
00227                 LACP_SYNCHRONIZATION |
00228                 LACP_COLLECTING      |
00229                 LACP_DISTRIBUTING    |
00230                 LACP_DEFAULTED;
00231 
00232         /* Set my partner defaults */
00233         lacp.pkt.tlv_type_partner_info      = LACP_TLV_PARTNER;
00234         lacp.pkt.partner_information_length = 0x14;
00235         lacp.pkt.partner.system_priority    = htons(1);
00236         /* memset(lacp.pkt.parnter_system, 0, ETH_ALEN); */
00237         lacp.pkt.partner.key                = htons(1);
00238         lacp.pkt.partner.port               = htons(1);
00239         lacp.pkt.partner.port_priority      = htons(1);
00240         lacp.pkt.partner.state =
00241                 LACP_ACTIVITY        |
00242                 LACP_SYNCHRONIZATION |
00243                 LACP_COLLECTING      |
00244                 LACP_DISTRIBUTING    |
00245                 LACP_DEFAULTED;
00246 
00247         lacp.pkt.tlv_type_collector_info      = LACP_TLV_COLLECTOR;
00248         lacp.pkt.collector_information_length = 0x10;
00249         lacp.pkt.collector_max_delay          = htons(0x8000); /* ???? */
00250 
00251         lacp.pkt.tlv_type_terminator          = LACP_TLV_TERMINATOR;
00252         lacp.pkt.terminator_length            = 0;
00253 }
00254 
00255 #define LACP_NTT_MASK (LACP_ACTIVITY | LACP_TIMEOUT | \
00256         LACP_SYNCHRONIZATION | LACP_AGGREGATION)
00257 
00258 static inline int lacp_update_ntt(struct slow_lacp *pkt)
00259 {
00260         int ntt = 0;
00261         if ((memcmp(&pkt->partner, &lacp.pkt.actor, LACP_CMP_LEN) != 0) ||
00262                 ((pkt->partner.state & LACP_NTT_MASK) != 
00263                         (lacp.pkt.actor.state & LACP_NTT_MASK)))
00264         {
00265                 ntt = 1;
00266         }
00267         return ntt;
00268 }
00269 
00270 static inline void lacp_record_pdu(struct slow_lacp *pkt)
00271 {
00272         memcpy(&lacp.pkt.partner, &pkt->actor, LACP_CP_LEN);
00273 
00274         lacp.pkt.actor.state &= ~LACP_DEFAULTED;
00275         lacp.pkt.partner.state &= ~LACP_SYNCHRONIZATION;
00276         if ((memcmp(&pkt->partner, &lacp.pkt.actor, LACP_CMP_LEN) == 0) &&
00277                 ((pkt->partner.state & LACP_AGGREGATION) ==
00278                         (lacp.pkt.actor.state & LACP_AGGREGATION)))
00279         {
00280                 lacp.pkt.partner.state  |= LACP_SYNCHRONIZATION;
00281         }
00282         if (!(pkt->actor.state & LACP_AGGREGATION)) {
00283                 lacp.pkt.partner.state |= LACP_SYNCHRONIZATION;
00284         }
00285 
00286         /* ACTIVITY? */
00287 }
00288 
00289 static inline int lacp_timer_expired(unsigned long now, unsigned long when)
00290 {
00291         return when && (now > when);
00292 }
00293 
00294 static inline void lacp_start_periodic_timer(unsigned long now)
00295 {
00296         if ((lacp.pkt.partner.state & LACP_ACTIVITY) ||
00297                 (lacp.pkt.actor.state & LACP_ACTIVITY)) {
00298                 lacp.periodic_timer = now +
00299                         (((lacp.pkt.partner.state & LACP_TIMEOUT)?
00300                                 FAST_PERIODIC_TIME : SLOW_PERIODIC_TIME));
00301         }
00302 }
00303 
00304 static inline void lacp_start_current_while_timer(unsigned long now)
00305 {
00306         lacp.current_while_timer = now +
00307                 ((lacp.pkt.actor.state & LACP_TIMEOUT) ?
00308                 SHORT_TIMEOUT_TIME : LONG_TIMEOUT_TIME);
00309 
00310         lacp.pkt.actor.state &= ~LACP_EXPIRED;
00311 }
00312 
00313 static void send_lacp_reports(unsigned long now, int ntt)
00314 {
00315         if (memcmp(nic.node_addr, lacp.pkt.actor.system, ETH_ALEN) != 0) {
00316                 lacp_init_state(nic.node_addr);
00317         }
00318         /* If the remote information has expired I need to take action */
00319         if (lacp_timer_expired(now, lacp.current_while_timer)) {
00320                 if (!(lacp.pkt.actor.state & LACP_EXPIRED)) {
00321                         lacp.pkt.partner.state &= ~LACP_SYNCHRONIZATION;
00322                         lacp.pkt.partner.state |= LACP_TIMEOUT;
00323                         lacp.pkt.actor.state |= LACP_EXPIRED;
00324                         lacp.current_while_timer = now + SHORT_TIMEOUT_TIME;
00325                         ntt = 1;
00326                 }
00327                 else {
00328                         lacp_init_state(nic.node_addr);
00329                 }
00330         }
00331         /* If the periodic timer has expired I need to transmit */
00332         if (lacp_timer_expired(now, lacp.periodic_timer)) {
00333                 ntt = 1;
00334                 /* Reset by lacp_start_periodic_timer */
00335         }
00336         if (ntt) {
00337                 eth_transmit(slow_dest, ETH_P_SLOW, sizeof(lacp.pkt), &lacp.pkt);
00338 
00339                 /* Restart the periodic timer */
00340                 lacp_start_periodic_timer(now);
00341 
00342                 print_lacp("Trasmitted", &lacp.pkt, now);
00343         }
00344 }
00345 
00346 static inline void send_eth_slow_reports(unsigned long now)
00347 {
00348         send_lacp_reports(now, 0);
00349 }
00350 
00351 static inline void process_eth_slow(unsigned short ptype, unsigned long now)
00352 {
00353         union slow_union *pkt;
00354         if ((ptype != ETH_P_SLOW) || 
00355                 (nic.packetlen < (ETH_HLEN + sizeof(pkt->header)))) {
00356                 return;
00357         }
00358         pkt = (union slow_union *)&nic.packet[ETH_HLEN];
00359         if ((pkt->header.subtype == SLOW_SUBTYPE_LACP) &&
00360                 (nic.packetlen >= ETH_HLEN + sizeof(pkt->lacp))) {
00361                 int ntt;
00362                 if (memcmp(nic.node_addr, lacp.pkt.actor.system, ETH_ALEN) != 0) {
00363                         lacp_init_state(nic.node_addr);
00364                 }
00365                 /* As long as nic.packet is 2 byte aligned all is good */
00366                 print_lacp("Received", &pkt->lacp, now);
00367                 /* I don't actually implement the MUX or SELECT
00368                  * machines.  
00369                  *
00370                  * What logically happens when the client and I
00371                  * disagree about an aggregator is the current
00372                  * aggregtator is unselected.  The MUX machine places
00373                  * me in DETACHED.  The SELECT machine runs and
00374                  * reslects the same aggregator.  If I go through
00375                  * these steps fast enough an outside observer can not
00376                  * notice this.  
00377                  *
00378                  * Since the process will not generate any noticeable
00379                  * effect it does not need an implmenetation.  This
00380                  * keeps the code simple and the code and binary
00381                  * size down.
00382                  */
00383                 /* lacp_update_selected(&pkt->lacp); */
00384                 ntt = lacp_update_ntt(&pkt->lacp);
00385                 lacp_record_pdu(&pkt->lacp);
00386                 lacp_start_current_while_timer(now);
00387                 send_lacp_reports(now, ntt);
00388         }
00389         /* If we receive a marker information packet return it */
00390         else if ((pkt->header.subtype == SLOW_SUBTYPE_MARKER) &&
00391                 (nic.packetlen >= ETH_HLEN + sizeof(pkt->marker)) &&
00392                 (pkt->marker.tlv_type == MARKER_TLV_INFO) &&
00393                 (pkt->marker.marker_length == 0x16)) 
00394         {
00395                 pkt->marker.tlv_type = MARKER_TLV_RESPONSE;
00396                 eth_transmit(slow_dest, ETH_P_SLOW, 
00397                         sizeof(pkt->marker), &pkt->marker);
00398         }
00399 
00400  }
00401 #else
00402 
00403 #define send_eth_slow_reports(now)    do {} while(0)
00404 #define process_eth_slow(ptype, now)  do {} while(0)
00405 
00406 #endif 

Generated on Tue Apr 6 20:00:51 2010 for gPXE by  doxygen 1.5.7.1