Address comments in gerrit 20328
Create a new class XconnecEndpoint to cover both physical port and load balancer
Also change the CLI load balancer identifier to "LB:"
Change-Id: I0b4cd6e474d8b21468d87fcadd9280fdf7d6aafa
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/XconnectAddCommand.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/XconnectAddCommand.java
index 0ff6195..d8a9ecf 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/XconnectAddCommand.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/XconnectAddCommand.java
@@ -21,17 +21,21 @@
import org.onlab.packet.VlanId;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.net.DeviceId;
+import org.onosproject.segmentrouting.xconnect.api.XconnectEndpoint;
+import org.onosproject.segmentrouting.xconnect.api.XconnectPortEndpoint;
import org.onosproject.segmentrouting.xconnect.api.XconnectService;
import java.util.Set;
-import static com.google.common.base.Preconditions.checkArgument;
-
/**
* Creates Xconnect.
*/
@Command(scope = "onos", name = "sr-xconnect-add", description = "Create Xconnect")
public class XconnectAddCommand extends AbstractShellCommand {
+ private static final String EP_DESC = "Can be a physical port number or a load balancer key. " +
+ "Use integer to specify physical port number. " +
+ "Use " + XconnectPortEndpoint.LB_KEYWORD + "key to specify load balancer key";
+
@Argument(index = 0, name = "deviceId",
description = "Device ID",
required = true, multiValued = false)
@@ -42,28 +46,29 @@
required = true, multiValued = false)
private String vlanIdStr;
- @Argument(index = 2, name = "port1",
- description = "Port 1. Can also specify L2 load balancer by L2LB(<key>)",
+ @Argument(index = 2, name = "ep1",
+ description = "First endpoint. " + EP_DESC,
required = true, multiValued = false)
- private String port1Str;
+ private String ep1Str;
- @Argument(index = 3, name = "port2",
- description = "Port 2. Can also specify L2 load balancer by L2LB(<key>)",
+ @Argument(index = 3, name = "ep2",
+ description = "Second endpoint. " + EP_DESC,
required = true, multiValued = false)
- private String port2Str;
-
- private static final String L2LB_PATTERN = "^(\\d*|L2LB\\(\\d*\\))$";
+ private String ep2Str;
@Override
protected void execute() {
DeviceId deviceId = DeviceId.deviceId(deviceIdStr);
VlanId vlanId = VlanId.vlanId(vlanIdStr);
- Set<String> ports = Sets.newHashSet(port1Str, port2Str);
- checkArgument(port1Str.matches(L2LB_PATTERN), "Wrong L2 load balancer format " + port1Str);
- checkArgument(port2Str.matches(L2LB_PATTERN), "Wrong L2 load balancer format " + port2Str);
+ XconnectEndpoint ep1 = XconnectEndpoint.fromString(ep1Str);
+ XconnectEndpoint ep2 = XconnectEndpoint.fromString(ep2Str);
+
+ Set<XconnectEndpoint> endpoints = Sets.newHashSet(ep1, ep2);
XconnectService xconnectService = get(XconnectService.class);
- xconnectService.addOrUpdateXconnect(deviceId, vlanId, ports);
+ xconnectService.addOrUpdateXconnect(deviceId, vlanId, endpoints);
}
+
+
}
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectCodec.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectCodec.java
index 08558a8..1154e40 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectCodec.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectCodec.java
@@ -28,10 +28,13 @@
import java.util.Set;
+/**
+ * Codec for Xconnect.
+ */
public class XconnectCodec extends JsonCodec<XconnectDesc> {
private static final String DEVICE_ID = "deviceId";
private static final String VLAN_ID = "vlanId";
- private static final String PORTS = "ports";
+ private static final String ENDPOINTS = "endpoints";
private static Logger log = LoggerFactory.getLogger(XconnectCodec.class);
@@ -40,8 +43,8 @@
final ObjectNode result = context.mapper().createObjectNode();
result.put(DEVICE_ID, desc.key().deviceId().toString());
result.put(VLAN_ID, desc.key().vlanId().toString());
- final ArrayNode portNode = result.putArray(PORTS);
- desc.ports().forEach(port -> portNode.add(port.toString()));
+ final ArrayNode portNode = result.putArray(ENDPOINTS);
+ desc.endpoints().forEach(endpoint -> portNode.add(endpoint.toString()));
return result;
}
@@ -51,13 +54,14 @@
DeviceId deviceId = DeviceId.deviceId(json.path(DEVICE_ID).asText());
VlanId vlanId = VlanId.vlanId(json.path(VLAN_ID).asText());
- Set<String> ports = Sets.newHashSet();
- JsonNode portNodes = json.get(PORTS);
- if (portNodes != null) {
- portNodes.forEach(portNode -> ports.add(portNode.asText()));
+ Set<XconnectEndpoint> endpoints = Sets.newHashSet();
+ JsonNode endpointNodes = json.get(ENDPOINTS);
+ if (endpointNodes != null) {
+ XconnectEndpoint endpoint = XconnectEndpoint.fromString(endpointNodes.asText());
+ endpointNodes.forEach(endpointNode -> endpoints.add(endpoint));
}
XconnectKey key = new XconnectKey(deviceId, vlanId);
- return new XconnectDesc(key, ports);
+ return new XconnectDesc(key, endpoints);
}
}
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectDesc.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectDesc.java
index e94c1db..1e7a3b2 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectDesc.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectDesc.java
@@ -25,17 +25,17 @@
*/
public class XconnectDesc {
private XconnectKey key;
- private Set<String> ports;
+ private Set<XconnectEndpoint> endpoints;
/**
* Constructs new Xconnect description with given device ID and VLAN ID.
*
* @param key Xconnect key
- * @param ports set of ports
+ * @param endpoints set of endpoints
*/
- public XconnectDesc(XconnectKey key, Set<String> ports) {
+ public XconnectDesc(XconnectKey key, Set<XconnectEndpoint> endpoints) {
this.key = key;
- this.ports = ports;
+ this.endpoints = endpoints;
}
/**
@@ -48,12 +48,12 @@
}
/**
- * Gets ports.
+ * Gets endpoints.
*
- * @return set of ports
+ * @return set of endpoints
*/
- public Set<String> ports() {
- return ports;
+ public Set<XconnectEndpoint> endpoints() {
+ return endpoints;
}
@Override
@@ -69,19 +69,19 @@
}
final XconnectDesc other = (XconnectDesc) obj;
return Objects.equals(this.key, other.key) &&
- Objects.equals(this.ports, other.ports);
+ Objects.equals(this.endpoints, other.endpoints);
}
@Override
public int hashCode() {
- return Objects.hash(key, ports);
+ return Objects.hash(key, endpoints);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("key", key)
- .add("ports", ports)
+ .add("endpoints", endpoints)
.toString();
}
}
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectEndpoint.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectEndpoint.java
new file mode 100644
index 0000000..c7a2242
--- /dev/null
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectEndpoint.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.segmentrouting.xconnect.api;
+
+/**
+ * Represents cross connect endpoint.
+ */
+public abstract class XconnectEndpoint {
+ public static final String LB_KEYWORD = "LB:";
+ static final String PORT_PATTERN = "^\\d+$";
+ static final String LOAD_BALANCER_PATTERN = "^" + LB_KEYWORD + "\\d+$";
+
+ /**
+ * Types of endpoint.
+ */
+ public enum Type {
+ /**
+ * The endpoint is specified by an port number.
+ */
+ PORT,
+
+ /**
+ * The endpoint is specified by a load balancer.
+ */
+ LOAD_BALANCER
+ }
+
+ /**
+ * Type of this endpoint.
+ *
+ * @return type
+ */
+ public abstract XconnectEndpoint.Type type();
+
+ /**
+ * Constructs XconnectEndpoint from string.
+ *
+ * @param s string
+ * @return XconnectEndpoint
+ * @throws IllegalArgumentException if given string is in a wrong format
+ */
+ public static XconnectEndpoint fromString(String s) {
+ if (s.matches(XconnectEndpoint.PORT_PATTERN)) {
+ return XconnectPortEndpoint.fromString(s);
+ } else if (s.matches(XconnectEndpoint.LOAD_BALANCER_PATTERN)) {
+ return XconnectLoadBalancerEndpoint.fromString(s);
+ } else {
+ throw new IllegalArgumentException("Illegal endpoint format: " + s);
+ }
+ }
+}
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectLoadBalancerEndpoint.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectLoadBalancerEndpoint.java
new file mode 100644
index 0000000..4172292f
--- /dev/null
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectLoadBalancerEndpoint.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.segmentrouting.xconnect.api;
+
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * Represents a cross connect endpoint specified by load balancer.
+ */
+public final class XconnectLoadBalancerEndpoint extends XconnectEndpoint {
+ private final int key;
+
+ private XconnectLoadBalancerEndpoint(int key) {
+ this.key = key;
+ }
+
+ /**
+ * Returns load balancer key.
+ *
+ * @return load balancer key.
+ */
+ public int key() {
+ return key;
+ }
+
+ /**
+ * Returns an instance of XconnectLoadBalancerEndpoint with given load balancer key.
+ *
+ * @param key load balancer key
+ * @return an instance of XconnectLoadBalancerEndpoint
+ */
+ public static XconnectLoadBalancerEndpoint of(int key) {
+ return new XconnectLoadBalancerEndpoint(key);
+ }
+
+ /**
+ * Gets XconnectLoadBalancerEndpoint from string.
+ *
+ * @param s string
+ * @return XconnectLoadBalancerEndpoint
+ */
+ public static XconnectLoadBalancerEndpoint fromString(String s) {
+ checkArgument(s.matches(LOAD_BALANCER_PATTERN), "String {} does not match {} format", s, LOAD_BALANCER_PATTERN);
+ return new XconnectLoadBalancerEndpoint(Integer.valueOf(s.replaceFirst(LB_KEYWORD, "")));
+ }
+
+ @Override
+ public Type type() {
+ return Type.LOAD_BALANCER;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(key);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof XconnectLoadBalancerEndpoint) {
+ final XconnectLoadBalancerEndpoint other = (XconnectLoadBalancerEndpoint) obj;
+ return Objects.equals(this.key, other.key);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return LB_KEYWORD + String.valueOf(key);
+ }
+}
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectPortEndpoint.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectPortEndpoint.java
new file mode 100644
index 0000000..f26eaf0
--- /dev/null
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectPortEndpoint.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.segmentrouting.xconnect.api;
+
+import org.onosproject.net.PortNumber;
+
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * Represents a cross connect endpoint specified by port number.
+ */
+public final class XconnectPortEndpoint extends XconnectEndpoint {
+ private final PortNumber port;
+
+ private XconnectPortEndpoint(PortNumber port) {
+ this.port = port;
+ }
+
+ /**
+ * Returns port number.
+ *
+ * @return port number
+ */
+ public PortNumber port() {
+ return port;
+ }
+
+ /**
+ * Returns an instance of XconnectPortEndpoint with given port number.
+ *
+ * @param port port number
+ * @return an instance of XconnectPortEndpoint
+ */
+ public static XconnectPortEndpoint of(PortNumber port) {
+ return new XconnectPortEndpoint(port);
+ }
+
+ /**
+ * Gets XconnectPortEndpoint from string.
+ *
+ * @param s string
+ * @return XconnectPortEndpoint
+ */
+ public static XconnectPortEndpoint fromString(String s) {
+ checkArgument(s.matches(PORT_PATTERN), "String {} does not match {} format", s, PORT_PATTERN);
+ return new XconnectPortEndpoint(PortNumber.fromString(s));
+ }
+
+ @Override
+ public XconnectEndpoint.Type type() {
+ return Type.PORT;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(port);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof XconnectPortEndpoint) {
+ final XconnectPortEndpoint other = (XconnectPortEndpoint) obj;
+ return Objects.equals(this.port, other.port);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return String.valueOf(port);
+ }
+}
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectService.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectService.java
index ec47180..1c4ff6d 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectService.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectService.java
@@ -46,9 +46,9 @@
*
* @param deviceId device ID
* @param vlanId VLAN ID
- * @param ports set of ports
+ * @param endpoints set of endpoints
*/
- void addOrUpdateXconnect(DeviceId deviceId, VlanId vlanId, Set<String> ports);
+ void addOrUpdateXconnect(DeviceId deviceId, VlanId vlanId, Set<XconnectEndpoint> endpoints);
/**
* Deletes Xconnect.
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/impl/XconnectManager.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/impl/XconnectManager.java
index 626ead3..91a03f3 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/impl/XconnectManager.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/xconnect/impl/XconnectManager.java
@@ -78,7 +78,10 @@
import org.onosproject.segmentrouting.storekey.VlanNextObjectiveStoreKey;
import org.onosproject.segmentrouting.xconnect.api.XconnectCodec;
import org.onosproject.segmentrouting.xconnect.api.XconnectDesc;
+import org.onosproject.segmentrouting.xconnect.api.XconnectEndpoint;
import org.onosproject.segmentrouting.xconnect.api.XconnectKey;
+import org.onosproject.segmentrouting.xconnect.api.XconnectLoadBalancerEndpoint;
+import org.onosproject.segmentrouting.xconnect.api.XconnectPortEndpoint;
import org.onosproject.segmentrouting.xconnect.api.XconnectService;
import org.onosproject.store.serializers.KryoNamespaces;
import org.onosproject.store.service.ConsistentMap;
@@ -146,10 +149,10 @@
public InterfaceService interfaceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- HostService hostService;
+ private HostService hostService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- L2LbService l2LbService;
+ private L2LbService l2LbService;
private static final String APP_NAME = "org.onosproject.xconnect";
private static final String ERROR_NOT_LEADER = "Not leader controller";
@@ -159,13 +162,13 @@
private static Logger log = LoggerFactory.getLogger(XconnectManager.class);
private ApplicationId appId;
- private ConsistentMap<XconnectKey, Set<String>> xconnectStore;
+ private ConsistentMap<XconnectKey, Set<XconnectEndpoint>> xconnectStore;
private ConsistentMap<XconnectKey, Integer> xconnectNextObjStore;
private ConsistentMap<VlanNextObjectiveStoreKey, Integer> xconnectMulticastNextStore;
private ConsistentMap<VlanNextObjectiveStoreKey, List<PortNumber>> xconnectMulticastPortsStore;
- private final MapEventListener<XconnectKey, Set<String>> xconnectListener = new XconnectMapListener();
+ private final MapEventListener<XconnectKey, Set<XconnectEndpoint>> xconnectListener = new XconnectMapListener();
private final DeviceListener deviceListener = new InternalDeviceListener();
private ExecutorService deviceEventExecutor;
@@ -179,8 +182,6 @@
private Cache<L2LbId, XconnectKey> l2LbCache;
// Executor for the cache
private ScheduledExecutorService l2lbExecutor;
- // Pattern for L2Lb key
- private static final String L2LB_PATTERN = "^(L2LB\\(\\d*\\))$";
// We need to listen for some events to properly installed the xconnect with l2lb
private final L2LbListener l2LbListener = new InternalL2LbListener();
@@ -193,9 +194,12 @@
.register(KryoNamespaces.API)
.register(XconnectManager.class)
.register(XconnectKey.class)
+ .register(XconnectEndpoint.class)
+ .register(XconnectPortEndpoint.class)
+ .register(XconnectLoadBalancerEndpoint.class)
.register(VlanNextObjectiveStoreKey.class);
- xconnectStore = storageService.<XconnectKey, Set<String>>consistentMapBuilder()
+ xconnectStore = storageService.<XconnectKey, Set<XconnectEndpoint>>consistentMapBuilder()
.withName("onos-sr-xconnect")
.withRelaxedReadConsistency()
.withSerializer(Serializer.using(serializer.build()))
@@ -255,11 +259,11 @@
}
@Override
- public void addOrUpdateXconnect(DeviceId deviceId, VlanId vlanId, Set<String> ports) {
- log.info("Adding or updating xconnect. deviceId={}, vlanId={}, ports={}",
- deviceId, vlanId, ports);
+ public void addOrUpdateXconnect(DeviceId deviceId, VlanId vlanId, Set<XconnectEndpoint> endpoints) {
+ log.info("Adding or updating xconnect. deviceId={}, vlanId={}, endpoints={}",
+ deviceId, vlanId, endpoints);
final XconnectKey key = new XconnectKey(deviceId, vlanId);
- xconnectStore.put(key, ports);
+ xconnectStore.put(key, endpoints);
}
@Override
@@ -270,9 +274,9 @@
xconnectStore.remove(key);
// Cleanup multicasting support, if any.
- srService.getPairDeviceId(deviceId).ifPresent(pairDeviceId -> {
- cleanupL2MulticastRule(pairDeviceId, srService.getPairLocalPort(pairDeviceId).get(), vlanId, true);
- });
+ srService.getPairDeviceId(deviceId).ifPresent(pairDeviceId ->
+ cleanupL2MulticastRule(pairDeviceId, srService.getPairLocalPort(pairDeviceId).get(), vlanId, true)
+ );
}
@@ -286,14 +290,17 @@
@Override
public boolean hasXconnect(ConnectPoint cp) {
return getXconnects().stream().anyMatch(desc ->
- desc.key().deviceId().equals(cp.deviceId()) && desc.ports().contains(cp.port().toString())
+ desc.key().deviceId().equals(cp.deviceId()) && desc.endpoints().stream().anyMatch(ep ->
+ ep.type() == XconnectEndpoint.Type.PORT && ((XconnectPortEndpoint) ep).port().equals(cp.port())
+ )
);
}
@Override
public List<VlanId> getXconnectVlans(DeviceId deviceId, PortNumber port) {
return getXconnects().stream()
- .filter(desc -> desc.key().deviceId().equals(deviceId) && desc.ports().contains(port.toString()))
+ .filter(desc -> desc.key().deviceId().equals(deviceId) && desc.endpoints().stream().anyMatch(ep ->
+ ep.type() == XconnectEndpoint.Type.PORT && ((XconnectPortEndpoint) ep).port().equals(port)))
.map(XconnectDesc::key)
.map(XconnectKey::vlanId)
.collect(Collectors.toList());
@@ -332,12 +339,12 @@
});
}
- private class XconnectMapListener implements MapEventListener<XconnectKey, Set<String>> {
+ private class XconnectMapListener implements MapEventListener<XconnectKey, Set<XconnectEndpoint>> {
@Override
- public void event(MapEvent<XconnectKey, Set<String>> event) {
+ public void event(MapEvent<XconnectKey, Set<XconnectEndpoint>> event) {
XconnectKey key = event.key();
- Set<String> ports = Versioned.valueOrNull(event.newValue());
- Set<String> oldPorts = Versioned.valueOrNull(event.oldValue());
+ Set<XconnectEndpoint> ports = Versioned.valueOrNull(event.newValue());
+ Set<XconnectEndpoint> oldPorts = Versioned.valueOrNull(event.oldValue());
switch (event.type()) {
case INSERT:
@@ -477,7 +484,7 @@
private void init(DeviceId deviceId) {
getXconnects().stream()
.filter(desc -> desc.key().deviceId().equals(deviceId))
- .forEach(desc -> populateXConnect(desc.key(), desc.ports()));
+ .forEach(desc -> populateXConnect(desc.key(), desc.endpoints()));
}
private void cleanup(DeviceId deviceId) {
@@ -490,21 +497,21 @@
/**
* Populates XConnect groups and flows for given key.
*
- * @param key XConnect key
- * @param ports a set of ports to be cross-connected
+ * @param key XConnect key
+ * @param endpoints a set of endpoints to be cross-connected
*/
- private void populateXConnect(XconnectKey key, Set<String> ports) {
+ private void populateXConnect(XconnectKey key, Set<XconnectEndpoint> endpoints) {
if (!isLocalLeader(key.deviceId())) {
log.info("Abort populating XConnect {}: {}", key, ERROR_NOT_LEADER);
return;
}
- int nextId = populateNext(key, ports);
+ int nextId = populateNext(key, endpoints);
if (nextId == -1) {
log.warn("Fail to populateXConnect {}: {}", key, ERROR_NEXT_ID);
return;
}
- populateFilter(key, ports);
+ populateFilter(key, endpoints);
populateFwd(key, nextId);
populateAcl(key);
}
@@ -512,45 +519,45 @@
/**
* Populates filtering objectives for given XConnect.
*
- * @param key XConnect store key
- * @param ports XConnect ports
+ * @param key XConnect store key
+ * @param endpoints XConnect endpoints
*/
- private void populateFilter(XconnectKey key, Set<String> ports) {
+ private void populateFilter(XconnectKey key, Set<XconnectEndpoint> endpoints) {
// FIXME Improve the logic
// If L2 load balancer is not involved, use filtered port. Otherwise, use unfiltered port.
// The purpose is to make sure existing XConnect logic can still work on a configured port.
- boolean filtered = ports.stream()
- .map(p -> getNextTreatment(key.deviceId(), p, false))
+ boolean filtered = endpoints.stream()
+ .map(ep -> getNextTreatment(key.deviceId(), ep, false))
.allMatch(t -> t.type().equals(NextTreatment.Type.TREATMENT));
- ports.stream()
- .map(p -> getPhysicalPorts(key.deviceId(), p))
+ endpoints.stream()
+ .map(ep -> getPhysicalPorts(key.deviceId(), ep))
.flatMap(Set::stream).forEach(port -> {
- FilteringObjective.Builder filtObjBuilder = filterObjBuilder(key, port, filtered);
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> log.debug("XConnect FilterObj for {} on port {} populated",
- key, port),
- (objective, error) ->
- log.warn("Failed to populate XConnect FilterObj for {} on port {}: {}",
- key, port, error));
- flowObjectiveService.filter(key.deviceId(), filtObjBuilder.add(context));
- });
+ FilteringObjective.Builder filtObjBuilder = filterObjBuilder(key, port, filtered);
+ ObjectiveContext context = new DefaultObjectiveContext(
+ (objective) -> log.debug("XConnect FilterObj for {} on port {} populated",
+ key, port),
+ (objective, error) ->
+ log.warn("Failed to populate XConnect FilterObj for {} on port {}: {}",
+ key, port, error));
+ flowObjectiveService.filter(key.deviceId(), filtObjBuilder.add(context));
+ });
}
/**
* Populates next objectives for given XConnect.
*
- * @param key XConnect store key
- * @param ports XConnect ports
+ * @param key XConnect store key
+ * @param endpoints XConnect endpoints
* @return next id
*/
- private int populateNext(XconnectKey key, Set<String> ports) {
+ private int populateNext(XconnectKey key, Set<XconnectEndpoint> endpoints) {
if (xconnectNextObjStore.containsKey(key)) {
int nextId = xconnectNextObjStore.get(key).value();
log.debug("NextObj for {} found, id={}", key, nextId);
return nextId;
} else {
- NextObjective.Builder nextObjBuilder = nextObjBuilder(key, ports);
+ NextObjective.Builder nextObjBuilder = nextObjBuilder(key, endpoints);
if (nextObjBuilder == null) {
log.warn("Fail to populate {}: {}", key, ERROR_NEXT_OBJ_BUILDER);
return -1;
@@ -603,10 +610,10 @@
/**
* Revokes XConnect groups and flows for given key.
*
- * @param key XConnect key
- * @param ports XConnect ports
+ * @param key XConnect key
+ * @param endpoints XConnect endpoints
*/
- private void revokeXConnect(XconnectKey key, Set<String> ports) {
+ private void revokeXConnect(XconnectKey key, Set<XconnectEndpoint> endpoints) {
if (!isLocalLeader(key.deviceId())) {
log.info("Abort revoking XConnect {}: {}", key, ERROR_NOT_LEADER);
return;
@@ -615,48 +622,51 @@
if (xconnectNextObjStore.containsKey(key)) {
int nextId = xconnectNextObjStore.get(key).value();
revokeFwd(key, nextId, null);
- revokeNext(key, ports, nextId, null);
+ revokeNext(key, endpoints, nextId, null);
} else {
log.warn("NextObj for {} does not exist in the store.", key);
}
- revokeFilter(key, ports);
+ revokeFilter(key, endpoints);
revokeAcl(key);
}
/**
* Revokes filtering objectives for given XConnect.
*
- * @param key XConnect store key
- * @param ports XConnect ports
+ * @param key XConnect store key
+ * @param endpoints XConnect endpoints
*/
- private void revokeFilter(XconnectKey key, Set<String> ports) {
+ private void revokeFilter(XconnectKey key, Set<XconnectEndpoint> endpoints) {
// FIXME Improve the logic
// If L2 load balancer is not involved, use filtered port. Otherwise, use unfiltered port.
// The purpose is to make sure existing XConnect logic can still work on a configured port.
- Set<Set<PortNumber>> portsSet = ports.stream()
- .map(p -> getPhysicalPorts(key.deviceId(), p)).collect(Collectors.toSet());
- boolean filtered = portsSet.stream().allMatch(s -> s.size() == 1);
- portsSet.stream().flatMap(Set::stream).forEach(port -> {
- FilteringObjective.Builder filtObjBuilder = filterObjBuilder(key, port, filtered);
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> log.debug("XConnect FilterObj for {} on port {} revoked",
- key, port),
- (objective, error) ->
- log.warn("Failed to revoke XConnect FilterObj for {} on port {}: {}",
- key, port, error));
- flowObjectiveService.filter(key.deviceId(), filtObjBuilder.remove(context));
- });
+ boolean filtered = endpoints.stream()
+ .map(ep -> getNextTreatment(key.deviceId(), ep, false))
+ .allMatch(t -> t.type().equals(NextTreatment.Type.TREATMENT));
+
+ endpoints.stream()
+ .map(ep -> getPhysicalPorts(key.deviceId(), ep)).
+ flatMap(Set::stream).forEach(port -> {
+ FilteringObjective.Builder filtObjBuilder = filterObjBuilder(key, port, filtered);
+ ObjectiveContext context = new DefaultObjectiveContext(
+ (objective) -> log.debug("XConnect FilterObj for {} on port {} revoked",
+ key, port),
+ (objective, error) ->
+ log.warn("Failed to revoke XConnect FilterObj for {} on port {}: {}",
+ key, port, error));
+ flowObjectiveService.filter(key.deviceId(), filtObjBuilder.remove(context));
+ });
}
/**
* Revokes next objectives for given XConnect.
*
* @param key XConnect store key
- * @param ports ports in the XConnect
+ * @param endpoints XConnect endpoints
* @param nextId next objective id
* @param nextFuture completable future for this next objective operation
*/
- private void revokeNext(XconnectKey key, Set<String> ports, int nextId,
+ private void revokeNext(XconnectKey key, Set<XconnectEndpoint> endpoints, int nextId,
CompletableFuture<ObjectiveError> nextFuture) {
ObjectiveContext context = new ObjectiveContext() {
@Override
@@ -677,18 +687,18 @@
}
};
- NextObjective.Builder nextObjBuilder = nextObjBuilder(key, ports, nextId);
+ NextObjective.Builder nextObjBuilder = nextObjBuilder(key, endpoints, nextId);
if (nextObjBuilder == null) {
log.warn("Fail to revokeNext {}: {}", key, ERROR_NEXT_OBJ_BUILDER);
return;
}
// Release the L2Lbs if present
- ports.forEach(port -> {
- if (isL2LbKey(port)) {
- String l2LbKey = port.substring("L2LB(".length(), port.length() - 1);
- l2LbService.release(new L2LbId(key.deviceId(), Integer.parseInt(l2LbKey)), appId);
- }
- });
+ endpoints.stream()
+ .filter(endpoint -> endpoint.type() == XconnectEndpoint.Type.LOAD_BALANCER)
+ .forEach(endpoint -> {
+ String l2LbKey = String.valueOf(((XconnectLoadBalancerEndpoint) endpoint).key());
+ l2LbService.release(new L2LbId(key.deviceId(), Integer.parseInt(l2LbKey)), appId);
+ });
flowObjectiveService.next(key.deviceId(), nextObjBuilder.remove(context));
xconnectNextObjStore.remove(key);
}
@@ -739,12 +749,12 @@
/**
* Updates XConnect groups and flows for given key.
*
- * @param key XConnect key
- * @param prevPorts previous XConnect ports
- * @param ports new XConnect ports
+ * @param key XConnect key
+ * @param prevEndpoints previous XConnect endpoints
+ * @param endpoints new XConnect endpoints
*/
- private void updateXConnect(XconnectKey key, Set<String> prevPorts,
- Set<String> ports) {
+ private void updateXConnect(XconnectKey key, Set<XconnectEndpoint> prevEndpoints,
+ Set<XconnectEndpoint> endpoints) {
if (!isLocalLeader(key.deviceId())) {
log.info("Abort updating XConnect {}: {}", key, ERROR_NOT_LEADER);
return;
@@ -753,11 +763,11 @@
// Pair port is built-in and thus not going to change. No need to update it.
// remove old filter
- prevPorts.stream().filter(port -> !ports.contains(port)).forEach(port ->
- revokeFilter(key, ImmutableSet.of(port)));
+ prevEndpoints.stream().filter(prevEndpoint -> !endpoints.contains(prevEndpoint)).forEach(prevEndpoint ->
+ revokeFilter(key, ImmutableSet.of(prevEndpoint)));
// install new filter
- ports.stream().filter(port -> !prevPorts.contains(port)).forEach(port ->
- populateFilter(key, ImmutableSet.of(port)));
+ endpoints.stream().filter(endpoint -> !prevEndpoints.contains(endpoint)).forEach(endpoint ->
+ populateFilter(key, ImmutableSet.of(endpoint)));
CompletableFuture<ObjectiveError> fwdFuture = new CompletableFuture<>();
CompletableFuture<ObjectiveError> nextFuture = new CompletableFuture<>();
@@ -769,14 +779,14 @@
fwdFuture.thenAcceptAsync(fwdStatus -> {
if (fwdStatus == null) {
log.debug("Fwd removed. Now remove group {}", key);
- revokeNext(key, prevPorts, nextId, nextFuture);
+ revokeNext(key, prevEndpoints, nextId, nextFuture);
}
});
nextFuture.thenAcceptAsync(nextStatus -> {
if (nextStatus == null) {
log.debug("Installing new group and flow for {}", key);
- int newNextId = populateNext(key, ports);
+ int newNextId = populateNext(key, endpoints);
if (newNextId == -1) {
log.warn("Fail to updateXConnect {}: {}", key, ERROR_NEXT_ID);
return;
@@ -792,12 +802,12 @@
/**
* Creates a next objective builder for XConnect with given nextId.
*
- * @param key XConnect key
- * @param ports ports or L2 load balancer key
+ * @param key XConnect key
+ * @param endpoints XConnect endpoints
* @param nextId next objective id
* @return next objective builder
*/
- private NextObjective.Builder nextObjBuilder(XconnectKey key, Set<String> ports, int nextId) {
+ private NextObjective.Builder nextObjBuilder(XconnectKey key, Set<XconnectEndpoint> endpoints, int nextId) {
TrafficSelector metadata =
DefaultTrafficSelector.builder().matchVlanId(key.vlanId()).build();
NextObjective.Builder nextObjBuilder = DefaultNextObjective
@@ -805,13 +815,13 @@
.withType(NextObjective.Type.BROADCAST).fromApp(appId)
.withMeta(metadata);
- for (String port : ports) {
- NextTreatment nextTreatment = getNextTreatment(key.deviceId(), port, true);
+ for (XconnectEndpoint endpoint : endpoints) {
+ NextTreatment nextTreatment = getNextTreatment(key.deviceId(), endpoint, true);
if (nextTreatment == null) {
// If a L2Lb is used in the XConnect - putting on hold
- if (isL2LbKey(port)) {
+ if (endpoint.type() == XconnectEndpoint.Type.LOAD_BALANCER) {
log.warn("Unable to create nextObj. L2Lb not ready");
- String l2LbKey = port.substring("L2LB(".length(), port.length() - 1);
+ String l2LbKey = String.valueOf(((XconnectLoadBalancerEndpoint) endpoint).key());
l2LbCache.asMap().putIfAbsent(new L2LbId(key.deviceId(), Integer.parseInt(l2LbKey)),
key);
} else {
@@ -828,13 +838,13 @@
/**
* Creates a next objective builder for XConnect.
*
- * @param key XConnect key
- * @param ports set of XConnect ports
+ * @param key XConnect key
+ * @param endpoints Xconnect endpoints
* @return next objective builder
*/
- private NextObjective.Builder nextObjBuilder(XconnectKey key, Set<String> ports) {
+ private NextObjective.Builder nextObjBuilder(XconnectKey key, Set<XconnectEndpoint> endpoints) {
int nextId = flowObjectiveService.allocateNextId();
- return nextObjBuilder(key, ports, nextId);
+ return nextObjBuilder(key, endpoints, nextId);
}
@@ -1224,57 +1234,36 @@
return ports.stream().anyMatch(p -> !p.equals(pairPort));
}
- private Set<PortNumber> getPhysicalPorts(DeviceId deviceId, String port) {
- // If port is numeric, treat it as regular port.
- // Otherwise try to parse it as load balancer key and get the physical port the LB maps to.
- try {
- return Sets.newHashSet(PortNumber.portNumber(Integer.parseInt(port)));
- } catch (NumberFormatException e) {
- log.debug("Port {} is not numeric. Try to parse it as load balancer key", port);
+ private Set<PortNumber> getPhysicalPorts(DeviceId deviceId, XconnectEndpoint endpoint) {
+ if (endpoint.type() == XconnectEndpoint.Type.PORT) {
+ PortNumber port = ((XconnectPortEndpoint) endpoint).port();
+ return Sets.newHashSet(port);
}
-
- String l2LbKey = port.substring("L2LB(".length(), port.length() - 1);
- L2LbId l2LbId = new L2LbId(deviceId, Integer.parseInt(l2LbKey));
- try {
- return Sets.newHashSet(l2LbService.getL2Lb(l2LbId).ports());
- } catch (NumberFormatException e) {
- log.debug("Port {} is not load balancer key either. Ignore", port);
- } catch (NullPointerException e) {
- log.debug("L2 load balancer {} not found. Ignore", l2LbKey);
+ if (endpoint.type() == XconnectEndpoint.Type.LOAD_BALANCER) {
+ L2LbId l2LbId = new L2LbId(deviceId, ((XconnectLoadBalancerEndpoint) endpoint).key());
+ Set<PortNumber> ports = l2LbService.getL2Lb(l2LbId).ports();
+ return Sets.newHashSet(ports);
}
-
return Sets.newHashSet();
}
- private NextTreatment getNextTreatment(DeviceId deviceId, String port, boolean reserve) {
- // If port is numeric, treat it as regular port.
- // Otherwise try to parse it as load balancer key and get the physical port the LB maps to.
- try {
- PortNumber portNumber = PortNumber.portNumber(Integer.parseInt(port));
- return DefaultNextTreatment.of(DefaultTrafficTreatment.builder().setOutput(portNumber).build());
- } catch (NumberFormatException e) {
- log.debug("Port {} is not numeric. Try to parse it as load balancer key", port);
+ private NextTreatment getNextTreatment(DeviceId deviceId, XconnectEndpoint endpoint, boolean reserve) {
+ if (endpoint.type() == XconnectEndpoint.Type.PORT) {
+ PortNumber port = ((XconnectPortEndpoint) endpoint).port();
+ return DefaultNextTreatment.of(DefaultTrafficTreatment.builder().setOutput(port).build());
}
-
- String l2LbKey = port.substring("L2LB(".length(), port.length() - 1);
- try {
- L2LbId l2LbId = new L2LbId(deviceId, Integer.parseInt(l2LbKey));
- NextTreatment idNextTreatment = IdNextTreatment.of(
- l2LbService.getL2LbNext(l2LbId));
+ if (endpoint.type() == XconnectEndpoint.Type.LOAD_BALANCER) {
+ L2LbId l2LbId = new L2LbId(deviceId, ((XconnectLoadBalancerEndpoint) endpoint).key());
+ NextTreatment idNextTreatment = IdNextTreatment.of(l2LbService.getL2LbNext(l2LbId));
// Reserve only one time during next objective creation
if (reserve) {
- if (!l2LbService.reserve(new L2LbId(deviceId, Integer.parseInt(l2LbKey)), appId)) {
+ if (!l2LbService.reserve(l2LbId, appId)) {
log.warn("Reservation failed for {}", l2LbId);
idNextTreatment = null;
}
}
return idNextTreatment;
- } catch (NumberFormatException e) {
- log.debug("Port {} is not load balancer key either. Ignore", port);
- } catch (NullPointerException e) {
- log.debug("L2 load balancer {} not found. Ignore", l2LbKey);
}
-
return null;
}
@@ -1294,10 +1283,6 @@
return true;
}
- private boolean isL2LbKey(String l2LbKey) {
- return l2LbKey.matches(L2LB_PATTERN);
- }
-
private class InternalL2LbListener implements L2LbListener {
// Populate xconnect once l2lb is available
@Override
@@ -1320,12 +1305,12 @@
}
log.debug("Dequeue {}", l2LbId);
l2LbCache.invalidate(l2LbId);
- Set<String> ports = Versioned.valueOrNull(xconnectStore.get(xconnectKey));
- if (ports == null || ports.isEmpty()) {
- log.warn("Ports not found for XConnect {}", xconnectKey);
+ Set<XconnectEndpoint> endpoints = Versioned.valueOrNull(xconnectStore.get(xconnectKey));
+ if (endpoints == null || endpoints.isEmpty()) {
+ log.warn("Endpoints not found for XConnect {}", xconnectKey);
return;
}
- populateXConnect(xconnectKey, ports);
+ populateXConnect(xconnectKey, endpoints);
log.trace("L2Lb cache size {}", l2LbCache.size());
}
diff --git a/apps/segmentrouting/web/src/main/java/org/onosproject/segmentrouting/web/XconnectWebResource.java b/apps/segmentrouting/web/src/main/java/org/onosproject/segmentrouting/web/XconnectWebResource.java
index edaea9e..51c9cc9 100644
--- a/apps/segmentrouting/web/src/main/java/org/onosproject/segmentrouting/web/XconnectWebResource.java
+++ b/apps/segmentrouting/web/src/main/java/org/onosproject/segmentrouting/web/XconnectWebResource.java
@@ -75,12 +75,12 @@
ObjectNode json = readTreeFromStream(mapper, input);
XconnectDesc desc = codec(XconnectDesc.class).decode(json, this);
- if (desc.ports().size() != 2) {
+ if (desc.endpoints().size() != 2) {
throw new IllegalArgumentException("Ports should have only two items.");
}
XconnectService xconnectService = get(XconnectService.class);
- xconnectService.addOrUpdateXconnect(desc.key().deviceId(), desc.key().vlanId(), desc.ports());
+ xconnectService.addOrUpdateXconnect(desc.key().deviceId(), desc.key().vlanId(), desc.endpoints());
return Response.ok().build();
}