Adding VLAN to PeerConnectivityManager

Change-Id: I695087c108dc4d9d2da61992019d8fa3d08c61c1
diff --git a/apps/routing-api/src/main/java/org/onosproject/routing/config/BgpConfig.java b/apps/routing-api/src/main/java/org/onosproject/routing/config/BgpConfig.java
index dc1cc81..45cda26 100644
--- a/apps/routing-api/src/main/java/org/onosproject/routing/config/BgpConfig.java
+++ b/apps/routing-api/src/main/java/org/onosproject/routing/config/BgpConfig.java
@@ -22,6 +22,7 @@
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.google.common.collect.Sets;
 import org.onlab.packet.IpAddress;
+import org.onlab.packet.VlanId;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.config.Config;
@@ -41,6 +42,7 @@
     public static final String CONNECT_POINT = "connectPoint";
     public static final String NAME = "name";
     public static final String PEERS = "peers";
+    public static final String VLAN = "vlan";
 
     /**
      * Gets the set of configured BGP speakers.
@@ -69,7 +71,10 @@
                 name = Optional.of(jsonNode.get(NAME).asText());
             }
 
+            VlanId vlan = getVlan(jsonNode);
+
             speakers.add(new BgpSpeakerConfig(name,
+                    vlan,
                     ConnectPoint.deviceConnectPoint(jsonNode.path(CONNECT_POINT).asText()),
                     listenAddresses));
         });
@@ -77,6 +82,15 @@
         return speakers;
     }
 
+    // If configured, it retreives a VLAN Id from a BGP speaker node
+    private VlanId getVlan(JsonNode node) {
+        VlanId vlan = VlanId.NONE;
+        if (!node.path(VLAN).isMissingNode()) {
+            vlan = VlanId.vlanId(node.path(VLAN).asText());
+        }
+        return vlan;
+    }
+
     /**
      * Examines whether a name of BGP speaker exists in configuration.
      *
@@ -102,6 +116,8 @@
 
         speakerNode.put(NAME, speaker.name().get());
 
+        speakerNode.put(VLAN, speaker.vlan().toString());
+
         speakerNode.put(CONNECT_POINT, speaker.connectPoint().elementId().toString()
                 + "/" + speaker.connectPoint().port().toString());
 
@@ -157,8 +173,8 @@
     /**
      * Finds BGP speaker peering with a given external peer.
      *
-     * @param peerAddress peering address to be removed
-     * @return speaker
+     * @param peerAddress BGP peer address
+     * @return BGP speaker
      */
     public BgpSpeakerConfig getSpeakerFromPeer(IpAddress peerAddress) {
         for (BgpConfig.BgpSpeakerConfig speaker : bgpSpeakers()) {
@@ -207,12 +223,14 @@
     public static class BgpSpeakerConfig {
 
         private Optional<String> name;
+        private VlanId vlanId;
         private ConnectPoint connectPoint;
         private Set<IpAddress> peers;
 
-        public BgpSpeakerConfig(Optional<String> name, ConnectPoint connectPoint,
-                                Set<IpAddress> peers) {
+        public BgpSpeakerConfig(Optional<String> name, VlanId vlanId,
+                                ConnectPoint connectPoint, Set<IpAddress> peers) {
             this.name = checkNotNull(name);
+            this.vlanId = checkNotNull(vlanId);
             this.connectPoint = checkNotNull(connectPoint);
             this.peers = checkNotNull(peers);
         }
@@ -221,6 +239,10 @@
             return name;
         }
 
+        public VlanId vlan() {
+            return vlanId;
+        }
+
         public ConnectPoint connectPoint() {
             return connectPoint;
         }
@@ -252,6 +274,7 @@
             if (obj instanceof BgpSpeakerConfig) {
                 final BgpSpeakerConfig that = (BgpSpeakerConfig) obj;
                 return Objects.equals(this.name, that.name) &&
+                        Objects.equals(this.vlanId, that.vlanId) &&
                         Objects.equals(this.connectPoint, that.connectPoint) &&
                         Objects.equals(this.peers, that.peers);
             }
@@ -260,7 +283,7 @@
 
         @Override
         public int hashCode() {
-            return Objects.hash(name, connectPoint, peers);
+            return Objects.hash(name, vlanId, connectPoint, peers);
         }
     }
 }
diff --git a/apps/routing-api/src/test/java/org/onosproject/routing/config/BgpConfigTest.java b/apps/routing-api/src/test/java/org/onosproject/routing/config/BgpConfigTest.java
index 28f52b7..130f748 100644
--- a/apps/routing-api/src/test/java/org/onosproject/routing/config/BgpConfigTest.java
+++ b/apps/routing-api/src/test/java/org/onosproject/routing/config/BgpConfigTest.java
@@ -21,6 +21,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.onlab.packet.IpAddress;
+import org.onlab.packet.VlanId;
 import org.onosproject.TestApplicationId;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.net.ConnectPoint;
@@ -51,6 +52,8 @@
     private static final IpAddress IP5 = IpAddress.valueOf("10.0.201.1");
     public static final IpAddress IP_NON_EXIST = IpAddress.valueOf("10.101.1.1");
 
+    public static final VlanId NO_VLAN = VlanId.NONE;
+
     public static final ConnectPoint CONNECT_POINT1 = ConnectPoint.
             deviceConnectPoint("of:0000000000000001/1");
     public static final ConnectPoint CONNECT_POINT2 = ConnectPoint.
@@ -230,7 +233,8 @@
         ConnectPoint connectPoint = CONNECT_POINT1;
         Set<IpAddress> connectedPeers = new HashSet<>(Arrays.asList(IP1, IP2, IP3));
 
-        return new BgpConfig.BgpSpeakerConfig(speakerName, connectPoint, connectedPeers);
+        return new BgpConfig.BgpSpeakerConfig(speakerName, NO_VLAN,
+                                              connectPoint, connectedPeers);
     }
 
     private BgpConfig.BgpSpeakerConfig createNewSpeaker() {
@@ -239,6 +243,7 @@
         Set<IpAddress> connectedPeers = new HashSet<>(
                 Arrays.asList(IP4, IP5));
 
-        return new BgpConfig.BgpSpeakerConfig(speakerName, connectPoint, connectedPeers);
+        return new BgpConfig.BgpSpeakerConfig(speakerName, NO_VLAN,
+                                              connectPoint, connectedPeers);
     }
 }
diff --git a/apps/routing/src/main/java/org/onosproject/routing/cli/AddSpeakerCommand.java b/apps/routing/src/main/java/org/onosproject/routing/cli/AddSpeakerCommand.java
index e414239..19ecc75 100644
--- a/apps/routing/src/main/java/org/onosproject/routing/cli/AddSpeakerCommand.java
+++ b/apps/routing/src/main/java/org/onosproject/routing/cli/AddSpeakerCommand.java
@@ -19,6 +19,7 @@
 import org.apache.karaf.shell.commands.Argument;
 import org.apache.karaf.shell.commands.Command;
 import org.onlab.packet.IpAddress;
+import org.onlab.packet.VlanId;
 import org.onosproject.cli.AbstractShellCommand;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
@@ -40,12 +41,18 @@
     @Argument(index = 0, name = "name",
             description = "Name of the internal BGP speaker",
             required = true, multiValued = false)
-    String name = null;
+    private String name = null;
 
     @Argument(index = 1, name = "connectionPoint",
             description = "Interface to the BGP speaker",
             required = true, multiValued = false)
-    String connectionPoint = null;
+    private String connectionPoint = null;
+
+    @Argument(index = 2, name = "vlanId",
+            description = "VLAN Id of the internal BGP speaker",
+            required = false, multiValued = false)
+    private String vlanId = null;
+    private VlanId vlanIdObj = null;
 
     private static final String SPEAKER_ADD_SUCCESS = "Speaker Successfully Added.";
 
@@ -57,10 +64,18 @@
 
         BgpConfig config = configService.addConfig(appId, BgpConfig.class);
 
-        BgpConfig.BgpSpeakerConfig speaker = config.getSpeakerWithName(name);
-        if (speaker != null) {
-            log.debug("Speaker already exists: {}", name);
-            return;
+        if (name != null) {
+            BgpConfig.BgpSpeakerConfig speaker = config.getSpeakerWithName(name);
+            if (speaker != null) {
+                log.debug("Speaker already exists: {}", name);
+                return;
+            }
+        }
+
+        if (vlanId == null || vlanId.isEmpty()) {
+            vlanIdObj = VlanId.NONE;
+        } else {
+            vlanIdObj = VlanId.vlanId(Short.valueOf(vlanId));
         }
 
         addSpeakerToConf(config);
@@ -85,6 +100,7 @@
         ConnectPoint connectPoint = ConnectPoint.
                 deviceConnectPoint(connectionPoint);
         return new BgpConfig.BgpSpeakerConfig(Optional.ofNullable(name),
-                connectPoint, new HashSet<IpAddress>());
+            vlanIdObj,
+            connectPoint, new HashSet<IpAddress>());
     }
 }
diff --git a/apps/routing/src/main/java/org/onosproject/routing/cli/BgpSpeakersListCommand.java b/apps/routing/src/main/java/org/onosproject/routing/cli/BgpSpeakersListCommand.java
index e107e36..aea768b 100644
--- a/apps/routing/src/main/java/org/onosproject/routing/cli/BgpSpeakersListCommand.java
+++ b/apps/routing/src/main/java/org/onosproject/routing/cli/BgpSpeakersListCommand.java
@@ -37,7 +37,7 @@
         description = "Lists all BGP speakers")
 public class BgpSpeakersListCommand extends AbstractShellCommand {
 
-    private static final String FORMAT = "port=%s/%s, peers=%s";
+    private static final String FORMAT = "port=%s/%s, vlan=%s, peers=%s";
     private static final String NAME_FORMAT = "%s: " + FORMAT;
 
     private static final Comparator<BgpConfig.BgpSpeakerConfig> SPEAKERS_COMPARATOR = (s1, s2) ->
@@ -67,10 +67,10 @@
                 s -> {
                     if (s.name().isPresent()) {
                         print(NAME_FORMAT, s.name().get(), s.connectPoint().deviceId(),
-                                s.connectPoint().port(), s.peers());
+                                s.connectPoint().port(), s.vlan(), s.peers());
                     } else {
                         print(FORMAT, s.connectPoint().deviceId(),
-                                s.connectPoint().port(), s.peers());
+                                s.connectPoint().port(), s.vlan(), s.peers());
                     }
                 });
         }
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/PeerConnectivityManager.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/PeerConnectivityManager.java
index df9aee0..96bfeca 100644
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/PeerConnectivityManager.java
+++ b/apps/sdnip/src/main/java/org/onosproject/sdnip/PeerConnectivityManager.java
@@ -21,6 +21,7 @@
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.TpPort;
+import org.onlab.packet.VlanId;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.incubator.net.intf.Interface;
 import org.onosproject.incubator.net.intf.InterfaceEvent;
@@ -166,6 +167,9 @@
     private Collection<PointToPointIntent> buildSpeakerIntents(BgpConfig.BgpSpeakerConfig speaker) {
         List<PointToPointIntent> intents = new ArrayList<>();
 
+        // Get the BGP Speaker VLAN Id
+        VlanId bgpSpeakerVlanId = speaker.vlan();
+
         for (IpAddress peerAddress : speaker.peers()) {
             Interface peeringInterface = interfaceService.getMatchingInterface(peerAddress);
 
@@ -175,18 +179,23 @@
                 continue;
             }
 
-            IpAddress peeringAddress = null;
-            for (InterfaceIpAddress address : peeringInterface.ipAddresses()) {
+            IpAddress bgpSpeakerAddress = null;
+            for (InterfaceIpAddress address : peeringInterface.ipAddressesList()) {
                 if (address.subnetAddress().contains(peerAddress)) {
-                    peeringAddress = address.ipAddress();
+                    bgpSpeakerAddress = address.ipAddress();
                     break;
                 }
             }
 
-            checkNotNull(peeringAddress);
+            checkNotNull(bgpSpeakerAddress);
 
-            intents.addAll(buildIntents(speaker.connectPoint(), peeringAddress,
-                    peeringInterface.connectPoint(), peerAddress));
+            VlanId peerVlanId = peeringInterface.vlan();
+
+            intents.addAll(buildIntents(speaker.connectPoint(), bgpSpeakerVlanId,
+                                        bgpSpeakerAddress,
+                                        peeringInterface.connectPoint(),
+                                        peerVlanId,
+                                        peerAddress));
         }
 
         return intents;
@@ -197,19 +206,25 @@
      * IP addresses.
      *
      * @param portOne the first connect point
+     * @param vlanOne the ingress VLAN
      * @param ipOne the first IP address
      * @param portTwo the second connect point
+     * @param vlanTwo the egress VLAN
      * @param ipTwo the second IP address
      * @return the intents to install
      */
     private Collection<PointToPointIntent> buildIntents(ConnectPoint portOne,
+                                                        VlanId vlanOne,
                                                         IpAddress ipOne,
                                                         ConnectPoint portTwo,
+                                                        VlanId vlanTwo,
                                                         IpAddress ipTwo) {
 
         List<PointToPointIntent> intents = new ArrayList<>();
 
-        TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
+        TrafficTreatment.Builder treatmentToPeer = DefaultTrafficTreatment.builder();
+        TrafficTreatment.Builder treatmentToSpeaker = DefaultTrafficTreatment.builder();
+
         TrafficSelector selector;
         Key key;
 
@@ -224,8 +239,15 @@
             icmpProtocol = IPv6.PROTOCOL_ICMP6;
         }
 
+        // Add treatment for VLAN for traffic going from BGP speaker to BGP peer
+        if (!vlanTwo.equals(VlanId.NONE)) {
+            treatmentToPeer.setVlanId(vlanTwo);
+        }
+
         // Path from BGP speaker to BGP peer matching destination TCP port 179
+
         selector = buildSelector(tcpProtocol,
+                vlanOne,
                 ipOne,
                 ipTwo,
                 null,
@@ -237,7 +259,7 @@
                 .appId(appId)
                 .key(key)
                 .selector(selector)
-                .treatment(treatment)
+                .treatment(treatmentToPeer.build())
                 .ingressPoint(portOne)
                 .egressPoint(portTwo)
                 .priority(PRIORITY_OFFSET)
@@ -245,6 +267,7 @@
 
         // Path from BGP speaker to BGP peer matching source TCP port 179
         selector = buildSelector(tcpProtocol,
+                vlanOne,
                 ipOne,
                 ipTwo,
                 BGP_PORT,
@@ -256,14 +279,40 @@
                 .appId(appId)
                 .key(key)
                 .selector(selector)
-                .treatment(treatment)
+                .treatment(treatmentToPeer.build())
                 .ingressPoint(portOne)
                 .egressPoint(portTwo)
                 .priority(PRIORITY_OFFSET)
                 .build());
 
+        // ICMP path from BGP speaker to BGP peer
+        selector = buildSelector(icmpProtocol,
+                                 vlanOne,
+                                 ipOne,
+                                 ipTwo,
+                                 null,
+                                 null);
+
+        key = buildKey(ipOne, ipTwo, SUFFIX_ICMP);
+
+        intents.add(PointToPointIntent.builder()
+                            .appId(appId)
+                            .key(key)
+                            .selector(selector)
+                            .treatment(treatmentToPeer.build())
+                            .ingressPoint(portOne)
+                            .egressPoint(portTwo)
+                            .priority(PRIORITY_OFFSET)
+                            .build());
+
+        // Add treatment for VLAN for traffic going from BGP peer to BGP speaker
+        if (!vlanOne.equals(VlanId.NONE)) {
+            treatmentToSpeaker.setVlanId(vlanOne);
+        }
+
         // Path from BGP peer to BGP speaker matching destination TCP port 179
         selector = buildSelector(tcpProtocol,
+                vlanTwo,
                 ipTwo,
                 ipOne,
                 null,
@@ -275,7 +324,7 @@
                 .appId(appId)
                 .key(key)
                 .selector(selector)
-                .treatment(treatment)
+                .treatment(treatmentToSpeaker.build())
                 .ingressPoint(portTwo)
                 .egressPoint(portOne)
                 .priority(PRIORITY_OFFSET)
@@ -283,6 +332,7 @@
 
         // Path from BGP peer to BGP speaker matching source TCP port 179
         selector = buildSelector(tcpProtocol,
+                vlanTwo,
                 ipTwo,
                 ipOne,
                 BGP_PORT,
@@ -294,33 +344,15 @@
                 .appId(appId)
                 .key(key)
                 .selector(selector)
-                .treatment(treatment)
+                .treatment(treatmentToSpeaker.build())
                 .ingressPoint(portTwo)
                 .egressPoint(portOne)
                 .priority(PRIORITY_OFFSET)
                 .build());
 
-        // ICMP path from BGP speaker to BGP peer
-        selector = buildSelector(icmpProtocol,
-                ipOne,
-                ipTwo,
-                null,
-                null);
-
-        key = buildKey(ipOne, ipTwo, SUFFIX_ICMP);
-
-        intents.add(PointToPointIntent.builder()
-                .appId(appId)
-                .key(key)
-                .selector(selector)
-                .treatment(treatment)
-                .ingressPoint(portOne)
-                .egressPoint(portTwo)
-                .priority(PRIORITY_OFFSET)
-                .build());
-
         // ICMP path from BGP peer to BGP speaker
         selector = buildSelector(icmpProtocol,
+                vlanTwo,
                 ipTwo,
                 ipOne,
                 null,
@@ -332,7 +364,7 @@
                 .appId(appId)
                 .key(key)
                 .selector(selector)
-                .treatment(treatment)
+                .treatment(treatmentToSpeaker.build())
                 .ingressPoint(portTwo)
                 .egressPoint(portOne)
                 .priority(PRIORITY_OFFSET)
@@ -351,11 +383,17 @@
      * @param dstTcpPort destination TCP port, or null if shouldn't be set
      * @return the new traffic selector
      */
-    private TrafficSelector buildSelector(byte ipProto, IpAddress srcIp,
+    private TrafficSelector buildSelector(byte ipProto, VlanId ingressVlanId,
+                                          IpAddress srcIp,
                                           IpAddress dstIp, Short srcTcpPort,
                                           Short dstTcpPort) {
         TrafficSelector.Builder builder = DefaultTrafficSelector.builder().matchIPProtocol(ipProto);
 
+        // Match on any VLAN Id if a VLAN Id configured on the ingress interface
+        if (!ingressVlanId.equals(VlanId.NONE)) {
+            builder.matchVlanId(VlanId.ANY);
+        }
+
         if (dstIp.isIp4()) {
             builder.matchEthType(Ethernet.TYPE_IPV4)
                     .matchIPSrc(IpPrefix.valueOf(srcIp, IpPrefix.MAX_INET_MASK_LENGTH))
diff --git a/apps/sdnip/src/test/java/org/onosproject/sdnip/PeerConnectivityManagerTest.java b/apps/sdnip/src/test/java/org/onosproject/sdnip/PeerConnectivityManagerTest.java
index 54cb16b..15bddea 100644
--- a/apps/sdnip/src/test/java/org/onosproject/sdnip/PeerConnectivityManagerTest.java
+++ b/apps/sdnip/src/test/java/org/onosproject/sdnip/PeerConnectivityManagerTest.java
@@ -90,24 +90,35 @@
 
     private final String dpid1 = "00:00:00:00:00:00:00:01";
     private final String dpid2 = "00:00:00:00:00:00:00:02";
+    private final String dpid3 = "00:00:00:00:00:00:00:03";
 
     private final DeviceId deviceId1 =
             DeviceId.deviceId(SdnIp.dpidToUri(dpid1));
     private final DeviceId deviceId2 =
             DeviceId.deviceId(SdnIp.dpidToUri(dpid2));
+    private final DeviceId deviceId3 =
+            DeviceId.deviceId(SdnIp.dpidToUri(dpid3));
 
     // Interfaces connected to BGP speakers
     private final ConnectPoint s1Eth100 =
             new ConnectPoint(deviceId1, PortNumber.portNumber(100));
+    private final ConnectPoint s2Eth100 =
+            new ConnectPoint(deviceId2, PortNumber.portNumber(100));
+    private final ConnectPoint s3Eth100 =
+            new ConnectPoint(deviceId3, PortNumber.portNumber(100));
 
     // Interfaces connected to BGP peers
     private final ConnectPoint s1Eth1 =
             new ConnectPoint(deviceId1, PortNumber.portNumber(1));
     private final ConnectPoint s2Eth1 =
             new ConnectPoint(deviceId2, PortNumber.portNumber(1));
+    private final ConnectPoint s3Eth1 =
+            new ConnectPoint(deviceId3, PortNumber.portNumber(1));
 
-    private final TrafficTreatment noTreatment =
-            DefaultTrafficTreatment.emptyTreatment();
+    private static final VlanId NO_VLAN = VlanId.NONE;
+    private static final VlanId VLAN10 = VlanId.vlanId(Short.valueOf("10"));
+    private static final VlanId VLAN20 = VlanId.vlanId(Short.valueOf("20"));
+    private static final VlanId VLAN30 = VlanId.vlanId(Short.valueOf("30"));
 
     @Before
     public void setUp() throws Exception {
@@ -139,16 +150,25 @@
 
         BgpConfig.BgpSpeakerConfig speaker1 = new BgpConfig.BgpSpeakerConfig(
                 Optional.empty(),
-                s1Eth100, Collections.singleton(IpAddress.valueOf("192.168.10.1")));
+                NO_VLAN, s1Eth100,
+                Collections.singleton(IpAddress.valueOf("192.168.10.1")));
 
         BgpConfig.BgpSpeakerConfig speaker2 = new BgpConfig.BgpSpeakerConfig(
                 Optional.empty(),
-                s1Eth100, Sets.newHashSet(IpAddress.valueOf("192.168.20.1"),
+                NO_VLAN, s1Eth100,
+                Sets.newHashSet(IpAddress.valueOf("192.168.20.1"),
                 IpAddress.valueOf("192.168.30.1")));
 
+        BgpConfig.BgpSpeakerConfig speaker3 = new BgpConfig.BgpSpeakerConfig(
+                Optional.empty(),
+                VLAN30, s3Eth100,
+                Sets.newHashSet(IpAddress.valueOf("192.168.40.1"),
+                                IpAddress.valueOf("192.168.50.1")));
+
         Set<BgpConfig.BgpSpeakerConfig> bgpSpeakers = Sets.newHashSet();
         bgpSpeakers.add(speaker1);
         bgpSpeakers.add(speaker2);
+        bgpSpeakers.add(speaker3);
 
         return bgpSpeakers;
     }
@@ -173,6 +193,7 @@
                 VlanId.NONE);
 
         configuredInterfaces.put(interfaceSw1Eth1, intfsw1eth1);
+
         String interfaceSw2Eth1 = "s2-eth1";
         InterfaceIpAddress ia2 =
             new InterfaceIpAddress(IpAddress.valueOf("192.168.20.101"),
@@ -181,6 +202,7 @@
                 Collections.singletonList(ia2),
                 MacAddress.valueOf("00:00:00:00:00:02"),
                 VlanId.NONE);
+
         configuredInterfaces.put(interfaceSw2Eth1, intfsw2eth1);
 
         String interfaceSw2Eth1intf2 = "s2-eth1_2";
@@ -191,14 +213,38 @@
                 Collections.singletonList(ia3),
                 MacAddress.valueOf("00:00:00:00:00:03"),
                 VlanId.NONE);
+
         configuredInterfaces.put(interfaceSw2Eth1intf2, intfsw2eth1intf2);
 
+        String interfaceSw3Eth1 = "s3-eth1";
+        InterfaceIpAddress ia4 =
+                new InterfaceIpAddress(IpAddress.valueOf("192.168.40.101"),
+                                       IpPrefix.valueOf("192.168.40.0/24"));
+        Interface intfsw3eth1 = new Interface(s3Eth1,
+                                              Collections.singleton(ia4),
+                                              MacAddress.valueOf("00:00:00:00:00:04"),
+                                              VLAN10);
+
+        configuredInterfaces.put(interfaceSw3Eth1, intfsw3eth1);
+
+        String interfaceSw3Eth1intf2 = "s3-eth1_2";
+        InterfaceIpAddress ia5 =
+                new InterfaceIpAddress(IpAddress.valueOf("192.168.50.101"),
+                                       IpPrefix.valueOf("192.168.50.0/24"));
+        Interface intfsw3eth1intf2 = new Interface(s3Eth1,
+                                                   Collections.singleton(ia5),
+                                                   MacAddress.valueOf("00:00:00:00:00:05"),
+                                                   VLAN20);
+
+        configuredInterfaces.put(interfaceSw3Eth1intf2, intfsw3eth1intf2);
+
         expect(interfaceService.getInterfacesByPort(s1Eth1))
                 .andReturn(Collections.singleton(intfsw1eth1)).anyTimes();
         expect(interfaceService.getInterfacesByIp(IpAddress.valueOf("192.168.10.101")))
                 .andReturn(Collections.singleton(intfsw1eth1)).anyTimes();
         expect(interfaceService.getMatchingInterface(IpAddress.valueOf("192.168.10.1")))
                 .andReturn(intfsw1eth1).anyTimes();
+
         expect(interfaceService.getInterfacesByPort(s2Eth1))
                 .andReturn(Collections.singleton(intfsw2eth1)).anyTimes();
         expect(interfaceService.getInterfacesByIp(IpAddress.valueOf("192.168.20.101")))
@@ -211,6 +257,16 @@
         expect(interfaceService.getMatchingInterface(IpAddress.valueOf("192.168.30.1")))
                 .andReturn(intfsw2eth1intf2).anyTimes();
 
+        expect(interfaceService.getInterfacesByIp(IpAddress.valueOf("192.168.40.101")))
+                .andReturn(Collections.singleton(intfsw3eth1)).anyTimes();
+        expect(interfaceService.getMatchingInterface(IpAddress.valueOf("192.168.40.1")))
+                .andReturn(intfsw3eth1).anyTimes();
+
+        expect(interfaceService.getInterfacesByIp(IpAddress.valueOf("192.168.50.101")))
+                .andReturn(Collections.singleton(intfsw3eth1intf2)).anyTimes();
+        expect(interfaceService.getMatchingInterface(IpAddress.valueOf("192.168.50.1")))
+                .andReturn(intfsw3eth1intf2).anyTimes();
+
         // Non-existent interface used during one of the tests
         expect(interfaceService.getInterfacesByPort(new ConnectPoint(
                 DeviceId.deviceId(SdnIp.dpidToUri("00:00:00:00:00:00:01:00")),
@@ -245,6 +301,14 @@
         configuredPeers.put(IpAddress.valueOf(peer2Sw2Eth1),
                 new BgpPeer(dpid2, 1, peer2Sw2Eth1));
 
+        String peer3Sw3Eth1 = "192.168.40.1";
+        configuredPeers.put(IpAddress.valueOf(peer3Sw3Eth1),
+                            new BgpPeer(dpid3, 1, peer3Sw3Eth1));
+
+        String peer4Sw3Eth1 = "192.168.50.1";
+        configuredPeers.put(IpAddress.valueOf(peer4Sw3Eth1),
+                            new BgpPeer(dpid3, 1, peer4Sw3Eth1));
+
         return configuredPeers;
     }
 
@@ -268,6 +332,8 @@
      * The purpose of this method is too simplify the setUpBgpIntents() method,
      * and to make the setUpBgpIntents() easy to read.
      *
+     * @param srcVlanId ingress VlanId
+     * @param dstVlanId egress VlanId
      * @param srcPrefix source IP prefix to match
      * @param dstPrefix destination IP prefix to match
      * @param srcTcpPort source TCP port to match
@@ -275,9 +341,11 @@
      * @param srcConnectPoint source connect point for PointToPointIntent
      * @param dstConnectPoint destination connect point for PointToPointIntent
      */
-    private void bgpPathintentConstructor(String srcPrefix, String dstPrefix,
-            Short srcTcpPort, Short dstTcpPort,
-            ConnectPoint srcConnectPoint, ConnectPoint dstConnectPoint) {
+    private void bgpPathintentConstructor(VlanId srcVlanId, VlanId dstVlanId,
+                                          String srcPrefix, String dstPrefix,
+                                          Short srcTcpPort, Short dstTcpPort,
+                                          ConnectPoint srcConnectPoint,
+                                          ConnectPoint dstConnectPoint) {
 
         TrafficSelector.Builder builder = DefaultTrafficSelector.builder()
                 .matchEthType(Ethernet.TYPE_IPV4)
@@ -285,6 +353,16 @@
                 .matchIPSrc(IpPrefix.valueOf(srcPrefix))
                 .matchIPDst(IpPrefix.valueOf(dstPrefix));
 
+        if (!srcVlanId.equals(VlanId.NONE)) {
+            builder.matchVlanId(VlanId.ANY);
+        }
+
+        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+
+        if (!dstVlanId.equals(VlanId.NONE)) {
+            treatment.setVlanId(dstVlanId);
+        }
+
         if (srcTcpPort != null) {
             builder.matchTcpSrc(TpPort.tpPort(srcTcpPort));
         }
@@ -299,7 +377,7 @@
                 .appId(APPID)
                 .key(key)
                 .selector(builder.build())
-                .treatment(noTreatment)
+                .treatment(treatment.build())
                 .ingressPoint(srcConnectPoint)
                 .egressPoint(dstConnectPoint)
                 .build();
@@ -316,49 +394,118 @@
 
         // Start to build intents between BGP speaker1 and BGP peer1
         bgpPathintentConstructor(
-                "192.168.10.101/32", "192.168.10.1/32", null, bgpPort,
+                NO_VLAN, NO_VLAN,
+                "192.168.10.101/32", "192.168.10.1/32",
+                null, bgpPort,
                 s1Eth100, s1Eth1);
         bgpPathintentConstructor(
-                "192.168.10.101/32", "192.168.10.1/32", bgpPort, null,
+                NO_VLAN, NO_VLAN,
+                "192.168.10.101/32", "192.168.10.1/32",
+                bgpPort, null,
                 s1Eth100, s1Eth1);
 
         bgpPathintentConstructor(
-                "192.168.10.1/32", "192.168.10.101/32", null, bgpPort,
+                NO_VLAN, NO_VLAN,
+                "192.168.10.1/32", "192.168.10.101/32",
+                null, bgpPort,
                 s1Eth1, s1Eth100);
         bgpPathintentConstructor(
-                "192.168.10.1/32", "192.168.10.101/32", bgpPort, null,
+                NO_VLAN, NO_VLAN,
+                "192.168.10.1/32", "192.168.10.101/32",
+                bgpPort, null,
                 s1Eth1, s1Eth100);
 
         // Start to build intents between BGP speaker1 and BGP peer2
         bgpPathintentConstructor(
-                "192.168.20.101/32", "192.168.20.1/32", null, bgpPort,
+                NO_VLAN, NO_VLAN,
+                "192.168.20.101/32", "192.168.20.1/32",
+                null, bgpPort,
                 s1Eth100, s2Eth1);
         bgpPathintentConstructor(
-                "192.168.20.101/32", "192.168.20.1/32", bgpPort, null,
+                NO_VLAN, NO_VLAN,
+                "192.168.20.101/32", "192.168.20.1/32",
+                bgpPort, null,
                 s1Eth100, s2Eth1);
 
         bgpPathintentConstructor(
-                "192.168.20.1/32", "192.168.20.101/32", null, bgpPort,
+                NO_VLAN, NO_VLAN,
+                "192.168.20.1/32", "192.168.20.101/32",
+                null, bgpPort,
                 s2Eth1, s1Eth100);
         bgpPathintentConstructor(
-                "192.168.20.1/32", "192.168.20.101/32", bgpPort, null,
+                NO_VLAN, NO_VLAN,
+                "192.168.20.1/32", "192.168.20.101/32",
+                bgpPort, null,
                 s2Eth1, s1Eth100);
 
-        //
-        // Start to build intents between BGP speaker3 and BGP peer1
+        // Start to build intents between BGP speaker2 and BGP peer1
         bgpPathintentConstructor(
-                "192.168.30.101/32", "192.168.30.1/32", null, bgpPort,
+                NO_VLAN, NO_VLAN,
+                "192.168.30.101/32", "192.168.30.1/32",
+                null, bgpPort,
                 s1Eth100, s2Eth1);
         bgpPathintentConstructor(
-                "192.168.30.101/32", "192.168.30.1/32", bgpPort, null,
+                NO_VLAN, NO_VLAN,
+                "192.168.30.101/32", "192.168.30.1/32",
+                bgpPort, null,
                 s1Eth100, s2Eth1);
 
         bgpPathintentConstructor(
-                "192.168.30.1/32", "192.168.30.101/32", null, bgpPort,
+                NO_VLAN, NO_VLAN,
+                "192.168.30.1/32", "192.168.30.101/32",
+                null, bgpPort,
                 s2Eth1, s1Eth100);
         bgpPathintentConstructor(
-                "192.168.30.1/32", "192.168.30.101/32", bgpPort, null,
+                NO_VLAN, NO_VLAN,
+                "192.168.30.1/32", "192.168.30.101/32",
+                bgpPort, null,
                 s2Eth1, s1Eth100);
+
+        // Start to build intents between BGP speaker3 and BGP peer4
+        bgpPathintentConstructor(
+                VLAN30, VLAN10,
+                "192.168.40.101/32", "192.168.40.1/32",
+                null, bgpPort,
+                s3Eth100, s3Eth1);
+        bgpPathintentConstructor(
+                VLAN30, VLAN10,
+                "192.168.40.101/32", "192.168.40.1/32",
+                bgpPort, null,
+                s3Eth100, s3Eth1);
+
+        bgpPathintentConstructor(
+                VLAN10, VLAN30,
+                "192.168.40.1/32", "192.168.40.101/32",
+                null, bgpPort,
+                s3Eth1, s3Eth100);
+        bgpPathintentConstructor(
+                VLAN10, VLAN30,
+                "192.168.40.1/32", "192.168.40.101/32",
+                bgpPort, null,
+                s3Eth1, s3Eth100);
+
+        // Start to build intents between BGP speaker3 and BGP peer5
+        bgpPathintentConstructor(
+                VLAN30, VLAN20,
+                "192.168.50.101/32", "192.168.50.1/32",
+                null, bgpPort,
+                s3Eth100, s3Eth1);
+        bgpPathintentConstructor(
+                VLAN30, VLAN20,
+                "192.168.50.101/32", "192.168.50.1/32",
+                bgpPort, null,
+                s3Eth100, s3Eth1);
+
+        bgpPathintentConstructor(
+                VLAN20, VLAN30,
+                "192.168.50.1/32", "192.168.50.101/32",
+                null, bgpPort,
+                s3Eth1, s3Eth100);
+        bgpPathintentConstructor(
+                VLAN20, VLAN30,
+                "192.168.50.1/32", "192.168.50.101/32",
+                bgpPort, null,
+                s3Eth1, s3Eth100);
     }
 
     /**
@@ -367,20 +514,33 @@
      * The purpose of this method is too simplify the setUpBgpIntents() method,
      * and to make the setUpBgpIntents() easy to read.
      *
+     * @param srcVlanId ingress VlanId
+     * @param dstVlanId egress VlanId
      * @param srcPrefix source IP prefix to match
      * @param dstPrefix destination IP prefix to match
      * @param srcConnectPoint source connect point for PointToPointIntent
      * @param dstConnectPoint destination connect point for PointToPointIntent
      */
-    private void icmpPathintentConstructor(String srcPrefix, String dstPrefix,
-            ConnectPoint srcConnectPoint, ConnectPoint dstConnectPoint) {
+    private void icmpPathintentConstructor(VlanId srcVlanId, VlanId dstVlanId,
+                                           String srcPrefix, String dstPrefix,
+                                           ConnectPoint srcConnectPoint,
+                                           ConnectPoint dstConnectPoint) {
 
-        TrafficSelector selector = DefaultTrafficSelector.builder()
+        TrafficSelector.Builder builder = DefaultTrafficSelector.builder()
                 .matchEthType(Ethernet.TYPE_IPV4)
                 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
                 .matchIPSrc(IpPrefix.valueOf(srcPrefix))
-                .matchIPDst(IpPrefix.valueOf(dstPrefix))
-                .build();
+                .matchIPDst(IpPrefix.valueOf(dstPrefix));
+
+        if (!srcVlanId.equals(VlanId.NONE)) {
+            builder.matchVlanId(VlanId.ANY);
+        }
+
+        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+
+        if (!dstVlanId.equals(VlanId.NONE)) {
+            treatment.setVlanId(dstVlanId);
+        }
 
         Key key = Key.of(srcPrefix.split("/")[0] + "-" + dstPrefix.split("/")[0]
                 + "-" + "icmp", APPID);
@@ -388,8 +548,8 @@
         PointToPointIntent intent = PointToPointIntent.builder()
                 .appId(APPID)
                 .key(key)
-                .selector(selector)
-                .treatment(noTreatment)
+                .selector(builder.build())
+                .treatment(treatment.build())
                 .ingressPoint(srcConnectPoint)
                 .egressPoint(dstConnectPoint)
                 .build();
@@ -403,20 +563,52 @@
     private void setUpIcmpIntents() {
         // Start to build intents between BGP speaker1 and BGP peer1
         icmpPathintentConstructor(
-                "192.168.10.101/32", "192.168.10.1/32", s1Eth100, s1Eth1);
+                NO_VLAN, NO_VLAN,
+                "192.168.10.101/32", "192.168.10.1/32",
+                s1Eth100, s1Eth1);
         icmpPathintentConstructor(
-                "192.168.10.1/32", "192.168.10.101/32", s1Eth1, s1Eth100);
+                NO_VLAN, NO_VLAN,
+                "192.168.10.1/32", "192.168.10.101/32",
+                s1Eth1, s1Eth100);
 
         // Start to build intents between BGP speaker1 and BGP peer2
         icmpPathintentConstructor(
-                "192.168.20.101/32", "192.168.20.1/32", s1Eth100, s2Eth1);
+                NO_VLAN, NO_VLAN,
+                "192.168.20.101/32", "192.168.20.1/32",
+                s1Eth100, s2Eth1);
         icmpPathintentConstructor(
-                "192.168.20.1/32", "192.168.20.101/32", s2Eth1, s1Eth100);
+                NO_VLAN, NO_VLAN,
+                "192.168.20.1/32", "192.168.20.101/32",
+                s2Eth1, s1Eth100);
 
         icmpPathintentConstructor(
-                "192.168.30.101/32", "192.168.30.1/32", s1Eth100, s2Eth1);
+                NO_VLAN, NO_VLAN,
+                "192.168.30.101/32", "192.168.30.1/32",
+                s1Eth100, s2Eth1);
         icmpPathintentConstructor(
-                "192.168.30.1/32", "192.168.30.101/32", s2Eth1, s1Eth100);
+                NO_VLAN, NO_VLAN,
+                "192.168.30.1/32", "192.168.30.101/32",
+                s2Eth1, s1Eth100);
+
+        // Start to build intents between BGP speaker3 and BGP peer 4
+        icmpPathintentConstructor(
+                VLAN10, VLAN30,
+                "192.168.40.1/32", "192.168.40.101/32",
+                s3Eth1, s3Eth100);
+        icmpPathintentConstructor(
+                VLAN30, VLAN10,
+                "192.168.40.101/32", "192.168.40.1/32",
+                s3Eth100, s3Eth1);
+
+        // Start to build intents between BGP speaker3 and BGP peer 5
+        icmpPathintentConstructor(
+                VLAN20, VLAN30,
+                "192.168.50.1/32", "192.168.50.101/32",
+                s3Eth1, s3Eth100);
+        icmpPathintentConstructor(
+                VLAN30, VLAN20,
+                "192.168.50.101/32", "192.168.50.1/32",
+                s3Eth100, s3Eth1);
     }
 
     /**
@@ -492,6 +684,14 @@
                 .andReturn(Collections.emptySet()).anyTimes();
         expect(interfaceService.getMatchingInterface(IpAddress.valueOf("192.168.30.1")))
                 .andReturn(null).anyTimes();
+        expect(interfaceService.getInterfacesByIp(IpAddress.valueOf("192.168.40.101")))
+                .andReturn(Collections.emptySet()).anyTimes();
+        expect(interfaceService.getMatchingInterface(IpAddress.valueOf("192.168.40.1")))
+                .andReturn(null).anyTimes();
+        expect(interfaceService.getInterfacesByIp(IpAddress.valueOf("192.168.50.101")))
+                .andReturn(Collections.emptySet()).anyTimes();
+        expect(interfaceService.getMatchingInterface(IpAddress.valueOf("192.168.50.1")))
+                .andReturn(null).anyTimes();
 
         replay(interfaceService);