ONOS-2709
Fix bug of installing flowrules.

Change-Id: I84fc3e3c4894b3f84173a5364e4506d4fc6ba3fc
diff --git a/apps/vtn/src/main/java/org/onosproject/vtn/impl/VTNManager.java b/apps/vtn/src/main/java/org/onosproject/vtn/impl/VTNManager.java
index 32bcc29..6fc63e1 100644
--- a/apps/vtn/src/main/java/org/onosproject/vtn/impl/VTNManager.java
+++ b/apps/vtn/src/main/java/org/onosproject/vtn/impl/VTNManager.java
@@ -19,7 +19,10 @@
 import static org.onlab.util.Tools.groupedThreads;

 import static org.slf4j.LoggerFactory.getLogger;

 

+import java.util.ArrayList;

+import java.util.Collection;

 import java.util.HashSet;

+import java.util.Iterator;

 import java.util.List;

 import java.util.Set;

 import java.util.concurrent.ScheduledExecutorService;

@@ -42,6 +45,7 @@
 import org.onosproject.net.Port;

 import org.onosproject.net.PortNumber;

 import org.onosproject.net.behaviour.BridgeConfig;

+import org.onosproject.net.behaviour.BridgeDescription;

 import org.onosproject.net.behaviour.BridgeName;

 import org.onosproject.net.behaviour.DefaultTunnelDescription;

 import org.onosproject.net.behaviour.IpTunnelEndPoint;

@@ -119,6 +123,11 @@
     private static final String PORT_HEAD = "vxlan";

     private static final String DEFAULT_BRIDGE_NAME = "br-int";

     private static final String CONTROLLER_IP_KEY = "ipaddress";

+    private static final int DEFAULT_MAC_PRIORITY = 0x0000;

+    private static final int MAC_PRIORITY = 0xffff;

+    private static final int DEFAULT_PORT_PRIORITY = 0x0000;

+    private static final int PORT_PRIORITY = 0xffff;

+    private static final String SWITCH_CHANNEL_ID = "channelId";

 

     @Activate

     public void activate() {

@@ -152,19 +161,20 @@
         bridgeConfig.addBridge(BridgeName.bridgeName(DEFAULT_BRIDGE_NAME));

         String ipAddress = device.annotations().value(CONTROLLER_IP_KEY);

         IpAddress ip = IpAddress.valueOf(ipAddress);

-        Sets.newHashSet(devices)

-                .stream()

-                .filter(d -> d.type() == Device.Type.CONTROLLER)

-                .filter(d -> !device.id().equals(d.id()))

-                .forEach(d -> {

-                             String ipAddress1 = d.annotations()

-                                     .value(CONTROLLER_IP_KEY);

-                             IpAddress ip1 = IpAddress.valueOf(ipAddress1);

-                             applyTunnelConfig(ip, ip1, handler);

-                             DriverHandler handler1 = driverService

-                                     .createHandler(d.id());

-                             applyTunnelConfig(ip1, ip, handler1);

-                         });

+        Sets.newHashSet(devices).stream()

+                .filter(d -> Device.Type.CONTROLLER == d.type())

+                .filter(d -> !device.id().equals(d.id())).forEach(d -> {

+                    if (!device.id().equals(d.id())

+                            && Device.Type.CONTROLLER == d.type()) {

+                        String ipAddress1 = d.annotations()

+                                .value(CONTROLLER_IP_KEY);

+                        IpAddress ip1 = IpAddress.valueOf(ipAddress1);

+                        applyTunnelConfig(ip, ip1, handler);

+                        DriverHandler handler1 = driverService

+                                .createHandler(d.id());

+                        applyTunnelConfig(ip1, ip, handler1);

+                    }

+                });

     }

 

     @Override

@@ -172,18 +182,15 @@
         Iterable<Device> devices = deviceService.getAvailableDevices();

         String ipAddress = device.annotations().value(CONTROLLER_IP_KEY);

         IpAddress dst = IpAddress.valueOf(ipAddress);

-        Sets.newHashSet(devices)

-                .stream()

+        Sets.newHashSet(devices).stream()

                 .filter(d -> d.type() == Device.Type.CONTROLLER)

-                .filter(d -> !device.id().equals(d.id()))

-                .forEach(d -> {

-                             String ipAddress1 = d.annotations()

-                                     .value(CONTROLLER_IP_KEY);

-                             DriverHandler handler = driverService

-                                     .createHandler(d.id());

-                             IpAddress src = IpAddress.valueOf(ipAddress1);

-                             removeTunnelConfig(src, dst, handler);

-                         });

+                .filter(d -> !device.id().equals(d.id())).forEach(d -> {

+                    String ipAddress1 = d.annotations()

+                            .value(CONTROLLER_IP_KEY);

+                    DriverHandler handler = driverService.createHandler(d.id());

+                    IpAddress src = IpAddress.valueOf(ipAddress1);

+                    removeTunnelConfig(src, dst, handler);

+                });

     }

 

     private void applyTunnelConfig(IpAddress src, IpAddress dst,

@@ -216,6 +223,32 @@
     public void onOvsDetected(Device device) {

         programMacDefaultRules(device.id(), appId, Objective.Operation.ADD);

         programPortDefaultRules(device.id(), appId, Objective.Operation.ADD);

+        Set<Host> hosts = hostService.getConnectedHosts(device.id());

+        hosts.forEach(h -> {

+            String ifaceId = h.annotations().value(IFACEID);

+            String currentControllerIp = getControllerIpOfSwitch(device.id());

+            VirtualPortId portId = VirtualPortId.portId(ifaceId);

+            VirtualPort port = virtualPortService.getPort(portId);

+            TenantNetwork network = tenantNetworkService

+                    .getNetwork(port.networkId());

+            String vxlanName = "vxlan-" + currentControllerIp;

+

+            DriverHandler handler = driverService.createHandler(device.id());

+            BridgeConfig bridgeConfig = handler.behaviour(BridgeConfig.class);

+            Collection<BridgeDescription> bridgeDescriptions = bridgeConfig

+                    .getBridges();

+            Iterator<BridgeDescription> it = bridgeDescriptions.iterator();

+            if (it.hasNext()) {

+                BridgeDescription sw = it.next();

+                Set<PortNumber> ports = bridgeConfig.getPortNumbers();

+                ports.stream().filter(p -> p.name().equalsIgnoreCase(vxlanName))

+                        .forEach(p -> {

+                    programTunnelOut(sw.deviceId(), network.segmentationId(), p,

+                                     h.mac(), appId, Objective.Operation.ADD);

+                });

+            }

+

+        });

     }

 

     @Override

@@ -227,58 +260,137 @@
     @Override

     public void onHostDetected(Host host) {

         String ifaceId = host.annotations().value(IFACEID);

+        DeviceId deviceId = host.location().deviceId();

+        String currentControllerIp = getControllerIpOfSwitch(deviceId);

+        Iterable<Device> devices = deviceService.getAvailableDevices();

         VirtualPortId portId = VirtualPortId.portId(ifaceId);

         VirtualPort port = virtualPortService.getPort(portId);

-        TenantNetwork network = tenantNetworkService.getNetwork(port

-                .networkId());

+        TenantNetwork network = tenantNetworkService

+                .getNetwork(port.networkId());

+        String tunnelName = "vxlan-" + currentControllerIp;

         binding.put(host.id(), network.segmentationId());

-        DeviceId deviceId = host.location().deviceId();

         List<Port> allPorts = deviceService.getPorts(deviceId);

         PortNumber inPort = host.location().port();

         Set<Port> localPorts = new HashSet<>();

-        allPorts.forEach(p -> {

-            if (!p.number().name().startsWith(PORT_HEAD)) {

+        Set<Port> tunnelPorts = new HashSet<>();

+        List<Port> outports = new ArrayList<>();

+        Sets.newHashSet(allPorts.iterator()).stream()

+        .filter(p -> !p.number().equals(PortNumber.LOCAL)).forEach(p -> {

+            if (!p.annotations().value("portName").startsWith(PORT_HEAD)) {

                 localPorts.add(p);

+            } else {

+                tunnelPorts.add(p);

             }

+            outports.add(p);

         });

+

         programLocalBcastRules(deviceId, network.segmentationId(), inPort,

-                               allPorts, appId, Objective.Operation.ADD);

+                               outports, appId, Objective.Operation.ADD);

         programLocalOut(deviceId, network.segmentationId(), inPort, host.mac(),

                         appId, Objective.Operation.ADD);

-        programTunnelFloodOut(deviceId, network.segmentationId(), inPort,

-                              localPorts, appId, Objective.Operation.ADD);

-        programTunnelOut(deviceId, network.segmentationId(), inPort,

-                         host.mac(), appId, Objective.Operation.ADD);

+        tunnelPorts

+                .forEach(tp -> programTunnelFloodOut(deviceId,

+                                                     network.segmentationId(),

+                                                     tp.number(), localPorts,

+                                                     appId,

+                                                     Objective.Operation.ADD));

+        Sets.newHashSet(devices).stream()

+                .filter(d -> d.type() == Device.Type.CONTROLLER).forEach(d -> {

+                    DriverHandler handler = driverService.createHandler(d.id());

+                    BridgeConfig bridgeConfig = handler

+                            .behaviour(BridgeConfig.class);

+                    Collection<BridgeDescription> bridgeDescriptions = bridgeConfig

+                            .getBridges();

+

+                    Iterator<BridgeDescription> it = bridgeDescriptions

+                            .iterator();

+                    if (it.hasNext()) {

+                        BridgeDescription sw = it.next();

+                        Set<PortNumber> ports = bridgeConfig.getPortNumbers();

+                        ports.stream()

+                                .filter(p -> p.name()

+                                        .equalsIgnoreCase(tunnelName))

+                                .forEach(p -> {

+                            programTunnelOut(sw.deviceId(),

+                                             network.segmentationId(), p,

+                                             host.mac(), appId,

+                                             Objective.Operation.ADD);

+                        });

+                    }

+                });

         programLocalIn(deviceId, network.segmentationId(), inPort, host.mac(),

                        appId, Objective.Operation.ADD);

-        programTunnelIn(deviceId, network.segmentationId(), inPort, host.mac(),

-                        appId, Objective.Operation.ADD);

+        tunnelPorts

+                .forEach(tp -> programTunnelIn(deviceId,

+                                               network.segmentationId(),

+                                               tp.number(), inPort, host.mac(),

+                                               appId, Objective.Operation.ADD));

+

     }

 

     @Override

     public void onHostVanished(Host host) {

         SegmentationId segId = binding.remove(host.id());

         DeviceId deviceId = host.location().deviceId();

+        String currentControllerIp = getControllerIpOfSwitch(deviceId);

+        Iterable<Device> devices = deviceService.getAvailableDevices();

         List<Port> allPorts = deviceService.getPorts(deviceId);

         PortNumber inPort = host.location().port();

+        String vxlanName = "vxlan-" + currentControllerIp;

         Set<Port> localPorts = new HashSet<>();

-        allPorts.forEach(p -> {

-            if (!p.number().name().startsWith(PORT_HEAD)) {

+        Set<Port> tunnelPorts = new HashSet<>();

+        List<Port> outports = new ArrayList<>();

+        Sets.newHashSet(allPorts.iterator()).stream()

+        .filter(p -> !p.number().equals(PortNumber.LOCAL)).forEach(p -> {

+            if (!p.annotations().value("portName").startsWith(PORT_HEAD)) {

                 localPorts.add(p);

+            } else {

+                tunnelPorts.add(p);

             }

+            outports.add(p);

         });

-        programLocalBcastRules(deviceId, segId, inPort, allPorts, appId,

-                               Objective.Operation.REMOVE);

-        programLocalOut(deviceId, segId, inPort, host.mac(), appId,

-                        Objective.Operation.REMOVE);

-        programTunnelFloodOut(deviceId, segId, inPort, localPorts, appId,

-                              Objective.Operation.REMOVE);

-        programTunnelOut(deviceId, segId, inPort, host.mac(), appId,

-                         Objective.Operation.REMOVE);

-        programLocalIn(deviceId, segId, inPort, host.mac(), appId,

-                       Objective.Operation.REMOVE);

-        programTunnelIn(deviceId, segId, inPort, host.mac(), appId,

-                        Objective.Operation.REMOVE);

+

+        programLocalBcastRules(deviceId, segId, inPort,

+                               outports, appId, Objective.Operation.REMOVE);

+        programLocalOut(deviceId, segId, inPort, host.mac(),

+                        appId, Objective.Operation.REMOVE);

+        tunnelPorts

+                .forEach(tp -> programTunnelFloodOut(deviceId,

+                                                     segId,

+                                                     tp.number(), localPorts,

+                                                     appId,

+                                                     Objective.Operation.REMOVE));

+        Sets.newHashSet(devices).stream()

+                .filter(d -> d.type() == Device.Type.CONTROLLER).forEach(d -> {

+                    DriverHandler handler = driverService.createHandler(d.id());

+                    BridgeConfig bridgeConfig = handler

+                            .behaviour(BridgeConfig.class);

+                    Collection<BridgeDescription> bridgeDescriptions = bridgeConfig

+                            .getBridges();

+

+                    Iterator<BridgeDescription> it = bridgeDescriptions

+                            .iterator();

+                    if (it.hasNext()) {

+                        BridgeDescription sw = it.next();

+                        Set<PortNumber> ports = bridgeConfig.getPortNumbers();

+                        ports.stream()

+                                .filter(p -> p.name()

+                                        .equalsIgnoreCase(vxlanName))

+                                .forEach(p -> {

+                            programTunnelOut(sw.deviceId(),

+                                             segId, p,

+                                             host.mac(), appId,

+                                             Objective.Operation.REMOVE);

+                        });

+                    }

+                });

+        programLocalIn(deviceId, segId, inPort, host.mac(),

+                       appId, Objective.Operation.REMOVE);

+        tunnelPorts

+                .forEach(tp -> programTunnelIn(deviceId,

+                                               segId,

+                                               tp.number(), inPort, host.mac(),

+                                               appId, Objective.Operation.REMOVE));

     }

 

     private class InnerDeviceListener implements DeviceListener {

@@ -309,7 +421,7 @@
                     onOvsVanished(device);

                 });

             } else {

-                log.info("do nothing for this device type");

+                log.info("Do nothing for this device type");

             }

         }

 

@@ -328,8 +440,11 @@
                 backgroundService.execute(() -> {

                     onHostVanished(host);

                 });

-            } else {

-                log.info("unknow host");

+            } else if (HostEvent.Type.HOST_UPDATED == event.type()) {

+                backgroundService.execute(() -> {

+                    onHostVanished(host);

+                    onHostDetected(host);

+                });

             }

         }

 

@@ -338,16 +453,18 @@
     // Used to forward the flows to the local VM.

     private void programLocalOut(DeviceId dpid, SegmentationId segmentationId,

                                  PortNumber outPort, MacAddress sourceMac,

-                                 ApplicationId appid, Objective.Operation type) {

+                                 ApplicationId appid,

+                                 Objective.Operation type) {

         TrafficSelector selector = DefaultTrafficSelector.builder()

                 .matchEthDst(sourceMac).build();

-        TrafficTreatment treatment = DefaultTrafficTreatment

-                .builder()

-                .add(Instructions.modTunnelId(Long.parseLong(segmentationId

-                             .toString()))).setOutput(outPort).build();

+        TrafficTreatment treatment = DefaultTrafficTreatment.builder()

+                .add(Instructions

+                        .modTunnelId(Long.parseLong(segmentationId.toString())))

+                .setOutput(outPort).build();

         ForwardingObjective.Builder objective = DefaultForwardingObjective

                 .builder().withTreatment(treatment).withSelector(selector)

-                .fromApp(appId).withFlag(Flag.SPECIFIC);

+                .fromApp(appId).withFlag(Flag.SPECIFIC)

+                .withPriority(MAC_PRIORITY);

         if (type.equals(Objective.Operation.ADD)) {

             flowObjectiveService.forward(dpid, objective.add());

         } else {

@@ -356,24 +473,28 @@
 

     }

 

-    // Used to forward the flows to the remote VM via VXLAN tunnel.

+    // Used to forward the flows into the VXLAN tunnel.

     private void programTunnelOut(DeviceId dpid, SegmentationId segmentationId,

-                                  PortNumber outPort, MacAddress sourceMac,

-                                  ApplicationId appid, Objective.Operation type) {

+                                  PortNumber tunnelOutPort, MacAddress dstMac,

+                                  ApplicationId appid,

+                                  Objective.Operation type) {

         TrafficSelector selector = DefaultTrafficSelector.builder()

-                .matchEthDst(sourceMac).build();

-        TrafficTreatment treatment = DefaultTrafficTreatment

-                .builder()

-                .add(Instructions.modTunnelId(Long.parseLong(segmentationId

-                             .toString()))).setOutput(outPort).build();

+                .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).makePermanent().withFlag(Flag.SPECIFIC);

+                .fromApp(appId).withFlag(Flag.SPECIFIC)

+                .withPriority(MAC_PRIORITY);

         if (type.equals(Objective.Operation.ADD)) {

             flowObjectiveService.forward(dpid, objective.add());

         } else {

             flowObjectiveService.forward(dpid, objective.remove());

         }

+

     }

 

     // Used to forward multicast flows to remote VMs of the same tenant via

@@ -384,8 +505,7 @@
                                        Iterable<Port> localports,

                                        ApplicationId appid,

                                        Objective.Operation type) {

-        TrafficSelector selector = DefaultTrafficSelector

-                .builder()

+        TrafficSelector selector = DefaultTrafficSelector.builder()

                 .matchInPort(ofPortOut)

 

                 .add(Criteria.matchTunnelId(Long.parseLong(segmentationId

@@ -399,7 +519,7 @@
         ForwardingObjective.Builder objective = DefaultForwardingObjective

                 .builder().withTreatment(treatment.build())

                 .withSelector(selector).fromApp(appId).makePermanent()

-                .withFlag(Flag.SPECIFIC);

+                .withFlag(Flag.SPECIFIC).withPriority(MAC_PRIORITY);

         if (type.equals(Objective.Operation.ADD)) {

             flowObjectiveService.forward(dpid, objective.add());

         } else {

@@ -415,7 +535,8 @@
                 .build();

         ForwardingObjective.Builder objective = DefaultForwardingObjective

                 .builder().withTreatment(treatment).withSelector(selector)

-                .fromApp(appId).makePermanent().withFlag(Flag.SPECIFIC);

+                .fromApp(appId).makePermanent().withFlag(Flag.SPECIFIC)

+                .withPriority(DEFAULT_MAC_PRIORITY);

         if (type.equals(Objective.Operation.ADD)) {

             flowObjectiveService.forward(dpid, objective.add());

         } else {

@@ -429,12 +550,11 @@
                                         PortNumber inPort, List<Port> allports,

                                         ApplicationId appid,

                                         Objective.Operation type) {

-        TrafficSelector selector = DefaultTrafficSelector

-                .builder()

-                .matchInPort(inPort)

-                .matchEthDst(MacAddress.BROADCAST)

-                .add(Criteria.matchTunnelId(Long.parseLong(segmentationId

-                             .toString()))).build();

+        TrafficSelector selector = DefaultTrafficSelector.builder()

+                .matchInPort(inPort).matchEthDst(MacAddress.BROADCAST)

+                .add(Criteria.matchTunnelId(Long

+                        .parseLong(segmentationId.toString())))

+                .build();

         TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();

 

         for (Port outport : allports) {

@@ -445,7 +565,7 @@
         ForwardingObjective.Builder objective = DefaultForwardingObjective

                 .builder().withTreatment(treatment.build())

                 .withSelector(selector).fromApp(appId).makePermanent()

-                .withFlag(Flag.SPECIFIC);

+                .withFlag(Flag.SPECIFIC).withPriority(MAC_PRIORITY);

         if (type.equals(Objective.Operation.ADD)) {

             flowObjectiveService.forward(dpid, objective.add());

         } else {

@@ -465,7 +585,7 @@
         ForwardingObjective.Builder objective = DefaultForwardingObjective

                 .builder().withTreatment(treatment.build())

                 .withSelector(selector).fromApp(appId).makePermanent()

-                .withFlag(Flag.SPECIFIC);

+                .withFlag(Flag.SPECIFIC).withPriority(PORT_PRIORITY);

         if (type.equals(Objective.Operation.ADD)) {

             flowObjectiveService.forward(dpid, objective.add());

         } else {

@@ -475,18 +595,19 @@
 

     // Used to forward the flows from the egress tunnel to the VM.

     private void programTunnelIn(DeviceId dpid, SegmentationId segmentationId,

-                                 PortNumber inPort, MacAddress sourceMac,

-                                 ApplicationId appid, Objective.Operation type) {

-        TrafficSelector selector = DefaultTrafficSelector

-                .builder()

-                .matchInPort(inPort)

-                .add(Criteria.matchTunnelId(Long.parseLong(segmentationId

-                             .toString()))).build();

+                                 PortNumber tunnelInPort, PortNumber outPort,

+                                 MacAddress sourceMac, ApplicationId appid,

+                                 Objective.Operation type) {

+        TrafficSelector selector = DefaultTrafficSelector.builder()

+                .matchInPort(tunnelInPort).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);

+                .fromApp(appId).makePermanent().withFlag(Flag.SPECIFIC)

+                .withPriority(PORT_PRIORITY);

         if (type.equals(Objective.Operation.ADD)) {

             flowObjectiveService.forward(dpid, objective.add());

         } else {

@@ -501,11 +622,20 @@
         TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();

         ForwardingObjective.Builder objective = DefaultForwardingObjective

                 .builder().withTreatment(treatment).withSelector(selector)

-                .fromApp(appId).makePermanent().withFlag(Flag.SPECIFIC);

+                .fromApp(appId).makePermanent().withFlag(Flag.SPECIFIC)

+                .withPriority(DEFAULT_PORT_PRIORITY);

         if (type.equals(Objective.Operation.ADD)) {

             flowObjectiveService.forward(dpid, objective.add());

         } else {

             flowObjectiveService.forward(dpid, objective.remove());

         }

     }

+

+    // Used to get channelId from the device annotations.

+    private String getControllerIpOfSwitch(DeviceId deviceId) {

+        Device device = deviceService.getDevice(deviceId);

+        String url = device.annotations().value(SWITCH_CHANNEL_ID);

+        return url.substring(0, url.lastIndexOf(":"));

+    }

+

 }