+TCP questions about a few defines

Would someone please explain the reason for the following:

    #define ipSIZE_OF_ETH_CRC_BYTES                    ( 4UL )
    #define ipSIZE_OF_ETH_OPTIONAL_802_1Q_TAG_BYTES    ( 4UL )
    #define ipTOTAL_ETHERNET_FRAME_SIZE                ( ( ( uint32_t ) ipconfigNETWORK_MTU ) + ( ( uint32_t ) ipSIZE_OF_ETH_HEADER ) + ipSIZE_OF_ETH_CRC_BYTES + ipSIZE_OF_ETH_OPTIONAL_802_1Q_TAG_BYTES )

Both ipSIZE_OF_ETH_CRC_BYTES and ipSIZE_OF_ETH_OPTIONAL_802_1Q_TAG_BYTES are only found in ipTOTAL_ETHERNET_FRAME_SIZE. I think I understand the intent of this as leaving space for data that different hardware might pass into the stack, but the stack generally doesn’t care about. If this is truly the case, shouldn’t those two be defined in FreeRTOSIPConfig.h? Are these historical leftovers?

I’m also not exactly sure of the reason for ipSIZE_OF_ETH_OPTIONAL_802_1Q_TAG_BYTES. The stack does not support 802.1q tags, so… was this put there to add space for future support of 801.2q tags or is it there for special tags that some ethernet chips can optionally add?
My specific hardware (lan9354) is configurable to add/parse a special tag that is used for ingress/egress port information. Is this the type of tag that this define is accounting for?
As far as I can see, removing the first two defines doesn’t brake anything, but that might be due to my specific setup where I don’t get the FCS and I’m accounting for the special tags in a different way. Thoughts?

Any insight is greatly appreciated. Thanks in advance.

I think this is taking into account what could be in the frame, probably in an unnecessarily verbose way. The 802.1Q field is optional but only makes a difference to the minimum payload length, not the maximum length (i.e. if the field is uses the overall maximum frame size doesn’t change).

Thank you @rtel, here some more details:

Are these historical leftovers?

Yes they are. They were already present in the earlier UDP-only library that preceded FreeRTOS+TCP.

And about IEEE 802.1Q: there has been an intention, but it never became realised, support for virtual LANs. It would increase the size of the Ethernet header with 4 bytes, from 14 to 18.

About ipSIZE_OF_ETH_CRC_BYTES : normally you do not see the Ethernet checksum, although I had one peripheral that would also pass them as 4 received bytes.

To anyone who wants to work with full-length packets, i.e. 1500 + 14 bytes long, I always recommend to reserve a maximum buffer size of 1536 ( 0x600 ) bytes. The MTU will be 1500, and the 14 bytes are used for the Ethernet header.

See this discussion about FreeRTOS+TCP Network Buffers and their length. It explains that part of the buffer space is reserved for the IP-task: it contains a pointer and IP-type information.

When using BufferAllocation_1.c, the buffer memory is allocated statically at start-up, as one chunk of memory, with a length of e.g. ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS times 1536 bytes.

In projects where less RAM is available, BufferAllocation_2.c is used. Every packet will be allocated dynamically, by calling pvPortMalloc(), to get just enough bytes as needed. vPortFree() is called to release the memory.

@htibosch Thanks for those comments. I’m trying to understand the state of things before I attempt to propose a vlan tag related change. In my product, I’m using special vlan-tagging to determine the ingress and set the egress port of the packets. This of course depends on my hardware, which is a LAN9354 3 port switch. VLANs don’t make much sense for the “main” branch because there is no support for multiple interfaces, so I’m trying to find the most versatile and easy way to incorporate my changes. I hacked my way through this about a year ago, and it’s been working great for my LLDP implementation.

My approach was to make the stack completely oblivious to those vlan tags that get insterted by the ethernet switch by adding 4+4 bytes in the Ethernet header.

struct xETH_HEADER
{
    MACAddress_t xDestinationAddress; /**< Destination address  0 + 6 = 6  */
    MACAddress_t xSourceAddress;      /**< Source address       6 + 6 = 12 */
    #if ( ipconfigENABLE_SPECAL_VLAN_PORT_TAGGING != 0 )
        uint16_t usTPID;
        uint16_t usTCI;
    #endif
    uint16_t usFrameType;             /**< The EtherType field 12 + 2 = 14 */
}

This way, the entire stack works as originally intended and skips over this special vlan tag. There are also a few more modification for the stack to calculate things properly, but I’ll ommit them for the sake of brevity.
Further, I modified the network driver’s

BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend )

to become

BaseType_t xNetworkInterfaceOutputToPortX( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend, uint8_t ucForceSwitchEgressPort )
#define xNetworkInterfaceOutput( pxNetworkBuffer, xReleaseAfterSend)	xNetworkInterfaceOutputToPortX(pxNetworkBuffer, xReleaseAfterSend, ETHERNET_PORT_AUTO)

Now, xNetworkInterfaceOutputToPortX() allows my LLDP handler to specify the egress port, while the stack uses ETHERNET_PORT_AUTO which causes the Ethernet switch to follow it’s normal egress port logic.

I realize doing things like that is only interesting to people that deal with multi-port switches, but there are quire a few interesting protocols that benefit from this… Think of almost any ring topology protocol.

Do you believe something like the changes above would be beneficial to push upstream for others to take advantage of? If there is interest, I’ll make a branch for people to examine the details.

As far as my original question, I think ipSIZE_OF_ETH_CRC_BYTES should have been made available in FreeRTOSIPConfig and ipSIZE_OF_ETH_OPTIONAL_802_1Q_TAG_BYTES is simply not needed it, but I’m now convinced that I should just leave them alone even though they are wasting 4 to 8 bytes. There might be code out there that quietly depends on them.

As usual, all input is greatly appreciated

I am wondering, will your device also handle normal Ethernet packets, that do not have the VLAN tags?

And FYI : there is already a FreeRTOS+TCP with support for multiple interfaces and, optionally, IPv6. That branch is still “in the labs”, we are working hard to get it fully tested and in a good shape.

Hein, what I’m describing is vlan tags that only appear on the CPU side of the Ethernet switch. I have a 3 port switch. Two of the ports have magnetics and RJ45 connectors on them and the third port provides an RMII PHY to my MCU. The switch is a managed switch and has the option to insert vlan tags into the frames that are sent to the MCU. The VLAN tag is a special one and the data in it tells the MCU which port, this particular frame came in through. When the MCU sends a packet, it can add the same tag in order to tell the switch where to send the frame. Those special VLAN tags get stripped when packets leave out of the normal switch ports.

This feature allows you to treat the two ports of the switch either as separate interfaces ( not applicable to the main branch) or implement specialized protocols like ring-topology protocols. Does this make a little more sense now?

Emil, yes it makes more sense now, thanks. Obviously I have never worked with VLAN tags. I only read about them.

The thing is: the library assumes that the IP-header is located at offset 14.
Now if we add 4 bytes in the Ethernet header, the offset will become 18.
In some locations, sizeof( EthernetHeader_t ) is used, which is OK.

But we’ll also need this change:

#if( ipconfigUSE_VLAN == 1 )
	#define ipSIZE_OF_ETH_HEADER	   18U
#else
	#define ipSIZE_OF_ETH_HEADER	   14U
#endif

Would that work for you?

Also I thought that maybe you want to store VLAN information in each network buffer. see the declaration in NetworkBufferDescriptor_t, Not sure if that is useful.

B.t.w. if you are interested, here some information about the new multi-interface version, and here about IPv6 sockets.

Thanks for the links Hein, I’ll go through them as I have general interest in moving my project onto the “multi” branch at least for testing.

As far as the vlan tags go, don’t worry about trying to help me achieve it. I have had it working for a while now. With this post I was just looking for some clarification and I’m sort of testing the water to see if there might be interest in pushing my “special vlan tag” patch to upstream. Again, in the context of the main branch, my modifications only make sense for someone using hardware that supports those special tags and I simply don’t know how many people would be interested. I’m starting to think that the answer is “not alot…” and I think for now, I will abandon the idea of a PR on this subject.

If you or others are curious, I might create a branch with just these “special vlan tags” to illustrate my point. I’m putting this on the back burner now because as you will find out in my upcoming topic, I have a much bigger feature proposal that I’m working on right now.

Thanks a lot for your continued support and insights!