ONOS-3404 Change p2p tunnel to p2any tunnel by using set tunnel_dst in
flow.
Change-Id: I06cb6d42772434de9c016e795de5c6d8a6f45dfb
diff --git a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/manager/impl/VTNManager.java b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/manager/impl/VTNManager.java
index 7192ad9..2e38251 100644
--- a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/manager/impl/VTNManager.java
+++ b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/manager/impl/VTNManager.java
@@ -15,12 +15,14 @@
*/
package org.onosproject.vtn.manager.impl;
+import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -30,6 +32,7 @@
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
+import org.onlab.packet.Ip4Address;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.util.KryoNamespace;
@@ -43,6 +46,7 @@
import org.onosproject.net.PortNumber;
import org.onosproject.net.behaviour.BridgeConfig;
import org.onosproject.net.behaviour.BridgeDescription;
+import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
import org.onosproject.net.config.NetworkConfigService;
import org.onosproject.net.config.basics.BasicDeviceConfig;
import org.onosproject.net.device.DeviceEvent;
@@ -50,15 +54,24 @@
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.driver.DriverHandler;
import org.onosproject.net.driver.DriverService;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficTreatment.Builder;
+import org.onosproject.net.flow.instructions.ExtensionTreatment;
import org.onosproject.net.flowobjective.Objective;
+import org.onosproject.net.group.DefaultGroupBucket;
+import org.onosproject.net.group.DefaultGroupDescription;
+import org.onosproject.net.group.DefaultGroupKey;
+import org.onosproject.net.group.GroupBucket;
+import org.onosproject.net.group.GroupBuckets;
+import org.onosproject.net.group.GroupDescription;
+import org.onosproject.net.group.GroupKey;
+import org.onosproject.net.group.GroupService;
import org.onosproject.net.host.HostEvent;
import org.onosproject.net.host.HostListener;
import org.onosproject.net.host.HostService;
import org.onosproject.store.serializers.KryoNamespaces;
-import org.onosproject.store.service.ConsistentMap;
import org.onosproject.store.service.EventuallyConsistentMap;
import org.onosproject.store.service.LogicalClockService;
-import org.onosproject.store.service.Serializer;
import org.onosproject.store.service.StorageService;
import org.onosproject.vtn.manager.VTNService;
import org.onosproject.vtn.table.ClassifierService;
@@ -79,6 +92,7 @@
import org.onosproject.vtnrsc.virtualport.VirtualPortService;
import org.slf4j.Logger;
+import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
/**
@@ -120,6 +134,9 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected MastershipService mastershipService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected GroupService groupService;
+
private ApplicationId appId;
private ClassifierService classifierService;
private L2ForwardService l2ForwardService;
@@ -133,9 +150,10 @@
private static final String EX_PORT_NAME = "eth0";
private static final String SWITCHES_OF_CONTROLLER = "switchesOfController";
private static final String SWITCH_OF_LOCAL_HOST_PORTS = "switchOfLocalHostPorts";
+ private static final String DEFAULT_IP = "0.0.0.0";
private EventuallyConsistentMap<IpAddress, Boolean> switchesOfController;
- private ConsistentMap<DeviceId, NetworkOfLocalHostPorts> switchOfLocalHostPorts;
+ private EventuallyConsistentMap<DeviceId, NetworkOfLocalHostPorts> switchOfLocalHostPorts;
@Activate
public void activate() {
@@ -162,9 +180,9 @@
.build();
switchOfLocalHostPorts = storageService
- .<DeviceId, NetworkOfLocalHostPorts>consistentMapBuilder()
- .withName(SWITCH_OF_LOCAL_HOST_PORTS)
- .withSerializer(Serializer.using(serializer.build()))
+ .<DeviceId, NetworkOfLocalHostPorts>eventuallyConsistentMapBuilder()
+ .withName(SWITCH_OF_LOCAL_HOST_PORTS).withSerializer(serializer)
+ .withTimestampProvider((k, v) -> clockService.getTimestamp())
.build();
log.info("Started");
@@ -251,44 +269,10 @@
private void programTunnelConfig(DeviceId localDeviceId, IpAddress localIp,
DriverHandler localHandler) {
- Iterable<Device> devices = deviceService.getAvailableDevices();
- Sets.newHashSet(devices).stream()
- .filter(d -> Device.Type.CONTROLLER == d.type())
- .filter(d -> !localDeviceId.equals(d.id())).forEach(d -> {
- DriverHandler tunHandler = driverService
- .createHandler(d.id());
- String remoteIpAddress = d.annotations()
- .value(CONTROLLER_IP_KEY);
- IpAddress remoteIp = IpAddress.valueOf(remoteIpAddress);
- if (remoteIp.toString()
- .equalsIgnoreCase(localIp.toString())) {
- log.error("The localIp and remoteIp are the same");
- return;
- }
- if (localHandler != null) {
- // Create tunnel in br-int on local controller
- if (mastershipService.isLocalMaster(localDeviceId)) {
- VtnConfig.applyTunnelConfig(localHandler, localIp, remoteIp);
- log.info("Add tunnel between {} and {}", localIp,
- remoteIp);
- }
- // Create tunnel in br-int on other controllers
- if (mastershipService.isLocalMaster(d.id())) {
- VtnConfig.applyTunnelConfig(tunHandler, remoteIp,
- localIp);
- log.info("Add tunnel between {} and {}", remoteIp,
- localIp);
- }
- } else {
- // remove tunnel in br-int on other controllers
- if (mastershipService.isLocalMaster(d.id())) {
- VtnConfig.removeTunnelConfig(tunHandler, remoteIp,
- localIp);
- log.info("Remove tunnel between {} and {}", remoteIp,
- localIp);
- }
- }
- });
+ if (mastershipService.isLocalMaster(localDeviceId)) {
+ VtnConfig.applyTunnelConfig(localHandler, localIp, IpAddress.valueOf(DEFAULT_IP));
+ log.info("Add tunnel on {}", localIp);
+ }
}
private void applyTunnelOut(Device device, Objective.Operation type) {
@@ -321,6 +305,7 @@
DriverHandler handler = driverService.createHandler(localControllerId);
Set<PortNumber> ports = VtnConfig.getPortNumbers(handler);
Iterable<Host> allHosts = hostService.getHosts();
+ String tunnelName = "vxlan-" + DEFAULT_IP;
if (allHosts != null) {
Sets.newHashSet(allHosts).stream().forEach(host -> {
MacAddress hostMac = host.mac();
@@ -346,13 +331,12 @@
}
IpAddress remoteIpAddress = IpAddress
.valueOf(remoteControllerIp);
- String tunnelName = "vxlan-" + remoteIpAddress.toString();
ports.stream()
.filter(p -> p.name().equalsIgnoreCase(tunnelName))
.forEach(p -> {
l2ForwardService
.programTunnelOut(device.id(), segmentationId, p,
- hostMac, type);
+ hostMac, type, remoteIpAddress);
});
});
}
@@ -392,16 +376,11 @@
Collection<PortNumber> localTunnelPorts = VtnData.getLocalTunnelPorts(ports);
// Get all the local vm's PortNumber in the current node
Map<TenantNetworkId, Set<PortNumber>> localHostPorts = switchOfLocalHostPorts
- .get(deviceId).value().getNetworkOfLocalHostPorts();
+ .get(deviceId).getNetworkOfLocalHostPorts();
Set<PortNumber> networkOflocalHostPorts = localHostPorts.get(network.id());
-
- l2ForwardService.programLocalBcastRules(deviceId, segmentationId,
- inPort, networkOflocalHostPorts,
- localTunnelPorts,
- type);
-
- l2ForwardService.programLocalOut(deviceId, segmentationId, inPort, mac,
- type);
+ for (PortNumber p : localTunnelPorts) {
+ programGroupTable(deviceId, appId, p, devices, type);
+ }
if (type == Objective.Operation.ADD) {
if (networkOflocalHostPorts == null) {
@@ -409,20 +388,33 @@
localHostPorts.putIfAbsent(network.id(), networkOflocalHostPorts);
}
networkOflocalHostPorts.add(inPort);
+ l2ForwardService.programLocalBcastRules(deviceId, segmentationId,
+ inPort, networkOflocalHostPorts,
+ localTunnelPorts,
+ type);
classifierService.programTunnelIn(deviceId, segmentationId,
localTunnelPorts,
type);
} else if (type == Objective.Operation.REMOVE) {
- networkOflocalHostPorts.remove(inPort);
- if (networkOflocalHostPorts.isEmpty()) {
- classifierService.programTunnelIn(deviceId, segmentationId,
- localTunnelPorts,
- Objective.Operation.REMOVE);
- switchOfLocalHostPorts.get(deviceId).value().getNetworkOfLocalHostPorts()
- .remove(virtualPort.networkId());
+ if (networkOflocalHostPorts != null) {
+ l2ForwardService.programLocalBcastRules(deviceId, segmentationId,
+ inPort, networkOflocalHostPorts,
+ localTunnelPorts,
+ type);
+ networkOflocalHostPorts.remove(inPort);
+ if (networkOflocalHostPorts.isEmpty()) {
+ classifierService.programTunnelIn(deviceId, segmentationId,
+ localTunnelPorts,
+ type);
+ switchOfLocalHostPorts.get(deviceId).getNetworkOfLocalHostPorts()
+ .remove(virtualPort.networkId());
+ }
}
}
+ l2ForwardService.programLocalOut(deviceId, segmentationId, inPort, mac,
+ type);
+
l2ForwardService.programTunnelBcastRules(deviceId, segmentationId,
networkOflocalHostPorts,
localTunnelPorts,
@@ -440,9 +432,11 @@
SegmentationId segmentationId,
MacAddress dstMac,
Objective.Operation type) {
- String tunnelName = "vxlan-" + ipAddress.toString();
+ String tunnelName = "vxlan-" + DEFAULT_IP;
Sets.newHashSet(devices).stream()
- .filter(d -> d.type() == Device.Type.CONTROLLER).forEach(d -> {
+ .filter(d -> d.type() == Device.Type.CONTROLLER)
+ .filter(d -> !("ovsdb:" + ipAddress).equals(d.id().toString()))
+ .forEach(d -> {
DriverHandler handler = driverService.createHandler(d.id());
BridgeConfig bridgeConfig = handler
.behaviour(BridgeConfig.class);
@@ -459,7 +453,7 @@
.forEach(p -> {
l2ForwardService.programTunnelOut(sw.deviceId(),
segmentationId, p,
- dstMac, type);
+ dstMac, type, ipAddress);
});
}
});
@@ -525,4 +519,45 @@
}
}
+ private void programGroupTable(DeviceId deviceId, ApplicationId appid,
+ PortNumber portNumber, Iterable<Device> devices, Objective.Operation type) {
+ if (type.equals(Objective.Operation.REMOVE)) {
+ return;
+ }
+
+ List<GroupBucket> buckets = Lists.newArrayList();
+ Sets.newHashSet(devices)
+ .stream()
+ .filter(d -> d.type() == Device.Type.CONTROLLER)
+ .filter(d -> !deviceId.equals(d.id()))
+ .forEach(d -> {
+ String ipAddress = d.annotations()
+ .value(CONTROLLER_IP_KEY);
+ Ip4Address dst = Ip4Address.valueOf(ipAddress);
+ Builder builder = DefaultTrafficTreatment.builder();
+
+ DriverHandler handler = driverService.createHandler(deviceId);
+ ExtensionTreatmentResolver resolver = handler.behaviour(ExtensionTreatmentResolver.class);
+ ExtensionTreatment treatment = resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
+ try {
+ treatment.setPropertyValue("tunnelDst", dst);
+ } catch (Exception e) {
+ log.error("Failed to get extension instruction to set tunnel dst {}", deviceId);
+ }
+
+ builder.extension(treatment, deviceId);
+ builder.setOutput(portNumber);
+ GroupBucket bucket = DefaultGroupBucket
+ .createAllGroupBucket(builder.build());
+ buckets.add(bucket);
+ });
+ final GroupKey key = new DefaultGroupKey(APP_ID.getBytes());
+ GroupDescription groupDescription = new DefaultGroupDescription(deviceId,
+ GroupDescription.Type.ALL,
+ new GroupBuckets(buckets),
+ key,
+ L2ForwardServiceImpl.GROUP_ID,
+ appid);
+ groupService.addGroup(groupDescription);
+ }
}
diff --git a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/L2ForwardService.java b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/L2ForwardService.java
index 3781c2b..cb661f8 100644
--- a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/L2ForwardService.java
+++ b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/L2ForwardService.java
@@ -15,6 +15,7 @@
*/
package org.onosproject.vtn.table;
+import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
@@ -22,13 +23,14 @@
import org.onosproject.vtnrsc.SegmentationId;
/**
- * Applies L2 flows to the device.
+ * Applies L2 flows to the device. L2Forward table is Table(50).
*/
public interface L2ForwardService {
/**
- * The local broadcast rule that message matches Table(50) Match: broadcast
- * mac and vnid Action: output port.
+ * The local broadcast rule that message matches Table(50).
+ * Match: broadcast mac and vnid.
+ * Action: set output port.
*
* @param deviceId Device Id
* @param segmentationId the vnid of the host belong to
@@ -45,8 +47,9 @@
Objective.Operation type);
/**
- * The tunnel broadcast rule that message matches Table(50) Match: broadcast
- * mac and vnid Action: output port.
+ * The tunnel broadcast rule that message matches Table(50).
+ * Match: broadcast mac and vnid.
+ * Action: output port.
*
* @param deviceId Device Id
* @param segmentationId the vnid of the host belong to
@@ -61,8 +64,9 @@
Objective.Operation type);
/**
- * The local out rule that message matches. Table(50) Match: local host mac
- * and vnid Action: output local host port.
+ * The local out rule that message matches Table(50).
+ * Match: local host mac and vnid.
+ * Action: output local host port.
*
* @param deviceId Device Id
* @param segmentationId the vnid of the host belong to
@@ -75,17 +79,19 @@
Objective.Operation type);
/**
- * The tunnel out rule that message matches. Table(50) Match: host mac and
- * vnid Action: output tunnel port.
+ * The tunnel out rule that message matches Table(50).
+ * Match: host mac and vnid.
+ * Action: output tunnel port.
*
* @param deviceId Device Id
* @param segmentationId the vnid of the host belong to
* @param tunnelOutPort the port of the tunnel
* @param dstMac the mac of the host
* @param type the operation of the flow
+ * @param ipAddress the ipAddress of the node
*/
void programTunnelOut(DeviceId deviceId, SegmentationId segmentationId,
PortNumber tunnelOutPort, MacAddress dstMac,
- Objective.Operation type);
+ Objective.Operation type, IpAddress ipAddress);
}
diff --git a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/impl/L2ForwardServiceImpl.java b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/impl/L2ForwardServiceImpl.java
index 64c5fee..3581cf6 100644
--- a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/impl/L2ForwardServiceImpl.java
+++ b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/impl/L2ForwardServiceImpl.java
@@ -16,19 +16,28 @@
package org.onosproject.vtn.table.impl;
import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
import static org.slf4j.LoggerFactory.getLogger;
import org.onlab.osgi.DefaultServiceDirectory;
import org.onlab.osgi.ServiceDirectory;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onosproject.core.ApplicationId;
+import org.onosproject.core.DefaultGroupId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
+import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
+import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.net.driver.DriverService;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.TrafficTreatment.Builder;
import org.onosproject.net.flow.criteria.Criteria;
+import org.onosproject.net.flow.instructions.ExtensionTreatment;
import org.onosproject.net.flowobjective.DefaultForwardingObjective;
import org.onosproject.net.flowobjective.FlowObjectiveService;
import org.onosproject.net.flowobjective.ForwardingObjective;
@@ -47,10 +56,10 @@
private final Logger log = getLogger(getClass());
private static final int MAC_PRIORITY = 0xffff;
-
+ public static final Integer GROUP_ID = 1;
private final FlowObjectiveService flowObjectiveService;
private final ApplicationId appId;
-
+ private final DriverService driverService;
/**
* Constructor.
*
@@ -60,6 +69,7 @@
this.appId = checkNotNull(appId, "ApplicationId can not be null");
ServiceDirectory serviceDirectory = new DefaultServiceDirectory();
this.flowObjectiveService = serviceDirectory.get(FlowObjectiveService.class);
+ this.driverService = serviceDirectory.get(DriverService.class);
}
@Override
@@ -91,9 +101,7 @@
if (type.equals(Objective.Operation.REMOVE) && inPort == lp) {
flag = false;
}
- for (PortNumber outport : localTunnelPorts) {
- treatment.setOutput(outport);
- }
+ treatment.group(new DefaultGroupId(GROUP_ID));
ForwardingObjective.Builder objective = DefaultForwardingObjective
.builder().withTreatment(treatment.build())
.withSelector(selector).fromApp(appId).makePermanent()
@@ -171,15 +179,26 @@
public void programTunnelOut(DeviceId deviceId,
SegmentationId segmentationId,
PortNumber tunnelOutPort, MacAddress dstMac,
- Objective.Operation type) {
+ Objective.Operation type, IpAddress ipAddress) {
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchEthDst(dstMac).add(Criteria.matchTunnelId(Long
.parseLong(segmentationId.toString())))
.build();
- TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+
+ DriverHandler handler = driverService.createHandler(deviceId);
+ ExtensionTreatmentResolver resolver = handler.behaviour(ExtensionTreatmentResolver.class);
+ ExtensionTreatment treatment = resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
+ try {
+ treatment.setPropertyValue("tunnelDst", Ip4Address.valueOf(ipAddress.toString()));
+ } catch (Exception e) {
+ log.error("Failed to get extension instruction to set tunnel dst {}", deviceId);
+ }
+
+ Builder builder = DefaultTrafficTreatment.builder();
+ builder.extension(treatment, deviceId)
.setOutput(tunnelOutPort).build();
ForwardingObjective.Builder objective = DefaultForwardingObjective
- .builder().withTreatment(treatment).withSelector(selector)
+ .builder().withTreatment(builder.build()).withSelector(selector)
.fromApp(appId).withFlag(Flag.SPECIFIC)
.withPriority(MAC_PRIORITY);
if (type.equals(Objective.Operation.ADD)) {
@@ -189,5 +208,4 @@
}
}
-
}
diff --git a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/util/VtnConfig.java b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/util/VtnConfig.java
index 1f98e55..5d70230 100644
--- a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/util/VtnConfig.java
+++ b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/util/VtnConfig.java
@@ -15,9 +15,12 @@
*/
package org.onosproject.vtn.util;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Set;
import org.onlab.packet.IpAddress;
+import org.onosproject.net.DefaultAnnotations;
import org.onosproject.net.PortNumber;
import org.onosproject.net.behaviour.BridgeConfig;
import org.onosproject.net.behaviour.BridgeName;
@@ -26,6 +29,7 @@
import org.onosproject.net.behaviour.TunnelConfig;
import org.onosproject.net.behaviour.TunnelDescription;
import org.onosproject.net.behaviour.TunnelEndPoint;
+import org.onosproject.net.behaviour.TunnelName;
import org.onosproject.net.driver.DriverHandler;
/**
@@ -34,7 +38,13 @@
public final class VtnConfig {
private static final String DEFAULT_BRIDGE_NAME = "br-int";
-
+ private static final String DEFAULT_TUNNEL = "vxlan-0.0.0.0";
+ private static final Map<String, String> DEFAULT_TUNNEL_OPTIONS = new HashMap<String, String>() {
+ {
+ put("key", "flow");
+ put("remote_ip", "flow");
+ }
+ };
/**
* Constructs a vtn config object. Utility classes should not have a
* public or default constructor, otherwise IDE will compile unsuccessfully. This
@@ -64,15 +74,19 @@
*/
public static void applyTunnelConfig(DriverHandler handler, IpAddress srcIp,
IpAddress dstIp) {
+ DefaultAnnotations.Builder optionBuilder = DefaultAnnotations.builder();
+ for (String key : DEFAULT_TUNNEL_OPTIONS.keySet()) {
+ optionBuilder.set(key, DEFAULT_TUNNEL_OPTIONS.get(key));
+ }
TunnelConfig tunnelConfig = handler.behaviour(TunnelConfig.class);
TunnelEndPoint tunnelAsSrc = IpTunnelEndPoint.ipTunnelPoint(srcIp);
- TunnelEndPoint tunnelAsDst = IpTunnelEndPoint.ipTunnelPoint(dstIp);
TunnelDescription tunnel = new DefaultTunnelDescription(
tunnelAsSrc,
- tunnelAsDst,
+ null,
TunnelDescription.Type.VXLAN,
- null);
- tunnelConfig.createTunnel(tunnel);
+ TunnelName.tunnelName(DEFAULT_TUNNEL),
+ optionBuilder.build());
+ tunnelConfig.createTunnelInterface(BridgeName.bridgeName(DEFAULT_BRIDGE_NAME), tunnel);
}
/**