Support for advertising MTU in IPv6 RAs 70/77670/8
authorSridhar Gaddam <sgaddam@redhat.com>
Sun, 11 Nov 2018 14:38:59 +0000 (20:08 +0530)
committerAswin Suryanarayanan <asuryana@redhat.com>
Sat, 5 Jan 2019 15:14:15 +0000 (15:14 +0000)
This patch includes the MTU Option as part of
Solicited/Un-solicited Router Advts and also fixes
some issues in ipv6service unit tests.

Depends-On: https://git.opendaylight.org/gerrit/#/c/77668/
Depends-On: https://git.opendaylight.org/gerrit/#/c/77851/

Change-Id: Ibeae0634bbfdd8b438968e4918026e7109521c6d
Signed-off-by: Sridhar Gaddam <sgaddam@redhat.com>
ipv6service/api/src/main/java/org/opendaylight/netvirt/ipv6service/api/IVirtualNetwork.java
ipv6service/impl/src/main/java/org/opendaylight/netvirt/ipv6service/IfMgr.java
ipv6service/impl/src/main/java/org/opendaylight/netvirt/ipv6service/Ipv6RouterAdvt.java
ipv6service/impl/src/main/java/org/opendaylight/netvirt/ipv6service/NeutronNetworkChangeListener.java
ipv6service/impl/src/main/java/org/opendaylight/netvirt/ipv6service/VirtualNetwork.java
ipv6service/impl/src/main/java/org/opendaylight/netvirt/ipv6service/VirtualPort.java
ipv6service/impl/src/test/java/org/opendaylight/netvirt/ipv6service/Ipv6PktHandlerTest.java

index 9ea7d520b5fbb9523e95a134a355256b4cb9dddb..1edbf5e4859dcc97634770d7cca83ad02a01a5f2 100644 (file)
@@ -17,4 +17,6 @@ public interface IVirtualNetwork {
     Long getElanTag();
 
     List<BigInteger> getDpnsHostingNetwork();
+
+    int getMtu();
 }
index e7a6e7db00c83566fb000d08d9bf86fca6503b34..4822b948452824c8021468a5bf9f287ca88b9582 100644 (file)
@@ -245,6 +245,10 @@ public class IfMgr implements ElementCache, AutoCloseable {
                 .routerIntfFlag(true).deviceOwner(deviceOwner).build();
         intf.setSubnetInfo(snetId, fixedIp);
         intf.setPeriodicTimer(ipv6Queue);
+        int networkMtu = getNetworkMtu(networkId);
+        if (networkMtu != 0) {
+            intf.setMtu(networkMtu);
+        }
 
         boolean newIntf = false;
         VirtualPort prevIntf = vintfs.putIfAbsent(portId, intf);
@@ -844,6 +848,14 @@ public class IfMgr implements ElementCache, AutoCloseable {
         return elanTag;
     }
 
+    @Nullable
+    public void updateNetworkMtuInfo(Uuid networkId, int mtu) {
+        VirtualNetwork net = getNetwork(networkId);
+        if (null != net) {
+            net.setMtu(mtu);
+        }
+    }
+
     @Nullable
     private VirtualNetwork getNetwork(Uuid networkId) {
         return networkId != null ? vnetworks.get(networkId) : null;
@@ -862,12 +874,23 @@ public class IfMgr implements ElementCache, AutoCloseable {
         return elanTag;
     }
 
-    public void addNetwork(Uuid networkId) {
+    @Nullable
+    public int getNetworkMtu(Uuid networkId) {
+        int mtu = 0;
+        IVirtualNetwork net = getNetwork(networkId);
+        if (null != net) {
+            mtu = net.getMtu();
+        }
+        return mtu;
+    }
+
+    public void addNetwork(Uuid networkId, int mtu) {
         if (networkId == null) {
             return;
         }
 
         if (vnetworks.putIfAbsent(networkId, new VirtualNetwork(networkId)) == null) {
+            updateNetworkMtuInfo(networkId, mtu);
             updateNetworkElanTag(networkId);
         }
         Set<VirtualPort> intfList = removeUnprocessed(unprocessedNetIntfs, networkId);
index 3bac01f69d8c909aa62f18786aa537b79fcb19eb..05871cb7b86bd0626ab4466520085435faa0a68b 100644 (file)
@@ -9,6 +9,7 @@
 package org.opendaylight.netvirt.ipv6service;
 
 import static java.util.Objects.requireNonNull;
+
 import static org.opendaylight.netvirt.ipv6service.utils.Ipv6ServiceUtils.nullToEmpty;
 
 import java.math.BigInteger;
@@ -142,8 +143,9 @@ public class Ipv6RouterAdvt {
 
         raPacket.setVersion(Ipv6Constants.IPV6_VERSION);
         int prefixListLength = autoConfigPrefixList.size() + statefulConfigPrefixList.size();
+        int mtuOptionLength = routerPort.getMtu() == 0 ? 0 : Ipv6Constants.ICMPV6_OPTION_MTU_LENGTH;
         raPacket.setIpv6Length(Ipv6Constants.ICMPV6_RA_LENGTH_WO_OPTIONS
-                + Ipv6Constants.ICMPV6_OPTION_SOURCE_LLA_LENGTH
+                + mtuOptionLength + Ipv6Constants.ICMPV6_OPTION_SOURCE_LLA_LENGTH
                 + prefixListLength * Ipv6Constants.ICMPV6_OPTION_PREFIX_LENGTH);
         raPacket.setNextHeader(IPProtocols.IPV6ICMP.shortValue());
         raPacket.setHopLimit(Ipv6Constants.ICMP_V6_MAX_HOP_LIMIT);
@@ -164,13 +166,19 @@ public class Ipv6RouterAdvt {
         raPacket.setReachableTime((long) Ipv6Constants.IPV6_RA_REACHABLE_TIME);
         raPacket.setRetransTime((long) 0);
 
-        raPacket.setOptionSourceAddr((short)1);
+        raPacket.setOptionSourceAddr(Ipv6Constants.ICMP_V6_OPTION_SOURCE_LLA);
         raPacket.setSourceAddrLength((short)1);
         raPacket.setSourceLlAddress(MacAddress.getDefaultInstance(gatewayMac));
 
+        if (mtuOptionLength != 0) {
+            raPacket.setOptionMtu(Ipv6Constants.ICMP_V6_OPTION_MTU);
+            raPacket.setOptionMtuLength((short)1);
+            raPacket.setMtu((long) routerPort.getMtu());
+        }
+
         List<PrefixList> prefixList = new ArrayList<>();
         PrefixListBuilder prefix = new PrefixListBuilder();
-        prefix.setOptionType((short)3);
+        prefix.setOptionType(Ipv6Constants.ICMP_V6_OPTION_PREFIX_INFO);
         prefix.setOptionLength((short)4);
         // Note: EUI-64 auto-configuration requires 64 bits.
         prefix.setPrefixLength((short)64);
@@ -225,6 +233,12 @@ public class Ipv6RouterAdvt {
         buf.put((byte)pdu.getOptionSourceAddr().shortValue());
         buf.put((byte)pdu.getSourceAddrLength().shortValue());
         buf.put(Ipv6Util.bytesFromHexString(pdu.getSourceLlAddress().getValue()));
+        if (pdu.getOptionMtu() != null) {
+            buf.put((byte)pdu.getOptionMtu().shortValue());
+            buf.put((byte)pdu.getOptionMtuLength().shortValue());
+            buf.putShort((byte)0); // Reserved field
+            buf.putInt((int)pdu.getMtu().longValue());
+        }
 
         for (PrefixList prefix : nullToEmpty(pdu.getPrefixList())) {
             buf.put((byte)prefix.getOptionType().shortValue());
index 5afbff0198cec6e3eab691851ab2eec569e1ae24..df079995fa11c73dc9dae9263b9505a6c25ff635 100644 (file)
@@ -13,6 +13,7 @@ import javax.inject.Singleton;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.genius.datastoreutils.AsyncClusteredDataTreeChangeListenerBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.mtu.ext.rev181114.NetworkMtuExtension;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.Networks;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
@@ -48,8 +49,12 @@ public class NeutronNetworkChangeListener extends AsyncClusteredDataTreeChangeLi
 
     @Override
     protected void add(InstanceIdentifier<Network> identifier, Network input) {
+        int mtu = 0;
         LOG.debug("Add Network notification handler is invoked {} ", input);
-        ifMgr.addNetwork(input.getUuid());
+        if (input.augmentation(NetworkMtuExtension.class) != null) {
+            mtu = input.augmentation(NetworkMtuExtension.class).getMtu();
+        }
+        ifMgr.addNetwork(input.getUuid(), mtu);
     }
 
     @Override
index 3f7b600a46599bfc46a8a4cafa8f3bb94b719ad3..b75d1416a479b317b40f1496534f2625f18db3f9 100644 (file)
@@ -26,6 +26,7 @@ public class VirtualNetwork implements IVirtualNetwork {
     private final Uuid networkUUID;
     private final ConcurrentMap<BigInteger, DpnInterfaceInfo> dpnIfaceList = new ConcurrentHashMap<>();
     private volatile Long elanTag;
+    private volatile int mtu = 0;
 
     public VirtualNetwork(Uuid networkUUID) {
         this.networkUUID = networkUUID;
@@ -110,6 +111,15 @@ public class VirtualNetwork implements IVirtualNetwork {
         }
     }
 
+    public void setMtu(int mtu) {
+        this.mtu = mtu;
+    }
+
+    @Override
+    public int getMtu() {
+        return this.mtu;
+    }
+
     public static class DpnInterfaceInfo {
         BigInteger dpId;
         int rsPuntFlowConfigured;
index 38c1f709bc4f65a22ec42e534891dac94d33a5e7..00ecad334d1750d7768643f022c9f5ad11b96a16 100644 (file)
@@ -46,6 +46,7 @@ public class VirtualPort implements IVirtualPort  {
     private volatile boolean serviceBindingStatus;
     private volatile Ipv6PeriodicTimer periodicTimer;
     private volatile Timeout periodicTimeout;
+    private volatile int mtu = 0;
 
     // associated router if any
     private volatile VirtualRouter router;
@@ -146,6 +147,14 @@ public class VirtualPort implements IVirtualPort  {
         return router;
     }
 
+    public void setMtu(int mtu) {
+        this.mtu = mtu;
+    }
+
+    public int getMtu() {
+        return this.mtu;
+    }
+
     @Override
     public String getDeviceOwner() {
         return deviceOwner;
index 10ded960f3d3568ebc0efac120bddd410fd3e7c1..24c60f18d0ca47ed8f4d1f19eaf9038468c54adf 100644 (file)
@@ -14,6 +14,7 @@ import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import com.google.common.util.concurrent.ListenableFuture;
 import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.List;
@@ -22,6 +23,7 @@ import org.junit.Test;
 import org.mockito.Mockito;
 import org.opendaylight.genius.ipv6util.api.Ipv6Util;
 import org.opendaylight.genius.ipv6util.api.decoders.Ipv6NaDecoder;
+import org.opendaylight.genius.mdsalutil.MDSALUtil;
 import org.opendaylight.genius.mdsalutil.NwConstants;
 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
 import org.opendaylight.netvirt.ipv6service.api.IIpv6PacketListener;
@@ -136,6 +138,9 @@ public class Ipv6PktHandlerTest {
     @Test
     public void testonPacketReceivedNeighborSolicitationWithInvalidPayload() throws Exception {
         //incorrect checksum
+        BigInteger mdata = new BigInteger(String.valueOf(0x1000000));
+        Metadata metadata = new MetadataBuilder().setMetadata(mdata).build();
+        MatchBuilder matchbuilder = new MatchBuilder().setMetadata(metadata);
         pktHandler.onPacketReceived(new PacketReceivedBuilder().setPayload(ipv6TestUtils.buildPacket(
                 "33 33 FF F5 00 00",                               // Destination MAC
                 "00 01 02 03 04 05",                               // Source MAC
@@ -151,12 +156,13 @@ public class Ipv6PktHandlerTest {
                 "67 3E",                                           // Checksum (invalid, should be 67 3C)
                 "00 00 00 00",                                     // ICMPv6 message body
                 "FE 80 00 00 00 00 00 00 C0 00 54 FF FE F5 00 00"  // Target
-        )).build());
+        )).setMatch(matchbuilder.build()).build());
         //wait on this thread until the async job is completed in the packet handler.
         waitForPacketProcessing();
         verify(pktProcessService, times(0)).transmitPacket(any(TransmitPacketInput.class));
 
         //unavailable ip
+        when(ifMgrInstance.getInterfaceNameFromTag(anyLong())).thenReturn("ddec9dba-d831-4ad7-84b9-00d7f65f052f");
         when(ifMgrInstance.obtainV6Interface(any())).thenReturn(null);
         counter = pktHandler.getPacketProcessedCounter();
         pktHandler.onPacketReceived(new PacketReceivedBuilder().setPayload(ipv6TestUtils.buildPacket(
@@ -174,7 +180,7 @@ public class Ipv6PktHandlerTest {
                 "67 3C",                                           // Checksum (valid)
                 "00 00 00 00",                                     // ICMPv6 message body
                 "FE 80 00 00 00 00 00 00 C0 00 54 FF FE F5 00 00"  // Target
-        )).build());
+        )).setMatch(matchbuilder.build()).build());
         //wait on this thread until the async job is completed in the packet handler.
         waitForPacketProcessing();
         verify(pktProcessService, times(0)).transmitPacket(any(TransmitPacketInput.class));
@@ -183,6 +189,9 @@ public class Ipv6PktHandlerTest {
     @Test
     public void testonPacketReceivedRouterSolicitationWithInvalidPayload() throws Exception {
         // incorrect checksum in Router Solicitation
+        BigInteger mdata = new BigInteger(String.valueOf(0x1000000));
+        Metadata metadata = new MetadataBuilder().setMetadata(mdata).build();
+        MatchBuilder matchbuilder = new MatchBuilder().setMetadata(metadata);
         pktHandler.onPacketReceived(new PacketReceivedBuilder().setPayload(ipv6TestUtils.buildPacket(
                 "33 33 FF F5 00 00",                               // Destination MAC
                 "00 01 02 03 04 05",                               // Source MAC
@@ -198,12 +207,13 @@ public class Ipv6PktHandlerTest {
                 "69 3E",                                           // Checksum (invalid, should be 67 3C)
                 "00 00 00 00",                                     // ICMPv6 message body
                 "FE 80 00 00 00 00 00 00 C0 00 54 FF FE F5 00 00"  // Target
-        )).build());
+        )).setMatch(matchbuilder.build()).build());
         //wait on this thread until the async job is completed in the packet handler.
         waitForPacketProcessing();
         verify(pktProcessService, times(0)).transmitPacket(any(TransmitPacketInput.class));
 
         // Request from an unknown port (i.e., unknown MAC Address)
+        when(ifMgrInstance.getInterfaceNameFromTag(anyLong())).thenReturn("ddec9dba-d831-4ad7-84b9-00d7f65f052f");
         when(ifMgrInstance.obtainV6Interface(any())).thenReturn(null);
         counter = pktHandler.getPacketProcessedCounter();
         pktHandler.onPacketReceived(new PacketReceivedBuilder().setPayload(ipv6TestUtils.buildPacket(
@@ -221,7 +231,7 @@ public class Ipv6PktHandlerTest {
                 "69 3C",                                           // Checksum (valid)
                 "00 00 00 00",                                     // ICMPv6 message body
                 "FE 80 00 00 00 00 00 00 C0 00 54 FF FE F5 00 00"  // Target
-        )).build());
+        )).setMatch(matchbuilder.build()).build());
         //wait on this thread until the async job is completed in the packet handler.
         waitForPacketProcessing();
         verify(pktProcessService, times(0)).transmitPacket(any(TransmitPacketInput.class));
@@ -240,6 +250,7 @@ public class Ipv6PktHandlerTest {
         Ipv6Address llAddr = Ipv6Util.getIpv6LinkLocalAddressFromMac(new MacAddress("08:00:27:FE:8F:95"));
         ipv6AddrList.add(llAddr);
         when(routerIntf.getIpv6Addresses()).thenReturn(ipv6AddrList);
+        when(pktProcessService.transmitPacket(any())).thenReturn(Mockito.mock(ListenableFuture.class));
 
         InstanceIdentifier<Node> ncId = InstanceIdentifier.builder(Nodes.class)
                 .child(Node.class, new NodeKey(new NodeId("openflow:1"))).build();
@@ -300,12 +311,14 @@ public class Ipv6PktHandlerTest {
         when(intf.getDpId()).thenReturn(new BigInteger(String.valueOf(1)));
         when(intf.getIntfUUID()).thenReturn(Uuid.getDefaultInstance("ddec9dba-d831-4ad7-84b9-00d7f65f052f"));
         when(intf.getMacAddress()).thenReturn("fa:16:3e:4e:18:0c");
+        when(intf.getMtu()).thenReturn(1400);
         when(ifMgrInstance.getInterfaceNameFromTag(anyLong())).thenReturn("ddec9dba-d831-4ad7-84b9-00d7f65f052f");
         List<Action> actions = new ArrayList<>();
         actions.add(new ActionNxResubmit(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE).buildAction());
         when(ifMgrInstance.getEgressAction(any())).thenReturn(actions);
         when(ifMgrInstance.obtainV6Interface(any())).thenReturn(intf);
         when(ifMgrInstance.getRouterV6InterfaceForNetwork(any())).thenReturn(intf);
+        when(pktProcessService.transmitPacket(any())).thenReturn(Mockito.mock(ListenableFuture.class));
 
         IpAddress gwIpAddress = Mockito.mock(IpAddress.class);
         when(gwIpAddress.getIpv4Address()).thenReturn(null);
@@ -322,9 +335,8 @@ public class Ipv6PktHandlerTest {
         subnetList.add(v6Subnet);
         when(intf.getSubnets()).thenReturn(subnetList);
 
-        InstanceIdentifier<Node> ncId = InstanceIdentifier.builder(Nodes.class)
-                .child(Node.class, new NodeKey(new NodeId("openflow:1"))).build();
-        NodeConnectorRef ncRef = new NodeConnectorRef(ncId);
+        BigInteger dpnId = new BigInteger("1");
+        NodeConnectorRef ncRef = MDSALUtil.getDefaultNodeConnRef(dpnId);
         BigInteger mdata = new BigInteger(String.valueOf(0x1000000));
         Metadata metadata = new MetadataBuilder().setMetadata(mdata).build();
         MatchBuilder matchbuilder = new MatchBuilder().setMetadata(metadata);
@@ -356,14 +368,14 @@ public class Ipv6PktHandlerTest {
                 "FA 16 3E 4E 18 0C",                               // Source MAC
                 "86 DD",                                           // IPv6
                 "60 00 00 00",                                     // Version 6, traffic class E0, no flowlabel
-                "00 38",                                           // Payload length
+                "00 40",                                           // Payload length
                 "3A",                                              // Next header is ICMPv6
                 "FF",                                              // Hop limit
                 "FE 80 00 00 00 00 00 00 F8 16 3E FF FE 4E 18 0C", // Source IP
                 "FE 80 00 00 00 00 00 00 F8 16 3E FF FE 69 2C F3", // Destination IP
                 "86",                                              // ICMPv6 router advertisement.
                 "00",                                              // Code
-                "1B B0",                                           // Checksum (valid)
+                "11 2F",                                           // Checksum (valid)
                 "40",                                              // Current Hop Limit
                 "00",                                              // ICMPv6 RA Flags
                 "11 94",                                           // Router Lifetime
@@ -372,6 +384,10 @@ public class Ipv6PktHandlerTest {
                 "01",                                              // Type: Source Link-Layer Option
                 "01",                                              // Option length
                 "FA 16 3E 4E 18 0C",                               // Source Link layer address
+                "05",                                              // Type: MTU Option
+                "01",                                              // Option length
+                "00 00",                                           // Reserved
+                "00 00 05 78",                                     // MTU
                 "03",                                              // Type: Prefix Information
                 "04",                                              // Option length
                 "40",                                              // Prefix length
@@ -381,8 +397,8 @@ public class Ipv6PktHandlerTest {
                 "00 00 00 00",                                     // Reserved
                 "20 01 0D B8 00 00 00 00 00 00 00 00 00 00 00 00"  // Prefix
         );
-        verify(pktProcessService).transmitPacket(new TransmitPacketInputBuilder().setPayload(expectedPayload)
-                .setNode(new NodeRef(ncId)).setEgress(ncRef).setIngress(ncRef).setAction(any(List.class)).build());
+        TransmitPacketInput transmitPacketInput = MDSALUtil.getPacketOut(actions, expectedPayload, dpnId);
+        verify(pktProcessService).transmitPacket(transmitPacketInput);
     }
 
     @Test
@@ -397,6 +413,7 @@ public class Ipv6PktHandlerTest {
         List<Action> actions = new ArrayList<>();
         actions.add(new ActionNxResubmit(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE).buildAction());
         when(ifMgrInstance.getEgressAction(any())).thenReturn(actions);
+        when(pktProcessService.transmitPacket(any())).thenReturn(Mockito.mock(ListenableFuture.class));
 
         IpAddress gwIpAddress = Mockito.mock(IpAddress.class);
         when(gwIpAddress.getIpv4Address()).thenReturn(null);
@@ -426,9 +443,8 @@ public class Ipv6PktHandlerTest {
         subnetList.add(v6Subnet3);
         when(intf.getSubnets()).thenReturn(subnetList);
 
-        InstanceIdentifier<Node> ncId = InstanceIdentifier.builder(Nodes.class)
-                .child(Node.class, new NodeKey(new NodeId("openflow:1"))).build();
-        NodeConnectorRef ncRef = new NodeConnectorRef(ncId);
+        BigInteger dpnId = new BigInteger("1");
+        NodeConnectorRef ncRef = MDSALUtil.getDefaultNodeConnRef(dpnId);
         BigInteger mdata = new BigInteger(String.valueOf(0x1000000));
         Metadata metadata = new MetadataBuilder().setMetadata(mdata).build();
         MatchBuilder matchbuilder = new MatchBuilder().setMetadata(metadata);
@@ -502,9 +518,8 @@ public class Ipv6PktHandlerTest {
                 "20 01 0D B8 33 33 00 00 00 00 00 00 00 00 00 00"  // Prefix
         );
 
-        verify(pktProcessService).transmitPacket(new TransmitPacketInputBuilder().setPayload(expectedPayload)
-                .setNode(new NodeRef(ncId))
-                .setEgress(ncRef).setIngress(ncRef).setAction(any(List.class)).build());
+        TransmitPacketInput transmitPacketInput = MDSALUtil.getPacketOut(actions, expectedPayload, dpnId);
+        verify(pktProcessService).transmitPacket(transmitPacketInput);
     }
 
     @Test