[ONOS-2831] Refactor L2 code according to the L3 plan. 

Change-Id: Ibc9dc47a18208b9b1602261064a33bc63b131fc3
diff --git a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/ClassifierService.java b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/ClassifierService.java
new file mode 100644
index 0000000..84fcefb
--- /dev/null
+++ b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/ClassifierService.java
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+package org.onosproject.vtn.table;
+
+import org.onlab.packet.MacAddress;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flowobjective.Objective;
+import org.onosproject.vtnrsc.SegmentationId;
+
+/**
+ * Applies classifier flows to the device.
+ */
+public interface ClassifierService {
+
+    /**
+     * The port rule that message from host matches Table(0) Match: host mac and
+     * ingress port Action: set vnid and go to table(50).
+     *
+     * @param deviceId Device Id
+     * @param segmentationId the vnid of the host belong to
+     * @param inPort the ingress port of the host
+     * @param srcMac the mac of the host
+     * @param appId the application ID of the vtn
+     * @param type the operation of the flow
+     */
+    void programLocalIn(DeviceId deviceId, SegmentationId segmentationId,
+                        PortNumber inPort, MacAddress srcMac,
+                        ApplicationId appId, Objective.Operation type);
+
+    /**
+     * The port rule that message from tunnel Table(0) Match: tunnel port and
+     * vnid Action: go to table(50).
+     *
+     * @param deviceId Device Id
+     * @param segmentationId the vnid of the host belong to
+     * @param localTunnelPorts the tunnel pors of the device
+     * @param type the operation of the flow
+     */
+    void programTunnelIn(DeviceId deviceId, SegmentationId segmentationId,
+                         Iterable<PortNumber> localTunnelPorts,
+                         Objective.Operation type);
+
+}
diff --git a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/L2ForwardService.java b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/L2ForwardService.java
new file mode 100644
index 0000000..3781c2b
--- /dev/null
+++ b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/L2ForwardService.java
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+package org.onosproject.vtn.table;
+
+import org.onlab.packet.MacAddress;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flowobjective.Objective;
+import org.onosproject.vtnrsc.SegmentationId;
+
+/**
+ * Applies L2 flows to the device.
+ */
+public interface L2ForwardService {
+
+    /**
+     * The local broadcast rule that message matches Table(50) Match: broadcast
+     * mac and vnid Action: output port.
+     *
+     * @param deviceId Device Id
+     * @param segmentationId the vnid of the host belong to
+     * @param inPort the ingress port of the host
+     * @param localVmPorts the local ports of the network which connect host
+     * @param localTunnelPorts the tunnel pors of the device
+     * @param type the operation of the flow
+     */
+    void programLocalBcastRules(DeviceId deviceId,
+                                SegmentationId segmentationId,
+                                PortNumber inPort,
+                                Iterable<PortNumber> localVmPorts,
+                                Iterable<PortNumber> localTunnelPorts,
+                                Objective.Operation type);
+
+    /**
+     * The tunnel broadcast rule that message matches Table(50) Match: broadcast
+     * mac and vnid Action: output port.
+     *
+     * @param deviceId Device Id
+     * @param segmentationId the vnid of the host belong to
+     * @param localVmPorts the local ports of the network which connect host
+     * @param localTunnelPorts the tunnel pors of the device
+     * @param type the operation of the flow
+     */
+    void programTunnelBcastRules(DeviceId deviceId,
+                                 SegmentationId segmentationId,
+                                 Iterable<PortNumber> localVmPorts,
+                                 Iterable<PortNumber> localTunnelPorts,
+                                 Objective.Operation type);
+
+    /**
+     * The local out rule that message matches. Table(50) Match: local host mac
+     * and vnid Action: output local host port.
+     *
+     * @param deviceId Device Id
+     * @param segmentationId the vnid of the host belong to
+     * @param outPort the ingress port of the host
+     * @param sourceMac the mac of the host
+     * @param type the operation of the flow
+     */
+    void programLocalOut(DeviceId deviceId, SegmentationId segmentationId,
+                         PortNumber outPort, MacAddress sourceMac,
+                         Objective.Operation type);
+
+    /**
+     * The tunnel out rule that message matches. Table(50) Match: host mac and
+     * vnid Action: output tunnel port.
+     *
+     * @param deviceId Device Id
+     * @param segmentationId the vnid of the host belong to
+     * @param tunnelOutPort the port of the tunnel
+     * @param dstMac the mac of the host
+     * @param type the operation of the flow
+     */
+    void programTunnelOut(DeviceId deviceId, SegmentationId segmentationId,
+                          PortNumber tunnelOutPort, MacAddress dstMac,
+                          Objective.Operation type);
+
+}
diff --git a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/impl/ClassifierServiceImpl.java b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/impl/ClassifierServiceImpl.java
new file mode 100644
index 0000000..620a0e9
--- /dev/null
+++ b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/impl/ClassifierServiceImpl.java
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+package org.onosproject.vtn.table.impl;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import org.onlab.osgi.DefaultServiceDirectory;
+import org.onlab.osgi.ServiceDirectory;
+import org.onlab.packet.MacAddress;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criteria;
+import org.onosproject.net.flow.instructions.Instructions;
+import org.onosproject.net.flowobjective.DefaultForwardingObjective;
+import org.onosproject.net.flowobjective.FlowObjectiveService;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.net.flowobjective.ForwardingObjective.Flag;
+import org.onosproject.net.flowobjective.Objective;
+import org.onosproject.vtn.table.ClassifierService;
+import org.onosproject.vtnrsc.SegmentationId;
+import org.slf4j.Logger;
+
+import com.google.common.collect.Sets;
+
+/**
+ * Provides implementation of ClassifierService.
+ */
+public class ClassifierServiceImpl implements ClassifierService {
+    private final Logger log = getLogger(getClass());
+
+    private static final int L2_CLAFFIFIER_PRIORITY = 50000;
+
+    private final FlowObjectiveService flowObjectiveService;
+    private final ApplicationId appId;
+
+    /**
+     * Constructor.
+     *
+     * @param appId the application id of vtn
+     */
+    public ClassifierServiceImpl(ApplicationId appId) {
+        this.appId = checkNotNull(appId, "ApplicationId can not be null");
+        ServiceDirectory serviceDirectory = new DefaultServiceDirectory();
+        this.flowObjectiveService = serviceDirectory.get(FlowObjectiveService.class);
+    }
+
+    @Override
+    public void programLocalIn(DeviceId deviceId,
+                               SegmentationId segmentationId, PortNumber inPort,
+                               MacAddress srcMac, ApplicationId appid,
+                               Objective.Operation type) {
+        TrafficSelector selector = DefaultTrafficSelector.builder()
+                .matchInPort(inPort).matchEthSrc(srcMac).build();
+        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+        treatment.add(Instructions
+                .modTunnelId(Long.parseLong(segmentationId.toString())));
+        ForwardingObjective.Builder objective = DefaultForwardingObjective
+                .builder().withTreatment(treatment.build())
+                .withSelector(selector).fromApp(appId).makePermanent()
+                .withFlag(Flag.SPECIFIC).withPriority(L2_CLAFFIFIER_PRIORITY);
+        if (type.equals(Objective.Operation.ADD)) {
+            log.debug("programLocalIn-->ADD");
+            flowObjectiveService.forward(deviceId, objective.add());
+        } else {
+            log.debug("programLocalIn-->REMOVE");
+            flowObjectiveService.forward(deviceId, objective.remove());
+        }
+    }
+
+    @Override
+    public void programTunnelIn(DeviceId deviceId,
+                                SegmentationId segmentationId,
+                                Iterable<PortNumber> localTunnelPorts,
+                                Objective.Operation type) {
+        if (localTunnelPorts == null) {
+            log.info("No tunnel port in device");
+            return;
+        }
+        Sets.newHashSet(localTunnelPorts).stream().forEach(tp -> {
+            TrafficSelector selector = DefaultTrafficSelector.builder()
+                    .matchInPort(tp).add(Criteria.matchTunnelId(Long
+                            .parseLong(segmentationId.toString())))
+                    .build();
+
+            TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                    .build();
+            ForwardingObjective.Builder objective = DefaultForwardingObjective
+                    .builder().withTreatment(treatment).withSelector(selector)
+                    .fromApp(appId).makePermanent().withFlag(Flag.SPECIFIC)
+                    .withPriority(L2_CLAFFIFIER_PRIORITY);
+            if (type.equals(Objective.Operation.ADD)) {
+                log.debug("programTunnelIn-->ADD");
+                flowObjectiveService.forward(deviceId, objective.add());
+            } else {
+                log.debug("programTunnelIn-->REMOVE");
+                flowObjectiveService.forward(deviceId, objective.remove());
+            }
+        });
+    }
+
+}
diff --git a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/impl/L2ForwardServiceImpl.java b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/impl/L2ForwardServiceImpl.java
new file mode 100644
index 0000000..64c5fee
--- /dev/null
+++ b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/impl/L2ForwardServiceImpl.java
@@ -0,0 +1,193 @@
+/*
+ * 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.
+ */
+package org.onosproject.vtn.table.impl;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import org.onlab.osgi.DefaultServiceDirectory;
+import org.onlab.osgi.ServiceDirectory;
+import org.onlab.packet.MacAddress;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criteria;
+import org.onosproject.net.flowobjective.DefaultForwardingObjective;
+import org.onosproject.net.flowobjective.FlowObjectiveService;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.net.flowobjective.ForwardingObjective.Flag;
+import org.onosproject.net.flowobjective.Objective;
+import org.onosproject.vtn.table.L2ForwardService;
+import org.onosproject.vtnrsc.SegmentationId;
+import org.slf4j.Logger;
+
+import com.google.common.collect.Sets;
+
+/**
+ * Provides implementation of L2ForwardService.
+ */
+public final class L2ForwardServiceImpl implements L2ForwardService {
+    private final Logger log = getLogger(getClass());
+
+    private static final int MAC_PRIORITY = 0xffff;
+
+    private final FlowObjectiveService flowObjectiveService;
+    private final ApplicationId appId;
+
+    /**
+     * Constructor.
+     *
+     * @param appId the application id of vtn
+     */
+    public L2ForwardServiceImpl(ApplicationId appId) {
+        this.appId = checkNotNull(appId, "ApplicationId can not be null");
+        ServiceDirectory serviceDirectory = new DefaultServiceDirectory();
+        this.flowObjectiveService = serviceDirectory.get(FlowObjectiveService.class);
+    }
+
+    @Override
+    public void programLocalBcastRules(DeviceId deviceId,
+                                       SegmentationId segmentationId,
+                                       PortNumber inPort,
+                                       Iterable<PortNumber> localVmPorts,
+                                       Iterable<PortNumber> localTunnelPorts,
+                                       Objective.Operation type) {
+        if (localVmPorts == null || localTunnelPorts == null) {
+            log.info("No other host port and tunnel in the device");
+            return;
+        }
+        Sets.newHashSet(localVmPorts).stream().forEach(lp -> {
+            TrafficSelector selector = DefaultTrafficSelector.builder()
+                    .matchInPort(lp).matchEthDst(MacAddress.BROADCAST)
+                    .add(Criteria.matchTunnelId(Long
+                            .parseLong(segmentationId.toString())))
+                    .build();
+            TrafficTreatment.Builder treatment = DefaultTrafficTreatment
+                    .builder();
+            boolean flag = false;
+            for (PortNumber outPort : localVmPorts) {
+                flag = true;
+                if (outPort != lp) {
+                    treatment.setOutput(outPort);
+                }
+            }
+            if (type.equals(Objective.Operation.REMOVE) && inPort == lp) {
+                flag = false;
+            }
+            for (PortNumber outport : localTunnelPorts) {
+                treatment.setOutput(outport);
+            }
+            ForwardingObjective.Builder objective = DefaultForwardingObjective
+                    .builder().withTreatment(treatment.build())
+                    .withSelector(selector).fromApp(appId).makePermanent()
+                    .withFlag(Flag.SPECIFIC).withPriority(MAC_PRIORITY);
+            if (flag) {
+                flowObjectiveService.forward(deviceId, objective.add());
+            } else {
+                flowObjectiveService.forward(deviceId, objective.remove());
+            }
+        });
+    }
+
+    @Override
+    public void programTunnelBcastRules(DeviceId deviceId,
+                                        SegmentationId segmentationId,
+                                        Iterable<PortNumber> localVmPorts,
+                                        Iterable<PortNumber> localTunnelPorts,
+                                        Objective.Operation type) {
+        if (localVmPorts == null || localTunnelPorts == null) {
+            log.info("No other host port or tunnel ports in the device");
+            return;
+        }
+        Sets.newHashSet(localTunnelPorts).stream().forEach(tp -> {
+            TrafficSelector selector = DefaultTrafficSelector.builder()
+                    .matchInPort(tp)
+                    .add(Criteria.matchTunnelId(Long
+                            .parseLong(segmentationId.toString())))
+                    .matchEthDst(MacAddress.BROADCAST).build();
+            TrafficTreatment.Builder treatment = DefaultTrafficTreatment
+                    .builder();
+
+            for (PortNumber outPort : localVmPorts) {
+                treatment.setOutput(outPort);
+            }
+
+            ForwardingObjective.Builder objective = DefaultForwardingObjective
+                    .builder().withTreatment(treatment.build())
+                    .withSelector(selector).fromApp(appId).makePermanent()
+                    .withFlag(Flag.SPECIFIC).withPriority(MAC_PRIORITY);
+            if (type.equals(Objective.Operation.ADD)) {
+                if (Sets.newHashSet(localVmPorts).size() == 0) {
+                    flowObjectiveService.forward(deviceId, objective.remove());
+                } else {
+                    flowObjectiveService.forward(deviceId, objective.add());
+                }
+            } else {
+                flowObjectiveService.forward(deviceId, objective.remove());
+            }
+        });
+    }
+
+    @Override
+    public void programLocalOut(DeviceId deviceId,
+                                SegmentationId segmentationId,
+                                PortNumber outPort, MacAddress sourceMac,
+                                Objective.Operation type) {
+        TrafficSelector selector = DefaultTrafficSelector.builder()
+                .matchTunnelId(Long.parseLong(segmentationId.toString()))
+                .matchEthDst(sourceMac).build();
+        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                .setOutput(outPort).build();
+        ForwardingObjective.Builder objective = DefaultForwardingObjective
+                .builder().withTreatment(treatment).withSelector(selector)
+                .fromApp(appId).withFlag(Flag.SPECIFIC)
+                .withPriority(MAC_PRIORITY);
+        if (type.equals(Objective.Operation.ADD)) {
+            flowObjectiveService.forward(deviceId, objective.add());
+        } else {
+            flowObjectiveService.forward(deviceId, objective.remove());
+        }
+
+    }
+
+    @Override
+    public void programTunnelOut(DeviceId deviceId,
+                                 SegmentationId segmentationId,
+                                 PortNumber tunnelOutPort, MacAddress dstMac,
+                                 Objective.Operation type) {
+        TrafficSelector selector = DefaultTrafficSelector.builder()
+                .matchEthDst(dstMac).add(Criteria.matchTunnelId(Long
+                        .parseLong(segmentationId.toString())))
+                .build();
+        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                .setOutput(tunnelOutPort).build();
+        ForwardingObjective.Builder objective = DefaultForwardingObjective
+                .builder().withTreatment(treatment).withSelector(selector)
+                .fromApp(appId).withFlag(Flag.SPECIFIC)
+                .withPriority(MAC_PRIORITY);
+        if (type.equals(Objective.Operation.ADD)) {
+            flowObjectiveService.forward(deviceId, objective.add());
+        } else {
+            flowObjectiveService.forward(deviceId, objective.remove());
+        }
+
+    }
+
+}
diff --git a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/impl/package-info.java b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/impl/package-info.java
new file mode 100644
index 0000000..fd2e18e
--- /dev/null
+++ b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/impl/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/**
+ * VTN application that applies configuration and flows to the device.
+ */
+package org.onosproject.vtn.table.impl;
diff --git a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/package-info.java b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/package-info.java
new file mode 100644
index 0000000..cf53c96
--- /dev/null
+++ b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/**
+ * VTN application that applies configuration and flows to the device.
+ */
+package org.onosproject.vtn.table;