Adds ARP/NDP handler for SDX-L2 and updates the README

Changes:
- Implements the internal ARP/NDP handler;
- Updates the README file;
- Adds interaction with PacketService

Change-Id: I245b2d5df2acaaa4b3f00ca2eed07d18337e41a5
diff --git a/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Manager.java b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Manager.java
index d59b909..21dd06a 100644
--- a/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Manager.java
+++ b/sdx-l2/src/main/java/org/onosproject/sdxl2/SdxL2Manager.java
@@ -23,12 +23,22 @@
 import org.apache.felix.scr.annotations.Service;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Deactivate;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.ICMP6;
+import org.onlab.packet.IPv6;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
 import org.onosproject.net.edge.EdgePortService;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.intent.IntentService;
 import org.onosproject.net.intent.Key;
+import org.onosproject.net.packet.InboundPacket;
+import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketProcessor;
+import org.onosproject.net.packet.PacketService;
 import org.osgi.service.component.ComponentContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -39,6 +49,12 @@
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
+import static org.onlab.packet.Ethernet.TYPE_ARP;
+import static org.onlab.packet.Ethernet.TYPE_IPV6;
+import static org.onlab.packet.ICMP6.NEIGHBOR_ADVERTISEMENT;
+import static org.onlab.packet.ICMP6.NEIGHBOR_SOLICITATION;
+import static org.onlab.packet.IPv6.PROTOCOL_ICMP6;
+import static org.onosproject.net.packet.PacketPriority.CONTROL;
 
 /**
  * Implementation of the SdxL2Service.
@@ -62,20 +78,34 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected EdgePortService edgePortService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected PacketService packetService;
+
+    protected SdxL2Processor processor = new SdxL2Processor();
+
+    protected SdxL2ArpNdpHandler arpndpHandler;
+
     protected ApplicationId appId;
 
     protected SdxL2MonitoringService monitoringManager;
 
+    protected String vcType = "MAC";
+
+
     @Activate
     protected void activate(ComponentContext context) {
         appId = coreService.registerApplication(SDXL2_APP);
         monitoringManager = new SdxL2MonitoringManager(appId, intentService, edgePortService);
+        handleArpNdp();
         log.info("Started");
     }
 
+
+
     @Deactivate
     protected void deactivate() {
         this.cleanSdxL2();
+        unhandleArpNdp();
         log.info("Stopped");
     }
 
@@ -236,4 +266,115 @@
         this.monitoringManager.cleanup();
     }
 
+    /**
+     * It requests ARP and NDP packets to the PacketService
+     * and registers the SDX-L2 PacketProcessor.
+     */
+    private void handleArpNdp() {
+        SdxL2ArpNdpHandler.vcType = vcType;
+        arpndpHandler = new SdxL2ArpNdpHandler(intentService, packetService, appId);
+        packetService.addProcessor(processor, PacketProcessor.director(1));
+
+        // ARP packet
+        TrafficSelector.Builder selectorBuilder =
+                DefaultTrafficSelector.builder();
+        selectorBuilder.matchEthType(TYPE_ARP);
+        packetService.requestPackets(selectorBuilder.build(),
+                CONTROL, appId, Optional.<DeviceId>empty());
+
+        // IPv6 Neighbor Solicitation packet.
+        selectorBuilder = DefaultTrafficSelector.builder();
+        selectorBuilder.matchEthType(TYPE_IPV6);
+        selectorBuilder.matchIPProtocol(PROTOCOL_ICMP6);
+        selectorBuilder.matchIcmpv6Type(NEIGHBOR_SOLICITATION);
+        packetService.requestPackets(selectorBuilder.build(),
+                CONTROL, appId, Optional.<DeviceId>empty());
+
+        // IPv6 Neighbor Advertisement packet.
+        selectorBuilder = DefaultTrafficSelector.builder();
+        selectorBuilder.matchEthType(TYPE_IPV6);
+        selectorBuilder.matchIPProtocol(PROTOCOL_ICMP6);
+        selectorBuilder.matchIcmpv6Type(NEIGHBOR_ADVERTISEMENT);
+        packetService.requestPackets(selectorBuilder.build(),
+                CONTROL, appId, Optional.<DeviceId>empty());
+    }
+
+    /**
+     * Withdraws the requests for ARP/NDP packets and
+     * unregisters the SDX-L2 PacketProcessor.
+     */
+    private void unhandleArpNdp() {
+        arpndpHandler = null;
+        packetService.removeProcessor(processor);
+        processor = null;
+
+        TrafficSelector.Builder selectorBuilder =
+                DefaultTrafficSelector.builder();
+        selectorBuilder.matchEthType(TYPE_ARP);
+        packetService.cancelPackets(selectorBuilder.build(),
+                CONTROL, appId, Optional.<DeviceId>empty());
+
+        selectorBuilder = DefaultTrafficSelector.builder();
+        selectorBuilder.matchEthType(TYPE_IPV6);
+        selectorBuilder.matchIPProtocol(PROTOCOL_ICMP6);
+        selectorBuilder.matchIcmpv6Type(NEIGHBOR_SOLICITATION);
+        packetService.cancelPackets(selectorBuilder.build(),
+                CONTROL, appId, Optional.<DeviceId>empty());
+
+        selectorBuilder = DefaultTrafficSelector.builder();
+        selectorBuilder.matchEthType(TYPE_IPV6);
+        selectorBuilder.matchIPProtocol(PROTOCOL_ICMP6);
+        selectorBuilder.matchIcmpv6Type(NEIGHBOR_ADVERTISEMENT);
+        packetService.cancelPackets(selectorBuilder.build(),
+                CONTROL, appId, Optional.<DeviceId>empty());
+    }
+
+    /**
+     * Packet processor responsible for forwarding packets along their paths.
+     */
+    private class SdxL2Processor implements PacketProcessor {
+
+        /**
+         * Processes the inbound packet as specified in the given context.
+         *
+         * @param context packet processing context
+         */
+        @Override
+        public void process(PacketContext context) {
+
+            /** Stop processing if the packet has been handled, since we
+             * can't do any more to it
+             */
+            if (context.isHandled()) {
+                return;
+            }
+
+            InboundPacket pkt = context.inPacket();
+            Ethernet ethPkt = pkt.parsed();
+            if (ethPkt == null) {
+                return;
+            }
+
+            boolean handled = false;
+            if (ethPkt.getEtherType() == TYPE_ARP) {
+                //handle the arp packet.
+                handled = arpndpHandler.handlePacket(context);
+            } else if (ethPkt.getEtherType() == TYPE_IPV6) {
+                IPv6 ipv6Pkt = (IPv6) ethPkt.getPayload();
+                if (ipv6Pkt.getNextHeader() == IPv6.PROTOCOL_ICMP6) {
+                    ICMP6 icmp6Pkt = (ICMP6) ipv6Pkt.getPayload();
+                    if (icmp6Pkt.getIcmpType() == NEIGHBOR_SOLICITATION ||
+                            icmp6Pkt.getIcmpType() == NEIGHBOR_ADVERTISEMENT) {
+                        // handle ICMPv6 solicitations and advertisements
+                        handled = arpndpHandler.handlePacket(context);
+                    }
+                }
+            }
+
+            if (handled) {
+                context.block();
+            }
+
+        }
+    }
 }