Adding more filtering objectives from the router application and handling them
in the corsa-pipeline driver

Change-Id: I3598b84ce25df97c10b33c6f1fdfc76421499046
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 58e796f..c012999 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;
@@ -30,14 +31,11 @@
 import org.onlab.packet.Ip6Address;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
 import org.onlab.util.KryoNamespace;
 import org.onosproject.config.NetworkConfigService;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.net.DeviceId;
-import org.onosproject.net.PortNumber;
 import org.onosproject.net.flow.DefaultFlowRule;
 import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
@@ -60,7 +58,6 @@
 import org.onosproject.net.group.GroupEvent;
 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;
@@ -75,7 +72,6 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
@@ -146,8 +142,6 @@
 
     private IcmpHandler icmpHandler;
 
-    private InternalTableHandler provisionStaticTables = new InternalTableHandler();
-
     private KryoNamespace appKryo = new KryoNamespace.Builder()
                     .register(IpAddress.Version.class)
                     .register(IpAddress.class)
@@ -168,7 +162,7 @@
 
         groupService.addListener(groupListener);
 
-        provisionStaticTables.provision(true, configService.getInterfaces());
+        processIntfFilters(true, configService.getInterfaces());
 
         connectivityManager = new TunnellingConnectivityManager(appId,
                                                                 configService,
@@ -192,7 +186,7 @@
         routingService.stop();
         connectivityManager.stop();
         icmpHandler.stop();
-        provisionStaticTables.provision(false, configService.getInterfaces());
+        processIntfFilters(false, configService.getInterfaces());
 
         groupService.removeListener(groupListener);
 
@@ -380,30 +374,20 @@
         }
     }
 
-    private class InternalTableHandler {
-
-        private Set<InterfaceIpAddress> intfIps = new HashSet<InterfaceIpAddress>();
-        private Set<MacAddress> intfMacs = new HashSet<MacAddress>();
-        private Map<PortNumber, VlanId> portVlanPair = Maps.newHashMap();
-
-        public void provision(boolean install, Set<Interface> intfs) {
-            getInterfaceConfig(intfs);
+    private void processIntfFilters(boolean install, Set<Interface> intfs) {
+        log.info("Processing {} router interfaces", intfs.size());
+        for (Interface intf : intfs) {
+            FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
+            fob.withKey(Criteria.matchInPort(intf.connectPoint().port()))
+               .addCondition(Criteria.matchEthDst(intf.mac()))
+               .addCondition(Criteria.matchVlanId(intf.vlan()));
+            intf.ipAddresses().stream()
+                .forEach(ipaddr -> fob.addCondition(
+                                   Criteria.matchIPDst(ipaddr.subnetAddress())));
+            fob.permit().fromApp(appId);
+            flowObjectiveService.filter(deviceId,
+                                 Collections.singletonList(fob.add()));
         }
-
-        private void getInterfaceConfig(Set<Interface> intfs) {
-            log.info("Processing {} router interfaces", intfs.size());
-            for (Interface intf : intfs) {
-                FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
-                flowObjectiveService.filter(deviceId, Collections.singletonList(
-                        fob.addCondition(Criteria.matchEthDst(intf.mac()))
-                                .fromApp(appId).permit().add()));
-                intfIps.addAll(intf.ipAddresses());
-                intfMacs.add(intf.mac());
-                portVlanPair.put(intf.connectPoint().port(), intf.vlan());
-            }
-        }
-
-
     }
 
     private class InternalGroupListener implements GroupListener {
diff --git a/drivers/src/main/java/org/onosproject/driver/pipeline/OVSCorsaPipeline.java b/drivers/src/main/java/org/onosproject/driver/pipeline/OVSCorsaPipeline.java
index f4394b7..997c207 100644
--- a/drivers/src/main/java/org/onosproject/driver/pipeline/OVSCorsaPipeline.java
+++ b/drivers/src/main/java/org/onosproject/driver/pipeline/OVSCorsaPipeline.java
@@ -83,53 +83,94 @@
 
     @Override
     public Future<Boolean> filter(Collection<FilteringObjective> filteringObjectives) {
-        Collection<Future<Boolean>> results =
-                Sets.newHashSet();
+        Collection<Future<Boolean>> results = Sets.newHashSet();
         filteringObjectives.stream()
                 .filter(obj -> obj.type() == FilteringObjective.Type.PERMIT)
-                .forEach(obj -> obj.conditions()
-                        .forEach(condition ->
-                            results.add(processCondition(condition,
-                                                   obj.op() == Objective.Operation.ADD,
-                                                   obj.appId()))
-                        ));
+                .forEach(filtobj -> results.add(processFilter(filtobj,
+                                        filtobj.op() == Objective.Operation.ADD,
+                                        filtobj.appId()
+                        )));
 
         //TODO: return something more helpful/sensible in the future (no pun intended)
         return results.iterator().next();
 
     }
 
-    private Future<Boolean> processCondition(Criterion c, boolean install,
+    private Future<Boolean> processFilter(FilteringObjective filt, boolean install,
                                              ApplicationId applicationId) {
         SettableFuture<Boolean> result = SettableFuture.create();
-        if (c.type() == Criterion.Type.ETH_DST) {
-            Criteria.EthCriterion e = (Criteria.EthCriterion) c;
-            log.debug("adding rule for MAC: {}", e.mac());
-
-            TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
-            TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
-            selector.matchEthDst(e.mac());
-            treatment.transition(FlowRule.Type.VLAN_MPLS);
-            FlowRule rule = new DefaultFlowRule(deviceId, selector.build(),
-                                                treatment.build(),
-                                                CONTROLLER_PRIORITY, applicationId, 0,
-                                                true, FlowRule.Type.FIRST);
-            FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
-            ops =  install ? ops.add(rule) : ops.remove(rule);
-            flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
-                @Override
-                public void onSuccess(FlowRuleOperations ops) {
-                    result.set(true);
-                    log.info("Provisioned default table for bgp router");
-                }
-
-                @Override
-                public void onError(FlowRuleOperations ops) {
-                    result.set(false);
-                    log.info("Failed to provision default table for bgp router");
-                }
-            }));
+        // This driver only processes filtering criteria defined with switch
+        // ports as the key
+        Criteria.PortCriterion p = null;
+        if (!filt.key().equals(Criteria.dummy()) &&
+                filt.key().type() == Criterion.Type.IN_PORT) {
+            p = (Criteria.PortCriterion) filt.key();
+        } else {
+            log.warn("No key defined in filtering objective from app: {}. Not"
+                    + "processing filtering objective", applicationId);
+            return null;
         }
+        // convert filtering conditions for switch-intfs into flowrules
+        FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
+        for (Criterion c : filt.conditions()) {
+            if (c.type() == Criterion.Type.ETH_DST) {
+                Criteria.EthCriterion e = (Criteria.EthCriterion) c;
+                log.debug("adding rule for MAC: {}", e.mac());
+                TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+                TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+                selector.matchEthDst(e.mac());
+                treatment.transition(FlowRule.Type.VLAN_MPLS);
+                FlowRule rule = new DefaultFlowRule(deviceId, selector.build(),
+                                                    treatment.build(),
+                                                    CONTROLLER_PRIORITY, applicationId,
+                                                    0, true, FlowRule.Type.FIRST);
+                ops =  install ? ops.add(rule) : ops.remove(rule);
+            } else if (c.type() == Criterion.Type.VLAN_VID) {
+                Criteria.VlanIdCriterion v = (Criteria.VlanIdCriterion) c;
+                log.debug("adding rule for VLAN: {}", v.vlanId());
+                TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+                TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+                selector.matchVlanId(v.vlanId());
+                selector.matchInPort(p.port());
+                treatment.transition(FlowRule.Type.ETHER);
+                treatment.deferred().popVlan();
+                FlowRule rule = new DefaultFlowRule(deviceId, selector.build(),
+                                           treatment.build(),
+                                           CONTROLLER_PRIORITY, applicationId,
+                                           0, true, FlowRule.Type.VLAN);
+                ops = install ? ops.add(rule) : ops.remove(rule);
+            } else if (c.type() == Criterion.Type.IPV4_DST) {
+                Criteria.IPCriterion ip = (Criteria.IPCriterion) c;
+                log.debug("adding rule for IP: {}", ip.ip());
+                TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+                TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+                selector.matchEthType(Ethernet.TYPE_IPV4);
+                selector.matchIPDst(ip.ip());
+                treatment.transition(FlowRule.Type.ACL);
+                FlowRule rule = new DefaultFlowRule(deviceId, selector.build(),
+                                           treatment.build(), HIGHEST_PRIORITY, appId,
+                                           0, true, FlowRule.Type.IP);
+                ops = install ? ops.add(rule) : ops.remove(rule);
+            } else {
+                log.warn("Driver does not currently process filtering condition"
+                        + " of type: {}", c.type());
+            }
+        }
+        // apply filtering flow rules
+        flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
+            @Override
+            public void onSuccess(FlowRuleOperations ops) {
+                result.set(true);
+                log.info("Provisioned default table for bgp router");
+            }
+
+            @Override
+            public void onError(FlowRuleOperations ops) {
+                result.set(false);
+                log.info("Failed to provision default table for bgp router");
+            }
+        }));
+
         return result;
     }