diff --git a/lldpad-0.9.41-reduce-number-of-select-timeouts-for-ECP.patch b/lldpad-0.9.41-reduce-number-of-select-timeouts-for-ECP.patch new file mode 100644 index 0000000..313bf99 --- /dev/null +++ b/lldpad-0.9.41-reduce-number-of-select-timeouts-for-ECP.patch @@ -0,0 +1,256 @@ +From aeb6d102f2b00c1799042cd02f079aa1f659d36c Mon Sep 17 00:00:00 2001 +From: Jens Osterkamp +Date: Wed, 4 May 2011 08:21:45 -0700 +Subject: [PATCH 2/3] reduce number of select timeouts for ECP + +A problem with the number of select timeouts has been reported in Redhat +bugzilla #694639 (https://bugzilla.redhat.com/show_bug.cgi?id=694639) and +by Will Cohen on the open-lldp mailing list. + +The number of select timeouts for any running applications can be measured +with 'stap -c "sleep 10" timeout.stp'. + +The high number of select timeouts was caused by the timers used in the ECP +code to control the timeout until when an ack has to be received and to +determine wether there is any work pending (e.g. changed profiles). + +This patch changes the timers from calling them at a regular interval to a +demand based model. For this it is necessary to setup a short-running timer +whenever work has been scheduled. This way the execution path returns to the +event loop much more often leaving other modules a chance to get work done. + +Signed-off-by: Jens Osterkamp +Signed-off-by: John Fastabend +Signed-off-by: Petr Sabata +--- + ecp/ecp.c | 104 ++++++++++++++++++++++++++++++++++++++++++++-------------- + ecp/ecp.h | 7 +++- + ecp/ecp_tx.c | 8 ++++- + 3 files changed, 91 insertions(+), 28 deletions(-) + +diff --git a/ecp/ecp.c b/ecp/ecp.c +index ea3558d..b4d075e 100644 +--- a/ecp/ecp.c ++++ b/ecp/ecp.c +@@ -37,9 +37,65 @@ + #include "lldp/l2_packet.h" + #include "ecp/ecp.h" + +-static int ecp_start_timer(struct vdp_data *vd); ++/* ecp_localchange_handler - triggers the processing of a local change ++ * @eloop_data: data structure of event loop ++ * @user_ctx: user context, vdp_data here ++ * ++ * no return value ++ * ++ * called from ecp_somethingchangedlocal when a change is pending. Calls ++ * the ECP tx station state machine. A oneshot handler. This detour is taken ++ * to not having to call the ecp code from the vdp state machine. Instead, we ++ * return to the event loop, giving other code a chance to do work. ++ */ ++void ecp_localchange_handler(void *eloop_data, void *user_ctx) ++{ ++ struct vdp_data *vd; ++ ++ vd = (struct vdp_data *) user_ctx; ++ ++ if (vd->ecp.tx.localChange) { ++ LLDPAD_DBG("%s(%i)-%s: ecp.tx.localChange %i!\n", ++ __func__, __LINE__, ++ vd->ifname, vd->ecp.tx.localChange); ++ ecp_tx_run_sm(vd); ++ } ++} ++ ++/* ecp_start_localchange_timer - starts the ECP localchange timer ++ * @vd: vdp_data for the interface ++ * ++ * returns 0 on success, -1 on error ++ * ++ * starts the ECP localchange timer when a localchange has been signaled from ++ * the VDP state machine. ++ */ ++int ecp_start_localchange_timer(struct vdp_data *vd) ++{ ++ unsigned int usecs; ++ ++ usecs = ECP_LOCALCHANGE_TIMEOUT; ++ ++ return eloop_register_timeout(0, usecs, ecp_localchange_handler, NULL, (void *) vd); ++} + +-/* ecp_timeout_handler - handles the timer expiry ++/* ecp_stop_localchange_timer - stop the ECP localchange timer ++ * @vd: vdp_data for the interface ++ * ++ * returns the number of removed handlers ++ * ++ * stops the ECP localchange timer. Used e.g. when the host interface goes down. ++ */ ++static int ecp_stop_localchange_timer(struct vdp_data *vd) ++{ ++ LLDPAD_DBG("%s(%i)-%s: stopping ecp localchange timer\n", __func__, __LINE__, ++ vd->ifname); ++ ++ return eloop_cancel_timeout(ecp_localchange_handler, NULL, (void *) vd); ++} ++ ++ ++/* ecp_ack_timeout_handler - handles the ack timer expiry + * @eloop_data: data structure of event loop + * @user_ctx: user context, vdp_data here + * +@@ -47,58 +103,55 @@ static int ecp_start_timer(struct vdp_data *vd); + * + * called when the ECP timer has expired. Calls the ECP station state machine. + */ +-void ecp_timeout_handler(void *eloop_data, void *user_ctx) ++void ecp_ack_timeout_handler(void *eloop_data, void *user_ctx) + { + struct vdp_data *vd; + + vd = (struct vdp_data *) user_ctx; + + if (vd->ecp.ackTimer > 0) +- vd->ecp.ackTimer--; ++ vd->ecp.ackTimer -= ECP_ACK_TIMER_DEFAULT; + +- if ((ecp_ackTimer_expired(vd) == true) || +- vd->ecp.tx.localChange) { ++ if (ecp_ackTimer_expired(vd) == true) { + LLDPAD_DBG("%s(%i)-%s: ecp_ackTimer_expired (%i) !\n", + __func__, __LINE__, vd->ifname, vd->ecp.ackTimer); +- LLDPAD_DBG("%s(%i)-%s: ecp.tx.localChange %i!\n", +- __func__, __LINE__, +- vd->ifname, vd->ecp.tx.localChange); + ecp_tx_run_sm(vd); ++ } else { ++ LLDPAD_DBG("%s(%i)-%s: BUG ! handler called but" ++ "vdp->ecp.ackTimer not expired (%i) !\n", ++ __func__, __LINE__, vd->ecp.ackTimer); + } +- +- ecp_start_timer(vd); + } + +-/* ecp_start_timer - starts the ECP timer ++/* ecp_start_ack_timer - starts the ECP ack timer + * @vd: vdp_data for the interface + * + * returns 0 on success, -1 on error + * +- * starts the ECP timer when the interface comes up. ++ * starts the ECP ack timer when a frame has been sent out. + */ +-static int ecp_start_timer(struct vdp_data *vd) ++int ecp_start_ack_timer(struct vdp_data *vd) + { +- unsigned int secs, usecs; ++ unsigned int usecs; + +- secs = 0; +- usecs = ECP_TIMER_GRANULARITY; ++ usecs = ECP_ACK_TIMER_DEFAULT; + +- return eloop_register_timeout(secs, usecs, ecp_timeout_handler, NULL, (void *) vd); ++ return eloop_register_timeout(0, usecs, ecp_ack_timeout_handler, NULL, (void *) vd); + } + +-/* ecp_stop_timer - stop the ECP timer ++/* ecp_stop_ack_timer - stop the ECP ack timer + * @vd: vdp_data for the interface + * + * returns the number of removed handlers + * +- * stops the ECP timer. Used e.g. when the host interface goes down. ++ * stops the ECP ack timer. Used e.g. when the host interface goes down. + */ +-static int ecp_stop_timer(struct vdp_data *vd) ++int ecp_stop_ack_timer(struct vdp_data *vd) + { +- LLDPAD_DBG("%s(%i)-%s: stopping ecp timer\n", __func__, __LINE__, ++ LLDPAD_DBG("%s(%i)-%s: stopping ecp ack timer\n", __func__, __LINE__, + vd->ifname); + +- return eloop_cancel_timeout(ecp_timeout_handler, NULL, (void *) vd); ++ return eloop_cancel_timeout(ecp_ack_timeout_handler, NULL, (void *) vd); + } + + /* ecp_init - initialize ecp module +@@ -138,7 +191,7 @@ int ecp_init(char *ifname) + ecp_rx_change_state(vd, ECP_RX_IDLE); + ecp_rx_run_sm(vd); + +- ecp_start_timer(vd); ++ ecp_somethingChangedLocal(vd, true); + + return 0; + +@@ -159,7 +212,8 @@ int ecp_deinit(char *ifname) + goto fail; + } + +- ecp_stop_timer(vd); ++ ecp_stop_ack_timer(vd); ++ ecp_stop_localchange_timer(vd); + ecp_tx_stop_ackTimer(vd); + + return 0; +diff --git a/ecp/ecp.h b/ecp/ecp.h +index c18b6d7..35fcf46 100644 +--- a/ecp/ecp.h ++++ b/ecp/ecp.h +@@ -34,8 +34,11 @@ + #define ECP_MAX_RETRIES 3 + #define ECP_SEQUENCE_NR_START 0x0 + +-#define ECP_ACK_TIMER_DEFAULT 50 /* 500 ms in 10 ms chunks */ +-#define ECP_TIMER_GRANULARITY 10000 /* 10 ms in us */ ++#define MSECS 1000 ++#define SECS 1000*MSECS ++ ++#define ECP_ACK_TIMER_DEFAULT 500*MSECS /* 500 ms */ ++#define ECP_LOCALCHANGE_TIMEOUT 1*MSECS /* 1 ms */ + + #define ECP_ACK_TIMER_STOPPED -1 + +diff --git a/ecp/ecp_tx.c b/ecp/ecp_tx.c +index ebf9e4b..ba96c6b 100644 +--- a/ecp/ecp_tx.c ++++ b/ecp/ecp_tx.c +@@ -53,11 +53,13 @@ void ecp_somethingChangedLocal(struct vdp_data *vd, bool flag) + if (!vd) + return; + +- LLDPAD_DBG("%s(%i): vd->ecp.tx.localChange to %s.", __func__, ++ LLDPAD_DBG("%s(%i): vd->ecp.tx.localChange to %s.\n", __func__, + __LINE__, (flag == true) ? "true" : "false"); + + vd->ecp.tx.localChange = flag; + ++ ecp_start_localchange_timer(vd); ++ + return; + } + +@@ -288,6 +290,8 @@ void ecp_tx_stop_ackTimer(struct vdp_data *vd) + + LLDPAD_DBG("%s(%i)-%s: stopped ecp ack timer\n", __func__, __LINE__, + vd->ifname); ++ ++ ecp_stop_ack_timer(vd); + } + + /* ecp_tx_start_ackTimer - starts the ECP ack timer +@@ -303,6 +307,8 @@ static void ecp_tx_start_ackTimer(struct vdp_data *vd) + + LLDPAD_DBG("%s(%i)-%s: starting ecp ack timer\n", __func__, __LINE__, + vd->ifname); ++ ++ ecp_start_ack_timer(vd); + } + + /* ecp_ackTimer_expired - checks for expired ack timer +-- +1.7.4.4 + diff --git a/lldpad-0.9.41-reduce-number-of-select-timeouts-for-VDP.patch b/lldpad-0.9.41-reduce-number-of-select-timeouts-for-VDP.patch new file mode 100644 index 0000000..6441ed9 --- /dev/null +++ b/lldpad-0.9.41-reduce-number-of-select-timeouts-for-VDP.patch @@ -0,0 +1,432 @@ +From 08a6ea57ef76248e439f94a77f74c80ab500d2db Mon Sep 17 00:00:00 2001 +From: Jens Osterkamp +Date: Wed, 4 May 2011 08:23:19 -0700 +Subject: [PATCH 3/3] reduce number of select timeouts for VDP + +A problem with the number of select timeouts has been reported in Redhat +bugzilla #694639 (https://bugzilla.redhat.com/show_bug.cgi?id=694639) and +by Will Cohen on the open-lldp mailing list. + +The number of select timeouts for any running applications can be measured +with 'stap -c "sleep 10" timeout.stp'. + +The high number of select timeouts was caused by the timers used in the VDP +code to control the ack and keepalive interval as well as to determine wether +there is any work pending (e.g. changed profiles or received acks). + +This patch changes the timers from calling them at a regular interval to a +demand based model. For this it is necessary to setup a short-running timer +whenever work has been scheduled. This way the execution path returns to the +event loop much more often leaving other modules a chance to get work done. + +Signed-off-by: Jens Osterkamp +Signed-off-by: Petr Sabata +--- + include/lldp_vdp.h | 6 +- + lldp_vdp.c | 234 ++++++++++++++++++++++++++++++++------------------- + 2 files changed, 150 insertions(+), 90 deletions(-) + +diff --git a/include/lldp_vdp.h b/include/lldp_vdp.h +index 4b7054b..947ae31 100644 +--- a/include/lldp_vdp.h ++++ b/include/lldp_vdp.h +@@ -64,11 +64,12 @@ static char *vsi_responses[] = { + + #define VDP_MACVLAN_FORMAT_1 1 + +-#define VDP_TIMER_GRANULARITY 10000 /* 10 ms in us */ +-#define VDP_KEEPALIVE_TIMER_DEFAULT 1000 /* 10s in 10ms chunks */ ++#define VDP_TIMER_GRANULARITY 100*MSECS /* 100 ms */ ++#define VDP_KEEPALIVE_TIMER_DEFAULT 10*SECS /* 10s */ + #define VDP_ACK_TIMER_DEFAULT (2*ECP_ACK_TIMER_DEFAULT*ECP_MAX_RETRIES) + #define VDP_KEEPALIVE_TIMER_STOPPED -1 + #define VDP_ACK_TIMER_STOPPED -1 ++#define VDP_LOCALCHANGE_TIMEOUT 1*MSECS /* 1 ms */ + + #define VDP_ROLE_STATION 0 + #define VDP_ROLE_BRIDGE 1 +@@ -155,7 +156,6 @@ 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 7be0b1c..4b2ce6a 100644 +--- a/lldp_vdp.c ++++ b/lldp_vdp.c +@@ -143,8 +143,10 @@ void vdp_ack_profiles(struct vdp_data *vd, int seqnr) + struct vsi_profile *p; + + LIST_FOREACH(p, &vd->profile_head, profile) { +- if (p->seqnr == seqnr) ++ if (p->seqnr == seqnr) { + p->ackReceived = true; ++ vdp_start_localchange_timer(p); ++ } + } + + } +@@ -205,7 +207,13 @@ int vdp_vsis_pending(struct vdp_data *vd) + */ + void vdp_somethingChangedLocal(struct vsi_profile *profile, bool flag) + { ++ LLDPAD_DBG("%s(%i): setting profile->localChange to %s.\n", ++ __func__, __LINE__, (flag == true) ? "true" : "false"); ++ + profile->localChange = flag; ++ ++ if (flag == true) ++ vdp_start_localchange_timer(profile); + } + + /* vdp_keepaliveTimer_expired - checks for expired ack timer +@@ -234,147 +242,182 @@ static bool vdp_ackTimer_expired(struct vsi_profile *profile) + return (profile->ackTimer == 0); + } + +-/* vdp_timeout_handler - handles the timer expiry ++/* vdp_localchange_handler - triggers in case of ackReceived or on vdp localchange + * @eloop_data: data structure of event loop + * @user_ctx: user context, vdp_data here + * + * no return value + * +- * called when the VDP timer has expired. Decrements ack and keepaliveTimer +- * and calls the VDP station state machine if necessary. ++ * called from vdp_somethingchangedlocal or vdp_ack_profiles when a change is ++ * pending. Calls the VDP station state machine. This detour is taken ++ * to not having to call the vdp code from the ecp state machine. Instead, we ++ * return to the event loop, giving other code a chance to do work. + */ +-void vdp_timeout_handler(void *eloop_data, void *user_ctx) ++void vdp_localchange_handler(void *eloop_data, void *user_ctx) + { +- struct vdp_data *vd; + struct vsi_profile *p; + +- vd = (struct vdp_data *) user_ctx; +- +- vd->nroftimers--; ++ p = (struct vsi_profile *) user_ctx; + +- LIST_FOREACH(p, &vd->profile_head, profile) { +- if (p->ackTimer > 0) +- p->ackTimer--; +- +- if (p->keepaliveTimer > 0) +- p->keepaliveTimer--; +- +- if (vdp_ackTimer_expired(p) || +- vdp_keepaliveTimer_expired(p) || +- p->ackReceived) { +- LLDPAD_DBG("%s(%i): profile 0x%02x\n", +- __func__, __LINE__, p->instance[15]); +- LLDPAD_DBG("%s(%i): vdp_ackTimer_expired %i\n", +- __func__, __LINE__, vdp_ackTimer_expired(p)); +- LLDPAD_DBG("%s(%i): p->ackReceived %i\n", +- __func__, __LINE__, p->ackReceived); +- LLDPAD_DBG("%s(%i): vdp_keepaliveTimer_expired %i\n", +- __func__, __LINE__, +- vdp_keepaliveTimer_expired(p)); +- vdp_vsi_sm_station(p); +- } ++ if ((p->ackReceived) || (p->localChange)) { ++ LLDPAD_DBG("%s(%i): p->localChange %i!\n", ++ __func__, __LINE__, p->localChange); ++ LLDPAD_DBG("%s(%i): p->ackReceived %i!\n", ++ __func__, __LINE__, p->ackReceived); ++ vdp_vsi_sm_station(p); + } +- +- vdp_start_timer(vd); + } + +-/* vdp_stop_timer - stop the VDP timer ++/* vdp_start_localchange_timer - starts the VDP localchange timer + * @vd: vdp_data for the interface + * +- * returns the number of removed handlers ++ * returns 0 on success, -1 on error + * +- * stops the VDP timer. Used e.g. when the host interface goes down. ++ * starts the VPP localchange timer when a localchange has been signaled from ++ * the VDP state machine. + */ +-static int vdp_stop_timer(struct vdp_data *vd) ++int vdp_start_localchange_timer(struct vsi_profile *p) + { +- LLDPAD_DBG("%s(%i)-%s: stopping vdp timer\n", __func__, __LINE__, +- vd->ifname); ++ unsigned int usecs; + +- vd->nroftimers--; ++ usecs = VDP_LOCALCHANGE_TIMEOUT; + +- return eloop_cancel_timeout(vdp_timeout_handler, NULL, (void *) vd); ++ return eloop_register_timeout(0, usecs, vdp_localchange_handler, NULL, (void *) p); + } + +-/* vdp_start_timer - starts the VDP timer +- * @vd: vdp_data for the interface ++/* vdp_ack_timeout_handler - handles the ack timer expiry ++ * @eloop_data: data structure of event loop ++ * @user_ctx: user context, vdp_data here + * +- * returns 0 on success, -1 on error ++ * no return value + * +- * starts the VDP timer when the interface comes up. ++ * called when the VDP ack timer for a profile has expired. ++ * Calls the VDP station state machine for the profile. + */ +-static int vdp_start_timer(struct vdp_data *vd) ++void vdp_ack_timeout_handler(void *eloop_data, void *user_ctx) + { +- unsigned int secs, usecs, rte; +- +- secs = 0; +- usecs = VDP_TIMER_GRANULARITY; +- +- vd->nroftimers++; +- +- if (vd->nroftimers > 1) { +- LLDPAD_WARN("%s(%i)-%s: nroftimers %i !\n", __func__, __LINE__, +- vd->ifname, vd->nroftimers); +- vd->nroftimers--; +- return 0; ++ struct vsi_profile *p = (struct vsi_profile *) user_ctx; ++ ++ if (p->ackTimer > 0) ++ p->ackTimer -= VDP_ACK_TIMER_DEFAULT; ++ ++ if (vdp_ackTimer_expired(p)) { ++ LLDPAD_DBG("%s(%i): profile 0x%02x\n", ++ __func__, __LINE__, p->instance[15]); ++ LLDPAD_DBG("%s(%i): vdp_ackTimer_expired %i\n", ++ __func__, __LINE__, vdp_ackTimer_expired(p)); ++ LLDPAD_DBG("%s(%i): p->ackReceived %i\n", ++ __func__, __LINE__, p->ackReceived); ++ vdp_vsi_sm_station(p); + } +- +- return eloop_register_timeout(secs, usecs, vdp_timeout_handler, NULL, (void *) vd); + } + +-/* vdp_start_ackTimer - starts the VDP ack timer +- * @profile: profile to process ++/* vdp_start_ack_timer - starts the VDP profile ack timer ++ * @profile: vsi_profile ++ * ++ * returns 0 on success, -1 on error + * +- * starts the ack timer when a frame has been sent out. ++ * starts the VDP profile ack timer when a profile has been handed to ecp for ++ * transmission. + */ +-static void vdp_start_ackTimer(struct vsi_profile *profile) ++static int vdp_start_ackTimer(struct vsi_profile *profile) + { ++ unsigned int usecs; ++ ++ usecs = VDP_ACK_TIMER_DEFAULT; ++ + profile->ackTimer = VDP_ACK_TIMER_DEFAULT; + + LLDPAD_DBG("%s(%i)-%s: starting ack timer for 0x%02x (%i)\n", + __func__, __LINE__, profile->port->ifname, + profile->instance[15], profile->ackTimer); ++ ++ return eloop_register_timeout(0, usecs, vdp_ack_timeout_handler, NULL, (void *) profile); + } + +-/* vdp_start_keepaliveTimer - starts the VDP keepalive timer for a profile +- * @profile: profile to process ++/* vdp_stop_ackTimer - stops the VDP profile ack timer ++ * @vd: vdp_data for the interface ++ * ++ * returns the number of removed handlers + * +- * starts the keepalive timer when a frame has been sent out. ++ * stops the VDP tck imer. Used e.g. when the host interface goes down. + */ +-static void vdp_start_keepaliveTimer(struct vsi_profile *profile) ++static int vdp_stop_ackTimer(struct vsi_profile *profile) + { +- profile->keepaliveTimer = VDP_KEEPALIVE_TIMER_DEFAULT; +- +- LLDPAD_DBG("%s(%i)-%s: starting keepalive timer for 0x%02x (%i)\n", ++ LLDPAD_DBG("%s(%i)-%s: stopping ack timer for 0x%02x (%i)\n", + __func__, __LINE__, profile->port->ifname, +- profile->instance[15], profile->keepaliveTimer); ++ profile->instance[15], profile->ackTimer); ++ ++ return eloop_cancel_timeout(vdp_ack_timeout_handler, NULL, (void *) profile); + } + +-/* vdp_stop_ackTimer - stops the VDP ack timer +- * @profile: profile to process ++/* vdp_keepalive_timeout_handler - handles the keepalive timer expiry ++ * @eloop_data: data structure of event loop ++ * @user_ctx: user context, vdp_data here ++ * ++ * no return value + * +- * stops the ack timer when a frame has been sent out. ++ * called when the VDP keepalive timer for a profile has expired. ++ * Calls the VDP station state machine for the profile. + */ +-static void vdp_stop_ackTimer(struct vsi_profile *profile) ++void vdp_keepalive_timeout_handler(void *eloop_data, void *user_ctx) + { +- profile->ackTimer = VDP_ACK_TIMER_STOPPED; ++ struct vsi_profile *p = (struct vsi_profile *) user_ctx; ++ ++ if (p->keepaliveTimer > 0) ++ p->keepaliveTimer -= VDP_KEEPALIVE_TIMER_DEFAULT; ++ ++ if (vdp_keepaliveTimer_expired(p)) { ++ LLDPAD_DBG("%s(%i): profile 0x%02x\n", ++ __func__, __LINE__, p->instance[15]); ++ LLDPAD_DBG("%s(%i): vdp_keepaliveTimer_expired %i\n", ++ __func__, __LINE__, vdp_keepaliveTimer_expired(p)); ++ LLDPAD_DBG("%s(%i): p->ackReceived %i\n", ++ __func__, __LINE__, p->ackReceived); ++ vdp_vsi_sm_station(p); ++ } ++} + +- LLDPAD_DBG("%s(%i)-%s: stopping ack timer for 0x%02x (%i)\n", ++/* vdp_start_keepalive_timer - starts the VDP profile keepalive timer ++ * @vd: vdp_data for the interface ++ * ++ * returns 0 on success, -1 on error ++ * ++ * starts the VDP profile keepalive timer when a profile has been handed to ecp for ++ * transmission. ++ */ ++static int vdp_start_keepaliveTimer(struct vsi_profile *profile) ++{ ++ unsigned int usecs; ++ ++ usecs = VDP_KEEPALIVE_TIMER_DEFAULT; ++ ++ profile->keepaliveTimer = VDP_KEEPALIVE_TIMER_DEFAULT; ++ ++ LLDPAD_DBG("%s(%i)-%s: starting keepalive timer for 0x%02x (%i)\n", + __func__, __LINE__, profile->port->ifname, +- profile->instance[15], profile->ackTimer); ++ profile->instance[15], profile->keepaliveTimer); ++ ++ return eloop_register_timeout(0, usecs, vdp_keepalive_timeout_handler, ++ NULL, (void *) profile); + } + +-/* vdp_stop_keepaliveTimer - stops the VDP keepalive timer for a profile +- * @profile: profile to process ++/* vdp_stop_keepalive_timer - stops the VDP profile keepalive timer ++ * @vd: vdp_data for the interface ++ * ++ * returns the number of removed handlers + * +- * stops the keepalive timer when a frame has been sent out. ++ * stops the VDP tck imer. Used e.g. when the host interface goes down. + */ +-static void vdp_stop_keepaliveTimer(struct vsi_profile *profile) ++static int vdp_stop_keepaliveTimer(struct vsi_profile *profile) + { + profile->keepaliveTimer = VDP_KEEPALIVE_TIMER_STOPPED; + + LLDPAD_DBG("%s(%i)-%s: stopping keepalive timer for 0x%02x (%i)\n", + __func__, __LINE__, profile->port->ifname, + profile->instance[15], profile->keepaliveTimer); ++ ++ return eloop_cancel_timeout(vdp_keepalive_timeout_handler, NULL, (void *) profile); + } + + static bool vdp_vsi_negative_response(struct vsi_profile *profile) +@@ -560,6 +603,7 @@ void vdp_vsi_sm_station(struct vsi_profile *profile) + profile->response = VDP_RESPONSE_NO_RESPONSE; + if (profile->localChange) { + ecp_somethingChangedLocal(vd, true); ++ profile->ackReceived = false; + vdp_start_ackTimer(profile); + } + break; +@@ -573,6 +617,7 @@ void vdp_vsi_sm_station(struct vsi_profile *profile) + vdp_stop_keepaliveTimer(profile); + profile->response = VDP_RESPONSE_NO_RESPONSE; + if (profile->localChange) { ++ profile->ackReceived = false; + ecp_somethingChangedLocal(vd, true); + vdp_start_ackTimer(profile); + } +@@ -588,6 +633,7 @@ void vdp_vsi_sm_station(struct vsi_profile *profile) + vdp_stop_keepaliveTimer(profile); + profile->response = VDP_RESPONSE_NO_RESPONSE; + if (profile->localChange) { ++ profile->ackReceived = false; + ecp_somethingChangedLocal(vd, true); + vdp_start_ackTimer(profile); + } +@@ -1271,7 +1317,12 @@ void vdp_ifdown(char *ifname) + if (ecp_deinit(ifname)) + goto out_err; + +- vdp_stop_timer(vd); ++ LIST_FOREACH(p, &vd->profile_head, profile) { ++ if (p->ackTimer > 0) ++ vdp_stop_ackTimer(p); ++ if (p->keepaliveTimer > 0) ++ vdp_stop_keepaliveTimer(p); ++ } + + LLDPAD_INFO("%s:%s vdp data removed\n", __func__, ifname); + return; +@@ -1291,10 +1342,11 @@ out_err: + */ + void vdp_ifup(char *ifname) + { +- char *p; ++ char *string; + struct vdp_data *vd; + struct vdp_user_data *ud; + struct port *port; ++ struct vsi_profile *p; + + LLDPAD_DBG("%s(%i): starting VDP for if %s !\n", __func__, __LINE__, ifname); + +@@ -1315,9 +1367,9 @@ void vdp_ifup(char *ifname) + + vd->role = VDP_ROLE_STATION; + +- if (!get_cfg(ifname, "vdp.role", (void *)&p, ++ if (!get_cfg(ifname, "vdp.role", (void *)&string, + CONFIG_TYPE_STRING)) { +- if (!strcasecmp(p, VAL_BRIDGE)) { ++ if (!strcasecmp(string, VAL_BRIDGE)) { + vd->role = VDP_ROLE_BRIDGE; + } + } +@@ -1356,7 +1408,15 @@ out_start_again: + + LLDPAD_DBG("%s(%i)-%s: starting vdp timer (%i)\n", __func__, __LINE__, + vd->ifname, vd->nroftimers); +- vdp_start_timer(vd); ++ ++ LIST_FOREACH(p, &vd->profile_head, profile) { ++ if (p->ackTimer > 0) { ++ vdp_somethingChangedLocal(p, true); ++ vdp_start_ackTimer(p); ++ } ++ if (p->keepaliveTimer > 0) ++ vdp_start_keepaliveTimer(p); ++ } + + LLDPAD_DBG("%s:%s vdp added\n", __func__, ifname); + return; +-- +1.7.4.4 + diff --git a/lldpad-0.9.41-support-disabling-of-LLDP-on-switch-side.patch b/lldpad-0.9.41-support-disabling-of-LLDP-on-switch-side.patch new file mode 100644 index 0000000..d6d2217 --- /dev/null +++ b/lldpad-0.9.41-support-disabling-of-LLDP-on-switch-side.patch @@ -0,0 +1,71 @@ +From 76dbd2e24ff64fe7ae1503c658614e44a0a4e2e4 Mon Sep 17 00:00:00 2001 +From: Jens Osterkamp +Date: Wed, 4 May 2011 08:21:42 -0700 +Subject: [PATCH 1/3] support disabling of LLDP on switch side + +In case LLDP is disabled on the switch side, the switch will send a LLDP +frame with chassis, port and TTL with TTL set to 0. +In this case evb_mibdelete is called to reset the previously negotiated EVB +data. + +Signed-off-by: Jens Osterkamp +Signed-off-by: John Fastabend +Signed-off-by: Petr Sabata +--- + lldp_evb.c | 33 +++++++++++++++++++++++++++++++++ + 1 files changed, 33 insertions(+), 0 deletions(-) + +diff --git a/lldp_evb.c b/lldp_evb.c +index 0839054..b3d756b 100644 +--- a/lldp_evb.c ++++ b/lldp_evb.c +@@ -594,6 +594,38 @@ out_err: + return; + } + ++u8 evb_mibdelete(struct port *port) ++{ ++ struct evb_data *ed; ++ ++ if (!is_tlv_txenabled(port->ifname, TLVID_8021Qbg(LLDP_EVB_SUBTYPE))) { ++ goto out_err; ++ } ++ ++ LLDPAD_DBG("%s(%i): mibdelete triggered for port %s.\n", __func__, ++ __LINE__, port->ifname); ++ ++ ed = evb_data(port->ifname); ++ if (!ed) { ++ LLDPAD_DBG("%s:%s does not exist.\n", __func__, port->ifname); ++ goto out_err; ++ } ++ ++ free(ed->tie); ++ free(ed->last); ++ free(ed->policy); ++ ++ if (evb_init_cfg_tlv(ed)) { ++ LLDPAD_ERR("%s:%s evb_init_cfg_tlv failed\n", __func__, port->ifname); ++ goto out_err; ++ } ++ ++ evb_bld_tlv(ed); ++ ++out_err: ++ return 0; ++} ++ + static const struct lldp_mod_ops evb_ops = { + .lldp_mod_register = evb_register, + .lldp_mod_unregister = evb_unregister, +@@ -601,6 +633,7 @@ static const struct lldp_mod_ops evb_ops = { + .lldp_mod_rchange = evb_rchange, + .lldp_mod_ifup = evb_ifup, + .lldp_mod_ifdown = evb_ifdown, ++ .lldp_mod_mibdelete = evb_mibdelete, + .get_arg_handler = evb_get_arg_handlers, + }; + +-- +1.7.4.4 + diff --git a/lldpad.spec b/lldpad.spec index 6baca9c..3f0661d 100644 --- a/lldpad.spec +++ b/lldpad.spec @@ -1,6 +1,6 @@ Name: lldpad Version: 0.9.41 -Release: 2%{?dist} +Release: 3%{?dist} Summary: Intel LLDP Agent Group: System Environment/Daemons @@ -64,6 +64,9 @@ Patch148: lldpad-0.9.41-lldpad-dormantTimer-should-not-be-touched-by-modul Patch149: lldpad-0.9.41-lldpad-dcbx-dropped-ifdown-messages-breaks-module.patch Patch150: lldpad-0.9.41-lldpad-DCB-remove-iSCSI-tc-qdisc-and-filters.patch Patch151: lldpad-0.9.41-lldpad-make-debug-messages-from-netlink-path-helpful.patch +Patch152: lldpad-0.9.41-support-disabling-of-LLDP-on-switch-side.patch +Patch153: lldpad-0.9.41-reduce-number-of-select-timeouts-for-ECP.patch +Patch154: lldpad-0.9.41-reduce-number-of-select-timeouts-for-VDP.patch Requires: kernel >= 2.6.32 BuildRequires: libconfig-devel >= 1.3.2 kernel-headers >= 2.6.32 @@ -145,6 +148,9 @@ that use %{name}. %patch149 -p1 %patch150 -p1 %patch151 -p1 +%patch152 -p1 +%patch153 -p1 +%patch154 -p1 # Fedora patches on top of that... %patch0 -p1 -b .make %patch1 -p1 -b .init @@ -211,6 +217,9 @@ fi %changelog +* Wed May 4 2011 Petr Sabata - 0.9.41-3 +- Fix the frequent, power consuming lldpad wake-ups (rhbz#701943) + * Thu Apr 21 2011 Petr Sabata - 0.9.41-2 - Bring in upstream 802.1Qbg bugfixes