Removes default router option and adds unit tests in OpenstackSwitchingDhcpHandler.

Change-Id: I39ff49448c4a98d7cec59325dcec5ac878b000fa
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingDhcpHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingDhcpHandler.java
index 3a11e5a..3f511e9 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingDhcpHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingDhcpHandler.java
@@ -73,6 +73,7 @@
 import java.util.List;
 import java.util.Objects;
 
+import static com.google.common.base.Preconditions.checkNotNull;
 import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_BroadcastAddress;
 import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_Classless_Static_Route;
 import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_DHCPServerIp;
@@ -80,7 +81,6 @@
 import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_END;
 import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_LeaseTime;
 import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_MessageType;
-import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_RouterAddress;
 import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_SubnetMask;
 import static org.onlab.packet.DHCP.MsgType.DHCPACK;
 import static org.onlab.packet.DHCP.MsgType.DHCPOFFER;
@@ -88,7 +88,6 @@
 import static org.onosproject.openstacknetworking.api.Constants.DHCP_ARP_TABLE;
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_DHCP_RULE;
 import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
-import static com.google.common.base.Preconditions.checkNotNull;
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
@@ -111,7 +110,7 @@
     private static final int DHCP_DATA_MTU_DEFAULT = 1450;
     private static final int OCTET_BIT_LENGTH = 8;
     private static final int V4_BYTE_SIZE = 4;
-    private static final int V4_CIDR_LOWER_BOUND = 0;
+    private static final int V4_CIDR_LOWER_BOUND = -1;
     private static final int V4_CIDR_UPPER_BOUND = 33;
     private static final int PADDING_SIZE = 4;
 
@@ -146,8 +145,6 @@
             label = "Fake MAC address for virtual network subnet gateway")
     private String dhcpServerMac = DEFAULT_GATEWAY_MAC_STR;
 
-    @Property(name = DHCP_DATA_MTU, intValue = DHCP_DATA_MTU_DEFAULT,
-            label = "DHCP data Maximum Transmission Unit")
     private int dhcpDataMtu = DHCP_DATA_MTU_DEFAULT;
 
     private final PacketProcessor packetProcessor = new InternalPacketProcessor();
@@ -182,19 +179,13 @@
     protected void modified(ComponentContext context) {
         Dictionary<?, ?> properties = context.getProperties();
         String updatedMac;
-        Integer updateMtu;
 
         updatedMac = Tools.get(properties, DHCP_SERVER_MAC);
-        updateMtu = Tools.getIntegerProperty(properties, DHCP_DATA_MTU);
 
         if (!Strings.isNullOrEmpty(updatedMac) && !updatedMac.equals(dhcpServerMac)) {
             dhcpServerMac = updatedMac;
         }
 
-        if (updateMtu != null && updateMtu != dhcpDataMtu) {
-            dhcpDataMtu = updateMtu;
-        }
-
         log.info("Modified");
     }
 
@@ -464,13 +455,6 @@
                 options.add(option);
             }
 
-            // router address
-            option = new DhcpOption();
-            option.setCode(OptionCode_RouterAddress.getValue());
-            option.setLength((byte) 4);
-            option.setData(Ip4Address.valueOf(osSubnet.getGateway()).toOctets());
-            options.add(option);
-
             // end option
             option = new DhcpOption();
             option.setCode(OptionCode_END.getValue());
@@ -492,8 +476,7 @@
                     throw new IllegalArgumentException("Illegal CIDR length value!");
                 }
 
-                for (int i = 1; i <= V4_BYTE_SIZE; i++) {
-
+                for (int i = 0; i <= V4_BYTE_SIZE; i++) {
                     if (preFixLen == Math.min(preFixLen, i * OCTET_BIT_LENGTH)) {
                         size = size + i + 1 + PADDING_SIZE;
                         break;
@@ -513,12 +496,13 @@
                     .split("/")[0]
                     .split("\\.");
 
-            // retrieve destination descriptor and put this to bytebuffer according to 3442
+            // retrieve destination descriptor and put this to bytebuffer according to RFC 3442
+            // ex) 0.0.0.0/0 -> 0
             // ex) 10.0.0.0/8 -> 8.10
             // ex) 10.17.0.0/16 -> 16.10.17
             // ex) 10.27.129.0/24 -> 24.10.27.129
             // ex) 10.229.0.128/25 -> 25.10.229.0.128
-            for (int i = 1; i <= V4_BYTE_SIZE; i++) {
+            for (int i = 0; i <= V4_BYTE_SIZE; i++) {
                 if (prefixLen == Math.min(prefixLen, i * OCTET_BIT_LENGTH)) {
                     byteBuffer = ByteBuffer.allocate(i + 1);
                     byteBuffer.put((byte) prefixLen);
diff --git a/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingDhcpHandlerTest.java b/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingDhcpHandlerTest.java
index 28323b0..65331fe 100644
--- a/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingDhcpHandlerTest.java
+++ b/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingDhcpHandlerTest.java
@@ -25,6 +25,7 @@
 import org.onlab.packet.IPv4;
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.UDP;
 import org.onlab.packet.dhcp.DhcpOption;
@@ -60,6 +61,7 @@
 import org.openstack4j.model.network.builder.NetworkBuilder;
 import org.openstack4j.model.network.builder.PortBuilder;
 import org.openstack4j.model.network.builder.SubnetBuilder;
+import org.openstack4j.openstack.networking.domain.NeutronHostRoute;
 import org.openstack4j.openstack.networking.domain.NeutronIP;
 
 import java.nio.ByteBuffer;
@@ -70,6 +72,11 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
+import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_Classless_Static_Route;
+import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_DomainServer;
+import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_END;
+import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_MessageType;
+import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_RequestedIP;
 import static org.onosproject.net.NetTestTools.connectPoint;
 
 /**
@@ -81,6 +88,9 @@
 
     protected PacketProcessor packetProcessor;
 
+    private static final byte DHCP_OPTION_MTU = (byte) 26;
+
+    private static final short MTU = 1450;
     private static final HostId CLIENT_HOST =
                          HostId.hostId(MacAddress.valueOf("1a:1a:1a:1a:1a:1a"));
     private static final String EXPECTED_IP = "10.2.0.2";
@@ -89,6 +99,21 @@
     private static final Ip4Address BROADCAST =
                          Ip4Address.valueOf("255.255.255.255");
     private static final int TRANSACTION_ID = 1986;
+    private static final Ip4Address DEFAULT_PRIMARY_DNS = Ip4Address.valueOf("8.8.8.8");
+    private static final Ip4Address DEFAULT_SECONDARY_DNS = Ip4Address.valueOf("8.8.4.4");
+    private static final String HOST_ROUTE_1_DESTINATION = "0.0.0.0/0";
+    private static final String HOST_ROUTE_1_NEXTHOP = "10.2.0.1";
+    private static final String HOST_ROUTE_2_DESTINATION = "10.0.0.0/8";
+    private static final String HOST_ROUTE_2_NEXTHOP = "10.2.0.1";
+    private static final String HOST_ROUTE_3_DESTINATION = "10.0.0.0/16";
+    private static final String HOST_ROUTE_3_NEXTHOP = "10.2.0.1";
+    private static final String HOST_ROUTE_4_DESTINATION = "10.0.0.0/24";
+    private static final String HOST_ROUTE_4_NEXTHOP = "10.2.0.1";
+    private static final HostRoute HOST_ROUTE_1 = new NeutronHostRoute(HOST_ROUTE_1_DESTINATION, HOST_ROUTE_1_NEXTHOP);
+    private static final HostRoute HOST_ROUTE_2 = new NeutronHostRoute(HOST_ROUTE_2_DESTINATION, HOST_ROUTE_2_NEXTHOP);
+    private static final HostRoute HOST_ROUTE_3 = new NeutronHostRoute(HOST_ROUTE_3_DESTINATION, HOST_ROUTE_3_NEXTHOP);
+    private static final HostRoute HOST_ROUTE_4 = new NeutronHostRoute(HOST_ROUTE_4_DESTINATION, HOST_ROUTE_4_NEXTHOP);
+    private static final int HOST_ROUTES_SIZE = 26;
 
     private static final String IP_SUBNET_ID = "1";
 
@@ -213,7 +238,7 @@
         List<DhcpOption> optionList = new ArrayList<>();
 
         // DHCP message type
-        option.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
+        option.setCode(OptionCode_MessageType.getValue());
         option.setLength((byte) 1);
         byte[] optionData = {(byte) msgType.getValue()};
         option.setData(optionData);
@@ -221,15 +246,50 @@
 
         // DHCP requested IP address
         option = new DhcpOption();
-        option.setCode(DHCP.DHCPOptionCode.OptionCode_RequestedIP.getValue());
+        option.setCode(OptionCode_RequestedIP.getValue());
         option.setLength((byte) 4);
         optionData = Ip4Address.valueOf(EXPECTED_IP).toOctets();
         option.setData(optionData);
         optionList.add(option);
 
+        // DHCP domain server
+        Subnet subnet = dhcpHandler.osNetworkService.subnet("subnet");
+
+        option = new DhcpOption();
+        option.setCode(OptionCode_DomainServer.getValue());
+        option.setLength((byte) 8);
+        ByteBuffer dnsByteBuf = ByteBuffer.allocate(8);
+        dnsByteBuf.put(DEFAULT_PRIMARY_DNS.toOctets());
+        dnsByteBuf.put(DEFAULT_SECONDARY_DNS.toOctets());
+        option.setData(dnsByteBuf.array());
+        optionList.add(option);
+
+        // MTU
+        option = new DhcpOption();
+        option.setCode(DHCP_OPTION_MTU);
+        option.setLength((byte) 2);
+        option.setData(ByteBuffer.allocate(2).putShort(MTU).array());
+        optionList.add(option);
+
+        // classless static route
+        option = new DhcpOption();
+        option.setCode(OptionCode_Classless_Static_Route.getValue());
+
+        option.setLength((byte) HOST_ROUTES_SIZE);
+        ByteBuffer hostRouteByteBuf = ByteBuffer.allocate(HOST_ROUTES_SIZE);
+
+        subnet.getHostRoutes().forEach(h -> {
+            IpPrefix ipPrefix = IpPrefix.valueOf(h.getDestination());
+            hostRouteByteBuf.put(bytesDestinationDescriptor(ipPrefix));
+            hostRouteByteBuf.put(Ip4Address.valueOf(h.getNexthop()).toOctets());
+        });
+
+        option.setData(hostRouteByteBuf.array());
+        optionList.add(option);
+
         // DHCP options end...
         option = new DhcpOption();
-        option.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
+        option.setCode(OptionCode_END.getValue());
         option.setLength((byte) 1);
         optionList.add(option);
 
@@ -242,6 +302,37 @@
         return ethFrame;
     }
 
+    private byte[] bytesDestinationDescriptor(IpPrefix ipPrefix) {
+        ByteBuffer byteBuffer;
+        int prefixLen = ipPrefix.prefixLength();
+
+        // retrieve ipPrefix to the destination descriptor format
+        // ex) 10.1.1.0/24 -> [10,1,1,0]
+        String[] ipPrefixString = ipPrefix.getIp4Prefix().toString()
+                .split("/")[0]
+                .split("\\.");
+
+        // retrieve destination descriptor and put this to bytebuffer according to RFC 3442
+        // ex) 0.0.0.0/0 -> 0
+        // ex) 10.0.0.0/8 -> 8.10
+        // ex) 10.17.0.0/16 -> 16.10.17
+        // ex) 10.27.129.0/24 -> 24.10.27.129
+        // ex) 10.229.0.128/25 -> 25.10.229.0.128
+        for (int i = 0; i <= 4; i++) {
+            if (prefixLen == Math.min(prefixLen, i * 8)) {
+                byteBuffer = ByteBuffer.allocate(i + 1);
+                byteBuffer.put((byte) prefixLen);
+
+                for (int j = 0; j < i; j++) {
+                    byteBuffer.put((byte) Integer.parseInt(ipPrefixString[j]));
+                }
+                return byteBuffer.array();
+            }
+        }
+
+        return null;
+    }
+
     /**
      * Mocks the CoreService.
      */
@@ -517,6 +608,7 @@
 
             }
         }
+
         /**
          * Mocks the Neutron subnet.
          */
@@ -534,7 +626,11 @@
 
             @Override
             public List<String> getDnsNames() {
-                return Lists.newArrayList();
+                List<String> dnsServers = Lists.newArrayList();
+                dnsServers.add(DEFAULT_PRIMARY_DNS.toString());
+                dnsServers.add(DEFAULT_SECONDARY_DNS.toString());
+
+                return dnsServers;
             }
 
             @Override
@@ -544,7 +640,14 @@
 
             @Override
             public List<? extends HostRoute> getHostRoutes() {
-                return Lists.newArrayList();
+                List<HostRoute> hostRoutes = Lists.newArrayList();
+
+                hostRoutes.add(HOST_ROUTE_1);
+                hostRoutes.add(HOST_ROUTE_2);
+                hostRoutes.add(HOST_ROUTE_3);
+                hostRoutes.add(HOST_ROUTE_4);
+
+                return hostRoutes;
             }
 
             @Override