CORD-906 Support trunk and native VLAN

- Include trunk L2IG in L2F
- Populate bridging rules for trunk vlan
- Extend populateVlanMacFilters to generate filtering obj for trunk port
- Extend host handler to check vlan mismatch between host and interface
  (Temporarily disabled for now. Check TODOs in the code for detail.)
- Extend getForwardingObjectiveBuilder in RoutingRulePopulator to support tagged host

Change-Id: Id168a02015f58b0957ba43ad7c52798029d895bc
diff --git a/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
index 0c30cef..3c801b7 100644
--- a/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -15,7 +15,9 @@
  */
 package org.onosproject.segmentrouting;
 
+import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -110,6 +112,7 @@
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
 import static com.google.common.base.Preconditions.checkState;
 import static org.onlab.packet.Ethernet.TYPE_ARP;
@@ -519,8 +522,12 @@
         return tunnelHandler.getTunnel(tunnelId);
     }
 
+    // TODO Consider moving these to InterfaceService
     /**
      * Returns untagged VLAN configured on given connect point.
+     * <p>
+     * Only returns the first match if there are multiple untagged VLAN configured
+     * on the connect point.
      *
      * @param connectPoint connect point
      * @return untagged VLAN or null if not configured
@@ -533,6 +540,64 @@
     }
 
     /**
+     * Returns tagged VLAN configured on given connect point.
+     * <p>
+     * Returns all matches if there are multiple tagged VLAN configured
+     * on the connect point.
+     *
+     * @param connectPoint connect point
+     * @return tagged VLAN or empty set if not configured
+     */
+    public Set<VlanId> getTaggedVlanId(ConnectPoint connectPoint) {
+        Set<Interface> interfaces = interfaceService.getInterfacesByPort(connectPoint);
+        return interfaces.stream()
+                .map(Interface::vlanTagged)
+                .flatMap(vlanIds -> vlanIds.stream())
+                .collect(Collectors.toSet());
+    }
+
+    /**
+     * Returns native VLAN configured on given connect point.
+     * <p>
+     * Only returns the first match if there are multiple native VLAN configured
+     * on the connect point.
+     *
+     * @param connectPoint connect point
+     * @return native VLAN or null if not configured
+     */
+    public VlanId getNativeVlanId(ConnectPoint connectPoint) {
+        Set<Interface> interfaces = interfaceService.getInterfacesByPort(connectPoint);
+        return interfaces.stream()
+                .filter(intf -> !intf.vlanNative().equals(VlanId.NONE))
+                .map(Interface::vlanNative)
+                .findFirst()
+                .orElse(null);
+    }
+
+    /**
+     * Returns vlan port map of given device.
+     *
+     * @param deviceId device id
+     * @return vlan-port multimap
+     */
+    public Multimap<VlanId, PortNumber> getVlanPortMap(DeviceId deviceId) {
+        HashMultimap<VlanId, PortNumber> vlanPortMap = HashMultimap.create();
+
+        interfaceService.getInterfaces().stream()
+                .filter(intf -> intf.connectPoint().deviceId().equals(deviceId))
+                .forEach(intf -> {
+                    vlanPortMap.put(intf.vlanUntagged(), intf.connectPoint().port());
+                    intf.vlanTagged().forEach(vlanTagged -> {
+                        vlanPortMap.put(vlanTagged, intf.connectPoint().port());
+                    });
+                    vlanPortMap.put(intf.vlanNative(), intf.connectPoint().port());
+                });
+        vlanPortMap.removeAll(VlanId.NONE);
+
+        return vlanPortMap;
+    }
+
+    /**
      * Returns the next objective ID for the given NeighborSet.
      * If the nextObjective does not exist, a new one is created and
      * its id is returned.