On Tuesday 12 October 2010, John Fastabend wrote:
> On 9/28/2010 8:10 AM, Jens Osterkamp wrote:
> > This is the implementation of the edge control protocol (ECP) and VSI
> > discovery protocol (VDP) currently being specified in IEEE 802.1Qbg.
> >
> > This implementation extends the infrastructure defined lldpad to send and
> > receive ECP frames with a new (yet to be defined) ethertype.
> > Received frames are validated and analyzed before the content is handed to
> > the
> > upper layer protocol (ULP, VDP in this case) for further processing. Frames
> > to be transmitted are compiled from VSI (guest interface) profiles
> > registered
> > on a interface.
> > Reception and transmission of ECP frames is controlled by RX and TX state
> > machines, timeouts are handled timeout functions.
> > The patch still contains a lot of debug code to allow low-level protocol
> > analysis.
> >
> > VDP serves as the upper layer protocol (ULP) for TLVs communicated via the
> > ECP protocol.
> > For this it registers as a new module in lldpad. The VDP module supports a
> > station and a bridge role. As a station, new VSI (virtual station interface)
> > profiles can be registered to the VDP module using lldptool or libvirt.
> > These profiles are then announced to an adjacent switch. Transmitted
> > profiles
> > are processed to the desired state by the VDP station state machine.
> > As a bridge, the VDP module waits for new profiles received in TLVs by ECP.
> > The received profiles are processed to the desired state by a VDP bridge
> > state machine.
> >
> > VDP module parameters are stored in the "vdp" section under the appropriate
> > interface.
> >
> > The patch still contains a lot of debug code to allow analysis of VDP
> > protocol behavior.
> >
> > Signed-off-by: Jens Osterkamp <[email protected]>
> > ---
> > Makefile.am | 10 +-
> > ecp/ecp.c | 79 ++++
> > ecp/ecp.h | 101 +++++
> > ecp/ecp_rx.c | 599 ++++++++++++++++++++++++++
> > ecp/ecp_tx.c | 494 ++++++++++++++++++++++
> > include/lldp.h | 1 +
> > include/lldp_evb.h | 6 +
> > include/lldp_vdp.h | 159 +++++++
> > lldp/l2_packet.h | 2 +
> > lldp/ports.h | 11 +-
> > lldp_vdp.c | 1185
> > ++++++++++++++++++++++++++++++++++++++++++++++++++++
> > lldpad.c | 2 +
> > 12 files changed, 2642 insertions(+), 7 deletions(-)
> > create mode 100644 ecp/ecp.c
> > create mode 100644 ecp/ecp.h
> > create mode 100644 ecp/ecp_rx.c
> > create mode 100644 ecp/ecp_tx.c
> > create mode 100644 include/lldp_vdp.h
> > create mode 100644 lldp_vdp.c
> >
[snip]
> > + return false;
> > + case ECP_RX_RECEIVE_ECPDU:
> > + if (vd->ecp.seqECPDU == vd->ecp.lastSequence) {
> > + printf("%s(%i):-(%s) seqECPDU %x, lastSequence
> > %x\n", __func__, __LINE__,
> > + vd->ifname, vd->ecp.seqECPDU,
> > vd->ecp.lastSequence);
> > + ecp_rx_change_state(vd, ECP_RX_RESEND_ACK);
> > + return true;
> > + }
> > + if (vd->ecp.seqECPDU != vd->ecp.lastSequence) {
> > + ecp_rx_change_state(vd, ECP_RX_RESEND_ACK);
> > + return true;
> > + }
> > + return false;
> > + case ECP_RX_SEND_ACK:
>
> How can we get to this state? Did I miss something or could the
> ECP_RX_SEND_ACK and ECP_RX_RESEND_ACK states be combined or ECP_RX_SEND_ACK
> removed outright?
Yep, can be combined but not entirely removed because different actions need to
be taken for both states according to draft. Fixed in my next series.
>
> > + ecp_rx_change_state(vd, ECP_RX_RECEIVE_WAIT);
> > + return false;
> > + case ECP_RX_RESEND_ACK:
> > + ecp_rx_change_state(vd, ECP_RX_RECEIVE_WAIT);
> > + return false;
> > + default:
> > + printf("ERROR: The ECP_RX State Machine is broken!\n");
> > + log_message(MSG_ERR_RX_SM_INVALID, "%s", vd->ifname);
> > + return false;
[snip]
> > + if ((ptlv->size+fb_offset) > ETH_MAX_DATA_LEN)
> > + goto error;
> > + memcpy(vd->ecp.tx.frameout+fb_offset,
> > + ptlv->tlv, ptlv->size);
> > + datasize += ptlv->size;
> > + fb_offset += ptlv->size;
>
> I think the ptlv needs to be free'd here? Else where is it getting free'd.
Fixed in my next series.
>
> > + }
> > + }
> > +
> > + /* The End TLV marks the end of the LLDP PDU */
> > + ptlv = pack_end_tlv();
> > + if (!ptlv || ((ptlv->size + fb_offset) > ETH_MAX_DATA_LEN))
> > + goto error;
> > + memcpy(vd->ecp.tx.frameout + fb_offset, ptlv->tlv, ptlv->size);
> > + datasize += ptlv->size;
> > + fb_offset += ptlv->size;
> > + ptlv = free_pkd_tlv(ptlv);
> > +
> > + if (datasize > ETH_MAX_DATA_LEN)
[snip]
> > +
> > + memset(vdp, 0, sizeof(struct tlv_info_vdp));
> > + memcpy(vdp, tlv->info, tlv->length);
> > +
> > + if (vdp_validate_tlv(vdp)) {
> > + printf("%s(%i): Invalid TLV received !\n", __func__,
> > __LINE__);
> > + goto out_err;
>
> Should be goto out_vdp
Fixed.
>
> > + }
> > +
> > + profile = malloc(sizeof(struct vsi_profile));
> > +
> > + if (!profile) {
> > + printf("%s(%i): unable to allocate profile !\n", __func__,
> > __LINE__);
> > + goto out_vdp;
> > + }
> > +
> > + memset(profile, 0, sizeof(struct vsi_profile));
> > +
> > + profile->mode = vdp->mode;
> > + profile->response = vdp->response;
> > +
> > + profile->mgrid = vdp->mgrid;
> > + profile->id = ntoh24(vdp->id);
> > + profile->version = vdp->version;
> > + memcpy(&profile->instance, &vdp->instance, 16);
> > + memcpy(&profile->mac, &vdp->mac_vlan.mac, MAC_ADDR_LEN);
> > + profile->vlan = ntohs(vdp->mac_vlan.vlan);
> > +
> > + profile->port = port;
> > +
> > + if (vd->role == VDP_ROLE_STATION) {
> > + /* do we have the profile already ? */
> > + LIST_FOREACH(p, &vd->profile_head, profile) {
> > + if (vdp_profile_equal(p, profile)) {
> > + printf("%s(%i): station: profile found,
> > localChange %i ackReceived %i!\n",
> > + __func__, __LINE__, p->localChange,
> > p->ackReceived);
> > +
> > + p->ackReceived = true;
> > +
> > + vdp_vsi_sm_station(p);
> > + } else {
> > + printf("%s(%i): station: profile not found
> > !\n", __func__, __LINE__);
> > + /* ignore profile */
> > + }
> > + }
> > + }
> > +
> > + if (vd->role == VDP_ROLE_BRIDGE) {
> > + /* do we have the profile already ? */
> > + LIST_FOREACH(p, &vd->profile_head, profile) {
> > + if (vdp_profile_equal(p, profile)) {
> > + break;
> > + }
> > + }
> > +
> > + if (p) {
> > + printf("%s(%i): bridge: profile found !\n",
> > __func__, __LINE__);
> > + } else {
> > + printf("%s(%i): bridge: profile not found !\n",
> > __func__, __LINE__);
> > + /* put it in the list */
> > + profile->state = VSI_UNASSOCIATED;
> > + LIST_INSERT_HEAD(&vd->profile_head, profile,
> > profile );
> > + }
> > +
> > + vdp_vsi_sm_bridge(profile);
> > + }
> > +
>
>
> Here the profile is added to a list if the port is in the VDP_ROLE_BRIDGE
> mode. Otherwise the profile is only used to lookup an existing profile? Looks
> like there might be a memory leak if the profile already exists. Does the
> profile need to be cleaned up the somewhere?
The standard is not clear on what to with profiles that e.g. have been
deassociated or have reached VSI_EXIT. In my next series I have added code to
remove the profile in the VSI_EXIT case.
>
> > + return 0;
> > +
> > +out_vdp:
> > + free(vdp);
> > +out_err:
> > + printf("%s(%i): error !\n", __func__, __LINE__);
> > + return 1;
> > +
> > +}
>
>
> The rest looks good.
Thanks ! I will post a new series soon.
Jens
--
IBM Deutschland Research & Development GmbH
Vorsitzender des Aufsichtsrats: Martin Jetter
Geschäftsführung: Dirk Wittkopp
Sitz der Gesellschaft: Böblingen
Registergericht: Amtsgericht Stuttgart, HRB 243294
_______________________________________________
Virtualization mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/virtualization