Blob Blame History Raw
From a2b1745d86cce79b0e4f9aa01045f06218afc991 Mon Sep 17 00:00:00 2001
From: Jens Osterkamp <jens@linux.vnet.ibm.com>
Date: Thu, 3 Feb 2011 23:00:02 +0000
Subject: [PATCH 01/51] new: rework of VDP code towards newer drafts

This is a first rework of the VDP towards the changes in newer drafts.
It contains the following changes:

- bugfix: prevent sending of duplicate keepalives

While checking ECP traffic on the wire a lot of ECP frames being
sent until an ack was received. This fixes it.

- allow transition from UNASSOCIATED to DEASSOCIATED

This is necessary in cases when lldpad has been terminated,
but VMs are still running, to allow these VMs to be deassociated.

- do not remove profile on ifdown

Up to now profiles were deleted and the vdp_data struct removed from the
list on "ifconfig eth? down".
Now profiles are retained during interface down. Processing of profiles will
continue after the interface comes up again. Keepalives are sent as before.

Signed-off-by: Jens Osterkamp <jens@linux.vnet.ibm.com>
Signed-off-by: Petr Sabata <psabata@redhat.com>
---
 ecp/ecp.c          |    2 -
 include/lldp_vdp.h |   14 +++-
 lldp_vdp.c         |  218 +++++++++++++++++++++++++---------------------------
 3 files changed, 116 insertions(+), 118 deletions(-)

diff --git a/ecp/ecp.c b/ecp/ecp.c
index 66e97a4..3798ae6 100644
--- a/ecp/ecp.c
+++ b/ecp/ecp.c
@@ -92,8 +92,6 @@ int ecp_deinit(char *ifname)
 
 	ecp_tx_stop_ackTimer(vd);
 
-	l2_packet_deinit(vd->ecp.l2);
-
 	return 0;
 
 fail:
diff --git a/include/lldp_vdp.h b/include/lldp_vdp.h
index 9906b52..146e29d 100644
--- a/include/lldp_vdp.h
+++ b/include/lldp_vdp.h
@@ -71,8 +71,11 @@ enum {
 
 #define VDP_MACVLAN_FORMAT_1	1
 
-#define VDP_TRANSMISSION_TIMER(rte)	3*EVB_RTM(rte)*EVB_RTG
-#define VDP_TRANSMISSION_DIVIDER	10000
+#define VDP_TIMER_GRANULARITY		10000 /* 10 ms in us */
+#define VDP_KEEPALIVE_TIMER_DEFAULT	1000
+#define VDP_ACK_TIMER_DEFAULT		150
+#define VDP_KEEPALIVE_TIMER_STOPPED	-1
+#define VDP_ACK_TIMER_STOPPED		-1
 
 #define VDP_ROLE_STATION		0
 #define VDP_ROLE_BRIDGE			1
@@ -126,9 +129,9 @@ struct vsi_profile {
 	u8 mac[6]; /* TODO: currently only one MAC/VLAN pair supported, more later */
 	u16 vlan;
 	struct port *port;
-	int ackTimerExpired;
+	int ackTimer;
 	int ackReceived;
-	int keepaliveTimerExpired;
+	int keepaliveTimer;
 	int state;
 	bool localChange;
 	LIST_ENTRY(vsi_profile) profile;
@@ -139,6 +142,8 @@ struct vdp_data {
 	struct ecp ecp;
 	struct unpacked_tlv *vdp;
 	int role;
+	int keepaliveTimer;
+	int ackTimer;
 	LIST_HEAD(profile_head, vsi_profile) profile_head;
 	LIST_ENTRY(vdp_data) entry;
 };
@@ -154,6 +159,7 @@ struct packed_tlv *vdp_gettlv(struct vdp_data *vd, struct vsi_profile *profile);
 void vdp_vsi_sm_station(struct vsi_profile *profile);
 struct vsi_profile *vdp_add_profile(struct vsi_profile *profile);
 void vdp_somethingChangedLocal(struct vsi_profile *profile, bool mode);
+static int vdp_start_timer(struct vdp_data *vd);
 
 #define MAC_ADDR_STRLEN		18
 #define INSTANCE_STRLEN		36
diff --git a/lldp_vdp.c b/lldp_vdp.c
index b2cc594..0cbf71e 100644
--- a/lldp_vdp.c
+++ b/lldp_vdp.c
@@ -153,146 +153,137 @@ void vdp_somethingChangedLocal(struct vsi_profile *profile, bool mode)
  */
 static bool vdp_keepaliveTimer_expired(struct vsi_profile *profile)
 {
-	return profile->keepaliveTimerExpired;
+	return (profile->keepaliveTimer == 0);
 }
 
-/* vdp_acktimeout_handler - handles the ack timer expiry
+/* vdp_ackTimer_expired - checks for expired ack timer
+ * @profile: profile to be checked
+ *
+ * returns true or false
+ *
+ * returns value of profile->ackTimerExpired, true if ack timer has expired,
+ * false otherwise.
+ */
+static bool vdp_ackTimer_expired(struct vsi_profile *profile)
+{
+	return (profile->ackTimer == 0);
+}
+
+/* vdp_timeout_handler - handles the timer expiry
  * @eloop_data: data structure of event loop
- * @user_ctx: user context, profile here
+ * @user_ctx: user context, vdp_data here
  *
  * no return value
  *
- * called when the VDP ack timer has expired. sets a flag and calls the VDP
- * state machine.
+ * called when the VDP timer has expired. Decrements ack and keepaliveTimer
+ * and calls the VDP station state machine if necessary.
  */
-void vdp_keepalivetimeout_handler(void *eloop_data, void *user_ctx)
+void vdp_timeout_handler(void *eloop_data, void *user_ctx)
 {
-	struct vsi_profile *profile;
+	struct vdp_data *vd;
+	struct vsi_profile *p;
 
-	profile = (struct vsi_profile *) user_ctx;
+	vd = (struct vdp_data *) user_ctx;
 
-	profile->keepaliveTimerExpired = true;
+	LIST_FOREACH(p, &vd->profile_head, profile) {
+		if (p->ackTimer > 0)
+			p->ackTimer--;
 
-	LLDPAD_DBG("%s(%i)-%s: keepalive timer expired\n", __func__, __LINE__,
-	       profile->port->ifname);
+		if (p->keepaliveTimer > 0)
+			p->keepaliveTimer--;
 
-	vdp_vsi_sm_station(profile);
+		if (vdp_ackTimer_expired(p))
+			vdp_vsi_sm_station(p);
+
+		if (vdp_keepaliveTimer_expired(p))
+			vdp_vsi_sm_station(p);
+	}
+
+	vdp_start_timer(vd);
 }
 
-/* vdp_stop_keepaliveTimer - stop the VDP keepalive timer
- * @profile: profile to process
+/* vdp_stop_timer - stop the VDP timer
+ * @vd: vdp_data for the interface
  *
  * returns the number of removed handlers
  *
- * stops the VDP keepalive timer. Used when the profile changes state e.g. a deassoc
- * has been requested.
+ * stops the VDP timer. Used e.g. when the host interface goes down.
  */
-static int vdp_stop_keepaliveTimer(struct vsi_profile *profile)
+static int vdp_stop_timer(struct vdp_data *vd)
 {
-	LLDPAD_DBG("%s(%i)-%s: stopping keepalive timer\n", __func__, __LINE__,
-	       profile->port->ifname);
+	LLDPAD_DBG("%s(%i)-%s: stopping vdp timer\n", __func__, __LINE__,
+	       vd->ifname);
 
-	return eloop_cancel_timeout(vdp_keepalivetimeout_handler, NULL, (void *) profile);
+	return eloop_cancel_timeout(vdp_timeout_handler, NULL, (void *) vd);
 }
 
-/* vdp_start_keepaliveTimer - starts the VDP keepalive timer
- * @profile: profile to process
+/* vdp_start_timer - starts the VDP timer
+ * @vd: vdp_data for the interface
  *
  * returns 0 on success, -1 on error
  *
- * starts the keepalive timer after a ack frame has received.
+ * starts the VDP timer when the interface comes up.
  */
-static int vdp_start_keepaliveTimer(struct vsi_profile *profile)
+static int vdp_start_timer(struct vdp_data *vd)
 {
 	unsigned int secs, usecs, rte;
 
-	profile->keepaliveTimerExpired = false;
-
-	rte = evb_get_rte(profile->port->ifname);
-
-	secs = VDP_TRANSMISSION_TIMER(rte) / VDP_TRANSMISSION_DIVIDER;
-	usecs = VDP_TRANSMISSION_TIMER(rte) % VDP_TRANSMISSION_DIVIDER;
+	secs = 0;
+	usecs = VDP_TIMER_GRANULARITY;
 
-	LLDPAD_DBG("%s(%i)-%s: starting keepalive timer (%i secs, %i usecs) \n", __func__, __LINE__,
-	       profile->port->ifname, secs, usecs);
-
-	return eloop_register_timeout(secs, usecs, vdp_keepalivetimeout_handler, NULL, (void *) profile);
+	return eloop_register_timeout(secs, usecs, vdp_timeout_handler, NULL, (void *) vd);
 }
 
-/* vdp_ackTimer_expired - checks for expired ack timer
- * @profile: profile to be checked
- *
- * returns true or false
+/* vdp_start_ackTimer - starts the VDP ack timer
+ * @profile: profile to process
  *
- * returns value of profile->ackTimerExpired, true if ack timer has expired,
- * false otherwise.
+ * starts the ack timer when a frame has been sent out.
  */
-static bool vdp_ackTimer_expired(struct vsi_profile *profile)
+static void vdp_start_ackTimer(struct vsi_profile *profile)
 {
-	return profile->ackTimerExpired;
+	profile->ackTimer = VDP_ACK_TIMER_DEFAULT;
+
+	LLDPAD_DBG("%s(%i)-%s: starting ack timer (%i)\n", __func__, __LINE__,
+	       profile->port->ifname, profile->ackTimer);
 }
 
-/* vdp_acktimeout_handler - handles the ack timer expiry
- * @eloop_data: data structure of event loop
- * @user_ctx: user context, profile here
- *
- * no return value
+/* vdp_start_ackTimer - starts the VDP keepalive timer for a profile
+ * @profile: profile to process
  *
- * called when the VDP ack timer has expired. sets a flag and calls the VDP
- * state machine.
+ * starts the keepalive timer when a frame has been sent out.
  */
-void vdp_acktimeout_handler(void *eloop_data, void *user_ctx)
+static void vdp_start_keepaliveTimer(struct vsi_profile *profile)
 {
-	struct vsi_profile *profile;
-
-	profile = (struct vsi_profile *) user_ctx;
+	profile->keepaliveTimer = VDP_KEEPALIVE_TIMER_DEFAULT;
 
-	profile->ackTimerExpired = true;
-
-	LLDPAD_DBG("%s(%i)-%s: ack timer expired\n", __func__, __LINE__,
-	       profile->port->ifname);
-
-	vdp_vsi_sm_station(profile);
+	LLDPAD_DBG("%s(%i)-%s: starting keepalive timer (%i)\n", __func__, __LINE__,
+	       profile->port->ifname, profile->keepaliveTimer);
 }
 
-/* vdp_stop_ackTimer - stop the VDP ack timer
+/* vdp_stop_ackTimer - stops the VDP ack timer
  * @profile: profile to process
  *
- * returns the number of removed handlers
- *
- * stops the VDP ack timer. used when a ack frame for the profile has been
- * received.
+ * stops the ack timer when a frame has been sent out.
  */
-static int vdp_stop_ackTimer(struct vsi_profile *profile)
+static void vdp_stop_ackTimer(struct vsi_profile *profile)
 {
-	LLDPAD_DBG("%s(%i)-%s: stopping ack timer\n", __func__, __LINE__,
-	       profile->port->ifname);
+	profile->ackTimer = VDP_ACK_TIMER_STOPPED;
 
-	return eloop_cancel_timeout(vdp_acktimeout_handler, NULL, (void *) profile);
+	LLDPAD_DBG("%s(%i)-%s: stopping ack timer (%i)\n", __func__, __LINE__,
+	       profile->port->ifname, profile->ackTimer);
 }
 
-/* vdp_start_ackTimer - starts the VDP ack timer
+/* vdp_stop_ackTimer - stops the VDP keepalive timer for a profile
  * @profile: profile to process
  *
- * returns 0 on success, -1 on error
- *
- * starts the ack timer when a frame has been sent out.
+ * stops the keepalive timer when a frame has been sent out.
  */
-static int vdp_start_ackTimer(struct vsi_profile *profile)
+static void vdp_stop_keepaliveTimer(struct vsi_profile *profile)
 {
-	unsigned int secs, usecs, rte;
+	profile->keepaliveTimer = VDP_KEEPALIVE_TIMER_STOPPED;
 
-	profile->ackTimerExpired = false;
-
-	rte = evb_get_rte(profile->port->ifname);
-
-	secs = VDP_TRANSMISSION_TIMER(rte) / VDP_TRANSMISSION_DIVIDER;
-	usecs = VDP_TRANSMISSION_TIMER(rte) % VDP_TRANSMISSION_DIVIDER;
-
-	LLDPAD_DBG("%s(%i)-%s: starting ack timer (%i secs, %i usecs)\n", __func__, __LINE__,
-	       profile->port->ifname, secs, usecs);
-
-	return eloop_register_timeout(secs, usecs, vdp_acktimeout_handler, NULL, (void *) profile);
+	LLDPAD_DBG("%s(%i)-%s: stopping keepalive timer (%i)\n", __func__, __LINE__,
+	       profile->port->ifname, profile->keepaliveTimer);
 }
 
 /* vdp_vsi_change_station_state - changes the VDP station sm state
@@ -325,6 +316,7 @@ void vdp_vsi_change_station_state(struct vsi_profile *profile, u8 newstate)
 		break;
 	case VSI_DEASSOC_PROCESSING:
 		assert((profile->state == VSI_PREASSOCIATED) ||
+		       (profile->state == VSI_UNASSOCIATED) ||
 		       (profile->state == VSI_ASSOCIATED));
 		break;
 	case VSI_EXIT:
@@ -361,13 +353,21 @@ static bool vdp_vsi_set_station_state(struct vsi_profile *profile)
 		if ((profile->mode == VDP_MODE_PREASSOCIATE) ||
 		    (profile->mode == VDP_MODE_PREASSOCIATE_WITH_RR)) {
 			vdp_vsi_change_station_state(profile, VSI_PREASSOC_PROCESSING);
+			vdp_somethingChangedLocal(profile, true);
 			return true;
 		} else if (profile->mode == VDP_MODE_ASSOCIATE) {
 			vdp_vsi_change_station_state(profile, VSI_ASSOC_PROCESSING);
+			vdp_somethingChangedLocal(profile, true);
+			return true;
+		} else if (profile->mode == VDP_MODE_DEASSOCIATE) {
+			vdp_vsi_change_station_state(profile, VSI_DEASSOC_PROCESSING);
+			vdp_somethingChangedLocal(profile, true);
 			return true;
 		}
 		return false;
 	case VSI_ASSOC_PROCESSING:
+		LLDPAD_DBG("profile->ackReceived %i, vdp_ackTimer %i\n",
+			   profile->ackReceived, profile->ackTimer);
 		if (profile->ackReceived) {
 			vdp_vsi_change_station_state(profile, VSI_ASSOCIATED);
 			return true;
@@ -439,9 +439,10 @@ void vdp_vsi_sm_station(struct vsi_profile *profile)
 			break;
 		case VSI_ASSOC_PROCESSING:
 			profile->response = VDP_RESPONSE_NO_RESPONSE;
-			vdp_somethingChangedLocal(profile, true);
-			ecp_somethingChangedLocal(vd);
-			ecp_tx_run_sm(vd);
+			if (profile->localChange) {
+				ecp_somethingChangedLocal(vd);
+				ecp_tx_run_sm(vd);
+			}
 			vdp_somethingChangedLocal(profile, false);
 			vdp_start_ackTimer(profile);
 			break;
@@ -449,36 +450,33 @@ void vdp_vsi_sm_station(struct vsi_profile *profile)
 			profile->ackReceived = false;
 			vdp_somethingChangedLocal(profile, false);
 			vdp_stop_ackTimer(profile);
-			if (profile->keepaliveTimerExpired) {
+			if (vdp_keepaliveTimer_expired(profile)) {
 				vdp_somethingChangedLocal(profile, true);
 				ecp_somethingChangedLocal(vd);
 				ecp_tx_run_sm(vd);
+				vdp_start_keepaliveTimer(profile);
 			}
-			vdp_start_keepaliveTimer(profile);
-			 /* TODO:
-			  * vsiError = ProcRxandSetCfg(remoteTLV, localtlv, vsistate);
-			 *       if (!vsiError) vsistate=ASSOCIATED */
 			break;
 		case VSI_PREASSOC_PROCESSING:
 			/* send out profile */
 			profile->response = VDP_RESPONSE_NO_RESPONSE;
-			vdp_somethingChangedLocal(profile, true);
-			ecp_somethingChangedLocal(vd);
-			ecp_tx_run_sm(vd);
+			if (profile->localChange) {
+				ecp_somethingChangedLocal(vd);
+				ecp_tx_run_sm(vd);
+			}
+			vdp_somethingChangedLocal(profile, false);
 			vdp_start_ackTimer(profile);
 			break;
 		case VSI_PREASSOCIATED:
 			profile->ackReceived = false;
 			vdp_somethingChangedLocal(profile, false);
 			vdp_stop_ackTimer(profile);
-			if (profile->keepaliveTimerExpired) {
+			if (vdp_keepaliveTimer_expired(profile)) {
 				vdp_somethingChangedLocal(profile, true);
 				ecp_somethingChangedLocal(vd);
 				ecp_tx_run_sm(vd);
 			}
 			vdp_start_keepaliveTimer(profile);
-			/* TODO	 vsiError = ProcRxandSetCfg(remoteTLV, localtlv, vsistate);
-			 *       if (!vsiError) vsistate=PREASSOCIATED */
 			break;
 		case VSI_DEASSOC_PROCESSING:
 			profile->response = VDP_RESPONSE_NO_RESPONSE;
@@ -490,7 +488,6 @@ void vdp_vsi_sm_station(struct vsi_profile *profile)
 			break;
 		case VSI_EXIT:
 			/* TODO: send DEASSOC here ? */
-			vdp_stop_ackTimer(profile);
 			vdp_remove_profile(profile);
 			break;
 		default:
@@ -822,7 +819,7 @@ int vdp_indicate(struct vdp_data *vd, struct unpacked_tlv *tlv, int ecp_mode)
 				       __func__, __LINE__, p->localChange, p->ackReceived);
 
 				p->ackReceived = true;
-				p->keepaliveTimerExpired = false;
+				p->keepaliveTimer = VDP_KEEPALIVE_TIMER_DEFAULT;
 				p->mode = vdp->mode;
 				p->response = vdp->response;
 
@@ -1057,7 +1054,6 @@ struct vsi_profile *vdp_add_profile(struct vsi_profile *profile)
 		return NULL;
 	}
 
-	profile->keepaliveTimerExpired = true;
 	profile->response = VDP_RESPONSE_NO_RESPONSE;
 
 	vdp_print_profile(profile);
@@ -1150,16 +1146,8 @@ void vdp_ifdown(char *ifname)
 	if (ecp_deinit(ifname))
 		goto out_err;
 
-	LIST_REMOVE(vd, entry);
+	vdp_stop_timer(vd);
 
-	LIST_FOREACH(p, &vd->profile_head, profile) {
-		vdp_stop_ackTimer(p);
-		vdp_stop_keepaliveTimer(p);
-		LIST_REMOVE(p, profile);
-		free(p);
-	}
-	vdp_free_tlv(vd);
-	free(vd);
 	LLDPAD_INFO("%s:%s vdp data removed\n", __func__, ifname);
 	return;
 out_err:
@@ -1187,7 +1175,7 @@ void vdp_ifup(char *ifname)
 	vd = vdp_data(ifname);
 	if (vd) {
 		LLDPAD_WARN("%s:%s vdp data already exists !\n", __func__, ifname);
-		return;
+		goto out_start_timer;
 	}
 
 	/* not found, alloc/init per-port module data */
@@ -1222,6 +1210,12 @@ void vdp_ifup(char *ifname)
 		goto out_err;
 	}
 
+	vd->keepaliveTimer = VDP_KEEPALIVE_TIMER_DEFAULT;
+	vd->ackTimer = VDP_ACK_TIMER_DEFAULT;
+
+out_start_timer:
+	vdp_start_timer(vd);
+
 	LLDPAD_DBG("%s:%s vdp added\n", __func__, ifname);
 	return;
 
-- 
1.7.4.4