CORD-999 changes to support vlans
Major changes to the DhcpRelay app
   Bug fix to not depend on global variables that can be overwritten
   App is now vlan aware i.e. client and server can be in different vlans
   Added probing of dhcpServer to get mac/vlan instead of configuring these values
   Added optional gateway IP for cases where dhcpServer is "behind" external router
Added support in host monitor for trunk vlan configurations
Javadoc fix in Interface.java
Commented out unused log message in HostLocationProvider
Bug fix to make ALL group editing vlan aware.

Change-Id: Ib04ed6c1ef45055f771983db29724cfde24ac54b
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelay.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelay.java
index 91ce95e..fd16e1a 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelay.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelay.java
@@ -53,7 +53,10 @@
 import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.host.HostEvent;
+import org.onosproject.net.host.HostListener;
 import org.onosproject.net.host.HostService;
+import org.onosproject.net.host.InterfaceIpAddress;
 import org.onosproject.net.packet.DefaultOutboundPacket;
 import org.onosproject.net.packet.OutboundPacket;
 import org.onosproject.net.packet.PacketContext;
@@ -78,8 +81,6 @@
     public static final String DHCP_RELAY_APP = "org.onosproject.dhcp-relay";
     private final Logger log = LoggerFactory.getLogger(getClass());
     private final InternalConfigListener cfgListener = new InternalConfigListener();
-    private static Ip4Address relayAgentIP = null;
-    private static MacAddress relayAgentMAC = null;
     private static MacAddress myMAC = valueOf("4f:4f:4f:4f:4f:4f");
 
     private final Set<ConfigFactory> factories = ImmutableSet.of(
@@ -113,15 +114,22 @@
     protected boolean arpEnabled = true;
 
     private DhcpRelayPacketProcessor dhcpRelayPacketProcessor = new DhcpRelayPacketProcessor();
-    private ConnectPoint dhcpServerConnectPoint = null;
+    private InternalHostListener hostListener = new InternalHostListener();
+
     private Ip4Address dhcpServerIp = null;
-    private MacAddress dhcpServerMac = null;
+    // dhcp server may be connected directly to the SDN network or
+    // via an external gateway. When connected directly, the dhcpConnectPoint, dhcpConnectMac,
+    // and dhcpConnectVlan refer to the server. When connected via the gateway, they refer
+    // to the gateway.
+    private ConnectPoint dhcpServerConnectPoint = null;
+    private MacAddress dhcpConnectMac = null;
+    private VlanId dhcpConnectVlan = null;
+    private Ip4Address dhcpGatewayIp = null;
     private ApplicationId appId;
 
     @Activate
     protected void activate(ComponentContext context) {
         //start the dhcp relay agent
-
         appId = coreService.registerApplication(DHCP_RELAY_APP);
 
         cfgService.addListener(cfgListener);
@@ -130,7 +138,7 @@
         updateConfig();
         //add the packet services.
         packetService.addProcessor(dhcpRelayPacketProcessor, PacketProcessor.director(0));
-
+        hostService.addListener(hostListener);
         requestDhcpPackets();
         modified(context);
 
@@ -142,9 +150,14 @@
         cfgService.removeListener(cfgListener);
         factories.forEach(cfgService::unregisterConfigFactory);
         packetService.removeProcessor(dhcpRelayPacketProcessor);
-
+        hostService.removeListener(hostListener);
         cancelDhcpPackets();
         cancelArpPackets();
+        if (dhcpGatewayIp != null) {
+            hostService.stopMonitoringIp(dhcpGatewayIp);
+        } else {
+            hostService.stopMonitoringIp(dhcpServerIp);
+        }
 
         log.info("DHCP-RELAY Stopped");
     }
@@ -174,23 +187,83 @@
      * @return true if all information we need have been initialized
      */
     private boolean configured() {
-        return (dhcpServerConnectPoint != null) && (dhcpServerIp != null) && (dhcpServerMac != null);
+        return dhcpServerConnectPoint != null && dhcpServerIp != null;
     }
 
     private void updateConfig() {
         DhcpRelayConfig cfg = cfgService.getConfig(appId, DhcpRelayConfig.class);
-
         if (cfg == null) {
             log.warn("Dhcp Server info not available");
             return;
         }
 
         dhcpServerConnectPoint = cfg.getDhcpServerConnectPoint();
+        Ip4Address oldDhcpServerIp = dhcpServerIp;
+        Ip4Address oldDhcpGatewayIp = dhcpGatewayIp;
         dhcpServerIp = cfg.getDhcpServerIp();
-        dhcpServerMac = cfg.getDhcpServermac();
-        log.info("dhcp server connect points are " + dhcpServerConnectPoint);
+        dhcpGatewayIp = cfg.getDhcpGatewayIp();
+        dhcpConnectMac = null; // reset for updated config
+        dhcpConnectVlan = null; // reset for updated config
+        log.info("dhcp server connect point: " + dhcpServerConnectPoint);
         log.info("dhcp server ipaddress " + dhcpServerIp);
-        log.info("dhcp server mac address " + dhcpServerMac);
+        if (dhcpGatewayIp != null) {
+            // check for gateway
+            Set<Host> ghosts = hostService.getHostsByIp(dhcpGatewayIp);
+            if (ghosts == null || ghosts.isEmpty()) {
+                log.info("Probing to resolve dhcp gateway IP {}", dhcpGatewayIp);
+                if (oldDhcpGatewayIp != null) {
+                    hostService.stopMonitoringIp(oldDhcpGatewayIp);
+                }
+                hostService.startMonitoringIp(dhcpGatewayIp);
+            } else {
+                // gw is known, no need to probe; should be only 1 host with this ip
+                hostUpdated(ghosts.iterator().next());
+            }
+        } else {
+            // check for server
+            Set<Host> shosts = hostService.getHostsByIp(dhcpServerIp);
+            if (shosts == null || shosts.isEmpty()) {
+                log.info("Probing to resolve dhcp server IP {}", dhcpServerIp);
+                if (oldDhcpServerIp != null) {
+                    hostService.stopMonitoringIp(oldDhcpServerIp);
+                }
+                hostService.startMonitoringIp(dhcpServerIp);
+            } else {
+                // dhcp server is know, no need to probe
+                hostUpdated(shosts.iterator().next());
+            }
+        }
+    }
+
+    private void hostRemoved(Host host) {
+        if (host.ipAddresses().contains(dhcpServerIp)) {
+            log.warn("DHCP server {} removed", dhcpServerIp);
+            dhcpConnectMac = null;
+            dhcpConnectVlan = null;
+        }
+        if (dhcpGatewayIp != null && host.ipAddresses().contains(dhcpGatewayIp)) {
+            log.warn("DHCP gateway {} removed", dhcpGatewayIp);
+            dhcpConnectMac = null;
+            dhcpConnectVlan = null;
+        }
+    }
+
+    private void hostUpdated(Host host) {
+        if (dhcpGatewayIp != null) {
+            if (host.ipAddresses().contains(dhcpGatewayIp)) {
+                dhcpConnectMac = host.mac();
+                dhcpConnectVlan = host.vlan();
+                log.info("DHCP gateway {} resolved to Mac/Vlan:{}/{}", dhcpGatewayIp,
+                        dhcpConnectMac, dhcpConnectVlan);
+            }
+            return;
+        }
+        if (host.ipAddresses().contains(dhcpServerIp)) {
+            dhcpConnectMac = host.mac();
+            dhcpConnectVlan = host.vlan();
+            log.info("DHCP server {} resolved to Mac/Vlan:{}/{}", dhcpServerIp,
+                    dhcpConnectMac, dhcpConnectVlan);
+        }
     }
 
     /**
@@ -250,13 +323,12 @@
         @Override
         public void process(PacketContext context) {
             if (!configured()) {
-                log.info("Missing DHCP rely server config. Abort packet processing");
+                log.warn("Missing DHCP relay server config. Abort packet processing");
                 return;
             }
 
             // process the packet and get the payload
             Ethernet packet = context.inPacket().parsed();
-
             if (packet == null) {
                 return;
             }
@@ -301,13 +373,15 @@
 
         //forward the packet to ConnectPoint where the DHCP server is attached.
         private void forwardPacket(Ethernet packet) {
-
             //send Packetout to dhcp server connectpoint.
             if (dhcpServerConnectPoint != null) {
                 TrafficTreatment t = DefaultTrafficTreatment.builder()
                         .setOutput(dhcpServerConnectPoint.port()).build();
                 OutboundPacket o = new DefaultOutboundPacket(
                         dhcpServerConnectPoint.deviceId(), t, ByteBuffer.wrap(packet.serialize()));
+                if (log.isTraceEnabled()) {
+                    log.trace("Relaying packet to dhcp server {}", packet);
+                }
                 packetService.emit(o);
             }
         }
@@ -319,7 +393,6 @@
          * @param packet the ethernet payload
          */
         private void processArpPacket(PacketContext context, Ethernet packet) {
-
             ARP arpPacket = (ARP) packet.getPayload();
 
             ARP arpReply = (ARP) arpPacket.clone();
@@ -366,31 +439,33 @@
 
             switch (incomingPacketType) {
             case DHCPDISCOVER:
-                //add the gatewayip as virtual interface ip for server to understand the lease to be assigned
-                //and forward the packet to dhcp server.
-                Ethernet ethernetPacketDiscover = processDhcpPacketFrmClient(context, packet, clientServerInterfaces);
+                // add the gatewayip as virtual interface ip for server to understand
+                // the lease to be assigned and forward the packet to dhcp server.
+                Ethernet ethernetPacketDiscover =
+                    processDhcpPacketFromClient(context, packet, clientServerInterfaces);
                 if (ethernetPacketDiscover != null) {
                     forwardPacket(ethernetPacketDiscover);
                 }
                 break;
             case DHCPOFFER:
                 //reply to dhcp client.
-                Ethernet ethernetPacketOffer = processDhcpPacketFrmServer(packet);
+                Ethernet ethernetPacketOffer = processDhcpPacketFromServer(packet);
                 if (ethernetPacketOffer != null) {
                     sendReply(ethernetPacketOffer, dhcpPayload);
                 }
                 break;
             case DHCPREQUEST:
-                //add the gatewayip as virtual interface ip for server to understand the lease to be assigned
-                //and forward the packet to dhcp server.
-                Ethernet ethernetPacketRequest = processDhcpPacketFrmClient(context, packet, clientServerInterfaces);
+                // add the gatewayip as virtual interface ip for server to understand
+                // the lease to be assigned and forward the packet to dhcp server.
+                Ethernet ethernetPacketRequest =
+                    processDhcpPacketFromClient(context, packet, clientServerInterfaces);
                 if (ethernetPacketRequest != null) {
                     forwardPacket(ethernetPacketRequest);
                 }
                 break;
             case DHCPACK:
                 //reply to dhcp client.
-                Ethernet ethernetPacketAck = processDhcpPacketFrmServer(packet);
+                Ethernet ethernetPacketAck = processDhcpPacketFromServer(packet);
                 if (ethernetPacketAck != null) {
                     sendReply(ethernetPacketAck, dhcpPayload);
                 }
@@ -401,75 +476,118 @@
         }
 
         //build the DHCP discover/request packet with gatewayip(unicast packet)
-        private Ethernet processDhcpPacketFrmClient(PacketContext context, Ethernet ethernetPacket,
-                Set<Interface> clientInterfaces) {
-
-            //assuming one interface per port for now.
-            relayAgentIP = clientInterfaces.iterator().next().ipAddressesList().get(0).
-                    ipAddress().getIp4Address();
-            relayAgentMAC = clientInterfaces.iterator().next().mac();
-
-            if (relayAgentIP == null || relayAgentMAC == null) {
-                log.info("Missing DHCP rely agent config. Abort packet processing");
+        private Ethernet processDhcpPacketFromClient(PacketContext context,
+                             Ethernet ethernetPacket, Set<Interface> clientInterfaces) {
+            Ip4Address relayAgentIp = getRelayAgentIPv4Address(clientInterfaces);
+            MacAddress relayAgentMac = clientInterfaces.iterator().next().mac();
+            if (relayAgentIp == null || relayAgentMac == null) {
+                log.warn("Missing DHCP relay agent interface Ipv4 addr config for "
+                        + "packet from client on port: {}. Aborting packet processing",
+                         clientInterfaces.iterator().next().connectPoint());
                 return null;
             }
-
+            if (dhcpConnectMac == null) {
+                log.warn("DHCP {} not yet resolved .. Aborting DHCP "
+                        + "packet processing from client on port: {}",
+                        (dhcpGatewayIp == null) ? "server IP " + dhcpServerIp
+                                                : "gateway IP " + dhcpGatewayIp,
+                        clientInterfaces.iterator().next().connectPoint());
+                return null;
+            }
             // get dhcp header.
             Ethernet etherReply = (Ethernet) ethernetPacket.clone();
-            etherReply.setSourceMACAddress(relayAgentMAC);
-            etherReply.setDestinationMACAddress(dhcpServerMac);
+            etherReply.setSourceMACAddress(relayAgentMac);
+            etherReply.setDestinationMACAddress(dhcpConnectMac);
+            etherReply.setVlanID(dhcpConnectVlan.toShort());
             IPv4 ipv4Packet = (IPv4) etherReply.getPayload();
-            ipv4Packet.setSourceAddress(relayAgentIP.toInt());
+            ipv4Packet.setSourceAddress(relayAgentIp.toInt());
             ipv4Packet.setDestinationAddress(dhcpServerIp.toInt());
             UDP udpPacket = (UDP) ipv4Packet.getPayload();
             DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
-            dhcpPacket.setGatewayIPAddress(relayAgentIP.toInt());
+            dhcpPacket.setGatewayIPAddress(relayAgentIp.toInt());
             udpPacket.setPayload(dhcpPacket);
             ipv4Packet.setPayload(udpPacket);
             etherReply.setPayload(ipv4Packet);
             return etherReply;
         }
 
-        //build the DHCP offer/ack with proper client port.
-        private Ethernet processDhcpPacketFrmServer(Ethernet ethernetPacket) {
-
-            if (relayAgentIP == null || relayAgentMAC == null) {
-                log.info("Missing DHCP rely agent config. Abort packet processing");
-                return null;
+        // Returns the first v4 interface ip out of a set of interfaces or null.
+        // Checks all interfaces, and ignores v6 interface ips
+        private Ip4Address getRelayAgentIPv4Address(Set<Interface> intfs) {
+            for (Interface intf : intfs) {
+                for (InterfaceIpAddress ip : intf.ipAddressesList()) {
+                    Ip4Address relayAgentIp = ip.ipAddress().getIp4Address();
+                    if (relayAgentIp != null) {
+                        return relayAgentIp;
+                    }
+                }
             }
+            return null;
+        }
 
+        //build the DHCP offer/ack with proper client port.
+        private Ethernet processDhcpPacketFromServer(Ethernet ethernetPacket) {
             // get dhcp header.
             Ethernet etherReply = (Ethernet) ethernetPacket.clone();
             IPv4 ipv4Packet = (IPv4) etherReply.getPayload();
             UDP udpPacket = (UDP) ipv4Packet.getPayload();
             DHCP dhcpPayload = (DHCP) udpPacket.getPayload();
-            //set the ethernet frame.
-            etherReply.setDestinationMACAddress(dhcpPayload.getClientHardwareAddress());
-            udpPacket.setDestinationPort(UDP.DHCP_CLIENT_PORT);
+
+            // determine the vlanId of the client host - note that this vlan id
+            // could be different from the vlan in the packet from the server
+            MacAddress dstMac = valueOf(dhcpPayload.getClientHardwareAddress());
+            Set<Host> hosts = hostService.getHostsByMac(dstMac);
+            if (hosts == null || hosts.isEmpty()) {
+                log.warn("Cannot determine host for DHCP client: {}. Aborting "
+                        + "relay for dhcp packet from server {}",
+                         dhcpPayload.getClientHardwareAddress(), ethernetPacket);
+                return null;
+            } else if (hosts.size() > 1) {
+                // XXX  redo to send reply to all hosts found
+                log.warn("Multiple hosts found for mac:{}. Picking one "
+                        + "host out of {}", dstMac, hosts);
+            }
+            Host host = hosts.iterator().next();
+            etherReply.setDestinationMACAddress(dstMac);
+            etherReply.setVlanID(host.vlan().toShort());
+            // we leave the srcMac from the original packet
+
+            // figure out the relay agent IP corresponding to the original request
+            Ip4Address relayAgentIP = getRelayAgentIPv4Address(
+                          interfaceService.getInterfacesByPort(host.location()));
+            if (relayAgentIP == null) {
+                log.warn("Cannot determine relay agent interface Ipv4 addr for host {}. "
+                        + "Aborting relay for dhcp packet from server {}",
+                        host, ethernetPacket);
+                return null;
+            }
             // SRC_IP: relay agent IP
             // DST_IP: offered IP
             ipv4Packet.setSourceAddress(relayAgentIP.toInt());
             ipv4Packet.setDestinationAddress(dhcpPayload.getYourIPAddress());
 
+            udpPacket.setDestinationPort(UDP.DHCP_CLIENT_PORT);
             udpPacket.setPayload(dhcpPayload);
             ipv4Packet.setPayload(udpPacket);
             etherReply.setPayload(ipv4Packet);
             return etherReply;
         }
 
-        //send the response to the requestor host.
+        //send the response to the requester host.
         private void sendReply(Ethernet ethPacket, DHCP dhcpPayload) {
-
-            MacAddress descMac = new MacAddress(dhcpPayload.getClientHardwareAddress());
+            MacAddress descMac = valueOf(dhcpPayload.getClientHardwareAddress());
             Host host = hostService.getHost(HostId.hostId(descMac,
                     VlanId.vlanId(ethPacket.getVlanID())));
 
-            // Send packet out to requestor if the host information is available
+            // Send packet out to requester if the host information is available
             if (host != null) {
                 TrafficTreatment t = DefaultTrafficTreatment.builder()
                         .setOutput(host.location().port()).build();
                 OutboundPacket o = new DefaultOutboundPacket(
                         host.location().deviceId(), t, ByteBuffer.wrap(ethPacket.serialize()));
+                if (log.isTraceEnabled()) {
+                    log.trace("Relaying packet to dhcp client {}", ethPacket);
+                }
                 packetService.emit(o);
             }
         }
@@ -491,4 +609,27 @@
             }
         }
     }
+
+    /**
+     * Internal listener for host events.
+     */
+    private class InternalHostListener implements HostListener {
+        @Override
+        public void event(HostEvent event) {
+            switch (event.type()) {
+            case HOST_ADDED:
+            case HOST_UPDATED:
+                hostUpdated(event.subject());
+                break;
+            case HOST_REMOVED:
+                hostRemoved(event.subject());
+                break;
+            case HOST_MOVED:
+                // XXX todo -- moving dhcp server
+                break;
+            default:
+                break;
+            }
+        }
+    }
 }
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayConfig.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayConfig.java
index 90921d0..ef5a742 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayConfig.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayConfig.java
@@ -20,9 +20,8 @@
 import org.onosproject.net.config.Config;
 
 import static org.onosproject.net.config.Config.FieldPresence.MANDATORY;
-
+import static org.onosproject.net.config.Config.FieldPresence.OPTIONAL;
 import org.onlab.packet.Ip4Address;
-import org.onlab.packet.MacAddress;
 /**
  * DHCP Relay Config class.
  */
@@ -30,15 +29,15 @@
 
     private static final String DHCP_CONNECT_POINT = "dhcpserverConnectPoint";
     private static final String DHCP_SERVER_IP = "serverip";
-    private static final String DHCP_SERVER_MAC = "servermac";
+    private static final String DHCP_GATEWAY_IP = "gatewayip";
 
     @Override
     public boolean isValid() {
 
-        return hasOnlyFields(DHCP_CONNECT_POINT, DHCP_SERVER_IP, DHCP_SERVER_MAC) &&
+        return hasOnlyFields(DHCP_CONNECT_POINT, DHCP_SERVER_IP, DHCP_GATEWAY_IP) &&
                 isConnectPoint(DHCP_CONNECT_POINT, MANDATORY) &&
                 isIpAddress(DHCP_SERVER_IP, MANDATORY) &&
-                isMacAddress(DHCP_SERVER_MAC, MANDATORY);
+                isIpAddress(DHCP_GATEWAY_IP, OPTIONAL);
     }
 
     /**
@@ -61,12 +60,15 @@
     }
 
     /**
-     * Returns the dhcp server mac.
+     * Returns the optional dhcp gateway ip, if configured. This option is
+     * typically used if the dhcp server is not directly attached to a switch;
+     * For example, the dhcp server may be reached via an external gateway connected
+     * to the dhcpserverConnectPoint.
      *
-     * @return server mac or null if not set
+     * @return gateway ip or null if not set
      */
-    public MacAddress getDhcpServermac() {
-        String mac = get(DHCP_SERVER_MAC, null);
-        return mac != null ? MacAddress.valueOf(mac) : null;
+    public Ip4Address getDhcpGatewayIp() {
+        String gip = get(DHCP_GATEWAY_IP, null);
+        return gip != null ? Ip4Address.valueOf(gip) : null;
     }
 }
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
index dc3f358..0a3eb92 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -1015,30 +1015,41 @@
         // to switch ports, link-events should take care of any re-routing or
         // group editing necessary for port up/down. Here we only process edge ports
         // that are already configured.
-        VlanId untaggedVlan = getUntaggedVlanId(new ConnectPoint(device.id(), port.number()));
-        VlanId vlanId = (untaggedVlan != null) ? untaggedVlan : INTERNAL_VLAN;
+        ConnectPoint cp = new ConnectPoint(device.id(), port.number());
+        VlanId untaggedVlan = getUntaggedVlanId(cp);
+        VlanId nativeVlan = getNativeVlanId(cp);
+        Set<VlanId> taggedVlans = getTaggedVlanId(cp);
 
-        if (vlanId.equals(INTERNAL_VLAN)) {
+        if (untaggedVlan == null && nativeVlan == null && taggedVlans.isEmpty()) {
             log.debug("Not handling port updated event for unconfigured port "
                     + "dev/port: {}/{}", device.id(), port.number());
             return;
         }
-        processEdgePort(device, port, vlanId);
+        if (untaggedVlan != null) {
+            processEdgePort(device, port, untaggedVlan, true);
+        }
+        if (nativeVlan != null) {
+            processEdgePort(device, port, nativeVlan, true);
+        }
+        if (!taggedVlans.isEmpty()) {
+            taggedVlans.forEach(tag -> processEdgePort(device, port, tag, false));
+        }
     }
 
-    private void processEdgePort(Device device, Port port, VlanId vlanId) {
+    private void processEdgePort(Device device, Port port, VlanId vlanId,
+                                 boolean popVlan) {
         boolean portUp = port.isEnabled();
         if (portUp) {
-            log.info("Device:EdgePort {}:{} is enabled in subnet: {}", device.id(),
+            log.info("Device:EdgePort {}:{} is enabled in vlan: {}", device.id(),
                      port.number(), vlanId);
         } else {
-            log.info("Device:EdgePort {}:{} is disabled in subnet: {}", device.id(),
+            log.info("Device:EdgePort {}:{} is disabled in vlan: {}", device.id(),
                      port.number(), vlanId);
         }
 
         DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
         if (groupHandler != null) {
-            groupHandler.processEdgePort(port.number(), vlanId, portUp);
+            groupHandler.processEdgePort(port.number(), vlanId, popVlan, portUp);
         } else {
             log.warn("Group handler not found for dev:{}. Not handling edge port"
                     + " {} event for port:{}", device.id(),
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
index 9e7fd04..93dfd0c 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
@@ -360,15 +360,18 @@
     }
 
     /**
-     * Adds or removes a port that has been configured with a subnet to a broadcast group
-     * for bridging. Note that this does not create the broadcast group itself.
-     * Should only be called by the master instance for this device/port.
+     * Adds or removes a port that has been configured with a vlan to a broadcast group
+     * for bridging. Should only be called by the master instance for this device.
      *
      * @param port the port on this device that needs to be added/removed to a bcast group
-     * @param vlanId the vlan id corresponding to the broadcast group
+     * @param vlanId the vlan id corresponding to the broadcast domain/group
+     * @param popVlan indicates if packets should be sent out untagged or not out
+     *                of the port. If true, indicates an access (untagged) or native vlan
+     *                configuration. If false, indicates a trunk (tagged) vlan config.
      * @param portUp true if port is enabled, false if disabled
      */
-    public void processEdgePort(PortNumber port, VlanId vlanId, boolean portUp) {
+    public void processEdgePort(PortNumber port, VlanId vlanId,
+                                boolean popVlan, boolean portUp) {
         //get the next id for the subnet and edit it.
         Integer nextId = getVlanNextObjectiveId(vlanId);
         if (nextId == -1) {
@@ -389,14 +392,13 @@
                                           port, nextId);
         // Create the bucket to be added or removed
         TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
-        tBuilder.popVlan();
+        if (popVlan) {
+            tBuilder.popVlan();
+        }
         tBuilder.setOutput(port);
 
-        VlanId untaggedVlan = srManager.getUntaggedVlanId(new ConnectPoint(deviceId, port));
-        VlanId assignedVlanId = (untaggedVlan != null) ? untaggedVlan : INTERNAL_VLAN;
-
         TrafficSelector metadata =
-                DefaultTrafficSelector.builder().matchVlanId(assignedVlanId).build();
+                DefaultTrafficSelector.builder().matchVlanId(vlanId).build();
 
         NextObjective.Builder nextObjBuilder = DefaultNextObjective
                 .builder().withId(nextId)