Getting router interface config into the corsa dataplane pipeline

Change-Id: I67d5bf7a20190b07a7bf55c7b60f771877ca8dbb
diff --git a/apps/bgprouter/pom.xml b/apps/bgprouter/pom.xml
index f5c63db..ae2a9d3 100644
--- a/apps/bgprouter/pom.xml
+++ b/apps/bgprouter/pom.xml
@@ -46,5 +46,11 @@
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
         </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-app-config</artifactId>
+            <version>${project.version}</version>
+        </dependency>
     </dependencies>
 </project>
diff --git a/apps/bgprouter/src/main/java/org/onosproject/bgprouter/BgpRouter.java b/apps/bgprouter/src/main/java/org/onosproject/bgprouter/BgpRouter.java
index 26ca396..aed558b 100644
--- a/apps/bgprouter/src/main/java/org/onosproject/bgprouter/BgpRouter.java
+++ b/apps/bgprouter/src/main/java/org/onosproject/bgprouter/BgpRouter.java
@@ -20,6 +20,7 @@
 import com.google.common.collect.Maps;
 import com.google.common.collect.Multimap;
 import com.google.common.collect.Multiset;
+
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -29,6 +30,7 @@
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
+import org.onlab.packet.VlanId;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.net.DeviceId;
@@ -41,6 +43,7 @@
 import org.onosproject.net.flow.FlowRuleService;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.FlowRule.Type;
 import org.onosproject.net.group.DefaultGroupBucket;
 import org.onosproject.net.group.DefaultGroupDescription;
 import org.onosproject.net.group.Group;
@@ -51,19 +54,24 @@
 import org.onosproject.net.group.GroupKey;
 import org.onosproject.net.group.GroupListener;
 import org.onosproject.net.group.GroupService;
+import org.onosproject.net.host.InterfaceIpAddress;
 import org.onosproject.net.packet.PacketService;
 import org.onosproject.routing.FibEntry;
 import org.onosproject.routing.FibListener;
 import org.onosproject.routing.FibUpdate;
 import org.onosproject.routing.RoutingService;
+import org.onosproject.routing.config.BgpSpeaker;
 import org.onosproject.routing.config.Interface;
 import org.onosproject.routing.config.RoutingConfigurationService;
+import org.onosproject.config.NetworkConfigService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * BgpRouter component.
@@ -95,6 +103,14 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected PacketService packetService;
 
+    //
+    // NOTE: Unused reference - needed to guarantee that the
+    // NetworkConfigReader component is activated and the network configuration
+    // is read.
+    //
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected NetworkConfigService networkConfigService;
+
     private ApplicationId appId;
 
     // Reference count for how many times a next hop is used by a route
@@ -109,7 +125,12 @@
     // Stores FIB updates that are waiting for groups to be set up
     private final Multimap<GroupKey, FibEntry> pendingUpdates = HashMultimap.create();
 
-    private DeviceId deviceId = DeviceId.deviceId("of:0000000000000001"); // TODO config
+    // Device id of data-plane switch - should be learned from config
+    private DeviceId deviceId;
+
+    // Device id of control-plane switch (OVS) connected to BGP Speaker - should be
+    // learned from config
+    private DeviceId ctrlDeviceId;
 
     private final GroupListener groupListener = new InternalGroupListener();
 
@@ -120,10 +141,11 @@
     @Activate
     protected void activate() {
         appId = coreService.registerApplication(BGP_ROUTER_APP);
+        getDeviceConfiguration(configService.getBgpSpeakers());
 
         groupService.addListener(groupListener);
 
-        provisionStaticTables.provision(true);
+        provisionStaticTables.provision(true, configService.getInterfaces());
 
         connectivityManager = new TunnellingConnectivityManager(appId,
                                                                 configService,
@@ -140,13 +162,31 @@
     protected void deactivate() {
         routingService.stop();
         connectivityManager.stop();
-        provisionStaticTables.provision(false);
+        provisionStaticTables.provision(false, configService.getInterfaces());
 
         groupService.removeListener(groupListener);
 
         log.info("BgpRouter stopped");
     }
 
+    private void getDeviceConfiguration(Map<String, BgpSpeaker> bgps) {
+        if (bgps == null || bgps.values().isEmpty()) {
+            log.error("BGP speakers configuration is missing");
+            return;
+        }
+        for (BgpSpeaker s : bgps.values()) {
+            ctrlDeviceId = s.connectPoint().deviceId();
+            if (s.interfaceAddresses() == null || s.interfaceAddresses().isEmpty()) {
+                log.error("BGP Router must have interfaces configured");
+                return;
+            }
+            deviceId = s.interfaceAddresses().get(0).connectPoint().deviceId();
+            break;
+        }
+        log.info("Router dpid: {}", deviceId);
+        log.info("Control Plane OVS dpid: {}", ctrlDeviceId);
+    }
+
     private void updateFibEntry(Collection<FibUpdate> updates) {
         for (FibUpdate update : updates) {
             FibEntry entry = update.entry();
@@ -279,9 +319,13 @@
 
         private static final int CONTROLLER_PRIORITY = 255;
         private static final int DROP_PRIORITY = 0;
+        private static final int HIGHEST_PRIORITY = 0xffff;
+        private Set<InterfaceIpAddress> intfIps = new HashSet<InterfaceIpAddress>();
+        private Set<MacAddress> intfMacs = new HashSet<MacAddress>();
+        private Set<VlanId> intfVlans = new HashSet<VlanId>();
 
-        public void provision(boolean install) {
-
+        public void provision(boolean install, Set<Interface> intfs) {
+            getIntefaceConfig(intfs);
             processTableZero(install);
             processTableOne(install);
             processTableTwo(install);
@@ -292,10 +336,20 @@
 
         }
 
+        private void getIntefaceConfig(Set<Interface> intfs) {
+            log.info("Processing {} router interfaces", intfs.size());
+            for (Interface intf : intfs) {
+                intfIps.addAll(intf.ipAddresses());
+                intfMacs.add(intf.mac());
+                intfVlans.add(intf.vlan());
+            }
+        }
+
         private void processTableZero(boolean install) {
             TrafficSelector.Builder selector;
             TrafficTreatment.Builder treatment;
 
+            // Bcast rule
             selector = DefaultTrafficSelector.builder();
             treatment = DefaultTrafficTreatment.builder();
 
@@ -311,6 +365,23 @@
 
             ops = install ? ops.add(rule) : ops.remove(rule);
 
+            // Interface MACs
+            for (MacAddress mac : intfMacs) {
+                log.debug("adding rule for MAC: {}", mac);
+                selector = DefaultTrafficSelector.builder();
+                treatment = DefaultTrafficTreatment.builder();
+
+                selector.matchEthDst(mac);
+                treatment.transition(FlowRule.Type.VLAN_MPLS);
+
+                rule = new DefaultFlowRule(deviceId, selector.build(),
+                                           treatment.build(),
+                                           CONTROLLER_PRIORITY, appId, 0,
+                                           true, FlowRule.Type.FIRST);
+
+                ops = install ? ops.add(rule) : ops.remove(rule);
+            }
+
             //Drop rule
             selector = DefaultTrafficSelector.builder();
             treatment = DefaultTrafficTreatment.builder();
@@ -404,13 +475,31 @@
         }
 
         private void processTableTwo(boolean install) {
-            TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
-            TrafficTreatment.Builder treatment = DefaultTrafficTreatment
-                    .builder();
+            TrafficSelector.Builder selector;
+            TrafficTreatment.Builder treatment;
             FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
             FlowRule rule;
 
+            //Interface Vlans
+            for (VlanId vid : intfVlans) {
+                log.debug("adding rule for VLAN: {}", vid);
+                selector = DefaultTrafficSelector.builder();
+                treatment = DefaultTrafficTreatment.builder();
+
+                selector.matchVlanId(vid);
+                treatment.popVlan();
+                treatment.transition(Type.ETHER);
+
+                rule = new DefaultFlowRule(deviceId, selector.build(),
+                                           treatment.build(), CONTROLLER_PRIORITY, appId,
+                                           0, true, FlowRule.Type.VLAN);
+
+                ops = install ? ops.add(rule) : ops.remove(rule);
+            }
+
             //Drop rule
+            selector = DefaultTrafficSelector.builder();
+            treatment = DefaultTrafficTreatment.builder();
 
             treatment.drop();
 
@@ -517,13 +606,33 @@
         }
 
         private void processTableSix(boolean install) {
-            TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
-            TrafficTreatment.Builder treatment = DefaultTrafficTreatment
-                    .builder();
+            TrafficSelector.Builder selector;
+            TrafficTreatment.Builder treatment;
             FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
             FlowRule rule;
 
+
+            //Interface IPs
+            for (InterfaceIpAddress ipAddr : intfIps) {
+                log.debug("adding rule for IPs: {}", ipAddr.ipAddress());
+                selector = DefaultTrafficSelector.builder();
+                treatment = DefaultTrafficTreatment.builder();
+
+                selector.matchEthType(Ethernet.TYPE_IPV4);
+                selector.matchIPDst(IpPrefix.valueOf(ipAddr.ipAddress(), 32));
+                treatment.transition(Type.ACL);
+
+                rule = new DefaultFlowRule(deviceId, selector.build(),
+                                           treatment.build(), HIGHEST_PRIORITY, appId,
+                                           0, true, FlowRule.Type.IP);
+
+                ops = install ? ops.add(rule) : ops.remove(rule);
+            }
+
+
             //Drop rule
+            selector = DefaultTrafficSelector.builder();
+            treatment = DefaultTrafficTreatment.builder();
 
             treatment.drop();
 
diff --git a/apps/config/src/main/java/org/onosproject/config/NetworkConfigReader.java b/apps/config/src/main/java/org/onosproject/config/NetworkConfigReader.java
index ccdb7a6..2d58a66 100644
--- a/apps/config/src/main/java/org/onosproject/config/NetworkConfigReader.java
+++ b/apps/config/src/main/java/org/onosproject/config/NetworkConfigReader.java
@@ -64,12 +64,11 @@
 
     @Activate
     protected void activate() {
-        log.info("Started network config reader");
-
         AddressConfiguration config = readNetworkConfig();
         if (config != null) {
             applyNetworkConfig(config);
         }
+        log.info("Started network config reader");
     }
 
     @Deactivate
diff --git a/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java b/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java
index a8880b0..f20d6cc 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java
@@ -255,6 +255,11 @@
         }
 
         @Override
+        public Builder popVlan() {
+            return add(Instructions.popVlan());
+        }
+
+        @Override
         public TrafficTreatment build() {
 
             //If we are dropping should we just return an empty list?
diff --git a/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java b/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java
index e890e62..9926751 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java
@@ -205,6 +205,13 @@
         public Builder transition(FlowRule.Type type);
 
         /**
+         * Pops outermost VLAN tag.
+         *
+         * @return a treatment builder.
+         */
+        public Builder popVlan();
+
+        /**
          * Builds an immutable traffic treatment descriptor.
          *
          * @return traffic treatment
diff --git a/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java b/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java
index 926d267..e0a5ca6 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java
@@ -255,6 +255,19 @@
         return new PushHeaderInstructions(L2SubType.MPLS_POP, etherType);
     }
 
+    /**
+     * Creates a vlan header instruction.
+     * @return a L2 modification.
+     */
+    public static Instruction popVlan() {
+        return new PopVlanInstruction(L2SubType.VLAN_POP);
+    }
+
+    /**
+     * Sends the packet to the table described in 'type'.
+     * @param type
+     * @return
+     */
     public static Instruction transition(FlowRule.Type type) {
         checkNotNull(type, "Table type cannot be null");
         return new TableTypeTransition(type);
diff --git a/core/api/src/main/java/org/onosproject/net/flow/instructions/L2ModificationInstruction.java b/core/api/src/main/java/org/onosproject/net/flow/instructions/L2ModificationInstruction.java
index 2288898..4702266 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/instructions/L2ModificationInstruction.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/instructions/L2ModificationInstruction.java
@@ -70,8 +70,12 @@
         /**
          * MPLS TTL modification.
          */
-        DEC_MPLS_TTL
+        DEC_MPLS_TTL,
 
+        /**
+         * VLAN Pop modification.
+         */
+        VLAN_POP
     }
 
     // TODO: Create factory class 'Instructions' that will have various factory
@@ -269,6 +273,44 @@
         }
     }
 
+    /**
+     * Represents a VLAN POP modification instruction.
+     */
+    public static final class PopVlanInstruction extends L2ModificationInstruction {
+        private final L2SubType subtype;
+
+        PopVlanInstruction(L2SubType subType) {
+            this.subtype = subType;
+        }
+
+        @Override
+        public L2SubType subtype() {
+            return subtype;
+        }
+
+        @Override
+        public String toString() {
+            return toStringHelper(subtype().toString())
+                    .toString();
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(type(), subtype);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj instanceof PushHeaderInstructions) {
+                PushHeaderInstructions that = (PushHeaderInstructions) obj;
+                return  Objects.equals(subtype, that.subtype);
+            }
+            return false;
+        }
+    }
 
     /**
      * Represents a MPLS label modification.
diff --git a/openflow/drivers/src/main/java/org/onosproject/openflow/drivers/OFCorsaSwitchDriver.java b/openflow/drivers/src/main/java/org/onosproject/openflow/drivers/OFCorsaSwitchDriver.java
index 75bb9d4..2c62c74 100644
--- a/openflow/drivers/src/main/java/org/onosproject/openflow/drivers/OFCorsaSwitchDriver.java
+++ b/openflow/drivers/src/main/java/org/onosproject/openflow/drivers/OFCorsaSwitchDriver.java
@@ -89,6 +89,7 @@
 
     @Override
     public void transformAndSendMsg(OFMessage msg, TableType type) {
+        log.trace("Trying to send {} of TableType {}", msg, type);
         if (msg.getType() == OFType.FLOW_MOD) {
             OFFlowMod flowMod = (OFFlowMod) msg;
             OFFlowMod.Builder builder = flowMod.createBuilder();
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java
index f0e4f84..16960a4 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java
@@ -265,10 +265,12 @@
                 OFActionGroup group = (OFActionGroup) act;
                 builder.group(new DefaultGroupId(group.getGroup().getGroupNumber()));
                 break;
+            case POP_VLAN:
+                builder.popVlan();
+                break;
             case SET_TP_DST:
             case SET_TP_SRC:
             case POP_PBB:
-            case POP_VLAN:
             case PUSH_PBB:
             case PUSH_VLAN:
             case SET_MPLS_LABEL:
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java
index 4c2dc93..1a423a9 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java
@@ -327,6 +327,8 @@
                 break;
             case DEC_MPLS_TTL:
                 return factory().actions().decMplsTtl();
+            case VLAN_POP:
+                return factory().actions().popVlan();
             default:
                 log.warn("Unimplemented action type {}.", l2m.subtype());
                 break;