Add push VLAN treatment and use it in BgpRouter groups

Change-Id: I8c241fd776cdddd77969413736bd786c0d5a4828
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 e5de812..cc50819 100644
--- a/apps/bgprouter/src/main/java/org/onosproject/bgprouter/BgpRouter.java
+++ b/apps/bgprouter/src/main/java/org/onosproject/bgprouter/BgpRouter.java
@@ -20,17 +20,17 @@
 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;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.onlab.packet.Ethernet;
-import org.onlab.packet.MacAddress;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
+import org.onosproject.config.NetworkConfigService;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.net.DeviceId;
@@ -39,12 +39,12 @@
 import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRule.Type;
 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.FlowRule.Type;
 import org.onosproject.net.group.DefaultGroupBucket;
 import org.onosproject.net.group.DefaultGroupDescription;
 import org.onosproject.net.group.Group;
@@ -64,7 +64,6 @@
 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;
 
@@ -264,6 +263,7 @@
             TrafficTreatment treatment = DefaultTrafficTreatment.builder()
                     .setEthSrc(egressIntf.mac())
                     .setEthDst(nextHop.mac())
+                    .pushVlan()
                     .setVlanId(egressIntf.vlan())
                     .setOutput(egressIntf.connectPoint().port())
                     .build();
@@ -334,7 +334,6 @@
             processTableFive(install);
             processTableSix(install);
             processTableNine(install);
-
         }
 
         private void getIntefaceConfig(Set<Interface> intfs) {
@@ -416,7 +415,6 @@
             FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
             FlowRule rule;
 
-
             selector.matchEthType(Ethernet.TYPE_VLAN);
             treatment.transition(FlowRule.Type.VLAN);
 
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 aa5af74..499e9e7 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
@@ -300,6 +300,11 @@
         }
 
         @Override
+        public Builder pushVlan() {
+            return add(Instructions.pushVlan());
+        }
+
+        @Override
         public Builder transition(FlowRule.Type type) {
             return add(Instructions.transition(type));
         }
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 b44411b..db634ff 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
@@ -15,18 +15,17 @@
  */
 package org.onosproject.net.flow;
 
-import java.util.List;
-
-import org.onosproject.core.GroupId;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.flow.DefaultTrafficTreatment.Builder;
-import org.onosproject.net.flow.instructions.Instruction;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.MplsLabel;
 import org.onlab.packet.VlanId;
+import org.onosproject.core.GroupId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.instructions.Instruction;
 import org.onosproject.net.flow.instructions.Instructions;
 
+import java.util.List;
+
 /**
  * Abstraction of network traffic treatment.
  */
@@ -247,6 +246,13 @@
         public Builder popVlan();
 
         /**
+         * Pushes a new VLAN tag.
+         *
+         * @return a treatment builder.
+         */
+        public Builder pushVlan();
+
+        /**
          * Any instructions preceded by this method call will be deferred.
          * @return a treatment builder
          */
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 47e473f..3a0566d 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
@@ -15,12 +15,11 @@
  */
 package org.onosproject.net.flow.instructions;
 
-import static com.google.common.base.MoreObjects.toStringHelper;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.onosproject.net.flow.instructions.L2ModificationInstruction.*;
-
-import java.util.Objects;
-
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.MplsLabel;
+import org.onlab.packet.VlanId;
 import org.onosproject.core.GroupId;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.flow.FlowRule;
@@ -33,11 +32,17 @@
 import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPv6FlowLabelInstruction;
 import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModTtlInstruction;
 
-import org.onlab.packet.Ethernet;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.MplsLabel;
-import org.onlab.packet.VlanId;
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction;
+import static org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsTtlInstruction;
+import static org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
+import static org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanPcpInstruction;
+import static org.onosproject.net.flow.instructions.L2ModificationInstruction.PopVlanInstruction;
+import static org.onosproject.net.flow.instructions.L2ModificationInstruction.PushHeaderInstructions;
+import static org.onosproject.net.flow.instructions.L2ModificationInstruction.StripVlanInstruction;
 
 /**
  * Factory class for creating various traffic treatment instructions.
@@ -62,6 +67,7 @@
 
     /**
      * Creates a drop instruction.
+     *
      * @return drop instruction
      */
     public static DropInstruction createDrop() {
@@ -81,7 +87,8 @@
 
     /**
      * Creates a l0 modification.
-     * @param lambda the lambda to modify to.
+     *
+     * @param lambda the lambda to modify to
      * @return a l0 modification
      */
     public static L0ModificationInstruction modL0Lambda(short lambda) {
@@ -91,7 +98,8 @@
 
     /**
      * Creates a l2 src modification.
-     * @param addr the mac address to modify to.
+     *
+     * @param addr the mac address to modify to
      * @return a l2 modification
      */
     public static L2ModificationInstruction modL2Src(MacAddress addr) {
@@ -101,7 +109,8 @@
 
     /**
      * Creates a L2 dst modification.
-     * @param addr the mac address to modify to.
+     *
+     * @param addr the mac address to modify to
      * @return a L2 modification
      */
     public static L2ModificationInstruction modL2Dst(MacAddress addr) {
@@ -110,8 +119,9 @@
     }
 
     /**
-     * Creates a Vlan id modification.
-     * @param vlanId the vlan id to modify to.
+     * Creates a VLAN ID modification.
+     *
+     * @param vlanId the VLAN ID to modify to
      * @return a L2 modification
      */
     public static L2ModificationInstruction modVlanId(VlanId vlanId) {
@@ -120,8 +130,9 @@
     }
 
     /**
-     * Creates a Vlan pcp modification.
-     * @param vlanPcp the pcp to modify to.
+     * Creates a VLAN PCP modification.
+     *
+     * @param vlanPcp the PCP to modify to
      * @return a L2 modification
      */
     public static L2ModificationInstruction modVlanPcp(Byte vlanPcp) {
@@ -131,6 +142,7 @@
 
     /**
      * Strips the VLAN tag if one is present.
+     *
      * @return a L2 modification
      */
     public static L2ModificationInstruction stripVlanId() {
@@ -139,7 +151,8 @@
 
     /**
      * Creates a MPLS label modification.
-     * @param mplsLabel to set.
+     *
+     * @param mplsLabel MPLS label to set
      * @return a L2 Modification
      */
     public static L2ModificationInstruction modMplsLabel(MplsLabel mplsLabel) {
@@ -148,7 +161,7 @@
     }
 
     /**
-     * Creates a MPLS TTL modification.
+     * Creates a MPLS decrement TTL modification.
      *
      * @return a L2 Modification
      */
@@ -211,7 +224,8 @@
     }
 
     /**
-     * Creates a L3 TTL modification.
+     * Creates a L3 decrement TTL modification.
+     *
      * @return a L3 modification
      */
     public static L3ModificationInstruction decNwTtl() {
@@ -219,7 +233,8 @@
     }
 
     /**
-     * Creates a L3 TTL modification.
+     * Creates a L3 copy TTL to outer header modification.
+     *
      * @return a L3 modification
      */
     public static L3ModificationInstruction copyTtlOut() {
@@ -227,7 +242,8 @@
     }
 
     /**
-     * Creates a L3 TTL modification.
+     * Creates a L3 copy TTL to inner header modification.
+     *
      * @return a L3 modification
      */
     public static L3ModificationInstruction copyTtlIn() {
@@ -235,7 +251,8 @@
     }
 
     /**
-     * Creates a mpls header instruction.
+     * Creates a push MPLS header instruction.
+     *
      * @return a L2 modification.
      */
     public static Instruction pushMpls() {
@@ -244,7 +261,8 @@
     }
 
     /**
-     * Creates a mpls header instruction.
+     * Creates a pop MPLS header instruction.
+     *
      * @return a L2 modification.
      */
     public static Instruction popMpls() {
@@ -253,7 +271,7 @@
     }
 
     /**
-     * Creates a mpls header instruction.
+     * Creates a pop MPLS header instruction with a particular ethertype.
      *
      * @param etherType Ethernet type to set
      * @return a L2 modification.
@@ -264,15 +282,26 @@
     }
 
     /**
-     * Creates a vlan header instruction.
-     * @return a L2 modification.
+     * Creates a pop VLAN header instruction.
+     *
+     * @return a L2 modification
      */
     public static Instruction popVlan() {
         return new PopVlanInstruction(L2SubType.VLAN_POP);
     }
 
     /**
+     * Creates a push VLAN header instruction.
+     *
+     * @return a L2 modification
+     */
+    public static Instruction pushVlan() {
+        return new PushHeaderInstructions(L2SubType.VLAN_PUSH, Ethernet.TYPE_VLAN);
+    }
+
+    /**
      * Sends the packet to the table described in 'type'.
+     *
      * @param type flow rule table type
      * @return table type transition instruction
      */
@@ -296,7 +325,6 @@
         @Override
         public String toString() {
             return toStringHelper(type().toString()).toString();
-
         }
 
         @Override
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 2a93b45..e29ffb9 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
@@ -15,14 +15,14 @@
  */
 package org.onosproject.net.flow.instructions;
 
-import static com.google.common.base.MoreObjects.toStringHelper;
-
-import java.util.Objects;
-
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.MplsLabel;
 import org.onlab.packet.VlanId;
 
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
 /**
  * Abstraction of a single traffic treatment step.
  */
@@ -80,7 +80,12 @@
         /**
          * VLAN Pop modification.
          */
-        VLAN_POP
+        VLAN_POP,
+
+        /**
+         * VLAN Push modification.
+         */
+        VLAN_PUSH
     }
 
     // TODO: Create factory class 'Instructions' that will have various factory
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 d253aef..cf4f490 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
@@ -345,6 +345,10 @@
                 return factory().actions().decMplsTtl();
             case VLAN_POP:
                 return factory().actions().popVlan();
+            case VLAN_PUSH:
+                PushHeaderInstructions pushVlanInstruction = (PushHeaderInstructions) l2m;
+                return factory().actions().pushVlan(
+                        EthType.of(pushVlanInstruction.ethernetType()));
             default:
                 log.warn("Unimplemented action type {}.", l2m.subtype());
                 break;
diff --git a/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/GroupModBuilder.java b/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/GroupModBuilder.java
index 07ddbec..25ece46 100644
--- a/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/GroupModBuilder.java
+++ b/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/GroupModBuilder.java
@@ -183,6 +183,7 @@
         if (treatment == null) {
             return actions;
         }
+
         for (Instruction i : treatment.instructions()) {
             switch (i.type()) {
                 case DROP:
@@ -254,6 +255,13 @@
                         (L2ModificationInstruction.ModVlanPcpInstruction) l2m;
                 oxm = factory.oxms().vlanPcp(VlanPcp.of(vlanPcp.vlanPcp()));
                 break;
+            case VLAN_POP:
+                return factory.actions().popVlan();
+            case VLAN_PUSH:
+                L2ModificationInstruction.PushHeaderInstructions pushVlanInstruction
+                        = (L2ModificationInstruction.PushHeaderInstructions) l2m;
+                return factory.actions().pushVlan(
+                        EthType.of(pushVlanInstruction.ethernetType()));
             case MPLS_PUSH:
                 L2ModificationInstruction.PushHeaderInstructions pushHeaderInstructions =
                         (L2ModificationInstruction.PushHeaderInstructions) l2m;