SONA: Pipeline for SONA
- Open vSwitch Pipeline for SONA added
- Only OpenStackSwitching app will use this
- Bug fixed
- Pipeline renamed

Change-Id: I0cee06c84db4f130c01dfea37dbab44bf9c1fd26
diff --git a/drivers/src/main/java/org/onosproject/driver/pipeline/OpenstackPipeline.java b/drivers/src/main/java/org/onosproject/driver/pipeline/OpenstackPipeline.java
new file mode 100644
index 0000000..268a6ac
--- /dev/null
+++ b/drivers/src/main/java/org/onosproject/driver/pipeline/OpenstackPipeline.java
@@ -0,0 +1,290 @@
+package org.onosproject.driver.pipeline;
+
+/**
+ * Created by mcpark on 15. 12. 3.
+ */
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.onlab.osgi.ServiceDirectory;
+import org.onlab.packet.Ethernet;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.behaviour.Pipeliner;
+import org.onosproject.net.behaviour.PipelinerContext;
+import org.onosproject.net.flow.DefaultFlowRule;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleOperations;
+import org.onosproject.net.flow.FlowRuleOperationsContext;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.criteria.EthTypeCriterion;
+import org.onosproject.net.flow.criteria.UdpPortCriterion;
+import org.onosproject.net.flowobjective.FilteringObjective;
+import org.onosproject.net.flowobjective.FlowObjectiveStore;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.net.flowobjective.NextObjective;
+import org.onosproject.net.flowobjective.Objective;
+import org.onosproject.net.flowobjective.ObjectiveError;
+import org.slf4j.Logger;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Driver for OpenstackSwitching.
+ */
+public class OpenstackPipeline extends DefaultSingleTablePipeline
+        implements Pipeliner {
+
+    private final Logger log = getLogger(getClass());
+    private CoreService coreService;
+    private ServiceDirectory serviceDirectory;
+    protected FlowObjectiveStore flowObjectiveStore;
+    protected DeviceId deviceId;
+    protected ApplicationId appId;
+    protected FlowRuleService flowRuleService;
+
+    protected static final int VNI_TABLE = 0;
+    protected static final int FORWARDING_TABLE = 1;
+
+    private static final int DROP_PRIORITY = 0;
+    private static final int TIME_OUT = 0;
+    private static final int DHCP_SERVER_PORT = 67;
+    private static final int DHCP_CLIENT_PORT = 68;
+
+
+    @Override
+    public void init(DeviceId deviceId, PipelinerContext context) {
+        super.init(deviceId, context);
+        this.serviceDirectory = context.directory();
+        this.deviceId = deviceId;
+
+        coreService = serviceDirectory.get(CoreService.class);
+        flowRuleService = serviceDirectory.get(FlowRuleService.class);
+        flowObjectiveStore = context.store();
+
+        appId = coreService.registerApplication(
+                "org.onosproject.driver.OpenstackPipeline");
+
+        initializePipeline();
+    }
+
+    @Override
+    public void filter(FilteringObjective filteringObjective) {
+        super.filter(filteringObjective);
+    }
+
+    @Override
+    public void next(NextObjective nextObjective) {
+        super.next(nextObjective);
+    }
+
+    @Override
+    public void forward(ForwardingObjective forwardingObjective) {
+        Collection<FlowRule> rules;
+        FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
+
+        rules = processForward(forwardingObjective);
+
+        switch (forwardingObjective.op()) {
+            case ADD:
+                rules.stream()
+                        .filter(rule -> rule != null)
+                        .forEach(flowOpsBuilder::add);
+                break;
+            case REMOVE:
+                rules.stream()
+                        .filter(rule -> rule != null)
+                        .forEach(flowOpsBuilder::remove);
+                break;
+            default:
+                fail(forwardingObjective, ObjectiveError.UNKNOWN);
+                log.warn("Unknown forwarding type {}");
+        }
+
+        flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() {
+            @Override
+            public void onSuccess(FlowRuleOperations ops) {
+                pass(forwardingObjective);
+            }
+
+            @Override
+            public void onError(FlowRuleOperations ops) {
+                fail(forwardingObjective, ObjectiveError.FLOWINSTALLATIONFAILED);
+            }
+        }));
+    }
+
+    private void initializePipeline() {
+        processVNITable(true);
+        processForwardingTable(true);
+    }
+
+    private void processVNITable(boolean install) {
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+
+        treatment.transition(FORWARDING_TABLE);
+
+        FlowRule flowRule = DefaultFlowRule.builder()
+                .forDevice(deviceId)
+                .withSelector(selector.build())
+                .withTreatment(treatment.build())
+                .withPriority(DROP_PRIORITY)
+                .fromApp(appId)
+                .makePermanent()
+                .forTable(VNI_TABLE)
+                .build();
+
+        applyRules(install, flowRule);
+    }
+
+    private void processForwardingTable(boolean install) {
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+
+        treatment.drop();
+
+        FlowRule flowRule = DefaultFlowRule.builder()
+                .forDevice(deviceId)
+                .withSelector(selector.build())
+                .withTreatment(treatment.build())
+                .withPriority(DROP_PRIORITY)
+                .fromApp(appId)
+                .makePermanent()
+                .forTable(FORWARDING_TABLE)
+                .build();
+
+        applyRules(install, flowRule);
+    }
+
+    private void applyRules(boolean install, FlowRule flowRule) {
+        FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
+
+        flowOpsBuilder = install ? flowOpsBuilder.add(flowRule) : flowOpsBuilder.remove(flowRule);
+
+        flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() {
+            @Override
+            public void onSuccess(FlowRuleOperations ops) {
+                log.debug("Provisioned vni or forwarding table");
+            }
+
+            @Override
+            public void onError(FlowRuleOperations ops) {
+                log.debug("Failed to privision vni or forwarding table");
+            }
+        }));
+    }
+
+    private Collection<FlowRule> processForward(ForwardingObjective forwardingObjective) {
+        switch (forwardingObjective.flag()) {
+            case SPECIFIC:
+                return processSpecific(forwardingObjective);
+            case VERSATILE:
+                return processVersatile(forwardingObjective);
+            default:
+                fail(forwardingObjective, ObjectiveError.UNKNOWN);
+                log.warn("Unknown forwarding flag {}", forwardingObjective.flag());
+        }
+        return Collections.emptySet();
+    }
+
+    private Collection<FlowRule> processVersatile(ForwardingObjective forwardingObjective) {
+        log.debug("Processing versatile forwarding objective");
+
+        FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
+                .forDevice(deviceId)
+                .withSelector(forwardingObjective.selector())
+                .withTreatment(forwardingObjective.treatment())
+                .withPriority(forwardingObjective.priority())
+                .fromApp(forwardingObjective.appId());
+
+        if (forwardingObjective.permanent()) {
+            ruleBuilder.makePermanent();
+        } else {
+            ruleBuilder.makeTemporary(TIME_OUT);
+        }
+
+        //ARP & DHCP Rule
+        EthTypeCriterion ethCriterion =
+                (EthTypeCriterion) forwardingObjective.selector().getCriterion(Criterion.Type.ETH_TYPE);
+        UdpPortCriterion udpPortCriterion = (UdpPortCriterion) forwardingObjective
+                .selector().getCriterion(Criterion.Type.UDP_DST);
+        if (ethCriterion != null) {
+            if (ethCriterion.ethType().toShort() == Ethernet.TYPE_ARP ||
+                    ethCriterion.ethType().toShort() == Ethernet.TYPE_LLDP) {
+                ruleBuilder.forTable(VNI_TABLE);
+                return Collections.singletonList(ruleBuilder.build());
+            } else if (udpPortCriterion != null && udpPortCriterion.udpPort().toInt() == DHCP_SERVER_PORT) {
+                ruleBuilder.forTable(VNI_TABLE);
+                return Collections.singletonList(ruleBuilder.build());
+            }
+        }
+        return Collections.emptySet();
+    }
+
+    private Collection<FlowRule> processSpecific(ForwardingObjective forwardingObjective) {
+        log.debug("Processing specific forwarding objective");
+
+        FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
+                .forDevice(deviceId)
+                .withSelector(forwardingObjective.selector())
+                .withTreatment(forwardingObjective.treatment())
+                .withPriority(forwardingObjective.priority())
+                .fromApp(forwardingObjective.appId());
+
+        if (forwardingObjective.permanent()) {
+            ruleBuilder.makePermanent();
+        } else {
+            ruleBuilder.makeTemporary(TIME_OUT);
+        }
+
+        //VNI Table Rule
+        if (forwardingObjective.selector().getCriterion(Criterion.Type.IN_PORT) != null) {
+            TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+            forwardingObjective.treatment().allInstructions().forEach(tBuilder::add);
+            tBuilder.transition(FORWARDING_TABLE);
+            ruleBuilder.withTreatment(tBuilder.build());
+            ruleBuilder.forTable(VNI_TABLE);
+        } else {
+            ruleBuilder.forTable(FORWARDING_TABLE);
+        }
+
+        return Collections.singletonList(ruleBuilder.build());
+    }
+
+
+    private void pass(Objective obj) {
+        if (obj.context().isPresent()) {
+            obj.context().get().onSuccess(obj);
+        }
+    }
+
+    private void fail(Objective obj, ObjectiveError error) {
+        if (obj.context().isPresent()) {
+            obj.context().get().onError(obj, error);
+        }
+    }
+}
+