Home | History | Annotate | Line # | Download | only in agr
      1 /*	$NetBSD: ieee8023ad_lacp_sm_rx.c,v 1.5 2021/11/30 01:17:02 yamaguchi Exp $	*/
      2 
      3 /*-
      4  * Copyright (c)2005 YAMAMOTO Takashi,
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 __KERNEL_RCSID(0, "$NetBSD: ieee8023ad_lacp_sm_rx.c,v 1.5 2021/11/30 01:17:02 yamaguchi Exp $");
     31 
     32 #include <sys/param.h>
     33 #include <sys/callout.h>
     34 #include <sys/mbuf.h>
     35 #include <sys/systm.h>
     36 
     37 #include <net/if.h>
     38 #include <net/if_ether.h>
     39 #include <net/ether_slowprotocols.h>
     40 
     41 #include <net/agr/ieee8023_tlv.h>
     42 #include <net/agr/ieee8023ad_lacp.h>
     43 #include <net/agr/ieee8023ad_lacp_impl.h>
     44 #include <net/agr/ieee8023ad_lacp_sm.h>
     45 #include <net/agr/ieee8023ad_lacp_debug.h>
     46 
     47 /* receive machine */
     48 
     49 static void lacp_sm_rx_update_ntt(struct lacp_port *, const struct lacpdu *);
     50 static void lacp_sm_rx_record_pdu(struct lacp_port *, const struct lacpdu *);
     51 static void lacp_sm_rx_update_selected(struct lacp_port *, const struct lacpdu *);
     52 
     53 static void lacp_sm_rx_record_default(struct lacp_port *);
     54 static void lacp_sm_rx_update_default_selected(struct lacp_port *);
     55 
     56 static void lacp_sm_rx_update_selected_from_peerinfo(struct lacp_port *,
     57     const struct lacp_peerinfo *);
     58 
     59 /*
     60  * partner administration variables.
     61  * XXX should be configurable.
     62  */
     63 
     64 static const struct lacp_peerinfo lacp_partner_admin = {
     65 	.lip_systemid = { .lsi_prio = 0xffff },
     66 	.lip_portid = { .lpi_prio = 0xffff },
     67 #if 1
     68 	/* optimistic */
     69 	.lip_state = LACP_STATE_SYNC | LACP_STATE_AGGREGATION |
     70 	    LACP_STATE_COLLECTING | LACP_STATE_DISTRIBUTING,
     71 #else
     72 	/* pessimistic */
     73 	.lip_state = 0,
     74 #endif
     75 };
     76 
     77 void
     78 lacp_sm_rx(struct lacp_port *lp, const struct lacpdu *du)
     79 {
     80 	int timeout;
     81 
     82 	/*
     83 	 * check LACP_DISABLED first
     84 	 */
     85 
     86 	if (!(lp->lp_state & LACP_STATE_AGGREGATION)) {
     87 		return;
     88 	}
     89 
     90 	/*
     91 	 * check loopback condition.
     92 	 */
     93 
     94 	if (!lacp_compare_systemid(&du->ldu_actor.lip_systemid,
     95 	    &lp->lp_actor.lip_systemid)) {
     96 		return;
     97 	}
     98 
     99 	/*
    100 	 * EXPIRED, DEFAULTED, CURRENT -> CURRENT
    101 	 */
    102 
    103 	lacp_sm_rx_update_selected(lp, du);
    104 	lacp_sm_rx_update_ntt(lp, du);
    105 	lacp_sm_rx_record_pdu(lp, du);
    106 
    107 	timeout = (lp->lp_state & LACP_STATE_TIMEOUT) ?
    108 	    LACP_SHORT_TIMEOUT_TIME : LACP_LONG_TIMEOUT_TIME;
    109 	LACP_TIMER_ARM(lp, LACP_TIMER_CURRENT_WHILE, timeout);
    110 
    111 	lp->lp_state &= ~LACP_STATE_EXPIRED;
    112 
    113 	/*
    114 	 * kick transmit machine without waiting the next tick.
    115 	 */
    116 
    117 	lacp_sm_tx(lp);
    118 }
    119 
    120 void
    121 lacp_sm_rx_set_expired(struct lacp_port *lp)
    122 {
    123 
    124 	lp->lp_partner.lip_state &= ~LACP_STATE_SYNC;
    125 	lp->lp_partner.lip_state |= LACP_STATE_TIMEOUT;
    126 	LACP_TIMER_ARM(lp, LACP_TIMER_CURRENT_WHILE, LACP_SHORT_TIMEOUT_TIME);
    127 	lp->lp_state |= LACP_STATE_EXPIRED;
    128 }
    129 
    130 void
    131 lacp_sm_rx_timer(struct lacp_port *lp)
    132 {
    133 
    134 	if ((lp->lp_state & LACP_STATE_EXPIRED) == 0) {
    135 		/* CURRENT -> EXPIRED */
    136 		LACP_DPRINTF((lp, "%s: CURRENT -> EXPIRED\n", __func__));
    137 		lacp_sm_rx_set_expired(lp);
    138 	} else {
    139 		/* EXPIRED -> DEFAULTED */
    140 		LACP_DPRINTF((lp, "%s: EXPIRED -> DEFAULTED\n", __func__));
    141 		lacp_sm_rx_update_default_selected(lp);
    142 		lacp_sm_rx_record_default(lp);
    143 		lp->lp_state &= ~LACP_STATE_EXPIRED;
    144 	}
    145 }
    146 
    147 static void
    148 lacp_sm_rx_record_pdu(struct lacp_port *lp, const struct lacpdu *du)
    149 {
    150 	bool active;
    151 	uint8_t oldpstate;
    152 #if defined(LACP_DEBUG)
    153 	char buf[LACP_STATESTR_MAX+1];
    154 #endif
    155 
    156 	/* LACP_DPRINTF((lp, "%s\n", __func__)); */
    157 
    158 	oldpstate = lp->lp_partner.lip_state;
    159 
    160 	active = (du->ldu_actor.lip_state & LACP_STATE_ACTIVITY)
    161 	    || ((lp->lp_state & LACP_STATE_ACTIVITY) &&
    162 	    (du->ldu_partner.lip_state & LACP_STATE_ACTIVITY));
    163 
    164 	lp->lp_partner = du->ldu_actor;
    165 	if (active &&
    166 	    ((LACP_STATE_EQ(lp->lp_state, du->ldu_partner.lip_state,
    167 	    LACP_STATE_AGGREGATION) &&
    168 	    !lacp_compare_peerinfo(&lp->lp_actor, &du->ldu_partner))
    169 	    || (du->ldu_partner.lip_state & LACP_STATE_AGGREGATION) == 0)) {
    170 		/* nothing */
    171 	} else {
    172 		lp->lp_partner.lip_state &= ~LACP_STATE_SYNC;
    173 	}
    174 
    175 	lp->lp_state &= ~LACP_STATE_DEFAULTED;
    176 
    177 	LACP_DPRINTF((lp, "old pstate %s\n",
    178 	    lacp_format_state(oldpstate, buf, sizeof(buf))));
    179 	LACP_DPRINTF((lp, "new pstate %s\n",
    180 	    lacp_format_state(lp->lp_partner.lip_state, buf, sizeof(buf))));
    181 
    182 	lacp_sm_ptx_update_timeout(lp, oldpstate);
    183 }
    184 
    185 static void
    186 lacp_sm_rx_update_ntt(struct lacp_port *lp, const struct lacpdu *du)
    187 {
    188 
    189 	/* LACP_DPRINTF((lp, "%s\n", __func__)); */
    190 
    191 	if (lacp_compare_peerinfo(&lp->lp_actor, &du->ldu_partner) ||
    192 	    !LACP_STATE_EQ(lp->lp_state, du->ldu_partner.lip_state,
    193 	    LACP_STATE_ACTIVITY | LACP_STATE_SYNC | LACP_STATE_AGGREGATION)) {
    194 		LACP_DPRINTF((lp, "%s: assert ntt\n", __func__));
    195 		lacp_sm_assert_ntt(lp);
    196 	}
    197 }
    198 
    199 static void
    200 lacp_sm_rx_record_default(struct lacp_port *lp)
    201 {
    202 	uint8_t oldpstate;
    203 
    204 	/* LACP_DPRINTF((lp, "%s\n", __func__)); */
    205 
    206 	oldpstate = lp->lp_partner.lip_state;
    207 	lp->lp_partner = lacp_partner_admin;
    208 	lp->lp_state |= LACP_STATE_DEFAULTED;
    209 	lacp_sm_ptx_update_timeout(lp, oldpstate);
    210 }
    211 
    212 static void
    213 lacp_sm_rx_update_selected_from_peerinfo(struct lacp_port *lp,
    214     const struct lacp_peerinfo *info)
    215 {
    216 
    217 	/* LACP_DPRINTF((lp, "%s\n", __func__)); */
    218 
    219 	if (lacp_compare_peerinfo(&lp->lp_partner, info) ||
    220 	    !LACP_STATE_EQ(lp->lp_partner.lip_state, info->lip_state,
    221 	    LACP_STATE_AGGREGATION)) {
    222 		lp->lp_selected = LACP_UNSELECTED;
    223 		/* mux machine will clean up lp->lp_aggregator */
    224 	}
    225 }
    226 
    227 static void
    228 lacp_sm_rx_update_selected(struct lacp_port *lp, const struct lacpdu *du)
    229 {
    230 
    231 	/* LACP_DPRINTF((lp, "%s\n", __func__)); */
    232 
    233 	lacp_sm_rx_update_selected_from_peerinfo(lp, &du->ldu_actor);
    234 }
    235 
    236 static void
    237 lacp_sm_rx_update_default_selected(struct lacp_port *lp)
    238 {
    239 
    240 	/* LACP_DPRINTF((lp, "%s\n", __func__)); */
    241 
    242 	lacp_sm_rx_update_selected_from_peerinfo(lp, &lacp_partner_admin);
    243 }
    244