[Ns-developers] TCP and UDP layer refactoring

Sébastien Vincent vincent at clarinet.u-strasbg.fr
Mon Jul 7 01:21:39 PDT 2008


Hi

Tom Henderson wrote:
> Hi Sebastien,  some questions below.
>
> Sébastien Vincent wrote:
>> Hi,
>>
>> Here is one solution for a design about the refactoring UDP/TCP 
>> layer. It will be decomposed in several part.
>
> To clarify, is your goal to achieve the minimally intrusive 
> refactoring to allow v6 protocols to reuse the existing transport code 
> logic, or more refactoring or goals than that?
>
Yes reuse existing transport code logic.

>>
>> I) Tags
>>
>> Add the following tags :
>>
>> - Ipv6SocketAddressesTag
>>    -> Ipv6Address src;
>>    -> Ipv6Address dst;
>>
>> - Ipv4SocketAddressesTag
>>    -> Ipv4Address src;
>>    -> Ipv4Address dst;
>>
>> - LocalIpv6InterfaceTag
>>    -> Ipv6Address addr;
>>    -> Ipv6Prefix mask;
>>
>> - LocalIpv4InterfaceTag
>>    -> Ipv4Address addr;
>>    -> Ipv4Mask mask;
>>    -> uint32_t ifIndex ???;
>>
>> The LocaIpv*InterfaceTag will be used to avoid having the 
>> Ptr<Ipv*Interface> in *L4Protocol::Receive.
>> In facts in the *EndPointDemux::Lookup, we use the interface to get 
>> its address and netmask.
>
> I think that we could probably get away without carrying around the 
> incomingInterface as an explicit parameter.
OK so we could remove all code that use this parameter in ::Lookup ?

>
> The FreeBSD socket demux code I've looked at before does not need to 
> carry this parameter.  Has anyone considered porting the logic for 
> socket wildcard matching from Linux or BSD to this demux function?  
> This is not a trivial demux to implement.
>
>>
>> II) Independant EndPoint
>>
>> - Have a single class EndPoint (and remove Ipv6EndPoint and 
>> Ipv4EndPoint).
>> - The members m_localAddr an m_peerAddress will be stored as Address
>> - Remove Ipv4Address argument from m_rxCallBack and SetRxCallback 
>> (see VI)).
>> - Add a AfType (AF_INET or AF_INET6) to know the type of address.
>
> Can't Address::IsMatchingType be used to learn the type of the address?
>
> Would it be sufficient and appropriate to just have logic something like:
>
> Endpoints::Lookup
> {
>   if (InetSocketAddress::IsMatchingType (address))
>     {
>       // do Ipv4-based lookup
>     }
>   else if (Inet6SocketAddress::IsMatchingType (address))
>     {
>       // do Ipv6-based lookup
>     }
> }
>
> this begs the question:  more generally than this lookup function, 
> since we have just two address families, would it suffice to handle 
> most of these address family issues by just passing class Address 
> around, and having the method first check whether the address is Ipv4 
> or Ipv6?

I try to be generic but if you don't plan to add other network layer, we 
could do this way.
>
>>
>> III) StorageSocketAddress
>>
>> Some functions in *SocketImpl use InetSocketAddress or 
>> Inet6SocketAddress. We can avoid this by having a class that have the 
>> same methods
>> than InetSocketAddress but with Address attributes called 
>> StorageSocketAddress. This is similar to the "struct 
>> sockaddr_storage" in C.
>>
>> StorageSocketAddress
>>    -> AfType type
>>    -> Address addr
>>    -> uint16_t port
>>    -> ConvertToInetSocketAddress (???)
>>    -> ConvertToInet6SocketAddress (???)
>>
>> The InetSocketAddress and Inet6SocketAddress should have a operator 
>> StorageSocketAddress() to map automatically its contents to a 
>> StorageSocketAddress and set the AfType.
>> -> No changes to existing applications.
>>
>> OR
>>
>> we can also remove InetSocketAddress and Inet6SocketAddress and use 
>> only StorageSocketAddress.
>
> Again, I would ask here whether class Address suffices.
>
>>
>>
>> IV) *SocketImpl
>>
>> - Use StorageSocketAddress;
>> - Use Address instead of Ipv*Address;
>> - In DoSendTo (Ptr<Packet> p, Address daddr, uint16_t dport), after
>>
>>  if (m_endPoint == 0)
>>    {
>>      if (Bind () == -1)
>>  {
>>          NS_ASSERT (m_endPoint == 0);
>>    return -1;
>>  }
>>      NS_ASSERT (m_endPoint != 0);
>>    }
>>  if (m_shutdownSend)
>>    {
>>      m_errno = ERROR_SHUTDOWN;
>>      return -1;
>>    }
>>
>> check m_endPoint->GetAfType() and do IPv6 or IPv4 stuff;
>>
>> - Add Ipv*SocketAddressesTag before sending to UdpL4Protocol.
>
> Regarding using tags to carry addresses between layers (if I 
> understand the intention correctly), I think it is clearer, if the 
> address is a mandatory parameter to pass, to just put it in the 
> function signature.
OK
>
>>
>>
>> V) Ipv*L3Protocol
>>
>> - Add the Ipv*SocketAddressesTag in ::ForwardUp();
>> - Add Ipv*InterfaceTag in ::ForwardUp().
>>
>> VI) *L4Protocol
>>
>> - Have Ipv6EndPointDemux and Ipv4EndPointDemux or one EndPointDemux 
>> (see VII));
>
> one EndPointDemux could check address type and call the right Ipv4 or 
> Ipv6 EndpointDemux function?
>
I have the same idea.
>> - Remove Ipv*Address in ::Receive signature, use tag instead (added 
>> in Ipv*L3Protocol);
>> - Remove Ipv*Address in ::Send() signature, use tag instead (added in 
>> *SocketImpl::DoSendTo());
>> - Check tag (if/else) in ::Receive, and do appropriate behavior 
>> (checksum, *EndPointDemux);
>> - Check tag (if/else) in ::Send, and do appropriate behavior 
>> (checksum, send to the right L3 stack);
>> - Remove Ipv*Address in ::ForwardUp() signature, check 
>> Ipv*SocketAddressesTag and get the source addresse, create a 
>> StorageSocketAddress, and put in SocketAddressTag;
>> - Allocate() method takes Address arguments and return EndPoint*.
>>
>> VII) Ipv*EndPointDemux
>>
>> First solution :
>> - Keep Ipv6EndPointDemux and Ipv4EndPointDemux;
>> - In ::Lookup(), get the Ipv*InterfaceTag, remove incomingInterface 
>> and do stuff as usual with the address/netmask in the tag.
>>
>> Second solution
>> - Have a single EndPointDemux;
>> - Overload Lookup function (one for IPv6 and one for IPv4);
>> - Two set of EndPoints list (one for IPv6 and one for IPv4);
>> - Have a AllocateEphemeralPort() and AllocateEphemeralPort6() 
>> (because a service can be associated for a distinct IPv4 socket and a 
>> IPv6 socket);
>> - Remove Ipv6EndPointDemux and Ipv4EndPointDemux.
>>
>> VIII) Other
>>
>> - When we *L4Protocol::CreateSocket(), it will give a socket that 
>> could be bound in IPv4 or IPv6 so no need to add Udp6/Tcp6SocketFactory;
>
> this is an interesting point, I think.  The SocketImpl classes can't 
> have any explicit address family dependency because they are created 
> before the family is known.  So I agree with your point.
>
>> - Have a single InternetL4Protocol class and remove Ipv6L4Protocol 
>> and Ipv4L4Protocol (since the ::Receive method signature will not 
>> have Ipv*Interface).
>>
>
> seems like a logical conclusion to the task of making L4 protocols 
> generic across address families.
>
>> What do you think ?
>>
>> I hope together, we can find a good solution for this issue.
>
> Yes, thanks for taking these issues up.  By the way, I put some flow 
> diagrams of how a packet traverses the current stack in section 6 of 
> the manual:
> http://www.nsnam.org/docs/manual.html#SEC71  (figures 6.2 and 6.3)
>
> These might be helpful for some context to some readers.
>
> Tom
>

Ok so if I summarize :
- Remove incomingInterface from EndPointDemux::Lookup() and associate code.
- One EndPointDemux with a ::Lookup() function for each address family 
(IPv4 and IPv6).
- *L4Protocol and *SocketImpl use Address and test with 
*Address::IsMatchingType().
- Have a single tag called SocketAddressesTag with Address parameters 
and test as usual (*Address::IsMatchingType).

If you are OK with this, I can begin something this week.

Regards,
--
Sebastien Vincent
Network and Protocol Team, University of Strasbourg, France



More information about the Ns-developers mailing list