Rename bundles
app -> impl
oar -> app
in order to be more consistent with other apps
Change-Id: Ic8c12bb7267d116bd58d09647ef4cca0c53ee272
diff --git a/app/app.xml b/app/app.xml
new file mode 100644
index 0000000..2395202
--- /dev/null
+++ b/app/app.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright 2015-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.
+ -->
+<app name="org.onosproject.segmentrouting" origin="Open Networking Foundation"
+ version="${project.version}"
+ category="Traffic Steering" url="http://trellisfabric.org"
+ title="Trellis Control App"
+ featuresRepo="mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features"
+ features="${project.artifactId}" apps="org.onosproject.mcast,org.onosproject.route-service,org.onosproject.portloadbalancer">
+ <description>${project.description}</description>
+ <artifact>mvn:${project.groupId}/segmentrouting-app/${project.version}</artifact>
+ <artifact>mvn:${project.groupId}/segmentrouting-web/${project.version}</artifact>
+</app>
\ No newline at end of file
diff --git a/app/features.xml b/app/features.xml
new file mode 100644
index 0000000..bdfa219
--- /dev/null
+++ b/app/features.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+ ~ Copyright 2015-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.
+ -->
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.2.0" name="${project.artifactId}-${project.version}">
+ <feature name="${project.artifactId}" version="${project.version}"
+ description="${project.description}">
+ <feature>onos-api</feature>
+ <bundle>mvn:${project.groupId}/segmentrouting-app/${project.version}</bundle>
+ <bundle>mvn:${project.groupId}/segmentrouting-web/${project.version}</bundle>
+ </feature>
+</features>
\ No newline at end of file
diff --git a/app/pom.xml b/app/pom.xml
index c43447e..eaea0db 100644
--- a/app/pom.xml
+++ b/app/pom.xml
@@ -29,115 +29,7 @@
<artifactId>segmentrouting-app</artifactId>
<packaging>bundle</packaging>
<url>http://trellisfabric.org</url>
- <description>Trellis control app</description>
-
- <dependencies>
- <!-- ONOS core -->
- <dependency>
- <groupId>org.onosproject</groupId>
- <artifactId>onos-api</artifactId>
- <version>${onos.version}</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.onosproject</groupId>
- <artifactId>onos-core-net</artifactId>
- <version>${onos.version}</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.onosproject</groupId>
- <artifactId>onos-core-serializers</artifactId>
- <version>${onos.version}</version>
- <scope>provided</scope>
- </dependency>
-
- <!-- Other Trellis apps -->
- <dependency>
- <groupId>org.onosproject</groupId>
- <artifactId>segmentrouting-api</artifactId>
- <version>${project.version}</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.onosproject</groupId>
- <artifactId>onos-apps-portloadbalancer</artifactId>
- <version>${onos.version}</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.onosproject</groupId>
- <artifactId>onos-apps-route-service-api</artifactId>
- <version>${onos.version}</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.onosproject</groupId>
- <artifactId>onos-apps-mcast-api</artifactId>
- <version>${onos.version}</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.onosproject</groupId>
- <artifactId>onos-apps-mcast-cli</artifactId>
- <version>${onos.version}</version>
- <scope>provided</scope>
- </dependency>
-
- <!-- Tests -->
- <dependency>
- <groupId>org.onosproject</groupId>
- <artifactId>onos-api</artifactId>
- <version>${onos.version}</version>
- <classifier>tests</classifier>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.onosproject</groupId>
- <artifactId>onos-core-common</artifactId>
- <version>${onos.version}</version>
- <classifier>tests</classifier>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.onosproject</groupId>
- <artifactId>segmentrouting-api</artifactId>
- <version>${project.version}</version>
- <classifier>tests</classifier>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.onosproject</groupId>
- <artifactId>onos-apps-route-service-api</artifactId>
- <version>${onos.version}</version>
- <classifier>tests</classifier>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.onosproject</groupId>
- <artifactId>onlab-junit</artifactId>
- <version>${onos.version}</version>
- <scope>test</scope>
- </dependency>
-
- <!-- CLI -->
- <dependency>
- <groupId>org.apache.karaf.shell</groupId>
- <artifactId>org.apache.karaf.shell.console</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.karaf.shell</groupId>
- <artifactId>org.apache.karaf.shell.core</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.onosproject</groupId>
- <artifactId>onos-cli</artifactId>
- <version>${onos.version}</version>
- <scope>provided</scope>
- </dependency>
- </dependencies>
+ <description>Trellis control OAR wrapper</description>
<build>
<plugins>
@@ -145,16 +37,6 @@
<groupId>org.onosproject</groupId>
<artifactId>onos-maven-plugin</artifactId>
</plugin>
- <plugin>
- <groupId>org.apache.felix</groupId>
- <artifactId>maven-bundle-plugin</artifactId>
- <extensions>true</extensions>
- <configuration>
- <instructions>
- <Karaf-Commands>org.onosproject.segmentrouting.cli</Karaf-Commands>
- </instructions>
- </configuration>
- </plugin>
</plugins>
</build>
</project>
\ No newline at end of file
diff --git a/app/src/main/java/org/onosproject/segmentrouting/AppConfigHandler.java b/app/src/main/java/org/onosproject/segmentrouting/AppConfigHandler.java
deleted file mode 100644
index 38d8aac..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/AppConfigHandler.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright 2016-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;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.MacAddress;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.config.NetworkConfigEvent;
-import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.flow.criteria.Criteria;
-import org.onosproject.net.flowobjective.DefaultFilteringObjective;
-import org.onosproject.net.flowobjective.DefaultObjectiveContext;
-import org.onosproject.net.flowobjective.FilteringObjective;
-import org.onosproject.net.flowobjective.ObjectiveContext;
-import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
-import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Handles Segment Routing app config events.
- */
-public class AppConfigHandler {
- private static final Logger log = LoggerFactory.getLogger(AppConfigHandler.class);
- private final SegmentRoutingManager srManager;
- private final DeviceService deviceService;
-
- /**
- * Constructs Segment Routing App Config Handler.
- *
- * @param srManager instance of {@link SegmentRoutingManager}
- */
- public AppConfigHandler(SegmentRoutingManager srManager) {
- this.srManager = srManager;
- this.deviceService = srManager.deviceService;
- }
-
- /**
- * Processes Segment Routing App Config added event.
- *
- * @param event network config added event
- */
- protected void processAppConfigAdded(NetworkConfigEvent event) {
- log.info("Processing AppConfig CONFIG_ADDED");
- SegmentRoutingAppConfig config = (SegmentRoutingAppConfig) event.config().get();
- deviceService.getAvailableDevices().forEach(device -> {
- populateVRouter(device.id(), getMacAddresses(config));
- config.blackholeIPs().forEach(ipPrefix -> {
- srManager.routingRulePopulator.populateDefaultRouteBlackhole(device.id(), ipPrefix);
- });
- });
- }
-
- /**
- * Processes Segment Routing App Config updated event.
- *
- * @param event network config updated event
- */
- protected void processAppConfigUpdated(NetworkConfigEvent event) {
- log.info("Processing AppConfig CONFIG_UPDATED");
- SegmentRoutingAppConfig config = (SegmentRoutingAppConfig) event.config().get();
- SegmentRoutingAppConfig prevConfig = (SegmentRoutingAppConfig) event.prevConfig().get();
- deviceService.getAvailableDevices().forEach(device -> {
- Set<MacAddress> macAddresses = new HashSet<>(getMacAddresses(config));
- Set<MacAddress> prevMacAddresses = new HashSet<>(getMacAddresses(prevConfig));
- // Avoid removing and re-adding unchanged MAC addresses since
- // FlowObjective does not guarantee the execution order.
- Set<MacAddress> sameMacAddresses = new HashSet<>(macAddresses);
- sameMacAddresses.retainAll(prevMacAddresses);
- macAddresses.removeAll(sameMacAddresses);
- prevMacAddresses.removeAll(sameMacAddresses);
-
- revokeVRouter(device.id(), prevMacAddresses);
- populateVRouter(device.id(), macAddresses);
- Set<IpPrefix> toRemove = Sets.difference(prevConfig.blackholeIPs(), config.blackholeIPs());
- toRemove.forEach(ipPrefix -> {
- srManager.routingRulePopulator.removeDefaultRouteBlackhole(device.id(), ipPrefix);
- });
- Set<IpPrefix> toAdd = Sets.difference(config.blackholeIPs(), prevConfig.blackholeIPs());
- toAdd.forEach(ipPrefix -> {
- srManager.routingRulePopulator.populateDefaultRouteBlackhole(device.id(), ipPrefix);
- });
- });
-
- }
-
- /**
- * Processes Segment Routing App Config removed event.
- *
- * @param event network config removed event
- */
- protected void processAppConfigRemoved(NetworkConfigEvent event) {
- log.info("Processing AppConfig CONFIG_REMOVED");
- SegmentRoutingAppConfig prevConfig = (SegmentRoutingAppConfig) event.prevConfig().get();
- deviceService.getAvailableDevices().forEach(device -> {
- revokeVRouter(device.id(), getMacAddresses(prevConfig));
- prevConfig.blackholeIPs().forEach(ipPrefix -> {
- srManager.routingRulePopulator.removeDefaultRouteBlackhole(device.id(), ipPrefix);
- });
- });
- }
-
- /**
- * Populates initial vRouter and blackhole rules.
- *
- * @param deviceId device ID
- */
- public void init(DeviceId deviceId) {
- SegmentRoutingAppConfig config =
- srManager.cfgService.getConfig(srManager.appId, SegmentRoutingAppConfig.class);
- populateVRouter(deviceId, getMacAddresses(config));
- if (config != null) {
- config.blackholeIPs().forEach(ipPrefix -> {
- srManager.routingRulePopulator.populateDefaultRouteBlackhole(deviceId, ipPrefix);
- });
- }
- }
-
- private void populateVRouter(DeviceId deviceId, Set<MacAddress> pendingAdd) {
- if (!isEdge(deviceId)) {
- return;
- }
- getVRouterFlowObjBuilders(pendingAdd).forEach(foBuilder -> {
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> log.debug("vRouterMac filter for {} populated", pendingAdd),
- (objective, error) ->
- log.warn("Failed to populate vRouterMac filter for {}: {}", pendingAdd, error));
- srManager.flowObjectiveService.filter(deviceId, foBuilder.add(context));
- });
- }
-
- private void revokeVRouter(DeviceId deviceId, Set<MacAddress> pendingRemove) {
- if (!isEdge(deviceId)) {
- return;
- }
- getVRouterFlowObjBuilders(pendingRemove).forEach(foBuilder -> {
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> log.debug("vRouterMac filter for {} revoked", pendingRemove),
- (objective, error) ->
- log.warn("Failed to revoke vRouterMac filter for {}: {}", pendingRemove, error));
- srManager.flowObjectiveService.filter(deviceId, foBuilder.remove(context));
- });
- }
-
- private Set<FilteringObjective.Builder> getVRouterFlowObjBuilders(Set<MacAddress> macAddresses) {
- ImmutableSet.Builder<FilteringObjective.Builder> setBuilder = ImmutableSet.builder();
- macAddresses.forEach(macAddress -> {
- FilteringObjective.Builder fobuilder = DefaultFilteringObjective.builder();
- fobuilder.withKey(Criteria.matchInPort(PortNumber.ANY))
- .addCondition(Criteria.matchEthDst(macAddress))
- .permit()
- .withPriority(SegmentRoutingService.DEFAULT_PRIORITY)
- .fromApp(srManager.appId);
- setBuilder.add(fobuilder);
- });
- return setBuilder.build();
- }
-
- private Set<MacAddress> getMacAddresses(SegmentRoutingAppConfig config) {
- if (config == null) {
- return ImmutableSet.of();
- }
- return ImmutableSet.copyOf(config.vRouterMacs());
- }
-
- private boolean isEdge(DeviceId deviceId) {
- try {
- if (srManager.deviceConfiguration.isEdgeDevice(deviceId)) {
- return true;
- }
- } catch (DeviceConfigNotFoundException e) {
- log.warn("Device configuration for {} is not present.", deviceId);
- }
- return false;
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/ArpHandler.java b/app/src/main/java/org/onosproject/segmentrouting/ArpHandler.java
deleted file mode 100644
index cfef0f1..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/ArpHandler.java
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright 2015-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;
-
-import org.onlab.packet.ARP;
-import org.onlab.packet.Ethernet;
-import org.onlab.packet.Ip4Address;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
-import org.onosproject.net.neighbour.NeighbourMessageContext;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.host.HostService;
-import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
-import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import static org.onosproject.net.neighbour.NeighbourMessageType.REQUEST;
-
-/**
- * Handler of ARP packets that responses or forwards ARP packets that
- * are sent to the controller.
- */
-public class ArpHandler extends SegmentRoutingNeighbourHandler {
-
- private static Logger log = LoggerFactory.getLogger(ArpHandler.class);
-
- /**
- * Creates an ArpHandler object.
- *
- * @param srManager SegmentRoutingManager object
- */
- public ArpHandler(SegmentRoutingManager srManager) {
- super(srManager);
- }
-
- /**
- * Processes incoming ARP packets.
- *
- * If it is an ARP request to router itself or known hosts,
- * then it sends ARP response.
- * If it is an ARP request to unknown hosts in its own subnet,
- * then it flood the ARP request to the ports.
- * If it is an ARP response, then set a flow rule for the host
- * and forward any IP packets to the host in the packet buffer to the host.
- * <p>
- * Note: We handles all ARP packet in, even for those ARP packets between
- * hosts in the same subnet.
- * For an ARP packet with broadcast destination MAC,
- * some switches pipelines will send it to the controller due to table miss,
- * other switches will flood the packets directly in the data plane without
- * packet in.
- * We can deal with both cases.
- *
- * @param pkt incoming ARP packet and context information
- * @param hostService the host service
- */
- public void processPacketIn(NeighbourMessageContext pkt, HostService hostService) {
-
- SegmentRoutingAppConfig appConfig = srManager.cfgService
- .getConfig(srManager.appId, SegmentRoutingAppConfig.class);
- if (appConfig != null && appConfig.suppressSubnet().contains(pkt.inPort())) {
- // Ignore ARP packets come from suppressed ports
- pkt.drop();
- return;
- }
-
- if (!validateArpSpa(pkt)) {
- log.debug("Ignore ARP packet discovered on {} with unexpected src protocol address {}.",
- pkt.inPort(), pkt.sender().getIp4Address());
- pkt.drop();
- return;
- }
-
- if (pkt.type() == REQUEST) {
- handleArpRequest(pkt, hostService);
- } else {
- handleArpReply(pkt, hostService);
- }
- }
-
- private void handleArpRequest(NeighbourMessageContext pkt, HostService hostService) {
- // ARP request for router. Send ARP reply.
- if (isArpForRouter(pkt)) {
- MacAddress targetMac = config.getRouterMacForAGatewayIp(pkt.target().getIp4Address());
- if (targetMac == null) {
- log.warn("Router MAC of {} is not configured. Cannot handle ARP request from {}",
- pkt.inPort().deviceId(), pkt.sender());
- return;
- }
- sendResponse(pkt, targetMac, hostService, true);
- } else {
- // NOTE: Ignore ARP packets except those target for the router
- // We will reconsider enabling this when we have host learning support
- /*
- Set<Host> hosts = hostService.getHostsByIp(pkt.target());
- if (hosts.size() > 1) {
- log.warn("More than one host with the same ip {}", pkt.target());
- }
- Host targetHost = hosts.stream().findFirst().orElse(null);
- // ARP request for known hosts. Send proxy ARP reply on behalf of the target.
- if (targetHost != null) {
- pkt.forward(targetHost.location());
- // ARP request for unknown host in the subnet. Flood in the subnet.
- } else {
- flood(pkt);
- }
- */
- }
- }
-
- private void handleArpReply(NeighbourMessageContext pkt, HostService hostService) {
- // ARP reply for router. Process all pending IP packets.
- if (isArpForRouter(pkt)) {
- Ip4Address hostIpAddress = pkt.sender().getIp4Address();
- srManager.ipHandler.forwardPackets(pkt.inPort().deviceId(), hostIpAddress);
- } else {
- // NOTE: Ignore ARP packets except those target for the router
- // We will reconsider enabling this when we have host learning support
- /*
- HostId targetHostId = HostId.hostId(pkt.dstMac(), pkt.vlan());
- Host targetHost = hostService.getHost(targetHostId);
- // ARP reply for known hosts. Forward to the host.
- if (targetHost != null) {
- pkt.forward(targetHost.location());
- // ARP reply for unknown host, Flood in the subnet.
- } else {
- // Don't flood to non-edge ports
- if (pkt.vlan().equals(SegmentRoutingManager.INTERNAL_VLAN)) {
- return;
- }
- flood(pkt);
- }
- */
- }
- }
-
- /**
- * Check if the source protocol address of an ARP packet belongs to the same
- * subnet configured on the port it is seen.
- *
- * @param pkt ARP packet and context information
- * @return true if the source protocol address belongs to the configured subnet
- */
- private boolean validateArpSpa(NeighbourMessageContext pkt) {
- Ip4Address spa = pkt.sender().getIp4Address();
- Set<IpPrefix> subnet = config.getPortSubnets(pkt.inPort().deviceId(), pkt.inPort().port())
- .stream()
- .filter(ipPrefix -> ipPrefix.isIp4() && ipPrefix.contains(spa))
- .collect(Collectors.toSet());
- return !subnet.isEmpty();
- }
-
-
- private boolean isArpForRouter(NeighbourMessageContext pkt) {
- Ip4Address targetProtocolAddress = pkt.target().getIp4Address();
- Set<IpAddress> gatewayIpAddresses = null;
- try {
- if (targetProtocolAddress.equals(config.getRouterIpv4(pkt.inPort().deviceId()))) {
- return true;
- }
- gatewayIpAddresses = config.getPortIPs(pkt.inPort().deviceId());
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage() + " Aborting check for router IP in processing arp");
- }
- if (gatewayIpAddresses != null &&
- gatewayIpAddresses.contains(targetProtocolAddress)) {
- return true;
- }
- return false;
- }
-
- /**
- * Sends an APR request for the target IP address to all ports except in-port.
- *
- * @param deviceId Switch device ID
- * @param targetAddress target IP address for ARP
- * @param inPort in-port
- */
- public void sendArpRequest(DeviceId deviceId, IpAddress targetAddress, ConnectPoint inPort) {
- byte[] senderMacAddress = new byte[MacAddress.MAC_ADDRESS_LENGTH];
- byte[] senderIpAddress = new byte[Ip4Address.BYTE_LENGTH];
- /*
- * Retrieves device info.
- */
- if (!getSenderInfo(senderMacAddress, senderIpAddress, deviceId, targetAddress)) {
- log.warn("Aborting sendArpRequest, we cannot get all the information needed");
- return;
- }
- /*
- * Creates the request.
- */
- Ethernet arpRequest = ARP.buildArpRequest(
- senderMacAddress,
- senderIpAddress,
- targetAddress.toOctets(),
- VlanId.NO_VID
- );
- flood(arpRequest, inPort, targetAddress);
- }
-
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java b/app/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
deleted file mode 100644
index 8b4b31c..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
+++ /dev/null
@@ -1,2222 +0,0 @@
-/*
- * Copyright 2015-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;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableMap.Builder;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-
-import org.onlab.packet.EthType;
-import com.google.common.collect.Streams;
-import org.onlab.packet.Ip4Address;
-import org.onlab.packet.Ip6Address;
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
-import org.onlab.util.PredictableExecutor;
-import org.onlab.util.PredictableExecutor.PickyCallable;
-import org.onosproject.cluster.NodeId;
-import org.onosproject.mastership.MastershipEvent;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.Device;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Link;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.flowobjective.Objective;
-import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
-import org.onosproject.segmentrouting.config.DeviceConfiguration;
-import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
-import org.onosproject.store.serializers.KryoNamespaces;
-import org.onosproject.store.service.ConsistentMultimap;
-import org.onosproject.store.service.Serializer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.time.Instant;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static java.util.concurrent.Executors.newScheduledThreadPool;
-import static org.onlab.util.Tools.groupedThreads;
-
-/**
- * Default routing handler that is responsible for route computing and
- * routing rule population.
- */
-public class DefaultRoutingHandler {
- private static final int MAX_CONSTANT_RETRY_ATTEMPTS = 5;
- private static final long RETRY_INTERVAL_MS = 250L;
- private static final int RETRY_INTERVAL_SCALE = 1;
- private static final long STABLITY_THRESHOLD = 10; //secs
- private static final long MASTER_CHANGE_DELAY = 1000; // ms
- private static final long PURGE_DELAY = 1000; // ms
- private static Logger log = LoggerFactory.getLogger(DefaultRoutingHandler.class);
-
- private SegmentRoutingManager srManager;
- private RoutingRulePopulator rulePopulator;
- private HashMap<DeviceId, EcmpShortestPathGraph> currentEcmpSpgMap;
- private HashMap<DeviceId, EcmpShortestPathGraph> updatedEcmpSpgMap;
- private DeviceConfiguration config;
- private final Lock statusLock = new ReentrantLock();
- private volatile Status populationStatus;
- private ScheduledExecutorService executorService
- = newScheduledThreadPool(1, groupedThreads("retryftr", "retry-%d", log));
- private ScheduledExecutorService executorServiceMstChg
- = newScheduledThreadPool(1, groupedThreads("masterChg", "mstch-%d", log));
- private ScheduledExecutorService executorServiceFRR
- = newScheduledThreadPool(1, groupedThreads("fullRR", "fullRR-%d", log));
- // Route populators - 0 will leverage available processors
- private static final int DEFAULT_THREADS = 0;
- private ExecutorService routePopulators;
-
- private Instant lastRoutingChange = Instant.EPOCH;
- private Instant lastFullReroute = Instant.EPOCH;
-
- // Distributed store to keep track of ONOS instance that should program the
- // device pair. There should be only one instance (the king) that programs the same pair.
- Map<Set<DeviceId>, NodeId> shouldProgram;
- Map<DeviceId, Boolean> shouldProgramCache;
-
- // Distributed routes store to keep track of the routes already seen
- // destination device is the key and target sw is the value
- ConsistentMultimap<DeviceId, DeviceId> seenBeforeRoutes;
-
- // Local store to keep track of all devices that this instance was responsible
- // for programming in the last run. Helps to determine if mastership changed
- // during a run - only relevant for programming as a result of topo change.
- Set<DeviceId> lastProgrammed;
-
- /**
- * Represents the default routing population status.
- */
- public enum Status {
- // population process is not started yet.
- IDLE,
- // population process started.
- STARTED,
- // population process was aborted due to errors, mostly for groups not found.
- ABORTED,
- // population process was finished successfully.
- SUCCEEDED
- }
-
- /**
- * Creates a DefaultRoutingHandler object.
- *
- * @param srManager SegmentRoutingManager object
- */
- DefaultRoutingHandler(SegmentRoutingManager srManager) {
- this.shouldProgram = srManager.storageService.<Set<DeviceId>, NodeId>consistentMapBuilder()
- .withName("sr-should-program")
- .withSerializer(Serializer.using(KryoNamespaces.API))
- .withRelaxedReadConsistency()
- .build().asJavaMap();
- this.seenBeforeRoutes = srManager.storageService.<DeviceId, DeviceId>consistentMultimapBuilder()
- .withName("programmed-routes")
- .withSerializer(Serializer.using(KryoNamespaces.API))
- .withRelaxedReadConsistency()
- .build();
- this.shouldProgramCache = Maps.newConcurrentMap();
- update(srManager);
- this.routePopulators = new PredictableExecutor(DEFAULT_THREADS,
- groupedThreads("onos/sr", "r-populator-%d", log));
- }
-
- /**
- * Updates a DefaultRoutingHandler object.
- *
- * @param srManager SegmentRoutingManager object
- */
- void update(SegmentRoutingManager srManager) {
- this.srManager = srManager;
- this.rulePopulator = checkNotNull(srManager.routingRulePopulator);
- this.config = checkNotNull(srManager.deviceConfiguration);
- this.populationStatus = Status.IDLE;
- this.currentEcmpSpgMap = Maps.newHashMap();
- this.lastProgrammed = Sets.newConcurrentHashSet();
- }
-
- /**
- * Returns an immutable copy of the current ECMP shortest-path graph as
- * computed by this controller instance.
- *
- * @return immutable copy of the current ECMP graph
- */
- public ImmutableMap<DeviceId, EcmpShortestPathGraph> getCurrentEmcpSpgMap() {
- Builder<DeviceId, EcmpShortestPathGraph> builder = ImmutableMap.builder();
- currentEcmpSpgMap.entrySet().forEach(entry -> {
- if (entry.getValue() != null) {
- builder.put(entry.getKey(), entry.getValue());
- }
- });
- return builder.build();
- }
-
- /**
- * Acquires the lock used when making routing changes.
- */
- public void acquireRoutingLock() {
- statusLock.lock();
- }
-
- /**
- * Releases the lock used when making routing changes.
- */
- public void releaseRoutingLock() {
- statusLock.unlock();
- }
-
- /**
- * Determines if routing in the network has been stable in the last
- * STABILITY_THRESHOLD seconds, by comparing the current time to the last
- * routing change timestamp.
- *
- * @return true if stable
- */
- public boolean isRoutingStable() {
- long last = (long) (lastRoutingChange.toEpochMilli() / 1000.0);
- long now = (long) (Instant.now().toEpochMilli() / 1000.0);
- log.trace("Routing stable since {}s", now - last);
- return (now - last) > STABLITY_THRESHOLD;
- }
-
- /**
- * Gracefully shuts down the defaultRoutingHandler. Typically called when
- * the app is deactivated
- */
- public void shutdown() {
- executorService.shutdown();
- executorServiceMstChg.shutdown();
- executorServiceFRR.shutdown();
- routePopulators.shutdown();
- }
-
- //////////////////////////////////////
- // Route path handling
- //////////////////////////////////////
-
- /* The following three methods represent the three major ways in which
- * route-path handling is triggered in the network
- * a) due to configuration change
- * b) due to route-added event
- * c) due to change in the topology
- */
-
- /**
- * Populates all routing rules to all switches. Typically triggered at
- * startup or after a configuration event.
- */
- public void populateAllRoutingRules() {
- lastRoutingChange = Instant.now();
- statusLock.lock();
- try {
- if (populationStatus == Status.STARTED) {
- log.warn("Previous rule population is not finished. Cannot"
- + " proceed with populateAllRoutingRules");
- return;
- }
-
- populationStatus = Status.STARTED;
- rulePopulator.resetCounter();
- log.info("Starting to populate all routing rules");
- log.debug("populateAllRoutingRules: populationStatus is STARTED");
-
- // take a snapshot of the topology
- updatedEcmpSpgMap = new HashMap<>();
- Set<EdgePair> edgePairs = new HashSet<>();
- Set<ArrayList<DeviceId>> routeChanges = new HashSet<>();
- for (DeviceId dstSw : srManager.deviceConfiguration.getRouters()) {
- EcmpShortestPathGraph ecmpSpgUpdated =
- new EcmpShortestPathGraph(dstSw, srManager);
- updatedEcmpSpgMap.put(dstSw, ecmpSpgUpdated);
- Optional<DeviceId> pairDev = srManager.getPairDeviceId(dstSw);
- if (pairDev.isPresent()) {
- // pairDev may not be available yet, but we still need to add
- ecmpSpgUpdated = new EcmpShortestPathGraph(pairDev.get(), srManager);
- updatedEcmpSpgMap.put(pairDev.get(), ecmpSpgUpdated);
- edgePairs.add(new EdgePair(dstSw, pairDev.get()));
- }
-
- if (!shouldProgram(dstSw)) {
- lastProgrammed.remove(dstSw);
- continue;
- } else {
- lastProgrammed.add(dstSw);
- }
- // To do a full reroute, assume all route-paths have changed
- for (DeviceId dev : deviceAndItsPair(dstSw)) {
- for (DeviceId targetSw : srManager.deviceConfiguration.getRouters()) {
- if (targetSw.equals(dev)) {
- continue;
- }
- routeChanges.add(Lists.newArrayList(targetSw, dev));
- }
- }
- }
-
- log.debug("seenBeforeRoutes size {}", seenBeforeRoutes.size());
- if (!redoRouting(routeChanges, edgePairs, null)) {
- log.debug("populateAllRoutingRules: populationStatus is ABORTED");
- populationStatus = Status.ABORTED;
- log.warn("Failed to repopulate all routing rules.");
- return;
- }
-
- log.debug("populateAllRoutingRules: populationStatus is SUCCEEDED");
- populationStatus = Status.SUCCEEDED;
- log.info("Completed all routing rule population. Total # of rules pushed : {}",
- rulePopulator.getCounter());
- return;
- } catch (Exception e) {
- log.error("populateAllRoutingRules thrown an exception: {}",
- e.getMessage(), e);
- populationStatus = Status.ABORTED;
- } finally {
- statusLock.unlock();
- }
- }
-
- /**
- * Populate rules from all other edge devices to the connect-point(s)
- * specified for the given subnets.
- *
- * @param cpts connect point(s) of the subnets being added
- * @param subnets subnets being added
- */
- // XXX refactor
- protected void populateSubnet(Set<ConnectPoint> cpts, Set<IpPrefix> subnets) {
- if (cpts == null || cpts.size() < 1 || cpts.size() > 2) {
- log.warn("Skipping populateSubnet due to illegal size of connect points. {}", cpts);
- return;
- }
-
- lastRoutingChange = Instant.now();
- statusLock.lock();
- try {
- if (populationStatus == Status.STARTED) {
- log.warn("Previous rule population is not finished. Cannot"
- + " proceed with routing rules for added routes");
- return;
- }
- populationStatus = Status.STARTED;
- rulePopulator.resetCounter();
- log.info("Starting to populate routing rules for added routes, subnets={}, cpts={}",
- subnets, cpts);
- // In principle an update to a subnet/prefix should not require a
- // new ECMPspg calculation as it is not a topology event. As a
- // result, we use the current/existing ECMPspg in the updated map
- // used by the redoRouting method.
- if (updatedEcmpSpgMap == null) {
- updatedEcmpSpgMap = new HashMap<>();
- }
- currentEcmpSpgMap.entrySet().forEach(entry -> {
- updatedEcmpSpgMap.put(entry.getKey(), entry.getValue());
- if (log.isTraceEnabled()) {
- log.trace("Root switch: {}", entry.getKey());
- log.trace(" Current/Existing SPG: {}", entry.getValue());
- }
- });
- log.debug("seenBeforeRoutes size {}", seenBeforeRoutes.size());
- Set<EdgePair> edgePairs = new HashSet<>();
- Set<ArrayList<DeviceId>> routeChanges = new HashSet<>();
- boolean handleRouting = false;
-
- if (cpts.size() == 2) {
- // ensure connect points are edge-pairs
- Iterator<ConnectPoint> iter = cpts.iterator();
- DeviceId dev1 = iter.next().deviceId();
- Optional<DeviceId> pairDev = srManager.getPairDeviceId(dev1);
- if (pairDev.isPresent() && iter.next().deviceId().equals(pairDev.get())) {
- edgePairs.add(new EdgePair(dev1, pairDev.get()));
- } else {
- log.warn("Connectpoints {} for subnets {} not on "
- + "pair-devices.. aborting populateSubnet", cpts, subnets);
- populationStatus = Status.ABORTED;
- return;
- }
- for (ConnectPoint cp : cpts) {
- if (updatedEcmpSpgMap.get(cp.deviceId()) == null) {
- EcmpShortestPathGraph ecmpSpgUpdated =
- new EcmpShortestPathGraph(cp.deviceId(), srManager);
- updatedEcmpSpgMap.put(cp.deviceId(), ecmpSpgUpdated);
- log.warn("populateSubnet: no updated graph for dev:{}"
- + " ... creating", cp.deviceId());
- }
- if (!shouldProgram(cp.deviceId())) {
- continue;
- }
- handleRouting = true;
- }
- } else {
- // single connect point
- DeviceId dstSw = cpts.iterator().next().deviceId();
- if (updatedEcmpSpgMap.get(dstSw) == null) {
- EcmpShortestPathGraph ecmpSpgUpdated =
- new EcmpShortestPathGraph(dstSw, srManager);
- updatedEcmpSpgMap.put(dstSw, ecmpSpgUpdated);
- log.warn("populateSubnet: no updated graph for dev:{}"
- + " ... creating", dstSw);
- }
- handleRouting = shouldProgram(dstSw);
- }
-
- if (!handleRouting) {
- log.debug("This instance is not handling ecmp routing to the "
- + "connectPoint(s) {}", cpts);
- populationStatus = Status.ABORTED;
- return;
- }
-
- // if it gets here, this instance should handle routing for the
- // connectpoint(s). Assume all route-paths have to be updated to
- // the connectpoint(s) with the following exceptions
- // 1. if target is non-edge no need for routing rules
- // 2. if target is one of the connectpoints
- for (ConnectPoint cp : cpts) {
- DeviceId dstSw = cp.deviceId();
- for (Device targetSw : srManager.deviceService.getDevices()) {
- boolean isEdge = false;
- try {
- isEdge = config.isEdgeDevice(targetSw.id());
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage() + "aborting populateSubnet on targetSw {}", targetSw.id());
- continue;
- }
- Optional<DeviceId> pairDev = srManager.getPairDeviceId(dstSw);
- if (dstSw.equals(targetSw.id()) || !isEdge ||
- (cpts.size() == 2 && pairDev.isPresent() && targetSw.id().equals(pairDev.get()))) {
- continue;
- }
- routeChanges.add(Lists.newArrayList(targetSw.id(), dstSw));
- }
- }
-
- if (!redoRouting(routeChanges, edgePairs, subnets)) {
- log.debug("populateSubnet: populationStatus is ABORTED");
- populationStatus = Status.ABORTED;
- log.warn("Failed to repopulate the rules for subnet.");
- return;
- }
-
- log.debug("populateSubnet: populationStatus is SUCCEEDED");
- populationStatus = Status.SUCCEEDED;
- log.info("Completed subnet population. Total # of rules pushed : {}",
- rulePopulator.getCounter());
- return;
-
- } catch (Exception e) {
- log.error("populateSubnet thrown an exception: {}",
- e.getMessage(), e);
- populationStatus = Status.ABORTED;
- } finally {
- statusLock.unlock();
- }
- }
-
- /**
- * Populates the routing rules or makes hash group changes according to the
- * route-path changes due to link failure, switch failure or link up. This
- * method should only be called for one of these three possible event-types.
- * Note that when a switch goes away, all of its links fail as well, but
- * this is handled as a single switch removal event.
- *
- * @param linkDown the single failed link, or null for other conditions such
- * as link-up or a removed switch
- * @param linkUp the single link up, or null for other conditions such as
- * link-down or a removed switch
- * @param switchDown the removed switch, or null for other conditions such
- * as link-down or link-up
- * @param seenBefore true if this event is for a linkUp or linkDown for a
- * seen link
- */
- // TODO This method should be refactored into three separated methods
- public void populateRoutingRulesForLinkStatusChange(Link linkDown, Link linkUp,
- DeviceId switchDown, boolean seenBefore) {
- if (Stream.of(linkDown, linkUp, switchDown).filter(Objects::nonNull)
- .count() != 1) {
- log.warn("Only one event can be handled for link status change .. aborting");
- return;
- }
-
- lastRoutingChange = Instant.now();
- statusLock.lock();
- try {
-
- if (populationStatus == Status.STARTED) {
- log.warn("Previous rule population is not finished. Cannot"
- + " proceeed with routingRules for Topology change");
- return;
- }
-
- // Take snapshots of the topology
- updatedEcmpSpgMap = new HashMap<>();
- Set<EdgePair> edgePairs = new HashSet<>();
- for (Device sw : srManager.deviceService.getDevices()) {
- EcmpShortestPathGraph ecmpSpgUpdated =
- new EcmpShortestPathGraph(sw.id(), srManager);
- updatedEcmpSpgMap.put(sw.id(), ecmpSpgUpdated);
- Optional<DeviceId> pairDev = srManager.getPairDeviceId(sw.id());
- if (pairDev.isPresent()) {
- // pairDev may not be available yet, but we still need to add
- ecmpSpgUpdated = new EcmpShortestPathGraph(pairDev.get(), srManager);
- updatedEcmpSpgMap.put(pairDev.get(), ecmpSpgUpdated);
- edgePairs.add(new EdgePair(sw.id(), pairDev.get()));
- }
- }
-
- log.info("Starting to populate routing rules from Topology change");
-
- Set<ArrayList<DeviceId>> routeChanges;
- log.debug("populateRoutingRulesForLinkStatusChange: "
- + "populationStatus is STARTED");
- log.debug("seenBeforeRoutes size {}", seenBeforeRoutes.size());
- populationStatus = Status.STARTED;
- rulePopulator.resetCounter(); //XXX maybe useful to have a rehash ctr
- boolean hashGroupsChanged = false;
- // try optimized re-routing
- if (linkDown == null) {
- // either a linkUp or a switchDown - compute all route changes by
- // comparing all routes of existing ECMP SPG to new ECMP SPG
- routeChanges = computeRouteChange(switchDown);
-
- // deal with linkUp
- if (linkUp != null) {
- // deal with linkUp of a seen-before link
- if (seenBefore) {
- // link previously seen before
- // do hash-bucket changes instead of a re-route
- processHashGroupChangeForLinkUp(routeChanges);
- // clear out routesChanges so a re-route is not attempted
- routeChanges = ImmutableSet.of();
- hashGroupsChanged = true;
- } else {
- // do hash-bucket changes first, method will return changed routes;
- // for each route not changed it will perform a reroute
- Set<ArrayList<DeviceId>> changedRoutes = processHashGroupChangeForLinkUp(routeChanges);
- Set<ArrayList<DeviceId>> routeChangesTemp = getExpandedRoutes(routeChanges);
- changedRoutes.forEach(routeChangesTemp::remove);
- // if routesChanges is empty a re-route is not attempted
- routeChanges = routeChangesTemp;
- for (ArrayList<DeviceId> route : routeChanges) {
- log.debug("remaining routes Target -> Root");
- if (route.size() == 1) {
- log.debug(" : all -> {}", route.get(0));
- } else {
- log.debug(" : {} -> {}", route.get(0), route.get(1));
- }
- }
- // Mark hash groups as changed
- if (!changedRoutes.isEmpty()) {
- hashGroupsChanged = true;
- }
- }
-
- }
-
- //deal with switchDown
- if (switchDown != null) {
- processHashGroupChangeForFailure(routeChanges, switchDown);
- // clear out routesChanges so a re-route is not attempted
- routeChanges = ImmutableSet.of();
- hashGroupsChanged = true;
- }
- } else {
- // link has gone down
- // Compare existing ECMP SPG only with the link that went down
- routeChanges = computeDamagedRoutes(linkDown);
- processHashGroupChangeForFailure(routeChanges, null);
- // clear out routesChanges so a re-route is not attempted
- routeChanges = ImmutableSet.of();
- hashGroupsChanged = true;
- }
-
- if (routeChanges.isEmpty()) {
- if (hashGroupsChanged) {
- log.info("Hash-groups changed for link status change");
- } else {
- log.info("No re-route or re-hash attempted for the link"
- + " status change");
- updatedEcmpSpgMap.keySet().forEach(devId -> {
- currentEcmpSpgMap.put(devId, updatedEcmpSpgMap.get(devId));
- log.debug("Updating ECMPspg for remaining dev:{}", devId);
- });
- }
- log.debug("populateRoutingRulesForLinkStatusChange: populationStatus is SUCCEEDED");
- populationStatus = Status.SUCCEEDED;
- return;
- }
-
- if (hashGroupsChanged) {
- log.debug("Hash-groups changed for link status change");
- }
-
- // reroute of routeChanges
- if (redoRouting(routeChanges, edgePairs, null)) {
- log.debug("populateRoutingRulesForLinkStatusChange: populationStatus is SUCCEEDED");
- populationStatus = Status.SUCCEEDED;
- log.info("Completed repopulation of rules for link-status change."
- + " # of rules populated : {}", rulePopulator.getCounter());
- return;
- } else {
- log.debug("populateRoutingRulesForLinkStatusChange: populationStatus is ABORTED");
- populationStatus = Status.ABORTED;
- log.warn("Failed to repopulate the rules for link status change.");
- return;
- }
- } catch (Exception e) {
- log.error("populateRoutingRulesForLinkStatusChange thrown an exception: {}",
- e.getMessage(), e);
- populationStatus = Status.ABORTED;
- } finally {
- statusLock.unlock();
- }
- }
-
- /**
- * Processes a set a route-path changes by reprogramming routing rules and
- * creating new hash-groups or editing them if necessary. This method also
- * determines the next-hops for the route-path from the src-switch (target)
- * of the path towards the dst-switch of the path.
- *
- * @param routeChanges a set of route-path changes, where each route-path is
- * a list with its first element the src-switch (target)
- * of the path, and the second element the dst-switch of
- * the path.
- * @param edgePairs a set of edge-switches that are paired by configuration
- * @param subnets a set of prefixes that need to be populated in the routing
- * table of the target switch in the route-path. Can be null,
- * in which case all the prefixes belonging to the dst-switch
- * will be populated in the target switch
- * @return true if successful in repopulating all routes
- */
- private boolean redoRouting(Set<ArrayList<DeviceId>> routeChanges,
- Set<EdgePair> edgePairs, Set<IpPrefix> subnets) {
- // first make every entry two-elements
- Set<ArrayList<DeviceId>> changedRoutes = getExpandedRoutes(routeChanges);
- // no valid routes - fail fast
- if (changedRoutes.isEmpty()) {
- return false;
- }
-
- // Temporary stores the changed routes
- Set<ArrayList<DeviceId>> tempRoutes = ImmutableSet.copyOf(changedRoutes);
- // now process changedRoutes according to edgePairs
- if (!redoRoutingEdgePairs(edgePairs, subnets, changedRoutes)) {
- return false; //abort routing and fail fast
- }
- // Calculate the programmed routes pointing to the pairs
- Set<ArrayList<DeviceId>> programmedPairRoutes = Sets.difference(tempRoutes, changedRoutes);
- log.debug("Evaluating programmed pair routes");
- storeSeenBeforeRoutes(programmedPairRoutes);
-
- // Temporary stores the left routes
- tempRoutes = ImmutableSet.copyOf(changedRoutes);
- // whatever is left in changedRoutes is now processed for individual dsts.
- Set<DeviceId> updatedDevices = Sets.newHashSet();
- if (!redoRoutingIndividualDests(subnets, changedRoutes,
- updatedDevices)) {
- return false; //abort routing and fail fast
- }
- // Calculate the individual programmed routes
- Set<ArrayList<DeviceId>> programmedIndividualRoutes = Sets.difference(tempRoutes, changedRoutes);
- log.debug("Evaluating individual programmed routes");
- storeSeenBeforeRoutes(programmedIndividualRoutes);
-
- // update ecmpSPG for all edge-pairs
- for (EdgePair ep : edgePairs) {
- currentEcmpSpgMap.put(ep.dev1, updatedEcmpSpgMap.get(ep.dev1));
- currentEcmpSpgMap.put(ep.dev2, updatedEcmpSpgMap.get(ep.dev2));
- log.debug("Updating ECMPspg for edge-pair:{}-{}", ep.dev1, ep.dev2);
- }
-
- // here is where we update all devices not touched by this instance
- updatedEcmpSpgMap.keySet().stream()
- .filter(devId -> !edgePairs.stream().anyMatch(ep -> ep.includes(devId)))
- .filter(devId -> !updatedDevices.contains(devId))
- .forEach(devId -> {
- currentEcmpSpgMap.put(devId, updatedEcmpSpgMap.get(devId));
- log.debug("Updating ECMPspg for remaining dev:{}", devId);
- });
- return true;
- }
-
- /**
- * Stores the routes seen before. Routes are two-elements arrays.
- * @param seenRoutes seen before routes
- */
- private void storeSeenBeforeRoutes(Set<ArrayList<DeviceId>> seenRoutes) {
- Set<DeviceId> nextHops;
- for (ArrayList<DeviceId> route : seenRoutes) {
- log.debug("Route {} -> {} has been programmed", route.get(0), route.get(1));
- nextHops = getNextHops(route.get(0), route.get(1));
- // No valid next hops - cannot be considered a programmed route
- if (nextHops.isEmpty()) {
- log.debug("Could not find next hop from target:{} --> dst {} "
- + "skipping this route", route.get(0), route.get(1));
- continue;
- }
- // Already present - do not add again
- if (seenBeforeRoutes.containsEntry(route.get(1), route.get(0))) {
- log.debug("Route from target:{} --> dst {} " +
- "already present, skipping this route", route.get(0), route.get(1));
- continue;
- }
- seenBeforeRoutes.put(route.get(1), route.get(0));
- }
- }
-
- /**
- * Programs targetSw in the changedRoutes for given prefixes reachable by
- * an edgePair. If no prefixes are given, the method will use configured
- * subnets/prefixes. If some configured subnets belong only to a specific
- * destination in the edgePair, then the target switch will be programmed
- * only to that destination.
- *
- * @param edgePairs set of edge-pairs for which target will be programmed
- * @param subnets a set of prefixes that need to be populated in the routing
- * table of the target switch in the changedRoutes. Can be null,
- * in which case all the configured prefixes belonging to the
- * paired switches will be populated in the target switch
- * @param changedRoutes a set of route-path changes, where each route-path is
- * a list with its first element the src-switch (target)
- * of the path, and the second element the dst-switch of
- * the path.
- * @return true if successful
- */
- private boolean redoRoutingEdgePairs(Set<EdgePair> edgePairs, Set<IpPrefix> subnets,
- Set<ArrayList<DeviceId>> changedRoutes) {
- for (EdgePair ep : edgePairs) {
- // temp store for a target's changedRoutes to this edge-pair
- Map<DeviceId, Set<ArrayList<DeviceId>>> targetRoutes = new HashMap<>();
- Iterator<ArrayList<DeviceId>> i = changedRoutes.iterator();
- while (i.hasNext()) {
- ArrayList<DeviceId> route = i.next();
- DeviceId dstSw = route.get(1);
- if (ep.includes(dstSw)) {
- // routeChange for edge pair found
- // sort by target iff target is edge and remove from changedRoutes
- DeviceId targetSw = route.get(0);
- try {
- if (!srManager.deviceConfiguration.isEdgeDevice(targetSw)) {
- continue;
- }
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage() + "aborting redoRouting");
- return false;
- }
- // route is from another edge to this edge-pair
- if (targetRoutes.containsKey(targetSw)) {
- targetRoutes.get(targetSw).add(route);
- } else {
- Set<ArrayList<DeviceId>> temp = new HashSet<>();
- temp.add(route);
- targetRoutes.put(targetSw, temp);
- }
- i.remove();
- }
- }
- // so now for this edgepair we have a per target set of routechanges
- // process target->edgePair route
- List<Future<Boolean>> futures = Lists.newArrayList();
- for (Entry<DeviceId, Set<ArrayList<DeviceId>>> entry :
- targetRoutes.entrySet()) {
- log.debug("* redoRoutingDstPair Target:{} -> edge-pair {}",
- entry.getKey(), ep);
- futures.add(routePopulators.submit(new RedoRoutingEdgePair(entry.getKey(), entry.getValue(),
- subnets, ep)));
- }
- if (!checkJobs(futures)) {
- return false;
- }
- // if it gets here it has succeeded for all targets to this edge-pair
- }
- return true;
- }
-
- private final class RedoRoutingEdgePair implements PickyCallable<Boolean> {
- private DeviceId targetSw;
- private Set<ArrayList<DeviceId>> routes;
- private Set<IpPrefix> subnets;
- private EdgePair ep;
-
- /**
- * Builds a RedoRoutingEdgePair task which provides a result.
- *
- * @param targetSw the target switch
- * @param routes the changed routes
- * @param subnets the subnets
- * @param ep the edge pair
- */
- RedoRoutingEdgePair(DeviceId targetSw, Set<ArrayList<DeviceId>> routes,
- Set<IpPrefix> subnets, EdgePair ep) {
- this.targetSw = targetSw;
- this.routes = routes;
- this.subnets = subnets;
- this.ep = ep;
- }
-
- @Override
- public Boolean call() throws Exception {
- return redoRoutingEdgePair();
- }
-
- @Override
- public int hint() {
- return targetSw.hashCode();
- }
-
- private boolean redoRoutingEdgePair() {
- Map<DeviceId, Set<DeviceId>> perDstNextHops = new HashMap<>();
- routes.forEach(route -> {
- Set<DeviceId> nhops = getNextHops(route.get(0), route.get(1));
- log.debug("route: target {} -> dst {} found with next-hops {}",
- route.get(0), route.get(1), nhops);
- perDstNextHops.put(route.get(1), nhops);
- });
-
- List<Set<IpPrefix>> batchedSubnetDev1, batchedSubnetDev2;
- if (subnets != null) {
- batchedSubnetDev1 = Lists.<Set<IpPrefix>>newArrayList(Sets.newHashSet(subnets));
- batchedSubnetDev2 = Lists.<Set<IpPrefix>>newArrayList(Sets.newHashSet(subnets));
- } else {
- batchedSubnetDev1 = config.getBatchedSubnets(ep.dev1);
- batchedSubnetDev2 = config.getBatchedSubnets(ep.dev2);
- }
- List<Set<IpPrefix>> batchedSubnetBoth = Streams
- .zip(batchedSubnetDev1.stream(), batchedSubnetDev2.stream(), (a, b) -> Sets.intersection(a, b))
- .filter(set -> !set.isEmpty())
- .collect(Collectors.toList());
- List<Set<IpPrefix>> batchedSubnetDev1Only = Streams
- .zip(batchedSubnetDev1.stream(), batchedSubnetDev2.stream(), (a, b) -> Sets.difference(a, b))
- .filter(set -> !set.isEmpty())
- .collect(Collectors.toList());
- List<Set<IpPrefix>> batchedSubnetDev2Only = Streams
- .zip(batchedSubnetDev1.stream(), batchedSubnetDev2.stream(), (a, b) -> Sets.difference(b, a))
- .filter(set -> !set.isEmpty())
- .collect(Collectors.toList());
-
- Set<DeviceId> nhDev1 = perDstNextHops.get(ep.dev1);
- Set<DeviceId> nhDev2 = perDstNextHops.get(ep.dev2);
-
- // handle routing to subnets common to edge-pair
- // only if the targetSw is not part of the edge-pair and there
- // exists a next hop to at least one of the devices in the edge-pair
- if (!ep.includes(targetSw)
- && ((nhDev1 != null && !nhDev1.isEmpty()) || (nhDev2 != null && !nhDev2.isEmpty()))) {
- log.trace("getSubnets on both {} and {}: {}", ep.dev1, ep.dev2, batchedSubnetBoth);
- for (Set<IpPrefix> prefixes : batchedSubnetBoth) {
- if (!populateEcmpRoutingRulePartial(targetSw, ep.dev1, ep.dev2,
- perDstNextHops, prefixes)) {
- return false; // abort everything and fail fast
- }
- }
-
- }
- // handle routing to subnets that only belong to dev1 only if
- // a next-hop exists from the target to dev1
- if (!batchedSubnetDev1Only.isEmpty() &&
- batchedSubnetDev1Only.stream().anyMatch(subnet -> !subnet.isEmpty()) &&
- nhDev1 != null && !nhDev1.isEmpty()) {
- Map<DeviceId, Set<DeviceId>> onlyDev1NextHops = new HashMap<>();
- onlyDev1NextHops.put(ep.dev1, nhDev1);
- log.trace("getSubnets on {} only: {}", ep.dev1, batchedSubnetDev1Only);
- for (Set<IpPrefix> prefixes : batchedSubnetDev1Only) {
- if (!populateEcmpRoutingRulePartial(targetSw, ep.dev1, null,
- onlyDev1NextHops, prefixes)) {
- return false; // abort everything and fail fast
- }
- }
- }
- // handle routing to subnets that only belong to dev2 only if
- // a next-hop exists from the target to dev2
- if (!batchedSubnetDev2Only.isEmpty() &&
- batchedSubnetDev2Only.stream().anyMatch(subnet -> !subnet.isEmpty()) &&
- nhDev2 != null && !nhDev2.isEmpty()) {
- Map<DeviceId, Set<DeviceId>> onlyDev2NextHops = new HashMap<>();
- onlyDev2NextHops.put(ep.dev2, nhDev2);
- log.trace("getSubnets on {} only: {}", ep.dev2, batchedSubnetDev2Only);
- for (Set<IpPrefix> prefixes : batchedSubnetDev2Only) {
- if (!populateEcmpRoutingRulePartial(targetSw, ep.dev2, null,
- onlyDev2NextHops, prefixes)) {
- return false; // abort everything and fail fast
- }
- }
- }
- return true;
- }
- }
-
- /**
- * Programs targetSw in the changedRoutes for given prefixes reachable by
- * a destination switch that is not part of an edge-pair.
- * If no prefixes are given, the method will use configured subnets/prefixes.
- *
- * @param subnets a set of prefixes that need to be populated in the routing
- * table of the target switch in the changedRoutes. Can be null,
- * in which case all the configured prefixes belonging to the
- * paired switches will be populated in the target switch
- * @param changedRoutes a set of route-path changes, where each route-path is
- * a list with its first element the src-switch (target)
- * of the path, and the second element the dst-switch of
- * the path.
- * @return true if successful
- */
- private boolean redoRoutingIndividualDests(Set<IpPrefix> subnets, Set<ArrayList<DeviceId>> changedRoutes,
- Set<DeviceId> updatedDevices) {
- // aggregate route-path changes for each dst device
- HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> routesBydevice =
- new HashMap<>();
- for (ArrayList<DeviceId> route: changedRoutes) {
- DeviceId dstSw = route.get(1);
- ArrayList<ArrayList<DeviceId>> deviceRoutes =
- routesBydevice.get(dstSw);
- if (deviceRoutes == null) {
- deviceRoutes = new ArrayList<>();
- routesBydevice.put(dstSw, deviceRoutes);
- }
- deviceRoutes.add(route);
- }
- // iterate over the impacted devices
- for (DeviceId impactedDstDevice : routesBydevice.keySet()) {
- ArrayList<ArrayList<DeviceId>> deviceRoutes =
- routesBydevice.get(impactedDstDevice);
- List<Future<Boolean>> futures = Lists.newArrayList();
- for (ArrayList<DeviceId> route: deviceRoutes) {
- log.debug("* redoRoutingIndiDst Target: {} -> dst: {}",
- route.get(0), route.get(1));
- futures.add(routePopulators.submit(new RedoRoutingIndividualDest(subnets, route)));
- changedRoutes.remove(route);
- }
- // check the execution of each job
- if (!checkJobs(futures)) {
- return false;
- }
- //Only if all the flows for all impacted routes to a
- //specific target are pushed successfully, update the
- //ECMP graph for that target. Or else the next event
- //would not see any changes in the ECMP graphs.
- //In another case, the target switch has gone away, so
- //routes can't be installed. In that case, the current map
- //is updated here, without any flows being pushed.
- currentEcmpSpgMap.put(impactedDstDevice,
- updatedEcmpSpgMap.get(impactedDstDevice));
- updatedDevices.add(impactedDstDevice);
- log.debug("Updating ECMPspg for impacted dev:{}", impactedDstDevice);
- }
- return true;
- }
-
- private final class RedoRoutingIndividualDest implements PickyCallable<Boolean> {
- private DeviceId targetSw;
- private ArrayList<DeviceId> route;
- private Set<IpPrefix> subnets;
-
- /**
- * Builds a RedoRoutingIndividualDest task, which provides a result.
- *
- * @param subnets a set of prefixes
- * @param route a route-path change
- */
- RedoRoutingIndividualDest(Set<IpPrefix> subnets, ArrayList<DeviceId> route) {
- this.targetSw = route.get(0);
- this.route = route;
- this.subnets = subnets;
- }
-
- @Override
- public Boolean call() throws Exception {
- DeviceId dstSw = route.get(1); // same as impactedDstDevice
- Set<DeviceId> nextHops = getNextHops(targetSw, dstSw);
- if (nextHops.isEmpty()) {
- log.debug("Could not find next hop from target:{} --> dst {} "
- + "skipping this route", targetSw, dstSw);
- return true;
- }
- Map<DeviceId, Set<DeviceId>> nhops = new HashMap<>();
- nhops.put(dstSw, nextHops);
- if (!populateEcmpRoutingRulePartial(targetSw, dstSw, null, nhops,
- (subnets == null) ? Sets.newHashSet() : subnets)) {
- return false; // abort routing and fail fast
- }
- log.debug("Populating flow rules from target: {} to dst: {}"
- + " is successful", targetSw, dstSw);
- return true;
- }
-
- @Override
- public int hint() {
- return targetSw.hashCode();
- }
- }
-
- /**
- * Populate ECMP rules for subnets from target to destination via nexthops.
- *
- * @param targetSw Device ID of target switch in which rules will be programmed
- * @param destSw1 Device ID of final destination switch to which the rules will forward
- * @param destSw2 Device ID of paired destination switch to which the rules will forward
- * A null deviceId indicates packets should only be sent to destSw1
- * @param nextHops Map of a set of next hops per destSw
- * @param subnets Subnets to be populated. If empty, populate all configured subnets.
- * @return true if it succeeds in populating rules
- */ // refactor
- private boolean populateEcmpRoutingRulePartial(DeviceId targetSw, DeviceId destSw1, DeviceId destSw2,
- Map<DeviceId, Set<DeviceId>> nextHops, Set<IpPrefix> subnets) {
- boolean result;
- // If both target switch and dest switch are edge routers, then set IP
- // rule for both subnet and router IP.
- boolean targetIsEdge;
- boolean dest1IsEdge;
- Ip4Address dest1RouterIpv4, dest2RouterIpv4 = null;
- Ip6Address dest1RouterIpv6, dest2RouterIpv6 = null;
-
- try {
- targetIsEdge = config.isEdgeDevice(targetSw);
- dest1IsEdge = config.isEdgeDevice(destSw1);
- dest1RouterIpv4 = config.getRouterIpv4(destSw1);
- dest1RouterIpv6 = config.getRouterIpv6(destSw1);
- if (destSw2 != null) {
- dest2RouterIpv4 = config.getRouterIpv4(destSw2);
- dest2RouterIpv6 = config.getRouterIpv6(destSw2);
- }
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage() + " Aborting populateEcmpRoutingRulePartial.");
- return false;
- }
-
- if (targetIsEdge && dest1IsEdge) {
- List<Set<IpPrefix>> batchedSubnets;
- if (subnets != null && !subnets.isEmpty()) {
- batchedSubnets = Lists.<Set<IpPrefix>>newArrayList(Sets.newHashSet(subnets));
- } else {
- batchedSubnets = config.getBatchedSubnets(destSw1);
- }
- // XXX - Rethink this - ignoring routerIPs in all other switches
- // even edge to edge switches
- /*subnets.add(dest1RouterIpv4.toIpPrefix());
- if (dest1RouterIpv6 != null) {
- subnets.add(dest1RouterIpv6.toIpPrefix());
- }
- if (destSw2 != null && dest2RouterIpv4 != null) {
- subnets.add(dest2RouterIpv4.toIpPrefix());
- if (dest2RouterIpv6 != null) {
- subnets.add(dest2RouterIpv6.toIpPrefix());
- }
- }*/
- log.trace("getSubnets on {}: {}", destSw1, batchedSubnets);
- for (Set<IpPrefix> prefixes : batchedSubnets) {
- log.debug(". populateEcmpRoutingRulePartial in device {} towards {} {} "
- + "for subnets {}", targetSw, destSw1,
- (destSw2 != null) ? ("& " + destSw2) : "",
- prefixes);
- if (!rulePopulator.populateIpRuleForSubnet(targetSw, prefixes, destSw1, destSw2, nextHops)) {
- return false;
- }
- }
- }
-
- if (!targetIsEdge && dest1IsEdge) {
- // MPLS rules in all non-edge target devices. These rules are for
- // individual destinations, even if the dsts are part of edge-pairs.
- log.debug(". populateEcmpRoutingRulePartial in device{} towards {} for "
- + "all MPLS rules", targetSw, destSw1);
- result = rulePopulator.populateMplsRule(targetSw, destSw1, nextHops.get(destSw1), dest1RouterIpv4);
- if (!result) {
- return false;
- }
- if (dest1RouterIpv6 != null) {
- int v4sid = 0, v6sid = 0;
- try {
- v4sid = config.getIPv4SegmentId(destSw1);
- v6sid = config.getIPv6SegmentId(destSw1);
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage());
- }
- if (v4sid != v6sid) {
- result = rulePopulator.populateMplsRule(targetSw, destSw1, nextHops.get(destSw1),
- dest1RouterIpv6);
- if (!result) {
- return false;
- }
- }
- }
- }
-
- if (!targetIsEdge && !dest1IsEdge) {
- // MPLS rules for inter-connected spines
- // can be merged with above if, left it here for clarity
- log.debug(". populateEcmpRoutingRulePartial in device{} towards {} for "
- + "all MPLS rules", targetSw, destSw1);
-
- result = rulePopulator.populateMplsRule(targetSw, destSw1, nextHops.get(destSw1), dest1RouterIpv4);
- if (!result) {
- return false;
- }
-
- if (dest1RouterIpv6 != null) {
- int v4sid = 0, v6sid = 0;
- try {
- v4sid = config.getIPv4SegmentId(destSw1);
- v6sid = config.getIPv6SegmentId(destSw1);
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage());
- }
- if (v4sid != v6sid) {
- result = rulePopulator.populateMplsRule(targetSw, destSw1, nextHops.get(destSw1),
- dest1RouterIpv6);
- if (!result) {
- return false;
- }
- }
- }
- }
-
- // To save on ECMP groups
- // avoid MPLS rules in non-edge-devices to non-edge-devices
- // avoid MPLS transit rules in edge-devices
- // avoid loopback IP rules in edge-devices to non-edge-devices
- return true;
- }
-
- /**
- * Processes a set a route-path changes due to a switch/link failure by editing hash groups.
- *
- * @param routeChanges a set of route-path changes, where each route-path is
- * a list with its first element the src-switch of the path
- * and the second element the dst-switch of the path.
- * @param failedSwitch the switchId if the route changes are for a failed switch,
- * otherwise null
- */
- private void processHashGroupChangeForFailure(Set<ArrayList<DeviceId>> routeChanges,
- DeviceId failedSwitch) {
- // first, ensure each routeChanges entry has two elements
- Set<ArrayList<DeviceId>> changedRoutes = getAllExpandedRoutes(routeChanges);
- boolean someFailed = false;
- boolean success;
- Set<DeviceId> updatedDevices = Sets.newHashSet();
- for (ArrayList<DeviceId> route : changedRoutes) {
- DeviceId targetSw = route.get(0);
- DeviceId dstSw = route.get(1);
- success = fixHashGroupsForRoute(route, true);
- // it's possible that we cannot fix hash groups for a route
- // if the target switch has failed. Nevertheless the ecmp graph
- // for the impacted switch must still be updated.
- if (!success && failedSwitch != null && targetSw.equals(failedSwitch)) {
- currentEcmpSpgMap.put(dstSw, updatedEcmpSpgMap.get(dstSw));
- currentEcmpSpgMap.remove(targetSw);
- log.debug("Updating ECMPspg for dst:{} removing failed switch "
- + "target:{}", dstSw, targetSw);
- updatedDevices.add(targetSw);
- updatedDevices.add(dstSw);
- continue;
-
- }
- //linkfailed - update both sides
- if (success) {
- currentEcmpSpgMap.put(targetSw, updatedEcmpSpgMap.get(targetSw));
- currentEcmpSpgMap.put(dstSw, updatedEcmpSpgMap.get(dstSw));
- log.debug("Updating ECMPspg for dst:{} and target:{} for linkdown"
- + " or switchdown", dstSw, targetSw);
- updatedDevices.add(targetSw);
- updatedDevices.add(dstSw);
- } else {
- someFailed = true;
- }
- }
- if (!someFailed) {
- // here is where we update all devices not touched by this instance
- updatedEcmpSpgMap.keySet().stream()
- .filter(devId -> !updatedDevices.contains(devId))
- .forEach(devId -> {
- currentEcmpSpgMap.put(devId, updatedEcmpSpgMap.get(devId));
- log.debug("Updating ECMPspg for remaining dev:{}", devId);
- });
- }
- }
-
- /**
- * Processes a set a route-path changes due to link up by editing hash groups.
- *
- * @param routeChanges a set of route-path changes, where each route-path is
- * a list with its first element the src-switch of the path
- * and the second element the dst-switch of the path.
- * @return set of changed routes
- */
- private Set<ArrayList<DeviceId>> processHashGroupChangeForLinkUp(Set<ArrayList<DeviceId>> routeChanges) {
- // Stores changed routes
- Set<ArrayList<DeviceId>> doneRoutes = new HashSet<>();
- // first, ensure each routeChanges entry has two elements
- Set<ArrayList<DeviceId>> changedRoutes = getAllExpandedRoutes(routeChanges);
- boolean someFailed = false;
- boolean success;
- Set<DeviceId> updatedDevices = Sets.newHashSet();
- for (ArrayList<DeviceId> route : changedRoutes) {
- DeviceId targetSw = route.get(0);
- DeviceId dstSw = route.get(1);
- // linkup - fix (if possible)
- success = fixHashGroupsForRoute(route, false);
- if (success) {
- currentEcmpSpgMap.put(targetSw, updatedEcmpSpgMap.get(targetSw));
- currentEcmpSpgMap.put(dstSw, updatedEcmpSpgMap.get(dstSw));
- log.debug("Updating ECMPspg for target:{} and dst:{} for linkup",
- targetSw, dstSw);
- updatedDevices.add(targetSw);
- updatedDevices.add(dstSw);
- doneRoutes.add(route);
- } else {
- someFailed = true;
- }
-
- }
- if (!someFailed) {
- // here is where we update all devices not touched by this instance
- updatedEcmpSpgMap.keySet().stream()
- .filter(devId -> !updatedDevices.contains(devId))
- .forEach(devId -> {
- currentEcmpSpgMap.put(devId, updatedEcmpSpgMap.get(devId));
- log.debug("Updating ECMPspg for remaining dev:{}", devId);
- });
- }
- return doneRoutes;
- }
-
- /**
- * Edits hash groups in the src-switch (targetSw) of a route-path by
- * calling the groupHandler to either add or remove buckets in an existing
- * hash group.
- *
- * @param route a single list representing a route-path where the first element
- * is the src-switch (targetSw) of the route-path and the
- * second element is the dst-switch
- * @param revoke true if buckets in the hash-groups need to be removed;
- * false if buckets in the hash-groups need to be added
- * @return true if the hash group editing is successful
- */
- private boolean fixHashGroupsForRoute(ArrayList<DeviceId> route,
- boolean revoke) {
- DeviceId targetSw = route.get(0);
- if (route.size() < 2) {
- log.warn("Cannot fixHashGroupsForRoute - no dstSw in route {}", route);
- return false;
- }
- DeviceId destSw = route.get(1);
- if (!seenBeforeRoutes.containsEntry(destSw, targetSw)) {
- log.warn("Cannot fixHashGroupsForRoute {} -> {} has not been programmed before",
- targetSw, destSw);
- return false;
- }
- log.debug("* processing fixHashGroupsForRoute: Target {} -> Dest {}",
- targetSw, destSw);
- // figure out the new next hops at the targetSw towards the destSw
- Set<DeviceId> nextHops = getNextHops(targetSw, destSw);
- // call group handler to change hash group at targetSw
- DefaultGroupHandler grpHandler = srManager.getGroupHandler(targetSw);
- if (grpHandler == null) {
- log.warn("Cannot find grouphandler for dev:{} .. aborting"
- + " {} hash group buckets for route:{} ", targetSw,
- (revoke) ? "revoke" : "repopulate", route);
- return false;
- }
- log.debug("{} hash-groups buckets For Route {} -> {} to new next-hops {}",
- (revoke) ? "revoke" : "repopulating",
- targetSw, destSw, nextHops);
- return (revoke) ? grpHandler.fixHashGroups(targetSw, nextHops,
- destSw, true)
- : grpHandler.fixHashGroups(targetSw, nextHops,
- destSw, false);
- }
-
- /**
- * Start the flow rule population process if it was never started. The
- * process finishes successfully when all flow rules are set and stops with
- * ABORTED status when any groups required for flows is not set yet.
- */
- public void startPopulationProcess() {
- statusLock.lock();
- try {
- if (populationStatus == Status.IDLE
- || populationStatus == Status.SUCCEEDED
- || populationStatus == Status.ABORTED) {
- populateAllRoutingRules();
- } else {
- log.warn("Not initiating startPopulationProcess as populationStatus is {}",
- populationStatus);
- }
- } finally {
- statusLock.unlock();
- }
- }
-
- /**
- * Revoke rules of given subnet in all edge switches.
- *
- * @param subnets subnet being removed
- * @return true if succeed
- */
- protected boolean revokeSubnet(Set<IpPrefix> subnets) {
- DeviceId targetSw;
- List<Future<Boolean>> futures = Lists.newArrayList();
- for (Device sw : srManager.deviceService.getAvailableDevices()) {
- targetSw = sw.id();
- if (shouldProgram(targetSw)) {
- futures.add(routePopulators.submit(new RevokeSubnet(targetSw, subnets)));
- } else {
- futures.add(CompletableFuture.completedFuture(true));
- }
- }
- // check the execution of each job
- return checkJobs(futures);
- }
-
- /**
- * Revoke rules of given subnets in the given switches.
- *
- * @param targetSwitches switched from which subnets to be removed
- * @param subnets subnet bring removed
- * @return true if succeed
- */
- protected boolean revokeSubnet(Set<DeviceId> targetSwitches, Set<IpPrefix> subnets) {
- List<Future<Boolean>> futures = Lists.newArrayList();
- for (DeviceId targetSw : targetSwitches) {
- if (shouldProgram(targetSw)) {
- futures.add(routePopulators.submit(new RevokeSubnet(targetSw, subnets)));
- } else {
- futures.add(CompletableFuture.completedFuture(true));
- }
- }
- // check the execution of each job
- return checkJobs(futures);
- }
-
- private final class RevokeSubnet implements PickyCallable<Boolean> {
- private DeviceId targetSw;
- private Set<IpPrefix> subnets;
-
- /**
- * Builds a RevokeSubnet task, which provides a result.
- *
- * @param subnets a set of prefixes
- * @param targetSw target switch
- */
- RevokeSubnet(DeviceId targetSw, Set<IpPrefix> subnets) {
- this.targetSw = targetSw;
- this.subnets = subnets;
- }
-
- @Override
- public Boolean call() throws Exception {
- return srManager.routingRulePopulator.revokeIpRuleForSubnet(targetSw, subnets);
- }
-
- @Override
- public int hint() {
- return targetSw.hashCode();
- }
- }
-
- /**
- * Populates IP rules for a route that has direct connection to the switch
- * if the current instance is the master of the switch.
- *
- * @param deviceId device ID of the device that next hop attaches to
- * @param prefix IP prefix of the route
- * @param hostMac MAC address of the next hop
- * @param hostVlanId Vlan ID of the nexthop
- * @param outPort port where the next hop attaches to
- * @param directHost host is of type direct or indirect
- * @return future that includes the flow objective if succeeded, null if otherwise
- */
- CompletableFuture<Objective> populateRoute(DeviceId deviceId, IpPrefix prefix, MacAddress hostMac,
- VlanId hostVlanId, PortNumber outPort, boolean directHost) {
- if (shouldProgram(deviceId)) {
- return srManager.routingRulePopulator.populateRoute(deviceId, prefix,
- hostMac, hostVlanId, outPort, directHost);
- }
- return CompletableFuture.completedFuture(null);
- }
-
- /**
- * Removes IP rules for a route when the next hop is gone.
- * if the current instance is the master of the switch.
- *
- * @param deviceId device ID of the device that next hop attaches to
- * @param prefix IP prefix of the route
- * @param hostMac MAC address of the next hop
- * @param hostVlanId Vlan ID of the nexthop
- * @param outPort port that next hop attaches to
- * @param directHost host is of type direct or indirect
- * @return future that carries the flow objective if succeeded, null if otherwise
- */
- CompletableFuture<Objective> revokeRoute(DeviceId deviceId, IpPrefix prefix,
- MacAddress hostMac, VlanId hostVlanId, PortNumber outPort, boolean directHost) {
- if (shouldProgram(deviceId)) {
- return srManager.routingRulePopulator.revokeRoute(deviceId, prefix, hostMac, hostVlanId,
- outPort, directHost);
- }
- return CompletableFuture.completedFuture(null);
- }
-
- CompletableFuture<Objective> populateBridging(DeviceId deviceId, PortNumber port, MacAddress mac, VlanId vlanId) {
- if (shouldProgram(deviceId)) {
- return srManager.routingRulePopulator.populateBridging(deviceId, port, mac, vlanId);
- }
- return CompletableFuture.completedFuture(null);
- }
-
- CompletableFuture<Objective> revokeBridging(DeviceId deviceId, PortNumber port, MacAddress mac, VlanId vlanId) {
- if (shouldProgram(deviceId)) {
- return srManager.routingRulePopulator.revokeBridging(deviceId, port, mac, vlanId);
- }
- return CompletableFuture.completedFuture(null);
- }
-
- void updateBridging(DeviceId deviceId, PortNumber portNum, MacAddress hostMac,
- VlanId vlanId, boolean popVlan, boolean install) {
- if (shouldProgram(deviceId)) {
- srManager.routingRulePopulator.updateBridging(deviceId, portNum, hostMac, vlanId, popVlan, install);
- }
- }
-
- void updateFwdObj(DeviceId deviceId, PortNumber portNumber, IpPrefix prefix, MacAddress hostMac,
- VlanId vlanId, boolean popVlan, boolean install) {
- if (shouldProgram(deviceId)) {
- srManager.routingRulePopulator.updateFwdObj(deviceId, portNumber, prefix, hostMac,
- vlanId, popVlan, install);
- }
- }
-
- /**
- * Populates IP rules for a route when the next hop is double-tagged.
- *
- * @param deviceId device ID that next hop attaches to
- * @param prefix IP prefix of the route
- * @param hostMac MAC address of the next hop
- * @param innerVlan Inner Vlan ID of the next hop
- * @param outerVlan Outer Vlan ID of the next hop
- * @param outerTpid Outer TPID of the next hop
- * @param outPort port that the next hop attaches to
- */
- void populateDoubleTaggedRoute(DeviceId deviceId, IpPrefix prefix, MacAddress hostMac, VlanId innerVlan,
- VlanId outerVlan, EthType outerTpid, PortNumber outPort) {
- if (srManager.mastershipService.isLocalMaster(deviceId)) {
- srManager.routingRulePopulator.populateDoubleTaggedRoute(
- deviceId, prefix, hostMac, innerVlan, outerVlan, outerTpid, outPort);
- srManager.routingRulePopulator.processDoubleTaggedFilter(
- deviceId, outPort, outerVlan, innerVlan, true);
- }
- }
-
- /**
- * Revokes IP rules for a route when the next hop is double-tagged.
- *
- * @param deviceId device ID that next hop attaches to
- * @param prefix IP prefix of the route
- * @param hostMac MAC address of the next hop
- * @param innerVlan Inner Vlan ID of the next hop
- * @param outerVlan Outer Vlan ID of the next hop
- * @param outerTpid Outer TPID of the next hop
- * @param outPort port that the next hop attaches to
- */
- void revokeDoubleTaggedRoute(DeviceId deviceId, IpPrefix prefix, MacAddress hostMac, VlanId innerVlan,
- VlanId outerVlan, EthType outerTpid, PortNumber outPort) {
- // Revoke route either if this node have the mastership (when device is available) or
- // if this node is the leader (even when device is unavailable)
- if (!srManager.mastershipService.isLocalMaster(deviceId)) {
- if (srManager.deviceService.isAvailable(deviceId)) {
- // Master node will revoke specified rule.
- log.debug("This node is not a master for {}, stop revoking route.", deviceId);
- return;
- }
-
- // isLocalMaster will return false when the device is unavailable.
- // Verify if this node is the leader in that case.
- NodeId leader = srManager.leadershipService.runForLeadership(
- deviceId.toString()).leaderNodeId();
- if (!srManager.clusterService.getLocalNode().id().equals(leader)) {
- // Leader node will revoke specified rule.
- log.debug("This node is not a master for {}, stop revoking route.", deviceId);
- return;
- }
- }
-
- srManager.routingRulePopulator.revokeDoubleTaggedRoute(deviceId, prefix, hostMac,
- innerVlan, outerVlan, outerTpid, outPort);
- srManager.routingRulePopulator.processDoubleTaggedFilter(deviceId, outPort, outerVlan, innerVlan, false);
- }
-
- /**
- * Purges seen before routes for a given device.
- * @param deviceId the device id
- */
- void purgeSeenBeforeRoutes(DeviceId deviceId) {
- log.debug("Purging seen before routes having as target {}", deviceId);
- Set<Entry<DeviceId, DeviceId>> routesToPurge = seenBeforeRoutes.stream()
- .filter(entry -> entry.getValue().equals(deviceId))
- .collect(Collectors.toSet());
- routesToPurge.forEach(entry -> seenBeforeRoutes.remove(entry.getKey(), entry.getValue()));
- }
-
- /**
- * Remove ECMP graph entry for the given device. Typically called when
- * device is no longer available.
- *
- * @param deviceId the device for which graphs need to be purged
- */
- void purgeEcmpGraph(DeviceId deviceId) {
- statusLock.lock();
- try {
- if (populationStatus == Status.STARTED) {
- log.warn("Previous rule population is not finished. Cannot"
- + " proceeed with purgeEcmpGraph for {}", deviceId);
- return;
- }
- log.debug("Updating ECMPspg for unavailable dev:{}", deviceId);
- currentEcmpSpgMap.remove(deviceId);
- if (updatedEcmpSpgMap != null) {
- updatedEcmpSpgMap.remove(deviceId);
- }
- } finally {
- statusLock.unlock();
- }
- }
-
- /**
- * Attempts a full reroute of route-paths if topology has changed relatively
- * close to a mastership change event. Does not do a reroute if mastership
- * change is due to reasons other than a ONOS cluster event - for example a
- * call to balance-masters, or a switch up/down event.
- *
- * @param devId the device identifier for which mastership has changed
- * @param me the mastership event
- */
- void checkFullRerouteForMasterChange(DeviceId devId, MastershipEvent me) {
- // give small delay to absorb mastership events that are caused by
- // device that has disconnected from cluster
- executorServiceMstChg.schedule(new MasterChange(devId, me),
- MASTER_CHANGE_DELAY, TimeUnit.MILLISECONDS);
- }
-
- protected final class MasterChange implements Runnable {
- private DeviceId devId;
- private MastershipEvent me;
- private static final long CLUSTER_EVENT_THRESHOLD = 4500; // ms
- private static final long DEVICE_EVENT_THRESHOLD = 2000; // ms
- private static final long EDGE_PORT_EVENT_THRESHOLD = 10000; //ms
- private static final long FULL_REROUTE_THRESHOLD = 10000; // ms
-
- MasterChange(DeviceId devId, MastershipEvent me) {
- this.devId = devId;
- this.me = me;
- }
-
- @Override
- public void run() {
- long lce = srManager.clusterListener.timeSinceLastClusterEvent();
- boolean clusterEvent = lce < CLUSTER_EVENT_THRESHOLD;
-
- // ignore event for lost switch if cluster event hasn't happened -
- // device down event will handle it
- if ((me.roleInfo().master() == null
- || !srManager.deviceService.isAvailable(devId))
- && !clusterEvent) {
- log.debug("Full reroute not required for lost device: {}/{} "
- + "clusterEvent/timeSince: {}/{}",
- devId, me.roleInfo(), clusterEvent, lce);
- return;
- }
-
- long update = srManager.deviceService.getLastUpdatedInstant(devId);
- long lde = Instant.now().toEpochMilli() - update;
- boolean deviceEvent = lde < DEVICE_EVENT_THRESHOLD;
-
- // ignore event for recently connected switch if cluster event hasn't
- // happened - link up events will handle it
- if (srManager.deviceService.isAvailable(devId) && deviceEvent
- && !clusterEvent) {
- log.debug("Full reroute not required for recently available"
- + " device: {}/{} deviceEvent/timeSince: {}/{} "
- + "clusterEvent/timeSince: {}/{}",
- devId, me.roleInfo(), deviceEvent, lde, clusterEvent, lce);
- return;
- }
-
- long lepe = Instant.now().toEpochMilli()
- - srManager.lastEdgePortEvent.toEpochMilli();
- boolean edgePortEvent = lepe < EDGE_PORT_EVENT_THRESHOLD;
-
- // if it gets here, then mastership change is likely due to onos
- // instance failure, or network partition in onos cluster
- // normally a mastership change like this does not require re-programming
- // but if topology changes happen at the same time then we may miss events
- if (!isRoutingStable() && clusterEvent) {
- log.warn("Mastership changed for dev: {}/{} while programming route-paths "
- + "due to clusterEvent {} ms ago .. attempting full reroute",
- devId, me.roleInfo(), lce);
- if (srManager.mastershipService.isLocalMaster(devId)) {
- // old master could have died when populating filters
- populatePortAddressingRules(devId);
- }
- // old master could have died when creating groups
- // XXX right now we have no fine-grained way to only make changes
- // for the route paths affected by this device. Thus we do a
- // full reroute after purging all hash groups. We also try to do
- // it only once, irrespective of the number of devices
- // that changed mastership when their master instance died.
- long lfrr = Instant.now().toEpochMilli() - lastFullReroute.toEpochMilli();
- boolean doFullReroute = lfrr > FULL_REROUTE_THRESHOLD;
- if (doFullReroute) {
- lastFullReroute = Instant.now();
- for (Device dev : srManager.deviceService.getDevices()) {
- if (shouldProgram(dev.id())) {
- srManager.purgeHashedNextObjectiveStore(dev.id());
- seenBeforeRoutes.removeAll(dev.id());
- }
- }
- // give small delay to ensure entire store is purged
- executorServiceFRR.schedule(new FullRerouteAfterPurge(),
- PURGE_DELAY,
- TimeUnit.MILLISECONDS);
- } else {
- log.warn("Full reroute attempted {} ms ago .. skipping", lfrr);
- }
-
- } else if (edgePortEvent && clusterEvent) {
- log.warn("Mastership changed for dev: {}/{} due to clusterEvent {} ms ago "
- + "while edge-port event happened {} ms ago "
- + " .. reprogramming all edge-ports",
- devId, me.roleInfo(), lce, lepe);
- if (shouldProgram(devId)) {
- srManager.deviceService.getPorts(devId).stream()
- .filter(p -> srManager.interfaceService
- .isConfigured(new ConnectPoint(devId, p.number())))
- .forEach(p -> srManager.processPortUpdated(devId, p));
- }
-
- } else {
- log.debug("Stable route-paths .. full reroute not attempted for "
- + "mastership change {}/{} deviceEvent/timeSince: {}/{} "
- + "clusterEvent/timeSince: {}/{}", devId, me.roleInfo(),
- deviceEvent, lde, clusterEvent, lce);
- }
- }
- }
-
- /**
- * Performs a full reroute of routing rules in all the switches. Assumes
- * caller has purged hash groups from the nextObjective store, otherwise
- * re-uses ones available in the store.
- */
- protected final class FullRerouteAfterPurge implements Runnable {
- @Override
- public void run() {
- populateAllRoutingRules();
- }
- }
-
-
- //////////////////////////////////////
- // Routing helper methods and classes
- //////////////////////////////////////
-
- /**
- * Computes set of affected routes due to failed link. Assumes previous ecmp
- * shortest-path graph exists for a switch in order to compute affected
- * routes. If such a graph does not exist, the method returns null.
- *
- * @param linkFail the failed link
- * @return the set of affected routes which may be empty if no routes were
- * affected
- */
- private Set<ArrayList<DeviceId>> computeDamagedRoutes(Link linkFail) {
- Set<ArrayList<DeviceId>> routes = new HashSet<>();
-
- for (Device sw : srManager.deviceService.getDevices()) {
- log.debug("Computing the impacted routes for device {} due to link fail",
- sw.id());
- if (!shouldProgram(sw.id())) {
- lastProgrammed.remove(sw.id());
- continue;
- }
- for (DeviceId rootSw : deviceAndItsPair(sw.id())) {
- // check for mastership change since last run
- if (!lastProgrammed.contains(sw.id())) {
- log.warn("New responsibility for this node to program dev:{}"
- + " ... nuking current ECMPspg", sw.id());
- currentEcmpSpgMap.remove(sw.id());
- }
- lastProgrammed.add(sw.id());
-
- EcmpShortestPathGraph ecmpSpg = currentEcmpSpgMap.get(rootSw);
- if (ecmpSpg == null) {
- log.warn("No existing ECMP graph for switch {}. Assuming "
- + "all route-paths have changed towards it.", rootSw);
- for (DeviceId targetSw : srManager.deviceConfiguration.getRouters()) {
- if (targetSw.equals(rootSw)) {
- continue;
- }
- routes.add(Lists.newArrayList(targetSw, rootSw));
- log.debug("Impacted route:{}->{}", targetSw, rootSw);
- }
- continue;
- }
-
- if (log.isDebugEnabled()) {
- log.debug("Root switch: {}", rootSw);
- log.debug(" Current/Existing SPG: {}", ecmpSpg);
- log.debug(" New/Updated SPG: {}", updatedEcmpSpgMap.get(rootSw));
- }
- HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>>
- switchVia = ecmpSpg.getAllLearnedSwitchesAndVia();
- // figure out if the broken link affected any route-paths in this graph
- for (Integer itrIdx : switchVia.keySet()) {
- log.trace("Current/Exiting SPG Iterindex# {}", itrIdx);
- HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap =
- switchVia.get(itrIdx);
- for (DeviceId targetSw : swViaMap.keySet()) {
- log.trace("TargetSwitch {} --> RootSwitch {}",
- targetSw, rootSw);
- for (ArrayList<DeviceId> via : swViaMap.get(targetSw)) {
- log.trace(" Via:");
- via.forEach(e -> log.trace(" {}", e));
- }
- Set<ArrayList<DeviceId>> subLinks =
- computeLinks(targetSw, rootSw, swViaMap);
- for (ArrayList<DeviceId> alink: subLinks) {
- if ((alink.get(0).equals(linkFail.src().deviceId()) &&
- alink.get(1).equals(linkFail.dst().deviceId()))
- ||
- (alink.get(0).equals(linkFail.dst().deviceId()) &&
- alink.get(1).equals(linkFail.src().deviceId()))) {
- log.debug("Impacted route:{}->{}", targetSw, rootSw);
- ArrayList<DeviceId> aRoute = new ArrayList<>();
- aRoute.add(targetSw); // switch with rules to populate
- aRoute.add(rootSw); // towards this destination
- routes.add(aRoute);
- break;
- }
- }
- }
- }
-
- }
-
- }
- return routes;
- }
-
- /**
- * Computes set of affected routes due to new links or failed switches.
- *
- * @param failedSwitch deviceId of failed switch if any
- * @return the set of affected routes which may be empty if no routes were
- * affected
- */
- private Set<ArrayList<DeviceId>> computeRouteChange(DeviceId failedSwitch) {
- ImmutableSet.Builder<ArrayList<DeviceId>> changedRtBldr =
- ImmutableSet.builder();
-
- for (Device sw : srManager.deviceService.getDevices()) {
- log.debug("Computing the impacted routes for device {}", sw.id());
- if (!shouldProgram(sw.id())) {
- lastProgrammed.remove(sw.id());
- continue;
- }
- for (DeviceId rootSw : deviceAndItsPair(sw.id())) {
- if (log.isTraceEnabled()) {
- log.trace("Device links for dev: {}", rootSw);
- for (Link link: srManager.linkService.getDeviceLinks(rootSw)) {
- log.trace("{} -> {} ", link.src().deviceId(),
- link.dst().deviceId());
- }
- }
- // check for mastership change since last run
- if (!lastProgrammed.contains(sw.id())) {
- log.warn("New responsibility for this node to program dev:{}"
- + " ... nuking current ECMPspg", sw.id());
- currentEcmpSpgMap.remove(sw.id());
- }
- lastProgrammed.add(sw.id());
- EcmpShortestPathGraph currEcmpSpg = currentEcmpSpgMap.get(rootSw);
- if (currEcmpSpg == null) {
- log.debug("No existing ECMP graph for device {}.. adding self as "
- + "changed route", rootSw);
- changedRtBldr.add(Lists.newArrayList(rootSw));
- continue;
- }
- EcmpShortestPathGraph newEcmpSpg = updatedEcmpSpgMap.get(rootSw);
- if (newEcmpSpg == null) {
- log.warn("Cannot find updated ECMP graph for dev:{}", rootSw);
- continue;
- }
- if (log.isDebugEnabled()) {
- log.debug("Root switch: {}", rootSw);
- log.debug(" Current/Existing SPG: {}", currEcmpSpg);
- log.debug(" New/Updated SPG: {}", newEcmpSpg);
- }
- // first use the updated/new map to compare to current/existing map
- // as new links may have come up
- changedRtBldr.addAll(compareGraphs(newEcmpSpg, currEcmpSpg, rootSw));
- // then use the current/existing map to compare to updated/new map
- // as switch may have been removed
- changedRtBldr.addAll(compareGraphs(currEcmpSpg, newEcmpSpg, rootSw));
- }
- }
-
- // handle clearing state for a failed switch in case the switch does
- // not have a pair, or the pair is not available
- if (failedSwitch != null) {
- Optional<DeviceId> pairDev = srManager.getPairDeviceId(failedSwitch);
- if (!pairDev.isPresent() || !srManager.deviceService.isAvailable(pairDev.get())) {
- log.debug("Proxy Route changes to downed Sw:{}", failedSwitch);
- srManager.deviceService.getDevices().forEach(dev -> {
- if (!dev.id().equals(failedSwitch) &&
- srManager.mastershipService.isLocalMaster(dev.id())) {
- log.debug(" : {}", dev.id());
- changedRtBldr.add(Lists.newArrayList(dev.id(), failedSwitch));
- }
- });
- }
- }
-
- Set<ArrayList<DeviceId>> changedRoutes = changedRtBldr.build();
- for (ArrayList<DeviceId> route: changedRoutes) {
- log.debug("Route changes Target -> Root");
- if (route.size() == 1) {
- log.debug(" : all -> {}", route.get(0));
- } else {
- log.debug(" : {} -> {}", route.get(0), route.get(1));
- }
- }
- return changedRoutes;
- }
-
- // Utility method to expands the route changes in two elements array using
- // the ECMP graph. Caller represents all to dst switch routes with an
- // array containing only the dst switch.
- private Set<ArrayList<DeviceId>> getExpandedRoutes(Set<ArrayList<DeviceId>> routeChanges) {
- Set<ArrayList<DeviceId>> changedRoutes = new HashSet<>();
- // Ensure each routeChanges entry has two elements
- for (ArrayList<DeviceId> route : routeChanges) {
- if (route.size() == 1) {
- DeviceId dstSw = route.get(0);
- EcmpShortestPathGraph ec = updatedEcmpSpgMap.get(dstSw);
- if (ec == null) {
- log.warn("No graph found for {} .. aborting redoRouting", dstSw);
- return Collections.emptySet();
- }
- ec.getAllLearnedSwitchesAndVia().keySet().forEach(key -> {
- ec.getAllLearnedSwitchesAndVia().get(key).keySet().forEach(target -> {
- changedRoutes.add(Lists.newArrayList(target, dstSw));
- });
- });
- } else {
- DeviceId targetSw = route.get(0);
- DeviceId dstSw = route.get(1);
- changedRoutes.add(Lists.newArrayList(targetSw, dstSw));
- }
- }
- return changedRoutes;
- }
-
- // Utility method to expands the route changes in two elements array using
- // the available devices. Caller represents all to dst switch routes with an
- // array containing only the dst switch.
- private Set<ArrayList<DeviceId>> getAllExpandedRoutes(Set<ArrayList<DeviceId>> routeChanges) {
- Set<ArrayList<DeviceId>> changedRoutes = new HashSet<>();
- // Ensure each routeChanges entry has two elements
- for (ArrayList<DeviceId> route : routeChanges) {
- if (route.size() == 1) {
- // route-path changes are from everyone else to this switch
- DeviceId dstSw = route.get(0);
- srManager.deviceService.getAvailableDevices().forEach(sw -> {
- if (!sw.id().equals(dstSw)) {
- changedRoutes.add(Lists.newArrayList(sw.id(), dstSw));
- }
- });
- } else {
- changedRoutes.add(route);
- }
- }
- return changedRoutes;
- }
-
- /**
- * For the root switch, searches all the target nodes reachable in the base
- * graph, and compares paths to the ones in the comp graph.
- *
- * @param base the graph that is indexed for all reachable target nodes
- * from the root node
- * @param comp the graph that the base graph is compared to
- * @param rootSw both ecmp graphs are calculated for the root node
- * @return all the routes that have changed in the base graph
- */
- private Set<ArrayList<DeviceId>> compareGraphs(EcmpShortestPathGraph base,
- EcmpShortestPathGraph comp,
- DeviceId rootSw) {
- ImmutableSet.Builder<ArrayList<DeviceId>> changedRoutesBuilder =
- ImmutableSet.builder();
- HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> baseMap =
- base.getAllLearnedSwitchesAndVia();
- HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> compMap =
- comp.getAllLearnedSwitchesAndVia();
- for (Integer itrIdx : baseMap.keySet()) {
- HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> baseViaMap =
- baseMap.get(itrIdx);
- for (DeviceId targetSw : baseViaMap.keySet()) {
- ArrayList<ArrayList<DeviceId>> basePath = baseViaMap.get(targetSw);
- ArrayList<ArrayList<DeviceId>> compPath = getVia(compMap, targetSw);
- if ((compPath == null) || !basePath.equals(compPath)) {
- log.trace("Impacted route:{} -> {}", targetSw, rootSw);
- ArrayList<DeviceId> route = new ArrayList<>();
- route.add(targetSw); // switch with rules to populate
- route.add(rootSw); // towards this destination
- changedRoutesBuilder.add(route);
- }
- }
- }
- return changedRoutesBuilder.build();
- }
-
- /**
- * Returns the ECMP paths traversed to reach the target switch.
- *
- * @param switchVia a per-iteration view of the ECMP graph for a root switch
- * @param targetSw the switch to reach from the root switch
- * @return the nodes traversed on ECMP paths to the target switch
- */
- private ArrayList<ArrayList<DeviceId>> getVia(HashMap<Integer, HashMap<DeviceId,
- ArrayList<ArrayList<DeviceId>>>> switchVia, DeviceId targetSw) {
- for (Integer itrIdx : switchVia.keySet()) {
- HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap =
- switchVia.get(itrIdx);
- if (swViaMap.get(targetSw) == null) {
- continue;
- } else {
- return swViaMap.get(targetSw);
- }
- }
-
- return null;
- }
-
- /**
- * Utility method to break down a path from src to dst device into a collection
- * of links.
- *
- * @param src src device of the path
- * @param dst dst device of the path
- * @param viaMap path taken from src to dst device
- * @return collection of links in the path
- */
- private Set<ArrayList<DeviceId>> computeLinks(DeviceId src,
- DeviceId dst,
- HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> viaMap) {
- Set<ArrayList<DeviceId>> subLinks = Sets.newHashSet();
- for (ArrayList<DeviceId> via : viaMap.get(src)) {
- DeviceId linkSrc = src;
- DeviceId linkDst = dst;
- for (DeviceId viaDevice: via) {
- ArrayList<DeviceId> link = new ArrayList<>();
- linkDst = viaDevice;
- link.add(linkSrc);
- link.add(linkDst);
- subLinks.add(link);
- linkSrc = viaDevice;
- }
- ArrayList<DeviceId> link = new ArrayList<>();
- link.add(linkSrc);
- link.add(dst);
- subLinks.add(link);
- }
-
- return subLinks;
- }
-
- /**
- * Determines whether this controller instance should program the
- * given {@code deviceId}, based on mastership and pairDeviceId if one exists.
- * <p>
- * Once an instance is elected, it will be the only instance responsible for programming
- * both devices in the pair until it goes down.
- *
- * @param deviceId device identifier to consider for routing
- * @return true if current instance should handle the routing for given device
- */
- boolean shouldProgram(DeviceId deviceId) {
- Boolean cached = shouldProgramCache.get(deviceId);
- if (cached != null) {
- log.debug("shouldProgram dev:{} cached:{}", deviceId, cached);
- return cached;
- }
-
- Optional<DeviceId> pairDeviceId = srManager.getPairDeviceId(deviceId);
-
- NodeId currentNodeId = srManager.clusterService.getLocalNode().id();
- NodeId masterNodeId = srManager.mastershipService.getMasterFor(deviceId);
- Optional<NodeId> pairMasterNodeId = pairDeviceId.map(srManager.mastershipService::getMasterFor);
- log.debug("Evaluate shouldProgram {}/pair={}. currentNodeId={}, master={}, pairMaster={}",
- deviceId, pairDeviceId, currentNodeId, masterNodeId, pairMasterNodeId);
-
- // No pair device configured. Only handle when current instance is the master of the device
- if (!pairDeviceId.isPresent()) {
- log.debug("No pair device. currentNodeId={}, master={}", currentNodeId, masterNodeId);
- return currentNodeId.equals(masterNodeId);
- }
-
- // Should not handle if current instance is not the master of either switch
- if (!currentNodeId.equals(masterNodeId) &&
- !(pairMasterNodeId.isPresent() && currentNodeId.equals(pairMasterNodeId.get()))) {
- log.debug("Current nodeId {} is neither the master of target device {} nor pair device {}",
- currentNodeId, deviceId, pairDeviceId);
- return false;
- }
-
- Set<DeviceId> key = Sets.newHashSet(deviceId, pairDeviceId.get());
-
- NodeId king = shouldProgram.compute(key, ((k, v) -> {
- if (v == null) {
- // There is no value in the map. Elect a node
- return elect(Lists.newArrayList(masterNodeId, pairMasterNodeId.orElse(null)));
- } else {
- if (v.equals(masterNodeId) || v.equals(pairMasterNodeId.orElse(null))) {
- // Use the node in the map if it is still alive and is a master of any of the two switches
- return v;
- } else {
- // Previously elected node is no longer the master of either switch. Re-elect a node.
- return elect(Lists.newArrayList(masterNodeId, pairMasterNodeId.orElse(null)));
- }
- }
- }));
-
- if (king != null) {
- log.debug("{} is king, should handle routing for {}/pair={}", king, deviceId, pairDeviceId);
- shouldProgramCache.put(deviceId, king.equals(currentNodeId));
- return king.equals(currentNodeId);
- } else {
- log.error("Fail to elect a king for {}/pair={}. Abort.", deviceId, pairDeviceId);
- shouldProgramCache.remove(deviceId);
- return false;
- }
- }
-
- /**
- * Elects a node who should take responsibility of programming devices.
- * @param nodeIds list of candidate node ID
- *
- * @return NodeId of the node that gets elected, or null if none of the node can be elected
- */
- private NodeId elect(List<NodeId> nodeIds) {
- // Remove all null elements. This could happen when some device has no master
- nodeIds.removeAll(Collections.singleton(null));
- nodeIds.sort(null);
- return nodeIds.size() == 0 ? null : nodeIds.get(0);
- }
-
- void invalidateShouldProgramCache(DeviceId deviceId) {
- shouldProgramCache.remove(deviceId);
- }
-
- /**
- * Returns a set of device ID, containing given device and its pair device if exist.
- *
- * @param deviceId Device ID
- * @return a set of device ID, containing given device and its pair device if exist.
- */
- private Set<DeviceId> deviceAndItsPair(DeviceId deviceId) {
- Set<DeviceId> ret = Sets.newHashSet(deviceId);
- srManager.getPairDeviceId(deviceId).ifPresent(ret::add);
- return ret;
- }
-
- /**
- * Returns the set of deviceIds which are the next hops from the targetSw
- * to the dstSw according to the latest ECMP spg.
- *
- * @param targetSw the switch for which the next-hops are desired
- * @param dstSw the switch to which the next-hops lead to from the targetSw
- * @return set of next hop deviceIds, could be empty if no next hops are found
- */
- private Set<DeviceId> getNextHops(DeviceId targetSw, DeviceId dstSw) {
- boolean targetIsEdge = false;
- try {
- targetIsEdge = srManager.deviceConfiguration.isEdgeDevice(targetSw);
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage() + "Cannot determine if targetIsEdge {}.. "
- + "continuing to getNextHops", targetSw);
- }
-
- EcmpShortestPathGraph ecmpSpg = updatedEcmpSpgMap.get(dstSw);
- if (ecmpSpg == null) {
- log.debug("No ecmpSpg found for dstSw: {}", dstSw);
- return ImmutableSet.of();
- }
- HashMap<Integer,
- HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia =
- ecmpSpg.getAllLearnedSwitchesAndVia();
- for (Integer itrIdx : switchVia.keySet()) {
- HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swViaMap =
- switchVia.get(itrIdx);
- for (DeviceId target : swViaMap.keySet()) {
- if (!target.equals(targetSw)) {
- continue;
- }
- // optimization for spines to not use leaves to get
- // to a spine or other leaves. Also leaves should not use other
- // leaves to get to the destination
- if ((!targetIsEdge && itrIdx > 1) || targetIsEdge) {
- boolean pathdevIsEdge = false;
- for (ArrayList<DeviceId> via : swViaMap.get(targetSw)) {
- log.debug("Evaluating next-hop in path: {}", via);
- for (DeviceId pathdev : via) {
- try {
- pathdevIsEdge = srManager.deviceConfiguration
- .isEdgeDevice(pathdev);
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage());
- }
- if (pathdevIsEdge) {
- log.debug("Avoiding {} hop path for targetSw:{}"
- + " --> dstSw:{} which goes through an edge"
- + " device {} in path {}", itrIdx,
- targetSw, dstSw, pathdev, via);
- return ImmutableSet.of();
- }
- }
- }
- }
- Set<DeviceId> nextHops = new HashSet<>();
- for (ArrayList<DeviceId> via : swViaMap.get(targetSw)) {
- if (via.isEmpty()) {
- // the dstSw is the next-hop from the targetSw
- nextHops.add(dstSw);
- } else {
- // first elem is next-hop in each ECMP path
- nextHops.add(via.get(0));
- }
- }
- log.debug("target {} --> dst: {} has next-hops:{}", targetSw,
- dstSw, nextHops);
- return nextHops;
- }
- }
- log.debug("No next hops found for target:{} --> dst: {}", targetSw, dstSw);
- return ImmutableSet.of(); //no next-hops found
- }
-
- //////////////////////////////////////
- // Filtering rule creation
- //////////////////////////////////////
-
- /**
- * Populates filtering rules for port, and punting rules
- * for gateway IPs, loopback IPs and arp/ndp traffic.
- * Should only be called by the master instance for this device/port.
- *
- * @param deviceId Switch ID to set the rules
- */
- void populatePortAddressingRules(DeviceId deviceId) {
- // Although device is added, sometimes device store does not have the
- // ports for this device yet. It results in missing filtering rules in the
- // switch. We will attempt it a few times. If it still does not work,
- // user can manually repopulate using CLI command sr-reroute-network
- PortFilterInfo firstRun = rulePopulator.populateVlanMacFilters(deviceId);
- if (firstRun == null) {
- firstRun = new PortFilterInfo(0, 0, 0);
- }
- executorService.schedule(new RetryFilters(deviceId, firstRun),
- RETRY_INTERVAL_MS, TimeUnit.MILLISECONDS);
- }
-
- /**
- * RetryFilters populates filtering objectives for a device and keeps retrying
- * till the number of ports filtered are constant for a predefined number
- * of attempts.
- */
- protected final class RetryFilters implements Runnable {
- int constantAttempts = MAX_CONSTANT_RETRY_ATTEMPTS;
- DeviceId devId;
- int counter;
- PortFilterInfo prevRun;
-
- private RetryFilters(DeviceId deviceId, PortFilterInfo previousRun) {
- devId = deviceId;
- prevRun = previousRun;
- counter = 0;
- }
-
- @Override
- public void run() {
- log.debug("RETRY FILTER ATTEMPT {} ** dev:{}", ++counter, devId);
- PortFilterInfo thisRun = rulePopulator.populateVlanMacFilters(devId);
- boolean sameResult = prevRun.equals(thisRun);
- log.debug("dev:{} prevRun:{} thisRun:{} sameResult:{}", devId, prevRun,
- thisRun, sameResult);
- if (thisRun == null || !sameResult || (--constantAttempts > 0)) {
- // exponentially increasing intervals for retries
- executorService.schedule(this,
- RETRY_INTERVAL_MS * (int) Math.pow(counter, RETRY_INTERVAL_SCALE),
- TimeUnit.MILLISECONDS);
- if (!sameResult) {
- constantAttempts = MAX_CONSTANT_RETRY_ATTEMPTS; //reset
- }
- }
- prevRun = (thisRun == null) ? prevRun : thisRun;
- }
- }
-
- // Check jobs completion. It returns false if one of the job fails
- // and cancel the remaining
- private boolean checkJobs(List<Future<Boolean>> futures) {
- boolean completed = true;
- for (Future<Boolean> future : futures) {
- try {
- if (completed) {
- if (!future.get()) {
- completed = false;
- }
- } else {
- future.cancel(true);
- }
- } catch (InterruptedException | ExecutionException e) {
- completed = false;
- }
- }
- return completed;
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/DefaultTunnel.java b/app/src/main/java/org/onosproject/segmentrouting/DefaultTunnel.java
deleted file mode 100644
index 0fd7c07..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/DefaultTunnel.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright 2015-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;
-
-import java.util.List;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-/**
- * Default Tunnel class.
- */
-public class DefaultTunnel implements Tunnel {
-
- private final String id;
- private final List<Integer> labelIds;
-
- private int groupId;
- private boolean allowedToRemoveGroup;
-
- /**
- * Creates a Tunnel reference.
- *
- * @param tid Tunnel ID
- * @param labelIds Label stack of the tunnel
- */
- public DefaultTunnel(String tid, List<Integer> labelIds) {
- this.id = checkNotNull(tid);
- this.labelIds = labelIds;
- //TODO: need to register the class in Kryo for this
- //this.labelIds = Collections.unmodifiableList(labelIds);
- this.groupId = -1;
- }
-
- /**
- * Creates a new DefaultTunnel reference using the tunnel reference.
- *
- * @param tunnel DefaultTunnel reference
- */
- public DefaultTunnel(DefaultTunnel tunnel) {
- this.id = tunnel.id;
- this.labelIds = tunnel.labelIds;
- this.groupId = tunnel.groupId;
- }
-
- @Override
- public String id() {
- return this.id;
- }
-
- @Override
- public List<Integer> labelIds() {
- return this.labelIds;
- }
-
- @Override
- public int groupId() {
- return this.groupId;
- }
-
- @Override
- public void setGroupId(int id) {
- this.groupId = id;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
-
- if (o instanceof DefaultTunnel) {
- DefaultTunnel tunnel = (DefaultTunnel) o;
- // We compare only the tunnel paths.
- if (tunnel.labelIds.equals(this.labelIds)) {
- return true;
- }
- }
-
- return false;
- }
-
- @Override
- public int hashCode() {
- return labelIds.hashCode();
- }
-
- @Override
- public boolean isAllowedToRemoveGroup() {
- return this.allowedToRemoveGroup;
- }
-
- @Override
- public void allowToRemoveGroup(boolean b) {
- this.allowedToRemoveGroup = b;
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/EcmpShortestPathGraph.java b/app/src/main/java/org/onosproject/segmentrouting/EcmpShortestPathGraph.java
deleted file mode 100644
index 036044c..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/EcmpShortestPathGraph.java
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright 2015-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;
-
-import org.onlab.graph.ScalarWeight;
-import org.onosproject.net.DefaultLink;
-import org.onosproject.net.DefaultPath;
-import org.onosproject.net.Device;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Link;
-import org.onosproject.net.Path;
-import org.onosproject.net.provider.ProviderId;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.collect.Sets;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.Set;
-
-/**
- * This class creates breadth-first-search (BFS) tree for a given root device
- * and returns paths from the root Device to leaf Devices (target devices).
- * The paths are snapshot paths at the point of the class instantiation.
- */
-public class EcmpShortestPathGraph {
- LinkedList<DeviceId> deviceQueue = new LinkedList<>();
- LinkedList<Integer> distanceQueue = new LinkedList<>();
- HashMap<DeviceId, Integer> deviceSearched = new HashMap<>();
- HashMap<DeviceId, ArrayList<Link>> upstreamLinks = new HashMap<>();
- HashMap<DeviceId, ArrayList<Path>> paths = new HashMap<>();
- HashMap<Integer, ArrayList<DeviceId>> distanceDeviceMap = new HashMap<>();
- DeviceId rootDevice;
- private SegmentRoutingManager srManager;
- private static final Logger log = LoggerFactory.getLogger(EcmpShortestPathGraph.class);
-
- /**
- * Constructor.
- *
- * @param rootDevice root of the BFS tree
- * @param srManager SegmentRoutingManager object
- */
- public EcmpShortestPathGraph(DeviceId rootDevice, SegmentRoutingManager srManager) {
- this.rootDevice = rootDevice;
- this.srManager = srManager;
- calcECMPShortestPathGraph();
- }
-
- /**
- * Calculates the BFS tree.
- */
- private void calcECMPShortestPathGraph() {
- deviceQueue.add(rootDevice);
- int currDistance = 0;
- distanceQueue.add(currDistance);
- deviceSearched.put(rootDevice, currDistance);
- while (!deviceQueue.isEmpty()) {
- DeviceId sw = deviceQueue.poll();
- Set<DeviceId> prevSw = Sets.newHashSet();
- currDistance = distanceQueue.poll();
-
- for (Link link : srManager.linkHandler.getDeviceEgressLinks(sw)) {
- if (srManager.linkHandler.avoidLink(link)) {
- continue;
- }
- DeviceId reachedDevice = link.dst().deviceId();
- if (prevSw.contains(reachedDevice)) {
- // Ignore LAG links between the same set of Devices
- continue;
- } else {
- prevSw.add(reachedDevice);
- }
-
- Integer distance = deviceSearched.get(reachedDevice);
- if ((distance != null) && (distance < (currDistance + 1))) {
- continue;
- }
- if (distance == null) {
- // First time visiting this Device node
- deviceQueue.add(reachedDevice);
- distanceQueue.add(currDistance + 1);
- deviceSearched.put(reachedDevice, currDistance + 1);
-
- ArrayList<DeviceId> distanceSwArray = distanceDeviceMap
- .get(currDistance + 1);
- if (distanceSwArray == null) {
- distanceSwArray = new ArrayList<>();
- distanceSwArray.add(reachedDevice);
- distanceDeviceMap.put(currDistance + 1, distanceSwArray);
- } else {
- distanceSwArray.add(reachedDevice);
- }
- }
-
- ArrayList<Link> upstreamLinkArray =
- upstreamLinks.get(reachedDevice);
- if (upstreamLinkArray == null) {
- upstreamLinkArray = new ArrayList<>();
- upstreamLinkArray.add(copyDefaultLink(link));
- //upstreamLinkArray.add(link);
- upstreamLinks.put(reachedDevice, upstreamLinkArray);
- } else {
- // ECMP links
- upstreamLinkArray.add(copyDefaultLink(link));
- }
- }
- }
- }
-
- private void getDFSPaths(DeviceId dstDeviceDeviceId, Path path, ArrayList<Path> paths) {
- DeviceId rootDeviceDeviceId = rootDevice;
- for (Link upstreamLink : upstreamLinks.get(dstDeviceDeviceId)) {
- /* Deep clone the path object */
- Path sofarPath;
- ArrayList<Link> sofarLinks = new ArrayList<>();
- if (path != null && !path.links().isEmpty()) {
- sofarLinks.addAll(path.links());
- }
- sofarLinks.add(upstreamLink);
- sofarPath = new DefaultPath(ProviderId.NONE, sofarLinks, ScalarWeight.toWeight(0));
- if (upstreamLink.src().deviceId().equals(rootDeviceDeviceId)) {
- paths.add(sofarPath);
- return;
- } else {
- getDFSPaths(upstreamLink.src().deviceId(), sofarPath, paths);
- }
- }
- }
-
- /**
- * Return root Device for the graph.
- *
- * @return root Device
- */
- public DeviceId getRootDevice() {
- return rootDevice;
- }
-
- /**
- * Return the computed ECMP paths from the root Device to a given Device in
- * the network.
- *
- * @param targetDevice the target Device
- * @return the list of ECMP Paths from the root Device to the target Device
- */
- public ArrayList<Path> getECMPPaths(DeviceId targetDevice) {
- ArrayList<Path> pathArray = paths.get(targetDevice);
- if (pathArray == null && deviceSearched.containsKey(
- targetDevice)) {
- pathArray = new ArrayList<>();
- DeviceId sw = targetDevice;
- getDFSPaths(sw, null, pathArray);
- paths.put(targetDevice, pathArray);
- }
- return pathArray;
- }
-
- /**
- * Return the complete info of the computed ECMP paths for each Device
- * learned in multiple iterations from the root Device.
- *
- * @return the hash table of Devices learned in multiple Dijkstra
- * iterations and corresponding ECMP paths to it from the root
- * Device
- */
- public HashMap<Integer, HashMap<DeviceId,
- ArrayList<Path>>> getCompleteLearnedDeviceesAndPaths() {
-
- HashMap<Integer, HashMap<DeviceId, ArrayList<Path>>> pathGraph = new HashMap<>();
-
- for (Integer itrIndx : distanceDeviceMap.keySet()) {
- HashMap<DeviceId, ArrayList<Path>> swMap = new HashMap<>();
- for (DeviceId sw : distanceDeviceMap.get(itrIndx)) {
- swMap.put(sw, getECMPPaths(sw));
- }
- pathGraph.put(itrIndx, swMap);
- }
-
- return pathGraph;
- }
-
- /**
- * Returns the complete info of the computed ECMP paths for each target device
- * learned in multiple iterations from the root Device. The computed info
- * returned is per iteration (Integer key of outer HashMap). In each
- * iteration, for the target devices reached (DeviceId key of inner HashMap),
- * the ECMP paths are detailed (2D array).
- *
- * @return the hash table of target Devices learned in multiple Dijkstra
- * iterations and corresponding ECMP paths in terms of Devices to
- * be traversed (via) from the root Device to the target Device
- */
- public HashMap<Integer, HashMap<DeviceId,
- ArrayList<ArrayList<DeviceId>>>> getAllLearnedSwitchesAndVia() {
-
- HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> deviceViaMap = new HashMap<>();
-
- for (Integer itrIndx : distanceDeviceMap.keySet()) {
- HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>> swMap = new HashMap<>();
-
- for (DeviceId sw : distanceDeviceMap.get(itrIndx)) {
- ArrayList<ArrayList<DeviceId>> swViaArray = new ArrayList<>();
- for (Path path : getECMPPaths(sw)) {
- ArrayList<DeviceId> swVia = new ArrayList<>();
- for (Link link : path.links()) {
- if (link.src().deviceId().equals(rootDevice)) {
- /* No need to add the root Device again in
- * the Via list
- */
- continue;
- }
- swVia.add(link.src().deviceId());
- }
- swViaArray.add(swVia);
- }
- swMap.put(sw, swViaArray);
- }
- deviceViaMap.put(itrIndx, swMap);
- }
- return deviceViaMap;
- }
-
-
- private Link copyDefaultLink(Link link) {
- DefaultLink src = (DefaultLink) link;
- DefaultLink defaultLink = DefaultLink.builder()
- .providerId(src.providerId())
- .src(src.src())
- .dst(src.dst())
- .type(src.type())
- .annotations(src.annotations())
- .build();
-
- return defaultLink;
- }
-
- @Override
- public String toString() {
- StringBuilder sBuilder = new StringBuilder();
- for (Device device: srManager.deviceService.getDevices()) {
- if (!device.id().equals(rootDevice)) {
- sBuilder.append("\r\n Paths from " + rootDevice + " to "
- + device.id());
- ArrayList<Path> paths = getECMPPaths(device.id());
- if (paths != null) {
- for (Path path : paths) {
- sBuilder.append("\r\n == "); // equal cost paths delimiter
- for (int i = path.links().size() - 1; i >= 0; i--) {
- Link link = path.links().get(i);
- sBuilder.append(" : " + link.src() + " -> " + link.dst());
- }
- }
- } else {
- sBuilder.append("\r\n == no paths");
- }
- }
- }
- return sBuilder.toString();
- }
-}
-
diff --git a/app/src/main/java/org/onosproject/segmentrouting/EdgePair.java b/app/src/main/java/org/onosproject/segmentrouting/EdgePair.java
deleted file mode 100644
index 571e87f..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/EdgePair.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2018-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;
-
-import org.onosproject.net.DeviceId;
-
-import java.util.Objects;
-
-import static com.google.common.base.MoreObjects.toStringHelper;
-
-/**
- * Represents two devices that are paired by configuration. An EdgePair for
- * (dev1, dev2) is the same as as EdgePair for (dev2, dev1)
- */
-public final class EdgePair {
- DeviceId dev1;
- DeviceId dev2;
-
- EdgePair(DeviceId dev1, DeviceId dev2) {
- this.dev1 = dev1;
- this.dev2 = dev2;
- }
-
- boolean includes(DeviceId dev) {
- return dev1.equals(dev) || dev2.equals(dev);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (!(o instanceof EdgePair)) {
- return false;
- }
- EdgePair that = (EdgePair) o;
- return ((this.dev1.equals(that.dev1) && this.dev2.equals(that.dev2)) ||
- (this.dev1.equals(that.dev2) && this.dev2.equals(that.dev1)));
- }
-
- @Override
- public int hashCode() {
- if (dev1.toString().compareTo(dev2.toString()) <= 0) {
- return Objects.hash(dev1, dev2);
- } else {
- return Objects.hash(dev2, dev1);
- }
- }
-
- @Override
- public String toString() {
- return toStringHelper(this)
- .add("Dev1", dev1)
- .add("Dev2", dev2)
- .toString();
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/onosproject/segmentrouting/HostHandler.java b/app/src/main/java/org/onosproject/segmentrouting/HostHandler.java
deleted file mode 100644
index 46231b0..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/HostHandler.java
+++ /dev/null
@@ -1,872 +0,0 @@
-/*
- * Copyright 2016-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;
-
-import com.google.common.collect.Lists;
-import org.onlab.packet.EthType;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
-import org.onlab.util.PredictableExecutor;
-import org.onlab.util.Tools;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Host;
-import org.onosproject.net.HostLocation;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.flowobjective.Objective;
-import org.onosproject.net.host.HostEvent;
-import org.onosproject.net.host.HostService;
-import org.onosproject.net.host.ProbeMode;
-import org.onosproject.segmentrouting.phasedrecovery.api.Phase;
-import org.onosproject.segmentrouting.phasedrecovery.api.PhasedRecoveryService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.collect.Sets;
-
-import java.util.HashSet;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static org.onlab.util.Tools.groupedThreads;
-
-/**
- * Handles host-related events.
- */
-public class HostHandler {
- private static final Logger log = LoggerFactory.getLogger(HostHandler.class);
-
- protected final SegmentRoutingManager srManager;
- private HostService hostService;
- // Host workers - 0 will leverage available processors
- private static final int DEFAULT_THREADS = 0;
- protected PredictableExecutor hostWorkers;
-
- /**
- * Constructs the HostHandler.
- *
- * @param srManager Segment Routing manager
- */
- HostHandler(SegmentRoutingManager srManager) {
- this.srManager = srManager;
- hostService = srManager.hostService;
- this.hostWorkers = new PredictableExecutor(DEFAULT_THREADS,
- groupedThreads("onos/sr", "h-worker-%d", log));
- }
-
- /**
- * Shutdowns the workers.
- */
- void terminate() {
- hostWorkers.shutdown();
- }
-
- protected void init(DeviceId devId) {
- log.info("Initializing hosts on {}", devId);
- List<CompletableFuture<Void>> hostFutures = Lists.newArrayList();
-
- // Init hosts in parallel using hostWorkers executor
- hostService.getHosts().forEach(host -> {
- hostFutures.add(hostWorkers.submit(() -> initHost(host, devId), host.id().hashCode()));
- });
-
- log.debug("{} hostFutures for {}", hostFutures.size(), devId);
- CompletableFuture<Void> allHostFuture = CompletableFuture.allOf(hostFutures.toArray(new CompletableFuture[0]));
- CompletableFuture<Void> timeoutFuture =
- Tools.completeAfter(PhasedRecoveryService.PAIR_TIMEOUT, TimeUnit.SECONDS);
-
- allHostFuture.runAfterEitherAsync(timeoutFuture, () -> {
- if (allHostFuture.isDone()) {
- log.info("{} hosts initialized. Move {} to the next phase", hostFutures.size(), devId);
- } else {
- log.info("Timeout reached. Move {} to the next phase", devId);
- }
- srManager.phasedRecoveryService.setPhase(devId, Phase.INFRA);
- });
- }
-
- private void initHost(Host host, DeviceId deviceId) {
- List<CompletableFuture<Objective>> locationFutures = Lists.newArrayList();
-
- effectiveLocations(host).forEach(location -> {
- if (location.deviceId().equals(deviceId) ||
- location.deviceId().equals(srManager.getPairDeviceId(deviceId).orElse(null))) {
- locationFutures.addAll(processHostAddedAtLocation(host, location));
- }
- });
-
- log.debug("{} locationFutures for {}", locationFutures.size(), host);
-
- // Waiting for all locationFutures to be completed.
- // This is a blocking operation but it is fine since this is run in a separate thread
- try {
- CompletableFuture.allOf(locationFutures.toArray(new CompletableFuture[0]))
- .thenApply(objectives -> locationFutures.stream()
- .map(CompletableFuture::join)
- .collect(Collectors.toList())
- )
- .get();
- } catch (InterruptedException | ExecutionException e) {
- log.warn("Exception caught when executing locationFutures");
- locationFutures.forEach(future -> future.cancel(false));
- }
- }
-
- void processHostAddedEvent(HostEvent event) {
- Host host = event.subject();
- hostWorkers.execute(() -> processHostAdded(host), host.id().hashCode());
- }
-
- private void processHostAdded(Host host) {
- effectiveLocations(host).forEach(location -> processHostAddedAtLocation(host, location));
- // ensure dual-homed host locations have viable uplinks
- if (effectiveLocations(host).size() > 1 || srManager.singleHomedDown) {
- effectiveLocations(host).forEach(loc -> {
- if (srManager.mastershipService.isLocalMaster(loc.deviceId())) {
- srManager.linkHandler.checkUplinksForHost(loc);
- }
- });
- }
- }
-
- List<CompletableFuture<Objective>> processHostAddedAtLocation(Host host, HostLocation location) {
- checkArgument(effectiveLocations(host).contains(location), "{} is not a location of {}", location, host);
-
- MacAddress hostMac = host.mac();
- VlanId hostVlanId = host.vlan();
- Set<HostLocation> locations = effectiveLocations(host);
- Set<IpAddress> ips = host.ipAddresses();
- log.info("Host {}/{} is added at {}", hostMac, hostVlanId, locations);
-
- List<CompletableFuture<Objective>> objectiveFutures = Lists.newArrayList();
-
- // TODO Phased recovery does not trace double tagged hosts
- if (isDoubleTaggedHost(host)) {
- ips.forEach(ip ->
- processDoubleTaggedRoutingRule(location.deviceId(), location.port(), hostMac,
- host.innerVlan(), hostVlanId, host.tpid(), ip, false)
- );
- } else {
- objectiveFutures.add(
- processBridgingRule(location.deviceId(), location.port(), hostMac, hostVlanId, false)
- );
- ips.forEach(ip ->
- objectiveFutures.add(
- processRoutingRule(location.deviceId(), location.port(), hostMac, hostVlanId, ip, false)
- )
- );
- }
-
- // Use the pair link temporarily before the second location of a dual-homed host shows up.
- // This do not affect single-homed hosts since the flow will be blocked in
- // processBridgingRule or processRoutingRule due to VLAN or IP mismatch respectively
- srManager.getPairDeviceId(location.deviceId()).ifPresent(pairDeviceId -> {
- if (effectiveLocations(host).stream().noneMatch(l -> l.deviceId().equals(pairDeviceId))) {
- srManager.getPairLocalPort(pairDeviceId).ifPresent(pairRemotePort -> {
- // NOTE: Since the pairLocalPort is trunk port, use assigned vlan of original port
- // when the host is untagged
- VlanId vlanId = vlanForPairPort(hostVlanId, location);
- if (vlanId == null) {
- return;
- }
-
- objectiveFutures.add(
- processBridgingRule(pairDeviceId, pairRemotePort, hostMac, vlanId, false)
- );
- ips.forEach(ip ->
- objectiveFutures.add(
- processRoutingRule(pairDeviceId, pairRemotePort, hostMac, vlanId, ip, false)
- )
- );
-
- if (srManager.activeProbing) {
- probe(host, location, pairDeviceId, pairRemotePort);
- }
- });
- }
- });
-
- int nextId = srManager.getMacVlanNextObjectiveId(location.deviceId(), hostMac, hostVlanId, null, false);
- if (nextId != -1) {
- VlanId vlanId = Optional.ofNullable(srManager.getInternalVlanId(location)).orElse(hostVlanId);
- log.debug(" Updating next objective for device {}, host {}/{}, port {}, nextid {}",
- location.deviceId(), hostMac, vlanId, location.port(), nextId);
- srManager.updateMacVlanTreatment(location.deviceId(), hostMac, vlanId,
- location.port(), nextId);
- }
-
- log.debug("{} objectiveFutures for {}", objectiveFutures.size(), location);
- return objectiveFutures;
- }
-
- void processHostRemovedEvent(HostEvent event) {
- Host host = event.subject();
- hostWorkers.execute(() -> processHostRemoved(host), host.id().hashCode());
- }
-
- private void processHostRemoved(Host host) {
- MacAddress hostMac = host.mac();
- VlanId hostVlanId = host.vlan();
- Set<HostLocation> locations = effectiveLocations(host);
- Set<IpAddress> ips = host.ipAddresses();
- log.info("Host {}/{} is removed from {}", hostMac, hostVlanId, locations);
-
- locations.forEach(location -> {
- if (isDoubleTaggedHost(host)) {
- ips.forEach(ip ->
- processDoubleTaggedRoutingRule(location.deviceId(), location.port(), hostMac,
- host.innerVlan(), hostVlanId, host.tpid(), ip, true)
- );
- } else {
- processBridgingRule(location.deviceId(), location.port(), hostMac, hostVlanId, true);
- ips.forEach(ip ->
- processRoutingRule(location.deviceId(), location.port(), hostMac, hostVlanId, ip, true)
- );
- }
-
- // Also remove redirection flows on the pair device if exists.
- Optional<DeviceId> pairDeviceId = srManager.getPairDeviceId(location.deviceId());
- Optional<PortNumber> pairLocalPort = srManager.getPairLocalPort(location.deviceId());
- if (pairDeviceId.isPresent() && pairLocalPort.isPresent()) {
- // NOTE: Since the pairLocalPort is trunk port, use assigned vlan of original port
- // when the host is untagged
- VlanId vlanId = vlanForPairPort(hostVlanId, location);
- if (vlanId == null) {
- return;
- }
-
- processBridgingRule(pairDeviceId.get(), pairLocalPort.get(), hostMac, vlanId, true);
- ips.forEach(ip ->
- processRoutingRule(pairDeviceId.get(), pairLocalPort.get(), hostMac, vlanId,
- ip, true));
- }
-
- // Delete prefix from sr-device-subnet when the next hop host is removed
- srManager.routeService.getRouteTables().forEach(tableId -> {
- srManager.routeService.getRoutes(tableId).forEach(routeInfo -> {
- if (routeInfo.allRoutes().stream().anyMatch(rr -> ips.contains(rr.nextHop()))) {
- log.debug("HostRemoved. removeSubnet {}, {}", location, routeInfo.prefix());
- srManager.deviceConfiguration.removeSubnet(location, routeInfo.prefix());
- }
- });
- });
-
- });
- }
-
- void processHostMovedEvent(HostEvent event) {
- Host host = event.subject();
- hostWorkers.execute(() -> processHostMovedEventInternal(event), host.id().hashCode());
- }
-
- private void processHostMovedEventInternal(HostEvent event) {
- // This method will be called when one of the following value has changed:
- // (1) locations (2) auxLocations or (3) both locations and auxLocations.
- // We only need to proceed when effectiveLocation has changed.
- Set<HostLocation> newLocations = effectiveLocations(event.subject());
- Set<HostLocation> prevLocations = effectiveLocations(event.prevSubject());
-
- if (newLocations.equals(prevLocations)) {
- log.info("effectiveLocations of {} has not changed. Skipping {}", event.subject().id(), event);
- return;
- }
-
- Host host = event.subject();
- Host prevHost = event.prevSubject();
- MacAddress hostMac = host.mac();
- VlanId hostVlanId = host.vlan();
- Set<IpAddress> prevIps = prevHost.ipAddresses();
- Set<IpAddress> newIps = host.ipAddresses();
- EthType hostTpid = host.tpid();
- boolean doubleTaggedHost = isDoubleTaggedHost(host);
-
- log.info("Host {}/{} is moved from {} to {}", hostMac, hostVlanId, prevLocations, newLocations);
- Set<DeviceId> newDeviceIds = newLocations.stream().map(HostLocation::deviceId)
- .collect(Collectors.toSet());
-
- // For each old location
- Sets.difference(prevLocations, newLocations).forEach(prevLocation -> {
- // Remove routing rules for old IPs
- Sets.difference(prevIps, newIps).forEach(ip -> {
- if (doubleTaggedHost) {
- processDoubleTaggedRoutingRule(prevLocation.deviceId(), prevLocation.port(),
- hostMac, host.innerVlan(), hostVlanId, hostTpid, ip, true);
- } else {
- processRoutingRule(prevLocation.deviceId(), prevLocation.port(), hostMac, hostVlanId,
- ip, true);
- }
- });
-
- // Redirect the flows to pair link if configured
- // Note: Do not continue removing any rule
- Optional<DeviceId> pairDeviceId = srManager.getPairDeviceId(prevLocation.deviceId());
- Optional<PortNumber> pairLocalPort = srManager.getPairLocalPort(prevLocation.deviceId());
- if (pairDeviceId.isPresent() && pairLocalPort.isPresent() &&
- newLocations.stream().anyMatch(location -> location.deviceId().equals(pairDeviceId.get())) &&
- newLocations.stream().noneMatch(location -> location.deviceId().equals(prevLocation.deviceId()))) {
- // NOTE: Since the pairLocalPort is trunk port, use assigned vlan of original port
- // when the host is untagged
- VlanId vlanId = Optional.ofNullable(srManager.getInternalVlanId(prevLocation)).orElse(hostVlanId);
-
- processBridgingRule(prevLocation.deviceId(), pairLocalPort.get(), hostMac, vlanId, false);
- newIps.forEach(ip ->
- processRoutingRule(prevLocation.deviceId(), pairLocalPort.get(), hostMac, vlanId,
- ip, false));
- return;
- }
-
- // Remove flows for unchanged IPs only when the host moves from a switch to another.
- // Otherwise, do not remove and let the adding part update the old flow
- if (!newDeviceIds.contains(prevLocation.deviceId())) {
- processBridgingRule(prevLocation.deviceId(), prevLocation.port(), hostMac, hostVlanId, true);
- Sets.intersection(prevIps, newIps).forEach(ip -> {
- if (doubleTaggedHost) {
- processDoubleTaggedRoutingRule(prevLocation.deviceId(), prevLocation.port(),
- hostMac, host.innerVlan(), hostVlanId, hostTpid, ip, true);
- } else {
- processRoutingRule(prevLocation.deviceId(), prevLocation.port(),
- hostMac, hostVlanId, ip, true);
- }
- });
- }
-
- // Remove bridging rules if new interface vlan is different from old interface vlan
- // Otherwise, do not remove and let the adding part update the old flow
- if (newLocations.stream().noneMatch(newLocation -> {
- VlanId oldAssignedVlan = srManager.getInternalVlanId(prevLocation);
- VlanId newAssignedVlan = srManager.getInternalVlanId(newLocation);
- // Host is tagged and the new location has the host vlan in vlan-tagged
- return srManager.interfaceService.getTaggedVlanId(newLocation).contains(hostVlanId) ||
- (oldAssignedVlan != null && newAssignedVlan != null &&
- // Host is untagged and the new location has the same assigned vlan
- oldAssignedVlan.equals(newAssignedVlan));
- })) {
- processBridgingRule(prevLocation.deviceId(), prevLocation.port(), hostMac, hostVlanId, true);
- }
-
- // Remove routing rules for unchanged IPs if none of the subnet of new location contains
- // the IP. Otherwise, do not remove and let the adding part update the old flow
- Sets.intersection(prevIps, newIps).forEach(ip -> {
- if (newLocations.stream().noneMatch(newLocation ->
- srManager.deviceConfiguration.inSameSubnet(newLocation, ip))) {
- if (doubleTaggedHost) {
- processDoubleTaggedRoutingRule(prevLocation.deviceId(), prevLocation.port(),
- hostMac, host.innerVlan(), hostVlanId, hostTpid, ip, true);
- } else {
- processRoutingRule(prevLocation.deviceId(), prevLocation.port(),
- hostMac, hostVlanId, ip, true);
- }
- }
- });
- });
-
- // For each new location, add all new IPs.
- Sets.difference(newLocations, prevLocations).forEach(newLocation -> {
- processBridgingRule(newLocation.deviceId(), newLocation.port(), hostMac, hostVlanId, false);
- newIps.forEach(ip -> {
- if (doubleTaggedHost) {
- processDoubleTaggedRoutingRule(newLocation.deviceId(), newLocation.port(),
- hostMac, host.innerVlan(), hostVlanId, hostTpid, ip, false);
- } else {
- processRoutingRule(newLocation.deviceId(), newLocation.port(), hostMac, hostVlanId,
- ip, false);
- }
- });
-
- // Probe on pair device when host move
- // Majorly for the 2nd step of [1A/x, 1B/x] -> [1A/x, 1B/y] -> [1A/y, 1B/y]
- // But will also cover [1A/x] -> [1A/y] -> [1A/y, 1B/y]
- if (srManager.activeProbing) {
-
- srManager.getPairDeviceId(newLocation.deviceId()).ifPresent(pairDeviceId ->
- srManager.getPairLocalPort(pairDeviceId).ifPresent(pairRemotePort ->
- probe(host, newLocation, pairDeviceId, pairRemotePort)
- )
- );
- }
- });
-
- // For each unchanged location, add new IPs and remove old IPs.
- Sets.intersection(newLocations, prevLocations).forEach(unchangedLocation -> {
- Sets.difference(prevIps, newIps).forEach(ip -> {
- if (doubleTaggedHost) {
- processDoubleTaggedRoutingRule(unchangedLocation.deviceId(), unchangedLocation.port(),
- hostMac, host.innerVlan(), hostVlanId, hostTpid, ip, true);
- } else {
- processRoutingRule(unchangedLocation.deviceId(), unchangedLocation.port(),
- hostMac, hostVlanId, ip, true);
- }
- });
-
- Sets.difference(newIps, prevIps).forEach(ip -> {
- if (doubleTaggedHost) {
- processDoubleTaggedRoutingRule(unchangedLocation.deviceId(), unchangedLocation.port(),
- hostMac, host.innerVlan(), hostVlanId, hostTpid, ip, false);
- } else {
- processRoutingRule(unchangedLocation.deviceId(), unchangedLocation.port(),
- hostMac, hostVlanId, ip, false);
- }
- });
-
- // Verify existing location and see if it is still valid
- srManager.probingService.probeHost(host, unchangedLocation, ProbeMode.VERIFY);
- });
-
- // ensure dual-homed host locations have viable uplinks
- if (newLocations.size() > prevLocations.size() || srManager.singleHomedDown) {
- newLocations.forEach(loc -> {
- if (srManager.mastershipService.isLocalMaster(loc.deviceId())) {
- srManager.linkHandler.checkUplinksForHost(loc);
- }
- });
- }
- }
-
- void processHostUpdatedEvent(HostEvent event) {
- Host host = event.subject();
- hostWorkers.execute(() -> processHostUpdatedEventInternal(event), host.id().hashCode());
- }
-
- private void processHostUpdatedEventInternal(HostEvent event) {
- Host host = event.subject();
- MacAddress hostMac = host.mac();
- VlanId hostVlanId = host.vlan();
- EthType hostTpid = host.tpid();
- Set<HostLocation> locations = effectiveLocations(host);
- Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
- Set<IpAddress> newIps = host.ipAddresses();
- log.info("Host {}/{} is updated", hostMac, hostVlanId);
-
- locations.forEach(location -> {
- Sets.difference(prevIps, newIps).forEach(ip -> {
- if (isDoubleTaggedHost(host)) {
- processDoubleTaggedRoutingRule(location.deviceId(), location.port(), hostMac,
- host.innerVlan(), hostVlanId, hostTpid, ip, true);
- } else {
- processRoutingRule(location.deviceId(), location.port(), hostMac,
- hostVlanId, ip, true);
- }
- });
- Sets.difference(newIps, prevIps).forEach(ip -> {
- if (isDoubleTaggedHost(host)) {
- processDoubleTaggedRoutingRule(location.deviceId(), location.port(), hostMac,
- host.innerVlan(), hostVlanId, hostTpid, ip, false);
- } else {
- processRoutingRule(location.deviceId(), location.port(), hostMac,
- hostVlanId, ip, false);
- }
- });
- });
-
- // Use the pair link temporarily before the second location of a dual-homed host shows up.
- // This do not affect single-homed hosts since the flow will be blocked in
- // processBridgingRule or processRoutingRule due to VLAN or IP mismatch respectively
- locations.forEach(location ->
- srManager.getPairDeviceId(location.deviceId()).ifPresent(pairDeviceId -> {
- if (locations.stream().noneMatch(l -> l.deviceId().equals(pairDeviceId))) {
- Set<IpAddress> ipsToAdd = Sets.difference(newIps, prevIps);
- Set<IpAddress> ipsToRemove = Sets.difference(prevIps, newIps);
-
- srManager.getPairLocalPort(pairDeviceId).ifPresent(pairRemotePort -> {
- // NOTE: Since the pairLocalPort is trunk port, use assigned vlan of original port
- // when the host is untagged
- VlanId vlanId = vlanForPairPort(hostVlanId, location);
- if (vlanId == null) {
- return;
- }
-
- ipsToRemove.forEach(ip ->
- processRoutingRule(pairDeviceId, pairRemotePort, hostMac, vlanId, ip, true)
- );
- ipsToAdd.forEach(ip ->
- processRoutingRule(pairDeviceId, pairRemotePort, hostMac, vlanId, ip, false)
- );
-
- if (srManager.activeProbing) {
- probe(host, location, pairDeviceId, pairRemotePort);
- }
- });
- }
- })
- );
- }
-
- /**
- * When a non-pair port comes up, probe each host on the pair device if
- * (1) the host is tagged and the tagged vlan of current port contains host vlan; or
- * (2) the host is untagged and the internal vlan is the same on the host port and current port.
- *
- * @param cp connect point
- */
- // TODO Current implementation does not handle dual-homed hosts with auxiliary locations.
- void processPortUp(ConnectPoint cp) {
- if (cp.port().equals(srManager.getPairLocalPort(cp.deviceId()).orElse(null))) {
- return;
- }
- if (srManager.activeProbing) {
- srManager.getPairDeviceId(cp.deviceId())
- .ifPresent(pairDeviceId -> srManager.hostService.getConnectedHosts(pairDeviceId).forEach(
- host -> hostWorkers.execute(() -> probingIfNecessary(host, pairDeviceId, cp),
- host.id().hashCode())));
- }
- }
-
- // TODO Current implementation does not handle dual-homed hosts with auxiliary locations.
- private void probingIfNecessary(Host host, DeviceId pairDeviceId, ConnectPoint cp) {
- if (isHostInVlanOfPort(host, pairDeviceId, cp)) {
- srManager.probingService.probeHost(host, cp, ProbeMode.DISCOVER);
- }
- }
-
- /**
- * Checks if given host located on given device id matches VLAN config of current port.
- *
- * @param host host to check
- * @param deviceId device id to check
- * @param cp current connect point
- * @return true if the host located at deviceId matches the VLAN config on cp
- */
- private boolean isHostInVlanOfPort(Host host, DeviceId deviceId, ConnectPoint cp) {
- VlanId internalVlan = srManager.getInternalVlanId(cp);
- Set<VlanId> taggedVlan = srManager.interfaceService.getTaggedVlanId(cp);
-
- return taggedVlan.contains(host.vlan()) ||
- (internalVlan != null && effectiveLocations(host).stream()
- .filter(l -> l.deviceId().equals(deviceId))
- .map(srManager::getInternalVlanId)
- .anyMatch(internalVlan::equals));
- }
-
- /**
- * Send a probe on all locations with the same VLAN on pair device, excluding pair port.
- *
- * @param host host to probe
- * @param location newly discovered host location
- * @param pairDeviceId pair device id
- * @param pairRemotePort pair remote port
- */
- // TODO Current implementation does not handle dual-homed hosts with auxiliary locations.
- private void probe(Host host, ConnectPoint location, DeviceId pairDeviceId, PortNumber pairRemotePort) {
- //Check if the host still exists in the host store
- if (hostService.getHost(host.id()) == null) {
- log.debug("Host entry for host {} no more present. Aborting hostprobe discover for this host", host.id());
- return;
- }
-
- VlanId vlanToProbe = host.vlan().equals(VlanId.NONE) ?
- srManager.getInternalVlanId(location) : host.vlan();
- if (srManager.symmetricProbing) {
- srManager.interfaceService.getInterfaces().stream()
- .filter(i -> i.vlanTagged().contains(vlanToProbe) ||
- i.vlanUntagged().equals(vlanToProbe) ||
- i.vlanNative().equals(vlanToProbe))
- .filter(i -> i.connectPoint().deviceId().equals(pairDeviceId))
- .filter(i -> i.connectPoint().port().equals(location.port()))
- .forEach(i -> {
- log.debug("Probing host {} on pair device {}", host.id(), i.connectPoint());
- srManager.probingService.probeHost(host, i.connectPoint(), ProbeMode.DISCOVER);
- });
- } else {
- srManager.interfaceService.getInterfaces().stream()
- .filter(i -> i.vlanTagged().contains(vlanToProbe) ||
- i.vlanUntagged().equals(vlanToProbe) ||
- i.vlanNative().equals(vlanToProbe))
- .filter(i -> i.connectPoint().deviceId().equals(pairDeviceId))
- .filter(i -> !i.connectPoint().port().equals(pairRemotePort))
- .forEach(i -> {
- log.debug("Probing host {} on pair device {}", host.id(), i.connectPoint());
- srManager.probingService.probeHost(host, i.connectPoint(), ProbeMode.DISCOVER);
- });
- }
- }
-
- /**
- * Populates or revokes a bridging rule on given deviceId that matches given mac,
- * given vlan and output to given port.
- *
- * @param deviceId device ID
- * @param port port
- * @param mac mac address
- * @param vlanId VLAN ID
- * @param revoke true to revoke the rule; false to populate
- * @return future that includes the flow objective if succeeded, null if otherwise
- */
- private CompletableFuture<Objective> processBridgingRule(DeviceId deviceId, PortNumber port, MacAddress mac,
- VlanId vlanId, boolean revoke) {
- log.info("{} bridging entry for host {}/{} at {}:{}", revoke ? "Revoking" : "Populating",
- mac, vlanId, deviceId, port);
-
- if (!revoke) {
- return srManager.defaultRoutingHandler.populateBridging(deviceId, port, mac, vlanId);
- } else {
- return srManager.defaultRoutingHandler.revokeBridging(deviceId, port, mac, vlanId);
- }
- }
-
- /**
- * Populate or revoke a routing rule on given deviceId that matches given ip,
- * set destination mac to given mac, set vlan to given vlan and output to given port.
- *
- * @param deviceId device ID
- * @param port port
- * @param mac mac address
- * @param vlanId VLAN ID
- * @param ip IP address
- * @param revoke true to revoke the rule; false to populate
- * @return future that includes the flow objective if succeeded, null if otherwise
- */
- private CompletableFuture<Objective> processRoutingRule(DeviceId deviceId, PortNumber port, MacAddress mac,
- VlanId vlanId, IpAddress ip, boolean revoke) {
- ConnectPoint location = new ConnectPoint(deviceId, port);
- if (!srManager.deviceConfiguration.inSameSubnet(location, ip)) {
- log.info("{} is not included in the subnet config of {}/{}. Ignored.", ip, deviceId, port);
- return CompletableFuture.completedFuture(null);
- }
-
- log.info("{} routing rule for {} at {}", revoke ? "Revoking" : "Populating", ip, location);
- if (revoke) {
- return srManager.defaultRoutingHandler.revokeRoute(deviceId, ip.toIpPrefix(), mac, vlanId, port, true);
- } else {
- return srManager.defaultRoutingHandler.populateRoute(deviceId, ip.toIpPrefix(), mac, vlanId, port, true);
- }
- }
-
- /**
- * Populate or revoke a routing rule and egress rules on given deviceId that matches given IP,
- * to set destination mac to given mac, set inner vlan and outer vlan to given vlans,
- * set outer TPID, and output to given port.
- *
- * @param deviceId device ID
- * @param port port
- * @param mac mac address
- * @param innerVlan inner VLAN ID
- * @param outerVlan outer VLAN ID
- * @param outerTpid outer TPID
- * @param ip IP address
- * @param revoke true to revoke the rule; false to populate
- */
- private void processDoubleTaggedRoutingRule(DeviceId deviceId, PortNumber port,
- MacAddress mac, VlanId innerVlan,
- VlanId outerVlan, EthType outerTpid,
- IpAddress ip, boolean revoke) {
- if (!srManager.routeDoubleTaggedHosts) {
- log.debug("Routing for double tagged host is disabled. Ignore {}/{}/{}", mac, outerVlan, innerVlan);
- return;
- }
-
- ConnectPoint location = new ConnectPoint(deviceId, port);
- if (!srManager.deviceConfiguration.inSameSubnet(location, ip)) {
- log.info("{} is not included in the subnet config of {}/{}. Ignored.", ip, deviceId, port);
- return;
- }
- log.info("{} routing rule for double-tagged host {} at {}",
- revoke ? "Revoking" : "Populating", ip, location);
- if (revoke) {
- srManager.defaultRoutingHandler.revokeDoubleTaggedRoute(
- deviceId, ip.toIpPrefix(), mac, innerVlan, outerVlan, outerTpid, port);
- } else {
- srManager.defaultRoutingHandler.populateDoubleTaggedRoute(
- deviceId, ip.toIpPrefix(), mac, innerVlan, outerVlan, outerTpid, port);
- }
- }
-
- void populateAllDoubleTaggedHost() {
- log.info("Enabling routing for all double tagged hosts");
- Sets.newHashSet(srManager.hostService.getHosts()).stream().filter(this::isDoubleTaggedHost)
- .forEach(h -> effectiveLocations(h).forEach(l ->
- h.ipAddresses().forEach(i ->
- processDoubleTaggedRoutingRule(l.deviceId(), l.port(), h.mac(), h.innerVlan(),
- h.vlan(), h.tpid(), i, false)
- )
- )
- );
- }
-
- void revokeAllDoubleTaggedHost() {
- log.info("Disabling routing for all double tagged hosts");
- Sets.newHashSet(srManager.hostService.getHosts()).stream().filter(this::isDoubleTaggedHost)
- .forEach(h -> effectiveLocations(h).forEach(l ->
- h.ipAddresses().forEach(i ->
- processDoubleTaggedRoutingRule(l.deviceId(), l.port(), h.mac(), h.innerVlan(),
- h.vlan(), h.tpid(), i, true)
- )
- )
- );
- }
-
- /**
- * Returns VLAN ID to be used to program redirection flow on pair port.
- *
- * @param hostVlanId host VLAN ID
- * @param location host location
- * @return VLAN ID to be used; Or null if host VLAN does not match the interface config
- */
- VlanId vlanForPairPort(VlanId hostVlanId, ConnectPoint location) {
- VlanId internalVlan = srManager.getInternalVlanId(location);
- Set<VlanId> taggedVlan = srManager.interfaceService.getTaggedVlanId(location);
-
- if (!hostVlanId.equals(VlanId.NONE) && taggedVlan.contains(hostVlanId)) {
- return hostVlanId;
- } else if (hostVlanId.equals(VlanId.NONE) && internalVlan != null) {
- return internalVlan;
- } else {
- log.warn("VLAN mismatch. hostVlan={}, location={}, internalVlan={}, taggedVlan={}",
- hostVlanId, location, internalVlan, taggedVlan);
- return null;
- }
- }
-
- /**
- * Update forwarding objective for unicast bridging and unicast routing.
- * Also check the validity of updated interface configuration on VLAN.
- *
- * @param deviceId device ID that host attaches to
- * @param portNum port number that host attaches to
- * @param vlanId Vlan ID configured on the switch port
- * @param popVlan true to pop Vlan tag at TrafficTreatment, false otherwise
- * @param install true to populate the objective, false to revoke
- */
- // TODO Current implementation does not handle dual-homed hosts with auxiliary locations.
- void processIntfVlanUpdatedEvent(DeviceId deviceId, PortNumber portNum, VlanId vlanId,
- boolean popVlan, boolean install) {
- ConnectPoint connectPoint = new ConnectPoint(deviceId, portNum);
- Set<Host> hosts = hostService.getConnectedHosts(connectPoint);
-
- if (hosts == null || hosts.size() == 0) {
- log.debug("processIntfVlanUpdatedEvent: No hosts connected to {}", connectPoint);
- return;
- }
-
- hosts.forEach(host -> hostWorkers.execute(() -> processIntfVlanUpdatedEventInternal(
- host, deviceId, portNum, vlanId, popVlan, install), host.id().hashCode()));
- }
-
- private void processIntfVlanUpdatedEventInternal(Host host, DeviceId deviceId, PortNumber portNum,
- VlanId vlanId, boolean popVlan, boolean install) {
- MacAddress mac = host.mac();
- VlanId hostVlanId = host.vlan();
-
- if (!install) {
- // Do not check the host validity. Just remove all rules corresponding to the vlan id
- // Revoke forwarding objective for bridging to the host
- srManager.defaultRoutingHandler.updateBridging(deviceId, portNum, mac, vlanId, popVlan, false);
-
- // Revoke forwarding objective and corresponding simple Next objective
- // for each Host and IP address connected to given port
- host.ipAddresses().forEach(ipAddress ->
- srManager.routingRulePopulator.updateFwdObj(deviceId, portNum, ipAddress.toIpPrefix(),
- mac, vlanId, popVlan, false)
- );
- } else {
- // Check whether the host vlan is valid for new interface configuration
- if ((!popVlan && hostVlanId.equals(vlanId)) ||
- (popVlan && hostVlanId.equals(VlanId.NONE))) {
- srManager.defaultRoutingHandler.updateBridging(deviceId, portNum, mac, vlanId, popVlan, true);
- // Update Forwarding objective and corresponding simple Next objective
- // for each Host and IP address connected to given port
- host.ipAddresses().forEach(ipAddress ->
- srManager.routingRulePopulator.updateFwdObj(deviceId, portNum, ipAddress.toIpPrefix(),
- mac, vlanId, popVlan, true)
- );
- }
- }
- }
-
- /**
- * Populate or revoke routing rule for each host, according to the updated
- * subnet configuration on the interface.
- * @param cp connect point of the updated interface
- * @param ipPrefixSet IP Prefixes added or removed
- * @param install true if IP Prefixes added, false otherwise
- */
- // TODO Current implementation does not handle dual-homed hosts with auxiliary locations.
- void processIntfIpUpdatedEvent(ConnectPoint cp, Set<IpPrefix> ipPrefixSet, boolean install) {
- Set<Host> hosts = hostService.getConnectedHosts(cp);
-
- if (hosts == null || hosts.size() == 0) {
- log.debug("processIntfIpUpdatedEvent: No hosts connected to {}", cp);
- return;
- }
-
- // Check whether the host IP address is in the interface's subnet
- hosts.forEach(host -> hostWorkers.execute(() -> processIntfIpUpdatedEventInternal(
- host, cp, ipPrefixSet, install)));
- }
-
- private void processIntfIpUpdatedEventInternal(Host host, ConnectPoint cp, Set<IpPrefix> ipPrefixSet,
- boolean install) {
- host.ipAddresses().forEach(hostIpAddress -> {
- ipPrefixSet.forEach(ipPrefix -> {
- if (install && ipPrefix.contains(hostIpAddress)) {
- srManager.defaultRoutingHandler.populateRoute(cp.deviceId(), hostIpAddress.toIpPrefix(),
- host.mac(), host.vlan(), cp.port(), true);
- } else if (!install && ipPrefix.contains(hostIpAddress)) {
- srManager.defaultRoutingHandler.revokeRoute(cp.deviceId(), hostIpAddress.toIpPrefix(),
- host.mac(), host.vlan(), cp.port(), true);
- }
- });
- });
- }
-
- /**
- * Returns the set of portnumbers on the given device that are part of the
- * locations for dual-homed hosts.
- *
- * @param deviceId the given deviceId
- * @return set of port numbers on given device that are dual-homed host
- * locations. May be empty if no dual homed hosts are connected to
- * the given device
- */
- Set<PortNumber> getDualHomedHostPorts(DeviceId deviceId) {
- Set<PortNumber> dualHomedLocations = new HashSet<>();
- srManager.hostService.getConnectedHosts(deviceId).stream()
- .filter(host -> effectiveLocations(host).size() == 2)
- .forEach(host -> effectiveLocations(host).stream()
- .filter(loc -> loc.deviceId().equals(deviceId))
- .forEach(loc -> dualHomedLocations.add(loc.port())));
- return dualHomedLocations;
- }
-
- /**
- * Checks if the given host is double-tagged or not.
- *
- * @param host host to check
- * @return true if it is double-tagged, false otherwise
- */
- private boolean isDoubleTaggedHost(Host host) {
- return !host.innerVlan().equals(VlanId.NONE);
- }
-
- /**
- * Returns effective locations of given host.
- *
- * @param host host to check
- * @return auxLocations of the host if exists, or locations of the host otherwise.
- */
- Set<HostLocation> effectiveLocations(Host host) {
- return (host.auxLocations() != null) ? host.auxLocations() : host.locations();
- }
-
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java b/app/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
deleted file mode 100644
index fc3dd17..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
+++ /dev/null
@@ -1,558 +0,0 @@
-/*
- * Copyright 2015-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;
-
-import org.onlab.packet.Ethernet;
-import org.onlab.packet.ICMP;
-import org.onlab.packet.ICMP6;
-import org.onlab.packet.IPv4;
-import org.onlab.packet.IPv6;
-import org.onlab.packet.Ip4Address;
-import org.onlab.packet.Ip6Address;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.MPLS;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
-import org.onlab.packet.ndp.NeighborSolicitation;
-import org.onosproject.net.neighbour.NeighbourMessageContext;
-import org.onosproject.net.neighbour.NeighbourMessageType;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.intf.Interface;
-import org.onosproject.net.flow.DefaultTrafficTreatment;
-import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.host.HostService;
-import org.onosproject.net.packet.DefaultOutboundPacket;
-import org.onosproject.net.packet.OutboundPacket;
-import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
-import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/**
- * Handler of ICMP packets that responses or forwards ICMP packets that
- * are sent to the controller.
- */
-public class IcmpHandler extends SegmentRoutingNeighbourHandler {
-
- private static Logger log = LoggerFactory.getLogger(IcmpHandler.class);
-
- /**
- * Creates an IcmpHandler object.
- *
- * @param srManager SegmentRoutingManager object
- */
- public IcmpHandler(SegmentRoutingManager srManager) {
- super(srManager);
- }
-
- /**
- * Utility function to send packet out.
- *
- * @param outport the output port
- * @param payload the packet to send
- * @param destSid the segment id of the dest device
- * @param destIpAddress the destination ip address
- * @param allowedHops the hop limit/ttl
- */
- private void sendPacketOut(ConnectPoint outport,
- Ethernet payload,
- int destSid,
- IpAddress destIpAddress,
- byte allowedHops) {
- int origSid;
- try {
- if (destIpAddress.isIp4()) {
- origSid = config.getIPv4SegmentId(outport.deviceId());
- } else {
- origSid = config.getIPv6SegmentId(outport.deviceId());
- }
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage() + " Aborting sendPacketOut");
- return;
- }
-
- if (destSid == -1 || origSid == destSid ||
- srManager.interfaceService.isConfigured(outport)) {
- TrafficTreatment treatment = DefaultTrafficTreatment.builder().
- setOutput(outport.port()).build();
- OutboundPacket packet = new DefaultOutboundPacket(outport.deviceId(),
- treatment, ByteBuffer.wrap(payload.serialize()));
- log.trace("Sending packet {} to {}", payload, outport);
- srManager.packetService.emit(packet);
- } else {
- TrafficTreatment treatment = DefaultTrafficTreatment.builder()
- .setOutput(outport.port())
- .build();
-
- payload.setEtherType(Ethernet.MPLS_UNICAST);
- MPLS mplsPkt = new MPLS();
- mplsPkt.setLabel(destSid);
- mplsPkt.setTtl(allowedHops);
- mplsPkt.setPayload(payload.getPayload());
- payload.setPayload(mplsPkt);
- OutboundPacket packet = new DefaultOutboundPacket(outport.deviceId(),
- treatment, ByteBuffer.wrap(payload.serialize()));
- log.trace("Sending packet {} to {}", payload, outport);
- srManager.packetService.emit(packet);
- }
- }
-
- private IpAddress selectRouterIpAddress(IpAddress destIpAddress, ConnectPoint outPort,
- Set<ConnectPoint> connectPoints) {
- IpAddress routerIpAddress;
- // Let's get first the online connect points
- Set<ConnectPoint> onlineCps = connectPoints.stream()
- .filter(connectPoint -> srManager.deviceService.isAvailable(connectPoint.deviceId()))
- .collect(Collectors.toSet());
- // Check if ping is local
- if (onlineCps.contains(outPort)) {
- routerIpAddress = config.getRouterIpAddress(destIpAddress, outPort.deviceId());
- log.trace("Local ping received from {} - send to {}", destIpAddress, routerIpAddress);
- return routerIpAddress;
- }
- // Check if it comes from a remote device. Loopbacks are sorted comparing byte by byte
- // FIXME if we lose both links from the chosen leaf to spine - ping will fail
- routerIpAddress = onlineCps.stream()
- .filter(onlineCp -> !onlineCp.deviceId().equals(outPort.deviceId()))
- .map(selectedCp -> config.getRouterIpAddress(destIpAddress, selectedCp.deviceId()))
- .filter(Objects::nonNull)
- .sorted()
- .findFirst().orElse(null);
- if (routerIpAddress != null) {
- log.trace("Remote ping received from {} - send to {}", destIpAddress, routerIpAddress);
- } else {
- log.warn("Not found a valid loopback for ping coming from {} - {}", destIpAddress, outPort);
- }
- return routerIpAddress;
- }
-
- private Ip4Address selectRouterIp4Address(IpAddress destIpAddress, ConnectPoint outPort,
- Set<ConnectPoint> connectPoints) {
- IpAddress routerIpAddress = selectRouterIpAddress(destIpAddress, outPort, connectPoints);
- return routerIpAddress != null ? routerIpAddress.getIp4Address() : null;
- }
-
- private Ip6Address selectRouterIp6Address(IpAddress destIpAddress, ConnectPoint outPort,
- Set<ConnectPoint> connectPoints) {
- IpAddress routerIpAddress = selectRouterIpAddress(destIpAddress, outPort, connectPoints);
- return routerIpAddress != null ? routerIpAddress.getIp6Address() : null;
- }
-
- //////////////////////////////////////
- // ICMP Echo/Reply Protocol //
- //////////////////////////////////////
-
- /**
- * Process incoming ICMP packet.
- * If it is an ICMP request to router, then sends an ICMP response.
- * Otherwise ignore the packet.
- *
- * @param eth inbound ICMP packet
- * @param inPort the input port
- */
- public void processIcmp(Ethernet eth, ConnectPoint inPort) {
- DeviceId deviceId = inPort.deviceId();
- IPv4 ipv4Packet = (IPv4) eth.getPayload();
- ICMP icmp = (ICMP) ipv4Packet.getPayload();
- Ip4Address destinationAddress = Ip4Address.valueOf(ipv4Packet.getDestinationAddress());
- Set<IpAddress> gatewayIpAddresses = config.getPortIPs(deviceId);
- IpAddress routerIp;
-
- // Only proceed with echo request
- if (icmp.getIcmpType() != ICMP.TYPE_ECHO_REQUEST) {
- return;
- }
-
- try {
- routerIp = config.getRouterIpv4(deviceId);
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage() + " Aborting processPacketIn.");
- return;
- }
-
- // Get pair ip - if it exists
- IpAddress pairRouterIp;
- try {
- DeviceId pairDeviceId = config.getPairDeviceId(deviceId);
- pairRouterIp = pairDeviceId != null ? config.getRouterIpv4(pairDeviceId) : null;
- } catch (DeviceConfigNotFoundException e) {
- pairRouterIp = null;
- }
-
- // ICMP to the router IP or gateway IP
- if (destinationAddress.equals(routerIp.getIp4Address()) ||
- (pairRouterIp != null && destinationAddress.equals(pairRouterIp.getIp4Address())) ||
- gatewayIpAddresses.contains(destinationAddress)) {
- sendIcmpResponse(eth, inPort);
- } else {
- log.trace("Ignore ICMP that targets for {}", destinationAddress);
- }
- }
-
- /**
- * Sends an ICMP reply message.
- *
- * @param icmpRequest the original ICMP request
- * @param outport the output port where the ICMP reply should be sent to
- */
- private void sendIcmpResponse(Ethernet icmpRequest, ConnectPoint outport) {
- Ethernet icmpReplyEth = ICMP.buildIcmpReply(icmpRequest);
- IPv4 icmpRequestIpv4 = (IPv4) icmpRequest.getPayload();
- IPv4 icmpReplyIpv4 = (IPv4) icmpReplyEth.getPayload();
- Ip4Address destIpAddress = Ip4Address.valueOf(icmpRequestIpv4.getSourceAddress());
-
- // Get the available connect points
- Set<ConnectPoint> destConnectPoints = config.getConnectPointsForASubnetHost(destIpAddress);
- // Select a router
- Ip4Address destRouterAddress = selectRouterIp4Address(destIpAddress, outport, destConnectPoints);
-
- // Note: Source IP of the ICMP request doesn't belong to any configured subnet.
- // The source might be an indirectly attached host (e.g. behind a router)
- // Lookup the route store for the nexthop instead.
- if (destRouterAddress == null) {
- Optional<DeviceId> deviceId = srManager.routeService
- .longestPrefixLookup(destIpAddress).map(srManager::nextHopLocations)
- .flatMap(locations -> locations.stream().findFirst())
- .map(ConnectPoint::deviceId);
- if (deviceId.isPresent()) {
- try {
- destRouterAddress = config.getRouterIpv4(deviceId.get());
- } catch (DeviceConfigNotFoundException e) {
- log.warn("Device config for {} not found. Abort ICMP processing", deviceId);
- return;
- }
- }
- }
-
- int destSid = config.getIPv4SegmentId(destRouterAddress);
- if (destSid < 0) {
- log.warn("Failed to lookup SID of the switch that {} attaches to. " +
- "Unable to process ICMP request.", destIpAddress);
- return;
- }
- sendPacketOut(outport, icmpReplyEth, destSid, destIpAddress, icmpReplyIpv4.getTtl());
- }
-
- ///////////////////////////////////////////
- // ICMPv6 Echo/Reply Protocol //
- ///////////////////////////////////////////
-
- /**
- * Process incoming ICMPv6 packet.
- * If it is an ICMPv6 request to router, then sends an ICMPv6 response.
- * Otherwise ignore the packet.
- *
- * @param eth the incoming ICMPv6 packet
- * @param inPort the input port
- */
- public void processIcmpv6(Ethernet eth, ConnectPoint inPort) {
- DeviceId deviceId = inPort.deviceId();
- IPv6 ipv6Packet = (IPv6) eth.getPayload();
- ICMP6 icmp6 = (ICMP6) ipv6Packet.getPayload();
- Ip6Address destinationAddress = Ip6Address.valueOf(ipv6Packet.getDestinationAddress());
- Set<IpAddress> gatewayIpAddresses = config.getPortIPs(deviceId);
- IpAddress routerIp;
-
- // Only proceed with echo request
- if (icmp6.getIcmpType() != ICMP6.ECHO_REQUEST) {
- return;
- }
-
- try {
- routerIp = config.getRouterIpv6(deviceId);
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage() + " Aborting processPacketIn.");
- return;
- }
-
- // Get pair ip - if it exists
- IpAddress pairRouterIp;
- try {
- DeviceId pairDeviceId = config.getPairDeviceId(deviceId);
- pairRouterIp = pairDeviceId != null ? config.getRouterIpv6(pairDeviceId) : null;
- } catch (DeviceConfigNotFoundException e) {
- pairRouterIp = null;
- }
-
- Optional<Ip6Address> linkLocalIp = getLinkLocalIp(inPort);
- // Ensure ICMP to the router IP, EUI-64 link-local IP, or gateway IP
- if (destinationAddress.equals(routerIp.getIp6Address()) ||
- (linkLocalIp.isPresent() && destinationAddress.equals(linkLocalIp.get())) ||
- (pairRouterIp != null && destinationAddress.equals(pairRouterIp.getIp6Address())) ||
- gatewayIpAddresses.contains(destinationAddress)) {
- sendIcmpv6Response(eth, inPort);
- } else {
- log.trace("Ignore ICMPv6 that targets for {}", destinationAddress);
- }
- }
-
- /**
- * Sends an ICMPv6 reply message.
- *
- * @param ethRequest the original ICMP request
- * @param outport the output port where the ICMP reply should be sent to
- */
- private void sendIcmpv6Response(Ethernet ethRequest, ConnectPoint outport) {
- int destSid = -1;
- Ethernet ethReply = ICMP6.buildIcmp6Reply(ethRequest);
- IPv6 icmpRequestIpv6 = (IPv6) ethRequest.getPayload();
- IPv6 icmpReplyIpv6 = (IPv6) ethRequest.getPayload();
- // Source IP of the echo "reply"
- Ip6Address srcIpAddress = Ip6Address.valueOf(icmpRequestIpv6.getDestinationAddress());
- // Destination IP of the echo "reply"
- Ip6Address destIpAddress = Ip6Address.valueOf(icmpRequestIpv6.getSourceAddress());
- Optional<Ip6Address> linkLocalIp = getLinkLocalIp(outport);
-
- // Fast path if the echo request targets the link-local address of switch interface
- if (linkLocalIp.isPresent() && srcIpAddress.equals(linkLocalIp.get())) {
- sendPacketOut(outport, ethReply, destSid, destIpAddress, icmpReplyIpv6.getHopLimit());
- return;
- }
-
- // Get the available connect points
- Set<ConnectPoint> destConnectPoints = config.getConnectPointsForASubnetHost(destIpAddress);
- // Select a router
- Ip6Address destRouterAddress = selectRouterIp6Address(destIpAddress, outport, destConnectPoints);
-
- // Note: Source IP of the ICMP request doesn't belong to any configured subnet.
- // The source might be an indirect host behind a router.
- // Lookup the route store for the nexthop instead.
- if (destRouterAddress == null) {
- Optional<DeviceId> deviceId = srManager.routeService
- .longestPrefixLookup(destIpAddress).map(srManager::nextHopLocations)
- .flatMap(locations -> locations.stream().findFirst())
- .map(ConnectPoint::deviceId);
- if (deviceId.isPresent()) {
- try {
- destRouterAddress = config.getRouterIpv6(deviceId.get());
- } catch (DeviceConfigNotFoundException e) {
- log.warn("Device config for {} not found. Abort ICMPv6 processing", deviceId);
- return;
- }
- }
- }
-
- destSid = config.getIPv6SegmentId(destRouterAddress);
- if (destSid < 0) {
- log.warn("Failed to lookup SID of the switch that {} attaches to. " +
- "Unable to process ICMPv6 request.", destIpAddress);
- return;
- }
- sendPacketOut(outport, ethReply, destSid, destIpAddress, icmpReplyIpv6.getHopLimit());
- }
-
- ///////////////////////////////////////////
- // ICMPv6 Neighbour Discovery Protocol //
- ///////////////////////////////////////////
-
- /**
- * Process incoming NDP packet.
- *
- * If it is an NDP request for the router or for the gateway, then sends a NDP reply.
- * If it is an NDP request to unknown host flood in the subnet.
- * If it is an NDP packet to known host forward the packet to the host.
- *
- * FIXME If the NDP packets use link local addresses we fail.
- *
- * @param pkt inbound packet
- * @param hostService the host service
- */
- public void processPacketIn(NeighbourMessageContext pkt, HostService hostService) {
- // First we validate the ndp packet
- SegmentRoutingAppConfig appConfig = srManager.cfgService
- .getConfig(srManager.appId, SegmentRoutingAppConfig.class);
- if (appConfig != null && appConfig.suppressSubnet().contains(pkt.inPort())) {
- // Ignore NDP packets come from suppressed ports
- pkt.drop();
- return;
- }
-
- if (pkt.type() == NeighbourMessageType.REQUEST) {
- handleNdpRequest(pkt, hostService);
- } else {
- handleNdpReply(pkt, hostService);
- }
-
- }
-
- /**
- * Helper method to handle the ndp requests.
- * @param pkt the ndp packet request and context information
- * @param hostService the host service
- */
- private void handleNdpRequest(NeighbourMessageContext pkt, HostService hostService) {
- // ND request for the gateway. We have to reply on behalf of the gateway.
- if (isNdpForGateway(pkt)) {
- log.trace("Sending NDP reply on behalf of gateway IP for pkt: {}", pkt.target());
- MacAddress routerMac = config.getRouterMacForAGatewayIp(pkt.target());
- if (routerMac == null) {
- log.warn("Router MAC of {} is not configured. Cannot handle NDP request from {}",
- pkt.inPort().deviceId(), pkt.sender());
- return;
- }
- sendResponse(pkt, routerMac, hostService, true);
- } else {
-
- // Process NDP targets towards EUI-64 address.
- try {
- DeviceId deviceId = pkt.inPort().deviceId();
-
- Optional<Ip6Address> linkLocalIp = getLinkLocalIp(pkt.inPort());
- if (linkLocalIp.isPresent() && pkt.target().equals(linkLocalIp.get())) {
- MacAddress routerMac = config.getDeviceMac(deviceId);
- sendResponse(pkt, routerMac, hostService, true);
- }
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage() + " Unable to handle NDP packet to {}. Aborting.", pkt.target());
- return;
- }
-
- // NOTE: Ignore NDP packets except those target for the router
- // We will reconsider enabling this when we have host learning support
- /*
- // ND request for an host. We do a search by Ip.
- Set<Host> hosts = hostService.getHostsByIp(pkt.target());
- // Possible misconfiguration ? In future this case
- // should be handled we can have same hosts in different VLANs.
- if (hosts.size() > 1) {
- log.warn("More than one host with IP {}", pkt.target());
- }
- Host targetHost = hosts.stream().findFirst().orElse(null);
- // If we know the host forward to its attachment point.
- if (targetHost != null) {
- log.debug("Forward NDP request to the target host");
- pkt.forward(targetHost.location());
- } else {
- // Flood otherwise.
- log.debug("Flood NDP request to the target subnet");
- flood(pkt);
- }
- */
- }
- }
-
- /**
- * Helper method to handle the ndp replies.
- *
- * @param pkt the ndp packet reply and context information
- * @param hostService the host service
- */
- private void handleNdpReply(NeighbourMessageContext pkt, HostService hostService) {
- if (isNdpForGateway(pkt)) {
- log.debug("Forwarding all the ip packets we stored");
- Ip6Address hostIpAddress = pkt.sender().getIp6Address();
- srManager.ipHandler.forwardPackets(pkt.inPort().deviceId(), hostIpAddress);
- } else {
- // NOTE: Ignore NDP packets except those target for the router
- // We will reconsider enabling this when we have host learning support
- /*
- HostId hostId = HostId.hostId(pkt.dstMac(), pkt.vlan());
- Host targetHost = hostService.getHost(hostId);
- if (targetHost != null) {
- log.debug("Forwarding the reply to the host");
- pkt.forward(targetHost.location());
- } else {
- // We don't have to flood towards spine facing ports.
- if (pkt.vlan().equals(SegmentRoutingManager.INTERNAL_VLAN)) {
- return;
- }
- log.debug("Flooding the reply to the subnet");
- flood(pkt);
- }
- */
- }
- }
-
- /**
- * Utility to verify if the ND are for the gateway.
- *
- * @param pkt the ndp packet
- * @return true if the ndp is for the gateway. False otherwise
- */
- private boolean isNdpForGateway(NeighbourMessageContext pkt) {
- DeviceId deviceId = pkt.inPort().deviceId();
- Set<IpAddress> gatewayIpAddresses = null;
-
- try {
- if (pkt.target().equals(config.getRouterIpv6(deviceId))) {
- return true;
- }
- gatewayIpAddresses = config.getPortIPs(deviceId);
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage() + " Aborting check for router IP in processing ndp");
- return false;
- }
- return gatewayIpAddresses != null && gatewayIpAddresses.stream()
- .filter(IpAddress::isIp6)
- .anyMatch(gatewayIp -> gatewayIp.equals(pkt.target()) ||
- Arrays.equals(IPv6.getSolicitNodeAddress(gatewayIp.toOctets()),
- pkt.target().toOctets()));
- }
-
- /**
- * Sends a NDP request for the target IP address to all ports except in-port.
- *
- * @param deviceId Switch device ID
- * @param targetAddress target IP address for ARP
- * @param inPort in-port
- */
- public void sendNdpRequest(DeviceId deviceId, IpAddress targetAddress, ConnectPoint inPort) {
- byte[] senderMacAddress = new byte[MacAddress.MAC_ADDRESS_LENGTH];
- byte[] senderIpAddress = new byte[Ip6Address.BYTE_LENGTH];
- // Retrieves device info.
- if (!getSenderInfo(senderMacAddress, senderIpAddress, deviceId, targetAddress)) {
- log.warn("Aborting sendNdpRequest, we cannot get all the information needed");
- return;
- }
- // We have to compute the dst mac address and dst ip address.
- byte[] dstIp = IPv6.getSolicitNodeAddress(targetAddress.toOctets());
- byte[] dstMac = IPv6.getMCastMacAddress(dstIp);
- // Creates the request.
- Ethernet ndpRequest = NeighborSolicitation.buildNdpSolicit(
- targetAddress.getIp6Address(),
- Ip6Address.valueOf(senderIpAddress),
- Ip6Address.valueOf(dstIp),
- MacAddress.valueOf(senderMacAddress),
- MacAddress.valueOf(dstMac),
- VlanId.NONE
- );
- flood(ndpRequest, inPort, targetAddress);
- }
-
- /**
- * Returns link-local IP of given connect point.
- *
- * @param cp connect point
- * @return optional link-local IP
- */
- private Optional<Ip6Address> getLinkLocalIp(ConnectPoint cp) {
- return srManager.interfaceService.getInterfacesByPort(cp)
- .stream()
- .map(Interface::mac)
- .map(MacAddress::toBytes)
- .map(IPv6::getLinkLocalAddress)
- .map(Ip6Address::valueOf)
- .findFirst();
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/IpHandler.java b/app/src/main/java/org/onosproject/segmentrouting/IpHandler.java
deleted file mode 100644
index c445ac4..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/IpHandler.java
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * Copyright 2015-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;
-
-import org.onlab.packet.Ethernet;
-import org.onlab.packet.IP;
-import org.onlab.packet.IPv4;
-import org.onlab.packet.IPv6;
-import org.onlab.packet.Ip4Address;
-import org.onlab.packet.Ip6Address;
-import org.onlab.packet.IpAddress;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Host;
-import org.onosproject.net.flow.DefaultTrafficTreatment;
-import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.packet.DefaultOutboundPacket;
-import org.onosproject.net.packet.OutboundPacket;
-import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
-import org.onosproject.segmentrouting.config.DeviceConfiguration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.nio.ByteBuffer;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentLinkedQueue;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.onlab.packet.IpAddress.Version.INET6;
-
-/**
- * Handler of IP packets that forwards IP packets that are sent to the controller,
- * except the ICMP packets which are processed by @link{IcmpHandler}.
- */
-public class IpHandler {
-
- private static Logger log = LoggerFactory.getLogger(IpHandler.class);
- private SegmentRoutingManager srManager;
- private DeviceConfiguration config;
- private ConcurrentHashMap<IpAddress, ConcurrentLinkedQueue<IP>> ipPacketQueue;
-
- /**
- * Creates an IpHandler object.
- *
- * @param srManager SegmentRoutingManager object
- */
- public IpHandler(SegmentRoutingManager srManager) {
- this.srManager = srManager;
- this.config = checkNotNull(srManager.deviceConfiguration);
- ipPacketQueue = new ConcurrentHashMap<>();
- }
-
- /**
- * Enqueues the packet using the destination address as key.
- *
- * @param ipPacket the ip packet to store
- * @param destinationAddress the destination address
- */
- private void enqueuePacket(IP ipPacket, IpAddress destinationAddress) {
-
- ipPacketQueue
- .computeIfAbsent(destinationAddress, a -> new ConcurrentLinkedQueue<>())
- .add(ipPacket);
-
- }
-
- /**
- * Dequeues the packet using the destination address as key.
- *
- * @param ipPacket the ip packet to remove
- * @param destinationAddress the destination address
- */
- public void dequeuePacket(IP ipPacket, IpAddress destinationAddress) {
-
- if (ipPacketQueue.get(destinationAddress) == null) {
- return;
- }
- ipPacketQueue.get(destinationAddress).remove(ipPacket);
- }
-
- /**
- * Forwards the packet to a given host and deque the packet.
- *
- * @param deviceId the target device
- * @param eth the packet to send
- * @param dest the target host
- */
- private void forwardToHost(DeviceId deviceId, Ethernet eth, Host dest) {
- TrafficTreatment treatment = DefaultTrafficTreatment.builder().
- setOutput(dest.location().port()).build();
- OutboundPacket packet = new DefaultOutboundPacket(deviceId,
- treatment, ByteBuffer.wrap(eth.serialize()));
- srManager.packetService.emit(packet);
- }
-
- //////////////////////
- // IPv4 Handling //
- ////////////////////
-
- /**
- * Processes incoming IP packets.
- *
- * If it is an IP packet for known host, then forward it to the host.
- * If it is an IP packet for unknown host in subnet, then send an ARP request
- * to the subnet.
- *
- * @param pkt incoming packet
- * @param connectPoint the target device
- */
- public void processPacketIn(IPv4 pkt, ConnectPoint connectPoint) {
-
- DeviceId deviceId = connectPoint.deviceId();
- Ip4Address destinationAddress = Ip4Address.valueOf(pkt.getDestinationAddress());
-
- // IP packet for know hosts
- if (!srManager.hostService.getHostsByIp(destinationAddress).isEmpty()) {
- forwardPackets(deviceId, destinationAddress);
-
- // IP packet for unknown host in one of the configured subnets of the router
- } else if (config.inSameSubnet(deviceId, destinationAddress)) {
- srManager.arpHandler.sendArpRequest(deviceId, destinationAddress, connectPoint);
-
- // IP packets for unknown host
- } else {
- log.debug("IPv4 packet for unknown host {} which is not in the subnet",
- destinationAddress);
- // Do nothing
- }
- }
-
- /**
- * Adds the IP packet to a buffer.
- * The packets are forwarded to corresponding destination when the destination
- * MAC address is known via ARP response.
- *
- * @param ipPacket IP packet to add to the buffer
- */
- public void addToPacketBuffer(IPv4 ipPacket) {
-
- // Better not buffer TCP packets due to out-of-order packet transfer
- if (ipPacket.getProtocol() == IPv4.PROTOCOL_TCP) {
- return;
- }
- IpAddress destIpAddress = IpAddress.valueOf(ipPacket.getDestinationAddress());
- enqueuePacket(ipPacket, destIpAddress);
- }
-
- /**
- * Forwards IP packets in the buffer to the destination IP address.
- * It is called when the controller finds the destination MAC address
- * via ARP responses.
- *
- * @param deviceId switch device ID
- * @param destIpAddress destination IP address
- */
- public void forwardPackets(DeviceId deviceId, Ip4Address destIpAddress) {
- if (ipPacketQueue.get(destIpAddress) == null) {
- return;
- }
- for (IP ipPacket : ipPacketQueue.get(destIpAddress)) {
- if (ipPacket.getVersion() == ((byte) 4)) {
- IPv4 ipv4Packet = (IPv4) ipPacket;
- Ip4Address destAddress = Ip4Address.valueOf(ipv4Packet.getDestinationAddress());
- if (config.inSameSubnet(deviceId, destAddress)) {
- ipv4Packet.setTtl((byte) (ipv4Packet.getTtl() - 1));
- ipv4Packet.setChecksum((short) 0);
- for (Host dest : srManager.hostService.getHostsByIp(destIpAddress)) {
- Ethernet eth = new Ethernet();
- eth.setDestinationMACAddress(dest.mac());
- try {
- eth.setSourceMACAddress(config.getDeviceMac(deviceId));
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage()
- + " Skipping forwardPackets for this destination.");
- continue;
- }
- eth.setEtherType(Ethernet.TYPE_IPV4);
- eth.setPayload(ipv4Packet);
- forwardToHost(deviceId, eth, dest);
- ipPacketQueue.get(destIpAddress).remove(ipPacket);
- }
- ipPacketQueue.get(destIpAddress).remove(ipPacket);
- }
- }
- }
- }
-
- //////////////////////
- // IPv6 Handling //
- ////////////////////
-
- /**
- * Processes incoming IPv6 packets.
- *
- * If it is an IPv6 packet for known host, then forward it to the host.
- * If it is an IPv6 packet for unknown host in subnet, then send an NDP request
- * to the subnet.
- *
- * @param pkt incoming packet
- * @param connectPoint the target device
- */
- public void processPacketIn(IPv6 pkt, ConnectPoint connectPoint) {
-
- DeviceId deviceId = connectPoint.deviceId();
- Ip6Address destinationAddress = Ip6Address.valueOf(pkt.getDestinationAddress());
-
- // IPv6 packet for know hosts
- if (!srManager.hostService.getHostsByIp(destinationAddress).isEmpty()) {
- forwardPackets(deviceId, destinationAddress);
-
- // IPv6 packet for unknown host in one of the configured subnets of the router
- } else if (config.inSameSubnet(deviceId, destinationAddress)) {
- srManager.icmpHandler.sendNdpRequest(deviceId, destinationAddress, connectPoint);
-
- // IPv6 packets for unknown host
- } else {
- log.debug("IPv6 packet for unknown host {} which is not in the subnet",
- destinationAddress);
- }
- }
-
- /**
- * Adds the IPv6 packet to a buffer.
- * The packets are forwarded to corresponding destination when the destination
- * MAC address is known via NDP response.
- *
- * @param ipPacket IP packet to add to the buffer
- */
- public void addToPacketBuffer(IPv6 ipPacket) {
-
- // Better not buffer TCP packets due to out-of-order packet transfer
- if (ipPacket.getNextHeader() == IPv6.PROTOCOL_TCP) {
- return;
- }
- IpAddress destIpAddress = IpAddress.valueOf(INET6, ipPacket.getDestinationAddress());
- enqueuePacket(ipPacket, destIpAddress);
- }
-
- /**
- * Forwards IP packets in the buffer to the destination IP address.
- * It is called when the controller finds the destination MAC address
- * via NDP replies.
- *
- * @param deviceId the target device
- * @param destIpAddress the destination ip address
- */
- public void forwardPackets(DeviceId deviceId, Ip6Address destIpAddress) {
- if (ipPacketQueue.get(destIpAddress) == null) {
- return;
- }
- for (IP ipPacket : ipPacketQueue.get(destIpAddress)) {
- if (ipPacket.getVersion() == ((byte) 6)) {
- IPv6 ipv6Packet = (IPv6) ipPacket;
- Ip6Address destAddress = Ip6Address.valueOf(ipv6Packet.getDestinationAddress());
- if (config.inSameSubnet(deviceId, destAddress)) {
- ipv6Packet.setHopLimit((byte) (ipv6Packet.getHopLimit() - 1));
- for (Host dest : srManager.hostService.getHostsByIp(destIpAddress)) {
- Ethernet eth = new Ethernet();
- eth.setDestinationMACAddress(dest.mac());
- try {
- eth.setSourceMACAddress(config.getDeviceMac(deviceId));
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage()
- + " Skipping forwardPackets for this destination.");
- continue;
- }
- eth.setEtherType(Ethernet.TYPE_IPV6);
- eth.setPayload(ipv6Packet);
- forwardToHost(deviceId, eth, dest);
- ipPacketQueue.get(destIpAddress).remove(ipPacket);
- }
- ipPacketQueue.get(destIpAddress).remove(ipPacket);
- }
- }
- ipPacketQueue.get(destIpAddress).remove(ipPacket);
- }
- }
-
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/LinkHandler.java b/app/src/main/java/org/onosproject/segmentrouting/LinkHandler.java
deleted file mode 100644
index 2193c95..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/LinkHandler.java
+++ /dev/null
@@ -1,736 +0,0 @@
-/*
- * Copyright 2018-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;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.stream.Collectors;
-
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.Device;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.HostLocation;
-import org.onosproject.net.Link;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.link.LinkService;
-import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
-import org.onosproject.segmentrouting.config.DeviceConfiguration;
-import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
-import org.onosproject.store.service.EventuallyConsistentMap;
-import org.onosproject.store.service.EventuallyConsistentMapBuilder;
-import org.onosproject.store.service.WallClockTimestamp;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Sets;
-
-
-public class LinkHandler {
- private static final Logger log = LoggerFactory.getLogger(LinkHandler.class);
- protected final SegmentRoutingManager srManager;
-
- // Local store for all links seen and their present status, used for
- // optimized routing. The existence of the link in the keys is enough to know
- // if the link has been "seen-before" by this instance of the controller.
- // The boolean value indicates if the link is currently up or not.
- // Currently the optimized routing logic depends on "forgetting" a link
- // when a switch goes down, but "remembering" it when only the link goes down.
- private Map<Link, Boolean> seenLinks = new ConcurrentHashMap<>();
- private Set<Link> seenBefore = Sets.newConcurrentHashSet();
- private EventuallyConsistentMap<DeviceId, Set<PortNumber>> downedPortStore = null;
-
- /**
- * Constructs the LinkHandler.
- *
- * @param srManager Segment Routing manager
- */
- LinkHandler(SegmentRoutingManager srManager) {
- this.srManager = srManager;
- log.debug("Creating EC map downedportstore");
- EventuallyConsistentMapBuilder<DeviceId, Set<PortNumber>> downedPortsMapBuilder
- = srManager.storageService.eventuallyConsistentMapBuilder();
- downedPortStore = downedPortsMapBuilder.withName("downedportstore")
- .withSerializer(srManager.createSerializer())
- .withTimestampProvider((k, v) -> new WallClockTimestamp())
- .build();
- log.trace("Current size {}", downedPortStore.size());
- }
-
- /**
- * Constructs the LinkHandler for unit-testing.
- *
- * @param srManager SegmentRoutingManager
- * @param linkService LinkService
- */
- LinkHandler(SegmentRoutingManager srManager, LinkService linkService) {
- this.srManager = srManager;
- }
-
- /**
- * Initialize LinkHandler.
- */
- void init() {
- log.info("Loading stored links");
- srManager.linkService.getActiveLinks().forEach(this::processLinkAdded);
- }
-
- /**
- * Preprocessing of added link before being sent for route-path handling.
- * Also performs post processing of link.
- *
- * @param link the link to be processed
- */
- void processLinkAdded(Link link) {
- log.info("** LINK ADDED {}", link.toString());
- if (!isLinkValid(link)) {
- return;
- }
- // Irrespective of whether the local is a MASTER or not for this device,
- // create group handler instance and push default TTP flow rules if needed,
- // as in a multi-instance setup, instances can initiate groups for any
- // device. Also update local groupHandler stores.
- DefaultGroupHandler groupHandler = srManager.groupHandlerMap
- .get(link.src().deviceId());
- if (groupHandler == null) {
- Device device = srManager.deviceService.getDevice(link.src().deviceId());
- if (device != null) {
- log.warn("processLinkAdded: Link Added notification without "
- + "Device Added event, still handling it");
- srManager.processDeviceAdded(device);
- }
- }
-
- if (isSeenLink(link)) {
- // temp store retains previous state, just before the state is updated in
- // seenLinks; previous state is necessary when processing the
- // linkupdate in defaultRoutingHandler
- seenBefore.add(link);
- }
- updateSeenLink(link, true);
-
- if (srManager.deviceConfiguration == null ||
- !srManager.deviceConfiguration.isConfigured(link.src().deviceId())) {
- log.warn("Source device of this link is not configured.. "
- + "not processing further");
- return;
- }
-
- // process link only if it is bidirectional
- if (!isBidirectionalLinkUp(link)) {
- log.debug("Link not bidirectional.. waiting for other direction " +
- "src {} --> dst {} ", link.dst(), link.src());
- return;
- }
-
- log.info("processing bidi links {} <--> {} UP", link.src(), link.dst());
- // update groupHandler internal port state for both directions
- List<Link> ulinks = getBidiComponentLinks(link);
- for (Link ulink : ulinks) {
- DefaultGroupHandler gh = srManager.groupHandlerMap
- .get(ulink.src().deviceId());
- if (gh != null) {
- gh.portUpForLink(ulink);
- }
- }
-
- for (Link ulink : ulinks) {
- log.info("-- Starting optimized route-path processing for component "
- + "unidirectional link {} --> {} UP", ulink.src(), ulink.dst());
- srManager.defaultRoutingHandler
- .populateRoutingRulesForLinkStatusChange(null, ulink, null,
- seenBefore.contains(ulink));
-
- if (srManager.mastershipService.isLocalMaster(ulink.src().deviceId())) {
- // handle edge-ports for dual-homed hosts
- updateHostPorts(ulink, true);
-
- // It's possible that linkUp causes no route-path change as ECMP graph does
- // not change if the link is a parallel link (same src-dst as
- // another link). However we still need to update ECMP hash
- // groups to include new buckets for the link that has come up.
- DefaultGroupHandler gh = srManager.groupHandlerMap
- .get(ulink.src().deviceId());
- if (gh != null) {
- if (!seenBefore.contains(ulink) && isParallelLink(ulink)) {
- // if link seen first time, we need to ensure hash-groups have
- // all ports
- log.debug("Attempting retryHash for paralled first-time link {}",
- ulink);
- gh.retryHash(ulink, false, true);
- } else {
- // seen before-link
- if (isParallelLink(ulink)) {
- log.debug("Attempting retryHash for paralled seen-before "
- + "link {}", ulink);
- gh.retryHash(ulink, false, false);
- }
- }
- }
- }
- //clean up temp state
- seenBefore.remove(ulink);
- }
-
- }
-
- /**
- * Preprocessing of removed link before being sent for route-path handling.
- * Also performs post processing of link.
- *
- * @param link the link to be processed
- */
- void processLinkRemoved(Link link) {
- log.info("** LINK REMOVED {}", link.toString());
- if (!isLinkValid(link)) {
- return;
- }
- // when removing links, update seen links first, before doing route-path
- // changes
- updateSeenLink(link, false);
- // handle edge-ports for dual-homed hosts
- if (srManager.mastershipService.isLocalMaster(link.src().deviceId())) {
- updateHostPorts(link, false);
- }
-
- // device availability check helps to ensure that multiple link-removed
- // events are actually treated as a single switch removed event.
- // purgeSeenLink is necessary so we do rerouting (instead of rehashing)
- // when switch comes back.
- if (link.src().elementId() instanceof DeviceId
- && !srManager.deviceService.isAvailable(link.src().deviceId())) {
- purgeSeenLink(link);
- return;
- }
- if (link.dst().elementId() instanceof DeviceId
- && !srManager.deviceService.isAvailable(link.dst().deviceId())) {
- purgeSeenLink(link);
- return;
- }
-
- // process link only if it is bidirectional
- if (!isBidirectionalLinkDown(link)) {
- log.debug("Link not bidirectional.. waiting for other direction " +
- "src {} --> dst {} ", link.dst(), link.src());
- return;
- }
- log.info("processing bidi links {} <--> {} DOWN", link.src(), link.dst());
-
- for (Link ulink : getBidiComponentLinks(link)) {
- log.info("-- Starting optimized route-path processing for component "
- + "unidirectional link {} --> {} DOWN", ulink.src(), ulink.dst());
- srManager.defaultRoutingHandler
- .populateRoutingRulesForLinkStatusChange(ulink, null, null, true);
-
- // attempt rehashing for parallel links
- DefaultGroupHandler groupHandler = srManager.groupHandlerMap
- .get(ulink.src().deviceId());
- if (groupHandler != null) {
- if (srManager.mastershipService.isLocalMaster(ulink.src().deviceId())
- && isParallelLink(ulink)) {
- log.debug("* retrying hash for parallel link removed:{}", ulink);
- groupHandler.retryHash(ulink, true, false);
- } else {
- log.debug("Not attempting retry-hash for link removed: {} .. {}",
- ulink,
- (srManager.mastershipService.isLocalMaster(ulink
- .src().deviceId())) ? "not parallel"
- : "not master");
- }
- // ensure local stores are updated after all rerouting or rehashing
- groupHandler.portDownForLink(ulink);
- } else {
- log.warn("group handler not found for dev:{} when removing link: {}",
- ulink.src().deviceId(), ulink);
- }
- }
- }
-
- /**
- * Checks validity of link. Examples of invalid links include
- * indirect-links, links between ports on the same switch, and more.
- *
- * @param link the link to be processed
- * @return true if valid link
- */
- boolean isLinkValid(Link link) {
- if (link.type() != Link.Type.DIRECT) {
- // NOTE: A DIRECT link might be transiently marked as INDIRECT
- // if BDDP is received before LLDP. We can safely ignore that
- // until the LLDP is received and the link is marked as DIRECT.
- log.info("Ignore link {}->{}. Link type is {} instead of DIRECT.",
- link.src(), link.dst(), link.type());
- return false;
- }
- DeviceId srcId = link.src().deviceId();
- DeviceId dstId = link.dst().deviceId();
- if (srcId.equals(dstId)) {
- log.warn("Links between ports on the same switch are not "
- + "allowed .. ignoring link {}", link);
- return false;
- }
- DeviceConfiguration devConfig = srManager.deviceConfiguration;
- if (devConfig == null) {
- log.warn("Cannot check validity of link without device config");
- return true;
- }
- try {
- /*if (!devConfig.isEdgeDevice(srcId)
- && !devConfig.isEdgeDevice(dstId)) {
- // ignore links between spines
- // XXX revisit when handling multi-stage fabrics
- log.warn("Links between spines not allowed...ignoring "
- + "link {}", link);
- return false;
- }*/
- if (devConfig.isEdgeDevice(srcId)
- && devConfig.isEdgeDevice(dstId)) {
- // ignore links between leaves if they are not pair-links
- // XXX revisit if removing pair-link config or allowing more than
- // one pair-link
- if (devConfig.getPairDeviceId(srcId).equals(dstId)
- && devConfig.getPairLocalPort(srcId)
- .equals(link.src().port())
- && devConfig.getPairLocalPort(dstId)
- .equals(link.dst().port())) {
- // found pair link - allow it
- return true;
- } else {
- log.warn("Links between leaves other than pair-links are "
- + "not allowed...ignoring link {}", link);
- return false;
- }
- }
- } catch (DeviceConfigNotFoundException e) {
- // We still want to count the links in seenLinks even though there
- // is no config. So we let it return true
- log.warn("Could not check validity of link {} as subtending devices "
- + "are not yet configured", link);
- }
- return true;
- }
-
- /**
- * Administratively enables or disables edge ports if the link that was
- * added or removed was the only uplink port from an edge device. Edge ports
- * that belong to dual-homed hosts are always processed. In addition,
- * single-homed host ports are optionally processed depending on the
- * singleHomedDown property.
- *
- * @param link the link to be processed
- * @param added true if link was added, false if link was removed
- */
- private void updateHostPorts(Link link, boolean added) {
- DeviceConfiguration devConfig = srManager.deviceConfiguration;
- if (added) {
- try {
- if (!devConfig.isEdgeDevice(link.src().deviceId())
- || devConfig.isEdgeDevice(link.dst().deviceId())) {
- return;
- }
- } catch (DeviceConfigNotFoundException e) {
- log.warn("Unable to determine if link is a valid uplink"
- + e.getMessage());
- }
- // re-enable previously disabled ports on this edge-device if any
- Set<PortNumber> p = downedPortStore.remove(link.src().deviceId());
- if (p != null) {
- log.warn("Link src {} --> dst {} added is an edge-device uplink, "
- + "enabling dual homed ports if any: {}", link.src().deviceId(),
- link.dst().deviceId(), (p.isEmpty()) ? "no ports" : p);
- p.forEach(pnum -> srManager.deviceAdminService
- .changePortState(link.src().deviceId(), pnum, true));
- }
- } else {
- // If the device does not have a pair device - skip
- DeviceId dev = link.src().deviceId();
- if (getPairDeviceIdOrNull(dev) == null) {
- log.info("Device {} does not have pair device " +
- "not disabling access port", dev);
- return;
- }
- // Verify if last uplink
- if (!lastUplink(link)) {
- return;
- }
- // find dual homed hosts on this dev to disable
- Set<PortNumber> dp = srManager.hostHandler
- .getDualHomedHostPorts(dev);
- log.warn("Link src {} --> dst {} removed was the last uplink, "
- + "disabling dual homed ports: {}", dev,
- link.dst().deviceId(), (dp.isEmpty()) ? "no ports" : dp);
- dp.forEach(pnum -> srManager.deviceAdminService
- .changePortState(dev, pnum, false));
- if (srManager.singleHomedDown) {
- // get all configured ports and down them if they haven't already
- // been downed
- srManager.deviceService.getPorts(dev).stream()
- .filter(p -> p.isEnabled() && !dp.contains(p.number()))
- .filter(p -> srManager.interfaceService
- .isConfigured(new ConnectPoint(dev, p.number())))
- .filter(p -> !srManager.deviceConfiguration
- .isPairLocalPort(dev, p.number()))
- .forEach(p -> {
- log.warn("Last uplink gone src {} -> dst {} .. removing "
- + "configured port {}", p.number());
- srManager.deviceAdminService
- .changePortState(dev, p.number(), false);
- dp.add(p.number());
- });
- }
- if (!dp.isEmpty()) {
- // update global store
- Set<PortNumber> p = downedPortStore.get(dev);
- if (p == null) {
- p = dp;
- } else {
- p.addAll(dp);
- }
- downedPortStore.put(link.src().deviceId(), p);
- }
- }
- }
-
- /**
- * Returns true if given link was the last active uplink from src-device of
- * link. An uplink is defined as a unidirectional link with src as
- * edgeRouter and dst as non-edgeRouter.
- *
- * @param link
- * @return true if given link was the last uplink from the src device
- */
- private boolean lastUplink(Link link) {
- DeviceConfiguration devConfig = srManager.deviceConfiguration;
- try {
- if (!devConfig.isEdgeDevice(link.src().deviceId())
- || devConfig.isEdgeDevice(link.dst().deviceId())) {
- return false;
- }
- // note that using linkservice here would cause race conditions as
- // more links can show up while the app is still processing the first one
- Set<Link> devLinks = seenLinks.entrySet().stream()
- .filter(entry -> entry.getKey().src().deviceId()
- .equals(link.src().deviceId()))
- .filter(entry -> entry.getValue())
- .filter(entry -> !entry.getKey().equals(link))
- .map(entry -> entry.getKey())
- .collect(Collectors.toSet());
-
- for (Link l : devLinks) {
- if (devConfig.isEdgeDevice(l.dst().deviceId())) {
- continue;
- }
- log.debug("Found another active uplink {}", l);
- return false;
- }
- log.debug("No active uplink found");
- return true;
- } catch (DeviceConfigNotFoundException e) {
- log.warn("Unable to determine if link was the last uplink"
- + e.getMessage());
- }
- return false;
- }
-
- /**
- * Returns true if this controller instance has seen this link before. The
- * link may not be currently up, but as long as the link had been seen
- * before this method will return true. The one exception is when the link
- * was indeed seen before, but this controller instance was forced to forget
- * it by a call to purgeSeenLink method.
- *
- * @param link the infrastructure link being queried
- * @return true if this controller instance has seen this link before
- */
- boolean isSeenLink(Link link) {
- return seenLinks.containsKey(link);
- }
-
- /**
- * Updates the seen link store. Updates can be for links that are currently
- * available or not.
- *
- * @param link the link to update in the seen-link local store
- * @param up the status of the link, true if up, false if down
- */
- void updateSeenLink(Link link, boolean up) {
- seenLinks.put(link, up);
- }
-
- /**
- * Returns the status of a seen-link (up or down). If the link has not been
- * seen-before, a null object is returned.
- *
- * @param link the infrastructure link being queried
- * @return null if the link was not seen-before; true if the seen-link is
- * up; false if the seen-link is down
- */
- private Boolean isSeenLinkUp(Link link) {
- return seenLinks.get(link);
- }
-
- /**
- * Makes this controller instance forget a previously seen before link.
- *
- * @param link the infrastructure link to purge
- */
- private void purgeSeenLink(Link link) {
- seenLinks.remove(link);
- seenBefore.remove(link);
- }
-
- /**
- * Returns the status of a link as parallel link. A parallel link is defined
- * as a link which has common src and dst switches as another seen-link that
- * is currently enabled. It is not necessary for the link being queried to
- * be a seen-link.
- *
- * @param link the infrastructure link being queried
- * @return true if a seen-link exists that is up, and shares the same src
- * and dst switches as the link being queried
- */
- private boolean isParallelLink(Link link) {
- for (Entry<Link, Boolean> seen : seenLinks.entrySet()) {
- Link seenLink = seen.getKey();
- if (seenLink.equals(link)) {
- continue;
- }
- if (seenLink.src().deviceId().equals(link.src().deviceId())
- && seenLink.dst().deviceId().equals(link.dst().deviceId())
- && seen.getValue()) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns true if the link being queried is a bidirectional link that is
- * up. A bidi-link is defined as a component unidirectional link, whose
- * reverse link - ie. the component unidirectional link in the reverse
- * direction - has been seen-before and is up. It is NOT necessary for the
- * link being queried to be a previously seen-link.
- *
- * @param link the infrastructure (unidirectional) link being queried
- * @return true if another unidirectional link exists in the reverse
- * direction, has been seen-before and is up
- */
- boolean isBidirectionalLinkUp(Link link) {
- // cannot call linkService as link may be gone
- Link reverseLink = getReverseLink(link);
- if (reverseLink == null) {
- return false;
- }
- Boolean result = isSeenLinkUp(reverseLink);
- if (result == null) {
- return false;
- }
- return result.booleanValue();
- }
-
- /**
- * Returns true if the link being queried is a bidirectional link that is
- * down. A bidi-link is defined as a component unidirectional link, whose
- * reverse link - i.e the component unidirectional link in the reverse
- * direction - has been seen before and is down. It is necessary for the
- * reverse-link to have been previously seen.
- *
- * @param link the infrastructure (unidirectional) link being queried
- * @return true if another unidirectional link exists in the reverse
- * direction, has been seen-before and is down
- */
- boolean isBidirectionalLinkDown(Link link) {
- // cannot call linkService as link may be gone
- Link reverseLink = getReverseLink(link);
- if (reverseLink == null) {
- log.warn("Query for bidi-link down but reverse-link not found "
- + "for link {}", link);
- return false;
- }
- Boolean result = seenLinks.get(reverseLink);
- if (result == null) {
- return false;
- }
- // if reverse link is seen UP (true), then its not bidi yet
- return !result.booleanValue();
- }
-
- /**
- * Returns the link in the reverse direction from the given link, by
- * consulting the seen-links store.
- *
- * @param link the given link
- * @return the reverse link or null
- */
- Link getReverseLink(Link link) {
- return seenLinks.keySet().stream()
- .filter(l -> l.src().equals(link.dst()) && l.dst().equals(link.src()))
- .findAny()
- .orElse(null);
- }
-
- /**
- * Returns the component unidirectional links of a declared bidirectional
- * link, by consulting the seen-links store. Caller is responsible for
- * previously verifying bidirectionality. Returned list may be empty if
- * errors are encountered.
- *
- * @param link the declared bidirectional link
- * @return list of component unidirectional links
- */
- List<Link> getBidiComponentLinks(Link link) {
- Link reverseLink = getReverseLink(link);
- List<Link> componentLinks;
- if (reverseLink == null) { // really should not happen if link is bidi
- log.error("cannot find reverse link for given link: {} ... is it "
- + "bi-directional?", link);
- componentLinks = ImmutableList.of();
- } else {
- componentLinks = ImmutableList.of(reverseLink, link);
- }
- return componentLinks;
- }
-
- /**
- * Determines if the given link should be avoided in routing calculations by
- * policy or design.
- *
- * @param link the infrastructure link being queried
- * @return true if link should be avoided
- */
- boolean avoidLink(Link link) {
- // XXX currently only avoids all pair-links. In the future can be
- // extended to avoid any generic link
- DeviceId src = link.src().deviceId();
- PortNumber srcPort = link.src().port();
- DeviceConfiguration devConfig = srManager.deviceConfiguration;
- if (devConfig == null || !devConfig.isConfigured(src)) {
- log.warn("Device {} not configured..cannot avoid link {}", src,
- link);
- return false;
- }
- DeviceId pairDev;
- PortNumber pairLocalPort, pairRemotePort = null;
- try {
- pairDev = devConfig.getPairDeviceId(src);
- pairLocalPort = devConfig.getPairLocalPort(src);
- if (pairDev != null) {
- pairRemotePort = devConfig
- .getPairLocalPort(pairDev);
- }
- } catch (DeviceConfigNotFoundException e) {
- log.warn("Pair dev for dev {} not configured..cannot avoid link {}",
- src, link);
- return false;
- }
-
- return srcPort.equals(pairLocalPort)
- && link.dst().deviceId().equals(pairDev)
- && link.dst().port().equals(pairRemotePort);
- }
-
- /**
- * Cleans up internal LinkHandler stores.
- *
- * @param device the device that has been removed
- */
- void processDeviceRemoved(Device device) {
- seenLinks.keySet()
- .removeIf(key -> key.src().deviceId().equals(device.id())
- || key.dst().deviceId().equals(device.id()));
- }
-
- /**
- * Administratively disables the host location switchport if the edge device
- * has no viable uplinks. The caller needs to determine if such behavior is
- * desired for the single or dual-homed host.
- *
- * @param loc the host location
- */
- void checkUplinksForHost(HostLocation loc) {
- // If the device does not have a pair device - return
- if (getPairDeviceIdOrNull(loc.deviceId()) == null) {
- log.info("Device {} does not have pair device " +
- "not disabling access port", loc.deviceId());
- return;
- }
- // Verify link validity
- try {
- for (Link l : srManager.linkService.getDeviceLinks(loc.deviceId())) {
- if (srManager.deviceConfiguration.isEdgeDevice(l.dst().deviceId())
- || l.state() == Link.State.INACTIVE) {
- continue;
- }
- // found valid uplink - so, nothing to do
- return;
- }
- } catch (DeviceConfigNotFoundException e) {
- log.warn("Could not check for valid uplinks due to missing device"
- + "config " + e.getMessage());
- return;
- }
- log.warn("Host location {} has no valid uplinks disabling port", loc);
- srManager.deviceAdminService.changePortState(loc.deviceId(), loc.port(),
- false);
- Set<PortNumber> p = downedPortStore.get(loc.deviceId());
- if (p == null) {
- p = Sets.newHashSet(loc.port());
- } else {
- p.add(loc.port());
- }
- downedPortStore.put(loc.deviceId(), p);
- }
-
- private DeviceId getPairDeviceIdOrNull(DeviceId deviceId) {
- DeviceId pairDev;
- try {
- pairDev = srManager.deviceConfiguration.getPairDeviceId(deviceId);
- } catch (DeviceConfigNotFoundException e) {
- pairDev = null;
- }
- return pairDev;
- }
-
- ImmutableMap<Link, Boolean> getSeenLinks() {
- return ImmutableMap.copyOf(seenLinks);
- }
-
- ImmutableMap<DeviceId, Set<PortNumber>> getDownedPorts() {
- return ImmutableMap.copyOf(downedPortStore.entrySet());
- }
-
- /**
- * Returns all links that egress from given device that are UP in the
- * seenLinks store. The returned links are also confirmed to be
- * bidirectional.
- *
- * @param deviceId the device identifier
- * @return set of egress links from the device
- */
- Set<Link> getDeviceEgressLinks(DeviceId deviceId) {
- return seenLinks.keySet().stream()
- .filter(link -> link.src().deviceId().equals(deviceId))
- .filter(link -> seenLinks.get(link))
- .filter(link -> isBidirectionalLinkUp(link))
- .collect(Collectors.toSet());
- }
-
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/OsgiPropertyConstants.java b/app/src/main/java/org/onosproject/segmentrouting/OsgiPropertyConstants.java
deleted file mode 100644
index ac63f73..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/OsgiPropertyConstants.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2018-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;
-
-/**
- * Constants for default values of configurable properties.
- */
-public final class OsgiPropertyConstants {
-
- private OsgiPropertyConstants() {}
-
- public static final String PROP_ACTIVE_PROBING = "activeProbing";
- public static final boolean ACTIVE_PROBING_DEFAULT = true;
-
- public static final String PROP_SINGLE_HOMED_DOWN = "singleHomedDown";
- public static final boolean SINGLE_HOMED_DOWN_DEFAULT = false;
-
- public static final String PROP_RESPOND_TO_UNKNOWN_HOSTS = "respondToUnknownHosts";
- public static final boolean RESPOND_TO_UNKNOWN_HOSTS_DEFAULT = true;
-
- public static final String PROP_ROUTE_DOUBLE_TAGGED_HOSTS = "routeDoubleTaggedHosts";
- public static final boolean ROUTE_DOUBLE_TAGGED_HOSTS_DEFAULT = false;
-
- public static final String PROP_DEFAULT_INTERNAL_VLAN = "defaultInternalVlan";
- public static final int DEFAULT_INTERNAL_VLAN_DEFAULT = 4094;
-
- public static final String PROP_PW_TRANSPORT_VLAN = "pwTransportVlan";
- public static final int PW_TRANSPORT_VLAN_DEFAULT = 4090;
-
- static final String PROP_SYMMETRIC_PROBING = "symmetricProbing";
- static final boolean SYMMETRIC_PROBING_DEFAULT = false;
-
- public static final String PROP_ROUTE_SIMPLIFICATION = "routeSimplification";
- public static final boolean ROUTE_SIMPLIFICATION_DEFAULT = false;
-
-
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/Policy.java b/app/src/main/java/org/onosproject/segmentrouting/Policy.java
deleted file mode 100644
index c9baf93..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/Policy.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 2015-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;
-
-/**
- * Interface for Segment Routing Policy.
- */
-public interface Policy {
- /**
- * Enums for policy type.
- */
- enum Type {
- /**
- * Tunnel flow policy type.
- */
- TUNNEL_FLOW,
-
- /**
- * Load balancing policy type.
- */
- LOADBALANCE,
-
- /**
- * policy to avoid specific routers or links.
- */
- AVOID,
-
- /**
- * Access Control policy type.
- */
- DENY
- }
-
- /**
- * Returns the policy ID.
- *
- * @return policy ID
- */
- String id();
-
- /**
- * Returns the priority of the policy.
- *
- * @return priority
- */
- int priority();
-
- /**
- * Returns the policy type.
- *
- * @return policy type
- */
- Type type();
-
- /**
- * Returns the source IP address of the policy.
- *
- * @return source IP address
- */
- String srcIp();
-
- /**
- * Returns the destination IP address of the policy.
- *
- * @return destination IP address
- */
- String dstIp();
-
- /**
- * Returns the IP protocol of the policy.
- *
- * @return IP protocol
- */
- String ipProto();
-
- /**
- * Returns the source port of the policy.
- *
- * @return source port
- */
- short srcPort();
-
- /**
- * Returns the destination of the policy.
- *
- * @return destination port
- */
- short dstPort();
-
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/PolicyHandler.java b/app/src/main/java/org/onosproject/segmentrouting/PolicyHandler.java
deleted file mode 100644
index a341bb1..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/PolicyHandler.java
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright 2015-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;
-
-import org.onlab.packet.Ethernet;
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.TpPort;
-import org.onosproject.cli.net.IpProtocol;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.flow.DefaultTrafficSelector;
-import org.onosproject.net.flow.TrafficSelector;
-import org.onosproject.net.flowobjective.DefaultForwardingObjective;
-import org.onosproject.net.flowobjective.FlowObjectiveService;
-import org.onosproject.net.flowobjective.ForwardingObjective;
-import org.onosproject.segmentrouting.config.DeviceConfiguration;
-import org.onosproject.store.service.EventuallyConsistentMap;
-import org.slf4j.Logger;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-import static org.slf4j.LoggerFactory.getLogger;
-
-/**
- * Segment Routing Policy Handler.
- */
-public class PolicyHandler {
-
- protected final Logger log = getLogger(getClass());
-
- private ApplicationId appId;
- private DeviceConfiguration deviceConfiguration;
- private FlowObjectiveService flowObjectiveService;
- private TunnelHandler tunnelHandler;
- private final EventuallyConsistentMap<String, Policy> policyStore;
- /**
- * Result of policy creation.
- */
- public enum Result {
- /**
- * Success.
- */
- SUCCESS,
-
- /**
- * The same policy exists already.
- */
- POLICY_EXISTS,
-
- /**
- * The policy ID exists already.
- */
- ID_EXISTS,
-
- /**
- * Cannot find associated tunnel.
- */
- TUNNEL_NOT_FOUND,
-
- /**
- * Policy was not found.
- */
- POLICY_NOT_FOUND,
-
- /**
- * Policy type {} is not supported yet.
- */
- UNSUPPORTED_TYPE
- }
-
- /**
- * Constructs policy handler.
- *
- * @param appId segment routing application ID
- * @param deviceConfiguration DeviceConfiguration reference
- * @param flowObjectiveService FlowObjectiveService reference
- * @param tunnelHandler tunnel handler reference
- * @param policyStore policy store
- */
- public PolicyHandler(ApplicationId appId,
- DeviceConfiguration deviceConfiguration,
- FlowObjectiveService flowObjectiveService,
- TunnelHandler tunnelHandler,
- EventuallyConsistentMap<String, Policy> policyStore) {
- this.appId = appId;
- this.deviceConfiguration = deviceConfiguration;
- this.flowObjectiveService = flowObjectiveService;
- this.tunnelHandler = tunnelHandler;
- this.policyStore = policyStore;
- }
-
- /**
- * Returns the policies.
- *
- * @return policy list
- */
- public List<Policy> getPolicies() {
- return policyStore.values()
- .stream()
- .filter(policy -> policy instanceof TunnelPolicy)
- .map(policy -> new TunnelPolicy((TunnelPolicy) policy))
- .collect(Collectors.toList());
- }
-
- /**
- * Creates a policy using the policy information given.
- * @param policy policy reference to create
- * @return ID_EXISTS if the same policy ID exists,
- * POLICY_EXISTS if the same policy exists, TUNNEL_NOT_FOUND if the tunnel
- * does not exists, UNSUPPORTED_TYPE if the policy type is not supported,
- * SUCCESS if the policy is created successfully
- */
- public Result createPolicy(Policy policy) {
-
- if (policyStore.containsKey(policy.id())) {
- log.warn("The policy id {} exists already", policy.id());
- return Result.ID_EXISTS;
- }
-
- if (policyStore.containsValue(policy)) {
- log.warn("The same policy exists already");
- return Result.POLICY_EXISTS;
- }
-
- if (policy.type() == Policy.Type.TUNNEL_FLOW) {
-
- TunnelPolicy tunnelPolicy = (TunnelPolicy) policy;
- Tunnel tunnel = tunnelHandler.getTunnel(tunnelPolicy.tunnelId());
- if (tunnel == null) {
- return Result.TUNNEL_NOT_FOUND;
- }
-
- ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
- .builder()
- .fromApp(appId)
- .makePermanent()
- .nextStep(tunnel.groupId())
- .withPriority(tunnelPolicy.priority())
- .withSelector(buildSelector(policy))
- .withFlag(ForwardingObjective.Flag.VERSATILE);
-
- DeviceId source = deviceConfiguration.getDeviceId(tunnel.labelIds().get(0));
- flowObjectiveService.forward(source, fwdBuilder.add());
-
- } else {
- log.warn("Policy type {} is not supported yet.", policy.type());
- return Result.UNSUPPORTED_TYPE;
- }
-
- policyStore.put(policy.id(), policy);
-
- return Result.SUCCESS;
- }
-
- /**
- * Removes the policy given.
- *
- * @param policyInfo policy information to remove
- * @return POLICY_NOT_FOUND if the policy to remove does not exists,
- * SUCCESS if it is removed successfully
- */
- public Result removePolicy(Policy policyInfo) {
-
- if (policyStore.get(policyInfo.id()) != null) {
- Policy policy = policyStore.get(policyInfo.id());
- if (policy.type() == Policy.Type.TUNNEL_FLOW) {
- TunnelPolicy tunnelPolicy = (TunnelPolicy) policy;
- Tunnel tunnel = tunnelHandler.getTunnel(tunnelPolicy.tunnelId());
-
- ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
- .builder()
- .fromApp(appId)
- .makePermanent()
- .withSelector(buildSelector(policy))
- .withPriority(tunnelPolicy.priority())
- .nextStep(tunnel.groupId())
- .withFlag(ForwardingObjective.Flag.VERSATILE);
-
- DeviceId source = deviceConfiguration.getDeviceId(tunnel.labelIds().get(0));
- flowObjectiveService.forward(source, fwdBuilder.remove());
-
- policyStore.remove(policyInfo.id());
- }
- } else {
- log.warn("Policy {} was not found", policyInfo.id());
- return Result.POLICY_NOT_FOUND;
- }
-
- return Result.SUCCESS;
- }
-
-
- private TrafficSelector buildSelector(Policy policy) {
-
- TrafficSelector.Builder tsb = DefaultTrafficSelector.builder();
- tsb.matchEthType(Ethernet.TYPE_IPV4);
- if (policy.dstIp() != null && !policy.dstIp().isEmpty()) {
- tsb.matchIPDst(IpPrefix.valueOf(policy.dstIp()));
- }
- if (policy.srcIp() != null && !policy.srcIp().isEmpty()) {
- tsb.matchIPSrc(IpPrefix.valueOf(policy.srcIp()));
- }
- if (policy.ipProto() != null && !policy.ipProto().isEmpty()) {
- Short ipProto = IpProtocol.valueOf(policy.ipProto()).value();
- tsb.matchIPProtocol(ipProto.byteValue());
- if (IpProtocol.valueOf(policy.ipProto()).equals(IpProtocol.TCP)) {
- if (policy.srcPort() != 0) {
- tsb.matchTcpSrc(TpPort.tpPort(policy.srcPort()));
- }
- if (policy.dstPort() != 0) {
- tsb.matchTcpDst(TpPort.tpPort(policy.dstPort()));
- }
- } else if (IpProtocol.valueOf(policy.ipProto()).equals(IpProtocol.UDP)) {
- if (policy.srcPort() != 0) {
- tsb.matchUdpSrc(TpPort.tpPort(policy.srcPort()));
- }
- if (policy.dstPort() != 0) {
- tsb.matchUdpDst(TpPort.tpPort(policy.dstPort()));
- }
- }
- }
-
- return tsb.build();
- }
-
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/PortAuthTracker.java b/app/src/main/java/org/onosproject/segmentrouting/PortAuthTracker.java
deleted file mode 100644
index 2127019..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/PortAuthTracker.java
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * Copyright 2017-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;
-
-
-import com.google.common.base.Objects;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.PortNumber;
-import org.onosproject.segmentrouting.config.BlockedPortsConfig;
-import org.onosproject.utils.Comparators;
-import org.slf4j.Logger;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import static org.onosproject.net.DeviceId.deviceId;
-import static org.onosproject.net.PortNumber.portNumber;
-import static org.slf4j.LoggerFactory.getLogger;
-
-/**
- * Keeps track of ports that have been configured for blocking,
- * and their current authentication state.
- */
-public class PortAuthTracker {
-
- private static final Logger log = getLogger(PortAuthTracker.class);
-
- private Map<DeviceId, Map<PortNumber, BlockState>> blockedPorts = new HashMap<>();
- private Map<DeviceId, Map<PortNumber, BlockState>> oldMap;
-
- @Override
- public String toString() {
- return "PortAuthTracker{entries = " + blockedPorts.size() + "}";
- }
-
- /**
- * Changes the state of the given device id / port number pair to the
- * specified state.
- *
- * @param d device identifier
- * @param p port number
- * @param newState the updated state
- * @return true, if the state changed from what was previously mapped
- */
- private boolean changeStateTo(DeviceId d, PortNumber p, BlockState newState) {
- Map<PortNumber, BlockState> portMap =
- blockedPorts.computeIfAbsent(d, k -> new HashMap<>());
- BlockState oldState =
- portMap.computeIfAbsent(p, k -> BlockState.UNCHECKED);
- portMap.put(p, newState);
- return (oldState != newState);
- }
-
- /**
- * Radius has authorized the supplicant at this connect point. If
- * we are tracking this port, clear the blocking flow and mark the
- * port as authorized.
- *
- * @param connectPoint supplicant connect point
- */
- void radiusAuthorize(ConnectPoint connectPoint) {
- DeviceId d = connectPoint.deviceId();
- PortNumber p = connectPoint.port();
- if (configured(d, p)) {
- clearBlockingFlow(d, p);
- markAsAuthenticated(d, p);
- }
- }
-
- /**
- * Supplicant at specified connect point has logged off Radius. If
- * we are tracking this port, install a blocking flow and mark the
- * port as blocked.
- *
- * @param connectPoint supplicant connect point
- */
- void radiusLogoff(ConnectPoint connectPoint) {
- DeviceId d = connectPoint.deviceId();
- PortNumber p = connectPoint.port();
- if (configured(d, p)) {
- installBlockingFlow(d, p);
- markAsBlocked(d, p);
- }
- }
-
- /**
- * Marks the specified device/port as blocked.
- *
- * @param d device id
- * @param p port number
- * @return true if the state changed (was not already blocked)
- */
- private boolean markAsBlocked(DeviceId d, PortNumber p) {
- return changeStateTo(d, p, BlockState.BLOCKED);
- }
-
- /**
- * Marks the specified device/port as authenticated.
- *
- * @param d device id
- * @param p port number
- * @return true if the state changed (was not already authenticated)
- */
- private boolean markAsAuthenticated(DeviceId d, PortNumber p) {
- return changeStateTo(d, p, BlockState.AUTHENTICATED);
- }
-
- /**
- * Returns true if the given device/port are configured for blocking.
- *
- * @param d device id
- * @param p port number
- * @return true if this device/port configured for blocking
- */
- private boolean configured(DeviceId d, PortNumber p) {
- Map<PortNumber, BlockState> portMap = blockedPorts.get(d);
- return portMap != null && portMap.get(p) != null;
- }
-
- private BlockState whatState(DeviceId d, PortNumber p,
- Map<DeviceId, Map<PortNumber, BlockState>> m) {
- Map<PortNumber, BlockState> portMap = m.get(d);
- if (portMap == null) {
- return BlockState.UNCHECKED;
- }
- BlockState state = portMap.get(p);
- if (state == null) {
- return BlockState.UNCHECKED;
- }
- return state;
- }
-
- /**
- * Returns the current state of the given device/port.
- *
- * @param d device id
- * @param p port number
- * @return current block-state
- */
- BlockState currentState(DeviceId d, PortNumber p) {
- return whatState(d, p, blockedPorts);
- }
-
- /**
- * Returns the current state of the given connect point.
- *
- * @param cp connect point
- * @return current block-state
- */
-
- BlockState currentState(ConnectPoint cp) {
- return whatState(cp.deviceId(), cp.port(), blockedPorts);
- }
-
- /**
- * Returns the number of entries being tracked.
- *
- * @return the number of tracked entries
- */
- int entryCount() {
- int count = 0;
- for (Map<PortNumber, BlockState> m : blockedPorts.values()) {
- count += m.size();
- }
- return count;
- }
-
- /**
- * Returns the previously recorded state of the given device/port.
- *
- * @param d device id
- * @param p port number
- * @return previous block-state
- */
- private BlockState oldState(DeviceId d, PortNumber p) {
- return whatState(d, p, oldMap);
- }
-
- private void configurePort(DeviceId d, PortNumber p) {
- boolean alreadyAuthenticated =
- oldState(d, p) == BlockState.AUTHENTICATED;
-
- if (alreadyAuthenticated) {
- clearBlockingFlow(d, p);
- markAsAuthenticated(d, p);
- } else {
- installBlockingFlow(d, p);
- markAsBlocked(d, p);
- }
- log.info("Configuring port {}/{} as {}", d, p,
- alreadyAuthenticated ? "AUTHENTICATED" : "BLOCKED");
- }
-
- private boolean notInMap(DeviceId deviceId, PortNumber portNumber) {
- Map<PortNumber, BlockState> m = blockedPorts.get(deviceId);
- return m == null || m.get(portNumber) == null;
- }
-
- private void logPortsNoLongerBlocked() {
- for (Map.Entry<DeviceId, Map<PortNumber, BlockState>> entry :
- oldMap.entrySet()) {
- DeviceId d = entry.getKey();
- Map<PortNumber, BlockState> portMap = entry.getValue();
-
- for (PortNumber p : portMap.keySet()) {
- if (notInMap(d, p)) {
- clearBlockingFlow(d, p);
- log.info("De-configuring port {}/{} (UNCHECKED)", d, p);
- }
- }
- }
- }
-
-
- /**
- * Reconfigures the port tracker using the supplied configuration.
- *
- * @param cfg the new configuration
- */
- void configurePortBlocking(BlockedPortsConfig cfg) {
- // remember the old map; prepare a new map
- oldMap = blockedPorts;
- blockedPorts = new HashMap<>();
-
- // for each configured device, add configured ports to map
- for (String devId : cfg.deviceIds()) {
- cfg.portIterator(devId)
- .forEachRemaining(p -> configurePort(deviceId(devId),
- portNumber(p)));
- }
-
- // have we de-configured any ports?
- logPortsNoLongerBlocked();
-
- // allow old map to be garbage collected
- oldMap = null;
- }
-
- private List<PortAuthState> reportPortsAuthState() {
- List<PortAuthState> result = new ArrayList<>();
-
- for (Map.Entry<DeviceId, Map<PortNumber, BlockState>> entry :
- blockedPorts.entrySet()) {
- DeviceId d = entry.getKey();
- Map<PortNumber, BlockState> portMap = entry.getValue();
-
- for (PortNumber p : portMap.keySet()) {
- result.add(new PortAuthState(d, p, portMap.get(p)));
- }
- }
- Collections.sort(result);
- return result;
- }
-
- /**
- * Installs a "blocking" flow for device/port specified.
- *
- * @param d device id
- * @param p port number
- */
- void installBlockingFlow(DeviceId d, PortNumber p) {
- log.debug("Installing Blocking Flow at {}/{}", d, p);
- // TODO: invoke SegmentRoutingService.block(...) appropriately
- log.info("TODO >> Installing Blocking Flow at {}/{}", d, p);
- }
-
- /**
- * Removes the "blocking" flow from device/port specified.
- *
- * @param d device id
- * @param p port number
- */
- void clearBlockingFlow(DeviceId d, PortNumber p) {
- log.debug("Clearing Blocking Flow from {}/{}", d, p);
- // TODO: invoke SegmentRoutingService.block(...) appropriately
- log.info("TODO >> Clearing Blocking Flow from {}/{}", d, p);
- }
-
-
- /**
- * Designates the state of a given port. One of:
- * <ul>
- * <li> UNCHECKED: not configured for blocking </li>
- * <li> BLOCKED: configured for blocking, and not yet authenticated </li>
- * <li> AUTHENTICATED: configured for blocking, but authenticated </li>
- * </ul>
- */
- public enum BlockState {
- UNCHECKED,
- BLOCKED,
- AUTHENTICATED
- }
-
- /**
- * A simple DTO binding of device identifier, port number, and block state.
- */
- public static final class PortAuthState implements Comparable<PortAuthState> {
- private final DeviceId d;
- private final PortNumber p;
- private final BlockState s;
-
- private PortAuthState(DeviceId d, PortNumber p, BlockState s) {
- this.d = d;
- this.p = p;
- this.s = s;
- }
-
- @Override
- public String toString() {
- return String.valueOf(d) + "/" + p + " -- " + s;
- }
-
- @Override
- public int compareTo(PortAuthState o) {
- // NOTE: only compare against "deviceid/port"
- int result = Comparators.ELEMENT_ID_COMPARATOR.compare(d, o.d);
- return (result != 0) ? result : Long.signum(p.toLong() - o.p.toLong());
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- final PortAuthTracker.PortAuthState that = (PortAuthTracker.PortAuthState) obj;
-
- return Comparators.ELEMENT_ID_COMPARATOR.compare(this.d, that.d) == 0 &&
- p.toLong() == that.p.toLong();
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(this.d, this.p);
- }
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/PortFilterInfo.java b/app/src/main/java/org/onosproject/segmentrouting/PortFilterInfo.java
deleted file mode 100644
index 75c12d6..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/PortFilterInfo.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2018-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;
-
-import com.google.common.base.MoreObjects;
-
-import java.util.Objects;
-
-import static com.google.common.base.MoreObjects.toStringHelper;
-
-/**
- * Utility class used to temporarily store information about the ports on a
- * device processed for filtering objectives.
- */
-public final class PortFilterInfo {
- int disabledPorts = 0, errorPorts = 0, filteredPorts = 0;
-
- public PortFilterInfo(int disabledPorts, int errorPorts,
- int filteredPorts) {
- this.disabledPorts = disabledPorts;
- this.filteredPorts = filteredPorts;
- this.errorPorts = errorPorts;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(disabledPorts, filteredPorts, errorPorts);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if ((obj == null) || (!(obj instanceof PortFilterInfo))) {
- return false;
- }
- PortFilterInfo other = (PortFilterInfo) obj;
- return ((disabledPorts == other.disabledPorts) &&
- (filteredPorts == other.filteredPorts) &&
- (errorPorts == other.errorPorts));
- }
-
- @Override
- public String toString() {
- MoreObjects.ToStringHelper helper = toStringHelper(this)
- .add("disabledPorts", disabledPorts)
- .add("errorPorts", errorPorts)
- .add("filteredPorts", filteredPorts);
- return helper.toString();
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/onosproject/segmentrouting/RouteHandler.java b/app/src/main/java/org/onosproject/segmentrouting/RouteHandler.java
deleted file mode 100644
index d9372fe..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/RouteHandler.java
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- * Copyright 2016-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;
-
-import com.google.common.collect.Sets;
-
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.HostLocation;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.host.HostEvent;
-import org.onosproject.routeservice.ResolvedRoute;
-import org.onosproject.routeservice.RouteEvent;
-import org.onosproject.net.DeviceId;
-import org.onosproject.routeservice.RouteInfo;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.List;
-import java.util.Collection;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/**
- * Handles RouteEvent and manages routing entries.
- */
-public class RouteHandler {
- private static final Logger log = LoggerFactory.getLogger(RouteHandler.class);
- private final SegmentRoutingManager srManager;
-
- RouteHandler(SegmentRoutingManager srManager) {
- this.srManager = srManager;
- }
-
- protected void init(DeviceId deviceId) {
- srManager.routeService.getRouteTables().stream()
- .map(srManager.routeService::getRoutes)
- .flatMap(Collection::stream)
- .map(RouteInfo::allRoutes)
- .filter(allRoutes -> allRoutes.stream().anyMatch(resolvedRoute ->
- srManager.nextHopLocations(resolvedRoute).stream()
- .anyMatch(cp -> deviceId.equals(cp.deviceId()))))
- .forEach(rr -> processRouteAddedInternal(rr, true));
- }
-
- void processRouteAdded(RouteEvent event) {
- processRouteAddedInternal(event.alternatives(), false);
- }
-
- /**
- * Internal logic that handles route addition.
- *
- * @param routes collection of routes to be processed
- * @param populateRouteOnly true if we only want to populateRoute but not populateSubnet.
- * Set it to true when initializing a device coming up.
- * populateSubnet will be done when link comes up later so it is redundant.
- * populateRoute still needs to be done for statically configured next hop hosts.
- */
- private void processRouteAddedInternal(Collection<ResolvedRoute> routes, boolean populateRouteOnly) {
- if (!isReady()) {
- log.info("System is not ready. Skip adding route for {}", routes);
- return;
- }
-
- log.info("processRouteAddedInternal. routes={}", routes);
-
- if (routes.size() > 2) {
- log.info("Route {} has more than two next hops. Do not process route change", routes);
- return;
- }
-
- ResolvedRoute rr = routes.stream().findFirst().orElse(null);
- if (rr == null) {
- log.warn("No resolved route found. Abort processRouteAddedInternal");
- }
-
- Set<ConnectPoint> allLocations = Sets.newHashSet();
- Set<IpPrefix> allPrefixes = Sets.newHashSet();
- routes.forEach(route -> {
- allLocations.addAll(srManager.nextHopLocations(route));
- allPrefixes.add(route.prefix());
- });
- log.debug("RouteAdded. populateSubnet {}, {}", allLocations, allPrefixes);
- srManager.defaultRoutingHandler.populateSubnet(allLocations, allPrefixes);
-
-
- routes.forEach(route -> {
- IpPrefix prefix = route.prefix();
- MacAddress nextHopMac = route.nextHopMac();
- VlanId nextHopVlan = route.nextHopVlan();
- Set<ConnectPoint> locations = srManager.nextHopLocations(route);
-
- locations.forEach(location -> {
- log.debug("RouteAdded. addSubnet {}, {}", location, prefix);
- srManager.deviceConfiguration.addSubnet(location, prefix);
- log.debug("RouteAdded populateRoute {}, {}, {}, {}", location, prefix, nextHopMac, nextHopVlan);
- srManager.defaultRoutingHandler.populateRoute(location.deviceId(), prefix,
- nextHopMac, nextHopVlan, location.port(), false);
- });
- });
- }
-
- void processRouteUpdated(RouteEvent event) {
- processRouteUpdatedInternal(Sets.newHashSet(event.alternatives()),
- Sets.newHashSet(event.prevAlternatives()));
- }
-
- void processAlternativeRoutesChanged(RouteEvent event) {
- processRouteUpdatedInternal(Sets.newHashSet(event.alternatives()),
- Sets.newHashSet(event.prevAlternatives()));
- }
-
- private void processRouteUpdatedInternal(Set<ResolvedRoute> routes, Set<ResolvedRoute> oldRoutes) {
- if (!isReady()) {
- log.info("System is not ready. Skip updating route for {} -> {}", oldRoutes, routes);
- return;
- }
-
- log.info("processRouteUpdatedInternal. routes={}, oldRoutes={}", routes, oldRoutes);
-
- if (routes.size() > 2) {
- log.info("Route {} has more than two next hops. Do not process route change", routes);
- return;
- }
-
- Set<ConnectPoint> allLocations = Sets.newHashSet();
- Set<IpPrefix> allPrefixes = Sets.newHashSet();
- routes.forEach(route -> {
- allLocations.addAll(srManager.nextHopLocations(route));
- allPrefixes.add(route.prefix());
- });
-
- // Just come back from an invalid next hop count
- // Revoke subnet from all locations and reset oldRoutes such that system will be reprogrammed from scratch
- if (oldRoutes.size() > 2) {
- log.info("Revoke subnet {} and reset oldRoutes");
- srManager.defaultRoutingHandler.revokeSubnet(allPrefixes);
- oldRoutes = Sets.newHashSet();
- }
-
- log.debug("RouteUpdated. populateSubnet {}, {}", allLocations, allPrefixes);
- srManager.defaultRoutingHandler.populateSubnet(allLocations, allPrefixes);
-
- Set<ResolvedRoute> toBeRemoved = Sets.difference(oldRoutes, routes).immutableCopy();
- Set<ResolvedRoute> toBeAdded = Sets.difference(routes, oldRoutes).immutableCopy();
-
- toBeRemoved.forEach(route -> {
- srManager.nextHopLocations(route).forEach(oldLocation -> {
- if (toBeAdded.stream().map(srManager::nextHopLocations)
- .flatMap(Set::stream).map(ConnectPoint::deviceId)
- .noneMatch(deviceId -> deviceId.equals(oldLocation.deviceId()))) {
- IpPrefix prefix = route.prefix();
- log.debug("RouteUpdated. removeSubnet {}, {}", oldLocation, prefix);
- srManager.deviceConfiguration.removeSubnet(oldLocation, prefix);
- // We don't remove the flow on the old location in occasion of two next hops becoming one
- // since the populateSubnet will point the old location to the new location via spine.
- }
- });
- });
-
- toBeAdded.forEach(route -> {
- IpPrefix prefix = route.prefix();
- MacAddress nextHopMac = route.nextHopMac();
- VlanId nextHopVlan = route.nextHopVlan();
- Set<ConnectPoint> locations = srManager.nextHopLocations(route);
-
- locations.forEach(location -> {
- log.debug("RouteUpdated. addSubnet {}, {}", location, prefix);
- srManager.deviceConfiguration.addSubnet(location, prefix);
- log.debug("RouteUpdated. populateRoute {}, {}, {}, {}", location, prefix, nextHopMac, nextHopVlan);
- srManager.defaultRoutingHandler.populateRoute(location.deviceId(), prefix,
- nextHopMac, nextHopVlan, location.port(), false);
- });
- });
- }
-
- void processRouteRemoved(RouteEvent event) {
- processRouteRemovedInternal(event.alternatives());
- }
-
- private void processRouteRemovedInternal(Collection<ResolvedRoute> routes) {
- if (!isReady()) {
- log.info("System is not ready. Skip removing route for {}", routes);
- return;
- }
-
- log.info("processRouteRemovedInternal. routes={}", routes);
-
- Set<IpPrefix> allPrefixes = Sets.newHashSet();
- routes.forEach(route -> {
- allPrefixes.add(route.prefix());
- });
- log.debug("RouteRemoved. revokeSubnet {}", allPrefixes);
- srManager.defaultRoutingHandler.revokeSubnet(allPrefixes);
-
- routes.forEach(route -> {
- IpPrefix prefix = route.prefix();
- MacAddress nextHopMac = route.nextHopMac();
- VlanId nextHopVlan = route.nextHopVlan();
- Set<ConnectPoint> locations = srManager.nextHopLocations(route);
-
- locations.forEach(location -> {
- log.debug("RouteRemoved. removeSubnet {}, {}", location, prefix);
- srManager.deviceConfiguration.removeSubnet(location, prefix);
- // We don't need to call revokeRoute again since revokeSubnet will remove the prefix
- // from all devices, including the ones that next hop attaches to.
-
- // Also remove redirection flows on the pair device if exists.
- Optional<DeviceId> pairDeviceId = srManager.getPairDeviceId(location.deviceId());
- Optional<PortNumber> pairLocalPort = srManager.getPairLocalPort(location.deviceId());
- if (pairDeviceId.isPresent() && pairLocalPort.isPresent()) {
- // NOTE: Since the pairLocalPort is trunk port, use assigned vlan of original port
- // when the host is untagged
- VlanId vlanId = Optional.ofNullable(srManager.getInternalVlanId(location)).orElse(nextHopVlan);
-
- log.debug("RouteRemoved. revokeRoute {}, {}, {}, {}", location, prefix, nextHopMac, nextHopVlan);
- srManager.defaultRoutingHandler.revokeRoute(pairDeviceId.get(), prefix,
- nextHopMac, vlanId, pairLocalPort.get(), false);
- }
- });
- });
- }
-
- void processHostMovedEvent(HostEvent event) {
- log.info("processHostMovedEvent {}", event);
- MacAddress hostMac = event.subject().mac();
- VlanId hostVlanId = event.subject().vlan();
-
- Set<HostLocation> prevLocations = event.prevSubject().locations();
- Set<HostLocation> newLocations = event.subject().locations();
- Set<ConnectPoint> connectPoints = newLocations.stream()
- .map(l -> (ConnectPoint) l).collect(Collectors.toSet());
- List<Set<IpPrefix>> batchedSubnets =
- srManager.deviceConfiguration.getBatchedSubnets(event.subject().id());
- Set<DeviceId> newDeviceIds = newLocations.stream().map(HostLocation::deviceId)
- .collect(Collectors.toSet());
-
- // Set of deviceIDs of the previous locations where the host was connected
- // Used to determine if host moved to different connect points
- // on same device or moved to a different device altogether
- Set<DeviceId> oldDeviceIds = prevLocations.stream().map(HostLocation::deviceId)
- .collect(Collectors.toSet());
-
- // L3 Ucast bucket needs to be updated only once per host
- // and only when the no. of routes with the host as next-hop is not zero
- if (!batchedSubnets.isEmpty()) {
- // For each new location, if NextObj exists for the host, update with new location ..
- Sets.difference(newLocations, prevLocations).forEach(newLocation -> {
- int nextId = srManager.getMacVlanNextObjectiveId(newLocation.deviceId(),
- hostMac, hostVlanId, null, false);
- VlanId vlanId = Optional.ofNullable(srManager.getInternalVlanId(newLocation)).orElse(hostVlanId);
-
- if (nextId != -1) {
- //Update the nextId group bucket
- log.debug("HostMoved. NextId exists, update L3 Ucast Group Bucket {}, {}, {} --> {}",
- newLocation, hostMac, vlanId, nextId);
- srManager.updateMacVlanTreatment(newLocation.deviceId(), hostMac, vlanId,
- newLocation.port(), nextId);
- } else {
- log.debug("HostMoved. NextId does not exist for this location {}, host {}/{}",
- newLocation, hostMac, vlanId);
- }
- });
- }
-
- batchedSubnets.forEach(subnets -> {
- log.debug("HostMoved. populateSubnet {}, {}", newLocations, subnets);
- srManager.defaultRoutingHandler.populateSubnet(connectPoints, subnets);
-
- subnets.forEach(prefix -> {
- // For each old location
- Sets.difference(prevLocations, newLocations).forEach(prevLocation -> {
-
- // Remove flows for unchanged IPs only when the host moves from a switch to another.
- // Otherwise, do not remove and let the adding part update the old flow
- if (newDeviceIds.contains(prevLocation.deviceId())) {
- return;
- }
-
- log.debug("HostMoved. removeSubnet {}, {}", prevLocation, prefix);
- srManager.deviceConfiguration.removeSubnet(prevLocation, prefix);
-
- // Do not remove flow from a device if the route is still reachable via its pair device.
- // populateSubnet will update the flow to point to its pair device via spine.
- DeviceId pairDeviceId = srManager.getPairDeviceId(prevLocation.deviceId()).orElse(null);
- if (newLocations.stream().anyMatch(n -> n.deviceId().equals(pairDeviceId))) {
- return;
- }
-
- log.debug("HostMoved. revokeRoute {}, {}, {}, {}", prevLocation, prefix, hostMac, hostVlanId);
- srManager.defaultRoutingHandler.revokeRoute(prevLocation.deviceId(), prefix,
- hostMac, hostVlanId, prevLocation.port(), false);
- });
-
- // For each new location, add all new IPs.
- Sets.difference(newLocations, prevLocations).forEach(newLocation -> {
- log.debug("HostMoved. addSubnet {}, {}", newLocation, prefix);
- srManager.deviceConfiguration.addSubnet(newLocation, prefix);
-
- //its a new connect point, not a move from an existing device, populateRoute
- if (!oldDeviceIds.contains(newLocation.deviceId())) {
- log.debug("HostMoved. populateRoute {}, {}, {}, {}", newLocation, prefix, hostMac, hostVlanId);
- srManager.defaultRoutingHandler.populateRoute(newLocation.deviceId(), prefix,
- hostMac, hostVlanId, newLocation.port(), false);
- }
- });
- });
- });
-
- }
-
- private boolean isReady() {
- return Objects.nonNull(srManager.deviceConfiguration) &&
- Objects.nonNull(srManager.defaultRoutingHandler);
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/RouteSimplifierUtils.java b/app/src/main/java/org/onosproject/segmentrouting/RouteSimplifierUtils.java
deleted file mode 100644
index 401007c..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/RouteSimplifierUtils.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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;
-
-import com.google.common.collect.ImmutableList;
-import org.onlab.packet.IpPrefix;
-import org.onosproject.routeservice.ResolvedRoute;
-import org.onosproject.routeservice.Route;
-
-/**
- * Utility class for route simplification.
- */
-final class RouteSimplifierUtils {
-
- /*
- * When route with source type listed in leafExclusionRouteTypes,
- * it will programme only on the leaf pair the nexthop attaches to. Other leaves will be ignored.
- */
- private static final ImmutableList<Route.Source> LEAF_EXCLUSION_ROUTE_TYPES =
- ImmutableList.of(Route.Source.DHCP, Route.Source.RIP, Route.Source.DHCPLQ);
-
- private SegmentRoutingManager srManager;
-
- RouteSimplifierUtils(SegmentRoutingManager srManager) {
-
- this.srManager = srManager;
- }
-
- /**
- * Checking whether the leafExclusionRouteTypes contains the given source type.
- *
- * @param s source type
- * @return boolean if it containsd the source type.
- *
- */
- public boolean hasLeafExclusionEnabledForType(Route.Source s) {
- return LEAF_EXCLUSION_ROUTE_TYPES.contains(s);
- }
-
- /**
- * When route with any source of given prefix is listed in leafExclusionRouteTypes,
- * it will programme only on the leaf pair the nexthop attaches to. Other leaves will be ignored.
- *
- * @param ipPrefix ip prefix of the route.
- * @return boolean if contains the prefix of the mentioned source type.
- */
- public boolean hasLeafExclusionEnabledForPrefix(IpPrefix ipPrefix) {
- for (ResolvedRoute route : srManager.routeService.getAllResolvedRoutes(ipPrefix)) {
- if (hasLeafExclusionEnabledForType(route.route().source())) {
- return true;
- }
- }
- return false;
- }
-
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java b/app/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
deleted file mode 100644
index a6f6e32..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
+++ /dev/null
@@ -1,1942 +0,0 @@
-/*
- * Copyright 2015-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;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-import org.apache.commons.lang3.tuple.ImmutablePair;
-import org.onlab.packet.EthType;
-import org.onlab.packet.Ethernet;
-import org.onlab.packet.IPv6;
-import org.onlab.packet.Ip4Address;
-import org.onlab.packet.Ip6Address;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.MplsLabel;
-import org.onlab.packet.VlanId;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.Device;
-import org.onosproject.net.Host;
-import org.onosproject.net.flowobjective.DefaultObjectiveContext;
-import org.onosproject.net.flowobjective.Objective;
-import org.onosproject.net.flowobjective.ObjectiveContext;
-import org.onosproject.net.flowobjective.ObjectiveError;
-import org.onosproject.net.intf.Interface;
-import org.onosproject.net.packet.PacketPriority;
-import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
-import org.onosproject.segmentrouting.config.DeviceConfiguration;
-import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
-import org.onosproject.segmentrouting.grouphandler.DestinationSet;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Port;
-import org.onosproject.net.PortNumber;
-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.criteria.Criteria;
-import org.onosproject.net.flowobjective.DefaultFilteringObjective;
-import org.onosproject.net.flowobjective.DefaultForwardingObjective;
-import org.onosproject.net.flowobjective.FilteringObjective;
-import org.onosproject.net.flowobjective.ForwardingObjective;
-import org.onosproject.net.flowobjective.ForwardingObjective.Builder;
-import org.onosproject.net.flowobjective.ForwardingObjective.Flag;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.stream.Collectors;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.onlab.packet.Ethernet.TYPE_ARP;
-import static org.onlab.packet.Ethernet.TYPE_IPV6;
-import static org.onlab.packet.ICMP6.NEIGHBOR_ADVERTISEMENT;
-import static org.onlab.packet.ICMP6.NEIGHBOR_SOLICITATION;
-import static org.onlab.packet.ICMP6.ROUTER_ADVERTISEMENT;
-import static org.onlab.packet.ICMP6.ROUTER_SOLICITATION;
-import static org.onlab.packet.IPv6.PROTOCOL_ICMP6;
-import static org.onosproject.segmentrouting.SegmentRoutingService.DEFAULT_PRIORITY;
-
-/**
- * Populator of segment routing flow rules.
- */
-public class RoutingRulePopulator {
- private static final Logger log = LoggerFactory.getLogger(RoutingRulePopulator.class);
-
- private static final int ARP_NDP_PRIORITY = 30000;
-
- private AtomicLong rulePopulationCounter;
- private SegmentRoutingManager srManager;
- private DeviceConfiguration config;
- private RouteSimplifierUtils routeSimplifierUtils;
-
- // used for signalling the driver to remove vlan table and tmac entry also
- private static final long CLEANUP_DOUBLE_TAGGED_HOST_ENTRIES = 1;
- private static final long DOUBLE_TAGGED_METADATA_MASK = 0xffffffffffffffffL;
-
- /**
- * Creates a RoutingRulePopulator object.
- *
- * @param srManager segment routing manager reference
- */
- RoutingRulePopulator(SegmentRoutingManager srManager) {
- this.srManager = srManager;
- this.config = checkNotNull(srManager.deviceConfiguration);
- this.rulePopulationCounter = new AtomicLong(0);
- this.routeSimplifierUtils = new RouteSimplifierUtils(srManager);
- }
-
- /**
- * Resets the population counter.
- */
- void resetCounter() {
- rulePopulationCounter.set(0);
- }
-
- /**
- * Returns the number of rules populated.
- *
- * @return number of rules
- */
- long getCounter() {
- return rulePopulationCounter.get();
- }
-
- /**
- * Populate a bridging rule on given deviceId that matches given mac, given vlan and
- * output to given port.
- *
- * @param deviceId device ID
- * @param port port
- * @param mac mac address
- * @param vlanId VLAN ID
- * @return future that carries the flow objective if succeeded, null if otherwise
- */
- CompletableFuture<Objective> populateBridging(DeviceId deviceId, PortNumber port, MacAddress mac, VlanId vlanId) {
- ForwardingObjective.Builder fob = bridgingFwdObjBuilder(deviceId, mac, vlanId, port, false);
- if (fob == null) {
- log.warn("Fail to build fwd obj for host {}/{}. Abort.", mac, vlanId);
- return CompletableFuture.completedFuture(null);
- }
-
- CompletableFuture<Objective> future = new CompletableFuture<>();
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> {
- log.debug("Brigding rule for {}/{} populated", mac, vlanId);
- future.complete(objective);
- },
- (objective, error) -> {
- log.warn("Failed to populate bridging rule for {}/{}: {}", mac, vlanId, error);
- future.complete(null);
- });
- srManager.flowObjectiveService.forward(deviceId, fob.add(context));
- return future;
- }
-
- /**
- * Revoke a bridging rule on given deviceId that matches given mac, given vlan and
- * output to given port.
- *
- * @param deviceId device ID
- * @param port port
- * @param mac mac address
- * @param vlanId VLAN ID
- * @return future that carries the flow objective if succeeded, null if otherwise
- */
- CompletableFuture<Objective> revokeBridging(DeviceId deviceId, PortNumber port, MacAddress mac, VlanId vlanId) {
- ForwardingObjective.Builder fob = bridgingFwdObjBuilder(deviceId, mac, vlanId, port, true);
- if (fob == null) {
- log.warn("Fail to build fwd obj for host {}/{}. Abort.", mac, vlanId);
- return CompletableFuture.completedFuture(null);
- }
-
- CompletableFuture<Objective> future = new CompletableFuture<>();
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> {
- log.debug("Brigding rule for {}/{} revoked", mac, vlanId);
- future.complete(objective);
- },
- (objective, error) -> {
- log.warn("Failed to revoke bridging rule for {}/{}: {}", mac, vlanId, error);
- future.complete(null);
- });
- srManager.flowObjectiveService.forward(deviceId, fob.remove(context));
- return future;
- }
-
- /**
- * Generates a forwarding objective builder for bridging rules.
- * <p>
- * The forwarding objective bridges packets destined to a given MAC to
- * given port on given device.
- *
- * @param deviceId Device that host attaches to
- * @param mac MAC address of the host
- * @param hostVlanId VLAN ID of the host
- * @param outport Port that host attaches to
- * @param revoke true if forwarding objective is meant to revoke forwarding rule
- * @return Forwarding objective builder
- */
- private ForwardingObjective.Builder bridgingFwdObjBuilder(
- DeviceId deviceId, MacAddress mac, VlanId hostVlanId, PortNumber outport, boolean revoke) {
- ConnectPoint connectPoint = new ConnectPoint(deviceId, outport);
- VlanId untaggedVlan = srManager.interfaceService.getUntaggedVlanId(connectPoint);
- Set<VlanId> taggedVlans = srManager.interfaceService.getTaggedVlanId(connectPoint);
- VlanId nativeVlan = srManager.interfaceService.getNativeVlanId(connectPoint);
-
- // Create host selector
- TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
- sbuilder.matchEthDst(mac);
-
- // Create host treatment
- TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
- tbuilder.immediate().setOutput(outport);
-
- // Create host meta
- TrafficSelector.Builder mbuilder = DefaultTrafficSelector.builder();
-
- // Adjust the selector, treatment and meta according to VLAN configuration
- if (taggedVlans.contains(hostVlanId)) {
- sbuilder.matchVlanId(hostVlanId);
- mbuilder.matchVlanId(hostVlanId);
- } else if (hostVlanId.equals(VlanId.NONE)) {
- if (untaggedVlan != null) {
- sbuilder.matchVlanId(untaggedVlan);
- mbuilder.matchVlanId(untaggedVlan);
- tbuilder.immediate().popVlan();
- } else if (nativeVlan != null) {
- sbuilder.matchVlanId(nativeVlan);
- mbuilder.matchVlanId(nativeVlan);
- tbuilder.immediate().popVlan();
- } else {
- log.warn("Untagged host {}/{} is not allowed on {} without untagged or native" +
- "vlan config", mac, hostVlanId, connectPoint);
- return null;
- }
- } else {
- log.warn("Tagged host {}/{} is not allowed on {} without VLAN listed in tagged vlan",
- mac, hostVlanId, connectPoint);
- return null;
- }
-
- // All forwarding is via Groups. Drivers can re-purpose to flow-actions if needed.
- // If the objective is to revoke an existing rule, and for some reason
- // the next-objective does not exist, then a new one should not be created
- int portNextObjId = srManager.getPortNextObjectiveId(deviceId, outport,
- tbuilder.build(), mbuilder.build(), !revoke);
- if (portNextObjId == -1) {
- // Warning log will come from getPortNextObjective method
- return null;
- }
-
- return DefaultForwardingObjective.builder()
- .withFlag(ForwardingObjective.Flag.SPECIFIC)
- .withSelector(sbuilder.build())
- .nextStep(portNextObjId)
- .withPriority(100)
- .fromApp(srManager.appId)
- .makePermanent();
- }
-
- /**
- * Populate or revoke a bridging rule on given deviceId that matches given vlanId,
- * and hostMAC connected to given port, and output to given port only when
- * vlan information is valid.
- *
- * @param deviceId device ID that host attaches to
- * @param portNum port number that host attaches to
- * @param hostMac mac address of the host connected to the switch port
- * @param vlanId Vlan ID configured on the switch port
- * @param popVlan true to pop Vlan tag at TrafficTreatment, false otherwise
- * @param install true to populate the objective, false to revoke
- */
- // TODO Refactor. There are a lot of duplications between this method, populateBridging,
- // revokeBridging and bridgingFwdObjBuilder.
- void updateBridging(DeviceId deviceId, PortNumber portNum, MacAddress hostMac,
- VlanId vlanId, boolean popVlan, boolean install) {
- // Create host selector
- TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
- sbuilder.matchEthDst(hostMac);
-
- // Create host meta
- TrafficSelector.Builder mbuilder = DefaultTrafficSelector.builder();
-
- sbuilder.matchVlanId(vlanId);
- mbuilder.matchVlanId(vlanId);
-
- // Create host treatment
- TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
- tbuilder.immediate().setOutput(portNum);
-
- if (popVlan) {
- tbuilder.immediate().popVlan();
- }
-
- int portNextObjId = srManager.getPortNextObjectiveId(deviceId, portNum,
- tbuilder.build(), mbuilder.build(), install);
- if (portNextObjId != -1) {
- ForwardingObjective.Builder fob = DefaultForwardingObjective.builder()
- .withFlag(ForwardingObjective.Flag.SPECIFIC)
- .withSelector(sbuilder.build())
- .nextStep(portNextObjId)
- .withPriority(100)
- .fromApp(srManager.appId)
- .makePermanent();
-
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> log.debug("Brigding rule for {}/{} {}", hostMac, vlanId,
- install ? "populated" : "revoked"),
- (objective, error) -> log.warn("Failed to {} bridging rule for {}/{}: {}",
- install ? "populate" : "revoke", hostMac, vlanId, error));
- srManager.flowObjectiveService.forward(deviceId, install ? fob.add(context) : fob.remove(context));
- } else {
- log.warn("Failed to retrieve next objective for {}/{}", hostMac, vlanId);
- }
- }
-
- /**
- * Populates IP rules for a route that has direct connection to the switch.
- * This method should not be invoked directly without going through DefaultRoutingHandler.
- *
- * @param deviceId device ID of the device that next hop attaches to
- * @param prefix IP prefix of the route
- * @param hostMac MAC address of the next hop
- * @param hostVlanId Vlan ID of the nexthop
- * @param outPort port where the next hop attaches to
- * @param directHost host is of type direct or indirect
- * @return future that carries the flow objective if succeeded, null if otherwise
- */
- CompletableFuture<Objective> populateRoute(DeviceId deviceId, IpPrefix prefix,
- MacAddress hostMac, VlanId hostVlanId, PortNumber outPort, boolean directHost) {
- log.debug("Populate direct routing entry for route {} at {}:{}",
- prefix, deviceId, outPort);
- ForwardingObjective.Builder fwdBuilder;
- try {
- fwdBuilder = routingFwdObjBuilder(deviceId, prefix, hostMac,
- hostVlanId, outPort, null, null, directHost, false);
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage() + " Aborting direct populateRoute");
- return CompletableFuture.completedFuture(null);
- }
- if (fwdBuilder == null) {
- log.warn("Aborting host routing table entry due "
- + "to error for dev:{} route:{}", deviceId, prefix);
- return CompletableFuture.completedFuture(null);
- }
-
- int nextId = fwdBuilder.add().nextId();
- CompletableFuture<Objective> future = new CompletableFuture<>();
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> {
- log.debug("Direct routing rule for route {} populated. nextId={}", prefix, nextId);
- future.complete(objective);
- },
- (objective, error) -> {
- log.warn("Failed to populate direct routing rule for route {}: {}", prefix, error);
- future.complete(null);
- });
- srManager.flowObjectiveService.forward(deviceId, fwdBuilder.add(context));
- rulePopulationCounter.incrementAndGet();
- return future;
- }
-
- /**
- * Removes IP rules for a route when the next hop is gone.
- * This method should not be invoked directly without going through DefaultRoutingHandler.
- *
- * @param deviceId device ID of the device that next hop attaches to
- * @param prefix IP prefix of the route
- * @param hostMac MAC address of the next hop
- * @param hostVlanId Vlan ID of the nexthop
- * @param outPort port that next hop attaches to
- * @param directHost host is of type direct or indirect
- * @return future that carries the flow objective if succeeded, null if otherwise
- */
- CompletableFuture<Objective> revokeRoute(DeviceId deviceId, IpPrefix prefix,
- MacAddress hostMac, VlanId hostVlanId, PortNumber outPort, boolean directHost) {
- log.debug("Revoke IP table entry for route {} at {}:{}",
- prefix, deviceId, outPort);
- ForwardingObjective.Builder fwdBuilder;
- try {
- fwdBuilder = routingFwdObjBuilder(deviceId, prefix, hostMac,
- hostVlanId, outPort, null, null, directHost, true);
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage() + " Aborting revokeIpRuleForHost.");
- return CompletableFuture.completedFuture(null);
- }
- if (fwdBuilder == null) {
- log.warn("Aborting host routing table entries due "
- + "to error for dev:{} route:{}", deviceId, prefix);
- return CompletableFuture.completedFuture(null);
- }
-
- CompletableFuture<Objective> future = new CompletableFuture<>();
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> {
- log.debug("IP rule for route {} revoked", prefix);
- future.complete(objective);
- },
- (objective, error) -> {
- log.warn("Failed to revoke IP rule for route {}: {}", prefix, error);
- future.complete(null);
- });
- srManager.flowObjectiveService.forward(deviceId, fwdBuilder.remove(context));
- return future;
- }
-
- /**
- * Returns a forwarding objective builder for routing rules.
- * <p>
- * The forwarding objective routes packets destined to a given prefix to
- * given port on given device with given destination MAC.
- *
- * @param deviceId device ID
- * @param prefix prefix that need to be routed
- * @param hostMac MAC address of the nexthop
- * @param hostVlanId Vlan ID of the nexthop
- * @param outPort port where the nexthop attaches to
- * @param revoke true if forwarding objective is meant to revoke forwarding rule
- * @param directHost host is direct or indirect
- * @return forwarding objective builder
- * @throws DeviceConfigNotFoundException if given device is not configured
- */
-
- private ForwardingObjective.Builder routingFwdObjBuilder(
- DeviceId deviceId, IpPrefix prefix,
- MacAddress hostMac, VlanId hostVlanId, PortNumber outPort,
- VlanId innerVlan, EthType outerTpid,
- boolean directHost, boolean revoke)
- throws DeviceConfigNotFoundException {
- int nextObjId;
- if (directHost) {
- // if the objective is to revoke an existing rule, and for some reason
- // the next-objective does not exist, then a new one should not be created
- ImmutablePair<TrafficTreatment, TrafficSelector> treatmentAndMeta =
- getTreatmentAndMeta(deviceId, hostMac, hostVlanId, outPort, innerVlan, outerTpid);
- if (treatmentAndMeta == null) {
- // Warning log will come from getTreatmentAndMeta method
- return null;
- }
- nextObjId = srManager.getPortNextObjectiveId(deviceId, outPort,
- treatmentAndMeta.getLeft(), treatmentAndMeta.getRight(), !revoke);
- } else {
- // if the objective is to revoke an existing rule, and for some reason
- // the next-objective does not exist, then a new one should not be created
- nextObjId = srManager.getMacVlanNextObjectiveId(deviceId, hostMac, hostVlanId,
- outPort, !revoke);
- }
- if (nextObjId == -1) {
- // Warning log will come from getMacVlanNextObjective method
- return null;
- }
-
- return DefaultForwardingObjective.builder()
- .withSelector(buildIpSelectorFromIpPrefix(prefix).build())
- .nextStep(nextObjId)
- .fromApp(srManager.appId).makePermanent()
- .withPriority(getPriorityFromPrefix(prefix))
- .withFlag(ForwardingObjective.Flag.SPECIFIC);
- }
-
- private ImmutablePair<TrafficTreatment, TrafficSelector> getTreatmentAndMeta(
- DeviceId deviceId, MacAddress hostMac, VlanId hostVlanId, PortNumber outPort,
- VlanId innerVlan, EthType outerTpid)
- throws DeviceConfigNotFoundException {
- MacAddress routerMac;
- routerMac = config.getDeviceMac(deviceId);
-
- ConnectPoint connectPoint = new ConnectPoint(deviceId, outPort);
- VlanId untaggedVlan = srManager.interfaceService.getUntaggedVlanId(connectPoint);
- Set<VlanId> taggedVlans = srManager.interfaceService.getTaggedVlanId(connectPoint);
- VlanId nativeVlan = srManager.interfaceService.getNativeVlanId(connectPoint);
-
- // Create route treatment
- TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
- tbuilder.deferred()
- .setEthDst(hostMac)
- .setEthSrc(routerMac)
- .setOutput(outPort);
-
- // Create route meta
- TrafficSelector.Builder mbuilder = DefaultTrafficSelector.builder();
-
- // Adjust treatment and meta according to VLAN configuration
- if (taggedVlans.contains(hostVlanId)) {
- tbuilder.setVlanId(hostVlanId);
- } else if (hostVlanId.equals(VlanId.NONE)) {
- if (untaggedVlan != null) {
- mbuilder.matchVlanId(untaggedVlan);
- } else if (nativeVlan != null) {
- mbuilder.matchVlanId(nativeVlan);
- } else {
- log.warn("Untagged nexthop {}/{} is not allowed on {} without untagged or native vlan",
- hostMac, hostVlanId, connectPoint);
- return null;
- }
- } else {
- // Double tagged hosts
- if (innerVlan == null || outerTpid == null) {
- log.warn("Failed to construct NextObj for double tagged hosts {}/{}. {} {}",
- hostMac, hostVlanId,
- (innerVlan == null) ? "innerVlan = null." : "",
- (outerTpid == null) ? "outerTpid = null." : "");
- return null;
- }
- tbuilder.setVlanId(innerVlan);
- tbuilder.pushVlan(outerTpid);
- tbuilder.setVlanId(hostVlanId);
- mbuilder.matchVlanId(VlanId.ANY);
- }
-
- return ImmutablePair.of(tbuilder.build(), mbuilder.build());
- }
-
- /**
- * Populates IP flow rules for all the given prefixes reachable from the
- * destination switch(es).
- *
- * @param targetSw switch where rules are to be programmed
- * @param subnets subnets/prefixes being added
- * @param destSw1 destination switch where the prefixes are reachable
- * @param destSw2 paired destination switch if one exists for the subnets/prefixes.
- * Should be null if there is no paired destination switch (by config)
- * or if the given prefixes are reachable only via destSw1
- * @param nextHops a map containing a set of next-hops for each destination switch.
- * If destSw2 is not null, then this map must contain an
- * entry for destSw2 with its next-hops from the targetSw
- * (although the next-hop set may be empty in certain scenarios).
- * If destSw2 is null, there should not be an entry in this
- * map for destSw2.
- * @return true if all rules are set successfully, false otherwise
- */
- boolean populateIpRuleForSubnet(DeviceId targetSw, Set<IpPrefix> subnets,
- DeviceId destSw1, DeviceId destSw2, Map<DeviceId, Set<DeviceId>> nextHops) {
- // Get pair device of the target switch
- Optional<DeviceId> pairDev = srManager.getPairDeviceId(targetSw);
- // Route simplification will be off in case of the nexthop location at target switch is down
- // (routing through spine case)
- boolean routeSimplOff = pairDev.isPresent() && pairDev.get().equals(destSw1) && destSw2 == null;
- // Iterates over the routes. Checking:
- // If route simplification is enabled
- // If the target device is another leaf in the network
- if (srManager.routeSimplification && !routeSimplOff) {
- Set<IpPrefix> subnetsToBePopulated = Sets.newHashSet();
- for (IpPrefix subnet : subnets) {
- // Skip route programming on the target device
- // If route simplification applies
- if (routeSimplifierUtils.hasLeafExclusionEnabledForPrefix(subnet)) {
- // XXX route simplification assumes that source of the traffic
- // towards the nexthops are co-located with the nexthops. In different
- // scenarios will not work properly.
- continue;
- }
- // populate the route in the remaning scenarios
- subnetsToBePopulated.add(subnet);
- }
- subnets = subnetsToBePopulated;
- }
- // populate the remaining routes in the target switch
- return populateIpRulesForRouter(targetSw, subnets, destSw1, destSw2, nextHops);
- }
-
- /**
- * Revokes IP flow rules for the subnets from given device.
- *
- * @param targetSw target switch from which the subnets need to be removed
- * @param subnets subnet being removed
- * @return true if all rules are removed successfully, false otherwise
- */
- boolean revokeIpRuleForSubnet(DeviceId targetSw, Set<IpPrefix> subnets) {
- for (IpPrefix subnet : subnets) {
- if (!revokeIpRuleForRouter(targetSw, subnet)) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Populates IP flow rules for a set of IP prefix in the target device.
- * The prefix are reachable via destination device(s).
- *
- * @param targetSw target device ID to set the rules
- * @param subnets the set of IP prefix
- * @param destSw1 destination switch where the prefixes are reachable
- * @param destSw2 paired destination switch if one exists for the subnets/prefixes.
- * Should be null if there is no paired destination switch (by config)
- * or if the given prefixes are reachable only via destSw1
- * @param nextHops map of destination switches and their next-hops.
- * Should only contain destination switches that are
- * actually meant to be routed to. If destSw2 is null, there
- * should not be an entry for destSw2 in this map.
- * @return true if all rules are set successfully, false otherwise
- */
- private boolean populateIpRulesForRouter(DeviceId targetSw,
- Set<IpPrefix> subnets,
- DeviceId destSw1, DeviceId destSw2,
- Map<DeviceId, Set<DeviceId>> nextHops) {
- // pre-compute the needed information
- int segmentIdIPv41, segmentIdIPv42 = -1;
- int segmentIdIPv61, segmentIdIPv62 = -1;
- TrafficTreatment treatment = null;
- DestinationSet dsIPv4, dsIPv6;
- TrafficSelector metaIpv4Selector, metaIpv6Selector = null;
- int nextIdIPv4, nextIdIPv6, nextId;
- TrafficSelector selector;
- // start with MPLS SIDs
- try {
- segmentIdIPv41 = config.getIPv4SegmentId(destSw1);
- segmentIdIPv61 = config.getIPv6SegmentId(destSw1);
- if (destSw2 != null) {
- segmentIdIPv42 = config.getIPv4SegmentId(destSw2);
- segmentIdIPv62 = config.getIPv6SegmentId(destSw2);
- }
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage() + " Aborting populateIpRuleForRouter.");
- return false;
- }
- // build the IPv4 and IPv6 destination set
- if (destSw2 == null) {
- // single dst - create destination set based on next-hop
- // If the next hop is the same as the final destination, then MPLS
- // label is not set.
- Set<DeviceId> nhd1 = nextHops.get(destSw1);
- if (nhd1.size() == 1 && nhd1.iterator().next().equals(destSw1)) {
- dsIPv4 = DestinationSet.createTypePushNone(destSw1);
- dsIPv6 = DestinationSet.createTypePushNone(destSw1);
- treatment = DefaultTrafficTreatment.builder()
- .immediate()
- .decNwTtl()
- .build();
- } else {
- dsIPv4 = DestinationSet.createTypePushBos(segmentIdIPv41, destSw1);
- dsIPv6 = DestinationSet.createTypePushBos(segmentIdIPv61, destSw1);
- }
- } else {
- // dst pair - IP rules for dst-pairs are always from other edge nodes
- // the destination set needs to have both destinations, even if there
- // are no next hops to one of them
- dsIPv4 = DestinationSet.createTypePushBos(segmentIdIPv41, destSw1, segmentIdIPv42, destSw2);
- dsIPv6 = DestinationSet.createTypePushBos(segmentIdIPv61, destSw1, segmentIdIPv62, destSw2);
- }
-
- // setup metadata to pass to nextObjective - indicate the vlan on egress
- // if needed by the switch pipeline. Since neighbor sets are always to
- // other neighboring routers, there is no subnet assigned on those ports.
- metaIpv4Selector = buildIpv4Selector()
- .matchVlanId(srManager.getDefaultInternalVlan())
- .build();
- metaIpv6Selector = buildIpv6Selector()
- .matchVlanId(srManager.getDefaultInternalVlan())
- .build();
- // get the group handler of the target switch
- DefaultGroupHandler grpHandler = srManager.getGroupHandler(targetSw);
- if (grpHandler == null) {
- log.warn("populateIPRuleForRouter: groupHandler for device {} "
- + "not found", targetSw);
- return false;
- }
- // get next id
- nextIdIPv4 = grpHandler.getNextObjectiveId(dsIPv4, nextHops, metaIpv4Selector, false);
- if (nextIdIPv4 <= 0) {
- log.warn("No next objective in {} for ds: {}", targetSw, dsIPv4);
- return false;
- }
- nextIdIPv6 = grpHandler.getNextObjectiveId(dsIPv6, nextHops, metaIpv6Selector, false);
- if (nextIdIPv6 <= 0) {
- log.warn("No next objective in {} for ds: {}", targetSw, dsIPv6);
- return false;
- }
- // build all the flow rules and send to the device
- for (IpPrefix subnet : subnets) {
- selector = buildIpSelectorFromIpPrefix(subnet).build();
- if (subnet.isIp4()) {
- nextId = nextIdIPv4;
- } else {
- nextId = nextIdIPv6;
- }
- ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
- .builder()
- .fromApp(srManager.appId)
- .makePermanent()
- .nextStep(nextId)
- .withSelector(selector)
- .withPriority(getPriorityFromPrefix(subnet))
- .withFlag(ForwardingObjective.Flag.SPECIFIC);
- if (treatment != null) {
- fwdBuilder.withTreatment(treatment);
- }
- log.debug("Installing {} forwarding objective for router IP/subnet {} "
- + "in switch {} with nextId: {}", subnet.isIp4() ? "IPv4" : "IPv6",
- subnet, targetSw, nextId);
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> log.debug("IP rule for router {} populated in dev:{}",
- subnet, targetSw),
- (objective, error) -> log.warn("Failed to populate IP rule for router {}: {} in dev:{}",
- subnet, error, targetSw));
- srManager.flowObjectiveService.forward(targetSw, fwdBuilder.add(context));
- }
- rulePopulationCounter.addAndGet(subnets.size());
- return true;
- }
-
- /**
- * Revokes IP flow rules for the router IP address from given device.
- *
- * @param targetSw target switch from which the ipPrefix need to be removed
- * @param ipPrefix the IP address of the destination router
- * @return true if all rules are removed successfully, false otherwise
- */
- private boolean revokeIpRuleForRouter(DeviceId targetSw, IpPrefix ipPrefix) {
- TrafficSelector.Builder sbuilder = buildIpSelectorFromIpPrefix(ipPrefix);
- TrafficSelector selector = sbuilder.build();
- TrafficTreatment dummyTreatment = DefaultTrafficTreatment.builder().build();
-
- ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
- .builder()
- .fromApp(srManager.appId)
- .makePermanent()
- .withSelector(selector)
- .withTreatment(dummyTreatment)
- .withPriority(getPriorityFromPrefix(ipPrefix))
- .withFlag(ForwardingObjective.Flag.SPECIFIC);
-
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> log.debug("IP rule for router {} revoked from {}", ipPrefix, targetSw),
- (objective, error) -> log.warn("Failed to revoke IP rule for router {} from {}: {}",
- ipPrefix, targetSw, error));
- srManager.flowObjectiveService.forward(targetSw, fwdBuilder.remove(context));
-
- return true;
- }
-
- /**
- * Populates MPLS flow rules in the target device to point towards the
- * destination device.
- *
- * @param targetSwId target device ID of the switch to set the rules
- * @param destSwId destination switch device ID
- * @param nextHops next hops switch ID list
- * @param routerIp the router ip of the destination switch
- * @return true if all rules are set successfully, false otherwise
- */
- boolean populateMplsRule(DeviceId targetSwId, DeviceId destSwId,
- Set<DeviceId> nextHops, IpAddress routerIp) {
- int segmentId;
- try {
- if (routerIp.isIp4()) {
- segmentId = config.getIPv4SegmentId(destSwId);
- } else {
- segmentId = config.getIPv6SegmentId(destSwId);
- }
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage() + " Aborting populateMplsRule.");
- return false;
- }
-
- List<ForwardingObjective> fwdObjs = new ArrayList<>();
- Collection<ForwardingObjective> fwdObjsMpls;
- // Generates the transit rules used by the standard "routing".
- fwdObjsMpls = handleMpls(targetSwId, destSwId, nextHops, segmentId,
- routerIp, true);
- if (fwdObjsMpls.isEmpty()) {
- return false;
- }
- fwdObjs.addAll(fwdObjsMpls);
-
- // Generates the transit rules used by the MPLS Pwaas.
- int pwSrLabel;
- try {
- pwSrLabel = config.getPWRoutingLabel(destSwId);
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage()
- + " Aborting populateMplsRule. No label for PseudoWire traffic.");
- return false;
- }
- fwdObjsMpls = handleMpls(targetSwId, destSwId, nextHops, pwSrLabel,
- routerIp, false);
- if (fwdObjsMpls.isEmpty()) {
- return false;
- }
- fwdObjs.addAll(fwdObjsMpls);
-
- for (ForwardingObjective fwdObj : fwdObjs) {
- log.debug("Sending MPLS fwd obj {} for SID {}-> next {} in sw: {}",
- fwdObj.id(), segmentId, fwdObj.nextId(), targetSwId);
- srManager.flowObjectiveService.forward(targetSwId, fwdObj);
- rulePopulationCounter.incrementAndGet();
- }
-
- return true;
- }
-
- /**
- * Differentiates between popping and swapping labels when building an MPLS
- * forwarding objective.
- *
- * @param targetSwId the target sw
- * @param destSwId the destination sw
- * @param nextHops the set of next hops
- * @param segmentId the segmentId to match representing the destination
- * switch
- * @param routerIp the router ip representing the destination switch
- * @return a collection of fwdobjective
- */
- private Collection<ForwardingObjective> handleMpls(
- DeviceId targetSwId,
- DeviceId destSwId,
- Set<DeviceId> nextHops,
- int segmentId,
- IpAddress routerIp,
- boolean isMplsBos) {
-
- TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
- List<ForwardingObjective.Builder> fwdObjBuilders = Lists.newArrayList();
- // For the transport of Pwaas we can use two or three MPLS label
- sbuilder.matchEthType(Ethernet.MPLS_UNICAST);
- sbuilder.matchMplsLabel(MplsLabel.mplsLabel(segmentId));
- sbuilder.matchMplsBos(isMplsBos);
- TrafficSelector selector = sbuilder.build();
-
- // setup metadata to pass to nextObjective - indicate the vlan on egress
- // if needed by the switch pipeline. Since mpls next-hops are always to
- // other neighboring routers, there is no subnet assigned on those ports.
- TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder(selector);
- metabuilder.matchVlanId(srManager.getDefaultInternalVlan());
-
- if (nextHops.size() == 1 && destSwId.equals(nextHops.toArray()[0])) {
- // If the next hop is the destination router for the segment, do pop
- log.debug("populateMplsRule: Installing MPLS forwarding objective for "
- + "label {} in switch {} with pop to next-hops {}",
- segmentId, targetSwId, nextHops);
- ForwardingObjective.Builder fwdObjNoBosBuilder =
- getMplsForwardingObjective(targetSwId,
- nextHops,
- true,
- isMplsBos,
- metabuilder.build(),
- routerIp,
- segmentId,
- destSwId);
- // Error case, we cannot handle, exit.
- if (fwdObjNoBosBuilder == null) {
- return Collections.emptyList();
- }
- fwdObjBuilders.add(fwdObjNoBosBuilder);
-
- } else {
- // next hop is not destination, irrespective of the number of next
- // hops (1 or more) -- SR CONTINUE case (swap with self)
- log.debug("Installing MPLS forwarding objective for "
- + "label {} in switch {} without pop to next-hops {}",
- segmentId, targetSwId, nextHops);
- ForwardingObjective.Builder fwdObjNoBosBuilder =
- getMplsForwardingObjective(targetSwId,
- nextHops,
- false,
- isMplsBos,
- metabuilder.build(),
- routerIp,
- segmentId,
- destSwId);
- // Error case, we cannot handle, exit.
- if (fwdObjNoBosBuilder == null) {
- return Collections.emptyList();
- }
- fwdObjBuilders.add(fwdObjNoBosBuilder);
-
- }
-
- List<ForwardingObjective> fwdObjs = Lists.newArrayList();
- // We add the final property to the fwdObjs.
- for (ForwardingObjective.Builder fwdObjBuilder : fwdObjBuilders) {
- ((Builder) ((Builder) fwdObjBuilder
- .fromApp(srManager.appId)
- .makePermanent())
- .withSelector(selector)
- .withPriority(SegmentRoutingService.DEFAULT_PRIORITY))
- .withFlag(ForwardingObjective.Flag.SPECIFIC);
-
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) ->
- log.debug("MPLS rule {} for SID {} populated in dev:{} ",
- objective.id(), segmentId, targetSwId),
- (objective, error) ->
- log.warn("Failed to populate MPLS rule {} for SID {}: {} in dev:{}",
- objective.id(), segmentId, error, targetSwId));
-
- ForwardingObjective fob = fwdObjBuilder.add(context);
- fwdObjs.add(fob);
- }
-
- return fwdObjs;
- }
-
- /**
- * Returns a Forwarding Objective builder for the MPLS rule that references
- * the desired Next Objective. Creates a DestinationSet that allows the
- * groupHandler to create or find the required next objective.
- *
- * @param targetSw the target sw
- * @param nextHops the set of next hops
- * @param phpRequired true if penultimate-hop-popping is required
- * @param isBos true if matched label is bottom-of-stack
- * @param meta metadata for creating next objective
- * @param routerIp the router ip representing the destination switch
- * @param destSw the destination sw
- * @return the mpls forwarding objective builder
- */
- private ForwardingObjective.Builder getMplsForwardingObjective(
- DeviceId targetSw,
- Set<DeviceId> nextHops,
- boolean phpRequired,
- boolean isBos,
- TrafficSelector meta,
- IpAddress routerIp,
- int segmentId,
- DeviceId destSw) {
-
- ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
- .builder().withFlag(ForwardingObjective.Flag.SPECIFIC);
-
- TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
- DestinationSet ds = null;
- DestinationSet.DestinationSetType dstType = null;
- boolean simple = false;
- if (phpRequired) {
- // php case - pop should always be flow-action
- log.debug("getMplsForwardingObjective: php required");
- tbuilder.deferred().copyTtlIn();
- if (isBos) {
- if (routerIp.isIp4()) {
- tbuilder.deferred().popMpls(EthType.EtherType.IPV4.ethType());
- } else {
- tbuilder.deferred().popMpls(EthType.EtherType.IPV6.ethType());
- }
- tbuilder.decNwTtl();
- // standard case -> BoS == True; pop results in IP packet and forwarding
- // is via an ECMP group
- ds = DestinationSet.createTypePopBos(destSw);
- } else {
- tbuilder.deferred().popMpls(EthType.EtherType.MPLS_UNICAST.ethType())
- .decMplsTtl();
- // double-label case -> BoS == False, pop results in MPLS packet
- // depending on configuration we can ECMP this packet or choose one output
- ds = DestinationSet.createTypePopNotBos(destSw);
- if (!srManager.getMplsEcmp()) {
- simple = true;
- }
- }
- } else {
- // swap with self case - SR CONTINUE
- log.debug("getMplsForwardingObjective: swap with self");
- tbuilder.deferred().decMplsTtl();
- // swap results in MPLS packet with same BoS bit regardless of bit value
- // depending on configuration we can ECMP this packet or choose one output
- // differentiate here between swap with not bos or swap with bos
- ds = isBos ? DestinationSet.createTypeSwapBos(segmentId, destSw) :
- DestinationSet.createTypeSwapNotBos(segmentId, destSw);
- if (!srManager.getMplsEcmp()) {
- simple = true;
- }
- }
-
- fwdBuilder.withTreatment(tbuilder.build());
- log.debug("Trying to get a nextObjId for mpls rule on device:{} to ds:{}",
- targetSw, ds);
- DefaultGroupHandler gh = srManager.getGroupHandler(targetSw);
- if (gh == null) {
- log.warn("getNextObjectiveId query - groupHandler for device {} "
- + "not found", targetSw);
- return null;
- }
-
- Map<DeviceId, Set<DeviceId>> dstNextHops = new HashMap<>();
- dstNextHops.put(destSw, nextHops);
- int nextId = gh.getNextObjectiveId(ds, dstNextHops, meta, simple);
- if (nextId <= 0) {
- log.warn("No next objective in {} for ds: {}", targetSw, ds);
- return null;
- } else {
- log.debug("nextObjId found:{} for mpls rule on device:{} to ds:{}",
- nextId, targetSw, ds);
- }
-
- fwdBuilder.nextStep(nextId);
- return fwdBuilder;
- }
-
- /**
- * Creates a filtering objective to permit all untagged packets with a
- * dstMac corresponding to the router's MAC address. For those pipelines
- * that need to internally assign vlans to untagged packets, this method
- * provides per-subnet vlan-ids as metadata.
- * <p>
- * Note that the vlan assignment and filter programming should only be done by
- * the master for a switch. This method is typically called at deviceAdd and
- * programs filters only for the enabled ports of the device. For port-updates,
- * that enable/disable ports after device add, singlePortFilter methods should
- * be called.
- *
- * @param deviceId the switch dpid for the router
- * @return PortFilterInfo information about the processed ports
- */
- PortFilterInfo populateVlanMacFilters(DeviceId deviceId) {
- log.debug("Installing per-port filtering objective for untagged "
- + "packets in device {}", deviceId);
-
- List<Port> devPorts = srManager.deviceService.getPorts(deviceId);
- if (devPorts == null || devPorts.isEmpty()) {
- log.warn("Device {} ports not available. Unable to add MacVlan filters",
- deviceId);
- return null;
- }
- int disabledPorts = 0, errorPorts = 0, filteredPorts = 0;
- for (Port port : devPorts) {
- if (!port.isEnabled()) {
- disabledPorts++;
- continue;
- }
- if (processSinglePortFilters(deviceId, port.number(), true)) {
- filteredPorts++;
- } else {
- errorPorts++;
- }
- }
- log.debug("Filtering on dev:{}, disabledPorts:{}, errorPorts:{}, filteredPorts:{}",
- deviceId, disabledPorts, errorPorts, filteredPorts);
- return new PortFilterInfo(disabledPorts, errorPorts, filteredPorts);
- }
-
- /**
- * Creates or removes filtering objectives for a single port. Should only be
- * called by the master for a switch.
- *
- * @param deviceId device identifier
- * @param portnum port identifier for port to be filtered
- * @param install true to install the filtering objective, false to remove
- * @return true if no errors occurred during the build of the filtering objective
- */
- boolean processSinglePortFilters(DeviceId deviceId, PortNumber portnum, boolean install) {
- ConnectPoint connectPoint = new ConnectPoint(deviceId, portnum);
- VlanId untaggedVlan = srManager.interfaceService.getUntaggedVlanId(connectPoint);
- Set<VlanId> taggedVlans = srManager.interfaceService.getTaggedVlanId(connectPoint);
- VlanId nativeVlan = srManager.interfaceService.getNativeVlanId(connectPoint);
-
- // Do not configure filter for edge ports where double-tagged hosts are connected.
- if (taggedVlans.size() != 0) {
- // Filter for tagged vlans
- if (!srManager.interfaceService.getTaggedVlanId(connectPoint).stream().allMatch(taggedVlanId ->
- processSinglePortFiltersInternal(deviceId, portnum, false, taggedVlanId, install))) {
- return false;
- }
- if (nativeVlan != null) {
- // Filter for native vlan
- if (!processSinglePortFiltersInternal(deviceId, portnum, true, nativeVlan, install)) {
- return false;
- }
- }
- } else if (untaggedVlan != null) {
- // Filter for untagged vlan
- if (!processSinglePortFiltersInternal(deviceId, portnum, true, untaggedVlan, install)) {
- return false;
- }
- } else if (!hasIPConfiguration(connectPoint)) {
- // Filter for unconfigured upstream port, using INTERNAL_VLAN
- if (!processSinglePortFiltersInternal(deviceId, portnum, true,
- srManager.getDefaultInternalVlan(),
- install)) {
- return false;
- }
- // Filter for receiveing pseudowire traffic
- if (!processSinglePortFiltersInternal(deviceId, portnum, false,
- srManager.getPwTransportVlan(),
- install)) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Updates filtering objectives for a single port. Should only be called by
- * the master for a switch
- * @param deviceId device identifier
- * @param portNum port identifier for port to be filtered
- * @param pushVlan true to push vlan, false otherwise
- * @param vlanId vlan identifier
- * @param install true to install the filtering objective, false to remove
- */
- void updateSinglePortFilters(DeviceId deviceId, PortNumber portNum,
- boolean pushVlan, VlanId vlanId, boolean install) {
- if (!processSinglePortFiltersInternal(deviceId, portNum, pushVlan, vlanId, install)) {
- log.warn("Failed to update FilteringObjective for {}/{} with vlan {}",
- deviceId, portNum, vlanId);
- }
- }
-
- private boolean processSinglePortFiltersInternal(DeviceId deviceId, PortNumber portnum,
- boolean pushVlan, VlanId vlanId, boolean install) {
- boolean doTMAC = true;
-
- if (!pushVlan) {
- // Skip the tagged vlans belonging to an interface without an IP address
- Set<Interface> ifaces = srManager.interfaceService
- .getInterfacesByPort(new ConnectPoint(deviceId, portnum))
- .stream()
- .filter(intf -> intf.vlanTagged().contains(vlanId) && intf.ipAddressesList().isEmpty())
- .collect(Collectors.toSet());
- if (!ifaces.isEmpty()) {
- log.debug("processSinglePortFiltersInternal: skipping TMAC for vlan {} at {}/{} - no IP",
- vlanId, deviceId, portnum);
- doTMAC = false;
- }
- }
-
- FilteringObjective.Builder fob = buildFilteringObjective(deviceId, portnum, pushVlan, vlanId, doTMAC);
- if (fob == null) {
- // error encountered during build
- return false;
- }
- log.debug("{} filtering objectives for dev/port: {}/{}",
- install ? "Installing" : "Removing", deviceId, portnum);
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> log.debug("Filter for {}/{} {}", deviceId, portnum,
- install ? "installed" : "removed"),
- (objective, error) -> log.warn("Failed to {} filter for {}/{}: {}",
- install ? "install" : "remove", deviceId, portnum, error));
- if (install) {
- srManager.flowObjectiveService.filter(deviceId, fob.add(context));
- } else {
- srManager.flowObjectiveService.filter(deviceId, fob.remove(context));
- }
- return true;
- }
-
- private FilteringObjective.Builder buildFilteringObjective(DeviceId deviceId, PortNumber portnum,
- boolean pushVlan, VlanId vlanId, boolean doTMAC) {
- MacAddress deviceMac;
- try {
- deviceMac = config.getDeviceMac(deviceId);
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage() + " Processing SinglePortFilters aborted");
- return null;
- }
- FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
-
- if (doTMAC) {
- fob.withKey(Criteria.matchInPort(portnum))
- .addCondition(Criteria.matchEthDst(deviceMac))
- .withPriority(SegmentRoutingService.DEFAULT_PRIORITY);
- } else {
- fob.withKey(Criteria.matchInPort(portnum))
- .withPriority(SegmentRoutingService.DEFAULT_PRIORITY);
- }
-
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
-
- if (pushVlan) {
- fob.addCondition(Criteria.matchVlanId(VlanId.NONE));
- tBuilder.pushVlan().setVlanId(vlanId);
- } else {
- fob.addCondition(Criteria.matchVlanId(vlanId));
- }
-
- // NOTE: Some switch hardware share the same filtering flow among different ports.
- // We use this metadata to let the driver know that there is no more enabled port
- // within the same VLAN on this device.
- if (noMoreEnabledPort(deviceId, vlanId)) {
- tBuilder.wipeDeferred();
- }
-
- fob.withMeta(tBuilder.build());
-
- fob.permit().fromApp(srManager.appId);
- return fob;
- }
-
- /**
- * Creates or removes filtering objectives for a double-tagged host on a port.
- *
- * @param deviceId device identifier
- * @param portNum port identifier for port to be filtered
- * @param outerVlan outer VLAN ID
- * @param innerVlan inner VLAN ID
- * @param install true to install the filtering objective, false to remove
- */
- void processDoubleTaggedFilter(DeviceId deviceId, PortNumber portNum, VlanId outerVlan,
- VlanId innerVlan, boolean install) {
- // We should trigger the removal of double tagged rules only when removing
- // the filtering objective and no other hosts are connected to the same device port.
- boolean cleanupDoubleTaggedRules = !anyDoubleTaggedHost(deviceId, portNum) && !install;
- FilteringObjective.Builder fob = buildDoubleTaggedFilteringObj(deviceId, portNum,
- outerVlan, innerVlan,
- cleanupDoubleTaggedRules);
- if (fob == null) {
- // error encountered during build
- return;
- }
- log.debug("{} double-tagged filtering objectives for dev/port: {}/{}",
- install ? "Installing" : "Removing", deviceId, portNum);
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> log.debug("Filter for {}/{} {}", deviceId, portNum,
- install ? "installed" : "removed"),
- (objective, error) -> log.warn("Failed to {} filter for {}/{}: {}",
- install ? "install" : "remove", deviceId, portNum, error));
- if (install) {
- srManager.flowObjectiveService.filter(deviceId, fob.add(context));
- } else {
- srManager.flowObjectiveService.filter(deviceId, fob.remove(context));
- }
- }
-
- /**
- * Checks if there is any double tagged host attached to given location.
- * This method will match on the effective location of a host.
- * That is, it will match on auxLocations when auxLocations is not null. Otherwise, it will match on locations.
- *
- * @param deviceId device ID
- * @param portNum port number
- * @return true if there is any host attached to given location.
- */
- private boolean anyDoubleTaggedHost(DeviceId deviceId, PortNumber portNum) {
- ConnectPoint cp = new ConnectPoint(deviceId, portNum);
- Set<Host> connectedHosts = srManager.hostService.getConnectedHosts(cp, false);
- Set<Host> auxConnectedHosts = srManager.hostService.getConnectedHosts(cp, true);
- return !auxConnectedHosts.isEmpty() ||
- connectedHosts.stream().anyMatch(host -> host.auxLocations() == null);
- }
-
- private FilteringObjective.Builder buildDoubleTaggedFilteringObj(DeviceId deviceId, PortNumber portNum,
- VlanId outerVlan, VlanId innerVlan,
- boolean cleanupDoubleTaggedRules) {
- MacAddress deviceMac;
- try {
- deviceMac = config.getDeviceMac(deviceId);
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage() + " Processing DoubleTaggedFilters aborted");
- return null;
- }
- FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
- // Outer vlan id match should be appeared before inner vlan id match.
- fob.withKey(Criteria.matchInPort(portNum))
- .addCondition(Criteria.matchEthDst(deviceMac))
- .addCondition(Criteria.matchVlanId(outerVlan))
- .addCondition(Criteria.matchInnerVlanId(innerVlan))
- .withPriority(SegmentRoutingService.DEFAULT_PRIORITY);
-
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
- // Pop outer vlan
- tBuilder.popVlan();
-
- // special metadata for driver
- if (cleanupDoubleTaggedRules) {
- tBuilder.writeMetadata(CLEANUP_DOUBLE_TAGGED_HOST_ENTRIES, DOUBLE_TAGGED_METADATA_MASK);
- } else {
- tBuilder.writeMetadata(0, DOUBLE_TAGGED_METADATA_MASK);
- }
-
- // NOTE: Some switch hardware share the same filtering flow among different ports.
- // We use this metadata to let the driver know that there is no more enabled port
- // within the same VLAN on this device.
- if (noMoreEnabledPort(deviceId, outerVlan)) {
- tBuilder.wipeDeferred();
- }
-
- fob.withMeta(tBuilder.build());
-
- fob.permit().fromApp(srManager.appId);
- return fob;
- }
-
- /**
- * Creates a forwarding objective to punt all IP packets, destined to the
- * router's port IP addresses, to the controller. Note that the input
- * port should not be matched on, as these packets can come from any input.
- * Furthermore, these are applied only by the master instance.
- *
- * @param deviceId the switch dpid for the router
- */
- void populateIpPunts(DeviceId deviceId) {
- Ip4Address routerIpv4, pairRouterIpv4 = null;
- Ip6Address routerIpv6, routerLinkLocalIpv6, pairRouterIpv6 = null;
- try {
- routerIpv4 = config.getRouterIpv4(deviceId);
- routerIpv6 = config.getRouterIpv6(deviceId);
- routerLinkLocalIpv6 = Ip6Address.valueOf(
- IPv6.getLinkLocalAddress(config.getDeviceMac(deviceId).toBytes()));
-
- if (config.isPairedEdge(deviceId)) {
- pairRouterIpv4 = config.getRouterIpv4(config.getPairDeviceId(deviceId));
- pairRouterIpv6 = config.getRouterIpv6(config.getPairDeviceId(deviceId));
- }
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage() + " Aborting populateIpPunts.");
- return;
- }
-
- if (!srManager.mastershipService.isLocalMaster(deviceId)) {
- log.debug("Not installing port-IP punts - not the master for dev:{} ",
- deviceId);
- return;
- }
- Set<IpAddress> allIps = new HashSet<>(config.getPortIPs(deviceId));
- allIps.add(routerIpv4);
- if (routerIpv6 != null) {
- allIps.add(routerIpv6);
- allIps.add(routerLinkLocalIpv6);
- }
- if (pairRouterIpv4 != null) {
- allIps.add(pairRouterIpv4);
- }
- if (pairRouterIpv6 != null) {
- allIps.add(pairRouterIpv6);
- }
- for (IpAddress ipaddr : allIps) {
- populateSingleIpPunts(deviceId, ipaddr);
- }
- }
-
- /**
- * Creates a forwarding objective to punt all IP packets, destined to the
- * specified IP address, which should be router's port IP address.
- *
- * @param deviceId the switch dpid for the router
- * @param ipAddress the IP address of the router's port
- */
- void populateSingleIpPunts(DeviceId deviceId, IpAddress ipAddress) {
- TrafficSelector.Builder sbuilder = buildIpSelectorFromIpAddress(ipAddress);
- Optional<DeviceId> optDeviceId = Optional.of(deviceId);
-
- srManager.packetService.requestPackets(sbuilder.build(),
- PacketPriority.CONTROL, srManager.appId, optDeviceId);
- }
-
- /**
- * Removes a forwarding objective to punt all IP packets, destined to the
- * specified IP address, which should be router's port IP address.
- *
- * @param deviceId the switch dpid for the router
- * @param ipAddress the IP address of the router's port
- */
- void revokeSingleIpPunts(DeviceId deviceId, IpAddress ipAddress) {
- TrafficSelector.Builder sbuilder = buildIpSelectorFromIpAddress(ipAddress);
- Optional<DeviceId> optDeviceId = Optional.of(deviceId);
-
- try {
- if (!ipAddress.equals(config.getRouterIpv4(deviceId)) &&
- !ipAddress.equals(config.getRouterIpv6(deviceId))) {
- srManager.packetService.cancelPackets(sbuilder.build(),
- PacketPriority.CONTROL, srManager.appId, optDeviceId);
- }
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage() + " Aborting revokeSingleIpPunts");
- }
- }
-
- // Method for building an IPv4 selector
- private TrafficSelector.Builder buildIpv4Selector() {
- TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
- selectorBuilder.matchEthType(Ethernet.TYPE_IPV4);
- return selectorBuilder;
- }
-
- // Method for building an IPv6 selector
- private TrafficSelector.Builder buildIpv6Selector() {
- TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
- selectorBuilder.matchEthType(Ethernet.TYPE_IPV6);
- return selectorBuilder;
- }
-
- // Method for building an IPv4 or IPv6 selector from an IP address
- private TrafficSelector.Builder buildIpSelectorFromIpAddress(IpAddress addressToMatch) {
- return buildIpSelectorFromIpPrefix(addressToMatch.toIpPrefix());
- }
-
- // Method for building an IPv4 or IPv6 selector from an IP prefix
- private TrafficSelector.Builder buildIpSelectorFromIpPrefix(IpPrefix prefixToMatch) {
- TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
- // If the prefix is IPv4
- if (prefixToMatch.isIp4()) {
- selectorBuilder.matchEthType(Ethernet.TYPE_IPV4);
- selectorBuilder.matchIPDst(prefixToMatch.getIp4Prefix());
- return selectorBuilder;
- }
- // If the prefix is IPv6
- selectorBuilder.matchEthType(Ethernet.TYPE_IPV6);
- selectorBuilder.matchIPv6Dst(prefixToMatch.getIp6Prefix());
- return selectorBuilder;
- }
-
- /**
- * Creates forwarding objectives to punt ARP and NDP packets, to the controller.
- * Furthermore, these are applied only by the master instance. Deferred actions
- * are not cleared such that packets can be flooded in the cross connect use case
- *
- * @param deviceId the switch dpid for the router
- */
- void populateArpNdpPunts(DeviceId deviceId) {
- // We are not the master just skip.
- if (!srManager.mastershipService.isLocalMaster(deviceId)) {
- log.debug("Not installing ARP/NDP punts - not the master for dev:{} ",
- deviceId);
- return;
- }
-
- ForwardingObjective fwdObj;
- // We punt all ARP packets towards the controller.
- fwdObj = arpFwdObjective(null, true, ARP_NDP_PRIORITY)
- .add(new ObjectiveContext() {
- @Override
- public void onError(Objective objective, ObjectiveError error) {
- log.warn("Failed to install forwarding objective to punt ARP to {}: {}",
- deviceId, error);
- }
- });
- srManager.flowObjectiveService.forward(deviceId, fwdObj);
-
- if (isIpv6Configured(deviceId)) {
- // We punt all NDP packets towards the controller.
- ndpFwdObjective(null, true, ARP_NDP_PRIORITY).forEach(builder -> {
- ForwardingObjective obj = builder.add(new ObjectiveContext() {
- @Override
- public void onError(Objective objective, ObjectiveError error) {
- log.warn("Failed to install forwarding objective to punt NDP to {}: {}",
- deviceId, error);
- }
- });
- srManager.flowObjectiveService.forward(deviceId, obj);
- });
- }
-
- srManager.getPairLocalPort(deviceId).ifPresent(port -> {
- ForwardingObjective pairFwdObj;
- // Do not punt ARP packets from pair port
- pairFwdObj = arpFwdObjective(port, false, PacketPriority.CONTROL.priorityValue() + 1)
- .add(new ObjectiveContext() {
- @Override
- public void onError(Objective objective, ObjectiveError error) {
- log.warn("Failed to install forwarding objective to ignore ARP to {}: {}",
- deviceId, error);
- }
- });
- srManager.flowObjectiveService.forward(deviceId, pairFwdObj);
-
- if (isIpv6Configured(deviceId)) {
- // Do not punt NDP packets from pair port
- ndpFwdObjective(port, false, PacketPriority.CONTROL.priorityValue() + 1).forEach(builder -> {
- ForwardingObjective obj = builder.add(new ObjectiveContext() {
- @Override
- public void onError(Objective objective, ObjectiveError error) {
- log.warn("Failed to install forwarding objective to ignore ARP to {}: {}",
- deviceId, error);
- }
- });
- srManager.flowObjectiveService.forward(deviceId, obj);
- });
-
- // Do not forward DAD packets from pair port
- pairFwdObj = dad6FwdObjective(port, PacketPriority.CONTROL.priorityValue() + 2)
- .add(new ObjectiveContext() {
- @Override
- public void onError(Objective objective, ObjectiveError error) {
- log.warn("Failed to install forwarding objective to drop DAD to {}: {}",
- deviceId, error);
- }
- });
- srManager.flowObjectiveService.forward(deviceId, pairFwdObj);
- }
- });
- }
-
- private ForwardingObjective.Builder fwdObjBuilder(TrafficSelector selector,
- TrafficTreatment treatment, int priority) {
- return DefaultForwardingObjective.builder()
- .withPriority(priority)
- .withSelector(selector)
- .fromApp(srManager.appId)
- .withFlag(ForwardingObjective.Flag.VERSATILE)
- .withTreatment(treatment)
- .makePermanent();
- }
-
- private ForwardingObjective.Builder arpFwdObjective(PortNumber port, boolean punt, int priority) {
- TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
- sBuilder.matchEthType(TYPE_ARP);
- if (port != null) {
- sBuilder.matchInPort(port);
- }
-
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
- if (punt) {
- tBuilder.punt();
- }
- return fwdObjBuilder(sBuilder.build(), tBuilder.build(), priority);
- }
-
- private Set<ForwardingObjective.Builder> ndpFwdObjective(PortNumber port, boolean punt, int priority) {
- Set<ForwardingObjective.Builder> result = Sets.newHashSet();
-
- Lists.newArrayList(NEIGHBOR_SOLICITATION, NEIGHBOR_ADVERTISEMENT, ROUTER_SOLICITATION, ROUTER_ADVERTISEMENT)
- .forEach(type -> {
- TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
- sBuilder.matchEthType(TYPE_IPV6)
- .matchIPProtocol(PROTOCOL_ICMP6)
- .matchIcmpv6Type(type);
- if (port != null) {
- sBuilder.matchInPort(port);
- }
-
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
- if (punt) {
- tBuilder.punt();
- }
-
- result.add(fwdObjBuilder(sBuilder.build(), tBuilder.build(), priority));
- });
-
- return result;
- }
-
- private ForwardingObjective.Builder dad6FwdObjective(PortNumber port, int priority) {
- TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
- sBuilder.matchEthType(TYPE_IPV6)
- .matchIPv6Src(Ip6Address.ZERO.toIpPrefix());
- // TODO CORD-1672 Fix this when OFDPA can distinguish ::/0 and ::/128 correctly
- // .matchIPProtocol(PROTOCOL_ICMP6)
- // .matchIcmpv6Type(NEIGHBOR_SOLICITATION);
- if (port != null) {
- sBuilder.matchInPort(port);
- }
-
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
- tBuilder.wipeDeferred();
- return fwdObjBuilder(sBuilder.build(), tBuilder.build(), priority);
- }
-
- /**
- * Block given prefix in routing table.
- *
- * @param address the address to block
- * @param deviceId switch ID to set the rules
- */
- void populateDefaultRouteBlackhole(DeviceId deviceId, IpPrefix address) {
- updateDefaultRouteBlackhole(deviceId, address, true);
- }
-
- /**
- * Unblock given prefix in routing table.
- *
- * @param address the address to block
- * @param deviceId switch ID to set the rules
- */
- void removeDefaultRouteBlackhole(DeviceId deviceId, IpPrefix address) {
- updateDefaultRouteBlackhole(deviceId, address, false);
- }
-
- private void updateDefaultRouteBlackhole(DeviceId deviceId, IpPrefix address, boolean install) {
- try {
- if (srManager.deviceConfiguration.isEdgeDevice(deviceId)) {
-
- TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
- if (address.isIp4()) {
- sbuilder.matchIPDst(address);
- sbuilder.matchEthType(EthType.EtherType.IPV4.ethType().toShort());
- } else {
- sbuilder.matchIPv6Dst(address);
- sbuilder.matchEthType(EthType.EtherType.IPV6.ethType().toShort());
- }
-
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
- tBuilder.wipeDeferred();
-
- ForwardingObjective.Builder fob = DefaultForwardingObjective.builder();
- fob.withFlag(Flag.SPECIFIC)
- .withSelector(sbuilder.build())
- .withTreatment(tBuilder.build())
- .withPriority(getPriorityFromPrefix(address))
- .fromApp(srManager.appId)
- .makePermanent();
-
- log.debug("{} blackhole forwarding objectives for dev: {}",
- install ? "Installing" : "Removing", deviceId);
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> log.debug("Forward for {} {}", deviceId,
- install ? "installed" : "removed"),
- (objective, error) -> log.warn("Failed to {} forward for {}: {}",
- install ? "install" : "remove", deviceId, error));
- if (install) {
- srManager.flowObjectiveService.forward(deviceId, fob.add(context));
- } else {
- srManager.flowObjectiveService.forward(deviceId, fob.remove(context));
- }
- }
- } catch (DeviceConfigNotFoundException e) {
- log.info("Not populating blackhole for un-configured device {}", deviceId);
- }
-
- }
-
- /**
- * Populates a forwarding objective to send packets that miss other high
- * priority Bridging Table entries to a group that contains all ports of
- * its subnet.
- *
- * @param deviceId switch ID to set the rules
- */
- void populateSubnetBroadcastRule(DeviceId deviceId) {
- srManager.getVlanPortMap(deviceId).asMap().forEach((vlanId, ports) -> {
- updateSubnetBroadcastRule(deviceId, vlanId, true);
- });
- }
-
- /**
- * Creates or removes a forwarding objective to broadcast packets to its subnet.
- * @param deviceId switch ID to set the rule
- * @param vlanId vlan ID to specify the subnet
- * @param install true to install the rule, false to revoke the rule
- */
- void updateSubnetBroadcastRule(DeviceId deviceId, VlanId vlanId, boolean install) {
- int nextId = srManager.getVlanNextObjectiveId(deviceId, vlanId);
-
- if (nextId < 0) {
- log.error("Cannot install vlan {} broadcast rule in dev:{} due"
- + " to vlanId:{} or nextId:{}", vlanId, deviceId, vlanId, nextId);
- return;
- }
-
- // Driver should treat objective with MacAddress.NONE as the
- // subnet broadcast rule
- TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
- sbuilder.matchVlanId(vlanId);
- sbuilder.matchEthDst(MacAddress.NONE);
-
- ForwardingObjective.Builder fob = DefaultForwardingObjective.builder();
- fob.withFlag(Flag.SPECIFIC)
- .withSelector(sbuilder.build())
- .nextStep(nextId)
- .withPriority(SegmentRoutingService.FLOOD_PRIORITY)
- .fromApp(srManager.appId)
- .makePermanent();
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> log.debug("Vlan broadcast rule for {} populated", vlanId),
- (objective, error) ->
- log.warn("Failed to populate vlan broadcast rule for {}: {}", vlanId, error));
-
- if (install) {
- srManager.flowObjectiveService.forward(deviceId, fob.add(context));
- } else {
- srManager.flowObjectiveService.forward(deviceId, fob.remove(context));
- }
- }
-
- private int getPriorityFromPrefix(IpPrefix prefix) {
- return (prefix.isIp4()) ?
- 2000 * prefix.prefixLength() + SegmentRoutingService.MIN_IP_PRIORITY :
- 500 * prefix.prefixLength() + SegmentRoutingService.MIN_IP_PRIORITY;
- }
-
- /**
- * Update Forwarding objective for each host and IP address connected to given port.
- * And create corresponding Simple Next objective if it does not exist.
- * Applied only when populating Forwarding objective
- * @param deviceId switch ID to set the rule
- * @param portNumber port number
- * @param prefix IP prefix of the route
- * @param hostMac MAC address of the next hop
- * @param vlanId Vlan ID of the port
- * @param popVlan true to pop vlan tag in TrafficTreatment
- * @param install true to populate the forwarding objective, false to revoke
- */
- void updateFwdObj(DeviceId deviceId, PortNumber portNumber, IpPrefix prefix, MacAddress hostMac,
- VlanId vlanId, boolean popVlan, boolean install) {
- ForwardingObjective.Builder fob;
- TrafficSelector.Builder sbuilder = buildIpSelectorFromIpPrefix(prefix);
- MacAddress deviceMac;
- try {
- deviceMac = config.getDeviceMac(deviceId);
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage() + " Aborting updateFwdObj.");
- return;
- }
-
- TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
- tbuilder.deferred()
- .setEthDst(hostMac)
- .setEthSrc(deviceMac)
- .setOutput(portNumber);
-
- TrafficSelector.Builder mbuilder = DefaultTrafficSelector.builder();
-
- if (!popVlan) {
- tbuilder.setVlanId(vlanId);
- } else {
- mbuilder.matchVlanId(vlanId);
- }
-
- // if the objective is to revoke an existing rule, and for some reason
- // the next-objective does not exist, then a new one should not be created
- int portNextObjId = srManager.getPortNextObjectiveId(deviceId, portNumber,
- tbuilder.build(), mbuilder.build(), install);
- if (portNextObjId == -1) {
- // Warning log will come from getPortNextObjective method
- return;
- }
-
- fob = DefaultForwardingObjective.builder().withSelector(sbuilder.build())
- .nextStep(portNextObjId).fromApp(srManager.appId).makePermanent()
- .withPriority(getPriorityFromPrefix(prefix)).withFlag(ForwardingObjective.Flag.SPECIFIC);
-
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> log.debug("IP rule for route {} {}", prefix, install ? "installed" : "revoked"),
- (objective, error) ->
- log.warn("Failed to {} IP rule for route {}: {}",
- install ? "install" : "revoke", prefix, error));
- srManager.flowObjectiveService.forward(deviceId, install ? fob.add(context) : fob.remove(context));
-
- if (!install) {
- if (!srManager.getVlanPortMap(deviceId).containsKey(vlanId) ||
- !srManager.getVlanPortMap(deviceId).get(vlanId).contains(portNumber)) {
- DefaultGroupHandler grpHandler = srManager.getGroupHandler(deviceId);
- if (grpHandler == null) {
- log.warn("updateFwdObj: groupHandler for device {} not found", deviceId);
- } else {
- // Remove L3UG for the given port and host
- grpHandler.removeGroupFromPort(portNumber, tbuilder.build(), mbuilder.build());
- }
- }
- }
- }
-
- /**
- * Checks if there is other enabled port within the given VLAN on the given device.
- *
- * @param deviceId device ID
- * @param vlanId VLAN ID
- * @return true if there is no more port enabled within the given VLAN on the given device
- */
- boolean noMoreEnabledPort(DeviceId deviceId, VlanId vlanId) {
- Set<ConnectPoint> enabledPorts = srManager.deviceService.getPorts(deviceId).stream()
- .filter(Port::isEnabled)
- .map(port -> new ConnectPoint(port.element().id(), port.number()))
- .collect(Collectors.toSet());
-
- return enabledPorts.stream().noneMatch(cp ->
- // Given vlanId is included in the vlan-tagged configuration
- srManager.interfaceService.getTaggedVlanId(cp).contains(vlanId) ||
- // Given vlanId is INTERNAL_VLAN or PSEUDOWIRE_VLAN and the interface is not configured
- (srManager.interfaceService.getTaggedVlanId(cp).isEmpty() && srManager.getInternalVlanId(cp) == null &&
- (vlanId.equals(srManager.getDefaultInternalVlan()) || vlanId.equals(srManager.getPwTransportVlan()))) ||
- // interface is configured and either vlan-untagged or vlan-native matches given vlanId
- (srManager.getInternalVlanId(cp) != null && srManager.getInternalVlanId(cp).equals(vlanId))
- );
- }
-
- /**
- * Returns a forwarding objective builder for egress forwarding rules.
- * <p>
- * The forwarding objective installs flow rules to egress pipeline to push
- * two vlan headers with given inner, outer vlan ids and outer tpid.
- *
- * @param portNumber port where the next hop attaches to
- * @param dummyVlanId vlan ID of the packet to match
- * @param innerVlan inner vlan ID of the next hop
- * @param outerVlan outer vlan ID of the next hop
- * @param outerTpid outer TPID of the next hop
- * @return forwarding objective builder
- */
- private ForwardingObjective.Builder egressFwdObjBuilder(PortNumber portNumber, VlanId dummyVlanId,
- VlanId innerVlan, VlanId outerVlan, EthType outerTpid) {
- TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
- sbuilder.matchVlanId(dummyVlanId);
- TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
- tbuilder.setOutput(portNumber).setVlanId(innerVlan);
-
- if (outerTpid.equals(EthType.EtherType.QINQ.ethType())) {
- tbuilder.pushVlan(outerTpid);
- } else {
- tbuilder.pushVlan();
- }
-
- tbuilder.setVlanId(outerVlan);
- return DefaultForwardingObjective.builder()
- .withSelector(sbuilder.build())
- .withTreatment(tbuilder.build())
- .fromApp(srManager.appId)
- .makePermanent()
- .withPriority(DEFAULT_PRIORITY)
- .withFlag(ForwardingObjective.Flag.EGRESS);
- }
-
- /**
- * Populates IP rules for a route that has double-tagged next hop.
- *
- * @param deviceId device ID of the device that next hop attaches to
- * @param prefix IP prefix of the route
- * @param hostMac MAC address of the next hop
- * @param innerVlan inner Vlan ID of the next hop
- * @param outerVlan outer Vlan ID of the next hop
- * @param outerTpid outer TPID of the next hop
- * @param outPort port where the next hop attaches to
- */
- void populateDoubleTaggedRoute(DeviceId deviceId, IpPrefix prefix, MacAddress hostMac,
- VlanId innerVlan, VlanId outerVlan, EthType outerTpid, PortNumber outPort) {
- ForwardingObjective.Builder fwdBuilder;
- log.debug("Populate direct routing entry for double-tagged host route {} at {}:{}",
- prefix, deviceId, outPort);
-
- try {
- fwdBuilder = routingFwdObjBuilder(deviceId, prefix, hostMac, outerVlan, outPort, innerVlan, outerTpid,
- true, false);
- } catch (DeviceConfigNotFoundException e) {
- log.error(e.getMessage() + " Aborting populateDoubleTaggedRoute");
- return;
- }
- if (fwdBuilder == null) {
- log.error("Aborting double-tagged host routing table entry due to error for dev:{} route:{}",
- deviceId, prefix);
- return;
- }
-
- int nextId = fwdBuilder.add().nextId();
- DefaultObjectiveContext context = new DefaultObjectiveContext(objective -> {
- log.debug("Direct routing rule for double-tagged host route {} populated. nextId={}", prefix, nextId);
- }, (objective, error) ->
- log.warn("Failed to populate direct routing rule for double-tagged host route {}: {}", prefix, error)
- );
- srManager.flowObjectiveService.forward(deviceId, fwdBuilder.add(context));
- rulePopulationCounter.incrementAndGet();
- }
-
- /**
- * Revokes IP rules for a route that has double-tagged next hop.
- *
- * @param deviceId device ID of the device that next hop attaches to
- * @param prefix IP prefix of the route
- * @param hostMac MAC address of the next hop
- * @param innerVlan inner Vlan ID of the next hop
- * @param outerVlan outer Vlan ID of the next hop
- * @param outerTpid outer TPID of the next hop
- * @param outPort port where the next hop attaches to
- */
- void revokeDoubleTaggedRoute(DeviceId deviceId, IpPrefix prefix, MacAddress hostMac,
- VlanId innerVlan, VlanId outerVlan, EthType outerTpid, PortNumber outPort) {
- ForwardingObjective.Builder fwdBuilder;
- log.debug("Revoking direct routing entry for double-tagged host route {} at {}:{}",
- prefix, deviceId, outPort);
-
- try {
- fwdBuilder = routingFwdObjBuilder(deviceId, prefix, hostMac, outerVlan, outPort, innerVlan, outerTpid,
- true, true);
- } catch (DeviceConfigNotFoundException e) {
- log.error(e.getMessage() + " Aborting revokeDoubleTaggedRoute");
- return;
- }
- if (fwdBuilder == null) {
- log.error("Aborting double-tagged host routing table entry due to error for dev:{} route:{}",
- deviceId, prefix);
- return;
- }
-
- int nextId = fwdBuilder.remove().nextId();
- DefaultObjectiveContext context = new DefaultObjectiveContext(objective -> {
- log.debug("Direct routing rule for double-tagged host route {} revoked. nextId={}", prefix, nextId);
-
- // Try to remove next objective as well
- ImmutablePair<TrafficTreatment, TrafficSelector> treatmentAndMeta;
- try {
- treatmentAndMeta = getTreatmentAndMeta(deviceId, hostMac, outerVlan, outPort, innerVlan, outerTpid);
- } catch (DeviceConfigNotFoundException e) {
- log.error(e.getMessage() + " Aborting revokeDoubleTaggedRoute");
- return;
- }
-
- if (treatmentAndMeta == null) {
- // Warning log will come from getTreatmentAndMeta method
- return;
- }
-
- DefaultGroupHandler groupHandler = srManager.getGroupHandler(deviceId);
- if (groupHandler == null) {
- log.warn("Failed to revoke direct routing rule for double-tagged host route {}: " +
- "group handler not found for {}", prefix, deviceId);
- return;
- }
- groupHandler.removeGroupFromPort(outPort, treatmentAndMeta.getLeft(), treatmentAndMeta.getRight());
-
- }, (objective, error) ->
- log.warn("Failed to revoke direct routing rule for double-tagged host route {}: {}", prefix, error)
- );
- srManager.flowObjectiveService.forward(deviceId, fwdBuilder.remove(context));
- }
-
- /**
- * Checks whether the specified port has IP configuration or not.
- *
- * @param cp ConnectPoint to check the existance of IP configuration
- * @return true if the port has IP configuration; false otherwise.
- */
- private boolean hasIPConfiguration(ConnectPoint cp) {
- Set<Interface> interfaces = srManager.interfaceService.getInterfacesByPort(cp);
- return interfaces.stream().anyMatch(intf -> intf.ipAddressesList().size() > 0);
- }
-
- /**
- * Updates filtering rules for unconfigured ports on all devices for which
- * this controller instance is master.
- *
- * @param pushVlan true if the filtering rule requires a push vlan action
- * @param oldVlanId the vlanId to be removed
- * @param newVlanId the vlanId to be added
- */
- void updateSpecialVlanFilteringRules(boolean pushVlan, VlanId oldVlanId,
- VlanId newVlanId) {
- for (Device dev : srManager.deviceService.getAvailableDevices()) {
- if (srManager.mastershipService.isLocalMaster(dev.id())) {
- for (Port p : srManager.deviceService.getPorts(dev.id())) {
- if (!hasIPConfiguration(new ConnectPoint(dev.id(), p.number()))
- && p.isEnabled()) {
- updateSinglePortFilters(dev.id(), p.number(), pushVlan,
- oldVlanId, false);
- updateSinglePortFilters(dev.id(), p.number(), pushVlan,
- newVlanId, true);
- }
- }
- }
- }
- }
-
- private boolean isIpv6Configured(DeviceId deviceId) {
- boolean isIpv6Configured;
- try {
- isIpv6Configured = (config.getRouterIpv6(deviceId) != null);
- } catch (DeviceConfigNotFoundException e) {
- isIpv6Configured = false;
- }
- return isIpv6Configured;
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/SRLinkWeigher.java b/app/src/main/java/org/onosproject/segmentrouting/SRLinkWeigher.java
deleted file mode 100644
index 01e07a7..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/SRLinkWeigher.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright 2018-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;
-
-import org.onlab.graph.DefaultEdgeWeigher;
-import org.onlab.graph.ScalarWeight;
-import org.onlab.graph.Weight;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Link;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.topology.LinkWeigher;
-import org.onosproject.net.topology.TopologyEdge;
-import org.onosproject.net.topology.TopologyVertex;
-import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
-
-import java.util.Set;
-
-/**
- * Link weigher for multicast related path computations.
- */
-public final class SRLinkWeigher
- extends DefaultEdgeWeigher<TopologyVertex, TopologyEdge>
- implements LinkWeigher {
-
- private final SegmentRoutingManager srManager;
- private final DeviceId srcPath;
- private final Set<Link> linksToEnforce;
-
- // Weight for the link to avoids. The high level idea is to build
- // a constrained shortest path computation. 100 should provide a good
- // threshold
- public static final ScalarWeight LINK_TO_AVOID_WEIGHT = new ScalarWeight(HOP_WEIGHT_VALUE + 100);
-
- /**
- * Creates a SRLinkWeigher object.
- *
- * @param srManager SegmentRoutingManager object
- * @param srcPath the source of the paths
- * @param linksToEnforce links to be enforced by the path computation
- */
- public SRLinkWeigher(SegmentRoutingManager srManager, DeviceId srcPath,
- Set<Link> linksToEnforce) {
- this.srManager = srManager;
- this.srcPath = srcPath;
- this.linksToEnforce = linksToEnforce;
- }
-
- @Override
- public Weight weight(TopologyEdge edge) {
- // 1) We need to avoid some particular paths like leaf-spine-leaf-*
- // 2) Properly handle the pair links
-
- // If the link is a pair link just return infinite value
- if (isPairLink(edge.link())) {
- return ScalarWeight.NON_VIABLE_WEIGHT;
- }
-
- // To avoid that the paths go through other leaves we need to influence
- // the path computation to return infinite value for all other links having
- // as a src a leaf different from the source we are passing to the weigher
- DeviceId srcDeviceLink = edge.link().src().deviceId();
- // Identify the link as leaf-spine link
- boolean isLeafSpine;
- try {
- isLeafSpine = srManager.deviceConfiguration().isEdgeDevice(srcDeviceLink);
- } catch (DeviceConfigNotFoundException e) {
- isLeafSpine = false;
- }
- // If it is not the source just return infinite value
- if (isLeafSpine && !srcDeviceLink.equals(srcPath)) {
- return ScalarWeight.NON_VIABLE_WEIGHT;
- }
-
- // If the links are not in the list of the links to be enforce
- if (!linksToEnforce.isEmpty() && !linksToEnforce.contains(edge.link())) {
- // 100 should be a good confidence threshold
- return LINK_TO_AVOID_WEIGHT;
- }
-
- // All other cases we return
- return new ScalarWeight(HOP_WEIGHT_VALUE);
- }
-
- // Utility method to verify is a link is a pair-link
- private boolean isPairLink(Link link) {
- // Take src id, src port, dst id and dst port
- final DeviceId srcId = link.src().deviceId();
- final PortNumber srcPort = link.src().port();
- final DeviceId dstId = link.dst().deviceId();
- final PortNumber dstPort = link.dst().port();
- // init as true
- boolean isPairLink = true;
- try {
- // If one of this condition is not true; it is not a pair link
- if (!(srManager.deviceConfiguration().isEdgeDevice(srcId) &&
- srManager.deviceConfiguration().isEdgeDevice(dstId) &&
- srManager.deviceConfiguration().getPairDeviceId(srcId).equals(dstId) &&
- srManager.deviceConfiguration().getPairLocalPort(srcId).equals(srcPort) &&
- srManager.deviceConfiguration().getPairLocalPort(dstId).equals(dstPort))) {
- isPairLink = false;
- }
- } catch (DeviceConfigNotFoundException e) {
- // Configuration not provided
- isPairLink = false;
- }
- return isPairLink;
- }
-
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
deleted file mode 100644
index 673cfc9..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ /dev/null
@@ -1,2398 +0,0 @@
-/*
- * Copyright 2015-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;
-
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Sets;
-import org.onlab.packet.Ethernet;
-import org.onlab.packet.ICMP6;
-import org.onlab.packet.IPv4;
-import org.onlab.packet.IPv6;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
-import org.onlab.util.KryoNamespace;
-import org.onlab.util.Tools;
-import org.onosproject.cfg.ComponentConfigService;
-import org.onosproject.cluster.ClusterEvent;
-import org.onosproject.cluster.ClusterEventListener;
-import org.onosproject.cluster.ClusterService;
-import org.onosproject.cluster.LeadershipService;
-import org.onosproject.cluster.NodeId;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.core.CoreService;
-import org.onosproject.event.Event;
-import org.onosproject.mastership.MastershipEvent;
-import org.onosproject.mastership.MastershipListener;
-import org.onosproject.mastership.MastershipService;
-import org.onosproject.mcast.api.McastEvent;
-import org.onosproject.mcast.api.McastListener;
-import org.onosproject.mcast.api.MulticastRouteService;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.Device;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Host;
-import org.onosproject.net.HostId;
-import org.onosproject.net.Link;
-import org.onosproject.net.Port;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.config.ConfigException;
-import org.onosproject.net.config.ConfigFactory;
-import org.onosproject.net.config.NetworkConfigEvent;
-import org.onosproject.net.config.NetworkConfigListener;
-import org.onosproject.net.config.NetworkConfigRegistry;
-import org.onosproject.net.config.basics.InterfaceConfig;
-import org.onosproject.net.config.basics.McastConfig;
-import org.onosproject.net.config.basics.SubjectFactories;
-import org.onosproject.net.device.DeviceAdminService;
-import org.onosproject.net.device.DeviceEvent;
-import org.onosproject.net.device.DeviceListener;
-import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.flow.TrafficSelector;
-import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.flowobjective.FlowObjectiveService;
-import org.onosproject.net.flowobjective.NextObjective;
-import org.onosproject.net.host.HostEvent;
-import org.onosproject.net.host.HostListener;
-import org.onosproject.net.host.HostProbingService;
-import org.onosproject.net.host.HostService;
-import org.onosproject.net.host.InterfaceIpAddress;
-import org.onosproject.net.intent.WorkPartitionService;
-import org.onosproject.net.intf.Interface;
-import org.onosproject.net.intf.InterfaceService;
-import org.onosproject.net.link.LinkEvent;
-import org.onosproject.net.link.LinkListener;
-import org.onosproject.net.link.LinkService;
-import org.onosproject.net.neighbour.NeighbourResolutionService;
-import org.onosproject.net.packet.InboundPacket;
-import org.onosproject.net.packet.PacketContext;
-import org.onosproject.net.packet.PacketProcessor;
-import org.onosproject.net.packet.PacketService;
-import org.onosproject.net.topology.TopologyEvent;
-import org.onosproject.net.topology.TopologyListener;
-import org.onosproject.net.topology.TopologyService;
-import org.onosproject.routeservice.ResolvedRoute;
-import org.onosproject.routeservice.RouteEvent;
-import org.onosproject.routeservice.RouteListener;
-import org.onosproject.routeservice.RouteService;
-import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
-import org.onosproject.segmentrouting.config.DeviceConfiguration;
-import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
-import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
-import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
-import org.onosproject.segmentrouting.grouphandler.DestinationSet;
-import org.onosproject.segmentrouting.grouphandler.NextNeighbors;
-import org.onosproject.segmentrouting.mcast.McastFilteringObjStoreKey;
-import org.onosproject.segmentrouting.mcast.McastHandler;
-import org.onosproject.segmentrouting.mcast.McastRole;
-import org.onosproject.segmentrouting.mcast.McastRoleStoreKey;
-import org.onosproject.segmentrouting.mcast.McastStoreKey;
-import org.onosproject.segmentrouting.phasedrecovery.api.PhasedRecoveryService;
-import org.onosproject.segmentrouting.pwaas.DefaultL2Tunnel;
-import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelDescription;
-import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelHandler;
-import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelPolicy;
-import org.onosproject.segmentrouting.pwaas.L2Tunnel;
-import org.onosproject.segmentrouting.pwaas.L2TunnelDescription;
-import org.onosproject.segmentrouting.pwaas.L2TunnelHandler;
-import org.onosproject.segmentrouting.pwaas.L2TunnelPolicy;
-import org.onosproject.segmentrouting.storekey.DestinationSetNextObjectiveStoreKey;
-import org.onosproject.segmentrouting.storekey.MacVlanNextObjectiveStoreKey;
-import org.onosproject.segmentrouting.storekey.PortNextObjectiveStoreKey;
-import org.onosproject.segmentrouting.storekey.VlanNextObjectiveStoreKey;
-import org.onosproject.segmentrouting.storekey.XConnectStoreKey;
-import org.onosproject.segmentrouting.xconnect.api.XconnectService;
-import org.onosproject.store.serializers.KryoNamespaces;
-import org.onosproject.store.service.EventuallyConsistentMap;
-import org.onosproject.store.service.EventuallyConsistentMapBuilder;
-import org.onosproject.store.service.StorageService;
-import org.onosproject.store.service.WallClockTimestamp;
-import org.osgi.service.component.ComponentContext;
-import org.osgi.service.component.annotations.Activate;
-import org.osgi.service.component.annotations.Component;
-import org.osgi.service.component.annotations.Deactivate;
-import org.osgi.service.component.annotations.Modified;
-import org.osgi.service.component.annotations.Reference;
-import org.osgi.service.component.annotations.ReferenceCardinality;
-import org.osgi.service.component.annotations.ReferencePolicy;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.time.Instant;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Dictionary;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.stream.Collectors;
-
-import static com.google.common.base.Preconditions.checkState;
-import static org.onlab.packet.Ethernet.TYPE_ARP;
-import static org.onlab.util.Tools.groupedThreads;
-import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_REGISTERED;
-import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_UNREGISTERED;
-import static org.onosproject.segmentrouting.OsgiPropertyConstants.ACTIVE_PROBING_DEFAULT;
-import static org.onosproject.segmentrouting.OsgiPropertyConstants.DEFAULT_INTERNAL_VLAN_DEFAULT;
-import static org.onosproject.segmentrouting.OsgiPropertyConstants.PROP_ACTIVE_PROBING;
-import static org.onosproject.segmentrouting.OsgiPropertyConstants.PROP_DEFAULT_INTERNAL_VLAN;
-import static org.onosproject.segmentrouting.OsgiPropertyConstants.PROP_PW_TRANSPORT_VLAN;
-import static org.onosproject.segmentrouting.OsgiPropertyConstants.PROP_RESPOND_TO_UNKNOWN_HOSTS;
-import static org.onosproject.segmentrouting.OsgiPropertyConstants.PROP_ROUTE_DOUBLE_TAGGED_HOSTS;
-import static org.onosproject.segmentrouting.OsgiPropertyConstants.PROP_ROUTE_SIMPLIFICATION;
-import static org.onosproject.segmentrouting.OsgiPropertyConstants.PROP_SINGLE_HOMED_DOWN;
-import static org.onosproject.segmentrouting.OsgiPropertyConstants.PROP_SYMMETRIC_PROBING;
-import static org.onosproject.segmentrouting.OsgiPropertyConstants.PW_TRANSPORT_VLAN_DEFAULT;
-import static org.onosproject.segmentrouting.OsgiPropertyConstants.RESPOND_TO_UNKNOWN_HOSTS_DEFAULT;
-import static org.onosproject.segmentrouting.OsgiPropertyConstants.ROUTE_DOUBLE_TAGGED_HOSTS_DEFAULT;
-import static org.onosproject.segmentrouting.OsgiPropertyConstants.ROUTE_SIMPLIFICATION_DEFAULT;
-import static org.onosproject.segmentrouting.OsgiPropertyConstants.SINGLE_HOMED_DOWN_DEFAULT;
-import static org.onosproject.segmentrouting.OsgiPropertyConstants.SYMMETRIC_PROBING_DEFAULT;
-
-/**
- * Segment routing manager.
- */
-@Component(
- immediate = true,
- service = SegmentRoutingService.class,
- property = {
- PROP_ACTIVE_PROBING + ":Boolean=" + ACTIVE_PROBING_DEFAULT,
- PROP_SINGLE_HOMED_DOWN + ":Boolean=" + SINGLE_HOMED_DOWN_DEFAULT,
- PROP_RESPOND_TO_UNKNOWN_HOSTS + ":Boolean=" + RESPOND_TO_UNKNOWN_HOSTS_DEFAULT,
- PROP_ROUTE_DOUBLE_TAGGED_HOSTS + ":Boolean=" + ROUTE_DOUBLE_TAGGED_HOSTS_DEFAULT,
- PROP_DEFAULT_INTERNAL_VLAN + ":Integer=" + DEFAULT_INTERNAL_VLAN_DEFAULT,
- PROP_PW_TRANSPORT_VLAN + ":Integer=" + PW_TRANSPORT_VLAN_DEFAULT,
- PROP_SYMMETRIC_PROBING + ":Boolean=" + SYMMETRIC_PROBING_DEFAULT,
- PROP_ROUTE_SIMPLIFICATION + ":Boolean=" + ROUTE_SIMPLIFICATION_DEFAULT
- }
-)
-public class SegmentRoutingManager implements SegmentRoutingService {
-
- private static Logger log = LoggerFactory.getLogger(SegmentRoutingManager.class);
- private static final String NOT_MASTER = "Current instance is not the master of {}. Ignore.";
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- private ComponentConfigService compCfgService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- public NeighbourResolutionService neighbourResolutionService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- public CoreService coreService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- PacketService packetService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- HostService hostService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- HostProbingService probingService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- public DeviceService deviceService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- DeviceAdminService deviceAdminService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- public FlowObjectiveService flowObjectiveService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- public LinkService linkService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- public MastershipService mastershipService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- public StorageService storageService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- public MulticastRouteService multicastRouteService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- public TopologyService topologyService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- public RouteService routeService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- public NetworkConfigRegistry cfgService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- public InterfaceService interfaceService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- public ClusterService clusterService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- public WorkPartitionService workPartitionService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- public LeadershipService leadershipService;
-
- @Reference(cardinality = ReferenceCardinality.OPTIONAL,
- policy = ReferencePolicy.DYNAMIC)
- public volatile XconnectService xconnectService;
-
- @Reference(cardinality = ReferenceCardinality.OPTIONAL,
- policy = ReferencePolicy.DYNAMIC)
- volatile PhasedRecoveryService phasedRecoveryService;
-
- /** Enable active probing to discover dual-homed hosts. */
- boolean activeProbing = ACTIVE_PROBING_DEFAULT;
-
- /** Enable only send probe on the same port number of the pair device. */
- boolean symmetricProbing = SYMMETRIC_PROBING_DEFAULT;
-
- /** Enable administratively taking down single-homed hosts. */
- boolean singleHomedDown = SINGLE_HOMED_DOWN_DEFAULT;
-
- /** Enable this to respond to ARP/NDP requests from unknown hosts. */
- boolean respondToUnknownHosts = RESPOND_TO_UNKNOWN_HOSTS_DEFAULT;
-
- /** Program flows and groups to pop and route double tagged hosts. */
- boolean routeDoubleTaggedHosts = ROUTE_DOUBLE_TAGGED_HOSTS_DEFAULT;
-
- /** internal vlan assigned by default to unconfigured ports. */
- private int defaultInternalVlan = DEFAULT_INTERNAL_VLAN_DEFAULT;
-
- /** vlan used for transport of pseudowires between switches. */
- private int pwTransportVlan = PW_TRANSPORT_VLAN_DEFAULT;
-
- /** Enabling route simplification. */
- boolean routeSimplification = ROUTE_SIMPLIFICATION_DEFAULT;
-
- ArpHandler arpHandler = null;
- IcmpHandler icmpHandler = null;
- IpHandler ipHandler = null;
- RoutingRulePopulator routingRulePopulator = null;
- ApplicationId appId;
- DeviceConfiguration deviceConfiguration = null;
-
- DefaultRoutingHandler defaultRoutingHandler = null;
- private TunnelHandler tunnelHandler = null;
- private PolicyHandler policyHandler = null;
- private InternalPacketProcessor processor = null;
- private InternalLinkListener linkListener = null;
- private InternalDeviceListener deviceListener = null;
- private AppConfigHandler appCfgHandler = null;
- McastHandler mcastHandler = null;
- HostHandler hostHandler = null;
- private RouteHandler routeHandler = null;
- LinkHandler linkHandler = null;
- private SegmentRoutingNeighbourDispatcher neighbourHandler = null;
- private DefaultL2TunnelHandler l2TunnelHandler = null;
- private TopologyHandler topologyHandler = null;
- private final InternalHostListener hostListener = new InternalHostListener();
- private final InternalConfigListener cfgListener = new InternalConfigListener(this);
- private final InternalMcastListener mcastListener = new InternalMcastListener();
- private final InternalRouteEventListener routeListener = new InternalRouteEventListener();
- private final InternalTopologyListener topologyListener = new InternalTopologyListener();
- private final InternalMastershipListener mastershipListener = new InternalMastershipListener();
- final InternalClusterListener clusterListener = new InternalClusterListener();
- //Completable future for network configuration process to buffer config events handling during activation
- private CompletableFuture<Boolean> networkConfigCompletion = null;
- private final Object networkConfigCompletionLock = new Object();
- private List<Event> queuedEvents = new CopyOnWriteArrayList<>();
-
- // Handles device, link, topology and network config events
- private ScheduledExecutorService mainEventExecutor;
-
- // Handles host, route and mcast events respectively
- private ScheduledExecutorService hostEventExecutor;
- private ScheduledExecutorService routeEventExecutor;
- private ScheduledExecutorService mcastEventExecutor;
- private ExecutorService packetExecutor;
- ExecutorService neighborExecutor;
-
- Map<DeviceId, DefaultGroupHandler> groupHandlerMap = new ConcurrentHashMap<>();
- /**
- * Per device next objective ID store with (device id + destination set) as key.
- * Used to keep track on MPLS group information.
- */
- private EventuallyConsistentMap<DestinationSetNextObjectiveStoreKey, NextNeighbors>
- dsNextObjStore = null;
- /**
- * Per device next objective ID store with (device id + vlanid) as key.
- * Used to keep track on L2 flood group information.
- */
- private EventuallyConsistentMap<VlanNextObjectiveStoreKey, Integer>
- vlanNextObjStore = null;
- /**
- * Per device next objective ID store with (device id + port + treatment + meta) as key.
- * Used to keep track on L2 interface group and L3 unicast group information for direct hosts.
- */
- private EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
- portNextObjStore = null;
-
- /**
- * Per device next objective ID store with (device id + MAC address + vlan) as key.
- * Used to keep track of L3 unicast group for indirect hosts.
- */
- private EventuallyConsistentMap<MacVlanNextObjectiveStoreKey, Integer>
- macVlanNextObjStore = null;
-
- private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
- private EventuallyConsistentMap<String, Policy> policyStore = null;
-
- private AtomicBoolean programmingScheduled = new AtomicBoolean();
-
- private final ConfigFactory<DeviceId, SegmentRoutingDeviceConfig> deviceConfigFactory =
- new ConfigFactory<DeviceId, SegmentRoutingDeviceConfig>(
- SubjectFactories.DEVICE_SUBJECT_FACTORY,
- SegmentRoutingDeviceConfig.class, "segmentrouting") {
- @Override
- public SegmentRoutingDeviceConfig createConfig() {
- return new SegmentRoutingDeviceConfig();
- }
- };
-
- private final ConfigFactory<ApplicationId, SegmentRoutingAppConfig> appConfigFactory =
- new ConfigFactory<ApplicationId, SegmentRoutingAppConfig>(
- SubjectFactories.APP_SUBJECT_FACTORY,
- SegmentRoutingAppConfig.class, "segmentrouting") {
- @Override
- public SegmentRoutingAppConfig createConfig() {
- return new SegmentRoutingAppConfig();
- }
- };
-
- private ConfigFactory<ApplicationId, McastConfig> mcastConfigFactory =
- new ConfigFactory<ApplicationId, McastConfig>(
- SubjectFactories.APP_SUBJECT_FACTORY,
- McastConfig.class, "multicast") {
- @Override
- public McastConfig createConfig() {
- return new McastConfig();
- }
- };
-
- /**
- * Segment Routing App ID.
- */
- public static final String APP_NAME = "org.onosproject.segmentrouting";
-
- /**
- * Minumum and maximum value of dummy VLAN ID to be allocated.
- */
- public static final int MIN_DUMMY_VLAN_ID = 2;
- public static final int MAX_DUMMY_VLAN_ID = 4093;
-
- private static final int DEFAULT_POOL_SIZE = 32;
-
- Instant lastEdgePortEvent = Instant.EPOCH;
-
- @Activate
- protected void activate(ComponentContext context) {
- appId = coreService.registerApplication(APP_NAME);
-
- mainEventExecutor = Executors.newSingleThreadScheduledExecutor(
- groupedThreads("onos/sr", "event-main-%d", log));
- hostEventExecutor = Executors.newSingleThreadScheduledExecutor(
- groupedThreads("onos/sr", "event-host-%d", log));
- routeEventExecutor = Executors.newSingleThreadScheduledExecutor(
- groupedThreads("onos/sr", "event-route-%d", log));
- mcastEventExecutor = Executors.newSingleThreadScheduledExecutor(
- groupedThreads("onos/sr", "event-mcast-%d", log));
- packetExecutor = Executors.newSingleThreadExecutor(groupedThreads("onos/sr", "packet-%d", log));
- neighborExecutor = Executors.newFixedThreadPool(DEFAULT_POOL_SIZE,
- groupedThreads("onos/sr", "neighbor-%d", log));
-
- log.debug("Creating EC map nsnextobjectivestore");
- EventuallyConsistentMapBuilder<DestinationSetNextObjectiveStoreKey, NextNeighbors>
- nsNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
- dsNextObjStore = nsNextObjMapBuilder
- .withName("nsnextobjectivestore")
- .withSerializer(createSerializer())
- .withTimestampProvider((k, v) -> new WallClockTimestamp())
- .build();
- log.trace("Current size {}", dsNextObjStore.size());
-
- log.debug("Creating EC map vlannextobjectivestore");
- EventuallyConsistentMapBuilder<VlanNextObjectiveStoreKey, Integer>
- vlanNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
- vlanNextObjStore = vlanNextObjMapBuilder
- .withName("vlannextobjectivestore")
- .withSerializer(createSerializer())
- .withTimestampProvider((k, v) -> new WallClockTimestamp())
- .build();
-
- log.debug("Creating EC map macvlannextobjectivestore");
- EventuallyConsistentMapBuilder<MacVlanNextObjectiveStoreKey, Integer>
- macVlanNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
- macVlanNextObjStore = macVlanNextObjMapBuilder
- .withName("macvlannextobjectivestore")
- .withSerializer(createSerializer())
- .withTimestampProvider((k, v) -> new WallClockTimestamp())
- .build();
-
- log.debug("Creating EC map subnetnextobjectivestore");
- EventuallyConsistentMapBuilder<PortNextObjectiveStoreKey, Integer>
- portNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
- portNextObjStore = portNextObjMapBuilder
- .withName("portnextobjectivestore")
- .withSerializer(createSerializer())
- .withTimestampProvider((k, v) -> new WallClockTimestamp())
- .build();
-
- EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder =
- storageService.eventuallyConsistentMapBuilder();
- tunnelStore = tunnelMapBuilder
- .withName("tunnelstore")
- .withSerializer(createSerializer())
- .withTimestampProvider((k, v) -> new WallClockTimestamp())
- .build();
-
- EventuallyConsistentMapBuilder<String, Policy> policyMapBuilder =
- storageService.eventuallyConsistentMapBuilder();
- policyStore = policyMapBuilder
- .withName("policystore")
- .withSerializer(createSerializer())
- .withTimestampProvider((k, v) -> new WallClockTimestamp())
- .build();
-
- processor = new InternalPacketProcessor();
- linkListener = new InternalLinkListener();
- deviceListener = new InternalDeviceListener();
- appCfgHandler = new AppConfigHandler(this);
- mcastHandler = new McastHandler(this);
- hostHandler = new HostHandler(this);
- linkHandler = new LinkHandler(this);
- routeHandler = new RouteHandler(this);
- neighbourHandler = new SegmentRoutingNeighbourDispatcher(this);
- l2TunnelHandler = new DefaultL2TunnelHandler(this);
- topologyHandler = new TopologyHandler(this);
-
- compCfgService.preSetProperty("org.onosproject.provider.host.impl.HostLocationProvider",
- "requestInterceptsEnabled", "false", false);
- compCfgService.preSetProperty("org.onosproject.net.neighbour.impl.NeighbourResolutionManager",
- "requestInterceptsEnabled", "false", false);
- compCfgService.preSetProperty("org.onosproject.dhcprelay.DhcpRelayManager",
- "arpEnabled", "false", false);
- compCfgService.preSetProperty("org.onosproject.net.host.impl.HostManager",
- "greedyLearningIpv6", "true", false);
- compCfgService.preSetProperty("org.onosproject.routing.cpr.ControlPlaneRedirectManager",
- "forceUnprovision", "true", false);
- compCfgService.preSetProperty("org.onosproject.routeservice.store.RouteStoreImpl",
- "distributed", "true", false);
- compCfgService.preSetProperty("org.onosproject.provider.host.impl.HostLocationProvider",
- "multihomingEnabled", "true", false);
- compCfgService.preSetProperty("org.onosproject.provider.lldp.impl.LldpLinkProvider",
- "staleLinkAge", "15000", false);
- compCfgService.preSetProperty("org.onosproject.net.host.impl.HostManager",
- "allowDuplicateIps", "false", false);
- // For P4 switches
- compCfgService.preSetProperty("org.onosproject.net.flow.impl.FlowRuleManager",
- "fallbackFlowPollFrequency", "4", false);
- compCfgService.preSetProperty("org.onosproject.net.group.impl.GroupManager",
- "fallbackGroupPollFrequency", "3", false);
- compCfgService.registerProperties(getClass());
- modified(context);
-
- cfgService.addListener(cfgListener);
- cfgService.registerConfigFactory(deviceConfigFactory);
- cfgService.registerConfigFactory(appConfigFactory);
- cfgService.registerConfigFactory(mcastConfigFactory);
- log.info("Configuring network before adding listeners");
-
- cfgListener.configureNetwork();
-
- hostService.addListener(hostListener);
- packetService.addProcessor(processor, PacketProcessor.director(2));
- linkService.addListener(linkListener);
- deviceService.addListener(deviceListener);
- multicastRouteService.addListener(mcastListener);
- routeService.addListener(routeListener);
- topologyService.addListener(topologyListener);
- mastershipService.addListener(mastershipListener);
- clusterService.addListener(clusterListener);
-
- linkHandler.init();
- l2TunnelHandler.init();
-
- synchronized (networkConfigCompletionLock) {
- networkConfigCompletion.whenComplete((value, ex) -> {
- //setting to null for easier fall through
- networkConfigCompletion = null;
- //process all queued events
- queuedEvents.forEach(event -> {
- mainEventExecutor.execute(new InternalEventHandler(event));
- });
- });
- }
-
- log.info("Started");
- }
-
- KryoNamespace.Builder createSerializer() {
- return new KryoNamespace.Builder()
- .register(KryoNamespaces.API)
- .register(DestinationSetNextObjectiveStoreKey.class,
- VlanNextObjectiveStoreKey.class,
- DestinationSet.class,
- DestinationSet.DestinationSetType.class,
- NextNeighbors.class,
- Tunnel.class,
- DefaultTunnel.class,
- Policy.class,
- TunnelPolicy.class,
- Policy.Type.class,
- PortNextObjectiveStoreKey.class,
- XConnectStoreKey.class,
- L2Tunnel.class,
- L2TunnelPolicy.class,
- DefaultL2Tunnel.class,
- DefaultL2TunnelPolicy.class,
- MacVlanNextObjectiveStoreKey.class
- );
- }
-
- @Deactivate
- protected void deactivate() {
- mainEventExecutor.shutdown();
- hostEventExecutor.shutdown();
- routeEventExecutor.shutdown();
- mcastEventExecutor.shutdown();
- packetExecutor.shutdown();
- neighborExecutor.shutdown();
-
- mainEventExecutor = null;
- hostEventExecutor = null;
- routeEventExecutor = null;
- mcastEventExecutor = null;
- packetExecutor = null;
- neighborExecutor = null;
-
- cfgService.removeListener(cfgListener);
- cfgService.unregisterConfigFactory(deviceConfigFactory);
- cfgService.unregisterConfigFactory(appConfigFactory);
- cfgService.unregisterConfigFactory(mcastConfigFactory);
- compCfgService.unregisterProperties(getClass(), false);
-
- hostService.removeListener(hostListener);
- packetService.removeProcessor(processor);
- linkService.removeListener(linkListener);
- deviceService.removeListener(deviceListener);
- multicastRouteService.removeListener(mcastListener);
- routeService.removeListener(routeListener);
- topologyService.removeListener(topologyListener);
- mastershipService.removeListener(mastershipListener);
- clusterService.removeListener(clusterListener);
-
- neighbourResolutionService.unregisterNeighbourHandlers(appId);
-
- processor = null;
- linkListener = null;
- deviceListener = null;
- groupHandlerMap.forEach((k, v) -> v.shutdown());
- groupHandlerMap.clear();
- defaultRoutingHandler.shutdown();
-
- dsNextObjStore.destroy();
- vlanNextObjStore.destroy();
- macVlanNextObjStore.destroy();
- portNextObjStore.destroy();
- tunnelStore.destroy();
- policyStore.destroy();
-
- mcastHandler.terminate();
- hostHandler.terminate();
- log.info("Stopped");
- }
-
- @Modified
- private void modified(ComponentContext context) {
- Dictionary<?, ?> properties = context.getProperties();
- if (properties == null) {
- return;
- }
-
- String strActiveProbing = Tools.get(properties, PROP_ACTIVE_PROBING);
- boolean expectActiveProbing = Boolean.parseBoolean(strActiveProbing);
- if (expectActiveProbing != activeProbing) {
- activeProbing = expectActiveProbing;
- log.info("{} active probing", activeProbing ? "Enabling" : "Disabling");
- }
-
-
- String strSymmetricProbing = Tools.get(properties, PROP_SYMMETRIC_PROBING);
- boolean expectSymmetricProbing = Boolean.parseBoolean(strSymmetricProbing);
- if (expectSymmetricProbing != symmetricProbing) {
- symmetricProbing = expectSymmetricProbing;
- log.info("{} symmetric probing", symmetricProbing ? "Enabling" : "Disabling");
- }
-
- String strSingleHomedDown = Tools.get(properties, PROP_SINGLE_HOMED_DOWN);
- boolean expectSingleHomedDown = Boolean.parseBoolean(strSingleHomedDown);
- if (expectSingleHomedDown != singleHomedDown) {
- singleHomedDown = expectSingleHomedDown;
- log.info("{} downing of single homed hosts for lost uplinks",
- singleHomedDown ? "Enabling" : "Disabling");
- if (singleHomedDown && linkHandler != null) {
- hostService.getHosts().forEach(host -> host.locations()
- .forEach(loc -> {
- if (interfaceService.isConfigured(loc)) {
- linkHandler.checkUplinksForHost(loc);
- }
- }));
- } else {
- log.warn("Disabling singleHomedDown does not re-enable already "
- + "downed ports for single-homed hosts");
- }
- }
-
- String strRespondToUnknownHosts = Tools.get(properties, PROP_RESPOND_TO_UNKNOWN_HOSTS);
- boolean expectRespondToUnknownHosts = Boolean.parseBoolean(strRespondToUnknownHosts);
- if (expectRespondToUnknownHosts != respondToUnknownHosts) {
- respondToUnknownHosts = expectRespondToUnknownHosts;
- log.info("{} responding to ARPs/NDPs from unknown hosts", respondToUnknownHosts ? "Enabling" : "Disabling");
- }
-
- String strRouteDoubleTaggedHosts = Tools.get(properties, PROP_ROUTE_DOUBLE_TAGGED_HOSTS);
- boolean expectRouteDoubleTaggedHosts = Boolean.parseBoolean(strRouteDoubleTaggedHosts);
- if (expectRouteDoubleTaggedHosts != routeDoubleTaggedHosts) {
- routeDoubleTaggedHosts = expectRouteDoubleTaggedHosts;
- log.info("{} routing for double tagged hosts", routeDoubleTaggedHosts ? "Enabling" : "Disabling");
-
- if (routeDoubleTaggedHosts) {
- hostHandler.populateAllDoubleTaggedHost();
- } else {
- hostHandler.revokeAllDoubleTaggedHost();
- }
- }
-
- String strDefaultInternalVlan = Tools.get(properties, PROP_DEFAULT_INTERNAL_VLAN);
- int defIntVlan = Integer.parseInt(strDefaultInternalVlan);
- if (defIntVlan != defaultInternalVlan) {
- if (canUseVlanId(defIntVlan)) {
- log.warn("Default internal vlan value changed from {} to {}.. "
- + "re-programming filtering rules, but NOT any groups already "
- + "created with the former value", defaultInternalVlan, defIntVlan);
- VlanId oldDefIntVlan = VlanId.vlanId((short) defaultInternalVlan);
- defaultInternalVlan = defIntVlan;
- routingRulePopulator
- .updateSpecialVlanFilteringRules(true, oldDefIntVlan,
- VlanId.vlanId((short) defIntVlan));
- } else {
- log.warn("Cannot change default internal vlan to unusable "
- + "value {}", defIntVlan);
- }
- }
-
- String strPwTxpVlan = Tools.get(properties, PROP_PW_TRANSPORT_VLAN);
- int pwTxpVlan = Integer.parseInt(strPwTxpVlan);
- if (pwTxpVlan != pwTransportVlan) {
- if (canUseVlanId(pwTxpVlan)) {
- log.warn("Pseudowire transport vlan value changed from {} to {}.. "
- + "re-programming filtering rules, but NOT any groups already "
- + "created with the former value", pwTransportVlan,
- pwTxpVlan);
- VlanId oldPwTxpVlan = VlanId.vlanId((short) pwTransportVlan);
- pwTransportVlan = pwTxpVlan;
- routingRulePopulator
- .updateSpecialVlanFilteringRules(false, oldPwTxpVlan,
- VlanId.vlanId((short) pwTxpVlan));
- } else {
- log.warn("Cannot change pseudowire transport vlan to unusable "
- + "value {}", pwTxpVlan);
- }
- }
-
- String strRouteSimplification = Tools.get(properties, PROP_ROUTE_SIMPLIFICATION);
- boolean expectRouteSimplification = Boolean.parseBoolean(strRouteSimplification);
- if (expectRouteSimplification != routeSimplification) {
- routeSimplification = expectRouteSimplification;
- log.info("{} route simplification", routeSimplification ? "Enabling" : "Disabling");
- }
-
- }
-
- /**
- * Returns true if given vlan id is not being used in the system currently,
- * either as one of the default system wide vlans or as one of the
- * configured interface vlans.
- *
- * @param vlanId given vlan id
- * @return true if vlan is not currently in use
- */
- public boolean canUseVlanId(int vlanId) {
- if (vlanId >= 4095 || vlanId <= 1) {
- log.error("Vlan id {} value is not in valid range 2 <--> 4094",
- vlanId);
- return false;
- }
-
- VlanId vid = VlanId.vlanId((short) vlanId);
- if (getDefaultInternalVlan().equals(vid) || getPwTransportVlan().equals(vid)) {
- log.warn("Vlan id {} value is already in use system-wide. "
- + "DefaultInternalVlan:{} PwTransportVlan:{} ", vlanId,
- getDefaultInternalVlan(), getPwTransportVlan());
- return false;
- }
-
- if (interfaceService.inUse(vid)) {
- log.warn("Vlan id {} value is already in use on a configured "
- + "interface in the system", vlanId);
- return false;
- }
- return true;
- }
-
- /**
- * Returns the VlanId assigned internally by default to unconfigured ports.
- *
- * @return the default internal vlan id
- */
- public VlanId getDefaultInternalVlan() {
- return VlanId.vlanId((short) defaultInternalVlan);
- }
-
- /**
- * Returns the Vlan id used to transport pseudowire traffic across the
- * network.
- *
- * @return the pseudowire transport vlan id
- */
- public VlanId getPwTransportVlan() {
- return VlanId.vlanId((short) pwTransportVlan);
- }
-
- @Override
- public List<Tunnel> getTunnels() {
- return tunnelHandler.getTunnels();
- }
-
- @Override
- public TunnelHandler.Result createTunnel(Tunnel tunnel) {
- return tunnelHandler.createTunnel(tunnel);
- }
-
- @Override
- public TunnelHandler.Result removeTunnel(Tunnel tunnel) {
- for (Policy policy: policyHandler.getPolicies()) {
- if (policy.type() == Policy.Type.TUNNEL_FLOW) {
- TunnelPolicy tunnelPolicy = (TunnelPolicy) policy;
- if (tunnelPolicy.tunnelId().equals(tunnel.id())) {
- log.warn("Cannot remove the tunnel used by a policy");
- return TunnelHandler.Result.TUNNEL_IN_USE;
- }
- }
- }
- return tunnelHandler.removeTunnel(tunnel);
- }
-
- @Override
- public PolicyHandler.Result removePolicy(Policy policy) {
- return policyHandler.removePolicy(policy);
- }
-
- @Override
- public PolicyHandler.Result createPolicy(Policy policy) {
- return policyHandler.createPolicy(policy);
- }
-
- @Override
- public List<Policy> getPolicies() {
- return policyHandler.getPolicies();
- }
-
- @Override
- public Set<L2TunnelDescription> getL2TunnelDescriptions(boolean pending) {
- return l2TunnelHandler.getL2Descriptions(pending);
- }
-
- @Override
- public List<L2Tunnel> getL2Tunnels() {
- return l2TunnelHandler.getL2Tunnels();
- }
-
- @Override
- public List<L2TunnelPolicy> getL2Policies() {
- return l2TunnelHandler.getL2Policies();
- }
-
- @Override
- @Deprecated
- public L2TunnelHandler.Result addPseudowiresBulk(List<DefaultL2TunnelDescription> bulkPseudowires) {
-
- // get both added and pending pseudowires
- List<L2TunnelDescription> pseudowires = new ArrayList<>();
- pseudowires.addAll(l2TunnelHandler.getL2Descriptions(false));
- pseudowires.addAll(l2TunnelHandler.getL2Descriptions(true));
- pseudowires.addAll(bulkPseudowires);
-
- Set<L2TunnelDescription> newPseudowires = new HashSet(bulkPseudowires);
-
- L2TunnelHandler.Result retRes = L2TunnelHandler.Result.SUCCESS;
- L2TunnelHandler.Result res;
- for (DefaultL2TunnelDescription pw : bulkPseudowires) {
- res = addPseudowire(pw);
- if (res != L2TunnelHandler.Result.SUCCESS) {
- log.error("Pseudowire with id {} can not be instantiated !", res);
- retRes = res;
- }
- }
-
- return retRes;
- }
-
- @Override
- public L2TunnelHandler.Result addPseudowire(L2TunnelDescription l2TunnelDescription) {
- return l2TunnelHandler.deployPseudowire(l2TunnelDescription);
- }
-
- @Override
- public L2TunnelHandler.Result removePseudowire(Integer pwId) {
- return l2TunnelHandler.tearDownPseudowire(pwId);
- }
-
- @Override
- public void rerouteNetwork() {
- cfgListener.configureNetwork();
- }
-
- @Override
- public Map<DeviceId, Set<IpPrefix>> getDeviceSubnetMap() {
- Map<DeviceId, Set<IpPrefix>> deviceSubnetMap = Maps.newHashMap();
- deviceConfiguration.getRouters().forEach(device ->
- deviceSubnetMap.put(device, deviceConfiguration.getSubnets(device)));
- return deviceSubnetMap;
- }
-
-
- @Override
- public ImmutableMap<DeviceId, EcmpShortestPathGraph> getCurrentEcmpSpg() {
- if (defaultRoutingHandler != null) {
- return defaultRoutingHandler.getCurrentEmcpSpgMap();
- } else {
- return null;
- }
- }
-
- @Override
- public ImmutableMap<DestinationSetNextObjectiveStoreKey, NextNeighbors> getDstNextObjStore() {
- if (dsNextObjStore != null) {
- return ImmutableMap.copyOf(dsNextObjStore.entrySet());
- } else {
- return ImmutableMap.of();
- }
- }
-
- @Override
- public ImmutableMap<VlanNextObjectiveStoreKey, Integer> getVlanNextObjStore() {
- if (vlanNextObjStore != null) {
- return ImmutableMap.copyOf(vlanNextObjStore.entrySet());
- } else {
- return ImmutableMap.of();
- }
- }
-
- @Override
- public ImmutableMap<MacVlanNextObjectiveStoreKey, Integer> getMacVlanNextObjStore() {
- if (macVlanNextObjStore != null) {
- return ImmutableMap.copyOf(macVlanNextObjStore.entrySet());
- } else {
- return ImmutableMap.of();
- }
- }
-
- @Override
- public ImmutableMap<PortNextObjectiveStoreKey, Integer> getPortNextObjStore() {
- if (portNextObjStore != null) {
- return ImmutableMap.copyOf(portNextObjStore.entrySet());
- } else {
- return ImmutableMap.of();
- }
- }
-
- @Override
- public ImmutableMap<String, NextObjective> getPwInitNext() {
- if (l2TunnelHandler != null) {
- return l2TunnelHandler.getInitNext();
- } else {
- return ImmutableMap.of();
- }
- }
-
- @Override
- public ImmutableMap<String, NextObjective> getPwTermNext() {
- if (l2TunnelHandler != null) {
- return l2TunnelHandler.getTermNext();
- } else {
- return ImmutableMap.of();
- }
- }
-
- @Override
- public void invalidateNextObj(int nextId) {
- if (dsNextObjStore != null) {
- dsNextObjStore.entrySet().forEach(e -> {
- if (e.getValue().nextId() == nextId) {
- dsNextObjStore.remove(e.getKey());
- }
- });
- }
- if (vlanNextObjStore != null) {
- vlanNextObjStore.entrySet().forEach(e -> {
- if (e.getValue() == nextId) {
- vlanNextObjStore.remove(e.getKey());
- }
- });
- }
- if (macVlanNextObjStore != null) {
- macVlanNextObjStore.entrySet().forEach(e -> {
- if (e.getValue() == nextId) {
- macVlanNextObjStore.remove(e.getKey());
- }
- });
- }
- if (portNextObjStore != null) {
- portNextObjStore.entrySet().forEach(e -> {
- if (e.getValue() == nextId) {
- portNextObjStore.remove(e.getKey());
- }
- });
- }
- if (mcastHandler != null) {
- mcastHandler.removeNextId(nextId);
- }
- if (l2TunnelHandler != null) {
- l2TunnelHandler.removeNextId(nextId);
- }
- if (xconnectService != null) {
- xconnectService.removeNextId(nextId);
- }
- }
-
- @Override
- public void verifyGroups(DeviceId id) {
- DefaultGroupHandler gh = groupHandlerMap.get(id);
- if (gh != null) {
- gh.triggerBucketCorrector();
- }
- }
-
- @Override
- public ImmutableMap<Link, Boolean> getSeenLinks() {
- return linkHandler.getSeenLinks();
- }
-
- @Override
- public ImmutableMap<DeviceId, Set<PortNumber>> getDownedPortState() {
- return linkHandler.getDownedPorts();
- }
-
- @Override
- public Map<McastStoreKey, Integer> getMcastNextIds(IpAddress mcastIp) {
- return mcastHandler.getNextIds(mcastIp);
- }
-
- @Override
- public Map<McastRoleStoreKey, McastRole> getMcastRoles(IpAddress mcastIp, ConnectPoint sourcecp) {
- return mcastHandler.getMcastRoles(mcastIp, sourcecp);
- }
-
- @Override
- public Multimap<ConnectPoint, List<ConnectPoint>> getMcastTrees(IpAddress mcastIp,
- ConnectPoint sourcecp) {
- return mcastHandler.getMcastTrees(mcastIp, sourcecp);
- }
-
- @Override
- public Map<IpAddress, NodeId> getMcastLeaders(IpAddress mcastIp) {
- return mcastHandler.getMcastLeaders(mcastIp);
- }
-
- @Override
- public Map<DeviceId, List<McastFilteringObjStoreKey>> getMcastFilters() {
- return mcastHandler.getMcastFilters();
- }
-
- @Override
- public Map<Set<DeviceId>, NodeId> getShouldProgram() {
- return defaultRoutingHandler == null ? ImmutableMap.of() :
- ImmutableMap.copyOf(defaultRoutingHandler.shouldProgram);
- }
-
- @Override
- public Map<DeviceId, Boolean> getShouldProgramCache() {
- return defaultRoutingHandler == null ? ImmutableMap.of() :
- ImmutableMap.copyOf(defaultRoutingHandler.shouldProgramCache);
- }
-
- @Override
- public boolean shouldProgram(DeviceId deviceId) {
- return defaultRoutingHandler.shouldProgram(deviceId);
- }
-
- @Override
- public boolean isRoutingStable() {
- return defaultRoutingHandler.isRoutingStable();
- }
-
- @Override
- public void initHost(DeviceId deviceId) {
- hostEventExecutor.execute(() -> hostHandler.init(deviceId));
- }
-
- @Override
- public void initRoute(DeviceId deviceId) {
- routeEventExecutor.execute(() -> routeHandler.init(deviceId));
- }
-
- @Override
- public ApplicationId appId() {
- return appId;
- }
-
- /**
- * Returns the device configuration.
- *
- * @return device configuration
- */
- public DeviceConfiguration deviceConfiguration() {
- return deviceConfiguration;
- }
-
- /**
- * Per device next objective ID store with (device id + destination set) as key.
- * Used to keep track on MPLS group information.
- *
- * @return next objective ID store
- */
- public EventuallyConsistentMap<DestinationSetNextObjectiveStoreKey, NextNeighbors>
- dsNextObjStore() {
- return dsNextObjStore;
- }
-
- /**
- * Per device next objective ID store with (device id + vlanid) as key.
- * Used to keep track on L2 flood group information.
- *
- * @return vlan next object store
- */
- public EventuallyConsistentMap<VlanNextObjectiveStoreKey, Integer> vlanNextObjStore() {
- return vlanNextObjStore;
- }
-
- /**
- * Per device next objective ID store with (device id + MAC address + vlan) as key.
- * Used to keep track on L3 Unicast group information for indirect hosts.
- *
- * @return mac vlan next object store
- */
- public EventuallyConsistentMap<MacVlanNextObjectiveStoreKey, Integer> macVlanNextObjStore() {
- return macVlanNextObjStore;
- }
-
- /**
- * Per device next objective ID store with (device id + port + treatment + meta) as key.
- * Used to keep track on L2 interface group and L3 unicast group information for direct hosts.
- *
- * @return port next object store.
- */
- public EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer> portNextObjStore() {
- return portNextObjStore;
- }
-
- /**
- * Returns the MPLS-ECMP configuration which indicates whether ECMP on
- * labeled packets should be programmed or not.
- *
- * @return MPLS-ECMP value
- */
- public boolean getMplsEcmp() {
- SegmentRoutingAppConfig segmentRoutingAppConfig = cfgService
- .getConfig(this.appId, SegmentRoutingAppConfig.class);
- return segmentRoutingAppConfig != null && segmentRoutingAppConfig.mplsEcmp();
- }
-
- /**
- * Returns the tunnel object with the tunnel ID.
- *
- * @param tunnelId Tunnel ID
- * @return Tunnel reference
- */
- public Tunnel getTunnel(String tunnelId) {
- return tunnelHandler.getTunnel(tunnelId);
- }
-
- @Override
- public VlanId getInternalVlanId(ConnectPoint connectPoint) {
- VlanId untaggedVlanId = interfaceService.getUntaggedVlanId(connectPoint);
- VlanId nativeVlanId = interfaceService.getNativeVlanId(connectPoint);
- return untaggedVlanId != null ? untaggedVlanId : nativeVlanId;
- }
-
- @Override
- public Optional<DeviceId> getPairDeviceId(DeviceId deviceId) {
- SegmentRoutingDeviceConfig deviceConfig =
- cfgService.getConfig(deviceId, SegmentRoutingDeviceConfig.class);
- return Optional.ofNullable(deviceConfig).map(SegmentRoutingDeviceConfig::pairDeviceId);
- }
-
- @Override
- public Optional<PortNumber> getPairLocalPort(DeviceId deviceId) {
- SegmentRoutingDeviceConfig deviceConfig =
- cfgService.getConfig(deviceId, SegmentRoutingDeviceConfig.class);
- return Optional.ofNullable(deviceConfig).map(SegmentRoutingDeviceConfig::pairLocalPort);
- }
-
- @Override
- public Set<PortNumber> getInfraPorts(DeviceId deviceId) {
- return deviceService.getPorts(deviceId).stream()
- .map(port -> new ConnectPoint(port.element().id(), port.number()))
- .filter(cp -> interfaceService.getInterfacesByPort(cp).isEmpty())
- .map(ConnectPoint::port)
- .collect(Collectors.toSet());
- }
-
- @Override
- public Set<PortNumber> getEdgePorts(DeviceId deviceId) {
- return deviceService.getPorts(deviceId).stream()
- .map(port -> new ConnectPoint(port.element().id(), port.number()))
- .filter(cp -> !interfaceService.getInterfacesByPort(cp).isEmpty() &&
- !cp.port().equals(getPairLocalPort(deviceId).orElse(null)))
- .map(ConnectPoint::port)
- .collect(Collectors.toSet());
- }
-
- /**
- * Returns locations of given resolved route.
- *
- * @param resolvedRoute resolved route
- * @return locations of nexthop. Might be empty if next hop is not found
- */
- public Set<ConnectPoint> nextHopLocations(ResolvedRoute resolvedRoute) {
- HostId hostId = HostId.hostId(resolvedRoute.nextHopMac(), resolvedRoute.nextHopVlan());
- return Optional.ofNullable(hostService.getHost(hostId))
- .map(Host::locations).orElse(Sets.newHashSet())
- .stream().map(l -> (ConnectPoint) l).collect(Collectors.toSet());
- }
-
- /**
- * Returns vlan port map of given device.
- *
- * @param deviceId device id
- * @return vlan-port multimap
- */
- public Multimap<VlanId, PortNumber> getVlanPortMap(DeviceId deviceId) {
- HashMultimap<VlanId, PortNumber> vlanPortMap = HashMultimap.create();
-
- interfaceService.getInterfaces().stream()
- .filter(intf -> intf.connectPoint().deviceId().equals(deviceId))
- .forEach(intf -> {
- vlanPortMap.put(intf.vlanUntagged(), intf.connectPoint().port());
- intf.vlanTagged().forEach(vlanTagged ->
- vlanPortMap.put(vlanTagged, intf.connectPoint().port())
- );
- vlanPortMap.put(intf.vlanNative(), intf.connectPoint().port());
- });
- vlanPortMap.removeAll(VlanId.NONE);
-
- return vlanPortMap;
- }
-
- /**
- * Returns the next objective ID for the given vlan id. It is expected
- * that the next-objective has been pre-created from configuration.
- *
- * @param deviceId Device ID
- * @param vlanId VLAN ID
- * @return next objective ID or -1 if it was not found
- */
- int getVlanNextObjectiveId(DeviceId deviceId, VlanId vlanId) {
- if (groupHandlerMap.get(deviceId) != null) {
- log.trace("getVlanNextObjectiveId query in device {}", deviceId);
- return groupHandlerMap.get(deviceId).getVlanNextObjectiveId(vlanId);
- } else {
- log.warn("getVlanNextObjectiveId query - groupHandler for "
- + "device {} not found", deviceId);
- return -1;
- }
- }
-
- /**
- * Returns the next objective ID for the given portNumber, given the treatment.
- * There could be multiple different treatments to the same outport, which
- * would result in different objectives. If the next object does not exist,
- * and should be created, a new one is created and its id is returned.
- *
- * @param deviceId Device ID
- * @param portNum port number on device for which NextObjective is queried
- * @param treatment the actions to apply on the packets (should include outport)
- * @param meta metadata passed into the creation of a Next Objective if necessary
- * @param createIfMissing true if a next object should be created if not found
- * @return next objective ID or -1 if an error occurred during retrieval or creation
- */
- public int getPortNextObjectiveId(DeviceId deviceId, PortNumber portNum,
- TrafficTreatment treatment,
- TrafficSelector meta,
- boolean createIfMissing) {
- DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
- if (ghdlr != null) {
- return ghdlr.getPortNextObjectiveId(portNum, treatment, meta, createIfMissing);
- } else {
- log.warn("getPortNextObjectiveId query - groupHandler for device {}"
- + " not found", deviceId);
- return -1;
- }
- }
-
- /**
- * Returns the next Objective ID for the given mac and vlan, given the treatment.
- * There could be multiple different treatments to the same outport, which
- * would result in different objectives. If the next object does not exist,
- * and should be created, a new one is created and its id is returned.
- *
- * @param deviceId Device ID
- * @param macAddr mac of host for which Next ID is required.
- * @param vlanId vlan of host for which Next ID is required.
- * @param port port with which to create the Next Obj.
- * @param createIfMissing true if a next object should be created if not found
- * @return next objective ID or -1 if an error occurred during retrieval or creation
- */
- public int getMacVlanNextObjectiveId(DeviceId deviceId, MacAddress macAddr, VlanId vlanId,
- PortNumber port, boolean createIfMissing) {
- DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
- if (ghdlr != null) {
- return ghdlr.getMacVlanNextObjectiveId(macAddr, vlanId, port, createIfMissing);
- } else {
- log.warn("getMacVlanNextObjectiveId query - groupHandler for device {}"
- + " not found", deviceId);
- return -1;
- }
- }
-
- /**
- * Updates the next objective for the given nextId .
- *
- * @param deviceId Device ID
- * @param hostMac mac of host for which Next obj is to be updated.
- * @param hostVlanId vlan of host for which Next obj is to be updated.
- * @param port port with which to update the Next Obj.
- * @param nextId of Next Obj which needs to be updated.
- */
- public void updateMacVlanTreatment(DeviceId deviceId, MacAddress hostMac,
- VlanId hostVlanId, PortNumber port, int nextId) {
- // Check if we are the king of this device
- // just one instance should perform this update
- if (!defaultRoutingHandler.shouldProgram(deviceId)) {
- log.debug("This instance is not handling the routing towards the "
- + "device {}", deviceId);
- return;
- }
- // Get the handler and perform the update
- DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
- if (ghdlr != null) {
- ghdlr.updateL3UcastGroupBucket(hostMac, hostVlanId, port, nextId);
- } else {
- log.warn("updateL3UcastGroupBucket query - groupHandler for device {}"
- + " not found", deviceId);
- }
- }
-
-
- /**
- * Returns the group handler object for the specified device id.
- *
- * @param devId the device identifier
- * @return the groupHandler object for the device id, or null if not found
- */
- DefaultGroupHandler getGroupHandler(DeviceId devId) {
- return groupHandlerMap.get(devId);
- }
-
- /**
- * Returns the default routing handler object.
- *
- * @return the default routing handler object
- */
- public DefaultRoutingHandler getRoutingHandler() {
- return defaultRoutingHandler;
- }
-
- private class InternalPacketProcessor implements PacketProcessor {
- @Override
- public void process(PacketContext context) {
- packetExecutor.execute(() -> processPacketInternal(context));
- }
-
- private void processPacketInternal(PacketContext context) {
- if (context.isHandled()) {
- return;
- }
-
- InboundPacket pkt = context.inPacket();
- Ethernet ethernet = pkt.parsed();
-
- if (ethernet == null) {
- return;
- }
-
- log.trace("Rcvd pktin from {}: {}", context.inPacket().receivedFrom(),
- ethernet);
- if (ethernet.getEtherType() == TYPE_ARP) {
- log.warn("Received unexpected ARP packet on {}",
- context.inPacket().receivedFrom());
- log.trace("{}", ethernet);
- return;
- } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
- IPv4 ipv4Packet = (IPv4) ethernet.getPayload();
- //ipHandler.addToPacketBuffer(ipv4Packet);
- if (ipv4Packet.getProtocol() == IPv4.PROTOCOL_ICMP) {
- icmpHandler.processIcmp(ethernet, pkt.receivedFrom());
- } else {
- // NOTE: We don't support IP learning at this moment so this
- // is not necessary. Also it causes duplication of DHCP packets.
- // ipHandler.processPacketIn(ipv4Packet, pkt.receivedFrom());
- }
- } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV6) {
- IPv6 ipv6Packet = (IPv6) ethernet.getPayload();
- //ipHandler.addToPacketBuffer(ipv6Packet);
- // We deal with the packet only if the packet is a ICMP6 ECHO/REPLY
- if (ipv6Packet.getNextHeader() == IPv6.PROTOCOL_ICMP6) {
- ICMP6 icmp6Packet = (ICMP6) ipv6Packet.getPayload();
- if (icmp6Packet.getIcmpType() == ICMP6.ECHO_REQUEST ||
- icmp6Packet.getIcmpType() == ICMP6.ECHO_REPLY) {
- icmpHandler.processIcmpv6(ethernet, pkt.receivedFrom());
- } else {
- log.trace("Received ICMPv6 0x{} - not handled",
- Integer.toHexString(icmp6Packet.getIcmpType() & 0xff));
- }
- } else {
- // NOTE: We don't support IP learning at this moment so this
- // is not necessary. Also it causes duplication of DHCPv6 packets.
- // ipHandler.processPacketIn(ipv6Packet, pkt.receivedFrom());
- }
- }
- }
- }
-
- private class InternalEventHandler implements Runnable {
- private Event event;
-
- InternalEventHandler(Event event) {
- this.event = event;
- }
-
- @Override
- public void run() {
- try {
- // TODO We should also change SR routing and PW to listen to TopologyEvents
- if (event.type() == LinkEvent.Type.LINK_ADDED ||
- event.type() == LinkEvent.Type.LINK_UPDATED) {
- linkHandler.processLinkAdded((Link) event.subject());
- } else if (event.type() == LinkEvent.Type.LINK_REMOVED) {
- linkHandler.processLinkRemoved((Link) event.subject());
- } else if (event.type() == DeviceEvent.Type.DEVICE_ADDED ||
- event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
- event.type() == DeviceEvent.Type.DEVICE_UPDATED) {
- DeviceId deviceId = ((Device) event.subject()).id();
- if (deviceService.isAvailable(deviceId)) {
- log.info("** DEVICE UP Processing device event {} "
- + "for available device {}",
- event.type(), ((Device) event.subject()).id());
- processDeviceAdded((Device) event.subject());
- } else {
- if (event.type() == DeviceEvent.Type.DEVICE_ADDED) {
- // Note: For p4 devices, the device will be added but unavailable at the beginning.
- // The device will later on being marked as available once the pipeline is pushed
- // to the device.
- log.info("** DEVICE ADDED but unavailable. Ignore");
- return;
- }
- log.info(" ** DEVICE DOWN Processing device event {}"
- + " for unavailable device {}",
- event.type(), ((Device) event.subject()).id());
- processDeviceRemoved((Device) event.subject());
- }
- } else if (event.type() == DeviceEvent.Type.PORT_ADDED) {
- // typically these calls come when device is added first time
- // so port filtering rules are handled at the device_added event.
- // port added calls represent all ports on the device,
- // enabled or not.
- log.trace("** PORT ADDED {}/{} -> {}",
- ((DeviceEvent) event).subject().id(),
- ((DeviceEvent) event).port().number(),
- event.type());
- } else if (event.type() == DeviceEvent.Type.PORT_UPDATED) {
- // these calls happen for every subsequent event
- // ports enabled, disabled, switch goes away, comes back
- log.info("** PORT UPDATED {}/{} -> {}",
- event.subject(),
- ((DeviceEvent) event).port(),
- event.type());
- processPortUpdatedInternal(((Device) event.subject()),
- ((DeviceEvent) event).port());
- mcastHandler.processPortUpdate(((Device) event.subject()),
- ((DeviceEvent) event).port());
- } else if (event.type() == TopologyEvent.Type.TOPOLOGY_CHANGED) {
- // Process topology event, needed for all modules relying on
- // topology service for path computation
- TopologyEvent topologyEvent = (TopologyEvent) event;
- log.info("Processing topology event {}, topology age {}, reasons {}",
- event.type(), topologyEvent.subject().time(),
- topologyEvent.reasons().size());
- topologyHandler.processTopologyChange(topologyEvent.reasons());
- } else if (event.type() == HostEvent.Type.HOST_ADDED) {
- hostHandler.processHostAddedEvent((HostEvent) event);
- } else if (event.type() == HostEvent.Type.HOST_MOVED) {
- hostHandler.processHostMovedEvent((HostEvent) event);
- routeHandler.processHostMovedEvent((HostEvent) event);
- } else if (event.type() == HostEvent.Type.HOST_AUX_MOVED) {
- hostHandler.processHostMovedEvent((HostEvent) event);
- // TODO RouteHandler also needs to process this event in order to
- // support nexthops that has auxLocations
- } else if (event.type() == HostEvent.Type.HOST_REMOVED) {
- hostHandler.processHostRemovedEvent((HostEvent) event);
- } else if (event.type() == HostEvent.Type.HOST_UPDATED) {
- hostHandler.processHostUpdatedEvent((HostEvent) event);
- } else if (event.type() == RouteEvent.Type.ROUTE_ADDED) {
- routeHandler.processRouteAdded((RouteEvent) event);
- } else if (event.type() == RouteEvent.Type.ROUTE_UPDATED) {
- routeHandler.processRouteUpdated((RouteEvent) event);
- } else if (event.type() == RouteEvent.Type.ROUTE_REMOVED) {
- routeHandler.processRouteRemoved((RouteEvent) event);
- } else if (event.type() == RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED) {
- routeHandler.processAlternativeRoutesChanged((RouteEvent) event);
- } else if (event.type() == McastEvent.Type.SOURCES_ADDED ||
- event.type() == McastEvent.Type.SOURCES_REMOVED ||
- event.type() == McastEvent.Type.SINKS_ADDED ||
- event.type() == McastEvent.Type.SINKS_REMOVED ||
- event.type() == McastEvent.Type.ROUTE_ADDED ||
- event.type() == McastEvent.Type.ROUTE_REMOVED) {
- mcastHandler.processMcastEvent((McastEvent) event);
- } else if (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED) {
- NetworkConfigEvent netcfgEvent = (NetworkConfigEvent) event;
- Class configClass = netcfgEvent.configClass();
- if (configClass.equals(SegmentRoutingAppConfig.class)) {
- appCfgHandler.processAppConfigAdded(netcfgEvent);
- log.info("App config event .. configuring network");
- cfgListener.configureNetwork();
- } else if (configClass.equals(SegmentRoutingDeviceConfig.class)) {
- log.info("Segment Routing Device Config added for {}", event.subject());
- cfgListener.configureNetwork();
- } else if (configClass.equals(InterfaceConfig.class)) {
- log.info("Interface Config added for {}", event.subject());
- cfgListener.configureNetwork();
- } else {
- log.error("Unhandled config class: {}", configClass);
- }
- } else if (event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) {
- NetworkConfigEvent netcfgEvent = (NetworkConfigEvent) event;
- Class configClass = netcfgEvent.configClass();
- if (configClass.equals(SegmentRoutingAppConfig.class)) {
- appCfgHandler.processAppConfigUpdated(netcfgEvent);
- log.info("App config event .. configuring network");
- cfgListener.configureNetwork();
- } else if (configClass.equals(SegmentRoutingDeviceConfig.class)) {
- log.info("Segment Routing Device Config updated for {}", event.subject());
- createOrUpdateDeviceConfiguration();
- } else if (configClass.equals(InterfaceConfig.class)) {
- log.info("Interface Config updated for {}", event.subject());
- createOrUpdateDeviceConfiguration();
- updateInterface((InterfaceConfig) netcfgEvent.config().get(),
- (InterfaceConfig) netcfgEvent.prevConfig().get());
- } else {
- log.error("Unhandled config class: {}", configClass);
- }
- } else if (event.type() == NetworkConfigEvent.Type.CONFIG_REMOVED) {
- NetworkConfigEvent netcfgEvent = (NetworkConfigEvent) event;
- Class configClass = netcfgEvent.configClass();
- if (configClass.equals(SegmentRoutingAppConfig.class)) {
- appCfgHandler.processAppConfigRemoved(netcfgEvent);
- log.info("App config event .. configuring network");
- cfgListener.configureNetwork();
- } else if (configClass.equals(SegmentRoutingDeviceConfig.class)) {
- // TODO Handle sr device config removal
- log.info("SegmentRoutingDeviceConfig removal is not handled in current implementation");
- } else if (configClass.equals(InterfaceConfig.class)) {
- // TODO Handle interface removal
- log.info("InterfaceConfig removal is not handled in current implementation");
- } else {
- log.error("Unhandled config class: {}", configClass);
- }
- } else if (event.type() == MastershipEvent.Type.MASTER_CHANGED) {
- MastershipEvent me = (MastershipEvent) event;
- DeviceId deviceId = me.subject();
- Optional<DeviceId> pairDeviceId = getPairDeviceId(deviceId);
- log.info(" ** MASTERSHIP CHANGED Invalidating shouldProgram cache"
- + " for {}/pair={} due to change", deviceId, pairDeviceId);
- defaultRoutingHandler.invalidateShouldProgramCache(deviceId);
- pairDeviceId.ifPresent(defaultRoutingHandler::invalidateShouldProgramCache);
- defaultRoutingHandler.checkFullRerouteForMasterChange(deviceId, me);
- } else {
- log.warn("Unhandled event type: {}", event.type());
- }
- } catch (Exception e) {
- log.error("SegmentRouting event handler thread thrown an exception: {}",
- e.getMessage(), e);
- }
- }
- }
-
- void processDeviceAdded(Device device) {
- log.info("** DEVICE ADDED with ID {}", device.id());
-
- // NOTE: Punt ARP/NDP even when the device is not configured.
- // Host learning without network config is required for CORD config generator.
- routingRulePopulator.populateIpPunts(device.id());
- routingRulePopulator.populateArpNdpPunts(device.id());
-
- if (deviceConfiguration == null || !deviceConfiguration.isConfigured(device.id())) {
- log.warn("Device configuration unavailable. Device {} will be "
- + "processed after configuration.", device.id());
- return;
- }
- processDeviceAddedInternal(device.id());
- }
-
- private void processDeviceAddedInternal(DeviceId deviceId) {
- // Irrespective of whether the local is a MASTER or not for this device,
- // we need to create a SR-group-handler instance. This is because in a
- // multi-instance setup, any instance can initiate forwarding/next-objectives
- // for any switch (even if this instance is a SLAVE or not even connected
- // to the switch). To handle this, a default-group-handler instance is necessary
- // per switch.
- log.debug("Current groupHandlerMap devs: {}", groupHandlerMap.keySet());
- if (groupHandlerMap.get(deviceId) == null) {
- DefaultGroupHandler groupHandler;
- try {
- groupHandler = DefaultGroupHandler.
- createGroupHandler(deviceId,
- appId,
- deviceConfiguration,
- linkService,
- flowObjectiveService,
- this);
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage() + " Aborting processDeviceAdded.");
- return;
- }
- log.debug("updating groupHandlerMap with new grpHdlr for device: {}",
- deviceId);
- groupHandlerMap.put(deviceId, groupHandler);
- }
-
- if (mastershipService.isLocalMaster(deviceId)) {
- defaultRoutingHandler.populatePortAddressingRules(deviceId);
- defaultRoutingHandler.purgeSeenBeforeRoutes(deviceId);
- DefaultGroupHandler groupHandler = groupHandlerMap.get(deviceId);
- groupHandler.createGroupsFromVlanConfig();
- routingRulePopulator.populateSubnetBroadcastRule(deviceId);
- phasedRecoveryService.init(deviceId);
- }
-
- appCfgHandler.init(deviceId);
- }
-
- private void processDeviceRemoved(Device device) {
- dsNextObjStore.entrySet().stream()
- .filter(entry -> entry.getKey().deviceId().equals(device.id()))
- .forEach(entry -> dsNextObjStore.remove(entry.getKey()));
- vlanNextObjStore.entrySet().stream()
- .filter(entry -> entry.getKey().deviceId().equals(device.id()))
- .forEach(entry -> vlanNextObjStore.remove(entry.getKey()));
- macVlanNextObjStore.entrySet().stream()
- .filter(entry -> entry.getKey().deviceId().equals(device.id()))
- .forEach(entry -> macVlanNextObjStore.remove(entry.getKey()));
- portNextObjStore.entrySet().stream()
- .filter(entry -> entry.getKey().deviceId().equals(device.id()))
- .forEach(entry -> portNextObjStore.remove(entry.getKey()));
- linkHandler.processDeviceRemoved(device);
-
- DefaultGroupHandler gh = groupHandlerMap.remove(device.id());
- if (gh != null) {
- gh.shutdown();
- }
- // Note that a switch going down is associated with all of its links
- // going down as well, but it is treated as a single switch down event
- // while the link-downs are ignored. We cannot rely on the ordering of
- // events - i.e we cannot expect all link-downs to come before the
- // switch down - so we purge all seen-links for the switch before
- // handling route-path changes for the switch-down
- defaultRoutingHandler
- .populateRoutingRulesForLinkStatusChange(null, null, device.id(), true);
- defaultRoutingHandler.purgeEcmpGraph(device.id());
-
- // Cleanup all internal groupHandler stores for this device. Should be
- // done after all rerouting or rehashing has been completed
- groupHandlerMap.entrySet()
- .forEach(entry -> entry.getValue().cleanUpForNeighborDown(device.id()));
-
- phasedRecoveryService.reset(device.id());
- }
-
- /**
- * Purge the destinationSet nextObjective store of entries with this device
- * as key. Erases app-level knowledge of hashed groups in this device.
- *
- * @param devId the device identifier
- */
- void purgeHashedNextObjectiveStore(DeviceId devId) {
- log.debug("Purging hashed next-obj store for dev:{}", devId);
- dsNextObjStore.entrySet().stream()
- .filter(entry -> entry.getKey().deviceId().equals(devId))
- .forEach(entry -> dsNextObjStore.remove(entry.getKey()));
- }
-
- private void processPortUpdatedInternal(Device device, Port port) {
- if (deviceConfiguration == null || !deviceConfiguration.isConfigured(device.id())) {
- log.warn("Device configuration uploading. Not handling port event for"
- + "dev: {} port: {}", device.id(), port.number());
- return;
- }
-
- if (interfaceService.isConfigured(new ConnectPoint(device.id(), port.number()))) {
- lastEdgePortEvent = Instant.now();
- }
-
- if (!mastershipService.isLocalMaster(device.id())) {
- log.debug("Not master for dev:{} .. not handling port updated event"
- + "for port {}", device.id(), port.number());
- return;
- }
- processPortUpdated(device.id(), port);
- }
-
- /**
- * Adds or remove filtering rules for the given switchport. If switchport is
- * an edge facing port, additionally handles host probing and broadcast
- * rules. Must be called by local master of device.
- *
- * @param deviceId the device identifier
- * @param port the port to update
- */
- void processPortUpdated(DeviceId deviceId, Port port) {
- // first we handle filtering rules associated with the port
- if (port.isEnabled()) {
- log.info("Switchport {}/{} enabled..programming filters",
- deviceId, port.number());
- routingRulePopulator.processSinglePortFilters(deviceId, port.number(), true);
- } else {
- log.info("Switchport {}/{} disabled..removing filters",
- deviceId, port.number());
- routingRulePopulator.processSinglePortFilters(deviceId, port.number(), false);
- }
-
- // portUpdated calls are for ports that have gone down or up. For switch
- // 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.
- ConnectPoint cp = new ConnectPoint(deviceId, port.number());
- VlanId untaggedVlan = interfaceService.getUntaggedVlanId(cp);
- VlanId nativeVlan = interfaceService.getNativeVlanId(cp);
- Set<VlanId> taggedVlans = interfaceService.getTaggedVlanId(cp);
-
- if (untaggedVlan == null && nativeVlan == null && taggedVlans.isEmpty()) {
- log.debug("Not handling port updated event for non-edge port (unconfigured) "
- + "dev/port: {}/{}", deviceId, port.number());
- return;
- }
- if (untaggedVlan != null) {
- processEdgePort(deviceId, port, untaggedVlan, true);
- }
- if (nativeVlan != null) {
- processEdgePort(deviceId, port, nativeVlan, true);
- }
- if (!taggedVlans.isEmpty()) {
- taggedVlans.forEach(tag -> processEdgePort(deviceId, port, tag, false));
- }
- }
-
- private void processEdgePort(DeviceId deviceId, Port port, VlanId vlanId,
- boolean popVlan) {
- boolean portUp = port.isEnabled();
- if (portUp) {
- log.info("Device:EdgePort {}:{} is enabled in vlan: {}", deviceId,
- port.number(), vlanId);
- hostEventExecutor.execute(() -> hostHandler.processPortUp(new ConnectPoint(deviceId, port.number())));
- } else {
- log.info("Device:EdgePort {}:{} is disabled in vlan: {}", deviceId,
- port.number(), vlanId);
- }
-
- DefaultGroupHandler groupHandler = groupHandlerMap.get(deviceId);
- if (groupHandler != null) {
- groupHandler.processEdgePort(port.number(), vlanId, popVlan, portUp);
- } else {
- log.warn("Group handler not found for dev:{}. Not handling edge port"
- + " {} event for port:{}", deviceId,
- (portUp) ? "UP" : "DOWN", port.number());
- }
- }
-
- private void createOrUpdateDeviceConfiguration() {
- if (deviceConfiguration == null) {
- log.info("Creating new DeviceConfiguration");
- deviceConfiguration = new DeviceConfiguration(this);
- } else {
- log.info("Updating DeviceConfiguration");
- deviceConfiguration.updateConfig();
- }
- }
-
- private void createOrUpdateDefaultRoutingHandler() {
- if (defaultRoutingHandler == null) {
- log.info("Creating new DefaultRoutingHandler");
- defaultRoutingHandler = new DefaultRoutingHandler(this);
- } else {
- log.info("Updating DefaultRoutingHandler");
- defaultRoutingHandler.update(this);
- }
- }
-
- /**
- * Registers the given connect point with the NRS, this is necessary
- * to receive the NDP and ARP packets from the NRS.
- *
- * @param portToRegister connect point to register
- */
- public void registerConnectPoint(ConnectPoint portToRegister) {
- neighbourResolutionService.registerNeighbourHandler(
- portToRegister,
- neighbourHandler,
- appId
- );
- }
-
- private class InternalConfigListener implements NetworkConfigListener {
- private static final long PROGRAM_DELAY = 2;
- SegmentRoutingManager srManager;
-
- /**
- * Constructs the internal network config listener.
- *
- * @param srManager segment routing manager
- */
- InternalConfigListener(SegmentRoutingManager srManager) {
- this.srManager = srManager;
- }
-
- /**
- * Reads network config and initializes related data structure accordingly.
- */
- void configureNetwork() {
- log.info("Configuring network ...");
-
- // Setting handling of network configuration events completable future
- // The completable future is needed because of the async behaviour of the configureNetwork,
- // listener registration and event arrival
- // Enables us to buffer the events and execute them when the configure network is done.
- synchronized (networkConfigCompletionLock) {
- networkConfigCompletion = new CompletableFuture<>();
-
- // add a small delay to absorb multiple network config added notifications
- if (!programmingScheduled.get()) {
- log.info("Buffering config calls for {} secs", PROGRAM_DELAY);
- programmingScheduled.set(true);
- mainEventExecutor.schedule(new ConfigChange(), PROGRAM_DELAY, TimeUnit.SECONDS);
- }
-
- createOrUpdateDeviceConfiguration();
-
- arpHandler = new ArpHandler(srManager);
- icmpHandler = new IcmpHandler(srManager);
- ipHandler = new IpHandler(srManager);
- routingRulePopulator = new RoutingRulePopulator(srManager);
- createOrUpdateDefaultRoutingHandler();
-
- tunnelHandler = new TunnelHandler(linkService, deviceConfiguration,
- groupHandlerMap, tunnelStore);
- policyHandler = new PolicyHandler(appId, deviceConfiguration,
- flowObjectiveService,
- tunnelHandler, policyStore);
- networkConfigCompletion.complete(true);
- }
-
- mcastHandler.init();
-
- }
-
- @Override
- public void event(NetworkConfigEvent event) {
- if (mainEventExecutor == null) {
- return;
- }
- checkState(appCfgHandler != null, "NetworkConfigEventHandler is not initialized");
- switch (event.type()) {
- case CONFIG_ADDED:
- case CONFIG_UPDATED:
- case CONFIG_REMOVED:
- if (networkConfigCompletion == null || networkConfigCompletion.isDone()) {
- log.debug("Process netcfg {}", event);
- mainEventExecutor.execute(new InternalEventHandler(event));
- } else {
- log.debug("Queue netcfg {}", event);
- queuedEvents.add(event);
- }
- break;
- default:
- break;
- }
- }
-
- @Override
- public boolean isRelevant(NetworkConfigEvent event) {
- if (event.type() == CONFIG_REGISTERED ||
- event.type() == CONFIG_UNREGISTERED) {
- log.debug("Ignore event {} due to type mismatch", event);
- return false;
- }
-
- if (!event.configClass().equals(SegmentRoutingDeviceConfig.class) &&
- !event.configClass().equals(SegmentRoutingAppConfig.class) &&
- !event.configClass().equals(InterfaceConfig.class)) {
- log.debug("Ignore event {} due to class mismatch", event);
- return false;
- }
-
- return true;
- }
-
- private final class ConfigChange implements Runnable {
- @Override
- public void run() {
- programmingScheduled.set(false);
- log.info("Reacting to config changes after buffer delay");
- for (Device device : deviceService.getDevices()) {
- processDeviceAdded(device);
- }
- defaultRoutingHandler.startPopulationProcess();
- }
- }
- }
-
- private class InternalLinkListener implements LinkListener {
- @Override
- public void event(LinkEvent event) {
- if (mainEventExecutor == null) {
- return;
- }
- if (event.type() == LinkEvent.Type.LINK_ADDED ||
- event.type() == LinkEvent.Type.LINK_UPDATED ||
- event.type() == LinkEvent.Type.LINK_REMOVED) {
- log.trace("Schedule Link event {}", event);
- if (networkConfigCompletion == null || networkConfigCompletion.isDone()) {
- mainEventExecutor.execute(new InternalEventHandler(event));
- } else {
- queuedEvents.add(event);
- }
- }
- }
- }
-
- private class InternalDeviceListener implements DeviceListener {
- @Override
- public void event(DeviceEvent event) {
- if (mainEventExecutor == null) {
- return;
- }
- switch (event.type()) {
- case DEVICE_ADDED:
- case PORT_UPDATED:
- case PORT_ADDED:
- case DEVICE_UPDATED:
- case DEVICE_AVAILABILITY_CHANGED:
- log.trace("Schedule Device event {}", event);
- if (networkConfigCompletion == null || networkConfigCompletion.isDone()) {
- mainEventExecutor.execute(new InternalEventHandler(event));
- } else {
- queuedEvents.add(event);
- }
- break;
- default:
- }
- }
- }
-
- private class InternalTopologyListener implements TopologyListener {
- @Override
- public void event(TopologyEvent event) {
- if (mainEventExecutor == null) {
- return;
- }
- switch (event.type()) {
- case TOPOLOGY_CHANGED:
- log.trace("Schedule Topology event {}", event);
- if (networkConfigCompletion == null || networkConfigCompletion.isDone()) {
- mainEventExecutor.execute(new InternalEventHandler(event));
- } else {
- queuedEvents.add(event);
- }
- break;
- default:
- }
- }
- }
-
- private class InternalHostListener implements HostListener {
- @Override
- public void event(HostEvent event) {
- if (hostEventExecutor == null) {
- return;
- }
- switch (event.type()) {
- case HOST_ADDED:
- case HOST_MOVED:
- case HOST_REMOVED:
- case HOST_UPDATED:
- log.trace("Schedule Host event {}", event);
- hostEventExecutor.execute(new InternalEventHandler(event));
- break;
- default:
- log.warn("Unsupported host event type: {}", event.type());
- break;
- }
- }
- }
-
- private class InternalMcastListener implements McastListener {
- @Override
- public void event(McastEvent event) {
- if (mcastEventExecutor == null) {
- return;
- }
- switch (event.type()) {
- case SOURCES_ADDED:
- case SOURCES_REMOVED:
- case SINKS_ADDED:
- case SINKS_REMOVED:
- case ROUTE_REMOVED:
- case ROUTE_ADDED:
- log.trace("Schedule Mcast event {}", event);
- mcastEventExecutor.execute(new InternalEventHandler(event));
- break;
- default:
- log.warn("Unsupported mcast event type: {}", event.type());
- break;
- }
- }
- }
-
- private class InternalRouteEventListener implements RouteListener {
- @Override
- public void event(RouteEvent event) {
- if (routeEventExecutor == null) {
- return;
- }
- switch (event.type()) {
- case ROUTE_ADDED:
- case ROUTE_UPDATED:
- case ROUTE_REMOVED:
- case ALTERNATIVE_ROUTES_CHANGED:
- log.trace("Schedule Route event {}", event);
- routeEventExecutor.execute(new InternalEventHandler(event));
- break;
- default:
- log.warn("Unsupported route event type: {}", event.type());
- break;
- }
- }
- }
-
- private class InternalMastershipListener implements MastershipListener {
- @Override
- public void event(MastershipEvent event) {
- if (mainEventExecutor == null) {
- return;
- }
- switch (event.type()) {
- case MASTER_CHANGED:
- log.debug("Mastership event: {}/{}", event.subject(),
- event.roleInfo());
- mainEventExecutor.execute(new InternalEventHandler(event));
- break;
- case BACKUPS_CHANGED:
- case SUSPENDED:
- default:
- log.debug("Mastership event type {} not handled", event.type());
- break;
- }
- }
- }
-
- class InternalClusterListener implements ClusterEventListener {
- private Instant lastClusterEvent = Instant.EPOCH;
-
- long timeSinceLastClusterEvent() {
- return Instant.now().toEpochMilli() - lastClusterEvent.toEpochMilli();
- }
-
- @Override
- public void event(ClusterEvent event) {
- switch (event.type()) {
- case INSTANCE_ACTIVATED:
- case INSTANCE_ADDED:
- case INSTANCE_READY:
- log.debug("Cluster event {} ignored", event.type());
- break;
- case INSTANCE_DEACTIVATED:
- case INSTANCE_REMOVED:
- log.info("** Cluster event {}", event.type());
- lastClusterEvent = Instant.now();
- break;
- default:
- break;
- }
-
- }
-
- }
-
- private void updateInterface(InterfaceConfig conf, InterfaceConfig prevConf) {
- try {
- Set<Interface> intfs = conf.getInterfaces();
- Set<Interface> prevIntfs = prevConf.getInterfaces();
-
- // Now we only handle one interface config at each port.
- if (intfs.size() != 1 || prevIntfs.size() != 1) {
- log.warn("Interface update aborted - one at a time is allowed, " +
- "but {} / {}(prev) received.", intfs.size(), prevIntfs.size());
- return;
- }
-
- //The system is in an incoherent state, abort
- if (defaultRoutingHandler == null) {
- log.warn("Interface update aborted, defaultRoutingHandler is null");
- return;
- }
-
- Interface intf = intfs.stream().findFirst().get();
- Interface prevIntf = prevIntfs.stream().findFirst().get();
-
- DeviceId deviceId = intf.connectPoint().deviceId();
- PortNumber portNum = intf.connectPoint().port();
-
- removeSubnetConfig(prevIntf.connectPoint(),
- Sets.difference(new HashSet<>(prevIntf.ipAddressesList()),
- new HashSet<>(intf.ipAddressesList())));
-
- if (!prevIntf.vlanNative().equals(VlanId.NONE)
- && !prevIntf.vlanNative().equals(intf.vlanUntagged())
- && !prevIntf.vlanNative().equals(intf.vlanNative())) {
- if (intf.vlanTagged().contains(prevIntf.vlanNative())) {
- // Update filtering objective and L2IG group bucket
- updatePortVlanTreatment(deviceId, portNum, prevIntf.vlanNative(), false);
- } else {
- // RemoveVlanNative
- updateVlanConfigInternal(deviceId, portNum, prevIntf.vlanNative(), true, false);
- }
- }
-
- if (!prevIntf.vlanUntagged().equals(VlanId.NONE)
- && !prevIntf.vlanUntagged().equals(intf.vlanUntagged())
- && !prevIntf.vlanUntagged().equals(intf.vlanNative())) {
- if (intf.vlanTagged().contains(prevIntf.vlanUntagged())) {
- // Update filtering objective and L2IG group bucket
- updatePortVlanTreatment(deviceId, portNum, prevIntf.vlanUntagged(), false);
- } else {
- // RemoveVlanUntagged
- updateVlanConfigInternal(deviceId, portNum, prevIntf.vlanUntagged(), true, false);
- }
- }
-
- if (!prevIntf.vlanTagged().isEmpty() && !intf.vlanTagged().equals(prevIntf.vlanTagged())) {
- // RemoveVlanTagged
- Sets.difference(prevIntf.vlanTagged(), intf.vlanTagged()).stream()
- .filter(i -> !intf.vlanUntagged().equals(i))
- .filter(i -> !intf.vlanNative().equals(i))
- .forEach(vlanId -> updateVlanConfigInternal(
- deviceId, portNum, vlanId, false, false));
- }
-
- if (!intf.vlanNative().equals(VlanId.NONE)
- && !prevIntf.vlanNative().equals(intf.vlanNative())
- && !prevIntf.vlanUntagged().equals(intf.vlanNative())) {
- if (prevIntf.vlanTagged().contains(intf.vlanNative())) {
- // Update filtering objective and L2IG group bucket
- updatePortVlanTreatment(deviceId, portNum, intf.vlanNative(), true);
- } else {
- // AddVlanNative
- updateVlanConfigInternal(deviceId, portNum, intf.vlanNative(), true, true);
- }
- }
-
- if (!intf.vlanTagged().isEmpty() && !intf.vlanTagged().equals(prevIntf.vlanTagged())) {
- // AddVlanTagged
- Sets.difference(intf.vlanTagged(), prevIntf.vlanTagged()).stream()
- .filter(i -> !prevIntf.vlanUntagged().equals(i))
- .filter(i -> !prevIntf.vlanNative().equals(i))
- .forEach(vlanId -> updateVlanConfigInternal(
- deviceId, portNum, vlanId, false, true)
- );
- }
-
- if (!intf.vlanUntagged().equals(VlanId.NONE)
- && !prevIntf.vlanUntagged().equals(intf.vlanUntagged())
- && !prevIntf.vlanNative().equals(intf.vlanUntagged())) {
- if (prevIntf.vlanTagged().contains(intf.vlanUntagged())) {
- // Update filtering objective and L2IG group bucket
- updatePortVlanTreatment(deviceId, portNum, intf.vlanUntagged(), true);
- } else {
- // AddVlanUntagged
- updateVlanConfigInternal(deviceId, portNum, intf.vlanUntagged(), true, true);
- }
- }
- addSubnetConfig(prevIntf.connectPoint(),
- Sets.difference(new HashSet<>(intf.ipAddressesList()),
- new HashSet<>(prevIntf.ipAddressesList())));
- } catch (ConfigException e) {
- log.error("Error in configuration");
- }
- }
-
- private void updatePortVlanTreatment(DeviceId deviceId, PortNumber portNum,
- VlanId vlanId, boolean pushVlan) {
- DefaultGroupHandler grpHandler = getGroupHandler(deviceId);
- if (grpHandler == null) {
- log.warn("Failed to retrieve group handler for device {}", deviceId);
- return;
- }
-
- // Update filtering objective for a single port
- routingRulePopulator.updateSinglePortFilters(deviceId, portNum, !pushVlan, vlanId, false);
- routingRulePopulator.updateSinglePortFilters(deviceId, portNum, pushVlan, vlanId, true);
-
- if (getVlanNextObjectiveId(deviceId, vlanId) != -1) {
- // Update L2IG bucket of the port
- grpHandler.updateL2InterfaceGroupBucket(portNum, vlanId, pushVlan);
- // Update bridging and unicast routing rule for each host
- hostEventExecutor.execute(() -> hostHandler.processIntfVlanUpdatedEvent(deviceId, portNum,
- vlanId, !pushVlan, false));
- hostEventExecutor.execute(() -> hostHandler.processIntfVlanUpdatedEvent(deviceId, portNum,
- vlanId, pushVlan, true));
- } else {
- log.warn("Failed to retrieve next objective for vlan {} in device {}:{}", vlanId, deviceId, portNum);
- }
- }
-
- private void updateVlanConfigInternal(DeviceId deviceId, PortNumber portNum,
- VlanId vlanId, boolean pushVlan, boolean install) {
- DefaultGroupHandler grpHandler = getGroupHandler(deviceId);
- if (grpHandler == null) {
- log.warn("Failed to retrieve group handler for device {}", deviceId);
- return;
- }
-
- // Update filtering objective for a single port
- routingRulePopulator.updateSinglePortFilters(deviceId, portNum, pushVlan, vlanId, install);
-
- // Update filtering objective for multicast ingress port
- mcastHandler.updateFilterToDevice(deviceId, portNum, vlanId, install);
-
- int nextId = getVlanNextObjectiveId(deviceId, vlanId);
-
- if (nextId != -1 && !install) {
- // Remove L2 Bridging rule and L3 Unicast rule to the host
- hostEventExecutor.execute(() -> hostHandler.processIntfVlanUpdatedEvent(deviceId, portNum,
- vlanId, pushVlan, install));
- // Remove broadcast forwarding rule and corresponding L2FG for VLAN
- // only if there is no port configured on that VLAN ID
- if (!getVlanPortMap(deviceId).containsKey(vlanId)) {
- // Remove broadcast forwarding rule for the VLAN
- routingRulePopulator.updateSubnetBroadcastRule(deviceId, vlanId, install);
- // Remove L2FG for VLAN
- grpHandler.removeBcastGroupFromVlan(deviceId, portNum, vlanId, pushVlan);
- } else {
- // Remove a single port from L2FG
- grpHandler.updateGroupFromVlanConfiguration(vlanId, portNum, nextId, install);
- }
- // Remove L2IG of the port
- grpHandler.removePortNextObjective(deviceId, portNum, vlanId, pushVlan);
- } else if (install) {
- // Create L2IG of the port
- grpHandler.createPortNextObjective(deviceId, portNum, vlanId, pushVlan);
- // Create L2 Bridging rule and L3 Unicast rule to the host
- hostEventExecutor.execute(() -> hostHandler.processIntfVlanUpdatedEvent(deviceId, portNum,
- vlanId, pushVlan, install));
- if (nextId != -1) {
- // Add a single port to L2FG
- grpHandler.updateGroupFromVlanConfiguration(vlanId, portNum, nextId, install);
- } else {
- // Create L2FG for VLAN
- grpHandler.createBcastGroupFromVlan(vlanId, Collections.singleton(portNum));
- routingRulePopulator.updateSubnetBroadcastRule(deviceId, vlanId, install);
- }
- } else {
- log.warn("Failed to retrieve next objective for vlan {} in device {}:{}", vlanId, deviceId, portNum);
- }
- }
-
- private void removeSubnetConfig(ConnectPoint cp, Set<InterfaceIpAddress> ipAddressSet) {
- Set<IpPrefix> ipPrefixSet = ipAddressSet.stream().
- map(InterfaceIpAddress::subnetAddress).collect(Collectors.toSet());
-
- Set<InterfaceIpAddress> deviceIntfIpAddrs = interfaceService.getInterfaces().stream()
- .filter(intf -> intf.connectPoint().deviceId().equals(cp.deviceId()))
- .filter(intf -> !intf.connectPoint().equals(cp))
- .flatMap(intf -> intf.ipAddressesList().stream())
- .collect(Collectors.toSet());
- // 1. Partial subnet population
- // Remove routing rules for removed subnet from previous configuration,
- // which does not also exist in other interfaces in the same device
- Set<IpPrefix> deviceIpPrefixSet = deviceIntfIpAddrs.stream()
- .map(InterfaceIpAddress::subnetAddress)
- .collect(Collectors.toSet());
-
- Set<IpPrefix> subnetsToBeRevoked = ipPrefixSet.stream()
- .filter(ipPrefix -> !deviceIpPrefixSet.contains(ipPrefix))
- .collect(Collectors.toSet());
-
- // Check if any of the subnets to be revoked is configured in the pairDevice.
- // If any, repopulate the subnet with pairDevice connectPoint instead of revoking.
- Optional<DeviceId> pairDevice = getPairDeviceId(cp.deviceId());
- if (pairDevice.isPresent()) {
- Set<IpPrefix> pairDeviceIpPrefix = getDeviceSubnetMap().get(pairDevice.get());
-
- Set<IpPrefix> subnetsExistingInPairDevice = subnetsToBeRevoked.stream()
- .filter(ipPrefix -> pairDeviceIpPrefix.contains(ipPrefix))
- .collect(Collectors.toSet());
-
- // Update the subnets existing in pair device with pair device connect point.
- if (!subnetsExistingInPairDevice.isEmpty()) {
- // PortNumber of connect point is not relevant in populate subnet and hence providing as ANY.
- ConnectPoint pairDeviceCp = new ConnectPoint(pairDevice.get(), PortNumber.ANY);
- log.debug("Updating the subnets: {} with pairDevice connectPoint as it exists in the Pair device: {}",
- subnetsExistingInPairDevice, pairDeviceCp);
- defaultRoutingHandler.populateSubnet(Collections.singleton(pairDeviceCp), subnetsExistingInPairDevice);
- }
-
- // Remove only the subnets that are not configured in the pairDevice.
- subnetsToBeRevoked = Sets.difference(subnetsToBeRevoked, subnetsExistingInPairDevice);
- }
-
- if (!subnetsToBeRevoked.isEmpty()) {
- log.debug("Removing subnets for connectPoint: {}, subnets: {}", cp, subnetsToBeRevoked);
- defaultRoutingHandler.revokeSubnet(subnetsToBeRevoked);
- }
-
- // 2. Interface IP punts
- // Remove IP punts for old Intf address
- Set<IpAddress> deviceIpAddrs = deviceIntfIpAddrs.stream()
- .map(InterfaceIpAddress::ipAddress)
- .collect(Collectors.toSet());
- ipAddressSet.stream()
- .map(InterfaceIpAddress::ipAddress)
- .filter(interfaceIpAddress -> !deviceIpAddrs.contains(interfaceIpAddress))
- .forEach(interfaceIpAddress ->
- routingRulePopulator.revokeSingleIpPunts(
- cp.deviceId(), interfaceIpAddress));
-
- // 3. Host unicast routing rule
- // Remove unicast routing rule
- hostEventExecutor.execute(() -> hostHandler.processIntfIpUpdatedEvent(cp, ipPrefixSet, false));
- }
-
- private void addSubnetConfig(ConnectPoint cp, Set<InterfaceIpAddress> ipAddressSet) {
- Set<IpPrefix> ipPrefixSet = ipAddressSet.stream().
- map(InterfaceIpAddress::subnetAddress).collect(Collectors.toSet());
-
- Set<InterfaceIpAddress> deviceIntfIpAddrs = interfaceService.getInterfaces().stream()
- .filter(intf -> intf.connectPoint().deviceId().equals(cp.deviceId()))
- .filter(intf -> !intf.connectPoint().equals(cp))
- .flatMap(intf -> intf.ipAddressesList().stream())
- .collect(Collectors.toSet());
- // 1. Partial subnet population
- // Add routing rules for newly added subnet, which does not also exist in
- // other interfaces in the same device
- Set<IpPrefix> deviceIpPrefixSet = deviceIntfIpAddrs.stream()
- .map(InterfaceIpAddress::subnetAddress)
- .collect(Collectors.toSet());
- Set<IpPrefix> subnetsToBePopulated = ipPrefixSet.stream()
- .filter(ipPrefix -> !deviceIpPrefixSet.contains(ipPrefix))
- .collect(Collectors.toSet());
-
- if (!subnetsToBePopulated.isEmpty()) {
- log.debug("Adding subnets for connectPoint: {}, subnets: {}", cp, subnetsToBePopulated);
-
- // check if pair-device has the same subnet configured?
- Optional<DeviceId> pairDevice = getPairDeviceId(cp.deviceId());
- if (pairDevice.isPresent()) {
- Set<IpPrefix> pairDeviceIpPrefix = getDeviceSubnetMap().get(pairDevice.get());
-
- Set<IpPrefix> subnetsToBePopulatedAsDualHomed = subnetsToBePopulated.stream()
- .filter(ipPrefix -> pairDeviceIpPrefix.contains(ipPrefix))
- .collect(Collectors.toSet());
- Set<IpPrefix> subnetsToBePopulatedAsSingleHomed = Sets.difference(subnetsToBePopulated,
- subnetsToBePopulatedAsDualHomed);
-
- if (!subnetsToBePopulatedAsSingleHomed.isEmpty()) {
- defaultRoutingHandler.populateSubnet(
- Collections.singleton(cp),
- subnetsToBePopulatedAsSingleHomed);
- }
-
- if (!subnetsToBePopulatedAsDualHomed.isEmpty()) {
- Set<ConnectPoint> cpts = new HashSet<>();
- cpts.add(cp);
- // As Subnets is DualHomed adding the pairDevice also as ConnectPoint.
- // PortNumber of connect point is not relevant in populate subnet and hence providing as ANY.
- ConnectPoint pairCp = new ConnectPoint(pairDevice.get(), PortNumber.ANY);
- cpts.add(pairCp);
-
- log.debug("Adding DualHomed subnets for connectPoint: {} and its pair device: {}, subnets: {}",
- cp, pairCp, subnetsToBePopulatedAsDualHomed);
-
- // populating the subnets as DualHomed
- defaultRoutingHandler.populateSubnet(
- cpts,
- subnetsToBePopulated);
-
- // revoking the subnets populated in the device as it is now Dualhomed.
- defaultRoutingHandler.revokeSubnet(Collections.singleton(cp.deviceId()),
- subnetsToBePopulatedAsDualHomed);
- }
- } else {
- defaultRoutingHandler.populateSubnet(
- Collections.singleton(cp),
- subnetsToBePopulated);
- }
- }
-
- // 2. Interface IP punts
- // Add IP punts for new Intf address
- Set<IpAddress> deviceIpAddrs = deviceIntfIpAddrs.stream()
- .map(InterfaceIpAddress::ipAddress)
- .collect(Collectors.toSet());
- ipAddressSet.stream()
- .map(InterfaceIpAddress::ipAddress)
- .filter(interfaceIpAddress -> !deviceIpAddrs.contains(interfaceIpAddress))
- .forEach(interfaceIpAddress ->
- routingRulePopulator.populateSingleIpPunts(
- cp.deviceId(), interfaceIpAddress));
-
- // 3. Host unicast routing rule
- // Add unicast routing rule
- hostEventExecutor.execute(() -> hostHandler.processIntfIpUpdatedEvent(cp, ipPrefixSet, true));
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingNeighbourDispatcher.java b/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingNeighbourDispatcher.java
deleted file mode 100644
index 3cf0e32..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingNeighbourDispatcher.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2016-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;
-
-import org.onosproject.net.neighbour.NeighbourMessageContext;
-import org.onosproject.net.neighbour.NeighbourMessageHandler;
-import org.onosproject.net.host.HostService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * This handler dispatches to the appropriate handlers the
- * neighbour discovery protocols.
- */
-public class SegmentRoutingNeighbourDispatcher implements NeighbourMessageHandler {
-
- private static Logger log = LoggerFactory.getLogger(SegmentRoutingNeighbourDispatcher.class);
- private SegmentRoutingManager manager;
-
- /**
- * Create a segment routing neighbour dispatcher.
- *
- * @param segmentRoutingManager the segment routing manager
- */
- public SegmentRoutingNeighbourDispatcher(SegmentRoutingManager segmentRoutingManager) {
- this.manager = segmentRoutingManager;
- }
-
- @Override
- public void handleMessage(NeighbourMessageContext context, HostService hostService) {
- manager.neighborExecutor.execute(() -> handleMessageInternal(context, hostService));
- }
-
- private void handleMessageInternal(NeighbourMessageContext context, HostService hostService) {
- log.trace("Received {} packet on {}: {}", context.protocol(),
- context.inPort(), context.packet());
- switch (context.protocol()) {
- case ARP:
- if (this.manager.arpHandler != null) {
- this.manager.arpHandler.processPacketIn(context, hostService);
- }
- break;
- case NDP:
- if (this.manager.icmpHandler != null) {
- this.manager.icmpHandler.processPacketIn(context, hostService);
- }
- break;
- default:
- log.warn("Unknown protocol", context.protocol());
- }
- }
-
-
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingNeighbourHandler.java b/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingNeighbourHandler.java
deleted file mode 100644
index 8ef8e7e..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingNeighbourHandler.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Copyright 2016-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;
-
-import org.onlab.packet.Ethernet;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
-import org.onosproject.net.neighbour.NeighbourMessageContext;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Host;
-import org.onosproject.net.HostId;
-import org.onosproject.net.flow.DefaultTrafficTreatment;
-import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.host.HostService;
-import org.onosproject.net.packet.DefaultOutboundPacket;
-import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
-import org.onosproject.segmentrouting.config.DeviceConfiguration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.nio.ByteBuffer;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-/**
- * This handler provides provides useful functions to the
- * neighbour handlers (ARP, NDP).
- */
-public class SegmentRoutingNeighbourHandler {
-
- private static Logger log = LoggerFactory.getLogger(SegmentRoutingNeighbourHandler.class);
-
- protected SegmentRoutingManager srManager;
- protected DeviceConfiguration config;
-
- /**
- * Creates an SegmentRoutingNeighbourHandler object.
- *
- * @param srManager SegmentRoutingManager object
- */
- public SegmentRoutingNeighbourHandler(SegmentRoutingManager srManager) {
- this.srManager = srManager;
- this.config = checkNotNull(srManager.deviceConfiguration);
- }
-
- /**
- * Creates an SegmentRoutingNeighbourHandler object.
- */
- public SegmentRoutingNeighbourHandler() {
- this.srManager = null;
- this.config = null;
- }
-
- /**
- * Retrieve router (device) info.
- *
- * @param mac where to copy the mac
- * @param ip where to copy the ip
- * @param deviceId the device id
- * @param targetAddress the target address
- * @return true if it was possible to get the necessary info.
- * False for errors
- */
- protected boolean getSenderInfo(byte[] mac,
- byte[] ip,
- DeviceId deviceId,
- IpAddress targetAddress) {
- byte[] senderMacAddress;
- byte[] senderIpAddress;
- IpAddress sender;
- try {
- senderMacAddress = config.getDeviceMac(deviceId).toBytes();
- if (targetAddress.isIp4()) {
- sender = config.getRouterIpAddressForASubnetHost(targetAddress.getIp4Address());
- } else {
- sender = config.getRouterIpAddressForASubnetHost(targetAddress.getIp6Address());
- }
- // If sender is null we abort.
- if (sender == null) {
- log.warn("Sender ip is null. Aborting getSenderInfo");
- return false;
- }
- senderIpAddress = sender.toOctets();
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage() + " Aborting getSenderInfo");
- return false;
- }
- System.arraycopy(senderMacAddress, 0, mac, 0, senderMacAddress.length);
- System.arraycopy(senderIpAddress, 0, ip, 0, senderIpAddress.length);
- return true;
- }
-
- /**
- * Reads the boolean configuration for responding to unknown hosts.
- *
- * @return respondToUnknownHosts boolean.
- */
- protected boolean respondToUnknownHosts() {
- return srManager.respondToUnknownHosts;
- }
-
- /**
- * Utility to send a ND reply using the supplied information.
- *
- * @param pkt the request
- * @param targetMac the target mac
- * @param hostService the host service
- * @param isRouter true if this reply is sent on behalf of a router
- */
- protected void sendResponse(NeighbourMessageContext pkt, MacAddress targetMac, HostService hostService,
- boolean isRouter) {
- // if this is false, check if host exists in the store
- if (!respondToUnknownHosts()) {
- short vlanId = pkt.packet().getQinQVID();
- HostId dstId = HostId.hostId(pkt.srcMac(), vlanId == Ethernet.VLAN_UNTAGGED
- ? pkt.vlan() : VlanId.vlanId(vlanId));
- Host dst = hostService.getHost(dstId);
- if (dst == null) {
- log.warn("Cannot send {} response to host {} - does not exist in the store",
- pkt.protocol(), dstId);
- return;
- }
- }
- pkt.setIsRouter(isRouter);
- pkt.reply(targetMac);
- }
-
- /**
- * Flood to all ports in the same subnet.
- *
- * @param packet packet to be flooded
- * @param inPort where the packet comes from
- * @param targetAddress the target address
- */
- protected void flood(Ethernet packet, ConnectPoint inPort, IpAddress targetAddress) {
- try {
- srManager.deviceConfiguration
- .getSubnetPortsMap(inPort.deviceId()).forEach((subnet, ports) -> {
- if (subnet.contains(targetAddress)) {
- ports.stream()
- .filter(port -> port != inPort.port())
- .forEach(port -> {
- forward(packet, new ConnectPoint(inPort.deviceId(), port));
- });
- }
- });
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage()
- + " Cannot flood in subnet as device config not available"
- + " for device: " + inPort.deviceId());
- }
- }
-
- /*
- * Floods only on the port which have been configured with the subnet
- * of the target address. The in port is excluded.
- *
- * @param pkt the ndp/arp packet and context information
- */
- protected void flood(NeighbourMessageContext pkt) {
- try {
- srManager.deviceConfiguration
- .getSubnetPortsMap(pkt.inPort().deviceId()).forEach((subnet, ports) -> {
- if (subnet.contains(pkt.target())) {
- ports.stream()
- .filter(port -> port != pkt.inPort().port())
- .forEach(port -> {
- ConnectPoint outPoint = new ConnectPoint(
- pkt.inPort().deviceId(),
- port
- );
- pkt.forward(outPoint);
- });
- }
- });
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage()
- + " Cannot flood in subnet as device config not available"
- + " for device: " + pkt.inPort().deviceId());
- }
- }
-
- /**
- * Packet out to given port.
- *
- * Note: In current implementation, we expect all communication with
- * end hosts within a subnet to be untagged.
- * <p>
- * For those pipelines that internally assigns a VLAN, the VLAN tag will be
- * removed before egress.
- * <p>
- * For those pipelines that do not assign internal VLAN, the packet remains
- * untagged.
- *
- * @param packet packet to be forwarded
- * @param outPort where the packet should be forwarded
- */
- private void forward(Ethernet packet, ConnectPoint outPort) {
- ByteBuffer buf = ByteBuffer.wrap(packet.serialize());
-
- TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
- tbuilder.setOutput(outPort.port());
- srManager.packetService.emit(new DefaultOutboundPacket(outPort.deviceId(),
- tbuilder.build(), buf));
- }
-
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingService.java b/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingService.java
deleted file mode 100644
index 3bfd88b..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingService.java
+++ /dev/null
@@ -1,439 +0,0 @@
-/*
- * Copyright 2015-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;
-
-import com.google.common.collect.Multimap;
-import org.apache.commons.lang3.NotImplementedException;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.VlanId;
-import org.onosproject.cluster.NodeId;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Link;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.flowobjective.NextObjective;
-import org.onosproject.segmentrouting.grouphandler.NextNeighbors;
-import org.onosproject.segmentrouting.mcast.McastFilteringObjStoreKey;
-import org.onosproject.segmentrouting.mcast.McastRole;
-import org.onosproject.segmentrouting.mcast.McastRoleStoreKey;
-import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelDescription;
-import org.onosproject.segmentrouting.pwaas.L2Tunnel;
-import org.onosproject.segmentrouting.pwaas.L2TunnelHandler;
-import org.onosproject.segmentrouting.pwaas.L2TunnelPolicy;
-import org.onosproject.segmentrouting.pwaas.L2TunnelDescription;
-import org.onosproject.segmentrouting.storekey.DestinationSetNextObjectiveStoreKey;
-
-import com.google.common.collect.ImmutableMap;
-import org.onosproject.segmentrouting.mcast.McastStoreKey;
-import org.onosproject.segmentrouting.storekey.PortNextObjectiveStoreKey;
-import org.onosproject.segmentrouting.storekey.VlanNextObjectiveStoreKey;
-import org.onosproject.segmentrouting.storekey.MacVlanNextObjectiveStoreKey;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-
-/**
- * Segment Routing Service for REST API.
- */
-public interface SegmentRoutingService {
- /**
- * VLAN cross-connect ACL priority.
- *
- * @deprecated in ONOS 1.12. Replaced by {@link org.onosproject.segmentrouting.xconnect.api.XconnectService}
- */
- @Deprecated
- int XCONNECT_ACL_PRIORITY = 60000;
-
- /**
- * VLAN cross-connect Bridging priority.
- *
- * @deprecated in ONOS 1.12. Replaced by {@link org.onosproject.segmentrouting.xconnect.api.XconnectService}
- */
- @Deprecated
- int XCONNECT_PRIORITY = 1000;
-
- /**
- * Default flow priority.
- */
- int DEFAULT_PRIORITY = 100;
-
- /**
- * Minimum IP priority.
- *
- * Should < 0 such that priority of /0 will not conflict with lowest
- * priority default entries.
- */
- int MIN_IP_PRIORITY = 10;
-
- /**
- * Subnet flooding flow priority.
- */
- int FLOOD_PRIORITY = 5;
-
- /**
- * Returns all tunnels.
- *
- * @return list of tunnels
- */
- List<Tunnel> getTunnels();
-
- /**
- * Creates a tunnel.
- *
- * @param tunnel tunnel reference to create
- * @return WRONG_PATH if the tunnel path is wrong, ID_EXISTS if the tunnel ID
- * exists already, TUNNEL_EXISTS if the same tunnel exists, INTERNAL_ERROR
- * if the tunnel creation failed internally, SUCCESS if the tunnel is created
- * successfully
- */
- TunnelHandler.Result createTunnel(Tunnel tunnel);
-
- /**
- * Returns all policies.
- *
- * @return list of policy
- */
- List<Policy> getPolicies();
-
- /**
- * Returns the l2 tunnel descriptions.
- *
- * @param pending if true fetch pending pseudowires, else fetch installed
- * @return set of l2 tunnel descriptions.
- */
- Set<L2TunnelDescription> getL2TunnelDescriptions(boolean pending);
-
- /**
- * Returns all l2 tunnels of pseudowires.
- *
- * @return list of l2 tunnels
- */
- List<L2Tunnel> getL2Tunnels();
-
- /**
- * Returns all l2 policie of pseudowires.
- *
- * @return list of l2 policies.
- */
- List<L2TunnelPolicy> getL2Policies();
-
- /**
- * Removes pseudowire.
- *
- * @param pwId The id of the pseudowire.
- * @return SUCCESS if operation successful or a descriptive error otherwise.
- */
- L2TunnelHandler.Result removePseudowire(Integer pwId);
-
- /**
- * Adds a Pseudowire to the system.
- *
- * @param tunnel The pseudowire tunnel.
- * @return SUCCESS if operation is successful or a descriptive error otherwise.
- */
- L2TunnelHandler.Result addPseudowire(L2TunnelDescription tunnel);
-
- /**
- * Adds a set of pseudowires.
- *
- *
- * @param l2TunnelDescriptions The pseudowires to add.
- * @return SUCCESS if ALL pseudowires can be instantiated and are deployed, or a
- * a descriptive error otherwise, without deploying any pseudowire.
- * @deprecated onos-1.12 use addPseudowire instead
- */
- @Deprecated
- L2TunnelHandler.Result addPseudowiresBulk(List<DefaultL2TunnelDescription> l2TunnelDescriptions);
-
- /**
- * Creates a policy.
- *
- * @param policy policy reference to create
- * @return ID_EXISTS if the same policy ID exists,
- * POLICY_EXISTS if the same policy exists, TUNNEL_NOT_FOUND if the tunnel
- * does not exists, UNSUPPORTED_TYPE if the policy type is not supported,
- * SUCCESS if the policy is created successfully.
- */
- PolicyHandler.Result createPolicy(Policy policy);
-
- /**
- * Removes a tunnel.
- *
- * @param tunnel tunnel reference to remove
- * @return TUNNEL_NOT_FOUND if the tunnel to remove does not exists,
- * INTERNAL_ERROR if the tunnel creation failed internally, SUCCESS
- * if the tunnel is created successfully.
- */
- TunnelHandler.Result removeTunnel(Tunnel tunnel);
-
- /**
- * Removes a policy.
- *
- * @param policy policy reference to remove
- * @return POLICY_NOT_FOUND if the policy to remove does not exists,
- * SUCCESS if it is removed successfully
- */
- PolicyHandler.Result removePolicy(Policy policy);
-
- /**
- * Use current state of the network to repopulate forwarding rules.
- *
- */
- void rerouteNetwork();
-
- /**
- * Returns device-subnet mapping.
- *
- * @return device-subnet mapping
- */
- Map<DeviceId, Set<IpPrefix>> getDeviceSubnetMap();
-
- /**
- * Returns the current ECMP shortest path graph in this controller instance.
- *
- * @return ECMP shortest path graph
- */
- ImmutableMap<DeviceId, EcmpShortestPathGraph> getCurrentEcmpSpg();
-
- /**
- * Returns the destinatiomSet-NextObjective store contents.
- *
- * @return current contents of the dstNextObjStore
- */
- ImmutableMap<DestinationSetNextObjectiveStoreKey, NextNeighbors> getDstNextObjStore();
-
- /**
- * Returns the VLAN next objective store.
- *
- * @return current contents of the vlanNextObjStore
- */
- ImmutableMap<VlanNextObjectiveStoreKey, Integer> getVlanNextObjStore();
-
- /**
- * Returns the Mac Vlan next objective store.
- *
- * @return current contents of the macVlanNextObjStore
- */
- ImmutableMap<MacVlanNextObjectiveStoreKey, Integer> getMacVlanNextObjStore();
-
- /**
- * Returns the port next objective store.
- *
- * @return current contents of the portNextObjStore
- */
- ImmutableMap<PortNextObjectiveStoreKey, Integer> getPortNextObjStore();
-
- /**
- * Returns the associated next ids to the mcast groups or to the single
- * group if mcastIp is present.
- *
- * @param mcastIp the group ip
- * @return the mapping mcastIp-device to next id
- */
- Map<McastStoreKey, Integer> getMcastNextIds(IpAddress mcastIp);
-
- /**
- * Returns the PW init next objective store.
- *
- * @return current contents of the l2InitiationNextObjStore
- */
- ImmutableMap<String, NextObjective> getPwInitNext();
-
- /**
- * Returns the PW termination next objective store.
- *
- * @return current contents of the l2TerminationNextObjStore
- */
- ImmutableMap<String, NextObjective> getPwTermNext();
-
- /**
- * Removes all entries in dst/vlan/port/mcast NextObjectiveStore that are associated with the given nextId.
- *
- * @param nextId nextId
- */
- void invalidateNextObj(int nextId);
-
- /**
- * Triggers the verification of all ECMP groups in the specified device.
- * Adjusts the group buckets if verification finds that there are more or less
- * buckets than what should be there.
- *
- * @param id the device identifier
- */
- void verifyGroups(DeviceId id);
-
- /**
- * Returns the internal link state as seen by this instance of the
- * controller.
- *
- * @return the internal link state
- */
- ImmutableMap<Link, Boolean> getSeenLinks();
-
- /**
- * Returns the ports administratively disabled by the controller.
- *
- * @return a map of devices and port numbers for administratively disabled
- * ports. Does not include ports manually disabled by the operator.
- */
- ImmutableMap<DeviceId, Set<PortNumber>> getDownedPortState();
-
- /**
- * Returns the associated roles to the mcast groups.
- *
- * @param mcastIp the group ip
- * @param sourcecp the source connect point
- * @return the mapping mcastIp-device to mcast role
- */
- Map<McastRoleStoreKey, McastRole> getMcastRoles(IpAddress mcastIp,
- ConnectPoint sourcecp);
-
- /**
- * Returns the associated trees to the mcast group.
- *
- * @param mcastIp the group ip
- * @param sourcecp the source connect point
- * @return the mapping egress point to mcast path
- */
- Multimap<ConnectPoint, List<ConnectPoint>> getMcastTrees(IpAddress mcastIp,
- ConnectPoint sourcecp);
-
- /**
- * Return the leaders of the mcast groups.
- *
- * @param mcastIp the group ip
- * @return the mapping group-node
- */
- Map<IpAddress, NodeId> getMcastLeaders(IpAddress mcastIp);
-
- /**
- * Returns shouldProgram map.
- *
- * @return shouldProgram map
- */
- Map<Set<DeviceId>, NodeId> getShouldProgram();
-
- /**
- * Returns shouldProgram local cache.
- *
- * @return shouldProgram local cache
- */
- Map<DeviceId, Boolean> getShouldProgramCache();
-
- /**
- * Returns whether instance should program device or not.
- *
- * @param deviceId .
- * @return boolean status saying instance should program device or not.
- */
- boolean shouldProgram(DeviceId deviceId);
-
- /**
- * Returns the mcast filtering obj.
- *
- * @return the mapping group-node
- */
- Map<DeviceId, List<McastFilteringObjStoreKey>> getMcastFilters();
-
- /**
- * Determines if routing in the network has been stable in the last
- * STABILITY_THRESHOLD seconds, by comparing the current time to the last
- * routing change timestamp.
- *
- * @return true if stable
- */
- boolean isRoutingStable();
-
- /**
- * Invoke hostHandler.init() for given device.
- *
- * @param deviceId device ID
- */
- void initHost(DeviceId deviceId);
-
- /**
- * Invoke routeHandler.init() for given device.
- *
- * @param deviceId device ID
- */
- void initRoute(DeviceId deviceId);
-
- /**
- * Gets application id.
- *
- * @return application id
- */
- default ApplicationId appId() {
- throw new NotImplementedException("appId not implemented");
- }
-
- /**
- * Returns internal VLAN for untagged hosts on given connect point.
- * <p>
- * The internal VLAN is either vlan-untagged for an access port,
- * or vlan-native for a trunk port.
- *
- * @param connectPoint connect point
- * @return internal VLAN or null if both vlan-untagged and vlan-native are undefined
- */
- default VlanId getInternalVlanId(ConnectPoint connectPoint) {
- throw new NotImplementedException("getInternalVlanId not implemented");
- }
-
- /**
- * Returns optional pair device ID of given device.
- *
- * @param deviceId device ID
- * @return optional pair device ID. Might be empty if pair device is not configured
- */
- default Optional<DeviceId> getPairDeviceId(DeviceId deviceId) {
- throw new NotImplementedException("getPairDeviceId not implemented");
- }
-
- /**
- * Returns optional pair device local port of given device.
- *
- * @param deviceId device ID
- * @return optional pair device ID. Might be empty if pair device is not configured
- */
- default Optional<PortNumber> getPairLocalPort(DeviceId deviceId) {
- throw new NotImplementedException("getPairLocalPort not implemented");
- }
-
- /**
- * Returns a set of infrastructure ports on the given device.
- *
- * @param deviceId device ID
- * @return a set of ports that does not have interface configuration
- */
- default Set<PortNumber> getInfraPorts(DeviceId deviceId) {
- throw new NotImplementedException("getInfraPorts not implemented");
- }
-
- /**
- * Returns a set of edge ports on the given device.
- *
- * @param deviceId device ID
- * @return a set of ports that has interface configuration
- */
- default Set<PortNumber> getEdgePorts(DeviceId deviceId) {
- throw new NotImplementedException("getEdgePorts not implemented");
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/TopologyHandler.java b/app/src/main/java/org/onosproject/segmentrouting/TopologyHandler.java
deleted file mode 100644
index 72b1a70..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/TopologyHandler.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright 2018-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;
-
-import com.google.common.collect.Maps;
-import org.onosproject.event.Event;
-import org.onosproject.net.Device;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Link;
-import org.onosproject.net.device.DeviceEvent;
-import org.onosproject.net.link.LinkEvent;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-/**
- * Handler for topology events.
- */
-class TopologyHandler {
-
- // Logging instance
- private static final Logger log = LoggerFactory.getLogger(TopologyHandler.class);
- // Internal reference for SR manager and its services
- private final SegmentRoutingManager srManager;
-
- /**
- * Constructs the TopologyHandler.
- *
- * @param srManager Segment Routing manager
- */
- TopologyHandler(SegmentRoutingManager srManager) {
- this.srManager = srManager;
- }
-
- // Check if the link event is valid
- private boolean isValid(LinkEvent linkEvent) {
- Link link = linkEvent.subject();
- // Verify if the link is valid with the link handler
- if (!srManager.linkHandler.isLinkValid(link)) {
- log.debug("Link {} ignored by the LinkHandler", link);
- return false;
- }
- // Processing for LINK_REMOVED
- if (linkEvent.type() == LinkEvent.Type.LINK_REMOVED) {
- // device availability check helps to ensure that multiple link-removed
- // events are actually treated as a single switch removed event.
- // purgeSeenLink is necessary so we do rerouting (instead of rehashing)
- // when switch comes back.
- if (link.src().elementId() instanceof DeviceId
- && !srManager.deviceService.isAvailable(link.src().deviceId())) {
- log.debug("Link {} ignored device {} is down", link, link.src().deviceId());
- return false;
- }
- if (link.dst().elementId() instanceof DeviceId
- && !srManager.deviceService.isAvailable(link.dst().deviceId())) {
- log.debug("Link {} ignored device {} is down", link, link.dst().deviceId());
- return false;
- }
- // LINK_REMOVED is ok
- return true;
- }
- // Processing for LINK_ADDED and LINK_UPDATED
- // Verify if source device is configured
- if (srManager.deviceConfiguration == null ||
- !srManager.deviceConfiguration.isConfigured(link.src().deviceId())) {
- // Source device is not configured, not valid for us
- log.warn("Source device of this link is not configured.. "
- + "not processing further");
- return false;
- }
- // LINK_ADDED/LINK_UPDATED is ok
- return true;
- }
-
- // Check if the device event is valid
- private boolean isValid(DeviceEvent deviceEvent) {
- Device device = deviceEvent.subject();
- // We don't process the event if the device is available
- return !srManager.deviceService.isAvailable(device.id());
- }
-
- /**
- * Process the TOPOLOGY_CHANGE event. An initial optimization
- * is performed to avoid the processing of not relevant events.
- *
- * @param reasons list of events that triggered topology change
- */
- void processTopologyChange(List<Event> reasons) {
- // Store temporary in the map all the link events,
- // events having the same subject will be automatically
- // overridden.
- Map<Link, LinkEvent> linkEvents = Maps.newHashMap();
- // Store temporary in the map all the device events,
- // events having the same subject will be automatically
- // overridden.
- Map<DeviceId, DeviceEvent> deviceEvents = Maps.newHashMap();
- // Pre-process all the events putting them in the right map
- reasons.forEach(reason -> {
- // Relevant events for devices
- if (reason.type() == DeviceEvent.Type.DEVICE_ADDED ||
- reason.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
- reason.type() == DeviceEvent.Type.DEVICE_UPDATED) {
- // Take the event and save in the map
- DeviceEvent deviceEvent = (DeviceEvent) reason;
- deviceEvents.put(deviceEvent.subject().id(), deviceEvent);
- /// Relevant events for links
- } else if (reason.type() == LinkEvent.Type.LINK_ADDED ||
- reason.type() == LinkEvent.Type.LINK_UPDATED ||
- reason.type() == LinkEvent.Type.LINK_REMOVED) {
- // Take the event and store the link in the map
- LinkEvent linkEvent = (LinkEvent) reason;
- linkEvents.put(linkEvent.subject(), linkEvent);
- // Other events are not relevant
- } else {
- log.debug("Unhandled event type: {}", reason.type());
- }
- });
- // Verify if the link events are valid
- // before sent for mcast handling
- List<LinkEvent> toProcessLinkEvent = linkEvents.values()
- .stream()
- .filter(this::isValid)
- .collect(Collectors.toList());
- // Verify if the device events are valid
- // before sent for mcast handling
- List<DeviceEvent> toProcessDeviceEvent = deviceEvents.values()
- .stream()
- .filter(this::isValid)
- .collect(Collectors.toList());
-
- // Processing part of the received events
- // We don't need to process all LINK_ADDED
- boolean isLinkAdded = false;
- // Iterate on link events
- for (LinkEvent linkEvent : toProcessLinkEvent) {
- // We process just the first one
- if (linkEvent.type() == LinkEvent.Type.LINK_ADDED ||
- linkEvent.type() == LinkEvent.Type.LINK_UPDATED) {
- // Other ones are skipped
- if (isLinkAdded) {
- continue;
- }
- log.info("Processing - Event: {}", linkEvent);
- // First time, let's process it
- isLinkAdded = true;
- // McastHandler, reroute all the mcast tree
- srManager.mcastHandler.init();
- } else {
- log.info("Processing - Event: {}", linkEvent);
- // We compute each time a LINK_DOWN event
- srManager.mcastHandler.processLinkDown(linkEvent.subject());
- }
- }
- // Process all the device events
- toProcessDeviceEvent.forEach(deviceEvent -> {
- log.info("Processing - Event: {}", deviceEvent);
- srManager.mcastHandler.processDeviceDown(deviceEvent.subject().id());
- });
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/Tunnel.java b/app/src/main/java/org/onosproject/segmentrouting/Tunnel.java
deleted file mode 100644
index 470662f..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/Tunnel.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2015-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;
-
-import java.util.List;
-
-/**
- * Tunnel interface.
- */
-public interface Tunnel {
-
- /**
- * Returns the tunnel ID.
- *
- * @return tunnel ID
- */
- String id();
-
- /**
- * Returns Segment IDs for the tunnel including source and destination.
- *
- * @return List of Node ID
- */
- List<Integer> labelIds();
-
- /**
- * Returns the group ID for the tunnel.
- *
- * @return group ID
- */
- int groupId();
-
- /**
- * Sets group ID for the tunnel.
- *
- * @param groupId group identifier
- */
- void setGroupId(int groupId);
-
- /**
- * Sets the flag to allow to remove the group or not.
- *
- * @param ok the flag; true - allow to remove
- */
- void allowToRemoveGroup(boolean ok);
-
- /**
- * Checks if it is allowed to remove the group for the tunnel.
- *
- * @return true if allowed, false otherwise
- */
- boolean isAllowedToRemoveGroup();
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/TunnelHandler.java b/app/src/main/java/org/onosproject/segmentrouting/TunnelHandler.java
deleted file mode 100644
index 7031507..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/TunnelHandler.java
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright 2015-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;
-
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Link;
-import org.onosproject.net.link.LinkService;
-import org.onosproject.segmentrouting.config.DeviceConfiguration;
-import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
-import org.onosproject.segmentrouting.grouphandler.DestinationSet;
-import org.onosproject.store.service.EventuallyConsistentMap;
-import org.slf4j.Logger;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import static org.slf4j.LoggerFactory.getLogger;
-
-/**
- * Tunnel Handler.
- */
-public class TunnelHandler {
- protected final Logger log = getLogger(getClass());
-
- private final DeviceConfiguration config;
- private final EventuallyConsistentMap<String, Tunnel> tunnelStore;
- private Map<DeviceId, DefaultGroupHandler> groupHandlerMap;
- private LinkService linkService;
-
- /**
- * Result of tunnel creation or removal.
- */
- public enum Result {
- /**
- * Success.
- */
- SUCCESS,
-
- /**
- * More than one router needs to specified to created a tunnel.
- */
- WRONG_PATH,
-
- /**
- * The same tunnel exists already.
- */
- TUNNEL_EXISTS,
-
- /**
- * The same tunnel ID exists already.
- */
- ID_EXISTS,
-
- /**
- * Tunnel not found.
- */
- TUNNEL_NOT_FOUND,
-
- /**
- * Cannot remove the tunnel used by a policy.
- */
- TUNNEL_IN_USE,
-
- /**
- * Failed to create/remove groups for the tunnel.
- */
- INTERNAL_ERROR
- }
-
- /**
- * Constructs tunnel handler.
- *
- * @param linkService link service
- * @param deviceConfiguration device configuration
- * @param groupHandlerMap group handler map
- * @param tunnelStore tunnel store
- */
- public TunnelHandler(LinkService linkService,
- DeviceConfiguration deviceConfiguration,
- Map<DeviceId, DefaultGroupHandler> groupHandlerMap,
- EventuallyConsistentMap<String, Tunnel> tunnelStore) {
- this.linkService = linkService;
- this.config = deviceConfiguration;
- this.groupHandlerMap = groupHandlerMap;
- this.tunnelStore = tunnelStore;
- }
-
- /**
- * Creates a tunnel.
- *
- * @param tunnel tunnel reference to create a tunnel
- * @return WRONG_PATH if the tunnel path is wrong, ID_EXISTS if the tunnel ID
- * exists already, TUNNEL_EXISTS if the same tunnel exists, INTERNAL_ERROR
- * if the tunnel creation failed internally, SUCCESS if the tunnel is created
- * successfully
- */
- public Result createTunnel(Tunnel tunnel) {
-
- if (tunnel.labelIds().isEmpty() || tunnel.labelIds().size() < 3) {
- log.error("More than one router needs to specified to created a tunnel");
- return Result.WRONG_PATH;
- }
-
- if (tunnelStore.containsKey(tunnel.id())) {
- log.warn("The same tunnel ID exists already");
- return Result.ID_EXISTS;
- }
-
- if (tunnelStore.containsValue(tunnel)) {
- log.warn("The same tunnel exists already");
- return Result.TUNNEL_EXISTS;
- }
-
- int groupId = createGroupsForTunnel(tunnel);
- if (groupId < 0) {
- log.error("Failed to create groups for the tunnel");
- return Result.INTERNAL_ERROR;
- }
-
- tunnel.setGroupId(groupId);
- tunnelStore.put(tunnel.id(), tunnel);
-
- return Result.SUCCESS;
- }
-
- /**
- * Removes the tunnel with the tunnel ID given.
- *
- * @param tunnelInfo tunnel information to delete tunnels
- * @return TUNNEL_NOT_FOUND if the tunnel to remove does not exists,
- * INTERNAL_ERROR if the tunnel creation failed internally, SUCCESS
- * if the tunnel is created successfully.
- */
- public Result removeTunnel(Tunnel tunnelInfo) {
-
- Tunnel tunnel = tunnelStore.get(tunnelInfo.id());
- if (tunnel != null) {
- DeviceId deviceId = config.getDeviceId(tunnel.labelIds().get(0));
- if (tunnel.isAllowedToRemoveGroup()) {
- if (groupHandlerMap.get(deviceId).removeGroup(tunnel.groupId())) {
- tunnelStore.remove(tunnel.id());
- } else {
- log.error("Failed to remove the tunnel {}", tunnelInfo.id());
- return Result.INTERNAL_ERROR;
- }
- } else {
- log.debug("The group is not removed because it is being used.");
- tunnelStore.remove(tunnel.id());
- }
- } else {
- log.error("No tunnel found for tunnel ID {}", tunnelInfo.id());
- return Result.TUNNEL_NOT_FOUND;
- }
-
- return Result.SUCCESS;
- }
-
- /**
- * Returns the tunnel with the tunnel ID given.
- *
- * @param tid Tunnel ID
- * @return Tunnel reference
- */
- public Tunnel getTunnel(String tid) {
- return tunnelStore.get(tid);
- }
-
- /**
- * Returns all tunnels.
- *
- * @return list of Tunnels
- */
- public List<Tunnel> getTunnels() {
- List<Tunnel> tunnels = new ArrayList<>();
- tunnelStore.values().forEach(tunnel -> tunnels.add(
- new DefaultTunnel((DefaultTunnel) tunnel)));
-
- return tunnels;
- }
-
- private int createGroupsForTunnel(Tunnel tunnel) {
-
- Set<Integer> portNumbers;
- final int groupError = -1;
-
- DeviceId deviceId = config.getDeviceId(tunnel.labelIds().get(0));
- if (deviceId == null) {
- log.warn("No device found for SID {}", tunnel.labelIds().get(0));
- return groupError;
- } else if (groupHandlerMap.get(deviceId) == null) {
- log.warn("group handler not found for {}", deviceId);
- return groupError;
- }
- Set<DeviceId> deviceIds = new HashSet<>();
- int sid = tunnel.labelIds().get(1);
- if (config.isAdjacencySid(deviceId, sid)) {
- portNumbers = config.getPortsForAdjacencySid(deviceId, sid);
- for (Link link: linkService.getDeviceEgressLinks(deviceId)) {
- for (Integer port: portNumbers) {
- if (link.src().port().toLong() == port) {
- deviceIds.add(link.dst().deviceId());
- }
- }
- }
- } else {
- deviceIds.add(config.getDeviceId(sid));
- }
- // For these NeighborSet isMpls is meaningless.
- // TODO : Revisit this, the code and also the type
- DestinationSet ns = DestinationSet.createTypePushBos(
- tunnel.labelIds().get(2),
- DeviceId.NONE);
-
- // If the tunnel reuses any existing groups, then tunnel handler
- // should not remove the group.
- if (groupHandlerMap.get(deviceId).hasNextObjectiveId(ns)) {
- tunnel.allowToRemoveGroup(false);
- } else {
- tunnel.allowToRemoveGroup(true);
- }
-
- return groupHandlerMap.get(deviceId).getNextObjectiveId(ns, null, null, true);
- }
-
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/TunnelPolicy.java b/app/src/main/java/org/onosproject/segmentrouting/TunnelPolicy.java
deleted file mode 100644
index 5df82af..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/TunnelPolicy.java
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * Copyright 2015-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;
-
-import java.util.Objects;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-/**
- * Tunnel Policy.
- */
-public final class TunnelPolicy implements Policy {
-
- private final Type type;
- private final String id;
- private final int priority;
- private final String tunnelId;
- private String dstIp;
- private String srcIp;
- private String ipProto;
- private short srcPort;
- private short dstPort;
-
- private TunnelPolicy(String policyId, Type type, int priority, String tunnelId, String srcIp,
- String dstIp, String ipProto, short srcPort, short dstPort) {
- this.id = checkNotNull(policyId);
- this.type = type;
- this.tunnelId = tunnelId;
- this.priority = priority;
- this.dstIp = dstIp;
- this.srcIp = srcIp;
- this.ipProto = ipProto;
- this.srcPort = srcPort;
- this.dstPort = dstPort;
-
- }
-
- /**
- * Creates a TunnelPolicy reference.
- *
- * @param p TunnelPolicy reference
- */
- public TunnelPolicy(TunnelPolicy p) {
- this.id = p.id;
- this.type = p.type;
- this.tunnelId = p.tunnelId;
- this.priority = p.priority;
- this.srcIp = p.srcIp;
- this.dstIp = p.dstIp;
- this.ipProto = p.ipProto;
- this.srcPort = p.srcPort;
- this.dstPort = p.dstPort;
- }
-
- /**
- * Returns the TunnelPolicy builder reference.
- *
- * @return TunnelPolicy builder
- */
- public static TunnelPolicy.Builder builder() {
- return new Builder();
- }
-
- @Override
- public String id() {
- return this.id;
- }
-
- @Override
- public int priority() {
- return priority;
- }
-
- @Override
- public Type type() {
- return type;
- }
-
- @Override
- public String srcIp() {
- return srcIp;
- }
-
- @Override
- public String dstIp() {
- return dstIp;
- }
-
- @Override
- public String ipProto() {
- return ipProto;
- }
-
- @Override
- public short srcPort() {
- return srcPort;
- }
-
- @Override
- public short dstPort() {
- return dstPort;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
-
- if (o instanceof TunnelPolicy) {
- TunnelPolicy that = (TunnelPolicy) o;
- // We do not compare the policy ID
- if (this.type.equals(that.type) &&
- this.tunnelId.equals(that.tunnelId) &&
- this.priority == that.priority &&
- this.srcIp.equals(that.srcIp) &&
- this.dstIp.equals(that.dstIp) &&
- this.srcPort == that.srcPort &&
- this.dstPort == that.dstPort &&
- this.ipProto.equals(that.ipProto)) {
- return true;
- }
- }
-
- return false;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(type, tunnelId, srcIp, dstIp, ipProto,
- srcPort, dstPort, priority);
- }
-
- /**
- * Returns the tunnel ID of the policy.
- *
- * @return Tunnel ID
- */
- public String tunnelId() {
- return this.tunnelId;
- }
-
-
- /**
- * Tunnel Policy Builder.
- */
- public static final class Builder {
-
- private String id;
- private Type type;
- private int priority;
- private String tunnelId;
- private String dstIp;
- private String srcIp;
- private String ipProto;
- private short srcPort;
- private short dstPort;
-
- /**
- * Sets the policy Id.
- *
- * @param id policy Id
- * @return Builder object
- */
- public Builder setPolicyId(String id) {
- this.id = id;
-
- return this;
- }
-
- /**
- * Sets the policy type.
- *
- * @param type policy type
- * @return Builder object
- */
- public Builder setType(Type type) {
- this.type = type;
-
- return this;
- }
-
- /**
- * Sets the source IP address.
- *
- * @param srcIp source IP address
- * @return Builder object
- */
- public Builder setSrcIp(String srcIp) {
- this.srcIp = srcIp;
-
- return this;
- }
-
- /**
- * Sets the destination IP address.
- *
- * @param dstIp destination IP address
- * @return Builder object
- */
- public Builder setDstIp(String dstIp) {
- this.dstIp = dstIp;
-
- return this;
- }
-
- /**
- * Sets the IP protocol.
- *
- * @param proto IP protocol
- * @return Builder object
- */
- public Builder setIpProto(String proto) {
- this.ipProto = proto;
-
- return this;
- }
-
- /**
- * Sets the source port.
- *
- * @param srcPort source port
- * @return Builder object
- */
- public Builder setSrcPort(short srcPort) {
- this.srcPort = srcPort;
-
- return this;
- }
-
- /**
- * Sets the destination port.
- *
- * @param dstPort destination port
- * @return Builder object
- */
- public Builder setDstPort(short dstPort) {
- this.dstPort = dstPort;
-
- return this;
- }
-
- /**
- * Sets the priority of the policy.
- *
- * @param p priority
- * @return Builder object
- */
- public Builder setPriority(int p) {
- this.priority = p;
-
- return this;
- }
-
- /**
- * Sets the tunnel Id.
- *
- * @param tunnelId tunnel Id
- * @return Builder object
- */
- public Builder setTunnelId(String tunnelId) {
- this.tunnelId = tunnelId;
-
- return this;
- }
-
- /**
- * Builds the policy.
- *
- * @return Tunnel Policy reference
- */
- public Policy build() {
- return new TunnelPolicy(id, type, priority, tunnelId, srcIp, dstIp,
- ipProto, srcPort, dstPort);
- }
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/BlackHoleCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/BlackHoleCommand.java
deleted file mode 100644
index c45ff8e..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/BlackHoleCommand.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2018-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.cli;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.common.collect.Sets;
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onlab.packet.IpPrefix;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.net.config.NetworkConfigService;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
-
-import java.util.Set;
-
-/**
- * CLI command for managing black hole routes.
- */
-@Service
-@Command(scope = "onos", name = "sr-blackhole",
- description = "Manage black hole routes")
-public class BlackHoleCommand extends AbstractShellCommand {
- @Argument(index = 0, name = "op",
- description = "list, add or remove",
- required = true, multiValued = false)
- private String op;
-
- @Argument(index = 1, name = "prefix",
- description = "IP prefix",
- required = false, multiValued = false)
- private String prefix;
-
- @Override
- protected void doExecute() {
- SegmentRoutingService srService = AbstractShellCommand.get(SegmentRoutingService.class);
- NetworkConfigService netcfgService = AbstractShellCommand.get(NetworkConfigService.class);
-
- SegmentRoutingAppConfig appConfig = netcfgService.getConfig(srService.appId(), SegmentRoutingAppConfig.class);
- if (appConfig == null) {
- JsonNode jsonNode = new ObjectMapper().createObjectNode();
- netcfgService.applyConfig(srService.appId(), SegmentRoutingAppConfig.class, jsonNode);
- appConfig = netcfgService.getConfig(srService.appId(), SegmentRoutingAppConfig.class);
- }
-
- Set<IpPrefix> blackHoleIps;
- switch (op) {
- case "list":
- appConfig.blackholeIPs().forEach(prefix -> print(prefix.toString()));
- break;
- case "add":
- blackHoleIps = Sets.newConcurrentHashSet(appConfig.blackholeIPs());
- blackHoleIps.add(IpPrefix.valueOf(prefix));
- appConfig.setBalckholeIps(blackHoleIps);
- break;
- case "remove":
- blackHoleIps = Sets.newConcurrentHashSet(appConfig.blackholeIPs());
- blackHoleIps.remove(IpPrefix.valueOf(prefix));
- appConfig.setBalckholeIps(blackHoleIps);
- break;
- default:
- throw new UnsupportedOperationException("Unknown operation " + op);
- }
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/DeviceSubnetListCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/DeviceSubnetListCommand.java
deleted file mode 100644
index 8f706b0..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/DeviceSubnetListCommand.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2016-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.cli;
-
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onlab.packet.IpPrefix;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.net.DeviceId;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Command to list device-subnet mapping in Segment Routing.
- */
-@Service
-@Command(scope = "onos", name = "sr-device-subnets",
- description = "List device-subnet mapping in Segment Routing")
-public class DeviceSubnetListCommand extends AbstractShellCommand {
- @Override
- protected void doExecute() {
- SegmentRoutingService srService =
- AbstractShellCommand.get(SegmentRoutingService.class);
- printDeviceSubnetMap(srService.getDeviceSubnetMap());
- }
-
- private void printDeviceSubnetMap(Map<DeviceId, Set<IpPrefix>> deviceSubnetMap) {
- deviceSubnetMap.forEach(((deviceId, ipPrefices) -> {
- print("%s", deviceId);
- ipPrefices.forEach(ipPrefix -> print(" %s", ipPrefix));
- }));
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/EcmpGraphCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/EcmpGraphCommand.java
deleted file mode 100644
index 269134d..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/EcmpGraphCommand.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2016-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.cli;
-
-
-import java.util.Map;
-
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.net.DeviceId;
-import org.onosproject.segmentrouting.EcmpShortestPathGraph;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-
-/**
- * Command to read the current state of the ECMP shortest-path graph.
- *
- */
-@Service
-@Command(scope = "onos", name = "sr-ecmp-spg",
- description = "Displays the current ecmp shortest-path-graph in this "
- + "controller instance")
-public class EcmpGraphCommand extends AbstractShellCommand {
-
- private static final String FORMAT_MAPPING = " %s";
-
- @Override
- protected void doExecute() {
- SegmentRoutingService srService =
- AbstractShellCommand.get(SegmentRoutingService.class);
- printEcmpGraph(srService.getCurrentEcmpSpg());
- }
-
- private void printEcmpGraph(Map<DeviceId, EcmpShortestPathGraph> currentEcmpSpg) {
- if (currentEcmpSpg == null) {
- print(FORMAT_MAPPING, "No ECMP graph found");
- return;
- }
- StringBuilder ecmp = new StringBuilder();
- currentEcmpSpg.forEach((key, value) -> {
- ecmp.append("\n\nRoot Device: " + key + " ECMP Paths: " + value);
- });
- print(FORMAT_MAPPING, ecmp.toString());
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/InvalidateNextCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/InvalidateNextCommand.java
deleted file mode 100644
index 094bea9..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/InvalidateNextCommand.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2018-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.cli;
-
-
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onlab.osgi.ServiceNotFoundException;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-
-/**
- * Command to invalidate next id from SR internal stores.
- */
-@Service
-@Command(scope = "onos", name = "sr-next-invalidate",
- description = "Invalidate given next id from SR internal stores")
-public class InvalidateNextCommand extends AbstractShellCommand {
-
- private static final String CONFIRM_PHRASE = "please";
-
- @Argument(name = "nextId", description = "Next ID", index = 0)
- private String nextId = null;
-
- @Argument(name = "confirm", description = "Confirmation phrase", index = 1)
- private String please = null;
-
- @Override
- protected void doExecute() {
- if (please == null || !please.equals(CONFIRM_PHRASE)) {
- print("WARNING: System may enter an unpredictable state if the next ID is force invalidated." +
- "Enter confirmation phrase to continue.");
- return;
- }
-
- try {
- SegmentRoutingService srService = AbstractShellCommand.get(SegmentRoutingService.class);
- srService.invalidateNextObj(Integer.parseInt(nextId));
- } catch (ServiceNotFoundException e) {
- print("SegmentRoutingService unavailable");
- }
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/LinkStateCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/LinkStateCommand.java
deleted file mode 100644
index 9d7147b..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/LinkStateCommand.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2018-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.cli;
-
-import java.util.Comparator;
-import java.util.List;
-import java.util.Set;
-
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Link;
-import org.onosproject.net.PortNumber;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-
-
-/**
- * Command to read the current state of the DestinationSetNextObjectiveStore.
- *
- */
-@Service
-@Command(scope = "onos", name = "sr-link-state", description = "Displays the current internal link state "
- + "noted by this instance of the controller")
-public class LinkStateCommand extends AbstractShellCommand {
- private static final String FORMAT_MAPPING = " %s";
-
- @Override
- protected void doExecute() {
- SegmentRoutingService srService = AbstractShellCommand
- .get(SegmentRoutingService.class);
- printLinkState(srService.getSeenLinks(),
- srService.getDownedPortState());
- }
-
- private void printLinkState(ImmutableMap<Link, Boolean> seenLinks,
- ImmutableMap<DeviceId, Set<PortNumber>> downedPortState) {
- List<Link> a = Lists.newArrayList();
- a.addAll(seenLinks.keySet());
- a.sort(new CompLinks());
-
- StringBuilder slbldr = new StringBuilder();
- slbldr.append("\n Seen Links: ");
- for (int i = 0; i < a.size(); i++) {
- slbldr.append("\n "
- + (seenLinks.get(a.get(i)) == Boolean.TRUE ? " up : "
- : "down : "));
- slbldr.append(a.get(i).src() + " --> " + a.get(i).dst());
- }
- print(FORMAT_MAPPING, slbldr.toString());
-
- StringBuilder dpbldr = new StringBuilder();
- dpbldr.append("\n\n Administratively Disabled Ports: ");
- downedPortState.entrySet().forEach(entry -> dpbldr
- .append("\n " + entry.getKey() + entry.getValue()));
- print(FORMAT_MAPPING, dpbldr.toString());
- }
-
- static class CompLinks implements Comparator<Link> {
-
- @Override
- public int compare(Link o1, Link o2) {
- int res = o1.src().deviceId().toString()
- .compareTo(o2.src().deviceId().toString());
- if (res < 0) {
- return -1;
- } else if (res > 0) {
- return +1;
- }
- if (o1.src().port().toLong() < o2.src().port().toLong()) {
- return -1;
- }
- return +1;
- }
-
- }
-
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/McastFilterListCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/McastFilterListCommand.java
deleted file mode 100644
index bc1eb42..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/McastFilterListCommand.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2020-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.cli;
-
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.net.DeviceId;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-import org.onosproject.segmentrouting.mcast.McastFilteringObjStoreKey;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * Command to show the list of mcast filtering obj.
- */
-@Service
-@Command(scope = "onos", name = "sr-filt-mcast",
- description = "Lists all mcast filtering objs")
-public class McastFilterListCommand extends AbstractShellCommand {
-
- private static final String FORMAT_HEADER = "device=%s";
- private static final String FILTER_HEADER = "\t%s,%s,%s";
-
- @Override
- protected void doExecute() {
- // Get SR service
- SegmentRoutingService srService = get(SegmentRoutingService.class);
- // Get the filt objs
- Map<DeviceId, List<McastFilteringObjStoreKey>> filteringObjKeys = srService.getMcastFilters();
- filteringObjKeys.forEach(this::printMcastFilter);
- }
-
- private void printMcastFilter(DeviceId deviceId, List<McastFilteringObjStoreKey> filteringObjs) {
- print(FORMAT_HEADER, deviceId);
- filteringObjs.forEach(filteringObj -> print(FILTER_HEADER, filteringObj.ingressCP(),
- filteringObj.isIpv4() ? "IPv4" : "IPv6",
- filteringObj.vlanId()));
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/McastLeaderListCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/McastLeaderListCommand.java
deleted file mode 100644
index 633745c..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/McastLeaderListCommand.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2018-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.cli;
-
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Completion;
-import org.apache.karaf.shell.api.action.Option;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onlab.packet.IpAddress;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.cluster.NodeId;
-import org.onosproject.mcast.cli.McastGroupCompleter;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-
-import java.util.Map;
-
-import static com.google.common.base.Strings.isNullOrEmpty;
-
-/**
- * Command to show the mcast leaders of the groups.
- */
-@Service
-@Command(scope = "onos", name = "sr-mcast-leader",
- description = "Lists all mcast leaders")
-public class McastLeaderListCommand extends AbstractShellCommand {
-
- // OSGi workaround to introduce package dependency
- McastGroupCompleter completer;
-
- // Format for group line
- private static final String G_FORMAT_MAPPING = "group=%s, leader=%s";
-
- @Option(name = "-gAddr", aliases = "--groupAddress",
- description = "IP Address of the multicast group",
- valueToShowInHelp = "224.0.0.0",
- required = false, multiValued = false)
- @Completion(McastGroupCompleter.class)
- String gAddr = null;
-
- @Override
- protected void doExecute() {
- // Verify mcast group
- IpAddress mcastGroup = null;
- if (!isNullOrEmpty(gAddr)) {
- mcastGroup = IpAddress.valueOf(gAddr);
- }
- // Get SR service
- SegmentRoutingService srService = get(SegmentRoutingService.class);
- // Get the mapping
- Map<IpAddress, NodeId> keyToRole = srService.getMcastLeaders(mcastGroup);
- // And print local cache
- keyToRole.forEach(this::printMcastLeder);
- }
-
- private void printMcastLeder(IpAddress mcastGroup,
- NodeId nodeId) {
- print(G_FORMAT_MAPPING, mcastGroup, nodeId);
- }
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/McastNextListCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/McastNextListCommand.java
deleted file mode 100644
index 7dd6fd3..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/McastNextListCommand.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2018-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.cli;
-
-import com.google.common.collect.Maps;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Completion;
-import org.apache.karaf.shell.api.action.Option;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.VlanId;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.mcast.cli.McastGroupCompleter;
-import org.onosproject.net.DeviceId;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-import org.onosproject.segmentrouting.mcast.McastStoreKey;
-import org.apache.commons.lang3.tuple.Pair;
-
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import static com.google.common.base.Strings.isNullOrEmpty;
-
-/**
- * Command to show the list of mcast nextids.
- */
-@Service
-@Command(scope = "onos", name = "sr-next-mcast",
- description = "Lists all mcast nextids")
-public class McastNextListCommand extends AbstractShellCommand {
-
- // OSGi workaround to introduce package dependency
- McastGroupCompleter completer;
-
- // Format for group line
- private static final String FORMAT_MAPPING = "group=%s, deviceIds-nextIds=%s";
-
- @Option(name = "-gAddr", aliases = "--groupAddress",
- description = "IP Address of the multicast group",
- valueToShowInHelp = "224.0.0.0",
- required = false, multiValued = false)
- @Completion(McastGroupCompleter.class)
- String gAddr = null;
-
- @Override
- protected void doExecute() {
- // Verify mcast group
- IpAddress mcastGroup = null;
- if (!isNullOrEmpty(gAddr)) {
- mcastGroup = IpAddress.valueOf(gAddr);
- }
- // Get SR service
- SegmentRoutingService srService = get(SegmentRoutingService.class);
- // Get the mapping
- Map<McastStoreKey, Integer> keyToNextId = srService.getMcastNextIds(mcastGroup);
- // Reduce to the set of mcast groups
- Set<IpAddress> mcastGroups = keyToNextId.keySet().stream()
- .map(McastStoreKey::mcastIp)
- .collect(Collectors.toSet());
- // Print the nextids for each group
- mcastGroups.forEach(group -> {
- // Create a new map for the group
- Map<Pair<DeviceId, VlanId>, Integer> deviceIdNextMap = Maps.newHashMap();
- keyToNextId.entrySet()
- .stream()
- // Filter only the elements related to this group
- .filter(entry -> entry.getKey().mcastIp().equals(group))
- // For each create a new entry in the group related map
- .forEach(entry -> deviceIdNextMap.put(Pair.of(entry.getKey().deviceId(),
- entry.getKey().vlanId()), entry.getValue()));
- // Print the map
- printMcastNext(group, deviceIdNextMap);
- });
- }
-
- private void printMcastNext(IpAddress mcastGroup, Map<Pair<DeviceId, VlanId>, Integer> deviceIdNextMap) {
- print(FORMAT_MAPPING, mcastGroup, deviceIdNextMap);
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/McastRoleListCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/McastRoleListCommand.java
deleted file mode 100644
index 2b22c67..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/McastRoleListCommand.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright 2018-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.cli;
-
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Multimap;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Completion;
-import org.apache.karaf.shell.api.action.Option;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onlab.packet.IpAddress;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.cli.net.ConnectPointCompleter;
-import org.onosproject.mcast.cli.McastGroupCompleter;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-import org.onosproject.segmentrouting.mcast.McastRole;
-import org.onosproject.segmentrouting.mcast.McastRoleStoreKey;
-
-import java.util.Collection;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import static com.google.common.base.Strings.isNullOrEmpty;
-
-/**
- * Command to show the list of mcast roles.
- */
-@Service
-@Command(scope = "onos", name = "sr-mcast-role",
- description = "Lists all mcast roles")
-public class McastRoleListCommand extends AbstractShellCommand {
-
- // OSGi workaround to introduce package dependency
- McastGroupCompleter completer;
-
- // Format for group line
- private static final String FORMAT_MAPPING = "%s,%s ingress=%s\ttransit=%s\tegress=%s";
-
- @Option(name = "-gAddr", aliases = "--groupAddress",
- description = "IP Address of the multicast group",
- valueToShowInHelp = "224.0.0.0",
- required = false, multiValued = false)
- @Completion(McastGroupCompleter.class)
- String gAddr = null;
-
- @Option(name = "-src", aliases = "--connectPoint",
- description = "Source port of:XXXXXXXXXX/XX",
- valueToShowInHelp = "of:0000000000000001/1",
- required = false, multiValued = false)
- @Completion(ConnectPointCompleter.class)
- String source = null;
-
- @Override
- protected void doExecute() {
- // Verify mcast group
- IpAddress mcastGroup = null;
- // We want to use source cp only for a specific group
- ConnectPoint sourcecp = null;
- if (!isNullOrEmpty(gAddr)) {
- mcastGroup = IpAddress.valueOf(gAddr);
- if (!isNullOrEmpty(source)) {
- sourcecp = ConnectPoint.deviceConnectPoint(source);
- }
- }
- // Get SR service, the roles and the groups
- SegmentRoutingService srService = get(SegmentRoutingService.class);
- Map<McastRoleStoreKey, McastRole> keyToRole = srService.getMcastRoles(mcastGroup, sourcecp);
- Set<IpAddress> mcastGroups = keyToRole.keySet().stream()
- .map(McastRoleStoreKey::mcastIp)
- .collect(Collectors.toSet());
- // Print the trees for each group
- mcastGroups.forEach(group -> {
- // Create a new map for the group
- Map<ConnectPoint, Multimap<McastRole, DeviceId>> roleDeviceIdMap = Maps.newHashMap();
- keyToRole.entrySet()
- .stream()
- .filter(entry -> entry.getKey().mcastIp().equals(group))
- .forEach(entry -> roleDeviceIdMap.compute(entry.getKey().source(), (gsource, map) -> {
- map = map == null ? ArrayListMultimap.create() : map;
- map.put(entry.getValue(), entry.getKey().deviceId());
- return map;
- }));
- roleDeviceIdMap.forEach((gsource, map) -> {
- // Print the map
- printMcastRole(group, gsource,
- map.get(McastRole.INGRESS),
- map.get(McastRole.TRANSIT),
- map.get(McastRole.EGRESS));
- });
- });
- }
-
- private void printMcastRole(IpAddress mcastGroup, ConnectPoint source,
- Collection<DeviceId> ingress,
- Collection<DeviceId> transit,
- Collection<DeviceId> egress) {
- print(FORMAT_MAPPING, mcastGroup, source, ingress, transit, egress);
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/McastTreeListCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/McastTreeListCommand.java
deleted file mode 100644
index 09c795c..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/McastTreeListCommand.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright 2018-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.cli;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ArrayNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Multimap;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Completion;
-import org.apache.karaf.shell.api.action.Option;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onlab.packet.IpAddress;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.cli.net.ConnectPointCompleter;
-import org.onosproject.mcast.cli.McastGroupCompleter;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import static com.google.common.base.Strings.isNullOrEmpty;
-
-/**
- * Command to show the list of mcast trees.
- */
-@Service
-@Command(scope = "onos", name = "sr-mcast-tree",
- description = "Lists all mcast trees")
-public class McastTreeListCommand extends AbstractShellCommand {
-
- // OSGi workaround to introduce package dependency
- McastGroupCompleter completer;
-
- // Format for group line
- private static final String G_FORMAT_MAPPING = "group=%s";
- // Format for sink line
- private static final String S_FORMAT_MAPPING = " sink=%s\tpath=%s";
-
- @Option(name = "-gAddr", aliases = "--groupAddress",
- description = "IP Address of the multicast group",
- valueToShowInHelp = "224.0.0.0",
- required = false, multiValued = false)
- @Completion(McastGroupCompleter.class)
- String gAddr = null;
-
- @Option(name = "-src", aliases = "--connectPoint",
- description = "Source port of:XXXXXXXXXX/XX",
- valueToShowInHelp = "of:0000000000000001/1",
- required = false, multiValued = false)
- @Completion(ConnectPointCompleter.class)
- String source = null;
-
- @Override
- protected void doExecute() {
- // Get SR service and the handled mcast groups
- SegmentRoutingService srService = get(SegmentRoutingService.class);
- Set<IpAddress> mcastGroups = ImmutableSet.copyOf(srService.getMcastLeaders(null)
- .keySet());
-
- if (!isNullOrEmpty(gAddr)) {
- mcastGroups = mcastGroups.stream()
- .filter(mcastIp -> mcastIp.equals(IpAddress.valueOf(gAddr)))
- .collect(Collectors.toSet());
- }
-
- ObjectMapper mapper = new ObjectMapper();
- ObjectNode root = mapper.createObjectNode();
-
- // Print the trees for each group or build json objects
- mcastGroups.forEach(group -> {
- // We want to use source cp only for a specific group
- ConnectPoint sourcecp = null;
- if (!isNullOrEmpty(source) &&
- !isNullOrEmpty(gAddr)) {
- sourcecp = ConnectPoint.deviceConnectPoint(source);
- }
- Multimap<ConnectPoint, List<ConnectPoint>> mcastTree = srService.getMcastTrees(group,
- sourcecp);
- if (!mcastTree.isEmpty()) {
- // Build a json object for each group
- if (outputJson()) {
- root.putPOJO(group.toString(), json(mcastTree));
- } else {
- // Banner and then the trees
- printMcastGroup(group);
- mcastTree.forEach(this::printMcastSink);
- }
- }
- });
-
- // Print the json object at the end
- if (outputJson()) {
- print("%s", root);
- }
-
- }
-
- private void printMcastGroup(IpAddress mcastGroup) {
- print(G_FORMAT_MAPPING, mcastGroup);
- }
-
- private void printMcastSink(ConnectPoint sink, List<ConnectPoint> path) {
- print(S_FORMAT_MAPPING, sink, path);
- }
-
- private ObjectNode json(Multimap<ConnectPoint, List<ConnectPoint>> mcastTree) {
- ObjectMapper mapper = new ObjectMapper();
- ObjectNode jsonSinks = mapper.createObjectNode();
- mcastTree.asMap().forEach((sink, paths) -> {
- ArrayNode jsonPaths = mapper.createArrayNode();
- paths.forEach(path -> {
- ArrayNode jsonPath = mapper.createArrayNode();
- path.forEach(connectPoint -> jsonPath.add(connectPoint.toString()));
- jsonPaths.addPOJO(jsonPath);
- });
- jsonSinks.putPOJO(sink.toString(), jsonPaths);
- });
- return jsonSinks;
- }
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/NextDstCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/NextDstCommand.java
deleted file mode 100644
index e6da695..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/NextDstCommand.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2016-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.cli;
-
-
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.Map;
-
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-import org.onosproject.segmentrouting.grouphandler.NextNeighbors;
-import org.onosproject.segmentrouting.storekey.DestinationSetNextObjectiveStoreKey;
-
-/**
- * Command to read the current state of the DestinationSetNextObjectiveStore.
- */
-@Service
-@Command(scope = "onos", name = "sr-next-dst",
- description = "Displays the current next-hops seen by each switch "
- + "towards a set of destinations and the next-id it maps to")
-public class NextDstCommand extends AbstractShellCommand {
-
- private static final String FORMAT_MAPPING = " %s";
-
- @Override
- protected void doExecute() {
- SegmentRoutingService srService =
- AbstractShellCommand.get(SegmentRoutingService.class);
- printDestinationSet(srService.getDstNextObjStore());
- }
-
- private void printDestinationSet(Map<DestinationSetNextObjectiveStoreKey,
- NextNeighbors> ds) {
- ArrayList<DestinationSetNextObjectiveStoreKey> a = new ArrayList<>();
- ds.keySet().forEach(key -> a.add(key));
- a.sort(new Comp());
-
- StringBuilder dsbldr = new StringBuilder();
- for (int i = 0; i < a.size(); i++) {
- dsbldr.append("\n " + a.get(i));
- dsbldr.append(" --> via: " + ds.get(a.get(i)));
- }
- print(FORMAT_MAPPING, dsbldr.toString());
- }
-
- static class Comp implements Comparator<DestinationSetNextObjectiveStoreKey> {
-
- @Override
- public int compare(DestinationSetNextObjectiveStoreKey o1,
- DestinationSetNextObjectiveStoreKey o2) {
- int res = o1.deviceId().toString().compareTo(o2.deviceId().toString());
- if (res < 0) {
- return -1;
- } else if (res > 0) {
- return +1;
- }
- return 0;
- }
-
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/NextMacVlanCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/NextMacVlanCommand.java
deleted file mode 100644
index e31e693..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/NextMacVlanCommand.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2018-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.cli;
-
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-import org.onosproject.segmentrouting.storekey.MacVlanNextObjectiveStoreKey;
-
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.Map;
-
-/**
- * Command to read the current state of the macVlanNextObjStore.
- */
-@Service
-@Command(scope = "onos", name = "sr-next-mac-vlan",
- description = "Displays the current next-hop / next-id it mapping")
-public class NextMacVlanCommand extends AbstractShellCommand {
- @Override
- protected void doExecute() {
- SegmentRoutingService srService =
- AbstractShellCommand.get(SegmentRoutingService.class);
- print(srService.getMacVlanNextObjStore());
- }
-
- private void print(Map<MacVlanNextObjectiveStoreKey, Integer> macVlanNextObjStore) {
- ArrayList<MacVlanNextObjectiveStoreKey> a = new ArrayList<>(macVlanNextObjStore.keySet());
- a.sort(Comparator
- .comparing((MacVlanNextObjectiveStoreKey o) -> o.deviceId().toString())
- .thenComparing((MacVlanNextObjectiveStoreKey o) -> o.vlanId().toString())
- .thenComparing((MacVlanNextObjectiveStoreKey o) -> o.macAddr().toString()));
-
- StringBuilder builder = new StringBuilder();
- a.forEach(k ->
- builder.append("\n")
- .append(k)
- .append(" --> ")
- .append(macVlanNextObjStore.get(k))
- );
- print(builder.toString());
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/NextPortCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/NextPortCommand.java
deleted file mode 100644
index fddc1d7..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/NextPortCommand.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2018-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.cli;
-
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-import org.onosproject.segmentrouting.storekey.PortNextObjectiveStoreKey;
-
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.Map;
-
-/**
- * Command to read the current state of the portNextObjStore.
- */
-@Service
-@Command(scope = "onos", name = "sr-next-port",
- description = "Displays the current port / next-id it mapping")
-public class NextPortCommand extends AbstractShellCommand {
- @Override
- protected void doExecute() {
- SegmentRoutingService srService =
- AbstractShellCommand.get(SegmentRoutingService.class);
- print(srService.getPortNextObjStore());
- }
-
- private void print(Map<PortNextObjectiveStoreKey, Integer> portNextObjStore) {
- ArrayList<PortNextObjectiveStoreKey> a = new ArrayList<>(portNextObjStore.keySet());
- a.sort(Comparator
- .comparing((PortNextObjectiveStoreKey o) -> o.deviceId().toString())
- .thenComparing((PortNextObjectiveStoreKey o) -> o.portNumber().toLong()));
-
- StringBuilder builder = new StringBuilder();
- a.forEach(k ->
- builder.append("\n")
- .append(k)
- .append(" --> ")
- .append(portNextObjStore.get(k))
- );
- print(builder.toString());
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/NextVlanCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/NextVlanCommand.java
deleted file mode 100644
index 8518a5f..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/NextVlanCommand.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2018-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.cli;
-
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-import org.onosproject.segmentrouting.storekey.VlanNextObjectiveStoreKey;
-
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.Map;
-
-/**
- * Command to read the current state of the vlanNextObjStore.
- */
-@Service
-@Command(scope = "onos", name = "sr-next-vlan",
- description = "Displays the current vlan / next-id it mapping")
-public class NextVlanCommand extends AbstractShellCommand {
- @Override
- protected void doExecute() {
- SegmentRoutingService srService =
- AbstractShellCommand.get(SegmentRoutingService.class);
- print(srService.getVlanNextObjStore());
- }
-
- private void print(Map<VlanNextObjectiveStoreKey, Integer> vlanNextObjStore) {
- ArrayList<VlanNextObjectiveStoreKey> a = new ArrayList<>(vlanNextObjStore.keySet());
- a.sort(Comparator
- .comparing((VlanNextObjectiveStoreKey o) -> o.deviceId().toString())
- .thenComparing((VlanNextObjectiveStoreKey o) -> o.vlanId().toShort()));
-
- StringBuilder builder = new StringBuilder();
- a.forEach(k ->
- builder.append("\n")
- .append(k)
- .append(" --> ")
- .append(vlanNextObjStore.get(k))
- );
- print(builder.toString());
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/PhaseCompleter.java b/app/src/main/java/org/onosproject/segmentrouting/cli/PhaseCompleter.java
deleted file mode 100644
index bd16068..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/PhaseCompleter.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2014-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.cli;
-
-import com.google.common.collect.Lists;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractChoicesCompleter;
-import org.onosproject.segmentrouting.phasedrecovery.api.Phase;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * Phase completer.
- */
-@Service
-public class PhaseCompleter extends AbstractChoicesCompleter {
- @Override
- protected List<String> choices() {
- return Lists.newArrayList(Phase.values()).stream().map(Enum::toString).collect(Collectors.toList());
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/PhasedRecoveryListCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/PhasedRecoveryListCommand.java
deleted file mode 100644
index 6efdaaa..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/PhasedRecoveryListCommand.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2020-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.cli;
-
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.segmentrouting.phasedrecovery.api.PhasedRecoveryService;
-
-@Service
-@Command(scope = "onos", name = "sr-pr-list", description = "List current recovery phase of each device")
-
-public class PhasedRecoveryListCommand extends AbstractShellCommand {
- @Override
- protected void doExecute() {
- PhasedRecoveryService prService = get(PhasedRecoveryService.class);
- print(prService.getPhases().toString());
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/PhasedRecoverySetCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/PhasedRecoverySetCommand.java
deleted file mode 100644
index 50e3bc6..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/PhasedRecoverySetCommand.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2020-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.cli;
-
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Completion;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.cli.net.DeviceIdCompleter;
-import org.onosproject.net.DeviceId;
-import org.onosproject.segmentrouting.phasedrecovery.api.Phase;
-import org.onosproject.segmentrouting.phasedrecovery.api.PhasedRecoveryService;
-
-@Service
-@Command(scope = "onos", name = "sr-pr-set", description = "Set recovery phase of given device")
-
-public class PhasedRecoverySetCommand extends AbstractShellCommand {
- @Argument(index = 0, name = "deviceId",
- description = "Device ID",
- required = true, multiValued = false)
- @Completion(DeviceIdCompleter.class)
- private String deviceIdStr;
-
- @Argument(index = 1, name = "phase",
- description = "Recovery phase",
- required = true, multiValued = false)
- @Completion(PhaseCompleter.class)
- private String phaseStr;
-
- @Override
- protected void doExecute() {
- DeviceId deviceId = DeviceId.deviceId(deviceIdStr);
- Phase newPhase = Phase.valueOf(phaseStr);
-
- PhasedRecoveryService prService = get(PhasedRecoveryService.class);
- prService.setPhase(deviceId, newPhase);
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/PolicyAddCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/PolicyAddCommand.java
deleted file mode 100644
index 1f75317..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/PolicyAddCommand.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright 2015-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.cli;
-
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.segmentrouting.Policy;
-import org.onosproject.segmentrouting.PolicyHandler;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-import org.onosproject.segmentrouting.TunnelPolicy;
-
-/**
- * Command to add a new policy.
- */
-@Service
-@Command(scope = "onos", name = "sr-policy-add",
- description = "Create a new policy")
-public class PolicyAddCommand extends AbstractShellCommand {
-
- // TODO: Need to support skipping some parameters
-
- @Argument(index = 0, name = "ID",
- description = "policy ID",
- required = true, multiValued = false)
- String policyId;
-
- @Argument(index = 1, name = "priority",
- description = "priority",
- required = true, multiValued = false)
- int priority;
-
- @Argument(index = 2, name = "src_IP",
- description = "src IP",
- required = false, multiValued = false)
- String srcIp;
-
- @Argument(index = 3, name = "src_port",
- description = "src port",
- required = false, multiValued = false)
- short srcPort;
-
- @Argument(index = 4, name = "dst_IP",
- description = "dst IP",
- required = false, multiValued = false)
- String dstIp;
-
- @Argument(index = 5, name = "dst_port",
- description = "dst port",
- required = false, multiValued = false)
- short dstPort;
-
- @Argument(index = 6, name = "proto",
- description = "IP protocol",
- required = false, multiValued = false)
- String proto;
-
- @Argument(index = 7, name = "policy_type",
- description = "policy type",
- required = true, multiValued = false)
- String policyType;
-
- @Argument(index = 8, name = "tunnel_ID",
- description = "tunnel ID",
- required = false, multiValued = false)
- String tunnelId;
-
- @Override
- protected void doExecute() {
-
- SegmentRoutingService srService =
- AbstractShellCommand.get(SegmentRoutingService.class);
-
- TunnelPolicy.Builder tpb = TunnelPolicy.builder().setPolicyId(policyId);
- tpb.setPriority(priority);
- tpb.setType(Policy.Type.valueOf(policyType));
-
- if (srcIp != null) {
- tpb.setSrcIp(srcIp);
- }
- if (dstIp != null) {
- tpb.setDstIp(dstIp);
- }
- if (srcPort != 0) {
- tpb.setSrcPort(srcPort);
- }
- if (dstPort != 0) {
- tpb.setDstPort(dstPort);
- }
- if (!"ip".equals(proto)) {
- tpb.setIpProto(proto);
- }
- if (Policy.Type.valueOf(policyType) == Policy.Type.TUNNEL_FLOW) {
- if (tunnelId == null) {
- error("tunnel ID must be specified for TUNNEL_FLOW policy");
- return;
- }
- tpb.setTunnelId(tunnelId);
- }
- PolicyHandler.Result result = srService.createPolicy(tpb.build());
-
- switch (result) {
- case POLICY_EXISTS:
- error("the same policy exists");
- break;
- case ID_EXISTS:
- error("the same policy ID exists");
- break;
- case TUNNEL_NOT_FOUND:
- error("the tunnel is not found");
- break;
- case UNSUPPORTED_TYPE:
- error("the policy type specified is not supported");
- break;
- default:
- break;
- }
-
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/PolicyListCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/PolicyListCommand.java
deleted file mode 100644
index 3520fba..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/PolicyListCommand.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2015-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.cli;
-
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.segmentrouting.Policy;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-import org.onosproject.segmentrouting.TunnelPolicy;
-
-/**
- * Command to show the list of policies.
- */
-@Service
-@Command(scope = "onos", name = "sr-policy-list",
- description = "Lists all policies")
-public class PolicyListCommand extends AbstractShellCommand {
-
- private static final String FORMAT_MAPPING_TUNNEL =
- " id=%s, type=%s, prio=%d, src=%s, port=%d, dst=%s, port=%d, proto=%s, tunnel=%s";
-
- @Override
- protected void doExecute() {
-
- SegmentRoutingService srService =
- AbstractShellCommand.get(SegmentRoutingService.class);
-
- srService.getPolicies().forEach(policy -> printPolicy(policy));
- }
-
- private void printPolicy(Policy policy) {
- if (policy.type() == Policy.Type.TUNNEL_FLOW) {
- print(FORMAT_MAPPING_TUNNEL, policy.id(), policy.type(), policy.priority(),
- policy.srcIp(), policy.srcPort(), policy.dstIp(), policy.dstPort(),
- (policy.ipProto() == null) ? "" : policy.ipProto(),
- ((TunnelPolicy) policy).tunnelId());
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/PolicyRemoveCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/PolicyRemoveCommand.java
deleted file mode 100644
index 575d35f..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/PolicyRemoveCommand.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2015-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.cli;
-
-
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.segmentrouting.PolicyHandler;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-import org.onosproject.segmentrouting.TunnelPolicy;
-
-/**
- * Command to remove a policy.
- */
-@Service
-@Command(scope = "onos", name = "sr-policy-remove",
- description = "Remove a policy")
-public class PolicyRemoveCommand extends AbstractShellCommand {
-
- @Argument(index = 0, name = "policy ID",
- description = "policy ID",
- required = true, multiValued = false)
- String policyId;
-
- @Override
- protected void doExecute() {
-
- SegmentRoutingService srService =
- AbstractShellCommand.get(SegmentRoutingService.class);
-
- TunnelPolicy.Builder tpb = TunnelPolicy.builder().setPolicyId(policyId);
- PolicyHandler.Result result = srService.removePolicy(tpb.build());
- if (result == PolicyHandler.Result.POLICY_NOT_FOUND) {
- print("ERROR: the policy is not found");
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/PortsCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/PortsCommand.java
deleted file mode 100644
index f24d28f..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/PortsCommand.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2020-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.cli;
-
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Completion;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.cli.PlaceholderCompleter;
-import org.onosproject.cli.net.DeviceIdCompleter;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.PortNumber;
-import org.onosproject.segmentrouting.phasedrecovery.api.PhasedRecoveryService;
-
-import java.util.Set;
-import java.util.stream.Collectors;
-
-@Service
-@Command(scope = "onos", name = "sr-ports", description = "Enable/Disable group of ports on a specific device")
-
-public class PortsCommand extends AbstractShellCommand {
- @Argument(index = 0, name = "deviceId",
- description = "Device ID",
- required = true, multiValued = false)
- @Completion(DeviceIdCompleter.class)
- private String deviceIdStr;
-
- @Argument(index = 1, name = "ports",
- description = "Ports to be enabled/disabled: ALL, PAIR, INFRA, EDGE",
- required = true, multiValued = false)
- @Completion(PlaceholderCompleter.class)
- private String portsStr;
-
- @Argument(index = 2, name = "action",
- description = "Action: ENABLE, DISABLE",
- required = true, multiValued = false)
- @Completion(PlaceholderCompleter.class)
- private String actionStr;
-
- @Override
- protected void doExecute() {
- PhasedRecoveryService prService = get(PhasedRecoveryService.class);
-
- DeviceId deviceId = DeviceId.deviceId(deviceIdStr);
-
- boolean enabled;
- switch (actionStr.toUpperCase()) {
- case "ENABLE":
- enabled = true;
- break;
- case "DISABLE":
- enabled = false;
- break;
- default:
- print("Action should be either ENABLE or DISABLE");
- return;
- }
-
- Set<PortNumber> portsChanged;
- switch (portsStr.toUpperCase()) {
- case "ALL":
- portsChanged = prService.changeAllPorts(deviceId, enabled);
- break;
- case "PAIR":
- portsChanged = prService.changePairPort(deviceId, enabled);
- break;
- case "INFRA":
- portsChanged = prService.changeInfraPorts(deviceId, enabled);
- break;
- case "EDGE":
- portsChanged = prService.changeEdgePorts(deviceId, enabled);
- break;
- default:
- print("Ports should be ALL, PAIR, INFRA, EDGE");
- return;
- }
- print("Ports set to %s: %s",
- enabled ? "enabled" : "disabled",
- portsChanged.stream().map(PortNumber::toLong).collect(Collectors.toSet()));
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireAddCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireAddCommand.java
deleted file mode 100644
index d595d5c..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireAddCommand.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright 2017-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.cli;
-
-
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-import org.onosproject.segmentrouting.pwaas.DefaultL2Tunnel;
-import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelDescription;
-import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelPolicy;
-import org.onosproject.segmentrouting.pwaas.L2Tunnel;
-import org.onosproject.segmentrouting.pwaas.L2TunnelDescription;
-import org.onosproject.segmentrouting.pwaas.L2TunnelHandler;
-import org.onosproject.segmentrouting.pwaas.L2TunnelPolicy;
-
-import static org.onosproject.segmentrouting.pwaas.PwaasUtil.*;
-
-
-/**
- * Command to add a pseuwodire.
- */
-@Service
-@Command(scope = "onos", name = "sr-pw-add",
- description = "Add a pseudowire to the network configuration, if it already exists update it.")
-public class PseudowireAddCommand extends AbstractShellCommand {
-
- @Argument(index = 0, name = "pwId",
- description = "Pseudowire ID",
- required = true, multiValued = false)
- String pwId;
-
- @Argument(index = 1, name = "pwLabel",
- description = "Pseudowire Label",
- required = true, multiValued = false)
- String pwLabel;
-
- @Argument(index = 2, name = "mode",
- description = "Mode used for pseudowire",
- required = true, multiValued = false)
- String mode;
-
- @Argument(index = 3, name = "sDTag",
- description = "Service delimiting tag",
- required = true, multiValued = false)
- String sDTag;
-
- @Argument(index = 4, name = "cP1",
- description = "Connection Point 1",
- required = true, multiValued = false)
- String cP1;
-
- @Argument(index = 5, name = "cP1InnerVlan",
- description = "Inner Vlan of Connection Point 1",
- required = true, multiValued = false)
- String cP1InnerVlan;
-
- @Argument(index = 6, name = "cP1OuterVlan",
- description = "Outer Vlan of Connection Point 1",
- required = true, multiValued = false)
- String cP1OuterVlan;
-
- @Argument(index = 7, name = "cP2",
- description = "Connection Point 2",
- required = true, multiValued = false)
- String cP2;
-
- @Argument(index = 8, name = "cP2InnerVlan",
- description = "Inner Vlan of Connection Point 2",
- required = true, multiValued = false)
- String cP2InnerVlan;
-
- @Argument(index = 9, name = "cP2OuterVlan",
- description = "Outer Vlan of Connection Point 2",
- required = true, multiValued = false)
- String cP2OuterVlan;
-
- @Override
- protected void doExecute() {
-
- SegmentRoutingService srService =
- AbstractShellCommand.get(SegmentRoutingService.class);
-
- L2Tunnel tun;
- L2TunnelPolicy policy;
-
- try {
- tun = new DefaultL2Tunnel(parseMode(mode), parseVlan(sDTag), parsePwId(pwId), parsePWLabel(pwLabel));
- } catch (IllegalArgumentException e) {
- log.error("Exception while parsing L2Tunnel : \n\t %s", e.getMessage());
- print("Exception while parsing L2Tunnel : \n\t %s", e.getMessage());
- return;
- }
-
- try {
- policy = new DefaultL2TunnelPolicy(parsePwId(pwId),
- ConnectPoint.deviceConnectPoint(cP1), parseVlan(cP1InnerVlan),
- parseVlan(cP1OuterVlan), ConnectPoint.deviceConnectPoint(cP2),
- parseVlan(cP2InnerVlan), parseVlan(cP2OuterVlan));
-
- } catch (IllegalArgumentException e) {
- log.error("Exception while parsing L2TunnelPolicy : \n\t %s", e.getMessage());
- print("Exception while parsing L2TunnelPolicy : \n\t %s", e.getMessage());
- return;
- }
-
- L2TunnelDescription pw = new DefaultL2TunnelDescription(tun, policy);
- L2TunnelHandler.Result res = srService.addPseudowire(pw);
- log.info("Deploying pseudowire {} via the command line.", pw);
- switch (res) {
- case WRONG_PARAMETERS:
- print("Pseudowire could not be added , error in the parameters : \n\t%s",
- res.getSpecificError());
- break;
- case CONFIGURATION_ERROR:
- print("Pseudowire could not be added, configuration error : \n\t%s",
- res.getSpecificError());
- break;
- case PATH_NOT_FOUND:
- print("Pseudowire path not found : \n\t%s",
- res.getSpecificError());
- break;
- case INTERNAL_ERROR:
- print("Pseudowire could not be added, internal error : \n\t%s",
- res.getSpecificError());
- break;
- case SUCCESS:
- break;
- default:
- break;
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireIdCompleter.java b/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireIdCompleter.java
deleted file mode 100644
index abf0c0c..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireIdCompleter.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 2014-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.cli;
-
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.karaf.shell.api.console.CommandLine;
-import org.apache.karaf.shell.api.console.Completer;
-import org.apache.karaf.shell.api.console.Session;
-import org.apache.karaf.shell.support.completers.StringsCompleter;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-import org.onosproject.segmentrouting.pwaas.L2Tunnel;
-
-import java.util.Iterator;
-import java.util.List;
-import java.util.SortedSet;
-import java.util.stream.Collectors;
-
-/**
- * Device ID completer.
- */
-@Service
-public class PseudowireIdCompleter implements Completer {
- @Override
- public int complete(Session session, CommandLine commandLine, List<String> candidates) {
- // Delegate string completer
- StringsCompleter delegate = new StringsCompleter();
-
- SegmentRoutingService srService =
- AbstractShellCommand.get(SegmentRoutingService.class);
-
-
- List<L2Tunnel> tunnels = srService.getL2Tunnels();
-
- // combine polices and tunnels to pseudowires
- Iterator<String> pseudowires = tunnels.stream()
- .map(l2Tunnel -> Long.toString(l2Tunnel.tunnelId()))
- .collect(Collectors.toList()).iterator();
-
- SortedSet<String> strings = delegate.getStrings();
- while (pseudowires.hasNext()) {
- strings.add(pseudowires.next());
- }
-
- // Now let the completer do the work for figuring out what to offer.
- return delegate.complete(session, commandLine, candidates);
- }
-
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireListCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireListCommand.java
deleted file mode 100644
index 475ce26..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireListCommand.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2017-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.cli;
-
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onlab.packet.VlanId;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-import org.onosproject.segmentrouting.pwaas.L2TunnelDescription;
-/**
- * Command to show the pseudowires.
- */
-@Service
-@Command(scope = "onos", name = "sr-pw-list",
- description = "Lists all pseudowires")
-public class PseudowireListCommand extends AbstractShellCommand {
-
- private static final String FORMAT_PSEUDOWIRE =
- "Pseudowire id = %s \n" +
- " mode : %s, sdTag : %s, pwLabel : %s \n" +
- " cP1 : %s , cP1OuterTag : %s, cP1InnerTag : %s \n" +
- " cP2 : %s , cP2OuterTag : %s, cP2InnerTag : %s \n" +
- " transportVlan : %s \n" +
- " pending = %s";
-
- @Override
- protected void doExecute() {
-
- SegmentRoutingService srService =
- AbstractShellCommand.get(SegmentRoutingService.class);
-
- srService.getL2TunnelDescriptions(false)
- .forEach(pw -> printPseudowire(pw, false));
-
- srService.getL2TunnelDescriptions(true)
- .forEach(pw -> printPseudowire(pw, true));
- }
-
- private void printPseudowire(L2TunnelDescription pseudowire, boolean pending) {
- VlanId vlan = pseudowire.l2Tunnel().transportVlan().equals(VlanId.vlanId((short) 4094)) ?
- VlanId.NONE : pseudowire.l2Tunnel().transportVlan();
-
- print(FORMAT_PSEUDOWIRE, pseudowire.l2Tunnel().tunnelId(), pseudowire.l2Tunnel().pwMode(),
- pseudowire.l2Tunnel().sdTag(), pseudowire.l2Tunnel().pwLabel(),
- pseudowire.l2TunnelPolicy().cP1(), pseudowire.l2TunnelPolicy().cP1OuterTag(),
- pseudowire.l2TunnelPolicy().cP1InnerTag(), pseudowire.l2TunnelPolicy().cP2(),
- pseudowire.l2TunnelPolicy().cP2OuterTag(), pseudowire.l2TunnelPolicy().cP2InnerTag(),
- vlan, pending);
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireNextListCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireNextListCommand.java
deleted file mode 100644
index f2b3e8d..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireNextListCommand.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2018-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.cli;
-
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.net.flowobjective.NextObjective;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.Map;
-
-/**
- * Command to read the current state of the pseudowire next stores.
- */
-@Service
-@Command(scope = "onos", name = "sr-next-pw",
- description = "Displays the current next-id for pseudowire")
-public class PseudowireNextListCommand extends AbstractShellCommand {
- @Override
- protected void doExecute() {
- SegmentRoutingService srService =
- AbstractShellCommand.get(SegmentRoutingService.class);
- print(srService.getPwInitNext());
- print(srService.getPwTermNext());
- }
-
- private void print(Map<String, NextObjective> nextStore) {
- ArrayList<String> a = new ArrayList<>(nextStore.keySet());
- a.sort(Comparator.comparing((String o) -> o));
-
- StringBuilder builder = new StringBuilder();
- a.forEach(k ->
- builder.append("\n")
- .append(k)
- .append(" --> ")
- .append(nextStore.get(k).id())
- );
- print(builder.toString());
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireRemoveCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireRemoveCommand.java
deleted file mode 100644
index 2bb28b0..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireRemoveCommand.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 2017-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.cli;
-
-
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Completion;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.segmentrouting.SegmentRoutingManager;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-import org.onosproject.segmentrouting.pwaas.L2TunnelHandler;
-
-import static org.onosproject.segmentrouting.pwaas.PwaasUtil.parsePwId;
-
-
-/**
- * Command to remove a pseudowire.
- */
-@Service
-@Command(scope = "onos", name = "sr-pw-remove",
- description = "Remove a pseudowire")
-public class PseudowireRemoveCommand extends AbstractShellCommand {
-
- @Argument(index = 0, name = "pwId",
- description = "pseudowire ID",
- required = true, multiValued = false)
- @Completion(PseudowireIdCompleter.class)
- String pwId;
-
- @Override
- protected void doExecute() {
-
- SegmentRoutingService srService =
- AbstractShellCommand.get(SegmentRoutingService.class);
-
- // remove the pseudowire
- SegmentRoutingManager mngr = (SegmentRoutingManager) srService;
- int pwIntId;
- try {
- pwIntId = parsePwId(pwId);
- } catch (IllegalArgumentException e) {
- log.error("Exception while parsing pseudowire id : \n\t %s", e.getMessage());
- print("Exception while parsing pseudowire id : \n\t %s", e.getMessage());
- return;
- }
-
- log.info("Removing pseudowire {} from the command line.", pwIntId);
- L2TunnelHandler.Result res = mngr.removePseudowire(pwIntId);
- switch (res) {
- case WRONG_PARAMETERS:
- error("Pseudowire could not be removed , wrong parameters: \n\t %s\n",
- res.getSpecificError());
- break;
- case INTERNAL_ERROR:
- error("Pseudowire could not be removed, internal error : \n\t %s\n",
- res.getSpecificError());
- break;
- case SUCCESS:
- break;
- default:
- break;
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/RerouteNetworkCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/RerouteNetworkCommand.java
deleted file mode 100644
index 6e8d3e9..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/RerouteNetworkCommand.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2016-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.cli;
-
-
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-
-/**
- * Command to manually trigger routing and rule-population in the network.
- *
- */
-@Service
-@Command(scope = "onos", name = "sr-reroute-network",
- description = "Repopulate routing rules given current network state")
-public class RerouteNetworkCommand extends AbstractShellCommand {
-
- @Override
- protected void doExecute() {
- SegmentRoutingService srService =
- AbstractShellCommand.get(SegmentRoutingService.class);
- srService.rerouteNetwork();
- }
-
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/ShouldProgramCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/ShouldProgramCommand.java
deleted file mode 100644
index 250fb3b..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/ShouldProgramCommand.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2018-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.cli;
-
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.cluster.NodeId;
-import org.onosproject.net.DeviceId;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Display current shouldProgram map.
- */
-@Service
-@Command(scope = "onos", name = "sr-should-program",
- description = "Display current shouldProgram map")
-public class ShouldProgramCommand extends AbstractShellCommand {
- @Override
- protected void doExecute() {
- SegmentRoutingService srService = AbstractShellCommand.get(SegmentRoutingService.class);
- Map<Set<DeviceId>, NodeId> shouldProgram = srService.getShouldProgram();
- Map<DeviceId, Boolean> shouldProgramCache = srService.getShouldProgramCache();
-
- print("shouldProgram");
- shouldProgram.forEach((k, v) -> print("%s -> %s", k, v));
-
- print("shouldProgramCache");
- shouldProgramCache.forEach((k, v) -> print("%s -> %s", k, v));
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/TunnelAddCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/TunnelAddCommand.java
deleted file mode 100644
index 0e487d0..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/TunnelAddCommand.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2015-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.cli;
-
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.segmentrouting.DefaultTunnel;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-import org.onosproject.segmentrouting.Tunnel;
-import org.onosproject.segmentrouting.TunnelHandler;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.StringTokenizer;
-
-/**
- * Command to add a new tunnel.
- */
-@Service
-@Command(scope = "onos", name = "sr-tunnel-add",
- description = "Create a new tunnel")
-public class TunnelAddCommand extends AbstractShellCommand {
-
- @Argument(index = 0, name = "tunnel ID",
- description = "tunnel ID",
- required = true, multiValued = false)
- String tunnelId;
-
- @Argument(index = 1, name = "label path",
- description = "label path",
- required = true, multiValued = false)
- String labels;
-
-
- @Override
- protected void doExecute() {
-
- SegmentRoutingService srService =
- AbstractShellCommand.get(SegmentRoutingService.class);
-
- List<Integer> labelIds = new ArrayList<>();
- StringTokenizer strToken = new StringTokenizer(labels, ",");
- while (strToken.hasMoreTokens()) {
- labelIds.add(Integer.valueOf(strToken.nextToken()));
- }
- Tunnel tunnel = new DefaultTunnel(tunnelId, labelIds);
-
- TunnelHandler.Result result = srService.createTunnel(tunnel);
- switch (result) {
- case ID_EXISTS:
- print("ERROR: the same tunnel ID exists");
- break;
- case TUNNEL_EXISTS:
- print("ERROR: the same tunnel exists");
- break;
- case INTERNAL_ERROR:
- print("ERROR: internal tunnel creation error");
- break;
- case WRONG_PATH:
- print("ERROR: the tunnel path is wrong");
- break;
- default:
- break;
- }
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/TunnelListCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/TunnelListCommand.java
deleted file mode 100644
index 6c5f33d..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/TunnelListCommand.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2015-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.cli;
-
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-import org.onosproject.segmentrouting.Tunnel;
-
-/**
- * Command to show the list of tunnels.
- */
-@Service
-@Command(scope = "onos", name = "sr-tunnel-list",
- description = "Lists all tunnels")
-public class TunnelListCommand extends AbstractShellCommand {
-
- private static final String FORMAT_MAPPING =
- " id=%s, path=%s";
-
- @Override
- protected void doExecute() {
-
- SegmentRoutingService srService =
- AbstractShellCommand.get(SegmentRoutingService.class);
-
- srService.getTunnels().forEach(tunnel -> printTunnel(tunnel));
- }
-
- private void printTunnel(Tunnel tunnel) {
- print(FORMAT_MAPPING, tunnel.id(), tunnel.labelIds());
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/TunnelRemoveCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/TunnelRemoveCommand.java
deleted file mode 100644
index f5f0299..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/TunnelRemoveCommand.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2015-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.cli;
-
-
-import com.google.common.collect.Lists;
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.segmentrouting.DefaultTunnel;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-import org.onosproject.segmentrouting.Tunnel;
-import org.onosproject.segmentrouting.TunnelHandler;
-
-/**
- * Command to remove a tunnel.
- */
-@Service
-@Command(scope = "onos", name = "sr-tunnel-remove",
- description = "Remove a tunnel")
-public class TunnelRemoveCommand extends AbstractShellCommand {
-
- @Argument(index = 0, name = "tunnel ID",
- description = "tunnel ID",
- required = true, multiValued = false)
- String tunnelId;
-
- @Override
- protected void doExecute() {
- SegmentRoutingService srService =
- AbstractShellCommand.get(SegmentRoutingService.class);
-
- Tunnel tunnel = new DefaultTunnel(tunnelId, Lists.newArrayList());
- TunnelHandler.Result result = srService.removeTunnel(tunnel);
- switch (result) {
- case TUNNEL_IN_USE:
- print("ERROR: the tunnel is still in use");
- break;
- case TUNNEL_NOT_FOUND:
- print("ERROR: the tunnel is not found");
- break;
- default:
- break;
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/VerifyGroupsCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/VerifyGroupsCommand.java
deleted file mode 100644
index 385260e..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/VerifyGroupsCommand.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2017-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.cli;
-
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Completion;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.cli.net.DeviceIdCompleter;
-import org.onosproject.net.Device;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.device.DeviceService;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-
-/**
- * Triggers the verification of hashed group buckets in the specified device,
- * and corrects the buckets if necessary. Outcome can be viewed in the 'groups'
- * command.
- */
-@Service
-@Command(scope = "onos", name = "sr-verify-groups",
- description = "Triggers the verification of hashed groups in the specified "
- + "device. Does not return any output; users can query the results "
- + "in the 'groups' command")
-public class VerifyGroupsCommand extends AbstractShellCommand {
-
- @Argument(index = 0, name = "uri", description = "Device ID",
- required = true, multiValued = false)
- @Completion(DeviceIdCompleter.class)
- String uri = null;
-
- @Override
- protected void doExecute() {
- DeviceService deviceService = get(DeviceService.class);
- SegmentRoutingService srService =
- AbstractShellCommand.get(SegmentRoutingService.class);
-
- if (uri != null) {
- Device dev = deviceService.getDevice(DeviceId.deviceId(uri));
- if (dev != null) {
- srService.verifyGroups(dev.id());
- }
- }
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/XconnectAddCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/XconnectAddCommand.java
deleted file mode 100644
index 22daeb5..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/XconnectAddCommand.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2018-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.cli;
-
-import com.google.common.collect.Sets;
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Completion;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onlab.packet.VlanId;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.cli.PlaceholderCompleter;
-import org.onosproject.cli.net.DeviceIdCompleter;
-import org.onosproject.cli.net.PortNumberCompleter;
-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;
-
-/**
- * Creates Xconnect.
- */
-@Service
-@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)
- @Completion(DeviceIdCompleter.class)
- private String deviceIdStr;
-
- @Argument(index = 1, name = "vlanId",
- description = "VLAN ID",
- required = true, multiValued = false)
- @Completion(PlaceholderCompleter.class)
- private String vlanIdStr;
-
- @Argument(index = 2, name = "ep1",
- description = "First endpoint. " + EP_DESC,
- required = true, multiValued = false)
- @Completion(PortNumberCompleter.class)
- private String ep1Str;
-
- @Argument(index = 3, name = "ep2",
- description = "Second endpoint. " + EP_DESC,
- required = true, multiValued = false)
- @Completion(PortNumberCompleter.class)
- private String ep2Str;
-
- private static final String L2LB_PATTERN = "^(\\d*|L2LB\\(\\d*\\))$";
-
- @Override
- protected void doExecute() {
- DeviceId deviceId = DeviceId.deviceId(deviceIdStr);
- VlanId vlanId = VlanId.vlanId(vlanIdStr);
-
- 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, endpoints);
- }
-
-
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/XconnectListCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/XconnectListCommand.java
deleted file mode 100644
index 44a7d37..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/XconnectListCommand.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2018-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.cli;
-
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.segmentrouting.xconnect.api.XconnectService;
-
-/**
- * Lists Xconnects.
- */
-@Service
-@Command(scope = "onos", name = "sr-xconnect", description = "Lists all Xconnects")
-public class XconnectListCommand extends AbstractShellCommand {
- @Override
- protected void doExecute() {
- XconnectService xconnectService = get(XconnectService.class);
- xconnectService.getXconnects().forEach(desc -> print("%s", desc));
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/XconnectNextListCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/XconnectNextListCommand.java
deleted file mode 100644
index 0b81186..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/XconnectNextListCommand.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2018-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.cli;
-
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.segmentrouting.xconnect.api.XconnectKey;
-import org.onosproject.segmentrouting.xconnect.api.XconnectService;
-
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.Map;
-
-/**
- * Command to read the current state of the xconnect next stores.
- */
-@Service
-@Command(scope = "onos", name = "sr-next-xconnect",
- description = "Displays the current next-id for xconnect")
-public class XconnectNextListCommand extends AbstractShellCommand {
- @Override
- protected void doExecute() {
- XconnectService xconnectService =
- AbstractShellCommand.get(XconnectService.class);
- print(xconnectService.getNext());
- }
-
- private void print(Map<XconnectKey, Integer> nextStore) {
- ArrayList<XconnectKey> a = new ArrayList<>(nextStore.keySet());
- a.sort(Comparator
- .comparing((XconnectKey o) -> o.deviceId().toString())
- .thenComparing((XconnectKey o) -> o.vlanId().toShort()));
-
- StringBuilder builder = new StringBuilder();
- a.forEach(k ->
- builder.append("\n")
- .append(k)
- .append(" --> ")
- .append(nextStore.get(k))
- );
- print(builder.toString());
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/XconnectRemoveCommand.java b/app/src/main/java/org/onosproject/segmentrouting/cli/XconnectRemoveCommand.java
deleted file mode 100644
index e651338..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/XconnectRemoveCommand.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2018-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.cli;
-
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Completion;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onlab.packet.VlanId;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.cli.PlaceholderCompleter;
-import org.onosproject.cli.net.DeviceIdCompleter;
-import org.onosproject.net.DeviceId;
-import org.onosproject.segmentrouting.xconnect.api.XconnectService;
-
-/**
- * Deletes Xconnect.
- */
-@Service
-@Command(scope = "onos", name = "sr-xconnect-remove", description = "Remove Xconnect")
-public class XconnectRemoveCommand extends AbstractShellCommand {
- @Argument(index = 0, name = "deviceId",
- description = "Device ID",
- required = true, multiValued = false)
- @Completion(DeviceIdCompleter.class)
- private String deviceIdStr;
-
- @Argument(index = 1, name = "vlanId",
- description = "VLAN ID",
- required = true, multiValued = false)
- @Completion(PlaceholderCompleter.class)
- private String vlanIdStr;
-
- @Override
- protected void doExecute() {
- DeviceId deviceId = DeviceId.deviceId(deviceIdStr);
- VlanId vlanId = VlanId.vlanId(vlanIdStr);
-
- XconnectService xconnectService = get(XconnectService.class);
- xconnectService.removeXonnect(deviceId, vlanId);
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/cli/package-info.java b/app/src/main/java/org/onosproject/segmentrouting/cli/package-info.java
deleted file mode 100644
index 0f2cea6..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/cli/package-info.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2015-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.
- */
-
-/**
- * Segment routing application CLI handlers.
- */
-package org.onosproject.segmentrouting.cli;
\ No newline at end of file
diff --git a/app/src/main/java/org/onosproject/segmentrouting/config/DeviceConfiguration.java b/app/src/main/java/org/onosproject/segmentrouting/config/DeviceConfiguration.java
deleted file mode 100644
index d161f63..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/config/DeviceConfiguration.java
+++ /dev/null
@@ -1,878 +0,0 @@
-/*
- * Copyright 2015-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.config;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.node.ArrayNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Multimaps;
-import com.google.common.collect.SetMultimap;
-import com.google.common.collect.Sets;
-import org.onlab.packet.Ip4Address;
-import org.onlab.packet.Ip6Address;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.HostId;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.config.ConfigException;
-import org.onosproject.net.config.basics.BasicDeviceConfig;
-import org.onosproject.net.config.basics.InterfaceConfig;
-import org.onosproject.net.host.InterfaceIpAddress;
-import org.onosproject.net.intf.Interface;
-import org.onosproject.routeservice.Route;
-import org.onosproject.segmentrouting.SegmentRoutingManager;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-/**
- * Segment Routing configuration component that reads the
- * segment routing related configuration from Network Configuration Manager
- * component and organizes in more accessible formats.
- */
-public class DeviceConfiguration implements DeviceProperties {
-
- private static final String NO_SUBNET = "No subnet configured on {}";
-
- private static final Logger log = LoggerFactory.getLogger(DeviceConfiguration.class);
- private final List<Integer> allSegmentIds = new ArrayList<>();
- private final Map<DeviceId, SegmentRouterInfo> deviceConfigMap = new ConcurrentHashMap<>();
- private SegmentRoutingManager srManager;
-
- private class SegmentRouterInfo {
- int ipv4NodeSid = -1;
- int ipv6NodeSid = -1;
- DeviceId deviceId;
- Ip4Address ipv4Loopback;
- Ip6Address ipv6Loopback;
- MacAddress mac;
- boolean isEdge;
- SetMultimap<PortNumber, IpAddress> gatewayIps;
- SetMultimap<PortNumber, IpPrefix> subnets;
- Map<Integer, Set<Integer>> adjacencySids;
- DeviceId pairDeviceId;
- PortNumber pairLocalPort;
- int pwRoutingLabel;
-
- public SegmentRouterInfo() {
- gatewayIps = Multimaps.synchronizedSetMultimap(HashMultimap.create());
- subnets = Multimaps.synchronizedSetMultimap(HashMultimap.create());
- }
- }
-
- /**
- * Constructs device configuration for all Segment Router devices,
- * organizing the data into various maps for easier access.
- *
- * @param srManager Segment Routing Manager
- */
- public DeviceConfiguration(SegmentRoutingManager srManager) {
- this.srManager = srManager;
- updateConfig();
- }
-
- public void updateConfig() {
- // Read config from device subject, excluding gatewayIps and subnets.
- Set<DeviceId> deviceSubjects =
- srManager.cfgService.getSubjects(DeviceId.class, SegmentRoutingDeviceConfig.class);
- deviceSubjects.forEach(subject -> {
- BasicDeviceConfig basicDeviceConfig = srManager.cfgService.addConfig(subject, BasicDeviceConfig.class);
- if (!basicDeviceConfig.purgeOnDisconnection()) {
- // Setting purge on disconnection flag for the device SR has control over.
- // addConfig returns a config if it exists or creates a new one.
- log.info("PurgeOnDisconnection set to true for device {}", subject);
- basicDeviceConfig.purgeOnDisconnection(true);
- srManager.cfgService.applyConfig(subject, BasicDeviceConfig.class, basicDeviceConfig.node());
- }
- SegmentRoutingDeviceConfig config =
- srManager.cfgService.getConfig(subject, SegmentRoutingDeviceConfig.class);
- SegmentRouterInfo info = new SegmentRouterInfo();
- info.deviceId = subject;
- info.ipv4NodeSid = config.nodeSidIPv4();
- info.ipv6NodeSid = config.nodeSidIPv6();
- info.ipv4Loopback = config.routerIpv4();
- info.ipv6Loopback = config.routerIpv6();
- info.mac = config.routerMac();
- info.isEdge = config.isEdgeRouter();
- info.adjacencySids = config.adjacencySids();
- info.pairDeviceId = config.pairDeviceId();
- info.pairLocalPort = config.pairLocalPort();
- info.pwRoutingLabel = info.ipv4NodeSid + 1000;
- deviceConfigMap.put(info.deviceId, info);
- log.debug("Read device config for device: {}", info.deviceId);
- /*
- * IPv6 sid is not inserted. this part of the code is not used for now.
- */
- allSegmentIds.add(info.ipv4NodeSid);
- });
-
- // Read gatewayIps and subnets from port subject. Ignore suppressed ports.
- Set<ConnectPoint> portSubjects = srManager.cfgService
- .getSubjects(ConnectPoint.class, InterfaceConfig.class);
- portSubjects.stream()
- .filter(subject -> deviceConfigMap.containsKey(subject.deviceId()))
- .filter(subject -> !isSuppressedPort(subject)).forEach(subject -> {
- InterfaceConfig config =
- srManager.cfgService.getConfig(subject, InterfaceConfig.class);
- Set<Interface> networkInterfaces;
- try {
- networkInterfaces = config.getInterfaces();
- } catch (ConfigException e) {
- log.error("Error loading port configuration");
- return;
- }
- networkInterfaces.forEach(networkInterface -> {
- VlanId vlanId = networkInterface.vlan();
- ConnectPoint connectPoint = networkInterface.connectPoint();
- DeviceId dpid = connectPoint.deviceId();
- PortNumber port = connectPoint.port();
- MacAddress mac = networkInterface.mac();
- SegmentRouterInfo info = deviceConfigMap.get(dpid);
-
- // skip if there is no corresponding device for this ConenctPoint
- if (info != null) {
- // Extract subnet information
- List<InterfaceIpAddress> interfaceAddresses = networkInterface.ipAddressesList();
- interfaceAddresses.forEach(interfaceAddress -> {
- // Do not add /0, /32 and /128 to gateway IP list
- int prefixLength = interfaceAddress.subnetAddress().prefixLength();
- IpPrefix ipPrefix = interfaceAddress.subnetAddress();
- if (ipPrefix.isIp4()) {
- if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET_MASK_LENGTH) {
- info.gatewayIps.put(port, interfaceAddress.ipAddress());
- }
- info.subnets.put(port, interfaceAddress.subnetAddress());
- } else {
- if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET6_MASK_LENGTH) {
- info.gatewayIps.put(port, interfaceAddress.ipAddress());
- }
- info.subnets.put(port, interfaceAddress.subnetAddress());
- }
- });
-
- // Override interface mac with router mac
- if (!mac.equals(info.mac)) {
- ArrayNode array = (ArrayNode) config.node();
- for (JsonNode intfNode : array) {
- ObjectNode objNode = (ObjectNode) intfNode;
- objNode.put(InterfaceConfig.MAC, info.mac.toString());
- }
- srManager.cfgService.applyConfig(connectPoint, InterfaceConfig.class, array);
- }
- }
- });
- // We register the connect point with the NRS.
- srManager.registerConnectPoint(subject);
- });
- }
-
- public Collection<DeviceId> getRouters() {
- return deviceConfigMap.keySet();
- }
-
- @Override
- public boolean isConfigured(DeviceId deviceId) {
- return deviceConfigMap.get(deviceId) != null;
- }
-
- @Override
- public int getIPv4SegmentId(DeviceId deviceId) throws DeviceConfigNotFoundException {
- SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
- if (srinfo != null) {
- log.trace("getIPv4SegmentId for device{} is {}", deviceId, srinfo.ipv4NodeSid);
- return srinfo.ipv4NodeSid;
- } else {
- String message = "getIPv4SegmentId fails for device: " + deviceId + ".";
- throw new DeviceConfigNotFoundException(message);
- }
- }
-
- @Override
- public int getIPv6SegmentId(DeviceId deviceId) throws DeviceConfigNotFoundException {
- SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
- if (srinfo != null) {
- log.trace("getIPv6SegmentId for device{} is {}", deviceId, srinfo.ipv6NodeSid);
- return srinfo.ipv6NodeSid;
- } else {
- String message = "getIPv6SegmentId fails for device: " + deviceId + ".";
- throw new DeviceConfigNotFoundException(message);
- }
- }
-
- @Override
- public int getPWRoutingLabel(DeviceId deviceId) throws DeviceConfigNotFoundException {
- SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
- if (srinfo != null) {
- log.trace("pwRoutingLabel for device{} is {}", deviceId, srinfo.pwRoutingLabel);
- return srinfo.pwRoutingLabel;
- } else {
- String message = "getPWRoutingLabel fails for device: " + deviceId + ".";
- throw new DeviceConfigNotFoundException(message);
- }
- }
-
- /**
- * Returns the IPv4 Node segment id of a segment router given its Router mac address.
- *
- * @param routerMac router mac address
- * @return node segment id, or -1 if not found in config
- */
- public int getIPv4SegmentId(MacAddress routerMac) {
- for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
- deviceConfigMap.entrySet()) {
- if (entry.getValue().mac.equals(routerMac)) {
- return entry.getValue().ipv4NodeSid;
- }
- }
-
- return -1;
- }
-
- /**
- * Returns the IPv6 Node segment id of a segment router given its Router mac address.
- *
- * @param routerMac router mac address
- * @return node segment id, or -1 if not found in config
- */
- public int getIPv6SegmentId(MacAddress routerMac) {
- for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
- deviceConfigMap.entrySet()) {
- if (entry.getValue().mac.equals(routerMac)) {
- return entry.getValue().ipv6NodeSid;
- }
- }
-
- return -1;
- }
-
- /**
- * Returns the IPv4 Node segment id of a segment router given its Router ip address.
- *
- * @param routerAddress router ip address
- * @return node segment id, or -1 if not found in config
- */
- public int getIPv4SegmentId(Ip4Address routerAddress) {
- for (Map.Entry<DeviceId, SegmentRouterInfo> entry: deviceConfigMap.entrySet()) {
- Ip4Address ipv4Loopback = entry.getValue().ipv4Loopback;
- if (ipv4Loopback == null) {
- continue;
- }
- if (entry.getValue().ipv4Loopback.equals(routerAddress)) {
- if (entry.getValue().ipv4NodeSid == -1) {
- continue;
- }
- return entry.getValue().ipv4NodeSid;
- }
- }
-
- return -1;
- }
-
- /**
- * Returns the IPv6 Node segment id of a segment router given its Router ip address.
- *
- * @param routerAddress router ip address
- * @return node segment id, or -1 if not found in config
- */
- public int getIPv6SegmentId(Ip6Address routerAddress) {
- for (Map.Entry<DeviceId, SegmentRouterInfo> entry: deviceConfigMap.entrySet()) {
- Ip6Address ipv6Loopback = entry.getValue().ipv6Loopback;
- if (ipv6Loopback == null) {
- continue;
- }
- if (entry.getValue().ipv6Loopback.equals(routerAddress)) {
- if (entry.getValue().ipv6NodeSid == -1) {
- continue;
- }
- return entry.getValue().ipv6NodeSid;
- }
- }
-
- return -1;
- }
-
- @Override
- public MacAddress getDeviceMac(DeviceId deviceId) throws DeviceConfigNotFoundException {
- SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
- if (srinfo != null) {
- return srinfo.mac;
- } else {
- String message = "getDeviceMac fails for device: " + deviceId + ".";
- throw new DeviceConfigNotFoundException(message);
- }
- }
-
- @Override
- public Ip4Address getRouterIpv4(DeviceId deviceId) throws DeviceConfigNotFoundException {
- SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
- if (srinfo != null) {
- log.trace("getRouterIpv4 for device{} is {}", deviceId, srinfo.ipv4Loopback);
- return srinfo.ipv4Loopback;
- } else {
- String message = "getRouterIpv4 fails for device: " + deviceId + ".";
- throw new DeviceConfigNotFoundException(message);
- }
- }
-
- @Override
- public Ip6Address getRouterIpv6(DeviceId deviceId) throws DeviceConfigNotFoundException {
- SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
- if (srinfo != null) {
- log.trace("getRouterIpv6 for device{} is {}", deviceId, srinfo.ipv6Loopback);
- return srinfo.ipv6Loopback;
- } else {
- String message = "getRouterIpv6 fails for device: " + deviceId + ".";
- throw new DeviceConfigNotFoundException(message);
- }
- }
-
- /**
- * Gets router ip address based on the destination ip address.
- *
- * @param destIpAddress the destination ip address
- * @param routerDeviceId the device id
- * @return the ip address of the routes
- */
- public IpAddress getRouterIpAddress(IpAddress destIpAddress, DeviceId routerDeviceId) {
- IpAddress routerIpAddress;
- try {
- routerIpAddress = destIpAddress.isIp4() ? getRouterIpv4(routerDeviceId) :
- getRouterIpv6(routerDeviceId);
- } catch (DeviceConfigNotFoundException e) {
- routerIpAddress = null;
- }
- return routerIpAddress;
- }
-
- @Override
- public boolean isEdgeDevice(DeviceId deviceId) throws DeviceConfigNotFoundException {
- SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
- if (srinfo != null) {
- log.trace("isEdgeDevice for device{} is {}", deviceId, srinfo.isEdge);
- return srinfo.isEdge;
- } else {
- String message = "isEdgeDevice fails for device: " + deviceId + ".";
- throw new DeviceConfigNotFoundException(message);
- }
- }
-
- @Override
- public List<Integer> getAllDeviceSegmentIds() {
- return allSegmentIds;
- }
-
- @Override
- public Map<IpPrefix, List<PortNumber>> getSubnetPortsMap(DeviceId deviceId)
- throws DeviceConfigNotFoundException {
- SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
- if (srinfo == null) {
- String message = "getSubnetPortsMap fails for device: " + deviceId + ".";
- throw new DeviceConfigNotFoundException(message);
- }
- // Construct subnet-port mapping from port-subnet mapping
- SetMultimap<PortNumber, IpPrefix> portSubnetMap = srinfo.subnets;
- Map<IpPrefix, List<PortNumber>> subnetPortMap = new HashMap<>();
-
- portSubnetMap.entries().forEach(entry -> {
- PortNumber port = entry.getKey();
- IpPrefix subnet = entry.getValue();
-
- if (subnet.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH ||
- subnet.prefixLength() == IpPrefix.MAX_INET6_MASK_LENGTH) {
- return;
- }
-
- if (subnetPortMap.containsKey(subnet)) {
- subnetPortMap.get(subnet).add(port);
- } else {
- ArrayList<PortNumber> ports = new ArrayList<>();
- ports.add(port);
- subnetPortMap.put(subnet, ports);
- }
- });
- return subnetPortMap;
- }
-
- /**
- * Returns the device identifier or data plane identifier (dpid)
- * of a segment router given its segment id.
- *
- * @param sid segment id
- * @return deviceId device identifier
- */
- public DeviceId getDeviceId(int sid) {
- for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
- deviceConfigMap.entrySet()) {
- if (entry.getValue().ipv4NodeSid == sid ||
- entry.getValue().ipv6NodeSid == sid) {
- return entry.getValue().deviceId;
- }
- }
-
- return null;
- }
-
- /**
- * Returns the device identifier or data plane identifier (dpid)
- * of a segment router given its router ip address.
- *
- * @param ipAddress router ip address
- * @return deviceId device identifier
- */
- public DeviceId getDeviceId(Ip4Address ipAddress) {
- for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
- deviceConfigMap.entrySet()) {
- if (entry.getValue().ipv4Loopback.equals(ipAddress)) {
- return entry.getValue().deviceId;
- }
- }
-
- return null;
- }
-
- /**
- * Returns the device identifier or data plane identifier (dpid)
- * of a segment router given its router ipv6 address.
- *
- * @param ipAddress router ipv6 address
- * @return deviceId device identifier
- */
- public DeviceId getDeviceId(Ip6Address ipAddress) {
- for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
- deviceConfigMap.entrySet()) {
- if (entry.getValue().ipv6Loopback.equals(ipAddress)) {
- return entry.getValue().deviceId;
- }
- }
-
- return null;
- }
-
- /**
- * Returns the configured port ip addresses for a segment router.
- * These addresses serve as gateway IP addresses for the subnets configured
- * on those ports.
- *
- * @param deviceId device identifier
- * @return immutable set of ip addresses configured on the ports or null if not found
- */
- public Set<IpAddress> getPortIPs(DeviceId deviceId) {
- SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
- if (srinfo != null) {
- log.trace("getSubnetGatewayIps for device{} is {}", deviceId,
- srinfo.gatewayIps.values());
- return ImmutableSet.copyOf(srinfo.gatewayIps.values());
- }
- return null;
- }
-
- /**
- * Returns configured subnets for a segment router.
- *
- * @param deviceId device identifier
- * @return list of ip prefixes or null if not found
- */
- public Set<IpPrefix> getConfiguredSubnets(DeviceId deviceId) {
- Set<IpPrefix> subnets = srManager.interfaceService.getInterfaces().stream()
- .filter(intf -> Objects.equals(deviceId, intf.connectPoint().deviceId()))
- .flatMap(intf -> intf.ipAddressesList().stream())
- .map(InterfaceIpAddress::subnetAddress)
- .collect(Collectors.toSet());
-
- if (subnets.isEmpty()) {
- log.debug(NO_SUBNET, deviceId);
- return Collections.emptySet();
- }
- return subnets;
- }
-
- /**
- * Returns all subnets for a segment router, including subnets learnt from route service.
- *
- * @param deviceId device identifier
- * @return set of ip prefixes or null if not found
- * @deprecated use getBatchedSubnets(DeviceId deviceId) instead
- */
- @Deprecated
- public Set<IpPrefix> getSubnets(DeviceId deviceId) {
- SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
- if (srinfo != null && srinfo.subnets != null) {
- // Note: ImmutableSet.Builder.addAll calls the iterator of parameter internally,
- // which is not protected by SynchronizedCollection mutex.
- ImmutableSet.Builder<IpPrefix> builder = ImmutableSet.builder();
- srinfo.subnets.forEach((k, v) -> builder.add(v));
- return builder.build();
- }
- return null;
- }
-
- /**
- * Returns batches of all subnets reachable via given next hop
- * <p>
- * First batch includes FPM and STATIC routes
- * Second batch includes all other type of routes obtained from routeService, including DHCP routes.
- *
- * @param hostId next hop host id
- * @return list of subnet batches, each batch includes a set of prefixes.
- */
- // TODO Querying routeService directly may be expensive. Some kind of reverse lookup cache should be developed.
- public List<Set<IpPrefix>> getBatchedSubnets(HostId hostId) {
- Set<IpPrefix> high = Sets.newHashSet();
- Set<IpPrefix> low = Sets.newHashSet();
-
- srManager.routeService.getRouteTables().stream()
- .map(tableId -> srManager.routeService.getResolvedRoutes(tableId))
- .flatMap(Collection::stream)
- .forEach(resolvedRoute -> {
- // Continue if next hop is not what we are looking for
- if (!Objects.equals(hostId.mac(), resolvedRoute.nextHopMac()) ||
- !Objects.equals(hostId.vlanId(), resolvedRoute.nextHopVlan())) {
- return;
- }
- // Prioritize STATIC and FPM among others
- if (resolvedRoute.route().source() == Route.Source.STATIC ||
- resolvedRoute.route().source() == Route.Source.FPM) {
- high.add(resolvedRoute.prefix());
- } else {
- low.add(resolvedRoute.prefix());
- }
- });
- return Stream.of(high, low).filter(set -> !set.isEmpty()).collect(Collectors.toList());
- }
-
- /**
- * Returns batches of all subnets reachable on the given device.
- * <p>
- * First batch includes configured subnets, FPM and STATIC routes
- * Second batch includes all other type of routes obtained from routeService, including DHCP routes.
- *
- * @param deviceId device identifier
- * @return list of subnet batches, each batch includes a set of prefixes.
- */
- // TODO Querying routeService directly may be expensive. Some kind of reverse lookup cache should be developed.
- public List<Set<IpPrefix>> getBatchedSubnets(DeviceId deviceId) {
- Set<IpPrefix> high = Sets.newHashSet();
- Set<IpPrefix> low = Sets.newHashSet();
-
- high.addAll(getConfiguredSubnets(deviceId));
- srManager.routeService.getRouteTables().stream()
- .map(tableId -> srManager.routeService.getResolvedRoutes(tableId))
- .flatMap(Collection::stream)
- .forEach(resolvedRoute -> {
- // Continue to next resolved route if none of the next hop attaches to given device
- if (srManager.nextHopLocations(resolvedRoute).stream()
- .noneMatch(cp -> Objects.equals(deviceId, cp.deviceId()))) {
- return;
- }
- // Prioritize STATIC and FPM among others
- if (resolvedRoute.route().source() == Route.Source.STATIC ||
- resolvedRoute.route().source() == Route.Source.FPM) {
- high.add(resolvedRoute.prefix());
- } else {
- low.add(resolvedRoute.prefix());
- }
- });
- return Lists.newArrayList(high, low);
- }
-
- /**
- * Returns the subnet configuration of given device and port.
- *
- * @param deviceId Device ID
- * @param port Port number
- * @return The subnets configured on given port or empty set if
- * the port is unconfigured or suppressed.
- */
- public Set<IpPrefix> getPortSubnets(DeviceId deviceId, PortNumber port) {
- ConnectPoint connectPoint = new ConnectPoint(deviceId, port);
-
- if (isSuppressedPort(connectPoint)) {
- return Collections.emptySet();
- }
-
- Set<IpPrefix> subnets = srManager.interfaceService.getInterfacesByPort(connectPoint).stream()
- .flatMap(intf -> intf.ipAddressesList().stream())
- .map(InterfaceIpAddress::subnetAddress)
- .collect(Collectors.toSet());
-
- if (subnets.isEmpty()) {
- log.debug(NO_SUBNET, connectPoint);
- return Collections.emptySet();
- }
- return subnets;
- }
-
- /**
- * Returns all ports that has a subnet that contains any of the given IP addresses.
- *
- * @param ips a set of IP addresses
- * @return a set of connect point that has a subnet that contains any of the given IP addresses
- */
- public Set<ConnectPoint> getPortByIps(Set<IpAddress> ips) {
- return srManager.interfaceService.getInterfaces().stream()
- .filter(intf -> intf.ipAddressesList().stream().anyMatch(intfAddress ->
- ips.stream().anyMatch(ip -> intfAddress.subnetAddress().contains(ip))))
- .map(Interface::connectPoint)
- .collect(Collectors.toSet());
- }
-
- /**
- * Returns all the connect points of the segment routers that have the
- * specified ip address in their subnets.
- *
- * @param destIpAddress target ip address
- * @return connect points of the segment routers
- */
- public Set<ConnectPoint> getConnectPointsForASubnetHost(IpAddress destIpAddress) {
- return srManager.interfaceService.getMatchingInterfaces(destIpAddress).stream()
- .map(Interface::connectPoint)
- .collect(Collectors.toSet());
- }
-
- /**
- * Returns the router ip address of segment router that has the
- * specified ip address in its subnets.
- *
- * @param destIpAddress target ip address
- * @return router ip address
- */
- public Ip4Address getRouterIpAddressForASubnetHost(Ip4Address destIpAddress) {
- Interface matchIntf = srManager.interfaceService.getMatchingInterface(destIpAddress);
-
- if (matchIntf == null) {
- log.debug("No router was found for {}", destIpAddress);
- return null;
- }
-
- DeviceId routerDeviceId = matchIntf.connectPoint().deviceId();
- SegmentRouterInfo srInfo = deviceConfigMap.get(routerDeviceId);
- if (srInfo == null) {
- log.debug("No device config was found for {}", routerDeviceId);
- return null;
- }
-
- return srInfo.ipv4Loopback;
- }
-
- /**
- * Returns the router ipv6 address of segment router that has the
- * specified ip address in its subnets.
- *
- * @param destIpAddress target ip address
- * @return router ip address
- */
- public Ip6Address getRouterIpAddressForASubnetHost(Ip6Address destIpAddress) {
- Interface matchIntf = srManager.interfaceService.getMatchingInterface(destIpAddress);
-
- if (matchIntf == null) {
- log.debug("No router was found for {}", destIpAddress);
- return null;
- }
-
- DeviceId routerDeviceId = matchIntf.connectPoint().deviceId();
- SegmentRouterInfo srInfo = deviceConfigMap.get(routerDeviceId);
- if (srInfo == null) {
- log.debug("No device config was found for {}", routerDeviceId);
- return null;
- }
-
- return srInfo.ipv6Loopback;
- }
-
- /**
- * Returns the router mac address of segment router that has the
- * specified ip address as one of its subnet gateway ip address.
- *
- * @param gatewayIpAddress router gateway ip address
- * @return router mac address or null if not found
- */
- public MacAddress getRouterMacForAGatewayIp(IpAddress gatewayIpAddress) {
- for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
- deviceConfigMap.entrySet()) {
- if (entry.getValue().gatewayIps.
- values().contains(gatewayIpAddress)) {
- return entry.getValue().mac;
- }
- }
-
- log.debug("Cannot find a router for {}", gatewayIpAddress);
- return null;
- }
-
- /**
- * Checks if the host IP is in any of the subnet defined in the router with the
- * device ID given.
- *
- * @param deviceId device identification of the router
- * @param hostIp host IP address to check
- * @return true if the given IP is within any of the subnet defined in the router,
- * false if no subnet is defined in the router or if the host is not
- * within any subnet defined in the router
- */
- public boolean inSameSubnet(DeviceId deviceId, IpAddress hostIp) {
- Set<IpPrefix> subnets = getConfiguredSubnets(deviceId);
- if (subnets == null) {
- return false;
- }
-
- for (IpPrefix subnet: subnets) {
- // Exclude /0 since it is a special case used for default route
- if (subnet.prefixLength() != 0 && subnet.contains(hostIp)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Checks if the IP is in the subnet defined on given connect point.
- *
- * @param connectPoint Connect point
- * @param ip The IP address to check
- * @return True if the IP belongs to the subnet.
- * False if the IP does not belong to the subnet, or
- * there is no subnet configuration on given connect point.
- */
- public boolean inSameSubnet(ConnectPoint connectPoint, IpAddress ip) {
- return getPortSubnets(connectPoint.deviceId(), connectPoint.port()).stream()
- .anyMatch(ipPrefix -> ipPrefix.contains(ip));
- }
-
- /**
- * Returns the ports corresponding to the adjacency Sid given.
- *
- * @param deviceId device identification of the router
- * @param sid adjacency Sid
- * @return set of port numbers
- */
- public Set<Integer> getPortsForAdjacencySid(DeviceId deviceId, int sid) {
- SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
- return srinfo != null ?
- ImmutableSet.copyOf(srinfo.adjacencySids.get(sid)) :
- ImmutableSet.copyOf(new HashSet<>());
- }
-
- /**
- * Check if the Sid given is whether adjacency Sid of the router device or not.
- *
- * @param deviceId device identification of the router
- * @param sid Sid to check
- * @return true if the Sid given is the adjacency Sid of the device,
- * otherwise false
- */
- public boolean isAdjacencySid(DeviceId deviceId, int sid) {
- SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
- return srinfo != null && srinfo.adjacencySids.containsKey(sid);
- }
-
- /**
- * Add subnet to specific connect point.
- *
- * @param cp connect point
- * @param ipPrefix subnet being added to the device
- */
- public void addSubnet(ConnectPoint cp, IpPrefix ipPrefix) {
- checkNotNull(cp);
- checkNotNull(ipPrefix);
- SegmentRouterInfo srinfo = deviceConfigMap.get(cp.deviceId());
- if (srinfo == null) {
- log.warn("Device {} is not configured. Abort.", cp.deviceId());
- return;
- }
- srinfo.subnets.put(cp.port(), ipPrefix);
- }
-
- /**
- * Remove subnet from specific connect point.
- *
- * @param cp connect point
- * @param ipPrefix subnet being removed to the device
- */
- public void removeSubnet(ConnectPoint cp, IpPrefix ipPrefix) {
- checkNotNull(cp);
- checkNotNull(ipPrefix);
- SegmentRouterInfo srinfo = deviceConfigMap.get(cp.deviceId());
- if (srinfo == null) {
- log.warn("Device {} is not configured. Abort.", cp.deviceId());
- return;
- }
- srinfo.subnets.remove(cp.port(), ipPrefix);
- }
-
- private boolean isSuppressedPort(ConnectPoint connectPoint) {
- SegmentRoutingAppConfig appConfig = srManager.cfgService
- .getConfig(srManager.appId(), SegmentRoutingAppConfig.class);
- if (appConfig != null && appConfig.suppressSubnet().contains(connectPoint)) {
- log.info("Interface configuration on port {} is ignored", connectPoint);
- return true;
- }
- return false;
- }
-
- public boolean isPairedEdge(DeviceId deviceId) throws DeviceConfigNotFoundException {
- if (!isEdgeDevice(deviceId)) {
- return false;
- }
- SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
- return (srinfo.pairDeviceId == null) ? false : true;
- }
-
- public DeviceId getPairDeviceId(DeviceId deviceId) throws DeviceConfigNotFoundException {
- SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
- if (srinfo != null) {
- return srinfo.pairDeviceId;
- } else {
- String message = "getPairDeviceId fails for device: " + deviceId + ".";
- throw new DeviceConfigNotFoundException(message);
- }
- }
-
- public PortNumber getPairLocalPort(DeviceId deviceId)
- throws DeviceConfigNotFoundException {
- SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
- if (srinfo != null) {
- return srinfo.pairLocalPort;
- } else {
- String message = "getPairLocalPort fails for device: " + deviceId + ".";
- throw new DeviceConfigNotFoundException(message);
- }
- }
-
- public boolean isPairLocalPort(DeviceId devId, PortNumber pnum) {
- return pnum.equals(srManager.getPairLocalPort(devId).orElse(null));
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/config/package-info.java b/app/src/main/java/org/onosproject/segmentrouting/config/package-info.java
deleted file mode 100644
index a664a8f..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/config/package-info.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2015-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.
- */
-
-/**
- * Segment routing network configuration mechanism.
- */
-package org.onosproject.segmentrouting.config;
\ No newline at end of file
diff --git a/app/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java b/app/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
deleted file mode 100644
index f8d3053..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
+++ /dev/null
@@ -1,1794 +0,0 @@
-/*
- * Copyright 2015-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.grouphandler;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-
-import org.apache.commons.lang3.RandomUtils;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.MplsLabel;
-import org.onlab.packet.VlanId;
-import org.onlab.util.KryoNamespace;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Link;
-import org.onosproject.net.PortNumber;
-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.flowobjective.DefaultNextObjective;
-import org.onosproject.net.flowobjective.DefaultObjectiveContext;
-import org.onosproject.net.flowobjective.FlowObjectiveService;
-import org.onosproject.net.flowobjective.NextObjective;
-import org.onosproject.net.flowobjective.ObjectiveContext;
-import org.onosproject.net.link.LinkService;
-import org.onosproject.segmentrouting.DefaultRoutingHandler;
-import org.onosproject.segmentrouting.SegmentRoutingManager;
-import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
-import org.onosproject.segmentrouting.config.DeviceProperties;
-import org.onosproject.segmentrouting.config.DeviceConfiguration;
-import org.onosproject.segmentrouting.storekey.DestinationSetNextObjectiveStoreKey;
-import org.onosproject.segmentrouting.storekey.PortNextObjectiveStoreKey;
-import org.onosproject.segmentrouting.storekey.VlanNextObjectiveStoreKey;
-import org.onosproject.segmentrouting.storekey.MacVlanNextObjectiveStoreKey;
-import org.onosproject.store.service.EventuallyConsistentMap;
-import org.slf4j.Logger;
-
-import java.net.URI;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static java.util.concurrent.Executors.newScheduledThreadPool;
-import static org.onlab.util.Tools.groupedThreads;
-import static org.slf4j.LoggerFactory.getLogger;
-
-/**
- * Default ECMP group handler creation module. This component creates a set of
- * ECMP groups for every neighbor that this device is connected to based on
- * whether the current device is an edge device or a transit device.
- */
-public class DefaultGroupHandler {
- private static final Logger log = getLogger(DefaultGroupHandler.class);
-
- private static final long VERIFY_INTERVAL = 30; // secs
-
- protected final DeviceId deviceId;
- protected final ApplicationId appId;
- protected final DeviceProperties deviceConfig;
- protected final List<Integer> allSegmentIds;
- protected int ipv4NodeSegmentId = -1;
- protected int ipv6NodeSegmentId = -1;
- protected boolean isEdgeRouter = false;
- protected MacAddress nodeMacAddr = null;
- protected LinkService linkService;
- protected FlowObjectiveService flowObjectiveService;
- private DeviceConfiguration config;
-
- /**
- * local store for neighbor-device-ids and the set of ports on this device
- * that connect to the same neighbor.
- */
- protected ConcurrentHashMap<DeviceId, Set<PortNumber>> devicePortMap =
- new ConcurrentHashMap<>();
- /**
- * local store for ports on this device connected to neighbor-device-id.
- */
- protected ConcurrentHashMap<PortNumber, DeviceId> portDeviceMap =
- new ConcurrentHashMap<>();
-
- // distributed store for (device+destination-set) mapped to next-id and neighbors
- protected EventuallyConsistentMap<DestinationSetNextObjectiveStoreKey, NextNeighbors>
- dsNextObjStore = null;
- // distributed store for (device+subnet-ip-prefix) mapped to next-id
- protected EventuallyConsistentMap<VlanNextObjectiveStoreKey, Integer>
- vlanNextObjStore = null;
- // distributed store for (device+mac+vlan+treatment) mapped to next-id
- protected EventuallyConsistentMap<MacVlanNextObjectiveStoreKey, Integer>
- macVlanNextObjStore = null;
- // distributed store for (device+port+treatment) mapped to next-id
- protected EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
- portNextObjStore = null;
- private SegmentRoutingManager srManager;
-
- private ScheduledExecutorService executorService
- = newScheduledThreadPool(1, groupedThreads("bktCorrector", "bktC-%d", log));
-
- protected KryoNamespace.Builder kryo = new KryoNamespace.Builder()
- .register(URI.class).register(HashSet.class)
- .register(DeviceId.class).register(PortNumber.class)
- .register(DestinationSet.class).register(PolicyGroupIdentifier.class)
- .register(PolicyGroupParams.class)
- .register(GroupBucketIdentifier.class)
- .register(GroupBucketIdentifier.BucketOutputType.class);
-
- protected DefaultGroupHandler(DeviceId deviceId, ApplicationId appId,
- DeviceProperties config,
- LinkService linkService,
- FlowObjectiveService flowObjService,
- SegmentRoutingManager srManager) {
- this.deviceId = checkNotNull(deviceId);
- this.appId = checkNotNull(appId);
- this.deviceConfig = checkNotNull(config);
- this.linkService = checkNotNull(linkService);
- this.allSegmentIds = checkNotNull(config.getAllDeviceSegmentIds());
- try {
- this.ipv4NodeSegmentId = config.getIPv4SegmentId(deviceId);
- this.ipv6NodeSegmentId = config.getIPv6SegmentId(deviceId);
- this.isEdgeRouter = config.isEdgeDevice(deviceId);
- this.nodeMacAddr = checkNotNull(config.getDeviceMac(deviceId));
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage()
- + " Skipping value assignment in DefaultGroupHandler");
- }
- this.flowObjectiveService = flowObjService;
- this.dsNextObjStore = srManager.dsNextObjStore();
- this.vlanNextObjStore = srManager.vlanNextObjStore();
- this.portNextObjStore = srManager.portNextObjStore();
- this.macVlanNextObjStore = srManager.macVlanNextObjStore();
- this.srManager = srManager;
- executorService.scheduleWithFixedDelay(new BucketCorrector(), 10,
- VERIFY_INTERVAL,
- TimeUnit.SECONDS);
- populateNeighborMaps();
- }
-
- /**
- * Gracefully shuts down a groupHandler. Typically called when the handler is
- * no longer needed.
- */
- public void shutdown() {
- executorService.shutdown();
- }
-
- /**
- * Creates a group handler object.
- *
- * @param deviceId device identifier
- * @param appId application identifier
- * @param config interface to retrieve the device properties
- * @param linkService link service object
- * @param flowObjService flow objective service object
- * @param srManager segment routing manager
- * @throws DeviceConfigNotFoundException if the device configuration is not found
- * @return default group handler type
- */
- public static DefaultGroupHandler createGroupHandler(
- DeviceId deviceId,
- ApplicationId appId,
- DeviceProperties config,
- LinkService linkService,
- FlowObjectiveService flowObjService,
- SegmentRoutingManager srManager)
- throws DeviceConfigNotFoundException {
- return new DefaultGroupHandler(deviceId, appId, config,
- linkService,
- flowObjService,
- srManager);
- }
-
- /**
- * Updates local stores for link-src-device/port to neighbor (link-dst) for
- * link that has come up.
- *
- * @param link the infrastructure link
- */
- public void portUpForLink(Link link) {
- if (!link.src().deviceId().equals(deviceId)) {
- log.warn("linkUp: deviceId{} doesn't match with link src {}",
- deviceId, link.src().deviceId());
- return;
- }
-
- log.info("* portUpForLink: Device {} linkUp at local port {} to "
- + "neighbor {}", deviceId, link.src().port(), link.dst().deviceId());
- // ensure local state is updated even if linkup is aborted later on
- addNeighborAtPort(link.dst().deviceId(),
- link.src().port());
- }
-
- /**
- * Updates local stores for link-src-device/port to neighbor (link-dst) for
- * link that has gone down.
- *
- * @param link the infrastructure link
- */
- public void portDownForLink(Link link) {
- PortNumber port = link.src().port();
- if (portDeviceMap.get(port) == null) {
- log.warn("portDown: unknown port");
- return;
- }
-
- log.debug("Device {} portDown {} to neighbor {}", deviceId, port,
- portDeviceMap.get(port));
- devicePortMap.get(portDeviceMap.get(port)).remove(port);
- portDeviceMap.remove(port);
- }
-
- /**
- * Cleans up local stores for removed neighbor device.
- *
- * @param neighborId the device identifier for the neighbor device
- */
- public void cleanUpForNeighborDown(DeviceId neighborId) {
- Set<PortNumber> ports = devicePortMap.remove(neighborId);
- if (ports != null) {
- ports.forEach(p -> portDeviceMap.remove(p));
- }
- }
-
- /**
- * Checks all groups in the src-device of link for neighbor sets that include
- * the dst-device of link, and edits the hash groups according to link up
- * or down. Should only be called by the master instance of the src-switch
- * of link. Typically used when there are no route-path changes due to the
- * link up or down, as the ECMPspg does not change.
- *
- * @param link the infrastructure link that has gone down or come up
- * @param linkDown true if link has gone down
- * @param firstTime true if link has come up for the first time i.e a link
- * not seen-before
- */
- public void retryHash(Link link, boolean linkDown, boolean firstTime) {
- MacAddress neighborMac;
- try {
- neighborMac = deviceConfig.getDeviceMac(link.dst().deviceId());
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage() + " Aborting retryHash.");
- return;
- }
- // find all the destinationSets related to link
- Set<DestinationSetNextObjectiveStoreKey> dsKeySet = dsNextObjStore.entrySet()
- .stream()
- .filter(entry -> entry.getKey().deviceId().equals(deviceId))
- // Filter out PW transit groups or include them if MPLS ECMP is supported
- .filter(entry -> !entry.getKey().destinationSet().notBos() ||
- (entry.getKey().destinationSet().notBos() && srManager.getMplsEcmp()))
- // Filter out simple SWAP groups or include them if MPLS ECMP is supported
- .filter(entry -> !entry.getKey().destinationSet().swap() ||
- (entry.getKey().destinationSet().swap() && srManager.getMplsEcmp()))
- .filter(entry -> entry.getValue().containsNextHop(link.dst().deviceId()))
- .map(entry -> entry.getKey())
- .collect(Collectors.toSet());
-
- log.debug("retryHash: dsNextObjStore contents for linkSrc {} -> linkDst {}: {}",
- deviceId, link.dst().deviceId(), dsKeySet);
-
- for (DestinationSetNextObjectiveStoreKey dsKey : dsKeySet) {
- NextNeighbors nextHops = dsNextObjStore.get(dsKey);
- if (nextHops == null) {
- log.warn("retryHash in device {}, but global store has no record "
- + "for dsKey:{}", deviceId, dsKey);
- continue;
- }
- int nextId = nextHops.nextId();
- Set<DeviceId> dstSet = nextHops.getDstForNextHop(link.dst().deviceId());
- if (!linkDown) {
- List<PortLabel> pl = Lists.newArrayList();
- if (firstTime) {
- // some links may have come up before the next-objective was created
- // we take this opportunity to ensure other ports to same next-hop-dst
- // are part of the hash group (see CORD-1180). Duplicate additions
- // to the same hash group are avoided by the driver.
- for (PortNumber p : devicePortMap.get(link.dst().deviceId())) {
- dstSet.forEach(dst -> {
- int edgeLabel = dsKey.destinationSet().getEdgeLabel(dst);
- pl.add(new PortLabel(p, edgeLabel, popVlanInHashGroup(dsKey.destinationSet())));
- });
- }
- addToHashedNextObjective(pl, neighborMac, nextId);
- } else {
- // handle only the port that came up
- dstSet.forEach(dst -> {
- int edgeLabel = dsKey.destinationSet().getEdgeLabel(dst);
- pl.add(new PortLabel(link.src().port(), edgeLabel, popVlanInHashGroup(dsKey.destinationSet())));
- });
- addToHashedNextObjective(pl, neighborMac, nextId);
- }
- } else {
- // linkdown
- List<PortLabel> pl = Lists.newArrayList();
- dstSet.forEach(dst -> {
- int edgeLabel = dsKey.destinationSet().getEdgeLabel(dst);
- pl.add(new PortLabel(link.src().port(), edgeLabel, popVlanInHashGroup(dsKey.destinationSet())));
- });
- removeFromHashedNextObjective(pl, neighborMac, nextId);
- }
- }
- }
-
- /**
- * Utility class for associating output ports and the corresponding MPLS
- * labels to push. In dual-homing, there are different labels to push
- * corresponding to the destination switches in an edge-pair. If both
- * destinations are reachable via the same spine, then the output-port to
- * the spine will be associated with two labels i.e. there will be two
- * PortLabel objects for the same port but with different labels.
- */
- private class PortLabel {
- PortNumber port;
- int edgeLabel;
- boolean popVlan;
-
- PortLabel(PortNumber port, int edgeLabel, boolean popVlan) {
- this.port = port;
- this.edgeLabel = edgeLabel;
- this.popVlan = popVlan;
- }
-
- @Override
- public String toString() {
- return port.toString() + "/" + String.valueOf(edgeLabel) + (popVlan ? "/popVlan" : "");
- }
- }
-
- /**
- * Makes a call to the FlowObjective service to add buckets to
- * a hashed group. User must ensure that all the ports & labels are meant
- * same neighbor (ie. dstMac).
- *
- * @param portLabels a collection of port & label combinations to add
- * to the hash group identified by the nextId
- * @param dstMac destination mac address of next-hop
- * @param nextId id for next-objective to which buckets will be added
- *
- */
- private void addToHashedNextObjective(Collection<PortLabel> portLabels,
- MacAddress dstMac, Integer nextId) {
- // setup metadata to pass to nextObjective - indicate the vlan on egress
- // if needed by the switch pipeline. Since hashed next-hops are always to
- // other neighboring routers, there is no subnet assigned on those ports.
- TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
- metabuilder.matchVlanId(srManager.getDefaultInternalVlan());
- NextObjective.Builder nextObjBuilder = DefaultNextObjective.builder()
- .withId(nextId)
- .withType(NextObjective.Type.HASHED)
- .withMeta(metabuilder.build())
- .fromApp(appId);
- // Create the new buckets to be updated
- portLabels.forEach(pl -> {
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
- tBuilder.setOutput(pl.port)
- .setEthDst(dstMac)
- .setEthSrc(nodeMacAddr);
- if (pl.popVlan) {
- tBuilder.popVlan();
- }
- if (pl.edgeLabel != DestinationSet.NO_EDGE_LABEL) {
- tBuilder.pushMpls()
- .copyTtlOut()
- .setMpls(MplsLabel.mplsLabel(pl.edgeLabel));
- }
- nextObjBuilder.addTreatment(tBuilder.build());
- });
-
- log.debug("addToHash in device {}: Adding Bucket with port/label {} "
- + "to nextId {}", deviceId, portLabels, nextId);
-
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> log.debug("addToHash port/label {} addedTo "
- + "NextObj {} on {}", portLabels, nextId, deviceId),
- (objective, error) -> {
- log.warn("addToHash failed to add port/label {} to NextObj {} on {}: {}",
- portLabels, nextId, deviceId, error);
- srManager.invalidateNextObj(objective.id());
- });
- NextObjective nextObjective = nextObjBuilder.addToExisting(context);
- flowObjectiveService.next(deviceId, nextObjective);
- }
-
- /**
- * Makes a call to the FlowObjective service to remove buckets from
- * a hash group. User must ensure that all the ports & labels are meant
- * same neighbor (ie. dstMac).
- *
- * @param portLabels a collection of port & label combinations to remove
- * from the hash group identified by the nextId
- * @param dstMac destination mac address of next-hop
- * @param nextId id for next-objective from which buckets will be removed
- */
- private void removeFromHashedNextObjective(Collection<PortLabel> portLabels,
- MacAddress dstMac, Integer nextId) {
- TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
- metabuilder.matchVlanId(srManager.getDefaultInternalVlan());
- NextObjective.Builder nextObjBuilder = DefaultNextObjective
- .builder()
- .withType(NextObjective.Type.HASHED) //same as original
- .withMeta(metabuilder.build())
- .withId(nextId)
- .fromApp(appId);
- // Create the buckets to be removed
- portLabels.forEach(pl -> {
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
- tBuilder.setOutput(pl.port)
- .setEthDst(dstMac)
- .setEthSrc(nodeMacAddr);
- if (pl.popVlan) {
- tBuilder.popVlan();
- }
- if (pl.edgeLabel != DestinationSet.NO_EDGE_LABEL) {
- tBuilder.pushMpls()
- .copyTtlOut()
- .setMpls(MplsLabel.mplsLabel(pl.edgeLabel));
- }
- nextObjBuilder.addTreatment(tBuilder.build());
- });
- log.debug("removeFromHash in device {}: Removing Bucket with port/label"
- + " {} from nextId {}", deviceId, portLabels, nextId);
-
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> log.debug("port/label {} removedFrom NextObj"
- + " {} on {}", portLabels, nextId, deviceId),
- (objective, error) -> {
- log.warn("port/label {} failed to removeFrom NextObj {} on {}: {}",
- portLabels, nextId, deviceId, error);
- srManager.invalidateNextObj(objective.id());
- });
- NextObjective nextObjective = nextObjBuilder.removeFromExisting(context);
- flowObjectiveService.next(deviceId, nextObjective);
- }
-
- /**
- * Checks all the hash-groups in the target-switch meant for the destination
- * switch, and either adds or removes buckets to make the neighbor-set
- * match the given next-hops. Typically called by the master instance of the
- * destination switch, which may be different from the master instance of the
- * target switch where hash-group changes are made.
- *
- * @param targetSw the switch in which the hash groups will be edited
- * @param nextHops the current next hops for the target switch to reach
- * the dest sw
- * @param destSw the destination switch
- * @param revoke true if hash groups need to remove buckets from the
- * the groups to match the current next hops
- * @return true if calls are made to edit buckets, or if no edits are required
- */
- public boolean fixHashGroups(DeviceId targetSw, Set<DeviceId> nextHops,
- DeviceId destSw, boolean revoke) {
- // temporary storage of keys to be updated
- Map<DestinationSetNextObjectiveStoreKey, Set<DeviceId>> tempStore =
- new HashMap<>();
- boolean foundNextObjective = false, success = true;
-
- // retrieve hash-groups meant for destSw, which have destinationSets
- // with different neighbors than the given next-hops
- for (DestinationSetNextObjectiveStoreKey dskey : dsNextObjStore.keySet()) {
- if (!dskey.deviceId().equals(targetSw) ||
- !dskey.destinationSet().getDestinationSwitches().contains(destSw)) {
- continue;
- }
- foundNextObjective = true;
- NextNeighbors nhops = dsNextObjStore.get(dskey);
- Set<DeviceId> currNeighbors = nhops.nextHops(destSw);
- int edgeLabel = dskey.destinationSet().getEdgeLabel(destSw);
- Integer nextId = nhops.nextId();
- if (currNeighbors == null || nextHops == null) {
- log.warn("fixing hash groups but found currNeighbors:{} or nextHops:{}"
- + " in targetSw:{} for dstSw:{}", currNeighbors,
- nextHops, targetSw, destSw);
- success &= false;
- continue;
- }
-
- // some store elements may not be hashed next-objectives - ignore them
- if (isSimpleNextObjective(dskey)) {
- log.debug("Ignoring {} of SIMPLE nextObj for targetSw:{}"
- + " -> dstSw:{} with current nextHops:{} to new"
- + " nextHops: {} in nextId:{}",
- (revoke) ? "removal" : "addition", targetSw, destSw,
- currNeighbors, nextHops, nextId);
- if ((revoke && !nextHops.isEmpty())
- || (!revoke && !nextHops.equals(currNeighbors))) {
- log.debug("Simple next objective cannot be edited to "
- + "move from {} to {}", currNeighbors, nextHops);
- }
- continue;
- }
-
- Set<DeviceId> diff;
- if (revoke) {
- diff = Sets.difference(currNeighbors, nextHops);
- log.debug("targetSw:{} -> dstSw:{} in nextId:{} has current next "
- + "hops:{} ..removing {}", targetSw, destSw, nextId,
- currNeighbors, diff);
- } else {
- diff = Sets.difference(nextHops, currNeighbors);
- log.debug("targetSw:{} -> dstSw:{} in nextId:{} has current next "
- + "hops:{} ..adding {}", targetSw, destSw, nextId,
- currNeighbors, diff);
- }
- boolean suc = updateAllPortsToNextHop(diff, edgeLabel, nextId, popVlanInHashGroup(dskey.destinationSet()),
- revoke);
- if (suc) {
- // to update neighbor set with changes made
- if (revoke) {
- tempStore.put(dskey, Sets.difference(currNeighbors, diff));
- } else {
- tempStore.put(dskey, Sets.union(currNeighbors, diff));
- }
- }
- success &= suc;
- }
-
- if (!foundNextObjective) {
- log.debug("Cannot find any nextObjectives for route targetSw:{} "
- + "-> dstSw:{}", targetSw, destSw);
- return false; // nothing to do, return false so re-route will be performed
- }
-
- // update the dsNextObjectiveStore with new destinationSet to nextId mappings
- for (DestinationSetNextObjectiveStoreKey key : tempStore.keySet()) {
- NextNeighbors currentNextHops = dsNextObjStore.get(key);
- if (currentNextHops == null) {
- log.warn("fixHashGroups could not update global store in "
- + "device {} .. missing nextNeighbors for key {}",
- deviceId, key);
- continue;
- }
- Set<DeviceId> newNeighbors = new HashSet<>();
- newNeighbors.addAll(tempStore.get(key));
- Map<DeviceId, Set<DeviceId>> oldDstNextHops =
- ImmutableMap.copyOf(currentNextHops.dstNextHops());
- currentNextHops.dstNextHops().put(destSw, newNeighbors); //local change
- log.debug("Updating nsNextObjStore target:{} -> dst:{} in key:{} nextId:{}",
- targetSw, destSw, key, currentNextHops.nextId());
- log.debug("Old dstNextHops: {}", oldDstNextHops);
- log.debug("New dstNextHops: {}", currentNextHops.dstNextHops());
- // update global store
- dsNextObjStore.put(key,
- new NextNeighbors(currentNextHops.dstNextHops(),
- currentNextHops.nextId()));
- }
-
- // even if one fails and others succeed, return false so ECMPspg not updated
- return success;
- }
-
- /**
- * Updates the DestinationSetNextObjectiveStore with any per-destination nexthops
- * that are not already in the store for the given DestinationSet. Note that
- * this method does not remove existing next hops for the destinations in the
- * DestinationSet.
- *
- * @param ds the DestinationSet for which the next hops need to be updated
- * @param newDstNextHops a map of per-destination next hops to update the
- * destinationSet with
- * @return true if successful in updating all next hops
- */
- private boolean updateNextHops(DestinationSet ds,
- Map<DeviceId, Set<DeviceId>> newDstNextHops) {
- DestinationSetNextObjectiveStoreKey key =
- new DestinationSetNextObjectiveStoreKey(deviceId, ds);
- NextNeighbors currNext = dsNextObjStore.get(key);
- Map<DeviceId, Set<DeviceId>> currDstNextHops = currNext.dstNextHops();
-
- // add newDstNextHops to currDstNextHops for each dst
- boolean success = true;
- for (DeviceId dstSw : ds.getDestinationSwitches()) {
- Set<DeviceId> currNhops = currDstNextHops.get(dstSw);
- Set<DeviceId> newNhops = newDstNextHops.get(dstSw);
- currNhops = (currNhops == null) ? Sets.newHashSet() : currNhops;
- newNhops = (newNhops == null) ? Sets.newHashSet() : newNhops;
- int edgeLabel = ds.getEdgeLabel(dstSw);
- int nextId = currNext.nextId();
-
- // new next hops should be added
- boolean suc = updateAllPortsToNextHop(Sets.difference(newNhops, currNhops),
- edgeLabel, nextId, popVlanInHashGroup(key.destinationSet()), false);
- if (suc) {
- currNhops.addAll(newNhops);
- currDstNextHops.put(dstSw, currNhops); // this is only a local change
- }
- success &= suc;
- }
-
- if (success) {
- // update global store
- dsNextObjStore.put(key, new NextNeighbors(currDstNextHops,
- currNext.nextId()));
- log.debug("Updated device:{} ds:{} new next-hops: {}", deviceId, ds,
- dsNextObjStore.get(key));
- }
- return success;
- }
-
- /**
- * Adds or removes buckets for all ports to a set of neighbor devices. Caller
- * needs to ensure that the given neighbors are all next hops towards the
- * same destination (represented by the given edgeLabel).
- *
- * @param neighbors set of neighbor device ids
- * @param edgeLabel MPLS label to use in buckets
- * @param nextId the nextObjective to change
- * @param popVlan this hash group bucket shuold includes a popVlan action
- * @param revoke true if buckets need to be removed, false if they need to
- * be added
- * @return true if successful in adding or removing buckets for all ports
- * to the neighbors
- */
- private boolean updateAllPortsToNextHop(Set<DeviceId> neighbors, int edgeLabel,
- int nextId, boolean popVlan, boolean revoke) {
- for (DeviceId neighbor : neighbors) {
- MacAddress neighborMac;
- try {
- neighborMac = deviceConfig.getDeviceMac(neighbor);
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage() + " Aborting updateAllPortsToNextHop"
- + " for nextId:" + nextId);
- return false;
- }
- Collection<PortNumber> portsToNeighbor = devicePortMap.get(neighbor);
- if (portsToNeighbor == null || portsToNeighbor.isEmpty()) {
- log.warn("No ports found in dev:{} for neighbor:{} .. cannot "
- + "updateAllPortsToNextHop for nextId: {}",
- deviceId, neighbor, nextId);
- return false;
- }
- List<PortLabel> pl = Lists.newArrayList();
- portsToNeighbor.forEach(p -> pl.add(new PortLabel(p, edgeLabel, popVlan)));
- if (revoke) {
- log.debug("updateAllPortsToNextHops in device {}: Removing Bucket(s) "
- + "with Port/Label:{} to next object id {}",
- deviceId, pl, nextId);
- removeFromHashedNextObjective(pl, neighborMac, nextId);
- } else {
- log.debug("fixHashGroup in device {}: Adding Bucket(s) "
- + "with Port/Label: {} to next object id {}",
- deviceId, pl, nextId);
- addToHashedNextObjective(pl, neighborMac, nextId);
- }
- }
- return true;
- }
-
- /**
- * Returns true if the destination set is meant for swap or multi-labeled
- * packet transport, and MPLS ECMP is not supported.
- *
- * @param dskey the key representing the destination set
- * @return true if destination set is meant for simple next objectives
- */
- boolean isSimpleNextObjective(DestinationSetNextObjectiveStoreKey dskey) {
- return (dskey.destinationSet().notBos() || dskey.destinationSet().swap())
- && !srManager.getMplsEcmp();
- }
-
- /**
- * 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 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 popVlan, boolean portUp) {
- //get the next id for the subnet and edit it.
- Integer nextId = getVlanNextObjectiveId(vlanId);
- if (nextId == -1) {
- if (portUp) {
- log.debug("**Creating flooding group for first port enabled in"
- + " vlan {} on dev {} port {}", vlanId, deviceId, port);
- createBcastGroupFromVlan(vlanId, Collections.singleton(port));
- } else {
- log.warn("Could not find flooding group for subnet {} on dev:{} when"
- + " removing port:{}", vlanId, deviceId, port);
- }
- return;
- }
-
- log.info("**port{} in device {}: {} Bucket with Port {} to"
- + " next-id {}", (portUp) ? "UP" : "DOWN", deviceId,
- (portUp) ? "Adding" : "Removing",
- port, nextId);
- // Create the bucket to be added or removed
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
- if (popVlan) {
- tBuilder.popVlan();
- }
- tBuilder.setOutput(port);
-
- TrafficSelector metadata =
- DefaultTrafficSelector.builder().matchVlanId(vlanId).build();
-
- NextObjective.Builder nextObjBuilder = DefaultNextObjective
- .builder().withId(nextId)
- .withType(NextObjective.Type.BROADCAST).fromApp(appId)
- .addTreatment(tBuilder.build())
- .withMeta(metadata);
-
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> log.debug("port {} successfully {} NextObj {} on {}",
- port, (portUp) ? "addedTo" : "removedFrom",
- nextId, deviceId),
- (objective, error) -> {
- log.warn("port {} failed to {} NextObj {} on {}: {}",
- port, (portUp) ? "addTo" : "removeFrom", nextId, deviceId, error);
- srManager.invalidateNextObj(objective.id());
- });
-
- NextObjective nextObj = (portUp) ? nextObjBuilder.addToExisting(context)
- : nextObjBuilder.removeFromExisting(context);
- log.debug("edgePort processed: Submited next objective {} in device {}",
- nextId, deviceId);
- flowObjectiveService.next(deviceId, nextObj);
- }
-
- /**
- * Returns the next objective of type hashed (or simple) associated with the
- * destination set. In addition, updates the existing next-objective if new
- * route-paths found have resulted in the addition of new next-hops to a
- * particular destination. If there is no existing next objective for this
- * destination set, this method would create a next objective and return the
- * nextId. Optionally metadata can be passed in for the creation of the next
- * objective. If the parameter simple is true then a simple next objective
- * is created instead of a hashed one.
- *
- * @param ds destination set
- * @param nextHops a map of per destination next hops
- * @param meta metadata passed into the creation of a Next Objective
- * @param simple if true, a simple next objective will be created instead of
- * a hashed next objective
- * @return int if found or -1 if there are errors in the creation of the
- * neighbor set.
- */
- public int getNextObjectiveId(DestinationSet ds,
- Map<DeviceId, Set<DeviceId>> nextHops,
- TrafficSelector meta, boolean simple) {
- NextNeighbors next = dsNextObjStore.
- get(new DestinationSetNextObjectiveStoreKey(deviceId, ds));
- if (next == null) {
- log.debug("getNextObjectiveId in device{}: Next objective id "
- + "not found for {} ... creating", deviceId, ds);
- log.trace("getNextObjectiveId: nsNextObjStore contents for device {}: {}",
- deviceId,
- dsNextObjStore.entrySet()
- .stream()
- .filter((nsStoreEntry) ->
- (nsStoreEntry.getKey().deviceId().equals(deviceId)))
- .collect(Collectors.toList()));
-
- createGroupFromDestinationSet(ds, nextHops, meta, simple);
- next = dsNextObjStore.
- get(new DestinationSetNextObjectiveStoreKey(deviceId, ds));
- if (next == null) {
- log.warn("getNextObjectiveId: unable to create next objective");
- // failure in creating group
- return -1;
- } else {
- log.debug("getNextObjectiveId in device{}: Next objective id {} "
- + "created for {}", deviceId, next.nextId(), ds);
- }
- } else {
- log.trace("getNextObjectiveId in device{}: Next objective id {} "
- + "found for {}", deviceId, next.nextId(), ds);
- // should fix hash groups too if next-hops have changed
- if (!next.dstNextHops().equals(nextHops)) {
- log.debug("Nexthops have changed for dev:{} nextId:{} ..updating",
- deviceId, next.nextId());
- if (!updateNextHops(ds, nextHops)) {
- // failure in updating group
- return -1;
- }
- }
- }
- return next.nextId();
- }
-
- /**
- * Returns the next objective of type broadcast associated with the vlan,
- * or -1 if no such objective exists. Note that this method does NOT create
- * the next objective as a side-effect. It is expected that is objective is
- * created at startup from network configuration. Typically this is used
- * for L2 flooding within the subnet configured on the switch.
- *
- * @param vlanId vlan id
- * @return int if found or -1
- */
- public int getVlanNextObjectiveId(VlanId vlanId) {
- Integer nextId = vlanNextObjStore.
- get(new VlanNextObjectiveStoreKey(deviceId, vlanId));
-
- return (nextId != null) ? nextId : -1;
- }
-
- /**
- * Returns the next objective of type simple associated with the mac/vlan on the
- * device, given the treatment. Different treatments to the same mac/vlan result
- * in different next objectives. If no such objective exists, this method
- * creates one (if requested) and returns the id. Optionally metadata can be passed in for
- * the creation of the objective. Typically this is used for L2 and L3 forwarding
- * to compute nodes and containers/VMs on the compute nodes directly attached
- * to the switch.
- *
- * @param macAddr the mac addr for the simple next objective
- * @param vlanId the vlan for the simple next objective
- * @param port port with which to create the Next Obj.
- * @param createIfMissing true if a next object should be created if not found
- * @return int if found or created, -1 if there are errors during the
- * creation of the next objective.
- */
- public int getMacVlanNextObjectiveId(MacAddress macAddr, VlanId vlanId, PortNumber port,
- boolean createIfMissing) {
-
- Integer nextId = macVlanNextObjStore
- .get(new MacVlanNextObjectiveStoreKey(deviceId, macAddr, vlanId));
-
- if (nextId != null) {
- return nextId;
- }
-
- log.debug("getMacVlanNextObjectiveId in device {}: Next objective id "
- + "not found for host : {}/{} .. {}", deviceId, macAddr, vlanId,
- (createIfMissing) ? "creating" : "aborting");
-
- if (!createIfMissing) {
- return -1;
- }
-
- MacAddress deviceMac;
- try {
- deviceMac = deviceConfig.getDeviceMac(deviceId);
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage() + " in getMacVlanNextObjectiveId");
- return -1;
- }
-
- // since we are creating now, port cannot be null
- if (port == null) {
- log.debug("getMacVlanNextObjectiveId : port information cannot be null "
- + "for device {}, host {}/{}", deviceId, macAddr, vlanId);
- return -1;
- }
-
- TrafficSelector.Builder meta = DefaultTrafficSelector.builder();
-
- TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
- treatment.deferred()
- .setEthDst(macAddr)
- .setEthSrc(deviceMac)
- .setOutput(port);
-
- ConnectPoint connectPoint = new ConnectPoint(deviceId, port);
- VlanId untaggedVlan = srManager.interfaceService.getUntaggedVlanId(connectPoint);
- Set<VlanId> taggedVlans = srManager.interfaceService.getTaggedVlanId(connectPoint);
- VlanId nativeVlan = srManager.interfaceService.getNativeVlanId(connectPoint);
-
- // Adjust the meta according to VLAN configuration
- if (taggedVlans.contains(vlanId)) {
- treatment.setVlanId(vlanId);
- } else if (vlanId.equals(VlanId.NONE)) {
- if (untaggedVlan != null) {
- meta.matchVlanId(untaggedVlan);
- } else if (nativeVlan != null) {
- meta.matchVlanId(nativeVlan);
- } else {
- log.warn("Untagged nexthop {}/{} is not allowed on {} without untagged or native vlan",
- macAddr, vlanId, connectPoint);
- return -1;
- }
- } else {
- log.warn("Tagged nexthop {}/{} is not allowed on {} without VLAN listed"
- + " in tagged vlan", macAddr, vlanId, connectPoint);
- return -1;
- }
-
- /* create missing next objective */
- nextId = createGroupFromMacVlan(macAddr, vlanId, treatment.build(), meta.build());
- if (nextId == null) {
- log.warn("getMacVlanNextObjectiveId: unable to create next obj"
- + "for dev:{} host:{}/{}", deviceId, macAddr, vlanId);
- return -1;
- }
- return nextId;
- }
-
-
- /**
- * Returns the next objective of type simple associated with the port on the
- * device, given the treatment. Different treatments to the same port result
- * in different next objectives. If no such objective exists, this method
- * creates one (if requested) and returns the id. Optionally metadata can be passed in for
- * the creation of the objective. Typically this is used for L2 and L3 forwarding
- * to compute nodes and containers/VMs on the compute nodes directly attached
- * to the switch.
- *
- * @param portNum the port number for the simple next objective
- * @param treatment the actions to apply on the packets (should include outport)
- * @param meta optional metadata passed into the creation of the next objective
- * @param createIfMissing true if a next object should be created if not found
- * @return int if found or created, -1 if there are errors during the
- * creation of the next objective.
- */
- public int getPortNextObjectiveId(PortNumber portNum, TrafficTreatment treatment,
- TrafficSelector meta, boolean createIfMissing) {
- Integer nextId = portNextObjStore
- .get(new PortNextObjectiveStoreKey(deviceId, portNum, treatment, meta));
- if (nextId != null) {
- return nextId;
- }
- log.debug("getPortNextObjectiveId in device {}: Next objective id "
- + "not found for port: {} .. {}", deviceId, portNum,
- (createIfMissing) ? "creating" : "aborting");
- if (!createIfMissing) {
- return -1;
- }
- // create missing next objective
- createGroupFromPort(portNum, treatment, meta);
- nextId = portNextObjStore.get(new PortNextObjectiveStoreKey(deviceId, portNum,
- treatment, meta));
- if (nextId == null) {
- log.warn("getPortNextObjectiveId: unable to create next obj"
- + "for dev:{} port:{}", deviceId, portNum);
- return -1;
- }
- return nextId;
- }
-
- /**
- * Checks if the next objective ID (group) for the neighbor set exists or not.
- *
- * @param ns neighbor set to check
- * @return true if it exists, false otherwise
- */
- public boolean hasNextObjectiveId(DestinationSet ns) {
- NextNeighbors nextHops = dsNextObjStore.
- get(new DestinationSetNextObjectiveStoreKey(deviceId, ns));
- if (nextHops == null) {
- return false;
- }
-
- return true;
- }
-
- private void populateNeighborMaps() {
- Set<Link> outgoingLinks = linkService.getDeviceEgressLinks(deviceId);
- for (Link link : outgoingLinks) {
- if (link.type() != Link.Type.DIRECT) {
- continue;
- }
- addNeighborAtPort(link.dst().deviceId(), link.src().port());
- }
- }
-
- protected void addNeighborAtPort(DeviceId neighborId,
- PortNumber portToNeighbor) {
- // Update DeviceToPort database
- log.debug("Device {} addNeighborAtPort: neighbor {} at port {}",
- deviceId, neighborId, portToNeighbor);
- Set<PortNumber> ports = Collections
- .newSetFromMap(new ConcurrentHashMap<PortNumber, Boolean>());
- ports.add(portToNeighbor);
- Set<PortNumber> portnums = devicePortMap.putIfAbsent(neighborId, ports);
- if (portnums != null) {
- portnums.add(portToNeighbor);
- }
-
- // Update portToDevice database
- // should always update as neighbor could have changed on this port
- DeviceId prev = portDeviceMap.put(portToNeighbor, neighborId);
- if (prev != null) {
- log.warn("Device/port: {}/{} previous neighbor: {}, current neighbor: {} ",
- deviceId, portToNeighbor, prev, neighborId);
- }
- }
-
- /**
- * Creates a NextObjective for a hash group in this device from a given
- * DestinationSet. If the parameter simple is true, a simple next objective
- * is created instead.
- *
- * @param ds the DestinationSet
- * @param neighbors a map for each destination and its next-hops
- * @param meta metadata passed into the creation of a Next Objective
- * @param simple if true, a simple next objective will be created instead of
- * a hashed next objective
- */
- public void createGroupFromDestinationSet(DestinationSet ds,
- Map<DeviceId, Set<DeviceId>> neighbors,
- TrafficSelector meta,
- boolean simple) {
- int nextId = flowObjectiveService.allocateNextId();
- NextObjective.Type type = (simple) ? NextObjective.Type.SIMPLE
- : NextObjective.Type.HASHED;
- if (neighbors == null || neighbors.isEmpty()) {
- log.warn("createGroupsFromDestinationSet: needs at least one neighbor"
- + "to create group in dev:{} for ds: {} with next-hops {}",
- deviceId, ds, neighbors);
- return;
- }
-
- NextObjective.Builder nextObjBuilder = DefaultNextObjective
- .builder()
- .withId(nextId)
- .withType(type)
- .fromApp(appId);
- if (meta != null) {
- nextObjBuilder.withMeta(meta);
- }
-
- // create treatment buckets for each neighbor for each dst Device
- // except in the special case where we only want to pick a single
- // neighbor/port for a simple nextObj
- boolean foundSingleNeighbor = false;
- boolean treatmentAdded = false;
- Map<DeviceId, Set<DeviceId>> dstNextHops = new ConcurrentHashMap<>();
- for (DeviceId dst : ds.getDestinationSwitches()) {
- Set<DeviceId> nextHops = neighbors.get(dst);
- if (nextHops == null || nextHops.isEmpty()) {
- continue;
- }
-
- if (foundSingleNeighbor) {
- break;
- }
-
- for (DeviceId neighborId : nextHops) {
- if (devicePortMap.get(neighborId) == null) {
- log.warn("Neighbor {} is not in the port map yet for dev:{}",
- neighborId, deviceId);
- return;
- } else if (devicePortMap.get(neighborId).isEmpty()) {
- log.warn("There are no ports for "
- + "the Device {} in the port map yet", neighborId);
- return;
- }
-
- MacAddress neighborMac;
- try {
- neighborMac = deviceConfig.getDeviceMac(neighborId);
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage() + " Aborting createGroupsFromDestinationset.");
- return;
- }
- // For each port to the neighbor, we create a new treatment
- Set<PortNumber> neighborPorts = devicePortMap.get(neighborId);
- // In this case we need a SIMPLE nextObj. We randomly pick a port
- if (simple) {
- int size = devicePortMap.get(neighborId).size();
- int index = RandomUtils.nextInt(0, size);
- neighborPorts = Collections.singleton(
- Iterables.get(devicePortMap.get(neighborId),
- index));
- foundSingleNeighbor = true;
- }
-
- for (PortNumber sp : neighborPorts) {
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
- .builder();
- tBuilder.setEthDst(neighborMac).setEthSrc(nodeMacAddr);
- int edgeLabel = ds.getEdgeLabel(dst);
- if (edgeLabel != DestinationSet.NO_EDGE_LABEL) {
- if (simple) {
- // swap label case
- tBuilder.setMpls(MplsLabel.mplsLabel(edgeLabel));
- } else {
- // ecmp with label push case
- tBuilder.pushMpls().copyTtlOut()
- .setMpls(MplsLabel.mplsLabel(edgeLabel));
- }
- }
-
- // Set VLAN ID for PW transport. Otherwise pop vlan
- if (!popVlanInHashGroup(ds)) {
- tBuilder.setVlanId(srManager.getPwTransportVlan());
- } else {
- tBuilder.popVlan();
- }
-
- tBuilder.setOutput(sp);
- nextObjBuilder.addTreatment(tBuilder.build());
- treatmentAdded = true;
- //update store
- Set<DeviceId> existingNeighbors = dstNextHops.get(dst);
- if (existingNeighbors == null) {
- existingNeighbors = new HashSet<>();
- }
- existingNeighbors.add(neighborId);
- dstNextHops.put(dst, existingNeighbors);
- log.debug("creating treatment for port/label {}/{} in next:{}",
- sp, edgeLabel, nextId);
- }
-
- if (foundSingleNeighbor) {
- break;
- }
- }
- }
-
- if (!treatmentAdded) {
- log.warn("Could not createGroup from DestinationSet {} without any"
- + "next hops {}", ds, neighbors);
- return;
- }
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) ->
- log.debug("createGroupsFromDestinationSet installed "
- + "NextObj {} on {}", nextId, deviceId),
- (objective, error) -> {
- log.warn("createGroupsFromDestinationSet failed to install NextObj {} on {}: {}",
- nextId, deviceId, error);
- srManager.invalidateNextObj(objective.id());
- });
- NextObjective nextObj = nextObjBuilder.add(context);
- log.debug(".. createGroupsFromDestinationSet: Submitted "
- + "next objective {} in device {}", nextId, deviceId);
- flowObjectiveService.next(deviceId, nextObj);
- //update store
- dsNextObjStore.put(new DestinationSetNextObjectiveStoreKey(deviceId, ds),
- new NextNeighbors(dstNextHops, nextId));
- }
-
- /**
- * Creates broadcast groups for all ports in the same subnet for
- * all configured subnets.
- */
- public void createGroupsFromVlanConfig() {
- srManager.getVlanPortMap(deviceId).asMap().forEach((vlanId, ports) -> {
- createBcastGroupFromVlan(vlanId, ports);
- });
- }
-
- /**
- * Creates a single broadcast group from a given vlan id and list of ports.
- *
- * @param vlanId vlan id
- * @param ports list of ports in the subnet
- */
- public void createBcastGroupFromVlan(VlanId vlanId, Collection<PortNumber> ports) {
- VlanNextObjectiveStoreKey key = new VlanNextObjectiveStoreKey(deviceId, vlanId);
-
- if (vlanNextObjStore.containsKey(key)) {
- log.debug("Broadcast group for device {} and subnet {} exists",
- deviceId, vlanId);
- return;
- }
-
- TrafficSelector metadata =
- DefaultTrafficSelector.builder().matchVlanId(vlanId).build();
-
- int nextId = flowObjectiveService.allocateNextId();
-
- NextObjective.Builder nextObjBuilder = DefaultNextObjective
- .builder().withId(nextId)
- .withType(NextObjective.Type.BROADCAST).fromApp(appId)
- .withMeta(metadata);
-
- ports.forEach(port -> {
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
- if (toPopVlan(port, vlanId)) {
- tBuilder.popVlan();
- }
- tBuilder.setOutput(port);
- nextObjBuilder.addTreatment(tBuilder.build());
- });
-
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) ->
- log.debug("createBroadcastGroupFromVlan installed "
- + "NextObj {} on {}", nextId, deviceId),
- (objective, error) -> {
- log.warn("createBroadcastGroupFromVlan failed to install NextObj {} on {}: {}",
- nextId, deviceId, error);
- srManager.invalidateNextObj(objective.id());
- });
- NextObjective nextObj = nextObjBuilder.add(context);
- flowObjectiveService.next(deviceId, nextObj);
- log.debug("createBcastGroupFromVlan: Submitted next objective {} "
- + "for vlan: {} in device {}", nextId, vlanId, deviceId);
-
- vlanNextObjStore.put(key, nextId);
- }
-
- /**
- * Removes a single broadcast group from a given vlan id.
- * The group should be empty.
- * @param deviceId device Id to remove the group
- * @param portNum port number related to the group
- * @param vlanId vlan id of the broadcast group to remove
- * @param popVlan true if the TrafficTreatment involves pop vlan tag action
- */
- public void removeBcastGroupFromVlan(DeviceId deviceId, PortNumber portNum,
- VlanId vlanId, boolean popVlan) {
- VlanNextObjectiveStoreKey key = new VlanNextObjectiveStoreKey(deviceId, vlanId);
-
- if (!vlanNextObjStore.containsKey(key)) {
- log.debug("Broadcast group for device {} and subnet {} does not exist",
- deviceId, vlanId);
- return;
- }
-
- TrafficSelector metadata =
- DefaultTrafficSelector.builder().matchVlanId(vlanId).build();
-
- int nextId = vlanNextObjStore.get(key);
-
- NextObjective.Builder nextObjBuilder = DefaultNextObjective
- .builder().withId(nextId)
- .withType(NextObjective.Type.BROADCAST).fromApp(appId)
- .withMeta(metadata);
-
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
- if (popVlan) {
- tBuilder.popVlan();
- }
- tBuilder.setOutput(portNum);
- nextObjBuilder.addTreatment(tBuilder.build());
-
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) ->
- log.debug("removeBroadcastGroupFromVlan removed "
- + "NextObj {} on {}", nextId, deviceId),
- (objective, error) -> {
- log.warn("removeBroadcastGroupFromVlan failed to remove NextObj {} on {}: {}",
- nextId, deviceId, error);
- srManager.invalidateNextObj(objective.id());
- });
- NextObjective nextObj = nextObjBuilder.remove(context);
- flowObjectiveService.next(deviceId, nextObj);
- log.debug("removeBcastGroupFromVlan: Submited next objective {} in device {}",
- nextId, deviceId);
-
- vlanNextObjStore.remove(key, nextId);
- }
-
- /**
- * Determine if we should pop given vlan before sending packets to the given port.
- *
- * @param portNumber port number
- * @param vlanId vlan id
- * @return true if the vlan id is not contained in any vlanTagged config
- */
- private boolean toPopVlan(PortNumber portNumber, VlanId vlanId) {
- return srManager.interfaceService
- .getInterfacesByPort(new ConnectPoint(deviceId, portNumber))
- .stream().noneMatch(intf -> intf.vlanTagged().contains(vlanId));
- }
-
- /**
- * Create simple next objective for an indirect host mac/vlan. The treatments can include
- * all outgoing actions that need to happen on the packet.
- *
- * @param macAddr the mac address of the host
- * @param vlanId the vlan of the host
- * @param treatment the actions to apply on the packets (should include outport)
- * @param meta optional data to pass to the driver
- * @return next objective ID
- */
- public int createGroupFromMacVlan(MacAddress macAddr, VlanId vlanId, TrafficTreatment treatment,
- TrafficSelector meta) {
- int nextId = flowObjectiveService.allocateNextId();
- MacVlanNextObjectiveStoreKey key = new MacVlanNextObjectiveStoreKey(deviceId, macAddr, vlanId);
-
- NextObjective.Builder nextObjBuilder = DefaultNextObjective
- .builder().withId(nextId)
- .withType(NextObjective.Type.SIMPLE)
- .addTreatment(treatment)
- .fromApp(appId)
- .withMeta(meta);
-
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) ->
- log.debug("createGroupFromMacVlan installed "
- + "NextObj {} on {}", nextId, deviceId),
- (objective, error) -> {
- log.warn("createGroupFromMacVlan failed to install NextObj {} on {}: {}", nextId, deviceId, error);
- srManager.invalidateNextObj(objective.id());
- });
- NextObjective nextObj = nextObjBuilder.add(context);
- flowObjectiveService.next(deviceId, nextObj);
- log.debug("createGroupFromMacVlan: Submited next objective {} in device {} "
- + "for host {}/{}", nextId, deviceId, macAddr, vlanId);
-
- macVlanNextObjStore.put(key, nextId);
- return nextId;
- }
-
- /**
- * Create simple next objective for a single port. The treatments can include
- * all outgoing actions that need to happen on the packet.
- *
- * @param portNum the outgoing port on the device
- * @param treatment the actions to apply on the packets (should include outport)
- * @param meta optional data to pass to the driver
- */
- public void createGroupFromPort(PortNumber portNum, TrafficTreatment treatment,
- TrafficSelector meta) {
- int nextId = flowObjectiveService.allocateNextId();
- PortNextObjectiveStoreKey key = new PortNextObjectiveStoreKey(
- deviceId, portNum, treatment, meta);
-
- NextObjective.Builder nextObjBuilder = DefaultNextObjective
- .builder().withId(nextId)
- .withType(NextObjective.Type.SIMPLE)
- .addTreatment(treatment)
- .fromApp(appId)
- .withMeta(meta);
-
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) ->
- log.debug("createGroupFromPort installed "
- + "NextObj {} on {}", nextId, deviceId),
- (objective, error) -> {
- log.warn("createGroupFromPort failed to install NextObj {} on {}: {}", nextId, deviceId, error);
- srManager.invalidateNextObj(objective.id());
- });
- NextObjective nextObj = nextObjBuilder.add(context);
- flowObjectiveService.next(deviceId, nextObj);
- log.debug("createGroupFromPort: Submited next objective {} in device {} "
- + "for port {}", nextId, deviceId, portNum);
-
- portNextObjStore.put(key, nextId);
- }
-
- /**
- * Creates simple next objective for a single port.
- *
- * @param deviceId device id that has the port to deal with
- * @param portNum the outgoing port on the device
- * @param vlanId vlan id associated with the port
- * @param popVlan true if POP_VLAN action is applied on the packets, false otherwise
- */
- public void createPortNextObjective(DeviceId deviceId, PortNumber portNum, VlanId vlanId, boolean popVlan) {
- TrafficSelector.Builder mbuilder = DefaultTrafficSelector.builder();
- mbuilder.matchVlanId(vlanId);
-
- TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
- tbuilder.immediate().setOutput(portNum);
- if (popVlan) {
- tbuilder.immediate().popVlan();
- }
-
- createGroupFromPort(portNum, tbuilder.build(), mbuilder.build());
- }
-
- /**
- * Removes simple next objective for a single port.
- *
- * @param deviceId device id that has the port to deal with
- * @param portNum the outgoing port on the device
- * @param vlanId vlan id associated with the port
- * @param popVlan true if POP_VLAN action is applied on the packets, false otherwise
- */
- public void removePortNextObjective(DeviceId deviceId, PortNumber portNum, VlanId vlanId, boolean popVlan) {
- TrafficSelector.Builder mbuilder = DefaultTrafficSelector.builder();
- mbuilder.matchVlanId(vlanId);
-
- TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
- tbuilder.immediate().setOutput(portNum);
- if (popVlan) {
- tbuilder.immediate().popVlan();
- }
-
- int portNextObjId = srManager.getPortNextObjectiveId(deviceId, portNum,
- tbuilder.build(), mbuilder.build(), false);
-
- PortNextObjectiveStoreKey key = new PortNextObjectiveStoreKey(
- deviceId, portNum, tbuilder.build(), mbuilder.build());
- if (portNextObjId != -1 && portNextObjStore.containsKey(key)) {
- NextObjective.Builder nextObjBuilder = DefaultNextObjective
- .builder().withId(portNextObjId)
- .withType(NextObjective.Type.SIMPLE).fromApp(appId);
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> log.debug("removePortNextObjective removes NextObj {} on {}",
- portNextObjId, deviceId),
- (objective, error) -> {
- log.warn("removePortNextObjective failed to remove NextObj {} on {}: {}",
- portNextObjId, deviceId, error);
- srManager.invalidateNextObj(objective.id());
- });
- NextObjective nextObjective = nextObjBuilder.remove(context);
- log.info("**removePortNextObjective: Submitted "
- + "next objective {} in device {}",
- portNextObjId, deviceId);
- flowObjectiveService.next(deviceId, nextObjective);
-
- portNextObjStore.remove(key);
- }
- }
-
- /**
- * Removes groups for the next objective ID given.
- *
- * @param objectiveId next objective ID to remove
- * @return true if succeeds, false otherwise
- */
- public boolean removeGroup(int objectiveId) {
- for (Map.Entry<DestinationSetNextObjectiveStoreKey, NextNeighbors> e :
- dsNextObjStore.entrySet()) {
- if (e.getValue().nextId() != objectiveId) {
- continue;
- }
- // Right now it is just used in TunnelHandler
- // remember in future that PW transit groups could
- // be Indirect groups
- NextObjective.Builder nextObjBuilder = DefaultNextObjective
- .builder().withId(objectiveId)
- .withType(NextObjective.Type.HASHED).fromApp(appId);
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> log.debug("RemoveGroup removes NextObj {} on {}",
- objectiveId, deviceId),
- (objective, error) -> {
- log.warn("RemoveGroup failed to remove NextObj {} on {}: {}", objectiveId, deviceId, error);
- srManager.invalidateNextObj(objective.id());
- });
- NextObjective nextObjective = nextObjBuilder.remove(context);
- log.info("**removeGroup: Submited "
- + "next objective {} in device {}",
- objectiveId, deviceId);
- flowObjectiveService.next(deviceId, nextObjective);
-
- dsNextObjStore.remove(e.getKey());
- return true;
- }
-
- return false;
- }
- /**
- * Remove simple next objective for a single port. The treatments can include
- * all outgoing actions that need to happen on the packet.
- *
- * @param portNum the outgoing port on the device
- * @param treatment the actions applied on the packets (should include outport)
- * @param meta optional data to pass to the driver
- */
- public void removeGroupFromPort(PortNumber portNum, TrafficTreatment treatment,
- TrafficSelector meta) {
- PortNextObjectiveStoreKey key = new PortNextObjectiveStoreKey(
- deviceId, portNum, treatment, meta);
- Integer nextId = portNextObjStore.get(key);
-
- NextObjective.Builder nextObjBuilder = DefaultNextObjective
- .builder().withId(nextId)
- .withType(NextObjective.Type.SIMPLE)
- .addTreatment(treatment)
- .fromApp(appId)
- .withMeta(meta);
-
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) ->
- log.info("removeGroupFromPort installed "
- + "NextObj {} on {}", nextId, deviceId),
- (objective, error) -> {
- log.warn("removeGroupFromPort failed to install NextObj {} on {}: {}", nextId, deviceId, error);
- srManager.invalidateNextObj(objective.id());
- }
- );
- NextObjective nextObj = nextObjBuilder.remove(context);
- flowObjectiveService.next(deviceId, nextObj);
- log.info("removeGroupFromPort: Submitted next objective {} in device {} "
- + "for port {}", nextId, deviceId, portNum);
-
- portNextObjStore.remove(key);
- }
-
- /**
- * Removes all groups from all next objective stores.
- */
- /*public void removeAllGroups() {
- for (Map.Entry<NeighborSetNextObjectiveStoreKey, NextNeighbors> entry:
- nsNextObjStore.entrySet()) {
- removeGroup(entry.getValue().nextId());
- }
- for (Map.Entry<PortNextObjectiveStoreKey, Integer> entry:
- portNextObjStore.entrySet()) {
- removeGroup(entry.getValue());
- }
- for (Map.Entry<VlanNextObjectiveStoreKey, Integer> entry:
- vlanNextObjStore.entrySet()) {
- removeGroup(entry.getValue());
- }
- }*/ //XXX revisit
-
- /**
- * Triggers a one time bucket verification operation on all hash groups
- * on this device.
- */
- public void triggerBucketCorrector() {
- BucketCorrector bc = new BucketCorrector();
- bc.run();
- }
-
- /**
- * Modifies L2IG bucket when the interface configuration is updated, especially
- * when the interface has same VLAN ID but the VLAN type is changed (e.g., from
- * vlan-tagged [10] to vlan-untagged 10), which requires changes on
- * TrafficTreatment in turn.
- *
- * @param portNumber the port on this device that needs to be updated
- * @param vlanId the vlan id corresponding to this port
- * @param pushVlan indicates if packets should be sent out untagged or not out
- * from the port. If true, updated TrafficTreatment involves
- * pop vlan tag action. If false, updated TrafficTreatment
- * does not involve pop vlan tag action.
- */
- public void updateL2InterfaceGroupBucket(PortNumber portNumber, VlanId vlanId, boolean pushVlan) {
- TrafficTreatment.Builder oldTBuilder = DefaultTrafficTreatment.builder();
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
- tBuilder.setOutput(portNumber);
- oldTBuilder.setOutput(portNumber);
- if (pushVlan) {
- tBuilder.popVlan();
- } else {
- oldTBuilder.popVlan();
- }
-
- TrafficSelector metadata =
- DefaultTrafficSelector.builder().matchVlanId(vlanId).build();
-
- // Update portNextObjStore with new L2IG
- int nextId = getPortNextObjectiveId(portNumber, oldTBuilder.build(), metadata, false);
- portNextObjStore.remove(new PortNextObjectiveStoreKey(deviceId, portNumber, oldTBuilder.build(), metadata));
- portNextObjStore.put(new PortNextObjectiveStoreKey(deviceId, portNumber, tBuilder.build(), metadata), nextId);
-
- NextObjective.Builder nextObjBuilder = DefaultNextObjective
- .builder().withId(nextId)
- .withType(NextObjective.Type.SIMPLE).fromApp(appId)
- .addTreatment(tBuilder.build())
- .withMeta(metadata);
-
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> log.debug("port {} successfully updated NextObj {} on {}",
- portNumber, nextId, deviceId),
- (objective, error) -> {
- log.warn("port {} failed to updated NextObj {} on {}: {}", portNumber, nextId, deviceId, error);
- srManager.invalidateNextObj(objective.id());
- });
-
- flowObjectiveService.next(deviceId, nextObjBuilder.modify(context));
- }
-
- /**
- * Updates the next objective for the given nextId .
- *
- * @param hostMac mac of host for which Next obj is to be updated.
- * @param hostVlanId vlan of host for which Next obj is to be updated.
- * @param port port with which to update the Next Obj.
- * @param nextId of Next Obj which needs to be updated.
- */
- public void updateL3UcastGroupBucket(MacAddress hostMac, VlanId hostVlanId, PortNumber port, int nextId) {
-
- MacAddress deviceMac;
- try {
- deviceMac = deviceConfig.getDeviceMac(deviceId);
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage() + " in updateL3UcastGroupBucket");
- return;
- }
-
- TrafficSelector metadata =
- DefaultTrafficSelector.builder().matchVlanId(hostVlanId).build();
-
- TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
- tbuilder.deferred()
- .setEthDst(hostMac)
- .setEthSrc(deviceMac)
- .setVlanId(hostVlanId)
- .setOutput(port);
-
- log.debug(" update L3Ucast : deviceMac {}, port {}, host {}/{}, nextid {}, Treatment {} Meta {}",
- deviceMac, port, hostMac, hostVlanId, nextId, tbuilder.build(), metadata);
-
- NextObjective.Builder nextObjBuilder = DefaultNextObjective
- .builder().withId(nextId)
- .withType(NextObjective.Type.SIMPLE).fromApp(appId)
- .addTreatment(tbuilder.build())
- .withMeta(metadata);
-
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> log.debug(" NextId {} successfully updated host {} vlan {} with port {}",
- nextId, hostMac, hostVlanId, port),
- (objective, error) -> {
- log.warn(" NextId {} failed to update host {} vlan {} with port {}, error : {}",
- nextId, hostMac, hostVlanId, port, error);
- srManager.invalidateNextObj(objective.id());
- });
-
- NextObjective nextObj = nextObjBuilder.modify(context);
- flowObjectiveService.next(deviceId, nextObj);
-
- }
-
- /**
- * Adds a single port to the L2FG or removes it from the L2FG.
- *
- * @param vlanId the vlan id corresponding to this port
- * @param portNum the port on this device to be updated
- * @param nextId the next objective ID for the given vlan id
- * @param install if true, adds the port to L2FG. If false, removes it from L2FG.
- */
- public void updateGroupFromVlanConfiguration(VlanId vlanId, PortNumber portNum, int nextId, boolean install) {
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
- if (toPopVlan(portNum, vlanId)) {
- tBuilder.popVlan();
- }
- tBuilder.setOutput(portNum);
-
- TrafficSelector metadata =
- DefaultTrafficSelector.builder().matchVlanId(vlanId).build();
-
- NextObjective.Builder nextObjBuilder = DefaultNextObjective
- .builder().withId(nextId)
- .withType(NextObjective.Type.BROADCAST).fromApp(appId)
- .addTreatment(tBuilder.build())
- .withMeta(metadata);
-
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> log.debug("port {} successfully removedFrom NextObj {} on {}",
- portNum, nextId, deviceId),
- (objective, error) -> {
- log.warn("port {} failed to removedFrom NextObj {} on {}: {}", portNum, nextId, deviceId, error);
- srManager.invalidateNextObj(objective.id());
- });
-
- if (install) {
- flowObjectiveService.next(deviceId, nextObjBuilder.addToExisting(context));
- } else {
- flowObjectiveService.next(deviceId, nextObjBuilder.removeFromExisting(context));
- }
- }
-
- /**
- * Performs bucket verification operation for all hash groups in this device.
- * Checks RouteHandler to ensure that routing is stable before attempting
- * verification. Verification involves creating a nextObjective with
- * operation VERIFY for existing next objectives in the store, and passing
- * it to the driver. It is the driver that actually performs the verification
- * by adding or removing buckets to match the verification next objective
- * created here.
- */
- protected final class BucketCorrector implements Runnable {
- Integer nextId;
-
- BucketCorrector() {
- this.nextId = null;
- }
-
- BucketCorrector(Integer nextId) {
- this.nextId = nextId;
- }
-
- @Override
- public void run() {
- if (!srManager.mastershipService.isLocalMaster(deviceId)) {
- return;
- }
- DefaultRoutingHandler rh = srManager.getRoutingHandler();
- if (rh == null) {
- return;
- }
- if (!rh.isRoutingStable()) {
- return;
- }
- rh.acquireRoutingLock();
- try {
- log.trace("running bucket corrector for dev: {}", deviceId);
- Set<DestinationSetNextObjectiveStoreKey> dsKeySet = dsNextObjStore.entrySet()
- .stream()
- .filter(entry -> entry.getKey().deviceId().equals(deviceId))
- // Filter out PW transit groups or include them if MPLS ECMP is supported
- .filter(entry -> !entry.getKey().destinationSet().notBos() ||
- (entry.getKey().destinationSet().notBos() && srManager.getMplsEcmp()))
- // Filter out simple SWAP groups or include them if MPLS ECMP is supported
- .filter(entry -> !entry.getKey().destinationSet().swap() ||
- (entry.getKey().destinationSet().swap() && srManager.getMplsEcmp()))
- .map(entry -> entry.getKey())
- .collect(Collectors.toSet());
- for (DestinationSetNextObjectiveStoreKey dsKey : dsKeySet) {
- NextNeighbors next = dsNextObjStore.get(dsKey);
- if (next == null) {
- continue;
- }
- int nid = next.nextId();
- if (nextId != null && nextId != nid) {
- continue;
- }
- log.trace("bkt-corr: dsNextObjStore for device {}: {}",
- deviceId, dsKey, next);
- TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
- metabuilder.matchVlanId(srManager.getDefaultInternalVlan());
- NextObjective.Builder nextObjBuilder = DefaultNextObjective.builder()
- .withId(nid)
- .withType(NextObjective.Type.HASHED)
- .withMeta(metabuilder.build())
- .fromApp(appId);
-
- next.dstNextHops().forEach((dstDev, nextHops) -> {
- int edgeLabel = dsKey.destinationSet().getEdgeLabel(dstDev);
- nextHops.forEach(neighbor -> {
- MacAddress neighborMac;
- try {
- neighborMac = deviceConfig.getDeviceMac(neighbor);
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage() + " Aborting neighbor"
- + neighbor);
- return;
- }
- devicePortMap.get(neighbor).forEach(port -> {
- log.trace("verify in device {} nextId {}: bucket with"
- + " port/label {}/{} to dst {} via {}",
- deviceId, nid, port, edgeLabel,
- dstDev, neighbor);
- nextObjBuilder
- .addTreatment(treatmentBuilder(port,
- neighborMac,
- dsKey.destinationSet().swap(),
- edgeLabel));
- });
- });
- });
-
- NextObjective nextObjective = nextObjBuilder.verify();
- flowObjectiveService.next(deviceId, nextObjective);
- }
- } finally {
- rh.releaseRoutingLock();
- }
-
- }
-
- TrafficTreatment treatmentBuilder(PortNumber outport, MacAddress dstMac,
- boolean swap, int edgeLabel) {
- TrafficTreatment.Builder tBuilder =
- DefaultTrafficTreatment.builder();
- tBuilder.setOutput(outport)
- .setEthDst(dstMac)
- .setEthSrc(nodeMacAddr);
- if (edgeLabel != DestinationSet.NO_EDGE_LABEL) {
- if (swap) {
- // swap label case
- tBuilder.setMpls(MplsLabel.mplsLabel(edgeLabel));
- } else {
- // ecmp with label push case
- tBuilder.pushMpls()
- .copyTtlOut()
- .setMpls(MplsLabel.mplsLabel(edgeLabel));
- }
- }
- return tBuilder.build();
- }
- }
-
- /**
- * Determines whether the hash group bucket should include a popVlan action.
- * We don't popVlan for PW.
- *
- * @param ds destination set
- * @return true if VLAN needs to be popped
- */
- private boolean popVlanInHashGroup(DestinationSet ds) {
- return (ds.getTypeOfDstSet() != DestinationSet.DestinationSetType.SWAP_NOT_BOS) &&
- (ds.getTypeOfDstSet() != DestinationSet.DestinationSetType.POP_NOT_BOS);
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/grouphandler/DestinationSet.java b/app/src/main/java/org/onosproject/segmentrouting/grouphandler/DestinationSet.java
deleted file mode 100644
index 3ecdd61..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/grouphandler/DestinationSet.java
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * Copyright 2015-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.grouphandler;
-
-import org.onosproject.net.DeviceId;
-import org.slf4j.Logger;
-
-import com.google.common.base.MoreObjects.ToStringHelper;
-import java.util.HashSet;
-import java.util.Objects;
-import java.util.Set;
-
-import static com.google.common.base.MoreObjects.toStringHelper;
-import static org.slf4j.LoggerFactory.getLogger;
-
-/**
- * Representation of a set of destination switch dpids along with their
- * edge-node labels. Meant to be used as a lookup-key in a hash-map to retrieve
- * an ECMP-group that hashes packets towards a specific destination switch, or
- * paired-destination switches. May also be used to represent cases where the
- * forwarding does not use ECMP groups (ie SIMPLE next objectives)
- */
-public final class DestinationSet {
- public static final int NO_EDGE_LABEL = -1;
- private static final int NOT_ASSIGNED = 0;
- private final DeviceId dstSw1;
- private final int edgeLabel1;
- private final DeviceId dstSw2;
- private final int edgeLabel2;
- private final DestinationSetType typeOfDstSet;
-
- private static final Logger log = getLogger(DestinationSet.class);
-
- /**
- * Constructor for a single destination with no Edge label.
- *
- * @param dsType type of next objective
- * @param dstSw the destination switch
- */
- private DestinationSet(DestinationSetType dsType, DeviceId dstSw) {
- this.edgeLabel1 = NO_EDGE_LABEL;
- this.dstSw1 = dstSw;
- this.edgeLabel2 = NOT_ASSIGNED;
- this.dstSw2 = null;
- this.typeOfDstSet = dsType;
- }
-
- /**
- * Constructor for a single destination with Edge label.
- *
- * @param dsType type of next objective
- * @param edgeLabel label to be pushed as part of group operation
- * @param dstSw the destination switch
- */
- private DestinationSet(DestinationSetType dsType,
- int edgeLabel, DeviceId dstSw) {
- this.edgeLabel1 = edgeLabel;
- this.dstSw1 = dstSw;
- this.edgeLabel2 = NOT_ASSIGNED;
- this.dstSw2 = null;
- this.typeOfDstSet = dsType;
- }
-
- /**
- * Constructor for paired destination switches and their associated edge
- * labels.
- *
- * @param dsType type of next objective
- * @param edgeLabel1 label to be pushed as part of group operation for
- * dstSw1
- * @param dstSw1 one of the paired destination switches
- * @param edgeLabel2 label to be pushed as part of group operation for
- * dstSw2
- * @param dstSw2 the other paired destination switch
- */
- private DestinationSet(DestinationSetType dsType,
- int edgeLabel1, DeviceId dstSw1,
- int edgeLabel2, DeviceId dstSw2) {
- if (dstSw1.toString().compareTo(dstSw2.toString()) <= 0) {
- this.edgeLabel1 = edgeLabel1;
- this.dstSw1 = dstSw1;
- this.edgeLabel2 = edgeLabel2;
- this.dstSw2 = dstSw2;
- } else {
- this.edgeLabel1 = edgeLabel2;
- this.dstSw1 = dstSw2;
- this.edgeLabel2 = edgeLabel1;
- this.dstSw2 = dstSw1;
- }
- this.typeOfDstSet = dsType;
- }
- /**
- * Default constructor for kryo serialization.
- */
- private DestinationSet() {
- this.edgeLabel1 = NOT_ASSIGNED;
- this.edgeLabel2 = NOT_ASSIGNED;
- this.dstSw1 = DeviceId.NONE;
- this.dstSw2 = DeviceId.NONE;
- this.typeOfDstSet = null;
- }
-
- /**
- * Gets the label associated with given destination switch.
- *
- * @param dstSw the destination switch
- * @return integer the label associated with the destination switch
- */
- public int getEdgeLabel(DeviceId dstSw) {
- if (dstSw.equals(dstSw1)) {
- return edgeLabel1;
- } else if (dstSw.equals(dstSw2)) {
- return edgeLabel2;
- }
- return NOT_ASSIGNED;
- }
-
- /**
- * Gets all the destination switches in this destination set.
- *
- * @return a set of destination switch ids
- */
- public Set<DeviceId> getDestinationSwitches() {
- Set<DeviceId> dests = new HashSet<>();
- dests.add(dstSw1);
- if (dstSw2 != null) {
- dests.add(dstSw2);
- }
- return dests;
- }
-
- /**
- * Returns the type of this ds.
- *
- * @return the type of the destination set
- */
- public DestinationSetType getTypeOfDstSet() {
- return typeOfDstSet;
- }
-
- /**
- * Returns true if the next objective represented by this destination set
- * is of type SWAP_NOT_BOS or POP_NOT_BOS.
- *
- * @return the value of notBos
- */
- public boolean notBos() {
- if ((typeOfDstSet == DestinationSetType.SWAP_NOT_BOS) || (typeOfDstSet == DestinationSetType.POP_NOT_BOS)) {
- return true;
- }
- return false;
- }
-
- /**
- * Returns true if the next objective represented by this destination set
- * is of type SWAP_NOT_BOS or SWAP_BOS.
- *
- * @return the value of swap
- */
- public boolean swap() {
- if ((typeOfDstSet == DestinationSetType.SWAP_BOS) || (typeOfDstSet == DestinationSetType.SWAP_NOT_BOS)) {
- return true;
- }
- return false;
- }
-
- // The list of destination ids and label are used for comparison.
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (!(o instanceof DestinationSet)) {
- return false;
- }
- DestinationSet that = (DestinationSet) o;
- if (this.typeOfDstSet != that.typeOfDstSet) {
- return false;
- }
- boolean equal = (this.edgeLabel1 == that.edgeLabel1 &&
- this.dstSw1.equals(that.dstSw1));
- if (this.dstSw2 != null && that.dstSw2 == null ||
- this.dstSw2 == null && that.dstSw2 != null) {
- return false;
- }
- if (this.dstSw2 != null && that.dstSw2 != null) {
- equal = equal && (this.edgeLabel2 == that.edgeLabel2 &&
- this.dstSw2.equals(that.dstSw2));
- }
- return equal;
- }
-
- // The list of destination ids and label are used for comparison.
- @Override
- public int hashCode() {
- if (dstSw2 == null) {
- return Objects.hash(typeOfDstSet, edgeLabel1, dstSw1);
- }
- return Objects.hash(typeOfDstSet, edgeLabel1, dstSw1, edgeLabel2,
- dstSw2);
- }
-
- @Override
- public String toString() {
- ToStringHelper h = toStringHelper(this)
- .add("Type", typeOfDstSet.getType())
- .add("DstSw1", dstSw1)
- .add("Label1", edgeLabel1);
- if (dstSw2 != null) {
- h.add("DstSw2", dstSw2)
- .add("Label2", edgeLabel2);
- }
- return h.toString();
- }
-
- public enum DestinationSetType {
- /**
- * Used to represent DestinationSetType where the next hop
- * is the same as the final destination.
- */
- PUSH_NONE("pushnon"),
- /**
- * Used to represent DestinationSetType where we need to
- * push a single mpls label, that of the destination.
- */
- PUSH_BOS("pushbos"),
- /**
- * Used to represent DestinationSetType where we need to pop
- * an mpls label which has the bos bit set.
- */
- POP_BOS("pop-bos"),
- /**
- * Used to represent DestinationSetType where we swap the outer
- * mpls label with a new one, and where the outer label has the
- * bos bit set.
- */
- SWAP_BOS("swapbos"),
- /**
- * Used to represent DestinationSetType where we need to pop
- * an mpls label which does not have the bos bit set.
- */
- POP_NOT_BOS("popnbos"),
- /**
- * Used to represent DestinationSetType where we swap the outer
- * mpls label with a new one, and where the outer label does not
- * have the bos bit set.
- */
- SWAP_NOT_BOS("swap-nb");
-
- private final String typeOfDstDest;
- DestinationSetType(String s) {
- typeOfDstDest = s;
- }
-
- public String getType() {
- return typeOfDstDest;
- }
- }
-
- /*
- * Static methods for creating DestinationSet objects in
- * order to remove ambiquity with multiple constructors.
- */
-
- /**
- * Returns a DestinationSet with type PUSH_NONE.
- *
- * @param destSw The deviceId for this next objective.
- * @return The DestinationSet of this type.
- */
- public static DestinationSet createTypePushNone(DeviceId destSw) {
- return new DestinationSet(DestinationSetType.PUSH_NONE, destSw);
- }
-
- /**
- * Returns a DestinationSet with type PUSH_BOS.
- *
- * @param edgeLabel1 The mpls label to push.
- * @param destSw1 The device on which the label is assigned.
- * @return The DestinationSet of this type.
- */
- public static DestinationSet createTypePushBos(int edgeLabel1, DeviceId destSw1) {
- return new DestinationSet(DestinationSetType.PUSH_BOS, edgeLabel1, destSw1);
- }
-
- /**
- * Returns a DestinationSet with type PUSH_BOS used for paired leafs.
- *
- * @param edgeLabel1 The label of first paired leaf.
- * @param destSw1 The device id of first paired leaf.
- * @param edgeLabel2 The label of the second leaf.
- * @param destSw2 The device id of the second leaf.
- * @return The DestinationSet of this type.
- */
- public static DestinationSet createTypePushBos(int edgeLabel1, DeviceId destSw1, int edgeLabel2, DeviceId destSw2) {
- return new DestinationSet(DestinationSetType.PUSH_BOS, edgeLabel1, destSw1, edgeLabel2, destSw2);
- }
-
- /**
- * Returns a DestinationSet with type POP_BOS.
- *
- * @param deviceId The deviceId for this next objective.
- * @return The DestinationSet of this type.
- */
- public static DestinationSet createTypePopBos(DeviceId deviceId) {
- return new DestinationSet(DestinationSetType.POP_BOS, deviceId);
- }
-
- /**
- * Returns a DestinationSet with type SWAP_BOS.
- *
- * @param edgeLabel The edge label to swap with.
- * @param deviceId The deviceId for this next objective.
- * @return The DestinationSet of this type.
- */
- public static DestinationSet createTypeSwapBos(int edgeLabel, DeviceId deviceId) {
- return new DestinationSet(DestinationSetType.SWAP_BOS, edgeLabel, deviceId);
- }
-
- /**
- * Returns a DestinationSet with type POP_NOT_BOS.
- *
- * @param deviceId The device-id this next objective should be installed.
- * @return The DestinationSet of this type.
- */
- public static DestinationSet createTypePopNotBos(DeviceId deviceId) {
- return new DestinationSet(DestinationSetType.POP_NOT_BOS, deviceId);
- }
-
- /**
- * Returns a DestinationSet with type SWAP_NOT_BOS.
- *
- * @param edgeLabel The edge label to swap with.
- * @param deviceId The deviceId for this next objective.
- * @return The DestinationSet of this type.
- */
- public static DestinationSet createTypeSwapNotBos(int edgeLabel, DeviceId deviceId) {
- return new DestinationSet(DestinationSetType.SWAP_NOT_BOS, edgeLabel, deviceId);
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/grouphandler/GroupBucketIdentifier.java b/app/src/main/java/org/onosproject/segmentrouting/grouphandler/GroupBucketIdentifier.java
deleted file mode 100644
index 1c2e1ac..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/grouphandler/GroupBucketIdentifier.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2015-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.grouphandler;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import org.onosproject.net.PortNumber;
-
-/**
- * Representation of policy group bucket identifier. Not exposed to
- * the application and only to be used internally.
- */
-public class GroupBucketIdentifier {
- private int label;
- private BucketOutputType type;
- private PortNumber outPort;
- private PolicyGroupIdentifier outGroup;
-
- protected enum BucketOutputType {
- PORT,
- GROUP
- }
-
- protected GroupBucketIdentifier(int label,
- PortNumber outPort) {
- this.label = label;
- this.type = BucketOutputType.PORT;
- this.outPort = checkNotNull(outPort);
- this.outGroup = null;
- }
-
- protected GroupBucketIdentifier(int label,
- PolicyGroupIdentifier outGroup) {
- this.label = label;
- this.type = BucketOutputType.GROUP;
- this.outPort = null;
- this.outGroup = checkNotNull(outGroup);
- }
-
- protected int label() {
- return this.label;
- }
-
- protected BucketOutputType type() {
- return this.type;
- }
-
- protected PortNumber outPort() {
- return this.outPort;
- }
-
- protected PolicyGroupIdentifier outGroup() {
- return this.outGroup;
- }
-}
-
diff --git a/app/src/main/java/org/onosproject/segmentrouting/grouphandler/NextNeighbors.java b/app/src/main/java/org/onosproject/segmentrouting/grouphandler/NextNeighbors.java
deleted file mode 100644
index eaca1aa..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/grouphandler/NextNeighbors.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright 2015-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.grouphandler;
-
-import static com.google.common.base.MoreObjects.toStringHelper;
-
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-
-import org.onosproject.net.DeviceId;
-
-/**
- * Represents the nexthop information associated with a route-path towards a
- * set of destinations.
- */
-public class NextNeighbors {
- private final Map<DeviceId, Set<DeviceId>> dstNextHops;
- private final int nextId;
-
- /**
- * Constructor.
- *
- * @param dstNextHops map of destinations and the next-hops towards each dest
- * @param nextId id of nextObjective that manifests the next-hop info
- */
- public NextNeighbors(Map<DeviceId, Set<DeviceId>> dstNextHops, int nextId) {
- this.dstNextHops = dstNextHops;
- this.nextId = nextId;
- }
-
- /**
- * Returns a map of destinations and the next-hops towards them.
- *
- * @return map of destinations and the next-hops towards them
- */
- public Map<DeviceId, Set<DeviceId>> dstNextHops() {
- return dstNextHops;
- }
-
- /**
- * Set of next-hops towards the given destination.
- *
- * @param deviceId the destination
- * @return set of nexthops towards the destination
- */
- public Set<DeviceId> nextHops(DeviceId deviceId) {
- return dstNextHops.get(deviceId);
- }
-
- /**
- * Return the nextId representing the nextObjective towards the next-hops.
- *
- * @return nextId representing the nextObjective towards the next-hops
- */
- public int nextId() {
- return nextId;
- }
-
- /**
- * Checks if the given nextHopId is a valid next hop to any one of the
- * destinations.
- *
- * @param nextHopId the deviceId for the next hop
- * @return true if given next
- */
- public boolean containsNextHop(DeviceId nextHopId) {
- for (Set<DeviceId> nextHops : dstNextHops.values()) {
- if (nextHops != null && nextHops.contains(nextHopId)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns a set of destinations which have the given nextHopId as one
- * of the next-hops to that destination.
- *
- * @param nextHopId the deviceId for the next hop
- * @return set of deviceIds that have the given nextHopId as a next-hop
- * which could be empty if no destinations were found
- */
- public Set<DeviceId> getDstForNextHop(DeviceId nextHopId) {
- Set<DeviceId> dstSet = new HashSet<>();
- for (DeviceId dstKey : dstNextHops.keySet()) {
- if (dstNextHops.get(dstKey).contains(nextHopId)) {
- dstSet.add(dstKey);
- }
- }
- return dstSet;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (!(o instanceof NextNeighbors)) {
- return false;
- }
- NextNeighbors that = (NextNeighbors) o;
- return (this.nextId == that.nextId) &&
- this.dstNextHops.equals(that.dstNextHops);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(nextId, dstNextHops);
- }
-
- @Override
- public String toString() {
- return toStringHelper(this)
- .add("nextId", nextId)
- .add("dstNextHops", dstNextHops)
- .toString();
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java b/app/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java
deleted file mode 100644
index c0935ce..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * Copyright 2015-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.grouphandler;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static org.slf4j.LoggerFactory.getLogger;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.MplsLabel;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.segmentrouting.SegmentRoutingManager;
-import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
-import org.onosproject.segmentrouting.config.DeviceProperties;
-import org.onosproject.segmentrouting.grouphandler.GroupBucketIdentifier.BucketOutputType;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.flow.DefaultTrafficTreatment;
-import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.flowobjective.FlowObjectiveService;
-import org.onosproject.net.group.GroupBucket;
-import org.onosproject.net.link.LinkService;
-import org.slf4j.Logger;
-
-/**
- * A module to create group chains based on the specified device
- * ports and label stack to be applied on each port.
- */
-public class PolicyGroupHandler extends DefaultGroupHandler {
-
- private final Logger log = getLogger(getClass());
- private HashMap<PolicyGroupIdentifier, PolicyGroupIdentifier> dependentGroups = new HashMap<>();
-
- /**
- * Constructs policy group handler.
- *
- * @param deviceId device identifier
- * @param appId application identifier
- * @param config interface to retrieve the device properties
- * @param linkService link service object
- * @param flowObjService flow objective service object
- * @param srManager segment routing manager
- */
- public PolicyGroupHandler(DeviceId deviceId,
- ApplicationId appId,
- DeviceProperties config,
- LinkService linkService,
- FlowObjectiveService flowObjService,
- SegmentRoutingManager srManager) {
- super(deviceId, appId, config, linkService, flowObjService, srManager);
- }
-
- /**
- * Creates policy group chain.
- *
- * @param id unique identifier associated with the policy group
- * @param params a list of policy group params
- * @return policy group identifier
- */
- public PolicyGroupIdentifier createPolicyGroupChain(String id,
- List<PolicyGroupParams> params) {
- List<GroupBucketIdentifier> bucketIds = new ArrayList<>();
- for (PolicyGroupParams param: params) {
- List<PortNumber> ports = param.getPorts();
- if (ports == null) {
- log.warn("createPolicyGroupChain in sw {} with wrong "
- + "input parameters", deviceId);
- return null;
- }
-
- int labelStackSize = (param.getLabelStack() != null) ?
- param.getLabelStack().size() : 0;
-
- if (labelStackSize > 1) {
- for (PortNumber sp : ports) {
- PolicyGroupIdentifier previousGroupkey = null;
- DeviceId neighbor = portDeviceMap.get(sp);
- for (int idx = 0; idx < param.getLabelStack().size(); idx++) {
- int label = param.getLabelStack().get(idx);
- if (idx == (labelStackSize - 1)) {
- // Innermost Group
- GroupBucketIdentifier bucketId =
- new GroupBucketIdentifier(label,
- previousGroupkey);
- bucketIds.add(bucketId);
- } else if (idx == 0) {
- // Outermost Group
- List<GroupBucket> outBuckets = new ArrayList<>();
- GroupBucketIdentifier bucketId =
- new GroupBucketIdentifier(label, sp);
- PolicyGroupIdentifier key = new
- PolicyGroupIdentifier(id,
- Collections.singletonList(param),
- Collections.singletonList(bucketId));
- MacAddress neighborEthDst;
- try {
- neighborEthDst = deviceConfig.getDeviceMac(neighbor);
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage()
- + " Skipping createPolicyGroupChain for this label.");
- continue;
- }
-
- TrafficTreatment.Builder tBuilder =
- DefaultTrafficTreatment.builder();
- tBuilder.setOutput(sp)
- .setEthDst(neighborEthDst)
- .setEthSrc(nodeMacAddr)
- .pushMpls()
- .setMpls(MplsLabel.mplsLabel(label));
- /*outBuckets.add(DefaultGroupBucket.
- createSelectGroupBucket(tBuilder.build()));
- GroupDescription desc = new
- DefaultGroupDescription(deviceId,
- GroupDescription.Type.INDIRECT,
- new GroupBuckets(outBuckets));
- //TODO: BoS*/
- previousGroupkey = key;
- //groupService.addGroup(desc);
- //TODO: Use nextObjective APIs here
- } else {
- // Intermediate Groups
- GroupBucketIdentifier bucketId =
- new GroupBucketIdentifier(label,
- previousGroupkey);
- PolicyGroupIdentifier key = new
- PolicyGroupIdentifier(id,
- Collections.singletonList(param),
- Collections.singletonList(bucketId));
- // Add to group dependency list
- dependentGroups.put(previousGroupkey, key);
- previousGroupkey = key;
- }
- }
- }
- } else {
- int label = -1;
- if (labelStackSize == 1) {
- label = param.getLabelStack().get(0);
- }
- for (PortNumber sp : ports) {
- GroupBucketIdentifier bucketId =
- new GroupBucketIdentifier(label, sp);
- bucketIds.add(bucketId);
- }
- }
- }
- PolicyGroupIdentifier innermostGroupkey = null;
- if (!bucketIds.isEmpty()) {
- innermostGroupkey = new
- PolicyGroupIdentifier(id,
- params,
- bucketIds);
- // Add to group dependency list
- boolean fullyResolved = true;
- for (GroupBucketIdentifier bucketId:bucketIds) {
- if (bucketId.type() == BucketOutputType.GROUP) {
- dependentGroups.put(bucketId.outGroup(),
- innermostGroupkey);
- fullyResolved = false;
- }
- }
-
- if (fullyResolved) {
- List<GroupBucket> outBuckets = new ArrayList<>();
- for (GroupBucketIdentifier bucketId : bucketIds) {
- DeviceId neighbor = portDeviceMap.
- get(bucketId.outPort());
-
- MacAddress neighborEthDst;
- try {
- neighborEthDst = deviceConfig.getDeviceMac(neighbor);
- } catch (DeviceConfigNotFoundException e) {
- log.warn(e.getMessage()
- + " Skipping createPolicyGroupChain for this bucketId.");
- continue;
- }
-
- TrafficTreatment.Builder tBuilder =
- DefaultTrafficTreatment.builder();
- tBuilder.setOutput(bucketId.outPort())
- .setEthDst(neighborEthDst)
- .setEthSrc(nodeMacAddr);
- if (bucketId.label() != DestinationSet.NO_EDGE_LABEL) {
- tBuilder.pushMpls()
- .setMpls(MplsLabel.mplsLabel(bucketId.label()));
- }
- //TODO: BoS
- /*outBuckets.add(DefaultGroupBucket.
- createSelectGroupBucket(tBuilder.build()));*/
- }
- /*GroupDescription desc = new
- DefaultGroupDescription(deviceId,
- GroupDescription.Type.SELECT,
- new GroupBuckets(outBuckets));
- groupService.addGroup(desc);*/
- //TODO: Use nextObjective APIs here
- }
- }
- return innermostGroupkey;
- }
-
- //TODO: Use nextObjective APIs to handle the group chains
- /*
- @Override
- protected void handleGroupEvent(GroupEvent event) {}
- */
-
- /**
- * Generates policy group key.
- *
- * @param id unique identifier associated with the policy group
- * @param params a list of policy group params
- * @return policy group identifier
- */
- public PolicyGroupIdentifier generatePolicyGroupKey(String id,
- List<PolicyGroupParams> params) {
- List<GroupBucketIdentifier> bucketIds = new ArrayList<>();
- for (PolicyGroupParams param: params) {
- List<PortNumber> ports = param.getPorts();
- if (ports == null) {
- log.warn("generateGroupKey in sw {} with wrong "
- + "input parameters", deviceId);
- return null;
- }
-
- int labelStackSize = (param.getLabelStack() != null)
- ? param.getLabelStack().size() : 0;
-
- if (labelStackSize > 1) {
- for (PortNumber sp : ports) {
- PolicyGroupIdentifier previousGroupkey = null;
- for (int idx = 0; idx < param.getLabelStack().size(); idx++) {
- int label = param.getLabelStack().get(idx);
- if (idx == (labelStackSize - 1)) {
- // Innermost Group
- GroupBucketIdentifier bucketId =
- new GroupBucketIdentifier(label,
- previousGroupkey);
- bucketIds.add(bucketId);
- } else if (idx == 0) {
- // Outermost Group
- GroupBucketIdentifier bucketId =
- new GroupBucketIdentifier(label, sp);
- PolicyGroupIdentifier key = new
- PolicyGroupIdentifier(id,
- Collections.singletonList(param),
- Collections.singletonList(bucketId));
- previousGroupkey = key;
- } else {
- // Intermediate Groups
- GroupBucketIdentifier bucketId =
- new GroupBucketIdentifier(label,
- previousGroupkey);
- PolicyGroupIdentifier key = new
- PolicyGroupIdentifier(id,
- Collections.singletonList(param),
- Collections.singletonList(bucketId));
- previousGroupkey = key;
- }
- }
- }
- } else {
- int label = -1;
- if (labelStackSize == 1) {
- label = param.getLabelStack().get(0);
- }
- for (PortNumber sp : ports) {
- GroupBucketIdentifier bucketId =
- new GroupBucketIdentifier(label, sp);
- bucketIds.add(bucketId);
- }
- }
- }
- PolicyGroupIdentifier innermostGroupkey = null;
- if (!bucketIds.isEmpty()) {
- innermostGroupkey = new
- PolicyGroupIdentifier(id,
- params,
- bucketIds);
- }
- return innermostGroupkey;
- }
-
- /**
- * Removes policy group chain.
- *
- * @param key policy group identifier
- */
- public void removeGroupChain(PolicyGroupIdentifier key) {
- checkArgument(key != null);
- List<PolicyGroupIdentifier> groupsToBeDeleted = new ArrayList<>();
- groupsToBeDeleted.add(key);
-
- Iterator<PolicyGroupIdentifier> it =
- groupsToBeDeleted.iterator();
-
- while (it.hasNext()) {
- PolicyGroupIdentifier innerMostGroupKey = it.next();
- for (GroupBucketIdentifier bucketId:
- innerMostGroupKey.bucketIds()) {
- if (bucketId.type() != BucketOutputType.GROUP) {
- groupsToBeDeleted.add(bucketId.outGroup());
- }
- }
- /*groupService.removeGroup(deviceId,
- getGroupKey(innerMostGroupKey),
- appId);*/
- //TODO: Use nextObjective APIs here
- it.remove();
- }
- }
-
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupIdentifier.java b/app/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupIdentifier.java
deleted file mode 100644
index fdc6dea..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupIdentifier.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright 2015-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.grouphandler;
-
-import java.util.List;
-
-/**
- * Representation of policy based group identifiers.
- * Opaque to group handler applications and only the outermost
- * policy group identifier in a chain is visible to the applications.
- */
-public class PolicyGroupIdentifier {
- private String id;
- private List<PolicyGroupParams> inputParams;
- private List<GroupBucketIdentifier> bucketIds;
-
- /**
- * Constructs policy group identifier.
- *
- * @param id unique identifier associated with the policy group
- * @param input policy group params associated with this group
- * @param bucketIds buckets associated with this group
- */
- protected PolicyGroupIdentifier(String id,
- List<PolicyGroupParams> input,
- List<GroupBucketIdentifier> bucketIds) {
- this.id = id;
- this.inputParams = input;
- this.bucketIds = bucketIds;
- }
-
- /**
- * Returns the bucket identifier list associated with the policy
- * group identifier.
- *
- * @return list of bucket identifier
- */
- protected List<GroupBucketIdentifier> bucketIds() {
- return this.bucketIds;
- }
-
- @Override
- public int hashCode() {
- int result = 17;
- int combinedHash = 0;
- for (PolicyGroupParams input:inputParams) {
- combinedHash = combinedHash + input.hashCode();
- }
- for (GroupBucketIdentifier bucketId:bucketIds) {
- combinedHash = combinedHash + bucketId.hashCode();
- }
- result = 31 * result + combinedHash;
-
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
-
- if (obj instanceof PolicyGroupIdentifier) {
- PolicyGroupIdentifier that = (PolicyGroupIdentifier) obj;
- boolean result = this.id.equals(that.id);
- result = result &&
- this.inputParams.containsAll(that.inputParams) &&
- that.inputParams.containsAll(this.inputParams);
- result = result &&
- this.bucketIds.containsAll(that.bucketIds) &&
- that.bucketIds.containsAll(this.bucketIds);
- return result;
- }
-
- return false;
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupParams.java b/app/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupParams.java
deleted file mode 100644
index 5baf849..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupParams.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2015-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.grouphandler;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.List;
-import java.util.Objects;
-
-import org.onosproject.net.PortNumber;
-
-/**
- * Representation of parameters used to create policy based groups.
- */
-public class PolicyGroupParams {
- private final List<PortNumber> ports;
- private final List<Integer> labelStack;
-
- /**
- * Constructor.
- *
- * @param labelStack mpls label stack to be applied on the ports
- * @param ports ports to be part of the policy group
- */
- public PolicyGroupParams(List<Integer> labelStack,
- List<PortNumber> ports) {
- this.ports = checkNotNull(ports);
- this.labelStack = checkNotNull(labelStack);
- }
-
- /**
- * Returns the ports associated with the policy group params.
- *
- * @return list of port numbers
- */
- public List<PortNumber> getPorts() {
- return ports;
- }
-
- /**
- * Returns the label stack associated with the policy group params.
- *
- * @return list of integers
- */
- public List<Integer> getLabelStack() {
- return labelStack;
- }
-
- @Override
- public int hashCode() {
- int result = 17;
- int combinedHash = 0;
- for (PortNumber port:ports) {
- combinedHash = combinedHash + port.hashCode();
- }
- combinedHash = combinedHash + Objects.hash(labelStack);
- result = 31 * result + combinedHash;
-
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
-
- if (obj instanceof PolicyGroupParams) {
- PolicyGroupParams that = (PolicyGroupParams) obj;
- boolean result = this.labelStack.equals(that.labelStack);
- result = result &&
- this.ports.containsAll(that.ports) &&
- that.ports.containsAll(this.ports);
- return result;
- }
-
- return false;
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/grouphandler/package-info.java b/app/src/main/java/org/onosproject/segmentrouting/grouphandler/package-info.java
deleted file mode 100644
index d99f1d1..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/grouphandler/package-info.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2015-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.
- */
-
-/**
- * Segment routing group handling.
- */
-package org.onosproject.segmentrouting.grouphandler;
\ No newline at end of file
diff --git a/app/src/main/java/org/onosproject/segmentrouting/mcast/McastFilteringObjStoreKey.java b/app/src/main/java/org/onosproject/segmentrouting/mcast/McastFilteringObjStoreKey.java
deleted file mode 100644
index 6d69984..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/mcast/McastFilteringObjStoreKey.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright 2018-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.mcast;
-
-import org.onlab.packet.VlanId;
-import org.onosproject.net.ConnectPoint;
-
-import java.util.Objects;
-
-import static com.google.common.base.MoreObjects.toStringHelper;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-/**
- * Key of multicast filtering objective store.
- */
-public class McastFilteringObjStoreKey {
-
- private final ConnectPoint ingressCP;
- private final VlanId vlanId;
- private final boolean isIpv4;
-
- /**
- * Constructs the key of multicast filtering objective store.
- *
- * @param ingressCP ingress ConnectPoint
- * @param vlanId vlan id
- * @param isIpv4 is Ipv4
- */
- public McastFilteringObjStoreKey(ConnectPoint ingressCP, VlanId vlanId, boolean isIpv4) {
- checkNotNull(ingressCP, "connectpoint cannot be null");
- checkNotNull(vlanId, "vlanid cannot be null");
- this.ingressCP = ingressCP;
- this.vlanId = vlanId;
- this.isIpv4 = isIpv4;
- }
-
- // Constructor for serialization
- private McastFilteringObjStoreKey() {
- this.ingressCP = null;
- this.vlanId = null;
- this.isIpv4 = false;
- }
-
-
- /**
- * Returns the connect point.
- *
- * @return ingress connectpoint
- */
- public ConnectPoint ingressCP() {
- return ingressCP;
- }
-
- /**
- * Returns whether the filtering is for ipv4 mcast.
- *
- * @return isIpv4
- */
- public boolean isIpv4() {
- return isIpv4;
- }
-
- /**
- * Returns the vlan ID of this key.
- *
- * @return vlan ID
- */
- public VlanId vlanId() {
- return vlanId;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (!(o instanceof McastFilteringObjStoreKey)) {
- return false;
- }
- McastFilteringObjStoreKey that =
- (McastFilteringObjStoreKey) o;
- return (Objects.equals(this.ingressCP, that.ingressCP) &&
- Objects.equals(this.isIpv4, that.isIpv4) &&
- Objects.equals(this.vlanId, that.vlanId));
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(ingressCP, vlanId, isIpv4);
- }
-
- @Override
- public String toString() {
- return toStringHelper(getClass())
- .add("ingressCP", ingressCP)
- .add("isIpv4", isIpv4)
- .add("vlanId", vlanId)
- .toString();
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/mcast/McastFilteringObjStoreSerializer.java b/app/src/main/java/org/onosproject/segmentrouting/mcast/McastFilteringObjStoreSerializer.java
deleted file mode 100644
index a23fa69..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/mcast/McastFilteringObjStoreSerializer.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2018-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.mcast;
-
-
-import com.esotericsoftware.kryo.Kryo;
-import com.esotericsoftware.kryo.Serializer;
-import com.esotericsoftware.kryo.io.Input;
-import com.esotericsoftware.kryo.io.Output;
-import org.onlab.packet.VlanId;
-import org.onosproject.net.ConnectPoint;
-
-/**
- * Custom serializer for {@link McastFilteringObjStoreKey}.
- */
-class McastFilteringObjStoreSerializer extends Serializer<McastFilteringObjStoreKey> {
-
- /**
- * Creates {@link McastFilteringObjStoreSerializer} serializer instance.
- */
- McastFilteringObjStoreSerializer() {
- // non-null, immutable
- super(false, true);
- }
-
- @Override
- public void write(Kryo kryo, Output output, McastFilteringObjStoreKey object) {
- kryo.writeClassAndObject(output, object.ingressCP());
- kryo.writeClassAndObject(output, object.vlanId());
- kryo.writeClassAndObject(output, object.isIpv4());
- }
-
- @Override
- public McastFilteringObjStoreKey read(Kryo kryo, Input input, Class<McastFilteringObjStoreKey> type) {
- ConnectPoint ingressCP = (ConnectPoint) kryo.readClassAndObject(input);
- VlanId vlanId = (VlanId) kryo.readClassAndObject(input);
- boolean isIpv4 = (boolean) kryo.readClassAndObject(input);
- return new McastFilteringObjStoreKey(ingressCP, vlanId, isIpv4);
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/mcast/McastHandler.java b/app/src/main/java/org/onosproject/segmentrouting/mcast/McastHandler.java
deleted file mode 100644
index 8c4968a..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/mcast/McastHandler.java
+++ /dev/null
@@ -1,2055 +0,0 @@
-/*
- * Copyright 2018-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.mcast;
-
-import com.google.common.base.Objects;
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Sets;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.VlanId;
-import org.onlab.util.KryoNamespace;
-import org.onosproject.cluster.NodeId;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.core.CoreService;
-import org.onosproject.mcast.api.McastEvent;
-import org.onosproject.mcast.api.McastRoute;
-import org.onosproject.mcast.api.McastRouteData;
-import org.onosproject.mcast.api.McastRouteUpdate;
-import org.onosproject.net.Device;
-import org.onosproject.net.HostId;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Link;
-import org.onosproject.net.Path;
-import org.onosproject.net.Port;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.flowobjective.DefaultObjectiveContext;
-import org.onosproject.net.flowobjective.ForwardingObjective;
-import org.onosproject.net.flowobjective.NextObjective;
-import org.onosproject.net.flowobjective.ObjectiveContext;
-import org.onosproject.segmentrouting.SegmentRoutingManager;
-import org.onosproject.store.serializers.KryoNamespaces;
-import org.onosproject.store.service.ConsistentMap;
-import org.onosproject.store.service.ConsistentMultimap;
-import org.onosproject.store.service.DistributedSet;
-import org.onosproject.store.service.Serializer;
-import org.onosproject.store.service.Versioned;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.time.Instant;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.stream.Collectors;
-
-import static java.util.concurrent.Executors.newScheduledThreadPool;
-import static org.onlab.util.Tools.groupedThreads;
-
-import static org.onosproject.mcast.api.McastEvent.Type.ROUTE_ADDED;
-import static org.onosproject.mcast.api.McastEvent.Type.ROUTE_REMOVED;
-import static org.onosproject.mcast.api.McastEvent.Type.SOURCES_ADDED;
-import static org.onosproject.mcast.api.McastEvent.Type.SOURCES_REMOVED;
-import static org.onosproject.mcast.api.McastEvent.Type.SINKS_ADDED;
-import static org.onosproject.mcast.api.McastEvent.Type.SINKS_REMOVED;
-
-import static org.onosproject.segmentrouting.mcast.McastRole.EGRESS;
-import static org.onosproject.segmentrouting.mcast.McastRole.INGRESS;
-import static org.onosproject.segmentrouting.mcast.McastRole.TRANSIT;
-
-/**
- * Handles Multicast related events.
- */
-public class McastHandler {
- // Internal elements
- private static final Logger log = LoggerFactory.getLogger(McastHandler.class);
- private final SegmentRoutingManager srManager;
- private final McastUtils mcastUtils;
- private final ConsistentMap<McastStoreKey, NextObjective> mcastNextObjStore;
- private final ConsistentMap<McastRoleStoreKey, McastRole> mcastRoleStore;
- private final ConsistentMultimap<McastPathStoreKey, List<Link>> mcastPathStore;
- private final DistributedSet<McastFilteringObjStoreKey> mcastFilteringObjStore;
- // Stability threshold for Mcast. Seconds
- private static final long MCAST_STABLITY_THRESHOLD = 5;
- // Verify interval for Mcast bucket corrector
- private static final long MCAST_VERIFY_INTERVAL = 30;
- // Max verify that can be processed at the same time
- private static final int MAX_VERIFY_ON_FLIGHT = 10;
- // Last change done
- private AtomicReference<Instant> lastMcastChange = new AtomicReference<>(Instant.now());
- // Last bucker corrector execution
- private AtomicReference<Instant> lastBktCorrExecution = new AtomicReference<>(Instant.now());
- // Executors for mcast bucket corrector and for the events
- private ScheduledExecutorService mcastCorrector
- = newScheduledThreadPool(1, groupedThreads("onos", "m-corrector", log));
- private ScheduledExecutorService mcastWorker
- = newScheduledThreadPool(1, groupedThreads("onos", "m-worker-%d", log));
-
- /**
- * Constructs the McastEventHandler.
- *
- * @param srManager Segment Routing manager
- */
- public McastHandler(SegmentRoutingManager srManager) {
- ApplicationId coreAppId = srManager.coreService.getAppId(CoreService.CORE_APP_NAME);
- this.srManager = srManager;
- KryoNamespace.Builder mcastKryo = new KryoNamespace.Builder()
- .register(KryoNamespaces.API)
- .register(new McastStoreKeySerializer(), McastStoreKey.class);
- mcastNextObjStore = srManager.storageService
- .<McastStoreKey, NextObjective>consistentMapBuilder()
- .withName("onos-mcast-nextobj-store")
- .withSerializer(Serializer.using(mcastKryo.build("McastHandler-NextObj")))
- .build();
- mcastKryo = new KryoNamespace.Builder()
- .register(KryoNamespaces.API)
- .register(new McastRoleStoreKeySerializer(), McastRoleStoreKey.class)
- .register(McastRole.class);
- mcastRoleStore = srManager.storageService
- .<McastRoleStoreKey, McastRole>consistentMapBuilder()
- .withName("onos-mcast-role-store")
- .withSerializer(Serializer.using(mcastKryo.build("McastHandler-Role")))
- .build();
- mcastKryo = new KryoNamespace.Builder()
- .register(KryoNamespaces.API)
- .register(new McastFilteringObjStoreSerializer(), McastFilteringObjStoreKey.class);
- mcastFilteringObjStore = srManager.storageService
- .<McastFilteringObjStoreKey>setBuilder()
- .withName("onos-mcast-filtering-store")
- .withSerializer(Serializer.using(mcastKryo.build("McastHandler-FilteringObj")))
- .build()
- .asDistributedSet();
- mcastKryo = new KryoNamespace.Builder()
- .register(KryoNamespaces.API)
- .register(new McastPathStoreKeySerializer(), McastPathStoreKey.class);
- mcastPathStore = srManager.storageService
- .<McastPathStoreKey, List<Link>>consistentMultimapBuilder()
- .withName("onos-mcast-path-store")
- .withSerializer(Serializer.using(mcastKryo.build("McastHandler-Path")))
- .build();
- mcastUtils = new McastUtils(srManager, coreAppId, log);
- // Init the executor for the buckets corrector
- mcastCorrector.scheduleWithFixedDelay(new McastBucketCorrector(), 10,
- MCAST_VERIFY_INTERVAL, TimeUnit.SECONDS);
- }
-
- /**
- * Determines if mcast in the network has been stable in the last
- * MCAST_STABLITY_THRESHOLD seconds, by comparing the current time
- * to the last mcast change timestamp.
- *
- * @return true if stable
- */
- private boolean isMcastStable() {
- long last = (long) (lastMcastChange.get().toEpochMilli() / 1000.0);
- long now = (long) (Instant.now().toEpochMilli() / 1000.0);
- log.trace("Multicast stable since {}s", now - last);
- return (now - last) > MCAST_STABLITY_THRESHOLD;
- }
-
- /**
- * Assures there are always MCAST_VERIFY_INTERVAL seconds between each execution,
- * by comparing the current time with the last corrector execution.
- *
- * @return true if stable
- */
- private boolean wasBktCorrRunning() {
- long last = (long) (lastBktCorrExecution.get().toEpochMilli() / 1000.0);
- long now = (long) (Instant.now().toEpochMilli() / 1000.0);
- log.trace("McastBucketCorrector executed {}s ago", now - last);
- return (now - last) < MCAST_VERIFY_INTERVAL;
- }
-
- /**
- * Read initial multicast configuration from mcast store.
- */
- public void init() {
- mcastWorker.execute(this::initInternal);
- }
-
- private void initInternal() {
- srManager.multicastRouteService.getRoutes().forEach(mcastRoute -> {
- lastMcastChange.set(Instant.now());
- log.debug("Init group {}", mcastRoute.group());
- if (!mcastUtils.isLeader(mcastRoute.group())) {
- log.debug("Skip {} due to lack of leadership", mcastRoute.group());
- return;
- }
- McastRouteData mcastRouteData = srManager.multicastRouteService.routeData(mcastRoute);
- // For each source process the mcast tree
- srManager.multicastRouteService.sources(mcastRoute).forEach(source -> {
- McastPathStoreKey pathStoreKey = new McastPathStoreKey(mcastRoute.group(), source);
- Collection<? extends List<Link>> storedPaths = Versioned.valueOrElse(
- mcastPathStore.get(pathStoreKey), Lists.newArrayList());
- Map<ConnectPoint, List<ConnectPoint>> mcastPaths = buildMcastPaths(storedPaths, mcastRoute.group(),
- source);
- // Get all the sinks and process them
- Set<ConnectPoint> sinks = processSinksToBeAdded(source, mcastRoute.group(),
- mcastRouteData.sinks());
- // Filter out all the working sinks, we do not want to move them
- // TODO we need a better way to distinguish flows coming from different sources
- sinks = sinks.stream()
- .filter(sink -> !mcastPaths.containsKey(sink) ||
- !isSinkForSource(mcastRoute.group(), sink, source))
- .collect(Collectors.toSet());
- if (sinks.isEmpty()) {
- log.debug("Skip {} for source {} nothing to do", mcastRoute.group(), source);
- return;
- }
- Map<ConnectPoint, List<Path>> mcasTree = mcastUtils.computeSinkMcastTree(mcastRoute.group(),
- source.deviceId(), sinks);
- mcasTree.forEach((sink, paths) -> processSinkAddedInternal(source, sink, mcastRoute.group(),
- null));
- });
- });
- }
-
- /**
- * Clean up when deactivating the application.
- */
- public void terminate() {
- mcastCorrector.shutdown();
- mcastWorker.shutdown();
- mcastNextObjStore.destroy();
- mcastRoleStore.destroy();
- mcastFilteringObjStore.destroy();
- mcastPathStore.destroy();
- mcastUtils.terminate();
- log.info("Terminated");
- }
-
- /**
- * Processes the SOURCE_ADDED, SOURCE_UPDATED, SINK_ADDED,
- * SINK_REMOVED, ROUTE_ADDED and ROUTE_REMOVED events.
- *
- * @param event the multicast event to be processed
- */
- public void processMcastEvent(McastEvent event) {
- mcastWorker.execute(() -> processMcastEventInternal(event));
- }
-
- private void processMcastEventInternal(McastEvent event) {
- lastMcastChange.set(Instant.now());
- // Current subject is null, for ROUTE_REMOVED events
- final McastRouteUpdate mcastUpdate = event.subject();
- final McastRouteUpdate mcastPrevUpdate = event.prevSubject();
- IpAddress mcastIp = mcastPrevUpdate.route().group();
- Set<ConnectPoint> prevSinks = mcastPrevUpdate.sinks()
- .values().stream().flatMap(Collection::stream).collect(Collectors.toSet());
- Set<ConnectPoint> prevSources = mcastPrevUpdate.sources()
- .values().stream().flatMap(Collection::stream).collect(Collectors.toSet());
- Set<ConnectPoint> sources;
- // Events handling
- if (event.type() == ROUTE_ADDED) {
- processRouteAddedInternal(mcastUpdate.route().group());
- } else if (event.type() == ROUTE_REMOVED) {
- processRouteRemovedInternal(prevSources, mcastIp);
- } else if (event.type() == SOURCES_ADDED) {
- // Current subject and prev just differ for the source connect points
- sources = mcastUpdate.sources()
- .values().stream().flatMap(Collection::stream).collect(Collectors.toSet());
- Set<ConnectPoint> sourcesToBeAdded = Sets.difference(sources, prevSources);
- processSourcesAddedInternal(sourcesToBeAdded, mcastIp, mcastUpdate.sinks());
- } else if (event.type() == SOURCES_REMOVED) {
- // Current subject and prev just differ for the source connect points
- sources = mcastUpdate.sources()
- .values().stream().flatMap(Collection::stream).collect(Collectors.toSet());
- Set<ConnectPoint> sourcesToBeRemoved = Sets.difference(prevSources, sources);
- processSourcesRemovedInternal(sourcesToBeRemoved, sources, mcastIp, mcastUpdate.sinks());
- } else if (event.type() == SINKS_ADDED) {
- processSinksAddedInternal(prevSources, mcastIp, mcastUpdate.sinks(), prevSinks);
- } else if (event.type() == SINKS_REMOVED) {
- processSinksRemovedInternal(prevSources, mcastIp, mcastUpdate.sinks(), mcastPrevUpdate.sinks());
- } else {
- log.warn("Event {} not handled", event);
- }
- }
-
- /**
- * Process the SOURCES_ADDED event.
- *
- * @param sources the sources connect point
- * @param mcastIp the group address
- * @param sinks the sinks connect points
- */
- private void processSourcesAddedInternal(Set<ConnectPoint> sources, IpAddress mcastIp,
- Map<HostId, Set<ConnectPoint>> sinks) {
- lastMcastChange.set(Instant.now());
- log.info("Processing sources added {} for group {}", sources, mcastIp);
- if (!mcastUtils.isLeader(mcastIp)) {
- log.debug("Skip {} due to lack of leadership", mcastIp);
- return;
- }
- if (sources.isEmpty()) {
- log.debug("Skip {} due to empty sources to be added", mcastIp);
- return;
- }
- sources.forEach(source -> {
- Set<ConnectPoint> sinksToBeAdded = processSinksToBeAdded(source, mcastIp, sinks);
- Map<ConnectPoint, List<Path>> mcasTree = mcastUtils.computeSinkMcastTree(mcastIp, source.deviceId(),
- sinksToBeAdded);
- mcasTree.forEach((sink, paths) -> processSinkAddedInternal(source, sink, mcastIp, paths));
- });
- }
-
- /**
- * Process the SOURCES_REMOVED event.
- *
- * @param sourcesToBeRemoved the source connect points to be removed
- * @param remainingSources the remainig source connect points
- * @param mcastIp the group address
- * @param sinks the sinks connect points
- */
- private void processSourcesRemovedInternal(Set<ConnectPoint> sourcesToBeRemoved,
- Set<ConnectPoint> remainingSources,
- IpAddress mcastIp,
- Map<HostId, Set<ConnectPoint>> sinks) {
- lastMcastChange.set(Instant.now());
- log.info("Processing sources removed {} for group {}", sourcesToBeRemoved, mcastIp);
- if (!mcastUtils.isLeader(mcastIp)) {
- log.debug("Skip {} due to lack of leadership", mcastIp);
- return;
- }
- if (remainingSources.isEmpty()) {
- log.debug("There are no more sources for {}", mcastIp);
- processRouteRemovedInternal(sourcesToBeRemoved, mcastIp);
- return;
- }
- // Let's heal the trees
- Set<Link> notAffectedLinks = Sets.newHashSet();
- Map<ConnectPoint, Set<Link>> affectedLinks = Maps.newHashMap();
- Map<ConnectPoint, Set<ConnectPoint>> candidateSinks = Maps.newHashMap();
- Set<ConnectPoint> totalSources = Sets.newHashSet(sourcesToBeRemoved);
- totalSources.addAll(remainingSources);
- // Calculate all the links used by the sources and the current sinks
- totalSources.forEach(source -> {
- Set<ConnectPoint> currentSinks = sinks.values()
- .stream().flatMap(Collection::stream)
- .filter(sink -> isSinkForSource(mcastIp, sink, source))
- .collect(Collectors.toSet());
- candidateSinks.put(source, currentSinks);
- McastPathStoreKey pathStoreKey = new McastPathStoreKey(mcastIp, source);
- Collection<? extends List<Link>> storedPaths = Versioned.valueOrElse(
- mcastPathStore.get(pathStoreKey), Lists.newArrayList());
- currentSinks.forEach(currentSink -> {
- Optional<? extends List<Link>> currentPath = mcastUtils.getStoredPath(currentSink.deviceId(),
- storedPaths);
- if (currentPath.isPresent()) {
- if (!sourcesToBeRemoved.contains(source)) {
- notAffectedLinks.addAll(currentPath.get());
- } else {
- affectedLinks.compute(source, (k, v) -> {
- v = v == null ? Sets.newHashSet() : v;
- v.addAll(currentPath.get());
- return v;
- });
- }
- }
- });
- });
- // Clean transit links
- affectedLinks.forEach((source, currentCandidateLinks) -> {
- Set<Link> linksToBeRemoved = Sets.difference(currentCandidateLinks, notAffectedLinks)
- .immutableCopy();
- if (!linksToBeRemoved.isEmpty()) {
- currentCandidateLinks.forEach(link -> {
- DeviceId srcLink = link.src().deviceId();
- // Remove ports only on links to be removed
- if (linksToBeRemoved.contains(link)) {
- removePortFromDevice(link.src().deviceId(), link.src().port(), mcastIp,
- mcastUtils.assignedVlan(srcLink.equals(source.deviceId()) ?
- source : null));
- }
- // Remove role on the candidate links
- mcastRoleStore.remove(new McastRoleStoreKey(mcastIp, srcLink, source));
- });
- }
- });
- // Clean ingress and egress
- sourcesToBeRemoved.forEach(source -> {
- Set<ConnectPoint> currentSinks = candidateSinks.get(source);
- McastPathStoreKey pathStoreKey = new McastPathStoreKey(mcastIp, source);
- currentSinks.forEach(currentSink -> {
- VlanId assignedVlan = mcastUtils.assignedVlan(source.deviceId().equals(currentSink.deviceId()) ?
- source : null);
- // Sinks co-located with the source
- if (source.deviceId().equals(currentSink.deviceId())) {
- if (source.port().equals(currentSink.port())) {
- log.warn("Skip {} since sink {} is on the same port of source {}. Abort",
- mcastIp, currentSink, source);
- return;
- }
- // We need to check against the other sources and if it is
- // necessary remove the port from the device - no overlap
- Set<VlanId> otherVlans = remainingSources.stream()
- // Only sources co-located and having this sink
- .filter(remainingSource -> remainingSource.deviceId()
- .equals(source.deviceId()) && candidateSinks.get(remainingSource)
- .contains(currentSink))
- .map(remainingSource -> mcastUtils.assignedVlan(
- remainingSource.deviceId().equals(currentSink.deviceId()) ?
- remainingSource : null)).collect(Collectors.toSet());
- if (!otherVlans.contains(assignedVlan)) {
- removePortFromDevice(currentSink.deviceId(), currentSink.port(),
- mcastIp, assignedVlan);
- }
- mcastRoleStore.remove(new McastRoleStoreKey(mcastIp, currentSink.deviceId(),
- source));
- return;
- }
- Set<VlanId> otherVlans = remainingSources.stream()
- .filter(remainingSource -> candidateSinks.get(remainingSource)
- .contains(currentSink))
- .map(remainingSource -> mcastUtils.assignedVlan(
- remainingSource.deviceId().equals(currentSink.deviceId()) ?
- remainingSource : null)).collect(Collectors.toSet());
- // Sinks on other leaves
- if (!otherVlans.contains(assignedVlan)) {
- removePortFromDevice(currentSink.deviceId(), currentSink.port(),
- mcastIp, assignedVlan);
- }
- mcastRoleStore.remove(new McastRoleStoreKey(mcastIp, currentSink.deviceId(),
- source));
- });
- // Clean the mcast paths
- mcastPathStore.removeAll(pathStoreKey);
- });
- }
-
- /**
- * Process the ROUTE_ADDED event.
- *
- * @param mcastIp the group address
- */
- private void processRouteAddedInternal(IpAddress mcastIp) {
- lastMcastChange.set(Instant.now());
- log.info("Processing route added for Multicast group {}", mcastIp);
- // Just elect a new leader
- mcastUtils.isLeader(mcastIp);
- }
-
- /**
- * Removes the entire mcast tree related to this group.
- * @param sources the source connect points
- * @param mcastIp multicast group IP address
- */
- private void processRouteRemovedInternal(Set<ConnectPoint> sources, IpAddress mcastIp) {
- lastMcastChange.set(Instant.now());
- log.info("Processing route removed for group {}", mcastIp);
- if (!mcastUtils.isLeader(mcastIp)) {
- log.debug("Skip {} due to lack of leadership", mcastIp);
- mcastUtils.withdrawLeader(mcastIp);
- return;
- }
- sources.forEach(source -> {
- // Find out the ingress, transit and egress device of the affected group
- DeviceId ingressDevice = getDevice(mcastIp, INGRESS, source)
- .stream().findFirst().orElse(null);
- Set<DeviceId> transitDevices = getDevice(mcastIp, TRANSIT, source);
- Set<DeviceId> egressDevices = getDevice(mcastIp, EGRESS, source);
- McastPathStoreKey pathStoreKey = new McastPathStoreKey(mcastIp, source);
- // If there are no egress and transit devices, sinks could be only on the ingress
- if (!egressDevices.isEmpty()) {
- egressDevices.forEach(deviceId -> {
- removeGroupFromDevice(deviceId, mcastIp, mcastUtils.assignedVlan(null));
- mcastRoleStore.remove(new McastRoleStoreKey(mcastIp, deviceId, source));
- });
- }
- if (!transitDevices.isEmpty()) {
- transitDevices.forEach(deviceId -> {
- removeGroupFromDevice(deviceId, mcastIp, mcastUtils.assignedVlan(null));
- mcastRoleStore.remove(new McastRoleStoreKey(mcastIp, deviceId, source));
- });
- }
- if (ingressDevice != null) {
- removeGroupFromDevice(ingressDevice, mcastIp, mcastUtils.assignedVlan(source));
- mcastRoleStore.remove(new McastRoleStoreKey(mcastIp, ingressDevice, source));
- }
- // Clean the mcast paths
- mcastPathStore.removeAll(pathStoreKey);
- });
- // Finally, withdraw the leadership
- mcastUtils.withdrawLeader(mcastIp);
- }
-
- /**
- * Process sinks to be removed.
- *
- * @param sources the source connect points
- * @param mcastIp the ip address of the group
- * @param newSinks the new sinks to be processed
- * @param prevSinks the previous sinks
- */
- private void processSinksRemovedInternal(Set<ConnectPoint> sources, IpAddress mcastIp,
- Map<HostId, Set<ConnectPoint>> newSinks,
- Map<HostId, Set<ConnectPoint>> prevSinks) {
- lastMcastChange.set(Instant.now());
- log.info("Processing sinks removed for group {} and for sources {}",
- mcastIp, sources);
- if (!mcastUtils.isLeader(mcastIp)) {
- log.debug("Skip {} due to lack of leadership", mcastIp);
- return;
- }
- Map<ConnectPoint, Map<ConnectPoint, Optional<? extends List<Link>>>> treesToBeRemoved = Maps.newHashMap();
- Map<ConnectPoint, Set<ConnectPoint>> treesToBeAdded = Maps.newHashMap();
- Set<Link> goodLinks = Sets.newHashSet();
- Map<ConnectPoint, Set<DeviceId>> goodDevicesBySource = Maps.newHashMap();
- sources.forEach(source -> {
- // Save the path associated to the sinks to be removed
- Set<ConnectPoint> sinksToBeRemoved = processSinksToBeRemoved(mcastIp, prevSinks,
- newSinks, source);
- Map<ConnectPoint, Optional<? extends List<Link>>> treeToBeRemoved = Maps.newHashMap();
- McastPathStoreKey pathStoreKey = new McastPathStoreKey(mcastIp, source);
- Collection<? extends List<Link>> storedPaths = Versioned.valueOrElse(
- mcastPathStore.get(pathStoreKey), Lists.newArrayList());
- sinksToBeRemoved.forEach(sink -> treeToBeRemoved.put(sink, mcastUtils.getStoredPath(sink.deviceId(),
- storedPaths)));
- treesToBeRemoved.put(source, treeToBeRemoved);
- // Save the good links and good devices
- Set<DeviceId> goodDevices = Sets.newHashSet();
- Set<DeviceId> totalDevices = Sets.newHashSet(getDevice(mcastIp, EGRESS, source));
- totalDevices.addAll(getDevice(mcastIp, INGRESS, source));
- Set<ConnectPoint> notAffectedSinks = Sets.newHashSet();
- // Compute good sinks
- totalDevices.forEach(device -> {
- Set<ConnectPoint> sinks = getSinks(mcastIp, device, source);
- notAffectedSinks.addAll(Sets.difference(sinks, sinksToBeRemoved));
- });
- // Compute good paths and good devices
- notAffectedSinks.forEach(notAffectedSink -> {
- Optional<? extends List<Link>> notAffectedPath = mcastUtils.getStoredPath(notAffectedSink.deviceId(),
- storedPaths);
- if (notAffectedPath.isPresent()) {
- List<Link> goodPath = notAffectedPath.get();
- goodLinks.addAll(goodPath);
- goodPath.forEach(link -> goodDevices.add(link.src().deviceId()));
- } else {
- goodDevices.add(notAffectedSink.deviceId());
- }
- });
- goodDevicesBySource.compute(source, (k, v) -> {
- v = v == null ? Sets.newHashSet() : v;
- v.addAll(goodDevices);
- return v;
- });
- // Recover the dual-homed sinks
- Set<ConnectPoint> sinksToBeRecovered = processSinksToBeRecovered(mcastIp, newSinks,
- prevSinks, source);
- treesToBeAdded.put(source, sinksToBeRecovered);
- });
- // Remove the sinks taking into account the multiple sources and the original paths
- treesToBeRemoved.forEach((source, tree) ->
- tree.forEach((sink, path) -> processSinkRemovedInternal(source, sink, mcastIp, path,
- goodLinks, goodDevicesBySource.get(source))));
- // Add new sinks according to the recovery procedure
- treesToBeAdded.forEach((source, sinks) ->
- sinks.forEach(sink -> processSinkAddedInternal(source, sink, mcastIp, null)));
- }
-
- /**
- * Removes a path from source to sink for given multicast group.
- *
- * @param source connect point of the multicast source
- * @param sink connection point of the multicast sink
- * @param mcastIp multicast group IP address
- * @param mcastPath path associated to the sink
- * @param usedLinks links used by the other sinks
- * @param usedDevices devices used by other sinks
- */
- private void processSinkRemovedInternal(ConnectPoint source, ConnectPoint sink,
- IpAddress mcastIp, Optional<? extends List<Link>> mcastPath,
- Set<Link> usedLinks, Set<DeviceId> usedDevices) {
-
- log.info("Used links {}", usedLinks);
- log.info("Used devices {}", usedDevices);
-
- lastMcastChange.set(Instant.now());
- log.info("Processing sink removed {} for group {} and for source {}", sink, mcastIp, source);
- boolean isLast;
- // When source and sink are on the same device
- if (source.deviceId().equals(sink.deviceId())) {
- // Source and sink are on even the same port. There must be something wrong.
- if (source.port().equals(sink.port())) {
- log.warn("Skip {} since sink {} is on the same port of source {}. Abort", mcastIp, sink, source);
- return;
- }
- isLast = removePortFromDevice(sink.deviceId(), sink.port(), mcastIp, mcastUtils.assignedVlan(source));
- if (isLast) {
- mcastRoleStore.remove(new McastRoleStoreKey(mcastIp, sink.deviceId(), source));
- }
- return;
- }
- // Process the egress device
- isLast = removePortFromDevice(sink.deviceId(), sink.port(), mcastIp, mcastUtils.assignedVlan(null));
- if (isLast) {
- mcastRoleStore.remove(new McastRoleStoreKey(mcastIp, sink.deviceId(), source));
- }
- // If this is the last sink on the device, also update upstream
- if (mcastPath.isPresent()) {
- List<Link> links = Lists.newArrayList(mcastPath.get());
- if (isLast) {
- // Clean the path
- McastPathStoreKey pathStoreKey = new McastPathStoreKey(mcastIp, source);
- mcastPathStore.remove(pathStoreKey, mcastPath.get());
- Collections.reverse(links);
- for (Link link : links) {
- // If nobody is using the port remove
- if (!usedLinks.contains(link)) {
- removePortFromDevice(link.src().deviceId(), link.src().port(), mcastIp,
- mcastUtils.assignedVlan(link.src().deviceId().equals(source.deviceId()) ? source : null));
- }
- // If nobody is using the device
- if (!usedDevices.contains(link.src().deviceId())) {
- mcastRoleStore.remove(new McastRoleStoreKey(mcastIp, link.src().deviceId(), source));
- }
- }
- }
- }
- }
-
- /**
- * Process sinks to be added.
- *
- * @param sources the source connect points
- * @param mcastIp the group IP
- * @param newSinks the new sinks to be processed
- * @param allPrevSinks all previous sinks
- */
- private void processSinksAddedInternal(Set<ConnectPoint> sources, IpAddress mcastIp,
- Map<HostId, Set<ConnectPoint>> newSinks,
- Set<ConnectPoint> allPrevSinks) {
- lastMcastChange.set(Instant.now());
- log.info("Processing sinks added for group {} and for sources {}", mcastIp, sources);
- if (!mcastUtils.isLeader(mcastIp)) {
- log.debug("Skip {} due to lack of leadership", mcastIp);
- return;
- }
- sources.forEach(source -> {
- Set<ConnectPoint> sinksToBeAdded = processSinksToBeAdded(source, mcastIp, newSinks);
- sinksToBeAdded = Sets.difference(sinksToBeAdded, allPrevSinks);
- sinksToBeAdded.forEach(sink -> processSinkAddedInternal(source, sink, mcastIp, null));
- });
- }
-
- /**
- * Establishes a path from source to sink for given multicast group.
- *
- * @param source connect point of the multicast source
- * @param sink connection point of the multicast sink
- * @param mcastIp multicast group IP address
- */
- private void processSinkAddedInternal(ConnectPoint source, ConnectPoint sink,
- IpAddress mcastIp, List<Path> allPaths) {
- lastMcastChange.set(Instant.now());
- log.info("Processing sink added {} for group {} and for source {}", sink, mcastIp, source);
- // Process the ingress device
- McastFilteringObjStoreKey mcastFilterObjStoreKey = new McastFilteringObjStoreKey(source,
- mcastUtils.assignedVlan(source), mcastIp.isIp4());
- addFilterToDevice(mcastFilterObjStoreKey, mcastIp, INGRESS);
- if (source.deviceId().equals(sink.deviceId())) {
- if (source.port().equals(sink.port())) {
- log.warn("Skip {} since sink {} is on the same port of source {}. Abort",
- mcastIp, sink, source);
- return;
- }
- addPortToDevice(sink.deviceId(), sink.port(), mcastIp, mcastUtils.assignedVlan(source));
- mcastRoleStore.put(new McastRoleStoreKey(mcastIp, sink.deviceId(), source), INGRESS);
- return;
- }
- // Find a path. If present, create/update groups and flows for each hop
- Optional<Path> mcastPath = getPath(source.deviceId(), sink.deviceId(), mcastIp, allPaths);
- if (mcastPath.isPresent()) {
- List<Link> links = mcastPath.get().links();
- McastPathStoreKey pathStoreKey = new McastPathStoreKey(mcastIp, source);
- // Setup mcast role for ingress
- mcastRoleStore.put(new McastRoleStoreKey(mcastIp, source.deviceId(), source), INGRESS);
- // Setup properly the transit forwarding
- links.forEach(link -> {
- addPortToDevice(link.src().deviceId(), link.src().port(), mcastIp,
- mcastUtils.assignedVlan(link.src().deviceId()
- .equals(source.deviceId()) ? source : null));
- McastFilteringObjStoreKey filteringKey = new McastFilteringObjStoreKey(link.dst(),
- mcastUtils.assignedVlan(null), mcastIp.isIp4());
- addFilterToDevice(filteringKey, mcastIp, null);
- });
- // Setup mcast role for the transit
- links.stream()
- .filter(link -> !link.dst().deviceId().equals(sink.deviceId()))
- .forEach(link -> mcastRoleStore.put(new McastRoleStoreKey(mcastIp, link.dst().deviceId(),
- source), TRANSIT));
- // Process the egress device
- addPortToDevice(sink.deviceId(), sink.port(), mcastIp, mcastUtils.assignedVlan(null));
- // Setup mcast role for egress
- mcastRoleStore.put(new McastRoleStoreKey(mcastIp, sink.deviceId(), source), EGRESS);
- // Store the used path
- mcastPathStore.put(pathStoreKey, links);
- } else {
- log.warn("Unable to find a path from {} to {}. Abort sinkAdded", source.deviceId(), sink.deviceId());
- }
- }
-
- /**
- * Processes the PORT_UPDATED event.
- *
- * @param affectedDevice Affected device
- * @param affectedPort Affected port
- */
- public void processPortUpdate(Device affectedDevice, Port affectedPort) {
- mcastWorker.execute(() -> processPortUpdateInternal(affectedDevice, affectedPort));
- }
-
- private void processPortUpdateInternal(Device affectedDevice, Port affectedPort) {
- // Clean the filtering obj store. Edge port case.
- lastMcastChange.set(Instant.now());
- ConnectPoint portDown = new ConnectPoint(affectedDevice.id(), affectedPort.number());
- if (!affectedPort.isEnabled()) {
- log.info("Processing port down {}", portDown);
- updateFilterObjStoreByPort(portDown);
- }
- }
-
- /**
- * Processes the LINK_DOWN event.
- *
- * @param linkDown Link that is going down
- */
- public void processLinkDown(Link linkDown) {
- mcastWorker.execute(() -> processLinkDownInternal(linkDown));
- }
-
- private void processLinkDownInternal(Link linkDown) {
- // Get mcast groups affected by the link going down
- Set<IpAddress> affectedGroups = getAffectedGroups(linkDown);
- log.info("Processing link down {} for groups {}", linkDown, affectedGroups);
- affectedGroups.forEach(mcastIp -> {
- lastMcastChange.set(Instant.now());
- log.debug("Processing link down {} for group {}", linkDown, mcastIp);
- recoverFailure(mcastIp, linkDown);
- });
- }
-
- /**
- * Process the DEVICE_DOWN event.
- *
- * @param deviceDown device going down
- */
- public void processDeviceDown(DeviceId deviceDown) {
- mcastWorker.execute(() -> processDeviceDownInternal(deviceDown));
- }
-
- private void processDeviceDownInternal(DeviceId deviceDown) {
- // Get the mcast groups affected by the device going down
- Set<IpAddress> affectedGroups = getAffectedGroups(deviceDown);
- log.info("Processing device down {} for groups {}", deviceDown, affectedGroups);
- updateFilterObjStoreByDevice(deviceDown);
- affectedGroups.forEach(mcastIp -> {
- lastMcastChange.set(Instant.now());
- log.debug("Processing device down {} for group {}", deviceDown, mcastIp);
- recoverFailure(mcastIp, deviceDown);
- });
- }
-
- /**
- * General failure recovery procedure.
- *
- * @param mcastIp the group to recover
- * @param failedElement the failed element
- */
- private void recoverFailure(IpAddress mcastIp, Object failedElement) {
- // Do not proceed if we are not the leaders
- if (!mcastUtils.isLeader(mcastIp)) {
- log.debug("Skip {} due to lack of leadership", mcastIp);
- return;
- }
- // Skip if it is not an infra failure
- Set<DeviceId> transitDevices = getDevice(mcastIp, TRANSIT);
- if (!mcastUtils.isInfraFailure(transitDevices, failedElement)) {
- log.debug("Skip {} not an infrastructure failure", mcastIp);
- return;
- }
- // Do not proceed if the sources of this group are missing
- Set<ConnectPoint> sources = getSources(mcastIp);
- if (sources.isEmpty()) {
- log.warn("Missing sources for group {}", mcastIp);
- return;
- }
- // Get all the paths, affected paths, good links and good devices
- Set<List<Link>> storedPaths = getStoredPaths(mcastIp);
- Set<List<Link>> affectedPaths = mcastUtils.getAffectedPaths(storedPaths, failedElement);
- Set<Link> goodLinks = Sets.newHashSet();
- Map<DeviceId, Set<DeviceId>> goodDevicesBySource = Maps.newHashMap();
- Map<DeviceId, Set<ConnectPoint>> processedSourcesByEgress = Maps.newHashMap();
- Sets.difference(storedPaths, affectedPaths).forEach(goodPath -> {
- goodLinks.addAll(goodPath);
- DeviceId srcDevice = goodPath.get(0).src().deviceId();
- Set<DeviceId> goodDevices = Sets.newHashSet();
- goodPath.forEach(link -> goodDevices.add(link.src().deviceId()));
- goodDevicesBySource.compute(srcDevice, (k, v) -> {
- v = v == null ? Sets.newHashSet() : v;
- v.addAll(goodDevices);
- return v;
- });
- });
- affectedPaths.forEach(affectedPath -> {
- // TODO remove
- log.info("Good links {}", goodLinks);
- // TODO remove
- log.info("Good devices {}", goodDevicesBySource);
- // TODO trace
- log.info("Healing the path {}", affectedPath);
- DeviceId srcDevice = affectedPath.get(0).src().deviceId();
- DeviceId dstDevice = affectedPath.get(affectedPath.size() - 1).dst().deviceId();
- // Fix in one shot multiple sources
- Set<ConnectPoint> affectedSources = sources.stream()
- .filter(device -> device.deviceId().equals(srcDevice))
- .collect(Collectors.toSet());
- Set<ConnectPoint> processedSources = processedSourcesByEgress.getOrDefault(dstDevice,
- Collections.emptySet());
- Optional<Path> alternativePath = getPath(srcDevice, dstDevice, mcastIp, null);
- // If an alternative is possible go ahead
- if (alternativePath.isPresent()) {
- // TODO trace
- log.info("Alternative path {}", alternativePath.get().links());
- } else {
- // Otherwise try to come up with an alternative
- // TODO trace
- log.info("No alternative path");
- Set<ConnectPoint> notAffectedSources = Sets.difference(sources, affectedSources);
- Set<ConnectPoint> remainingSources = Sets.difference(notAffectedSources, processedSources);
- alternativePath = recoverSinks(dstDevice, mcastIp, affectedSources, remainingSources);
- processedSourcesByEgress.compute(dstDevice, (k, v) -> {
- v = v == null ? Sets.newHashSet() : v;
- v.addAll(affectedSources);
- return v;
- });
- }
- // Recover from the failure if possible
- Optional<Path> finalPath = alternativePath;
- affectedSources.forEach(affectedSource -> {
- // Update the mcastPath store
- McastPathStoreKey mcastPathStoreKey = new McastPathStoreKey(mcastIp, affectedSource);
- // Verify if there are local sinks
- Set<DeviceId> localSinks = getSinks(mcastIp, srcDevice, affectedSource).stream()
- .map(ConnectPoint::deviceId)
- .collect(Collectors.toSet());
- Set<DeviceId> goodDevices = goodDevicesBySource.compute(affectedSource.deviceId(), (k, v) -> {
- v = v == null ? Sets.newHashSet() : v;
- v.addAll(localSinks);
- return v;
- });
- // TODO remove
- log.info("Good devices {}", goodDevicesBySource);
- Collection<? extends List<Link>> storedPathsBySource = Versioned.valueOrElse(
- mcastPathStore.get(mcastPathStoreKey), Lists.newArrayList());
- Optional<? extends List<Link>> storedPath = storedPathsBySource.stream()
- .filter(path -> path.equals(affectedPath))
- .findFirst();
- // Remove bad links
- affectedPath.forEach(affectedLink -> {
- DeviceId affectedDevice = affectedLink.src().deviceId();
- // If there is overlap with good paths - skip it
- if (!goodLinks.contains(affectedLink)) {
- removePortFromDevice(affectedDevice, affectedLink.src().port(), mcastIp,
- mcastUtils.assignedVlan(affectedDevice.equals(affectedSource.deviceId()) ?
- affectedSource : null));
- }
- // Remove role on the affected links if last
- if (!goodDevices.contains(affectedDevice)) {
- mcastRoleStore.remove(new McastRoleStoreKey(mcastIp, affectedDevice, affectedSource));
- }
- });
- // Sometimes the removal fails for serialization issue
- // trying with the original object as workaround
- if (storedPath.isPresent()) {
- mcastPathStore.remove(mcastPathStoreKey, storedPath.get());
- } else {
- log.warn("Unable to find the corresponding path - trying removeal");
- mcastPathStore.remove(mcastPathStoreKey, affectedPath);
- }
- // Program new links
- if (finalPath.isPresent()) {
- List<Link> links = finalPath.get().links();
- installPath(mcastIp, affectedSource, links);
- mcastPathStore.put(mcastPathStoreKey, links);
- links.forEach(link -> goodDevices.add(link.src().deviceId()));
- goodDevicesBySource.compute(srcDevice, (k, v) -> {
- v = v == null ? Sets.newHashSet() : v;
- v.addAll(goodDevices);
- return v;
- });
- goodLinks.addAll(finalPath.get().links());
- }
- });
- });
- }
-
- /**
- * Try to recover sinks using alternative locations.
- *
- * @param notRecovered the device not recovered
- * @param mcastIp the group address
- * @param affectedSources affected sources
- * @param goodSources sources not affected
- */
- private Optional<Path> recoverSinks(DeviceId notRecovered, IpAddress mcastIp,
- Set<ConnectPoint> affectedSources,
- Set<ConnectPoint> goodSources) {
- log.debug("Processing recover sinks on {} for group {}", notRecovered, mcastIp);
- Map<ConnectPoint, Set<ConnectPoint>> affectedSinksBySource = Maps.newHashMap();
- Map<ConnectPoint, Set<ConnectPoint>> sinksBySource = Maps.newHashMap();
- Set<ConnectPoint> sources = Sets.union(affectedSources, goodSources);
- // Hosts influenced by the failure
- Map<HostId, Set<ConnectPoint>> hostIdSetMap = mcastUtils.getAffectedSinks(notRecovered, mcastIp);
- // Locations influenced by the failure
- Set<ConnectPoint> affectedSinks = hostIdSetMap.values()
- .stream()
- .flatMap(Collection::stream)
- .filter(connectPoint -> connectPoint.deviceId().equals(notRecovered))
- .collect(Collectors.toSet());
- // All locations
- Set<ConnectPoint> sinks = hostIdSetMap.values()
- .stream()
- .flatMap(Collection::stream)
- .collect(Collectors.toSet());
- // Maps sinks with the sources
- sources.forEach(source -> {
- Set<ConnectPoint> currentSinks = affectedSinks.stream()
- .filter(sink -> isSinkForSource(mcastIp, sink, source))
- .collect(Collectors.toSet());
- affectedSinksBySource.put(source, currentSinks);
- });
- // Remove sinks one by one if they are not used by other sources
- affectedSources.forEach(affectedSource -> {
- Set<ConnectPoint> currentSinks = affectedSinksBySource.get(affectedSource);
- log.info("Current sinks {} for source {}", currentSinks, affectedSource);
- currentSinks.forEach(currentSink -> {
- VlanId assignedVlan = mcastUtils.assignedVlan(
- affectedSource.deviceId().equals(currentSink.deviceId()) ? affectedSource : null);
- log.info("Assigned vlan {}", assignedVlan);
- Set<VlanId> otherVlans = goodSources.stream()
- .filter(remainingSource -> affectedSinksBySource.get(remainingSource).contains(currentSink))
- .map(remainingSource -> mcastUtils.assignedVlan(
- remainingSource.deviceId().equals(currentSink.deviceId()) ? remainingSource : null))
- .collect(Collectors.toSet());
- log.info("Other vlans {}", otherVlans);
- // Sinks on other leaves
- if (!otherVlans.contains(assignedVlan)) {
- removePortFromDevice(currentSink.deviceId(), currentSink.port(), mcastIp, assignedVlan);
- }
- mcastRoleStore.remove(new McastRoleStoreKey(mcastIp, currentSink.deviceId(), affectedSource));
- });
- });
- // Get the sinks to be added and the new egress
- Set<DeviceId> newEgress = Sets.newHashSet();
- affectedSources.forEach(affectedSource -> {
- Set<ConnectPoint> currentSinks = affectedSinksBySource.get(affectedSource);
- Set<ConnectPoint> newSinks = Sets.difference(sinks, currentSinks);
- sinksBySource.put(affectedSource, newSinks);
- newSinks.stream()
- .map(ConnectPoint::deviceId)
- .forEach(newEgress::add);
- });
- log.info("newEgress {}", newEgress);
- // If there are more than one new egresses, return the problem
- if (newEgress.size() != 1) {
- log.warn("There are {} new egress, wrong configuration. Abort.", newEgress.size());
- return Optional.empty();
- }
- DeviceId egress = newEgress.stream()
- .findFirst()
- .orElse(null);
- DeviceId ingress = affectedSources.stream()
- .map(ConnectPoint::deviceId)
- .findFirst()
- .orElse(null);
- log.info("Ingress {}", ingress);
- if (ingress == null) {
- log.warn("No new ingress, wrong configuration. Abort.");
- return Optional.empty();
- }
- // Get an alternative path
- Optional<Path> alternativePath = getPath(ingress, egress, mcastIp, null);
- // If there are new path install sinks and return path
- if (alternativePath.isPresent()) {
- log.info("Alternative path {}", alternativePath.get().links());
- affectedSources.forEach(affectedSource -> {
- Set<ConnectPoint> newSinks = sinksBySource.get(affectedSource);
- newSinks.forEach(newSink -> {
- addPortToDevice(newSink.deviceId(), newSink.port(), mcastIp, mcastUtils.assignedVlan(null));
- mcastRoleStore.put(new McastRoleStoreKey(mcastIp, newSink.deviceId(), affectedSource), EGRESS);
- });
- });
- return alternativePath;
- }
- // No new path but sinks co-located with sources install sinks and return empty
- if (ingress.equals(egress)) {
- log.info("No Alternative path but sinks co-located");
- affectedSources.forEach(affectedSource -> {
- Set<ConnectPoint> newSinks = sinksBySource.get(affectedSource);
- newSinks.forEach(newSink -> {
- if (affectedSource.port().equals(newSink.port())) {
- log.warn("Skip {} since sink {} is on the same port of source {}. Abort",
- mcastIp, newSink, affectedSource);
- return;
- }
- addPortToDevice(newSink.deviceId(), newSink.port(), mcastIp,
- mcastUtils.assignedVlan(affectedSource));
- mcastRoleStore.put(new McastRoleStoreKey(mcastIp, newSink.deviceId(), affectedSource), INGRESS);
- });
- });
- }
- return Optional.empty();
- }
-
- /**
- * Process all the sinks related to a mcast group and return
- * the ones to be removed.
- *
- * @param mcastIp the group address
- * @param prevsinks the previous sinks to be evaluated
- * @param newSinks the new sinks to be evaluted
- * @param source the source connect point
- * @return the set of the sinks to be removed
- */
- private Set<ConnectPoint> processSinksToBeRemoved(IpAddress mcastIp,
- Map<HostId, Set<ConnectPoint>> prevsinks,
- Map<HostId, Set<ConnectPoint>> newSinks,
- ConnectPoint source) {
- final Set<ConnectPoint> sinksToBeProcessed = Sets.newHashSet();
- log.debug("Processing sinks to be removed for Multicast group {}, source {}",
- mcastIp, source);
- prevsinks.forEach(((hostId, connectPoints) -> {
- if (Objects.equal(HostId.NONE, hostId)) {
- //in this case connect points are single homed sinks.
- //just found the difference btw previous and new sinks for this source.
- Set<ConnectPoint> difference = Sets.difference(connectPoints, newSinks.get(hostId));
- sinksToBeProcessed.addAll(difference);
- return;
- }
- // We have to check with the existing flows
- ConnectPoint sinkToBeProcessed = connectPoints.stream()
- .filter(connectPoint -> isSinkForSource(mcastIp, connectPoint, source))
- .findFirst().orElse(null);
- if (sinkToBeProcessed != null) {
- // If the host has been removed or location has been removed
- if (!newSinks.containsKey(hostId) ||
- !newSinks.get(hostId).contains(sinkToBeProcessed)) {
- sinksToBeProcessed.add(sinkToBeProcessed);
- }
- }
- }));
- // We have done, return the set
- return sinksToBeProcessed;
- }
-
- /**
- * Process new locations and return the set of sinks to be added
- * in the context of the recovery.
- *
- * @param newSinks the remaining sinks
- * @param prevSinks the previous sinks
- * @param source the source connect point
- * @return the set of the sinks to be processed
- */
- private Set<ConnectPoint> processSinksToBeRecovered(IpAddress mcastIp,
- Map<HostId, Set<ConnectPoint>> newSinks,
- Map<HostId, Set<ConnectPoint>> prevSinks,
- ConnectPoint source) {
- final Set<ConnectPoint> sinksToBeProcessed = Sets.newHashSet();
- log.debug("Processing sinks to be recovered for Multicast group {}, source {}",
- mcastIp, source);
- newSinks.forEach((hostId, connectPoints) -> {
- // If it has more than 1 locations
- if (connectPoints.size() > 1 || connectPoints.size() == 0) {
- log.debug("Skip {} since sink {} has {} locations",
- mcastIp, hostId, connectPoints.size());
- return;
- }
- // If previously it had two locations, we need to recover it
- // Filter out if the remaining location is already served
- if (prevSinks.containsKey(hostId) && prevSinks.get(hostId).size() == 2) {
- ConnectPoint sinkToBeProcessed = connectPoints.stream()
- .filter(connectPoint -> !isSinkForSource(mcastIp, connectPoint, source))
- .findFirst().orElse(null);
- if (sinkToBeProcessed != null) {
- sinksToBeProcessed.add(sinkToBeProcessed);
- }
- }
- });
- return sinksToBeProcessed;
- }
-
- /**
- * Process all the sinks related to a mcast group and return
- * the ones to be processed.
- *
- * @param source the source connect point
- * @param mcastIp the group address
- * @param sinks the sinks to be evaluated
- * @return the set of the sinks to be processed
- */
- private Set<ConnectPoint> processSinksToBeAdded(ConnectPoint source, IpAddress mcastIp,
- Map<HostId, Set<ConnectPoint>> sinks) {
- final Set<ConnectPoint> sinksToBeProcessed = Sets.newHashSet();
- log.debug("Processing sinks to be added for Multicast group {}, source {}",
- mcastIp, source);
- sinks.forEach(((hostId, connectPoints) -> {
- //add all connect points that are not tied with any host
- if (Objects.equal(HostId.NONE, hostId)) {
- sinksToBeProcessed.addAll(connectPoints);
- return;
- }
- // If it has more than 2 locations
- if (connectPoints.size() > 2 || connectPoints.size() == 0) {
- log.debug("Skip {} since sink {} has {} locations",
- mcastIp, hostId, connectPoints.size());
- return;
- }
- // If it has one location, just use it
- if (connectPoints.size() == 1) {
- sinksToBeProcessed.add(connectPoints.stream().findFirst().orElse(null));
- return;
- }
- // We prefer to reuse existing flows
- ConnectPoint sinkToBeProcessed = connectPoints.stream()
- .filter(connectPoint -> {
- if (!isSinkForGroup(mcastIp, connectPoint, source)) {
- return false;
- }
- if (!isSinkReachable(mcastIp, connectPoint, source)) {
- return false;
- }
- ConnectPoint other = connectPoints.stream()
- .filter(remaining -> !remaining.equals(connectPoint))
- .findFirst().orElse(null);
- // We are already serving the sink
- return !isSinkForSource(mcastIp, other, source);
- }).findFirst().orElse(null);
-
- if (sinkToBeProcessed != null) {
- sinksToBeProcessed.add(sinkToBeProcessed);
- return;
- }
- // Otherwise we prefer to reuse existing egresses
- Set<DeviceId> egresses = getDevice(mcastIp, EGRESS, source);
- sinkToBeProcessed = connectPoints.stream()
- .filter(connectPoint -> {
- if (!egresses.contains(connectPoint.deviceId())) {
- return false;
- }
- if (!isSinkReachable(mcastIp, connectPoint, source)) {
- return false;
- }
- ConnectPoint other = connectPoints.stream()
- .filter(remaining -> !remaining.equals(connectPoint))
- .findFirst().orElse(null);
- return !isSinkForSource(mcastIp, other, source);
- }).findFirst().orElse(null);
- if (sinkToBeProcessed != null) {
- sinksToBeProcessed.add(sinkToBeProcessed);
- return;
- }
- // Otherwise we prefer a location co-located with the source (if it exists)
- sinkToBeProcessed = connectPoints.stream()
- .filter(connectPoint -> connectPoint.deviceId().equals(source.deviceId()))
- .findFirst().orElse(null);
- if (sinkToBeProcessed != null) {
- sinksToBeProcessed.add(sinkToBeProcessed);
- return;
- }
- // Finally, we randomly pick a new location if it is reachable
- sinkToBeProcessed = connectPoints.stream()
- .filter(connectPoint -> {
- if (!isSinkReachable(mcastIp, connectPoint, source)) {
- return false;
- }
- ConnectPoint other = connectPoints.stream()
- .filter(remaining -> !remaining.equals(connectPoint))
- .findFirst().orElse(null);
- return !isSinkForSource(mcastIp, other, source);
- }).findFirst().orElse(null);
- if (sinkToBeProcessed != null) {
- sinksToBeProcessed.add(sinkToBeProcessed);
- }
- }));
- return sinksToBeProcessed;
- }
-
- /**
- * Adds a port to given multicast group on given device. This involves the
- * update of L3 multicast group and multicast routing table entry.
- *
- * @param deviceId device ID
- * @param port port to be added
- * @param mcastIp multicast group
- * @param assignedVlan assigned VLAN ID
- */
- private void addPortToDevice(DeviceId deviceId, PortNumber port,
- IpAddress mcastIp, VlanId assignedVlan) {
- // TODO trace
- log.info("Adding {} on {}/{} and vlan {}", mcastIp, deviceId, port, assignedVlan);
- McastStoreKey mcastStoreKey = new McastStoreKey(mcastIp, deviceId, assignedVlan);
- ImmutableSet.Builder<PortNumber> portBuilder = ImmutableSet.builder();
- NextObjective newNextObj;
- if (!mcastNextObjStore.containsKey(mcastStoreKey)) {
- // First time someone request this mcast group via this device
- portBuilder.add(port);
- // New nextObj
- if (!srManager.deviceConfiguration().isConfigured(deviceId)) {
- log.debug("Passing 0 as nextId for unconfigured device {}", deviceId);
- newNextObj = mcastUtils.nextObjBuilder(mcastIp, assignedVlan,
- portBuilder.build(), 0).add();
- } else {
- newNextObj = mcastUtils.nextObjBuilder(mcastIp, assignedVlan,
- portBuilder.build(), null).add();
- }
- // Store the new port
- mcastNextObjStore.put(mcastStoreKey, newNextObj);
- // Create, store and apply the new nextObj and fwdObj
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> log.debug("Successfully add {} on {}/{}, vlan {}",
- mcastIp, deviceId, port.toLong(), assignedVlan),
- (objective, error) -> {
- log.warn("Failed to add {} on {}/{}, vlan {}: {}",
- mcastIp, deviceId, port.toLong(), assignedVlan, error);
- // Schedule the removal using directly the key
- mcastWorker.execute(() -> mcastNextObjStore.remove(mcastStoreKey));
- });
- ForwardingObjective fwdObj = mcastUtils.fwdObjBuilder(mcastIp, assignedVlan,
- newNextObj.id()).add(context);
- if (!srManager.deviceConfiguration().isConfigured(deviceId)) {
- log.debug("skip next and forward flowobjective addition for device: {}", deviceId);
- } else {
- srManager.flowObjectiveService.next(deviceId, newNextObj);
- srManager.flowObjectiveService.forward(deviceId, fwdObj);
- }
- } else {
- // This device already serves some subscribers of this mcast group
- NextObjective nextObj = mcastNextObjStore.get(mcastStoreKey).value();
- // Stop if the port is already in the nextobj
- Set<PortNumber> existingPorts = mcastUtils.getPorts(nextObj.next());
- if (existingPorts.contains(port)) {
- log.debug("Port {}/{} already exists for {}. Abort", deviceId, port, mcastIp);
- return;
- }
- // Let's add the port and reuse the previous one
- portBuilder.addAll(existingPorts).add(port);
- // Reuse previous nextObj
- newNextObj = mcastUtils.nextObjBuilder(mcastIp, assignedVlan,
- portBuilder.build(), nextObj.id()).addToExisting();
- // Store the final next objective and send only the difference to the driver
- mcastNextObjStore.put(mcastStoreKey, newNextObj);
- // Add just the new port
- portBuilder = ImmutableSet.builder();
- portBuilder.add(port);
- newNextObj = mcastUtils.nextObjBuilder(mcastIp, assignedVlan,
- portBuilder.build(), nextObj.id()).addToExisting();
- if (!srManager.deviceConfiguration().isConfigured(deviceId)) {
- log.debug("skip next flowobjective update for device: {}", deviceId);
- } else {
- // no need to update the flow here since we have updated the nextobjective/group
- // the existing flow will keep pointing to the updated nextobj
- srManager.flowObjectiveService.next(deviceId, newNextObj);
- }
- }
- }
-
- /**
- * Removes a port from given multicast group on given device.
- * This involves the update of L3 multicast group and multicast routing
- * table entry.
- *
- * @param deviceId device ID
- * @param port port to be added
- * @param mcastIp multicast group
- * @param assignedVlan assigned VLAN ID
- * @return true if this is the last sink on this device
- */
- private boolean removePortFromDevice(DeviceId deviceId, PortNumber port,
- IpAddress mcastIp, VlanId assignedVlan) {
- // TODO trace
- log.info("Removing {} on {}/{} and vlan {}", mcastIp, deviceId, port, assignedVlan);
- McastStoreKey mcastStoreKey =
- new McastStoreKey(mcastIp, deviceId, assignedVlan);
- // This device is not serving this multicast group
- if (!mcastNextObjStore.containsKey(mcastStoreKey)) {
- return true;
- }
- NextObjective nextObj = mcastNextObjStore.get(mcastStoreKey).value();
- Set<PortNumber> existingPorts = mcastUtils.getPorts(nextObj.next());
- // This port does not serve this multicast group
- if (!existingPorts.contains(port)) {
- if (!existingPorts.isEmpty()) {
- log.debug("{} is not serving {} on port {}. Abort.", deviceId, mcastIp, port);
- return false;
- }
- return true;
- }
- // Copy and modify the ImmutableSet
- existingPorts = Sets.newHashSet(existingPorts);
- existingPorts.remove(port);
- NextObjective newNextObj;
- ObjectiveContext context;
- ForwardingObjective fwdObj;
- if (existingPorts.isEmpty()) {
- context = new DefaultObjectiveContext(
- (objective) -> log.debug("Successfully remove {} on {}/{}, vlan {}",
- mcastIp, deviceId, port.toLong(), assignedVlan),
- (objective, error) -> log.warn("Failed to remove {} on {}/{}, vlan {}: {}",
- mcastIp, deviceId, port.toLong(), assignedVlan, error));
- fwdObj = mcastUtils.fwdObjBuilder(mcastIp, assignedVlan, nextObj.id()).remove(context);
- if (!srManager.deviceConfiguration().isConfigured(deviceId)) {
- log.debug("skip forward flowobjective removal for device: {}", deviceId);
- } else {
- srManager.flowObjectiveService.forward(deviceId, fwdObj);
- }
- mcastNextObjStore.remove(mcastStoreKey);
- } else {
- // Here we store the next objective with the remaining port
- newNextObj = mcastUtils.nextObjBuilder(mcastIp, assignedVlan,
- existingPorts, nextObj.id()).removeFromExisting();
- mcastNextObjStore.put(mcastStoreKey, newNextObj);
- // Let's modify the next objective removing the bucket
- newNextObj = mcastUtils.nextObjBuilder(mcastIp, assignedVlan,
- ImmutableSet.of(port), nextObj.id()).removeFromExisting();
- if (!srManager.deviceConfiguration().isConfigured(deviceId)) {
- log.debug("skip next flowobjective update for device: {}", deviceId);
- } else {
- // no need to update the flow here since we have updated the next objective + group
- // the existing flow will keep pointing to the updated nextobj
- srManager.flowObjectiveService.next(deviceId, newNextObj);
- }
- }
- return existingPorts.isEmpty();
- }
-
- /**
- * Removes entire group on given device.
- *
- * @param deviceId device ID
- * @param mcastIp multicast group to be removed
- * @param assignedVlan assigned VLAN ID
- */
- private void removeGroupFromDevice(DeviceId deviceId, IpAddress mcastIp,
- VlanId assignedVlan) {
- // TODO trace
- log.info("Removing {} on {} and vlan {}", mcastIp, deviceId, assignedVlan);
- McastStoreKey mcastStoreKey = new McastStoreKey(mcastIp, deviceId, assignedVlan);
- // This device is not serving this multicast group
- if (!mcastNextObjStore.containsKey(mcastStoreKey)) {
- log.debug("{} is not serving {}. Abort.", deviceId, mcastIp);
- return;
- }
- NextObjective nextObj = mcastNextObjStore.get(mcastStoreKey).value();
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> log.debug("Successfully remove {} on {}, vlan {}",
- mcastIp, deviceId, assignedVlan),
- (objective, error) -> log.warn("Failed to remove {} on {}, vlan {}: {}",
- mcastIp, deviceId, assignedVlan, error));
- if (!srManager.deviceConfiguration().isConfigured(deviceId)) {
- log.debug("skip flow changes on unconfigured device: {}", deviceId);
- } else {
- ForwardingObjective fwdObj = mcastUtils.fwdObjBuilder(mcastIp, assignedVlan, nextObj.id()).remove(context);
- srManager.flowObjectiveService.forward(deviceId, fwdObj);
- }
- mcastNextObjStore.remove(mcastStoreKey);
- }
-
- private void installPath(IpAddress mcastIp, ConnectPoint source, List<Link> links) {
- if (links.isEmpty()) {
- log.warn("There is no link that can be used. Stopping installation.");
- return;
- }
- // Setup new ingress mcast role
- mcastRoleStore.put(new McastRoleStoreKey(mcastIp, links.get(0).src().deviceId(), source),
- INGRESS);
- // For each link, modify the next on the source device adding the src port
- // and a new filter objective on the destination port
- links.forEach(link -> {
- addPortToDevice(link.src().deviceId(), link.src().port(), mcastIp,
- mcastUtils.assignedVlan(link.src().deviceId().equals(source.deviceId()) ? source : null));
- McastFilteringObjStoreKey mcastFilterObjStoreKey = new McastFilteringObjStoreKey(link.dst(),
- mcastUtils.assignedVlan(null), mcastIp.isIp4());
- addFilterToDevice(mcastFilterObjStoreKey, mcastIp, null);
- });
- // Setup mcast role for the transit
- links.stream()
- .filter(link -> !link.src().deviceId().equals(source.deviceId()))
- .forEach(link -> mcastRoleStore.put(new McastRoleStoreKey(mcastIp, link.src().deviceId(), source),
- TRANSIT));
- }
-
- /**
- * Gets a path from src to dst.
- * If a path was allocated before, returns the allocated path.
- * Otherwise, randomly pick one from available paths.
- *
- * @param src source device ID
- * @param dst destination device ID
- * @param mcastIp multicast group
- * @param allPaths paths list
- *
- * @return an optional path from src to dst
- */
- private Optional<Path> getPath(DeviceId src, DeviceId dst,
- IpAddress mcastIp, List<Path> allPaths) {
- if (allPaths == null) {
- allPaths = mcastUtils.getPaths(src, dst, Collections.emptySet());
- }
- if (allPaths.isEmpty()) {
- return Optional.empty();
- }
- // Create a map index of suitability-to-list of paths. For example
- // a path in the list associated to the index 1 shares only one link
- // and it is less suitable of a path belonging to the index 2
- Map<Integer, List<Path>> eligiblePaths = Maps.newHashMap();
- int score;
- // Let's build the multicast tree
- Set<List<Link>> storedPaths = getStoredPaths(mcastIp);
- Set<Link> storedTree = storedPaths.stream()
- .flatMap(Collection::stream).collect(Collectors.toSet());
- log.trace("Stored tree {}", storedTree);
- Set<Link> pathLinks;
- for (Path path : allPaths) {
- if (!src.equals(path.links().get(0).src().deviceId())) {
- continue;
- }
- pathLinks = Sets.newHashSet(path.links());
- score = Sets.intersection(pathLinks, storedTree).size();
- // score defines the index
- if (score > 0) {
- eligiblePaths.compute(score, (index, paths) -> {
- paths = paths == null ? Lists.newArrayList() : paths;
- paths.add(path);
- return paths;
- });
- }
- }
- if (eligiblePaths.isEmpty()) {
- log.trace("No eligiblePath(s) found from {} to {}", src, dst);
- Collections.shuffle(allPaths);
- return allPaths.stream().findFirst();
- }
- // Let's take the best ones
- Integer bestIndex = eligiblePaths.keySet().stream()
- .sorted(Comparator.reverseOrder()).findFirst().orElse(null);
- List<Path> bestPaths = eligiblePaths.get(bestIndex);
- log.trace("{} eligiblePath(s) found from {} to {}",
- bestPaths.size(), src, dst);
- Collections.shuffle(bestPaths);
- return bestPaths.stream().findFirst();
- }
-
- /**
- * Gets stored paths of the group.
- *
- * @param mcastIp group address
- * @return a collection of paths
- */
- private Set<List<Link>> getStoredPaths(IpAddress mcastIp) {
- return mcastPathStore.stream()
- .filter(entry -> entry.getKey().mcastIp().equals(mcastIp))
- .map(Entry::getValue)
- .collect(Collectors.toSet());
- }
-
- /**
- * Gets device(s) of given role and of given source in given multicast tree.
- *
- * @param mcastIp multicast IP
- * @param role multicast role
- * @param source source connect point
- * @return set of device ID or empty set if not found
- */
- private Set<DeviceId> getDevice(IpAddress mcastIp, McastRole role, ConnectPoint source) {
- return mcastRoleStore.entrySet().stream()
- .filter(entry -> entry.getKey().mcastIp().equals(mcastIp) &&
- entry.getKey().source().equals(source) &&
- entry.getValue().value() == role)
- .map(Entry::getKey).map(McastRoleStoreKey::deviceId).collect(Collectors.toSet());
- }
-
- /**
- * Gets device(s) of given role in given multicast group.
- *
- * @param mcastIp multicast IP
- * @param role multicast role
- * @return set of device ID or empty set if not found
- */
- private Set<DeviceId> getDevice(IpAddress mcastIp, McastRole role) {
- return mcastRoleStore.entrySet().stream()
- .filter(entry -> entry.getKey().mcastIp().equals(mcastIp) &&
- entry.getValue().value() == role)
- .map(Entry::getKey).map(McastRoleStoreKey::deviceId).collect(Collectors.toSet());
- }
-
- /**
- * Gets source(s) of given multicast group.
- *
- * @param mcastIp multicast IP
- * @return set of device ID or empty set if not found
- */
- private Set<ConnectPoint> getSources(IpAddress mcastIp) {
- return mcastRoleStore.entrySet().stream()
- .filter(entry -> entry.getKey().mcastIp().equals(mcastIp))
- .map(Entry::getKey).map(McastRoleStoreKey::source).collect(Collectors.toSet());
- }
-
- /**
- * Gets sink(s) of given multicast group.
- *
- * @param mcastIp multicast IP
- * @return set of connect point or empty set if not found
- */
- private Set<ConnectPoint> getSinks(IpAddress mcastIp, DeviceId device, ConnectPoint source) {
- McastPathStoreKey pathStoreKey = new McastPathStoreKey(mcastIp, source);
- Collection<? extends List<Link>> storedPaths = Versioned.valueOrElse(
- mcastPathStore.get(pathStoreKey), Lists.newArrayList());
- VlanId assignedVlan = mcastUtils.assignedVlan(device.equals(source.deviceId()) ? source : null);
- McastStoreKey mcastStoreKey = new McastStoreKey(mcastIp, device, assignedVlan);
- NextObjective nextObjective = Versioned.valueOrNull(mcastNextObjStore.get(mcastStoreKey));
- ImmutableSet.Builder<ConnectPoint> cpBuilder = ImmutableSet.builder();
- if (nextObjective != null) {
- Set<PortNumber> outputPorts = mcastUtils.getPorts(nextObjective.next());
- outputPorts.forEach(portNumber -> cpBuilder.add(new ConnectPoint(device, portNumber)));
- }
- Set<ConnectPoint> egressCp = cpBuilder.build();
- return egressCp.stream()
- .filter(connectPoint -> !mcastUtils.isInfraPort(connectPoint, storedPaths))
- .collect(Collectors.toSet());
- }
-
-
-
- /**
- * Gets groups which is affected by the link down event.
- *
- * @param link link going down
- * @return a set of multicast IpAddress
- */
- private Set<IpAddress> getAffectedGroups(Link link) {
- DeviceId deviceId = link.src().deviceId();
- PortNumber port = link.src().port();
- return mcastNextObjStore.entrySet().stream()
- .filter(entry -> entry.getKey().deviceId().equals(deviceId) &&
- mcastUtils.getPorts(entry.getValue().value().next()).contains(port))
- .map(Entry::getKey).map(McastStoreKey::mcastIp).collect(Collectors.toSet());
- }
-
- /**
- * Gets groups which are affected by the device down event.
- *
- * @param deviceId device going down
- * @return a set of multicast IpAddress
- */
- private Set<IpAddress> getAffectedGroups(DeviceId deviceId) {
- return mcastNextObjStore.entrySet().stream()
- .filter(entry -> entry.getKey().deviceId().equals(deviceId))
- .map(Entry::getKey).map(McastStoreKey::mcastIp)
- .collect(Collectors.toSet());
- }
-
- /**
- * Verify if a given connect point is sink for this group.
- *
- * @param mcastIp group address
- * @param connectPoint connect point to be verified
- * @param source source connect point
- * @return true if the connect point is sink of the group
- */
- private boolean isSinkForGroup(IpAddress mcastIp, ConnectPoint connectPoint,
- ConnectPoint source) {
- VlanId assignedVlan = mcastUtils.assignedVlan(connectPoint.deviceId().equals(source.deviceId()) ?
- source : null);
- McastStoreKey mcastStoreKey = new McastStoreKey(mcastIp, connectPoint.deviceId(), assignedVlan);
- if (!mcastNextObjStore.containsKey(mcastStoreKey)) {
- return false;
- }
- NextObjective mcastNext = mcastNextObjStore.get(mcastStoreKey).value();
- return mcastUtils.getPorts(mcastNext.next()).contains(connectPoint.port());
- }
-
- /**
- * Verify if a given connect point is sink for this group and for this source.
- *
- * @param mcastIp group address
- * @param connectPoint connect point to be verified
- * @param source source connect point
- * @return true if the connect point is sink of the group
- */
- private boolean isSinkForSource(IpAddress mcastIp, ConnectPoint connectPoint,
- ConnectPoint source) {
- boolean isSink = isSinkForGroup(mcastIp, connectPoint, source);
- DeviceId device;
- if (connectPoint.deviceId().equals(source.deviceId())) {
- device = getDevice(mcastIp, INGRESS, source).stream()
- .filter(deviceId -> deviceId.equals(connectPoint.deviceId()))
- .findFirst().orElse(null);
- } else {
- device = getDevice(mcastIp, EGRESS, source).stream()
- .filter(deviceId -> deviceId.equals(connectPoint.deviceId()))
- .findFirst().orElse(null);
- }
- return isSink && device != null;
- }
-
- /**
- * Verify if a sink is reachable from this source.
- *
- * @param mcastIp group address
- * @param sink connect point to be verified
- * @param source source connect point
- * @return true if the connect point is reachable from the source
- */
- private boolean isSinkReachable(IpAddress mcastIp, ConnectPoint sink,
- ConnectPoint source) {
- return sink.deviceId().equals(source.deviceId()) ||
- getPath(source.deviceId(), sink.deviceId(), mcastIp, null).isPresent();
- }
-
- /**
- * Updates filtering objective for given device and port.
- * It is called in general when the mcast config has been
- * changed.
- *
- * @param deviceId device ID
- * @param portNum ingress port number
- * @param vlanId assigned VLAN ID
- * @param install true to add, false to remove
- */
- public void updateFilterToDevice(DeviceId deviceId, PortNumber portNum,
- VlanId vlanId, boolean install) {
- mcastWorker.execute(() -> updateFilterToDeviceInternal(deviceId, portNum, vlanId, install));
- }
-
- private void updateFilterToDeviceInternal(DeviceId deviceId, PortNumber portNum,
- VlanId vlanId, boolean install) {
- lastMcastChange.set(Instant.now());
- // Iterates over the route and updates properly the filtering objective on the source device.
- srManager.multicastRouteService.getRoutes().forEach(mcastRoute -> {
- log.debug("Update filter for {}", mcastRoute.group());
- if (!mcastUtils.isLeader(mcastRoute.group())) {
- log.debug("Skip {} due to lack of leadership", mcastRoute.group());
- return;
- }
- // Get the sources and for each one update properly the filtering objectives
- Set<ConnectPoint> sources = srManager.multicastRouteService.sources(mcastRoute);
- sources.forEach(source -> {
- if (source.deviceId().equals(deviceId) && source.port().equals(portNum)) {
- if (install) {
- McastFilteringObjStoreKey mcastFilterObjStoreKey = new McastFilteringObjStoreKey(source,
- vlanId, mcastRoute.group().isIp4());
- addFilterToDevice(mcastFilterObjStoreKey, mcastRoute.group(), INGRESS);
- } else {
- mcastUtils.removeFilterToDevice(deviceId, portNum, vlanId, mcastRoute.group(), null);
- }
- }
- });
- });
- }
-
- /**
- * Add filtering to the device if needed.
- *
- * @param filterObjStoreKey the filtering obj key
- * @param mcastIp the multicast group
- * @param mcastRole the multicast role
- */
- private void addFilterToDevice(McastFilteringObjStoreKey filterObjStoreKey,
- IpAddress mcastIp,
- McastRole mcastRole) {
- if (!containsFilterInTheDevice(filterObjStoreKey)) {
- // if this is the first sink for this group/device
- // match additionally on mac
- log.debug("Filtering not available for device {}, vlan {} and {}",
- filterObjStoreKey.ingressCP().deviceId(), filterObjStoreKey.vlanId(),
- filterObjStoreKey.isIpv4() ? "IPv4" : "IPv6");
- mcastUtils.addFilterToDevice(filterObjStoreKey.ingressCP().deviceId(),
- filterObjStoreKey.ingressCP().port(),
- filterObjStoreKey.vlanId(), mcastIp,
- mcastRole, true);
- mcastFilteringObjStore.add(filterObjStoreKey);
- } else if (!mcastFilteringObjStore.contains(filterObjStoreKey)) {
- // match only vlan
- log.debug("Filtering not available for connect point {}, vlan {} and {}",
- filterObjStoreKey.ingressCP(), filterObjStoreKey.vlanId(),
- filterObjStoreKey.isIpv4() ? "IPv4" : "IPv6");
- mcastUtils.addFilterToDevice(filterObjStoreKey.ingressCP().deviceId(),
- filterObjStoreKey.ingressCP().port(),
- filterObjStoreKey.vlanId(), mcastIp,
- mcastRole, false);
- mcastFilteringObjStore.add(filterObjStoreKey);
- } else {
- // do nothing
- log.debug("Filtering already present for connect point {}, vlan {} and {}. Abort",
- filterObjStoreKey.ingressCP(), filterObjStoreKey.vlanId(),
- filterObjStoreKey.isIpv4() ? "IPv4" : "IPv6");
- }
- }
-
- /**
- * Verify if there are related filtering obj in the device.
- *
- * @param filteringKey the filtering obj key
- * @return true if related filtering obj are found
- */
- private boolean containsFilterInTheDevice(McastFilteringObjStoreKey filteringKey) {
- // check if filters are already added on the device
- McastFilteringObjStoreKey key = mcastFilteringObjStore.stream()
- .filter(mcastFilteringKey ->
- mcastFilteringKey.ingressCP().deviceId().equals(filteringKey.ingressCP().deviceId())
- && mcastFilteringKey.isIpv4() == filteringKey.isIpv4()
- && mcastFilteringKey.vlanId().equals(filteringKey.vlanId())
- ).findFirst().orElse(null);
- // we are interested to filt obj on the same device, same vlan and same ip type
- return key != null;
- }
-
- /**
- * Update the filtering objective store upon device failure.
- *
- * @param affectedDevice the affected device
- */
- private void updateFilterObjStoreByDevice(DeviceId affectedDevice) {
- // purge the related filter objective key
- Set<McastFilteringObjStoreKey> filterObjs = Sets.newHashSet(mcastFilteringObjStore);
- Iterator<McastFilteringObjStoreKey> filterIterator = filterObjs.iterator();
- McastFilteringObjStoreKey filterKey;
- while (filterIterator.hasNext()) {
- filterKey = filterIterator.next();
- if (filterKey.ingressCP().deviceId().equals(affectedDevice)) {
- mcastFilteringObjStore.remove(filterKey);
- }
- }
- }
-
- /**
- * Update the filtering objective store upon port failure.
- *
- * @param affectedPort the affected port
- */
- private void updateFilterObjStoreByPort(ConnectPoint affectedPort) {
- // purge the related filter objective key
- Set<McastFilteringObjStoreKey> filterObjs = Sets.newHashSet(mcastFilteringObjStore);
- Iterator<McastFilteringObjStoreKey> filterIterator = filterObjs.iterator();
- McastFilteringObjStoreKey filterKey;
- while (filterIterator.hasNext()) {
- filterKey = filterIterator.next();
- if (filterKey.ingressCP().equals(affectedPort)) {
- mcastFilteringObjStore.remove(filterKey);
- }
- }
- }
-
- /**
- * Performs bucket verification operation for all mcast groups in the devices.
- * Firstly, it verifies that mcast is stable before trying verification operation.
- * Verification consists in creating new nexts with VERIFY operation. Actually,
- * the operation is totally delegated to the driver.
- */
- private final class McastBucketCorrector implements Runnable {
- private final AtomicInteger verifyOnFlight = new AtomicInteger(0);
- // Define the context used for the back pressure mechanism
- private final ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> {
- synchronized (verifyOnFlight) {
- log.trace("Verify {} done", objective.id());
- verifyOnFlight.updateAndGet(i -> i > 0 ? i - 1 : i);
- verifyOnFlight.notify();
- }
- },
- (objective, error) -> {
- synchronized (verifyOnFlight) {
- log.trace("Verify {} error {}", objective.id(), error);
- verifyOnFlight.updateAndGet(i -> i > 0 ? i - 1 : i);
- verifyOnFlight.notify();
- }
- });
-
- @Override
- public void run() {
- try {
- // Iterates over the routes and verify the related next objectives
- for (McastRoute mcastRoute : srManager.multicastRouteService.getRoutes()) {
- if (!isMcastStable() || wasBktCorrRunning()) {
- return;
- }
- IpAddress mcastIp = mcastRoute.group();
- log.trace("Running mcast buckets corrector for mcast group: {}", mcastIp);
- // Verify leadership on the operation
- if (!mcastUtils.isLeader(mcastIp)) {
- log.trace("Skip {} due to lack of leadership", mcastIp);
- continue;
- }
- // Get sources and sinks from Mcast Route Service and warn about errors
- Set<ConnectPoint> sources = mcastUtils.getSources(mcastIp);
- Set<ConnectPoint> sinks = mcastUtils.getSinks(mcastIp).values().stream()
- .flatMap(Collection::stream).collect(Collectors.toSet());
- // Do not proceed if sources of this group are missing
- if (sources.isEmpty()) {
- if (!sinks.isEmpty()) {
- log.warn("Unable to run buckets corrector. " +
- "Missing source {} for group {}", sources, mcastIp);
- }
- continue;
- }
- // For each group we get current information in the store
- // and issue a check of the next objectives in place
- Set<McastStoreKey> processedKeys = Sets.newHashSet();
- for (ConnectPoint source : sources) {
- Set<DeviceId> ingressDevices = getDevice(mcastIp, INGRESS, source);
- Set<DeviceId> transitDevices = getDevice(mcastIp, TRANSIT, source);
- Set<DeviceId> egressDevices = getDevice(mcastIp, EGRESS, source);
- // Do not proceed if ingress devices are missing
- if (ingressDevices.isEmpty()) {
- if (!sinks.isEmpty()) {
- log.warn("Unable to run buckets corrector. " +
- "Missing ingress {} for source {} and for group {}",
- ingressDevices, source, mcastIp);
- }
- continue;
- }
- // Create the set of the devices to be processed
- ImmutableSet.Builder<DeviceId> devicesBuilder = ImmutableSet.builder();
- devicesBuilder.addAll(ingressDevices);
- if (!transitDevices.isEmpty()) {
- devicesBuilder.addAll(transitDevices);
- }
- if (!egressDevices.isEmpty()) {
- devicesBuilder.addAll(egressDevices);
- }
- Set<DeviceId> devicesToProcess = devicesBuilder.build();
- for (DeviceId deviceId : devicesToProcess) {
- if (!srManager.deviceConfiguration().isConfigured(deviceId)) {
- log.trace("Skipping Bucket corrector for unconfigured device {}", deviceId);
- continue;
- }
- synchronized (verifyOnFlight) {
- while (verifyOnFlight.get() == MAX_VERIFY_ON_FLIGHT) {
- verifyOnFlight.wait();
- }
- }
- VlanId assignedVlan = mcastUtils.assignedVlan(deviceId.equals(source.deviceId()) ?
- source : null);
- McastStoreKey currentKey = new McastStoreKey(mcastIp, deviceId, assignedVlan);
- // Check if we already processed this next - trees merge at some point
- if (processedKeys.contains(currentKey)) {
- continue;
- }
- // Verify the nextobjective or skip to next device
- if (mcastNextObjStore.containsKey(currentKey)) {
- NextObjective currentNext = mcastNextObjStore.get(currentKey).value();
- // Rebuild the next objective using assigned vlan
- currentNext = mcastUtils.nextObjBuilder(mcastIp, assignedVlan,
- mcastUtils.getPorts(currentNext.next()), currentNext.id()).verify(context);
- // Send to the flowobjective service
- srManager.flowObjectiveService.next(deviceId, currentNext);
- verifyOnFlight.incrementAndGet();
- log.trace("Verify on flight {}", verifyOnFlight);
- processedKeys.add(currentKey);
- } else {
- log.warn("Unable to run buckets corrector. " +
- "Missing next for {}, for source {} and for group {}",
- deviceId, source, mcastIp);
- }
- }
- }
- // Let's wait the group before start the next one
- synchronized (verifyOnFlight) {
- while (verifyOnFlight.get() > 0) {
- verifyOnFlight.wait();
- }
- }
- }
- } catch (InterruptedException e) {
- log.warn("BktCorr has been interrupted");
- } finally {
- lastBktCorrExecution.set(Instant.now());
- }
- }
- }
-
- /**
- * Returns the associated next ids to the mcast groups or to the single
- * group if mcastIp is present.
- *
- * @param mcastIp the group ip
- * @return the mapping mcastIp-device to next id
- */
- public Map<McastStoreKey, Integer> getNextIds(IpAddress mcastIp) {
- log.info("mcastNexts {}", mcastNextObjStore.size());
- if (mcastIp != null) {
- return mcastNextObjStore.entrySet().stream()
- .filter(mcastEntry -> mcastIp.equals(mcastEntry.getKey().mcastIp()))
- .collect(Collectors.toMap(Entry::getKey, entry -> entry.getValue().value().id()));
- }
- return mcastNextObjStore.entrySet().stream()
- .collect(Collectors.toMap(Entry::getKey, entry -> entry.getValue().value().id()));
- }
-
- /**
- * Removes given next ID from mcast next id store.
- *
- * @param nextId next id
- */
- public void removeNextId(int nextId) {
- mcastNextObjStore.entrySet().forEach(e -> {
- if (e.getValue().value().id() == nextId) {
- mcastNextObjStore.remove(e.getKey());
- }
- });
- }
-
- /**
- * Build the mcast paths.
- *
- * @param storedPaths mcast tree
- * @param mcastIp the group ip
- * @param source the source
- */
- private Map<ConnectPoint, List<ConnectPoint>> buildMcastPaths(Collection<? extends List<Link>> storedPaths,
- IpAddress mcastIp, ConnectPoint source) {
- Map<ConnectPoint, List<ConnectPoint>> mcastTree = Maps.newHashMap();
- // Local sinks
- Set<ConnectPoint> localSinks = getSinks(mcastIp, source.deviceId(), source);
- localSinks.forEach(localSink -> mcastTree.put(localSink, Lists.newArrayList(localSink, source)));
- // Remote sinks
- storedPaths.forEach(path -> {
- List<Link> links = path;
- DeviceId egressDevice = links.get(links.size() - 1).dst().deviceId();
- Set<ConnectPoint> remoteSinks = getSinks(mcastIp, egressDevice, source);
- List<ConnectPoint> connectPoints = Lists.newArrayList(source);
- links.forEach(link -> {
- connectPoints.add(link.src());
- connectPoints.add(link.dst());
- });
- Collections.reverse(connectPoints);
- remoteSinks.forEach(remoteSink -> {
- List<ConnectPoint> finalPath = Lists.newArrayList(connectPoints);
- finalPath.add(0, remoteSink);
- mcastTree.put(remoteSink, finalPath);
- });
- });
- return mcastTree;
- }
-
- /**
- * Returns the associated roles to the mcast groups.
- *
- * @param mcastIp the group ip
- * @param sourcecp the source connect point
- * @return the mapping mcastIp-device to mcast role
- */
- public Map<McastRoleStoreKey, McastRole> getMcastRoles(IpAddress mcastIp,
- ConnectPoint sourcecp) {
- log.info("mcastRoles {}", mcastRoleStore.size());
- if (mcastIp != null) {
- Map<McastRoleStoreKey, McastRole> roles = mcastRoleStore.entrySet().stream()
- .filter(mcastEntry -> mcastIp.equals(mcastEntry.getKey().mcastIp()))
- .collect(Collectors.toMap(entry -> new McastRoleStoreKey(entry.getKey().mcastIp(),
- entry.getKey().deviceId(), entry.getKey().source()), entry -> entry.getValue().value()));
- if (sourcecp != null) {
- roles = roles.entrySet().stream()
- .filter(mcastEntry -> sourcecp.equals(mcastEntry.getKey().source()))
- .collect(Collectors.toMap(entry -> new McastRoleStoreKey(entry.getKey().mcastIp(),
- entry.getKey().deviceId(), entry.getKey().source()), Entry::getValue));
- }
- return roles;
- }
- return mcastRoleStore.entrySet().stream()
- .collect(Collectors.toMap(entry -> new McastRoleStoreKey(entry.getKey().mcastIp(),
- entry.getKey().deviceId(), entry.getKey().source()), entry -> entry.getValue().value()));
- }
-
- /**
- * Returns the associated trees to the mcast group.
- *
- * @param mcastIp the group ip
- * @param sourcecp the source connect point
- * @return the mapping egress point to mcast path
- */
- public Multimap<ConnectPoint, List<ConnectPoint>> getMcastTrees(IpAddress mcastIp,
- ConnectPoint sourcecp) {
- // TODO remove
- log.info("{}", getStoredPaths(mcastIp));
- Multimap<ConnectPoint, List<ConnectPoint>> mcastTrees = HashMultimap.create();
- Set<ConnectPoint> sources = mcastUtils.getSources(mcastIp);
- if (sourcecp != null) {
- sources = sources.stream()
- .filter(source -> source.equals(sourcecp)).collect(Collectors.toSet());
- }
- if (!sources.isEmpty()) {
- sources.forEach(source -> {
- McastPathStoreKey pathStoreKey = new McastPathStoreKey(mcastIp, source);
- Collection<? extends List<Link>> storedPaths = Versioned.valueOrElse(
- mcastPathStore.get(pathStoreKey), Lists.newArrayList());
- // TODO remove
- log.info("Paths for group {} and source {} - {}", mcastIp, source, storedPaths.size());
- Map<ConnectPoint, List<ConnectPoint>> mcastTree = buildMcastPaths(storedPaths, mcastIp, source);
- mcastTree.forEach(mcastTrees::put);
- });
- }
- return mcastTrees;
- }
-
- /**
- * Return the leaders of the mcast groups.
- *
- * @param mcastIp the group ip
- * @return the mapping group-node
- */
- public Map<IpAddress, NodeId> getMcastLeaders(IpAddress mcastIp) {
- return mcastUtils.getMcastLeaders(mcastIp);
- }
-
- /**
- * Returns the mcast filtering obj.
- *
- * @return the mapping group-node
- */
- public Map<DeviceId, List<McastFilteringObjStoreKey>> getMcastFilters() {
- // TODO remove
- log.info("mcastFilters {}", mcastFilteringObjStore.size());
- Map<DeviceId, List<McastFilteringObjStoreKey>> mapping = Maps.newHashMap();
- Set<McastFilteringObjStoreKey> currentKeys = Sets.newHashSet(mcastFilteringObjStore);
- currentKeys.forEach(filteringObjStoreKey ->
- mapping.compute(filteringObjStoreKey.ingressCP().deviceId(), (k, v) -> {
- List<McastFilteringObjStoreKey> values = v;
- if (values == null) {
- values = Lists.newArrayList();
- }
- values.add(filteringObjStoreKey);
- return values;
- })
- );
- return mapping;
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/mcast/McastPathStoreKey.java b/app/src/main/java/org/onosproject/segmentrouting/mcast/McastPathStoreKey.java
deleted file mode 100644
index 76f46fe..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/mcast/McastPathStoreKey.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright 2020-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.mcast;
-
-import org.onlab.packet.IpAddress;
-import org.onosproject.net.ConnectPoint;
-
-import java.util.Objects;
-
-import static com.google.common.base.MoreObjects.toStringHelper;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-/**
- * Key of multicast path store.
- */
-public class McastPathStoreKey {
- // Identify path using group address and source
- private final IpAddress mcastIp;
- private final ConnectPoint source;
-
- /**
- * Constructs the key of multicast path store.
- *
- * @param mcastIp multicast group IP address
- * @param source source connect point
- */
- public McastPathStoreKey(IpAddress mcastIp, ConnectPoint source) {
- checkNotNull(mcastIp, "mcastIp cannot be null");
- checkNotNull(source, "source cannot be null");
- checkArgument(mcastIp.isMulticast(), "mcastIp must be a multicast address");
- this.mcastIp = mcastIp;
- this.source = source;
- }
-
- // Constructor for serialization
- private McastPathStoreKey() {
- this.mcastIp = null;
- this.source = null;
- }
-
- /**
- * Returns the multicast IP address of this key.
- *
- * @return multicast IP
- */
- public IpAddress mcastIp() {
- return mcastIp;
- }
-
- /**
- * Returns the device ID of this key.
- *
- * @return device ID
- */
- public ConnectPoint source() {
- return source;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (!(o instanceof McastPathStoreKey)) {
- return false;
- }
- McastPathStoreKey that =
- (McastPathStoreKey) o;
- return (Objects.equals(this.mcastIp, that.mcastIp) &&
- Objects.equals(this.source, that.source));
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mcastIp, source);
- }
-
- @Override
- public String toString() {
- return toStringHelper(getClass())
- .add("mcastIp", mcastIp)
- .add("source", source)
- .toString();
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/mcast/McastPathStoreKeySerializer.java b/app/src/main/java/org/onosproject/segmentrouting/mcast/McastPathStoreKeySerializer.java
deleted file mode 100644
index 4ef0194..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/mcast/McastPathStoreKeySerializer.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2020-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.mcast;
-
-
-import com.esotericsoftware.kryo.Kryo;
-import com.esotericsoftware.kryo.Serializer;
-import com.esotericsoftware.kryo.io.Input;
-import com.esotericsoftware.kryo.io.Output;
-import org.onlab.packet.IpAddress;
-import org.onosproject.net.ConnectPoint;
-
-/**
- * Custom serializer for {@link McastPathStoreKey}.
- */
-class McastPathStoreKeySerializer extends Serializer<McastPathStoreKey> {
-
- /**
- * Creates {@link McastPathStoreKeySerializer} serializer instance.
- */
- McastPathStoreKeySerializer() {
- // non-null, immutable
- super(false, true);
- }
-
- @Override
- public void write(Kryo kryo, Output output, McastPathStoreKey object) {
- kryo.writeClassAndObject(output, object.mcastIp());
- kryo.writeClassAndObject(output, object.source());
- }
-
- @Override
- public McastPathStoreKey read(Kryo kryo, Input input, Class<McastPathStoreKey> type) {
- IpAddress mcastIp = (IpAddress) kryo.readClassAndObject(input);
- ConnectPoint source = (ConnectPoint) kryo.readClassAndObject(input);
- return new McastPathStoreKey(mcastIp, source);
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/mcast/McastRole.java b/app/src/main/java/org/onosproject/segmentrouting/mcast/McastRole.java
deleted file mode 100644
index 454bb5c..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/mcast/McastRole.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2018-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.mcast;
-
-/**
- * Enum that defines role in the multicast tree.
- */
-public enum McastRole {
- /**
- * The device is the ingress device of this group.
- */
- INGRESS,
- /**
- * The device is the transit device of this group.
- */
- TRANSIT,
- /**
- * The device is the egress device of this group.
- */
- EGRESS
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/mcast/McastRoleStoreKey.java b/app/src/main/java/org/onosproject/segmentrouting/mcast/McastRoleStoreKey.java
deleted file mode 100644
index 26f21f2..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/mcast/McastRoleStoreKey.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright 2018-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.mcast;
-
-import org.onlab.packet.IpAddress;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
-
-import java.util.Objects;
-
-import static com.google.common.base.MoreObjects.toStringHelper;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-/**
- * Key of multicast role store.
- */
-public class McastRoleStoreKey {
- // Identify role using group address, deviceId and source
- private final IpAddress mcastIp;
- private final DeviceId deviceId;
- private final ConnectPoint source;
-
- /**
- * Constructs the key of multicast role store.
- *
- * @param mcastIp multicast group IP address
- * @param deviceId device ID
- * @param source source connect point
- */
- public McastRoleStoreKey(IpAddress mcastIp, DeviceId deviceId, ConnectPoint source) {
- checkNotNull(mcastIp, "mcastIp cannot be null");
- checkNotNull(deviceId, "deviceId cannot be null");
- checkNotNull(source, "source cannot be null");
- checkArgument(mcastIp.isMulticast(), "mcastIp must be a multicast address");
- this.mcastIp = mcastIp;
- this.deviceId = deviceId;
- this.source = source;
- }
-
- // Constructor for serialization
- private McastRoleStoreKey() {
- this.mcastIp = null;
- this.deviceId = null;
- this.source = null;
- }
-
- /**
- * Returns the multicast IP address of this key.
- *
- * @return multicast IP
- */
- public IpAddress mcastIp() {
- return mcastIp;
- }
-
- /**
- * Returns the device ID of this key.
- *
- * @return device ID
- */
- public DeviceId deviceId() {
- return deviceId;
- }
-
- /**
- * Returns the source connect point of this key.
- *
- * @return the source connect point
- */
- public ConnectPoint source() {
- return source;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (!(o instanceof McastRoleStoreKey)) {
- return false;
- }
- final McastRoleStoreKey that = (McastRoleStoreKey) o;
-
- return Objects.equals(this.mcastIp, that.mcastIp) &&
- Objects.equals(this.deviceId, that.deviceId) &&
- Objects.equals(this.source, that.source);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mcastIp, deviceId, source);
- }
-
- @Override
- public String toString() {
- return toStringHelper(getClass())
- .add("mcastIp", mcastIp)
- .add("deviceId", deviceId)
- .add("source", source)
- .toString();
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/mcast/McastRoleStoreKeySerializer.java b/app/src/main/java/org/onosproject/segmentrouting/mcast/McastRoleStoreKeySerializer.java
deleted file mode 100644
index aec7278..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/mcast/McastRoleStoreKeySerializer.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2018-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.mcast;
-
-
-import com.esotericsoftware.kryo.Kryo;
-import com.esotericsoftware.kryo.Serializer;
-import com.esotericsoftware.kryo.io.Input;
-import com.esotericsoftware.kryo.io.Output;
-import org.onlab.packet.IpAddress;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
-
-/**
- * Custom serializer for {@link McastRoleStoreKey}.
- */
-class McastRoleStoreKeySerializer extends Serializer<McastRoleStoreKey> {
-
- /**
- * Creates {@link McastRoleStoreKeySerializer} serializer instance.
- */
- McastRoleStoreKeySerializer() {
- // non-null, immutable
- super(false, true);
- }
-
- @Override
- public void write(Kryo kryo, Output output, McastRoleStoreKey object) {
- kryo.writeClassAndObject(output, object.mcastIp());
- output.writeString(object.deviceId().toString());
- kryo.writeClassAndObject(output, object.source());
- }
-
- @Override
- public McastRoleStoreKey read(Kryo kryo, Input input, Class<McastRoleStoreKey> type) {
- IpAddress mcastIp = (IpAddress) kryo.readClassAndObject(input);
- final String str = input.readString();
- DeviceId deviceId = DeviceId.deviceId(str);
- ConnectPoint source = (ConnectPoint) kryo.readClassAndObject(input);
- return new McastRoleStoreKey(mcastIp, deviceId, source);
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/mcast/McastStoreKey.java b/app/src/main/java/org/onosproject/segmentrouting/mcast/McastStoreKey.java
deleted file mode 100644
index aa32797..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/mcast/McastStoreKey.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright 2018-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.mcast;
-
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.VlanId;
-import org.onosproject.net.DeviceId;
-import static com.google.common.base.MoreObjects.toStringHelper;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import java.util.Objects;
-
-/**
- * Key of multicast next objective store.
- */
-public class McastStoreKey {
- // Identify a flow using group address, deviceId, and assigned vlan
- private final IpAddress mcastIp;
- private final DeviceId deviceId;
- private final VlanId vlanId;
-
- /**
- * Constructs the key of multicast next objective store.
- *
- * @param mcastIp multicast group IP address
- * @param deviceId device ID
- *
- * @deprecated in 1.12 ("Magpie") release.
- */
- @Deprecated
- public McastStoreKey(IpAddress mcastIp, DeviceId deviceId) {
- checkNotNull(mcastIp, "mcastIp cannot be null");
- checkNotNull(deviceId, "deviceId cannot be null");
- checkArgument(mcastIp.isMulticast(), "mcastIp must be a multicast address");
- this.mcastIp = mcastIp;
- this.deviceId = deviceId;
- this.vlanId = null;
- }
-
- /**
- * Constructs the key of multicast next objective store.
- *
- * @param mcastIp multicast group IP address
- * @param deviceId device ID
- * @param vlanId vlan id
- */
- public McastStoreKey(IpAddress mcastIp, DeviceId deviceId, VlanId vlanId) {
- checkNotNull(mcastIp, "mcastIp cannot be null");
- checkNotNull(deviceId, "deviceId cannot be null");
- checkNotNull(vlanId, "vlan id cannot be null");
- checkArgument(mcastIp.isMulticast(), "mcastIp must be a multicast address");
- this.mcastIp = mcastIp;
- this.deviceId = deviceId;
- // FIXME probably we should avoid not valid values
- this.vlanId = vlanId;
- }
-
- // Constructor for serialization
- private McastStoreKey() {
- this.mcastIp = null;
- this.deviceId = null;
- this.vlanId = null;
- }
-
- /**
- * Returns the multicast IP address of this key.
- *
- * @return multicast IP
- */
- public IpAddress mcastIp() {
- return mcastIp;
- }
-
- /**
- * Returns the device ID of this key.
- *
- * @return device ID
- */
- public DeviceId deviceId() {
- return deviceId;
- }
-
- /**
- * Returns the vlan ID of this key.
- *
- * @return vlan ID
- */
- public VlanId vlanId() {
- return vlanId;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (!(o instanceof McastStoreKey)) {
- return false;
- }
- McastStoreKey that =
- (McastStoreKey) o;
- return (Objects.equals(this.mcastIp, that.mcastIp) &&
- Objects.equals(this.deviceId, that.deviceId) &&
- Objects.equals(this.vlanId, that.vlanId));
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mcastIp, deviceId, vlanId);
- }
-
- @Override
- public String toString() {
- return toStringHelper(getClass())
- .add("mcastIp", mcastIp)
- .add("deviceId", deviceId)
- .add("vlanId", vlanId)
- .toString();
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/mcast/McastStoreKeySerializer.java b/app/src/main/java/org/onosproject/segmentrouting/mcast/McastStoreKeySerializer.java
deleted file mode 100644
index c32b0ba..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/mcast/McastStoreKeySerializer.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2018-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.mcast;
-
-
-import com.esotericsoftware.kryo.Kryo;
-import com.esotericsoftware.kryo.Serializer;
-import com.esotericsoftware.kryo.io.Input;
-import com.esotericsoftware.kryo.io.Output;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.VlanId;
-import org.onosproject.net.DeviceId;
-
-/**
- * Custom serializer for {@link McastStoreKey}.
- */
-class McastStoreKeySerializer extends Serializer<McastStoreKey> {
-
- /**
- * Creates {@link McastStoreKeySerializer} serializer instance.
- */
- McastStoreKeySerializer() {
- // non-null, immutable
- super(false, true);
- }
-
- @Override
- public void write(Kryo kryo, Output output, McastStoreKey object) {
- kryo.writeClassAndObject(output, object.mcastIp());
- output.writeString(object.deviceId().toString());
- kryo.writeClassAndObject(output, object.vlanId());
- }
-
- @Override
- public McastStoreKey read(Kryo kryo, Input input, Class<McastStoreKey> type) {
- IpAddress mcastIp = (IpAddress) kryo.readClassAndObject(input);
- final String str = input.readString();
- DeviceId deviceId = DeviceId.deviceId(str);
- VlanId vlanId = (VlanId) kryo.readClassAndObject(input);
- return new McastStoreKey(mcastIp, deviceId, vlanId);
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/mcast/McastUtils.java b/app/src/main/java/org/onosproject/segmentrouting/mcast/McastUtils.java
deleted file mode 100644
index 396b998..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/mcast/McastUtils.java
+++ /dev/null
@@ -1,715 +0,0 @@
-/*
- * Copyright 2018-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.mcast;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import com.google.common.hash.HashFunction;
-import com.google.common.hash.Hashing;
-import org.onlab.packet.Ethernet;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
-import org.onosproject.cluster.NodeId;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.mcast.api.McastRoute;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.HostId;
-import org.onosproject.net.Link;
-import org.onosproject.net.Path;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.config.basics.McastConfig;
-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.criteria.Criteria;
-import org.onosproject.net.flow.instructions.Instructions;
-import org.onosproject.net.flowobjective.DefaultFilteringObjective;
-import org.onosproject.net.flowobjective.DefaultForwardingObjective;
-import org.onosproject.net.flowobjective.DefaultNextObjective;
-import org.onosproject.net.flowobjective.DefaultObjectiveContext;
-import org.onosproject.net.flowobjective.FilteringObjective;
-import org.onosproject.net.flowobjective.ForwardingObjective;
-import org.onosproject.net.flowobjective.NextObjective;
-import org.onosproject.net.flowobjective.ObjectiveContext;
-import org.onosproject.net.topology.LinkWeigher;
-import org.onosproject.net.topology.Topology;
-import org.onosproject.net.topology.TopologyService;
-import org.onosproject.segmentrouting.SRLinkWeigher;
-import org.onosproject.segmentrouting.SegmentRoutingManager;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
-import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
-import org.slf4j.Logger;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/**
- * Utility class for Multicast Handler.
- */
-class McastUtils {
- // Internal reference to the log
- private final Logger log;
- // Internal reference to SR Manager and topology service
- private final SegmentRoutingManager srManager;
- private final TopologyService topologyService;
- // Internal reference to the app id
- private ApplicationId coreAppId;
- // Hashing function for the multicast hasher
- private static final HashFunction HASH_FN = Hashing.md5();
- // Read only cache of the Mcast leader
- private Map<IpAddress, NodeId> mcastLeaderCache;
-
- /**
- * Builds a new McastUtils object.
- *
- * @param srManager the SR manager
- * @param coreAppId the core application id
- * @param log log reference of the McastHandler
- */
- McastUtils(SegmentRoutingManager srManager, ApplicationId coreAppId, Logger log) {
- this.srManager = srManager;
- this.topologyService = srManager.topologyService;
- this.coreAppId = coreAppId;
- this.log = log;
- this.mcastLeaderCache = Maps.newConcurrentMap();
- }
-
- /**
- * Clean up when deactivating the application.
- */
- void terminate() {
- mcastLeaderCache.clear();
- }
-
- /**
- * Get router mac using application config and the connect point.
- *
- * @param deviceId the device id
- * @param port the port number
- * @return the router mac if the port is configured, otherwise null
- */
- private MacAddress getRouterMac(DeviceId deviceId, PortNumber port) {
- // Do nothing if the port is configured as suppressed
- ConnectPoint connectPoint = new ConnectPoint(deviceId, port);
- SegmentRoutingAppConfig appConfig = srManager.cfgService
- .getConfig(srManager.appId(), SegmentRoutingAppConfig.class);
- if (appConfig != null && appConfig.suppressSubnet().contains(connectPoint)) {
- log.info("Ignore suppressed port {}", connectPoint);
- return MacAddress.NONE;
- }
- // Get the router mac using the device configuration
- MacAddress routerMac;
- try {
- routerMac = srManager.deviceConfiguration().getDeviceMac(deviceId);
- } catch (DeviceConfigNotFoundException dcnfe) {
- log.warn("Failed to get device MAC since the device {} is not configured", deviceId);
- return null;
- }
- return routerMac;
- }
-
- /**
- * Adds filtering objective for given device and port.
- *
- * @param deviceId device ID
- * @param port ingress port number
- * @param assignedVlan assigned VLAN ID
- * @param mcastIp the group address
- * @param mcastRole the role of the device
- * @param matchOnMac match or not on macaddress
- */
- void addFilterToDevice(DeviceId deviceId, PortNumber port, VlanId assignedVlan,
- IpAddress mcastIp, McastRole mcastRole, boolean matchOnMac) {
- if (!srManager.deviceConfiguration().isConfigured(deviceId)) {
- log.debug("skip update of fitering objective for unconfigured device: {}", deviceId);
- return;
- }
- MacAddress routerMac = getRouterMac(deviceId, port);
-
- if (MacAddress.NONE.equals(routerMac)) {
- return;
- }
- FilteringObjective.Builder filtObjBuilder = filterObjBuilder(port, assignedVlan, mcastIp,
- routerMac, mcastRole, matchOnMac);
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> log.debug("Successfully add filter on {}/{}, vlan {}",
- deviceId, port.toLong(), assignedVlan),
- (objective, error) ->
- log.warn("Failed to add filter on {}/{}, vlan {}: {}",
- deviceId, port.toLong(), assignedVlan, error));
- srManager.flowObjectiveService.filter(deviceId, filtObjBuilder.add(context));
- }
-
- /**
- * Removes filtering objective for given device and port.
- *
- * @param deviceId device ID
- * @param port ingress port number
- * @param assignedVlan assigned VLAN ID
- * @param mcastIp multicast IP address
- * @param mcastRole the multicast role of the device
- */
- void removeFilterToDevice(DeviceId deviceId, PortNumber port, VlanId assignedVlan,
- IpAddress mcastIp, McastRole mcastRole) {
- if (!srManager.deviceConfiguration().isConfigured(deviceId)) {
- log.debug("skip update of fitering objective for unconfigured device: {}", deviceId);
- return;
- }
- MacAddress routerMac = getRouterMac(deviceId, port);
-
- if (MacAddress.NONE.equals(routerMac)) {
- return;
- }
- FilteringObjective.Builder filtObjBuilder =
- filterObjBuilder(port, assignedVlan, mcastIp, routerMac, mcastRole, false);
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> log.debug("Successfully removed filter on {}/{}, vlan {}",
- deviceId, port.toLong(), assignedVlan),
- (objective, error) ->
- log.warn("Failed to remove filter on {}/{}, vlan {}: {}",
- deviceId, port.toLong(), assignedVlan, error));
- srManager.flowObjectiveService.filter(deviceId, filtObjBuilder.remove(context));
- }
-
- /**
- * Gets ingress VLAN from McastConfig.
- *
- * @return ingress VLAN or VlanId.NONE if not configured
- */
- private VlanId ingressVlan() {
- McastConfig mcastConfig =
- srManager.cfgService.getConfig(coreAppId, McastConfig.class);
- return (mcastConfig != null) ? mcastConfig.ingressVlan() : VlanId.NONE;
- }
-
- /**
- * Gets egress VLAN from McastConfig.
- *
- * @return egress VLAN or VlanId.NONE if not configured
- */
- private VlanId egressVlan() {
- McastConfig mcastConfig =
- srManager.cfgService.getConfig(coreAppId, McastConfig.class);
- return (mcastConfig != null) ? mcastConfig.egressVlan() : VlanId.NONE;
- }
-
- /**
- * Gets assigned VLAN according to the value of egress VLAN.
- * If connect point is specified, try to reuse the assigned VLAN on the connect point.
- *
- * @param cp connect point; Can be null if not specified
- * @return assigned VLAN ID
- */
- VlanId assignedVlan(ConnectPoint cp) {
- // Use the egressVlan if it is tagged
- if (!egressVlan().equals(VlanId.NONE)) {
- return egressVlan();
- }
- // Reuse unicast VLAN if the port has subnet configured
- if (cp != null) {
- VlanId untaggedVlan = srManager.getInternalVlanId(cp);
- return (untaggedVlan != null) ? untaggedVlan
- : srManager.getDefaultInternalVlan();
- }
- // Use DEFAULT_VLAN if none of the above matches
- return srManager.getDefaultInternalVlan();
- }
-
-
-
- /**
- * Gets sources connect points of given multicast group.
- *
- * @param mcastIp multicast IP
- * @return sources connect points or empty set if not found
- */
- Set<ConnectPoint> getSources(IpAddress mcastIp) {
- // TODO we should support different types of routes
- McastRoute mcastRoute = srManager.multicastRouteService.getRoutes().stream()
- .filter(mcastRouteInternal -> mcastRouteInternal.group().equals(mcastIp))
- .findFirst().orElse(null);
- return mcastRoute == null ? ImmutableSet.of() :
- srManager.multicastRouteService.sources(mcastRoute);
- }
-
- /**
- * Gets sinks of given multicast group.
- *
- * @param mcastIp multicast IP
- * @return map of sinks or empty map if not found
- */
- Map<HostId, Set<ConnectPoint>> getSinks(IpAddress mcastIp) {
- // TODO we should support different types of routes
- McastRoute mcastRoute = srManager.multicastRouteService.getRoutes().stream()
- .filter(mcastRouteInternal -> mcastRouteInternal.group().equals(mcastIp))
- .findFirst().orElse(null);
- return mcastRoute == null ?
- ImmutableMap.of() :
- srManager.multicastRouteService.routeData(mcastRoute).sinks();
- }
-
- /**
- * Get sinks affected by this egress device.
- *
- * @param egressDevice the egress device
- * @param mcastIp the mcast ip address
- * @return the map of the sinks affected
- */
- Map<HostId, Set<ConnectPoint>> getAffectedSinks(DeviceId egressDevice,
- IpAddress mcastIp) {
- return getSinks(mcastIp).entrySet()
- .stream()
- .filter(hostIdSetEntry -> hostIdSetEntry.getValue().stream()
- .map(ConnectPoint::deviceId)
- .anyMatch(deviceId -> deviceId.equals(egressDevice))
- ).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
- }
-
- /**
- * Creates a next objective builder for multicast.
- *
- * @param mcastIp multicast group
- * @param assignedVlan assigned VLAN ID
- * @param outPorts set of output port numbers
- * @param nextId the next id
- * @return next objective builder
- */
- NextObjective.Builder nextObjBuilder(IpAddress mcastIp, VlanId assignedVlan,
- Set<PortNumber> outPorts, Integer nextId) {
- // If nextId is null allocate a new one
- if (nextId == null) {
- nextId = srManager.flowObjectiveService.allocateNextId();
- }
- // Build the meta selector with the fwd objective info
- TrafficSelector metadata =
- DefaultTrafficSelector.builder()
- .matchVlanId(assignedVlan)
- .matchIPDst(mcastIp.toIpPrefix())
- .build();
- // Define the nextobjective type
- NextObjective.Builder nextObjBuilder = DefaultNextObjective
- .builder().withId(nextId)
- .withType(NextObjective.Type.BROADCAST)
- .fromApp(srManager.appId())
- .withMeta(metadata);
- // Add the output ports
- outPorts.forEach(port -> {
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
- if (egressVlan().equals(VlanId.NONE)) {
- tBuilder.popVlan();
- }
- tBuilder.setOutput(port);
- nextObjBuilder.addTreatment(tBuilder.build());
- });
- // Done return the complete builder
- return nextObjBuilder;
- }
-
- /**
- * Creates a forwarding objective builder for multicast.
- *
- * @param mcastIp multicast group
- * @param assignedVlan assigned VLAN ID
- * @param nextId next ID of the L3 multicast group
- * @return forwarding objective builder
- */
- ForwardingObjective.Builder fwdObjBuilder(IpAddress mcastIp,
- VlanId assignedVlan, int nextId) {
- TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
- // Let's the matching on the group address
- // TODO SSM support in future
- if (mcastIp.isIp6()) {
- sbuilder.matchEthType(Ethernet.TYPE_IPV6);
- sbuilder.matchIPv6Dst(mcastIp.toIpPrefix());
- } else {
- sbuilder.matchEthType(Ethernet.TYPE_IPV4);
- sbuilder.matchIPDst(mcastIp.toIpPrefix());
- }
- // Then build the meta selector
- TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
- metabuilder.matchVlanId(assignedVlan);
- // Finally return the completed builder
- ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective.builder();
- fwdBuilder.withSelector(sbuilder.build())
- .withMeta(metabuilder.build())
- .nextStep(nextId)
- .withFlag(ForwardingObjective.Flag.SPECIFIC)
- .fromApp(srManager.appId())
- .withPriority(SegmentRoutingService.DEFAULT_PRIORITY);
- return fwdBuilder;
- }
-
- /**
- * Creates a filtering objective builder for multicast.
- *
- * @param ingressPort ingress port of the multicast stream
- * @param assignedVlan assigned VLAN ID
- * @param mcastIp the group address
- * @param routerMac router MAC. This is carried in metadata and used from some switches that
- * need to put unicast entry before multicast entry in TMAC table.
- * @param mcastRole the Multicast role
- * @param matchOnMac match or not on macaddress
- * @return filtering objective builder
- */
- private FilteringObjective.Builder filterObjBuilder(PortNumber ingressPort, VlanId assignedVlan,
- IpAddress mcastIp, MacAddress routerMac, McastRole mcastRole,
- boolean matchOnMac) {
- FilteringObjective.Builder filtBuilder = DefaultFilteringObjective.builder();
- // Let's add the in port matching and the priority
- filtBuilder.withKey(Criteria.matchInPort(ingressPort))
- .withPriority(SegmentRoutingService.DEFAULT_PRIORITY);
- // According to the mcast role we match on the proper vlan
- // If the role is null we are on the transit or on the egress
- if (mcastRole == null) {
- filtBuilder.addCondition(Criteria.matchVlanId(egressVlan()));
- } else {
- filtBuilder.addCondition(Criteria.matchVlanId(ingressVlan()));
- }
- // Add vlan info to the treatment builder
- TrafficTreatment.Builder ttb = DefaultTrafficTreatment.builder()
- .pushVlan().setVlanId(assignedVlan);
- // Additionally match on mac address and augment the treatment
- if (matchOnMac) {
- // According to the IP type we set the proper match on the mac address
- if (mcastIp.isIp4()) {
- filtBuilder.addCondition(Criteria.matchEthDstMasked(MacAddress.IPV4_MULTICAST,
- MacAddress.IPV4_MULTICAST_MASK));
- } else {
- filtBuilder.addCondition(Criteria.matchEthDstMasked(MacAddress.IPV6_MULTICAST,
- MacAddress.IPV6_MULTICAST_MASK));
- }
- // We set mac address to the treatment
- if (routerMac != null && !routerMac.equals(MacAddress.NONE)) {
- ttb.setEthDst(routerMac);
- }
- }
- // We finally build the meta treatment
- TrafficTreatment tt = ttb.build();
- filtBuilder.withMeta(tt);
- // Done, we return a permit filtering objective
- return filtBuilder.permit().fromApp(srManager.appId());
- }
-
- /**
- * Gets output ports information from treatments.
- *
- * @param treatments collection of traffic treatments
- * @return set of output port numbers
- */
- Set<PortNumber> getPorts(Collection<TrafficTreatment> treatments) {
- ImmutableSet.Builder<PortNumber> builder = ImmutableSet.builder();
- treatments.forEach(treatment -> treatment.allInstructions().stream()
- .filter(instr -> instr instanceof Instructions.OutputInstruction)
- .forEach(instr -> builder.add(((Instructions.OutputInstruction) instr).port())));
- return builder.build();
- }
-
- /**
- * Returns the hash of the group address.
- *
- * @param ipAddress the ip address
- * @return the hash of the address
- */
- private Long hasher(IpAddress ipAddress) {
- return HASH_FN.newHasher()
- .putBytes(ipAddress.toOctets())
- .hash()
- .asLong();
- }
-
- /**
- * Given a multicast group define a leader for it.
- *
- * @param mcastIp the group address
- * @return true if the instance is the leader of the group
- */
- boolean isLeader(IpAddress mcastIp) {
- // Get our id
- final NodeId currentNodeId = srManager.clusterService.getLocalNode().id();
- // Get the leader for this group using the ip address as key
- final NodeId leader = srManager.workPartitionService.getLeader(mcastIp, this::hasher);
- // If there is not a leader, let's send an error
- if (leader == null) {
- log.error("Fail to elect a leader for {}.", mcastIp);
- return false;
- }
- // Update cache and return operation result
- mcastLeaderCache.put(mcastIp, leader);
- return currentNodeId.equals(leader);
- }
-
- /**
- * Given a multicast group withdraw its leader.
- *
- * @param mcastIp the group address
- */
- void withdrawLeader(IpAddress mcastIp) {
- // For now just update the cache
- mcastLeaderCache.remove(mcastIp);
- }
-
- Map<IpAddress, NodeId> getMcastLeaders(IpAddress mcastIp) {
- // If mcast ip is present
- if (mcastIp != null) {
- return mcastLeaderCache.entrySet().stream()
- .filter(entry -> entry.getKey().equals(mcastIp))
- .collect(Collectors.toMap(Map.Entry::getKey,
- Map.Entry::getValue));
- }
- // Otherwise take all the groups
- return ImmutableMap.copyOf(mcastLeaderCache);
- }
-
- /**
- * Go through all the paths, looking for shared links to be used
- * in the final path computation.
- *
- * @param egresses egress devices
- * @param availablePaths all the available paths towards the egress
- * @return shared links between egress devices
- */
- private Set<Link> exploreMcastTree(Set<DeviceId> egresses,
- Map<DeviceId, List<Path>> availablePaths) {
- int minLength = Integer.MAX_VALUE;
- int length;
- List<Path> currentPaths;
- // Verify the source can still reach all the egresses
- for (DeviceId egress : egresses) {
- // From the source we cannot reach all the sinks
- // just continue and let's figure out after
- currentPaths = availablePaths.get(egress);
- if (currentPaths.isEmpty()) {
- continue;
- }
- // Get the length of the first one available, update the min length
- length = currentPaths.get(0).links().size();
- if (length < minLength) {
- minLength = length;
- }
- }
- // If there are no paths
- if (minLength == Integer.MAX_VALUE) {
- return Collections.emptySet();
- }
- int index = 0;
- Set<Link> sharedLinks = Sets.newHashSet();
- Set<Link> currentSharedLinks;
- Set<Link> currentLinks;
- DeviceId egressToRemove = null;
- // Let's find out the shared links
- while (index < minLength) {
- // Initialize the intersection with the paths related to the first egress
- currentPaths = availablePaths.get(egresses.stream().findFirst().orElse(null));
- currentSharedLinks = Sets.newHashSet();
- // Iterate over the paths and take the "index" links
- for (Path path : currentPaths) {
- currentSharedLinks.add(path.links().get(index));
- }
- // Iterate over the remaining egress
- for (DeviceId egress : egresses) {
- // Iterate over the paths and take the "index" links
- currentLinks = Sets.newHashSet();
- for (Path path : availablePaths.get(egress)) {
- currentLinks.add(path.links().get(index));
- }
- // Do intersection
- currentSharedLinks = Sets.intersection(currentSharedLinks, currentLinks);
- // If there are no shared paths exit and record the device to remove
- // we have to retry with a subset of sinks
- if (currentSharedLinks.isEmpty()) {
- egressToRemove = egress;
- index = minLength;
- break;
- }
- }
- sharedLinks.addAll(currentSharedLinks);
- index++;
- }
- // If the shared links is empty and there are egress let's retry another time with less sinks,
- // we can still build optimal subtrees
- if (sharedLinks.isEmpty() && egresses.size() > 1 && egressToRemove != null) {
- egresses.remove(egressToRemove);
- sharedLinks = exploreMcastTree(egresses, availablePaths);
- }
- return sharedLinks;
- }
-
- /**
- * Build Mcast tree having as root the given source and as leaves the given egress points.
- *
- * @param mcastIp multicast group
- * @param source source of the tree
- * @param sinks leaves of the tree
- * @return the computed Mcast tree
- */
- Map<ConnectPoint, List<Path>> computeSinkMcastTree(IpAddress mcastIp,
- DeviceId source,
- Set<ConnectPoint> sinks) {
- // Get the egress devices, remove source from the egress if present
- Set<DeviceId> egresses = sinks.stream().map(ConnectPoint::deviceId)
- .filter(deviceId -> !deviceId.equals(source)).collect(Collectors.toSet());
- Map<DeviceId, List<Path>> mcastTree = computeMcastTree(mcastIp, source, egresses);
- final Map<ConnectPoint, List<Path>> finalTree = Maps.newHashMap();
- // We need to put back the source if it was originally present
- sinks.forEach(sink -> {
- List<Path> sinkPaths = mcastTree.get(sink.deviceId());
- finalTree.put(sink, sinkPaths != null ? sinkPaths : ImmutableList.of());
- });
- return finalTree;
- }
-
- /**
- * Build Mcast tree having as root the given source and as leaves the given egress.
- *
- * @param mcastIp multicast group
- * @param source source of the tree
- * @param egresses leaves of the tree
- * @return the computed Mcast tree
- */
- private Map<DeviceId, List<Path>> computeMcastTree(IpAddress mcastIp,
- DeviceId source,
- Set<DeviceId> egresses) {
- log.debug("Computing tree for Multicast group {}, source {} and leafs {}",
- mcastIp, source, egresses);
- // Pre-compute all the paths
- Map<DeviceId, List<Path>> availablePaths = Maps.newHashMap();
- egresses.forEach(egress -> availablePaths.put(egress, getPaths(source, egress,
- Collections.emptySet())));
- // Explore the topology looking for shared links amongst the egresses
- Set<Link> linksToEnforce = exploreMcastTree(Sets.newHashSet(egresses), availablePaths);
- // Build the final paths enforcing the shared links between egress devices
- availablePaths.clear();
- egresses.forEach(egress -> availablePaths.put(egress, getPaths(source, egress,
- linksToEnforce)));
- return availablePaths;
- }
-
- /**
- * Gets path from src to dst computed using the custom link weigher.
- *
- * @param src source device ID
- * @param dst destination device ID
- * @param linksToEnforce links to be enforced
- * @return list of paths from src to dst
- */
- List<Path> getPaths(DeviceId src, DeviceId dst, Set<Link> linksToEnforce) {
- final Topology currentTopology = topologyService.currentTopology();
- final LinkWeigher linkWeigher = new SRLinkWeigher(srManager, src, linksToEnforce);
- List<Path> allPaths = Lists.newArrayList(topologyService.getPaths(currentTopology, src, dst, linkWeigher));
- log.trace("{} path(s) found from {} to {}", allPaths.size(), src, dst);
- return allPaths;
- }
-
- /**
- * Gets a stored path having dst as egress.
- *
- * @param dst destination device ID
- * @param storedPaths paths list
- * @return an optional path
- */
- Optional<? extends List<Link>> getStoredPath(DeviceId dst, Collection<? extends List<Link>> storedPaths) {
- return storedPaths.stream()
- .filter(path -> path.get(path.size() - 1).dst().deviceId().equals(dst))
- .findFirst();
- }
-
- /**
- * Returns a set of affected paths by the failed element.
- *
- * @param paths the paths to check
- * @param failedElement the failed element
- * @return the affected paths
- */
- Set<List<Link>> getAffectedPaths(Set<List<Link>> paths, Object failedElement) {
- if (failedElement instanceof DeviceId) {
- return getAffectedPathsByDevice(paths, failedElement);
- }
- return getAffectedPathsByLink(paths, failedElement);
- }
-
- private Set<List<Link>> getAffectedPathsByDevice(Set<List<Link>> paths, Object failedElement) {
- DeviceId affectedDevice = (DeviceId) failedElement;
- Set<List<Link>> affectedPaths = Sets.newHashSet();
- paths.forEach(path -> {
- if (path.stream().anyMatch(link -> link.src().deviceId().equals(affectedDevice))) {
- affectedPaths.add(path);
- }
- });
- return affectedPaths;
- }
-
- private Set<List<Link>> getAffectedPathsByLink(Set<List<Link>> paths, Object failedElement) {
- Link affectedLink = (Link) failedElement;
- Set<List<Link>> affectedPaths = Sets.newHashSet();
- paths.forEach(path -> {
- if (path.contains(affectedLink)) {
- affectedPaths.add(path);
- }
- });
- return affectedPaths;
- }
-
- /**
- * Checks if the failure is affecting the transit device.
- *
- * @param devices the transit devices
- * @param failedElement the failed element
- * @return true if the failed element is affecting the transit devices
- */
- boolean isInfraFailure(Set<DeviceId> devices, Object failedElement) {
- if (failedElement instanceof DeviceId) {
- return isInfraFailureByDevice(devices, failedElement);
- }
- return true;
- }
-
- private boolean isInfraFailureByDevice(Set<DeviceId> devices, Object failedElement) {
- DeviceId affectedDevice = (DeviceId) failedElement;
- return devices.contains(affectedDevice);
- }
-
- /**
- * Checks if a port is an infra port.
- *
- * @param connectPoint port to be checked
- * @param storedPaths paths to be checked against
- * @return true if the port is an infra port. False otherwise.
- */
- boolean isInfraPort(ConnectPoint connectPoint, Collection<? extends List<Link>> storedPaths) {
- for (List<Link> path : storedPaths) {
- if (path.stream().anyMatch(link -> link.src().equals(connectPoint) ||
- link.dst().equals(connectPoint))) {
- return true;
- }
- }
- return false;
- }
-
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/mcast/package-info.java b/app/src/main/java/org/onosproject/segmentrouting/mcast/package-info.java
deleted file mode 100644
index dfdd39a..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/mcast/package-info.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2018-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.
- */
-
-/**
- * Trellis Multicast service.
- */
-package org.onosproject.segmentrouting.mcast;
diff --git a/app/src/main/java/org/onosproject/segmentrouting/package-info.java b/app/src/main/java/org/onosproject/segmentrouting/package-info.java
deleted file mode 100644
index 137ba3c..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/package-info.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2015-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.
- */
-
-/**
- * Segment routing application components.
- */
-package org.onosproject.segmentrouting;
\ No newline at end of file
diff --git a/app/src/main/java/org/onosproject/segmentrouting/phasedrecovery/api/OsgiPropertyConstants.java b/app/src/main/java/org/onosproject/segmentrouting/phasedrecovery/api/OsgiPropertyConstants.java
deleted file mode 100644
index cdeb8a2..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/phasedrecovery/api/OsgiPropertyConstants.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2020-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.phasedrecovery.api;
-
-/**
- * Constants for default values of configurable properties.
- */
-public final class OsgiPropertyConstants {
- private OsgiPropertyConstants() {}
-
- public static final String PROP_PHASED_RECOVERY = "phasedRecovery";
- public static final boolean PHASED_RECOVERY_DEFAULT = false;
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/phasedrecovery/api/Phase.java b/app/src/main/java/org/onosproject/segmentrouting/phasedrecovery/api/Phase.java
deleted file mode 100644
index 7f18685..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/phasedrecovery/api/Phase.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2020-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.phasedrecovery.api;
-
-/**
- * Phases of recovering devices.
- */
-public enum Phase {
-
- /**
- * Device is waiting for ports to be reported.
- */
- PENDING,
-
- /**
- * Pair port enabled. This is the initial state for paired devices.
- */
- PAIR,
-
- /**
- * Infrastructure ports enabled.
- */
- INFRA,
-
- /**
- * Edge ports enabled. This is the initial state for non-paired and spine devices.
- */
- EDGE
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/phasedrecovery/api/PhasedRecoveryService.java b/app/src/main/java/org/onosproject/segmentrouting/phasedrecovery/api/PhasedRecoveryService.java
deleted file mode 100644
index 705ecb7..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/phasedrecovery/api/PhasedRecoveryService.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright 2020-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.phasedrecovery.api;
-
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.PortNumber;
-
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Service that provides functionality related to phased recovery.
- */
-public interface PhasedRecoveryService {
-
- // TODO Make timeout values configurable via Component Config Service
- /**
- * Timeout for PAIR phase in seconds.
- */
- int PAIR_TIMEOUT = 30;
-
- /**
- * Timeout for INFRA phase in seconds.
- */
- int INFRA_TIMEOUT = 30;
-
- /**
- * Timeout for EDGE phase in seconds.
- */
- int EDGE_TIMEOUT = 30;
-
- //
- // Phased recovery APIs.
- //
-
-
- /**
- * Returns true if phased recovery is enabled.
- *
- * @return true if phased recovery is enabled.
- */
- boolean isEnabled();
-
- /**
- * Initializes a device. Only the master of the device is allowed to do this.
- *
- * @param deviceId device ID
- * @return true if the device is initialized successfully and the caller should proceed,
- * false if the device initialization has failed and the caller should abort.
- */
- boolean init(DeviceId deviceId);
-
- /**
- * Resets a device. Only the master of the device is allowed to do this.
- *
- * @param deviceId device ID
- * @return true if the device is reset successfully.
- * false if the device has not been previously initialized.
- */
- boolean reset(DeviceId deviceId);
-
- /**
- * Gets recovery phase of every devices.
- *
- * @return a map between device ID and recovery phase
- */
- Map<DeviceId, Phase> getPhases();
-
- /**
- * Gets recovery phase of given device.
- *
- * @param deviceId device ID
- * @return current phase or null if the device wasn't seen before
- */
- Phase getPhase(DeviceId deviceId);
-
- /**
- * Sets given device with given recovery phase. Only the master of the device is allowed to do this.
- *
- * @param deviceId device ID
- * @param newPhase recovery phase
- * @return new phase if transition succeeded, otherwise return current phase.
- */
- Phase setPhase(DeviceId deviceId, Phase newPhase);
-
- //
- // Port manipulation APIs.
- //
-
- /**
- * Enables every ports on the given device.
- *
- * @param deviceId device id
- * @param enabled true to enable, false to disable
- * @return ports that have been enabled
- */
- Set<PortNumber> changeAllPorts(DeviceId deviceId, boolean enabled);
-
- /**
- * Enables pair port on the given device.
- *
- * @param deviceId device id
- * @param enabled true to enable, false to disable
- * @return ports that have been enabled
- */
- Set<PortNumber> changePairPort(DeviceId deviceId, boolean enabled);
-
- /**
- * Enables infrastructure ports on the given device.
- *
- * @param deviceId device id
- * @param enabled true to enable, false to disable
- * @return ports that have been enabled
- */
- Set<PortNumber> changeInfraPorts(DeviceId deviceId, boolean enabled);
-
- /**
- * Enables edge ports on the given device.
- *
- * @param deviceId device id
- * @param enabled true to enable, false to disable
- * @return ports that have been enabled
- */
- Set<PortNumber> changeEdgePorts(DeviceId deviceId, boolean enabled);
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/phasedrecovery/api/package-info.java b/app/src/main/java/org/onosproject/segmentrouting/phasedrecovery/api/package-info.java
deleted file mode 100644
index cc556be..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/phasedrecovery/api/package-info.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2020-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.
- */
-
-/**
- * Phased recovery API.
- */
-package org.onosproject.segmentrouting.phasedrecovery.api;
\ No newline at end of file
diff --git a/app/src/main/java/org/onosproject/segmentrouting/phasedrecovery/impl/PhasedRecoveryManager.java b/app/src/main/java/org/onosproject/segmentrouting/phasedrecovery/impl/PhasedRecoveryManager.java
deleted file mode 100644
index 5e25015..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/phasedrecovery/impl/PhasedRecoveryManager.java
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * Copyright 2020-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.phasedrecovery.impl;
-
-import com.google.common.collect.Sets;
-import org.onlab.util.KryoNamespace;
-import org.onlab.util.Tools;
-import org.onosproject.cfg.ComponentConfigService;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.core.CoreService;
-import org.onosproject.mastership.MastershipService;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Port;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.device.DeviceAdminService;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-import org.onosproject.segmentrouting.phasedrecovery.api.Phase;
-import org.onosproject.segmentrouting.phasedrecovery.api.PhasedRecoveryService;
-import org.onosproject.store.serializers.KryoNamespaces;
-import org.onosproject.store.service.ConsistentMap;
-import org.onosproject.store.service.Serializer;
-import org.onosproject.store.service.StorageService;
-import org.onosproject.store.service.Versioned;
-import org.osgi.service.component.ComponentContext;
-import org.osgi.service.component.annotations.Activate;
-import org.osgi.service.component.annotations.Component;
-import org.osgi.service.component.annotations.Deactivate;
-import org.osgi.service.component.annotations.Modified;
-import org.osgi.service.component.annotations.Reference;
-import org.osgi.service.component.annotations.ReferenceCardinality;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.Dictionary;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
-
-import static org.onlab.util.Tools.groupedThreads;
-import static org.onosproject.segmentrouting.phasedrecovery.api.OsgiPropertyConstants.PHASED_RECOVERY_DEFAULT;
-import static org.onosproject.segmentrouting.phasedrecovery.api.OsgiPropertyConstants.PROP_PHASED_RECOVERY;
-
-@Component(
- immediate = true,
- service = PhasedRecoveryService.class,
- property = {
- PROP_PHASED_RECOVERY + ":Boolean=" + PHASED_RECOVERY_DEFAULT
- }
-)
-public class PhasedRecoveryManager implements PhasedRecoveryService {
- private static final Logger log = LoggerFactory.getLogger(PhasedRecoveryManager.class);
- private static final String APP_NAME = "org.onosproject.phasedrecovery";
-
- // TODO Make these configurable via Component Config
- // Amount of time delayed to wait for port description (in second)
- private static final int PORT_CHECKER_INTERVAL = 1;
- // Max number of retry for port checker
- private static final int PORT_CHECKER_RETRIES = 5;
- // RoutingStableChecker interval (in second)
- private static final int ROUTING_CHECKER_DELAY = 3;
- // RoutingStableChecker timeout (in second)
- private static final int ROUTING_CHECKER_TIMEOUT = 15;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- private CoreService coreService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- private ComponentConfigService compCfgService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- private DeviceAdminService deviceAdminService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- private MastershipService mastershipService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- private StorageService storageService;
-
- @Reference(cardinality = ReferenceCardinality.OPTIONAL)
- volatile SegmentRoutingService srService;
-
- /** Enabling phased recovery. */
- boolean phasedRecovery = PHASED_RECOVERY_DEFAULT;
-
- private ApplicationId appId;
- private ConsistentMap<DeviceId, Phase> phasedRecoveryStore;
- private ScheduledExecutorService executor = Executors.newScheduledThreadPool(
- Runtime.getRuntime().availableProcessors(), groupedThreads("onos/sr/pr", "executor"));
-
- @Activate
- protected void activate(ComponentContext context) {
- appId = coreService.registerApplication(APP_NAME);
-
- KryoNamespace.Builder serializer = KryoNamespace.newBuilder()
- .register(KryoNamespaces.API)
- .register(Phase.class);
- phasedRecoveryStore = storageService.<DeviceId, Phase>consistentMapBuilder()
- .withName("onos-sr-phasedrecovery")
- .withRelaxedReadConsistency()
- .withSerializer(Serializer.using(serializer.build()))
- .build();
-
- compCfgService.registerProperties(getClass());
- modified(context);
- log.info("Started");
- }
-
- @Deactivate
- protected void deactivate() {
- phasedRecoveryStore.destroy();
- compCfgService.unregisterProperties(getClass(), false);
- log.info("Stopped");
- }
-
- @Modified
- protected void modified(ComponentContext context) {
- Dictionary<?, ?> properties = context.getProperties();
- if (properties == null) {
- return;
- }
-
- String strPhasedRecovery = Tools.get(properties, PROP_PHASED_RECOVERY);
- boolean expectPhasedRecovery = Boolean.parseBoolean(strPhasedRecovery);
- if (expectPhasedRecovery != phasedRecovery) {
- phasedRecovery = expectPhasedRecovery;
- log.info("{} phased recovery", phasedRecovery ? "Enabling" : "Disabling");
- }
- }
-
- @Override
- public boolean isEnabled() {
- return phasedRecovery;
- }
-
- @Override
- public boolean init(DeviceId deviceId) {
- if (this.srService == null) {
- log.info("SegmentRoutingService is not ready");
- return false;
- }
- if (!mastershipService.isLocalMaster(deviceId)) {
- log.info("Not master of {}", deviceId);
- return false;
- }
-
- Phase phase = Optional.ofNullable(phasedRecoveryStore.putIfAbsent(deviceId, Phase.PENDING))
- .map(Versioned::value).orElse(null);
-
- if (phase != null) {
- log.info("{} has been initialized already. Skipping.", deviceId);
- return false;
- } else {
- Phase nextPhase = (phasedRecovery && this.srService.getPairDeviceId(deviceId).isPresent()) ?
- Phase.PAIR : Phase.EDGE;
- if (nextPhase == Phase.PAIR) {
- // Wait for the PORT_STAT before entering next phase.
- // Note: Unlikely, when the device init fails due to PORT_STATS timeout,
- // it requires operator to manually move the device to the next phase by CLI command.
- executor.schedule(new PortChecker(deviceId, PORT_CHECKER_RETRIES),
- PORT_CHECKER_INTERVAL, TimeUnit.SECONDS);
- } else {
- // We assume that all ports will be reported as enabled on devices that don't require phased recovery
- setPhase(deviceId, Phase.EDGE);
- }
- return true;
- }
- }
-
- @Override
- public boolean reset(DeviceId deviceId) {
- if (this.srService == null) {
- log.info("SegmentRoutingService is not ready");
- return false;
- }
- // FIXME Skip mastership checking since master will not be available when a device goes offline
- // Improve this when persistent mastership is introduced
-
- Phase result = Optional.ofNullable(phasedRecoveryStore.remove(deviceId))
- .map(Versioned::value).orElse(null);
- if (result != null) {
- log.info("{} is reset", deviceId);
- }
- return result != null;
- }
-
- @Override
- public Map<DeviceId, Phase> getPhases() {
- return phasedRecoveryStore.asJavaMap();
- }
-
- @Override
- public Phase getPhase(DeviceId deviceId) {
- return Optional.ofNullable(phasedRecoveryStore.get(deviceId)).map(Versioned::value).orElse(null);
- }
-
- @Override
- public Phase setPhase(DeviceId deviceId, Phase newPhase) {
- if (this.srService == null) {
- log.info("SegmentRoutingService is not ready");
- return null;
- }
- if (!mastershipService.isLocalMaster(deviceId)) {
- log.info("Not master of {}", deviceId);
- return null;
- }
-
- return Optional.ofNullable(phasedRecoveryStore.compute(deviceId, (k, v) -> {
- if (v == null && newPhase == Phase.PENDING) {
- log.info("Initializing {}", deviceId);
- return newPhase;
- } else if (v == Phase.PENDING && newPhase == Phase.PAIR) {
- srService.initHost(deviceId);
- // RouteHandler init is intentionally skipped when phased recovery is on.
- // Edge ports remain down in this phase. Therefore, no nexthop will be discovered on the given device.
- // The flow on given device will be programmed later by hostHandler.processHostMovedEvent()
- changePairPort(deviceId, true);
- log.info("Transitioning {} from PENDING to PAIR", deviceId);
- return newPhase;
- } else if (v == Phase.PAIR && newPhase == Phase.INFRA) {
- changeInfraPorts(deviceId, true);
- srService.initRoute(deviceId);
- log.info("Transitioning {} from PAIR to INFRA", deviceId);
- monitorRoutingStability(deviceId);
- return newPhase;
- } else if (v == Phase.INFRA && newPhase == Phase.EDGE) {
- changeEdgePorts(deviceId, true);
- log.info("Transitioning {} from INFRA to EDGE", deviceId);
- return newPhase;
- } else if (v == Phase.PENDING && newPhase == Phase.EDGE) {
- changeAllPorts(deviceId, true);
- srService.initHost(deviceId);
- srService.initRoute(deviceId);
- log.info("Transitioning {} from PENDING to EDGE", deviceId);
- return newPhase;
- } else {
- log.debug("Ignore illegal state transition on {} from {} to {}", deviceId, v, newPhase);
- return v;
- }
- })).map(Versioned::value).orElse(null);
- }
-
- private void monitorRoutingStability(DeviceId deviceId) {
- CompletableFuture<Void> checkerFuture = new CompletableFuture<>();
- CompletableFuture<Void> timeoutFuture =
- Tools.completeAfter(ROUTING_CHECKER_TIMEOUT, TimeUnit.SECONDS);
- RoutingStabilityChecker checker = new RoutingStabilityChecker(checkerFuture);
-
- checkerFuture.runAfterEitherAsync(timeoutFuture, () -> {
- if (checkerFuture.isDone()) {
- log.info("Routing stable. Move {} to the next phase", deviceId);
- } else {
- log.info("Timeout reached. Move {} to the next phase", deviceId);
- // Mark the future as completed to signify the termination of periodical checker
- checkerFuture.complete(null);
- }
- setPhase(deviceId, Phase.EDGE);
- });
-
- executor.schedule(checker, ROUTING_CHECKER_DELAY, TimeUnit.SECONDS);
- }
-
- @Override
- public Set<PortNumber> changeAllPorts(DeviceId deviceId, boolean enabled) {
- if (this.srService == null) {
- log.warn("SegmentRoutingService is not ready. Unable to changeAllPorts({}) to {}", deviceId, enabled);
- return Sets.newHashSet();
- }
- Set<PortNumber> portsToBeEnabled = deviceAdminService.getPorts(deviceId)
- .stream().map(Port::number).collect(Collectors.toSet());
- changePorts(deviceId, portsToBeEnabled, enabled);
- return portsToBeEnabled;
- }
-
- @Override
- public Set<PortNumber> changePairPort(DeviceId deviceId, boolean enabled) {
- if (this.srService == null) {
- log.warn("SegmentRoutingService is not ready. Unable to changePairPort({}) to {}", deviceId, enabled);
- return Sets.newHashSet();
- }
- Set<PortNumber> portsToBeEnabled = this.srService.getPairLocalPort(deviceId)
- .map(Sets::newHashSet).orElse(Sets.newHashSet());
- changePorts(deviceId, portsToBeEnabled, enabled);
- return portsToBeEnabled;
- }
-
- @Override
- public Set<PortNumber> changeInfraPorts(DeviceId deviceId, boolean enabled) {
- if (this.srService == null) {
- log.warn("SegmentRoutingService is not ready. Unable to changeInfraPorts({}) to {}", deviceId, enabled);
- return Sets.newHashSet();
- }
- Set<PortNumber> portsToBeEnabled = this.srService.getInfraPorts(deviceId);
- changePorts(deviceId, portsToBeEnabled, enabled);
- return portsToBeEnabled;
- }
-
- @Override
- public Set<PortNumber> changeEdgePorts(DeviceId deviceId, boolean enabled) {
- if (this.srService == null) {
- log.warn("SegmentRoutingService is not ready. Unable to changeEdgePorts({}) to {}", deviceId, enabled);
- return Sets.newHashSet();
- }
- Set<PortNumber> portsToBeEnabled = this.srService.getEdgePorts(deviceId);
- changePorts(deviceId, portsToBeEnabled, enabled);
- return portsToBeEnabled;
- }
-
- private void changePorts(DeviceId deviceId, Set<PortNumber> portNumbers, boolean enabled) {
- log.info("{} {} on {}", enabled ? "Enabled" : "Disabled", portNumbers, deviceId);
- portNumbers.forEach(portNumber ->
- deviceAdminService.changePortState(deviceId, portNumber, enabled));
- }
-
- private class PortChecker implements Runnable {
- int retries;
- DeviceId deviceId;
-
- PortChecker(DeviceId deviceId, int retries) {
- this.deviceId = deviceId;
- this.retries = retries;
- }
-
- @Override
- public void run() {
- retries -= 1;
- if (retries < 0) {
- log.warn("PORT_STATS timeout. Unable to initialize {}", deviceId);
- return;
- }
-
- if (!deviceAdminService.getPorts(deviceId).isEmpty()) {
- log.info("{} reported PORT_STATS", deviceId);
- setPhase(deviceId, Phase.PAIR);
- }
- log.info("{} still waiting for PORT_STATS", deviceId);
- executor.schedule(this, PORT_CHECKER_INTERVAL, TimeUnit.SECONDS);
- }
- }
-
- private class RoutingStabilityChecker implements Runnable {
- private final CompletableFuture<Void> future;
-
- RoutingStabilityChecker(CompletableFuture<Void> future) {
- this.future = future;
- }
-
- @Override
- public void run() {
- // Do not continue if the future has been completed
- if (future.isDone()) {
- log.trace("RouteStabilityChecker is done. Stop checking");
- return;
- }
-
- if (srService.isRoutingStable()) {
- log.trace("Routing is stable");
- future.complete(null);
- } else {
- log.trace("Routing is not yet stable");
- executor.schedule(this, ROUTING_CHECKER_DELAY, TimeUnit.SECONDS);
- }
- }
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/phasedrecovery/impl/package-info.java b/app/src/main/java/org/onosproject/segmentrouting/phasedrecovery/impl/package-info.java
deleted file mode 100644
index 3788085..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/phasedrecovery/impl/package-info.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2020-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.
- */
-
-/**
- * Phased recovery implementation.
- */
-package org.onosproject.segmentrouting.phasedrecovery.impl;
\ No newline at end of file
diff --git a/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2Tunnel.java b/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2Tunnel.java
deleted file mode 100644
index 417a795..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2Tunnel.java
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Copyright 2016-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.pwaas;
-
-
-import com.google.common.base.MoreObjects;
-import org.onlab.packet.MplsLabel;
-import org.onlab.packet.VlanId;
-import org.onosproject.net.Link;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-/**
- * Implementation of the default l2 tunnel.
- */
-public class DefaultL2Tunnel implements L2Tunnel {
-
- /**
- * Mode of the pseudo wire.
- */
- private L2Mode pwMode;
- /**
- * Service delimiting tag.
- */
- private VlanId sdTag;
- /**
- * Tunnel id.
- */
- private long tunnelId;
- /**
- * Pseudo wire label.
- */
- private MplsLabel pwLabel;
- /**
- * Inter-CO label.
- */
- private MplsLabel interCoLabel;
-
- private List<Link> pathUsed;
-
- /**
- * Vlan which will be used for the encapsualted
- * vlan traffic.
- */
- private VlanId transportVlan;
-
- /**
- * Creates a inter-co l2 tunnel using the
- * supplied parameters.
- *
- * @param mode the tunnel mode
- * @param sdtag the service delimiting tag
- * @param tunnelId the tunnel id
- * @param pwLabel the pseudo wire label
- * @param interCoLabel the inter central office label
- */
- public DefaultL2Tunnel(L2Mode mode, VlanId sdtag, long tunnelId, MplsLabel pwLabel, MplsLabel interCoLabel) {
- checkNotNull(mode);
- checkArgument(tunnelId > 0);
- checkNotNull(pwLabel);
- checkNotNull(interCoLabel);
-
- this.pwMode = mode;
- this.sdTag = sdtag;
- this.tunnelId = tunnelId;
- this.pwLabel = pwLabel;
- this.interCoLabel = interCoLabel;
- }
-
- /**
- * Creates a l2Tunnel from a given tunnel.
- *
- * @param l2Tunnel to replicate
- */
- public DefaultL2Tunnel(DefaultL2Tunnel l2Tunnel) {
-
- this.pwMode = l2Tunnel.pwMode();
- this.sdTag = l2Tunnel.sdTag();
- this.tunnelId = l2Tunnel.tunnelId();
- this.pwLabel = l2Tunnel.pwLabel();
- this.interCoLabel = l2Tunnel.interCoLabel();
- this.pathUsed = l2Tunnel.pathUsed();
- this.transportVlan = l2Tunnel.transportVlan;
- }
-
- /**
- * Creates a intra-co l2 tunnel using the
- * supplied parameters.
- *
- * @param mode the tunnel mode
- * @param sdtag the service delimiting tag
- * @param tunnelId the tunnel id
- * @param pwLabel the pseudo wire label
- */
- public DefaultL2Tunnel(L2Mode mode, VlanId sdtag, long tunnelId, MplsLabel pwLabel) {
- this(mode, sdtag, tunnelId, pwLabel, MplsLabel.mplsLabel(MplsLabel.MAX_MPLS));
- }
-
-
- /**
- * Creates an empty l2 tunnel.
- **/
- public DefaultL2Tunnel() {
- this.pwMode = null;
- this.sdTag = null;
- this.tunnelId = 0;
- this.pwLabel = null;
- this.interCoLabel = null;
- }
-
- /**
- * Returns the mode of the pseudo wire.
- *
- * @return the pseudo wire mode
- */
- @Override
- public L2Mode pwMode() {
- return pwMode;
- }
-
- /**
- * Returns the service delimitation
- * tag.
- *
- * @return the service delimitation vlan id
- */
- @Override
- public VlanId sdTag() {
- return sdTag;
- }
-
- /**
- * Returns the tunnel id of the pseudo wire.
- *
- * @return the pseudo wire tunnel id
- */
- @Override
- public long tunnelId() {
- return tunnelId;
- }
-
- /**
- * Returns the pw label.
- *
- * @return the mpls pw label
- */
- @Override
- public MplsLabel pwLabel() {
- return pwLabel;
- }
-
- /**
- * Set the path for the pseudowire.
- *
- * @param path The path to set
- */
- @Override
- public void setPath(List<Link> path) {
- pathUsed = new ArrayList<>(path);
- }
-
- /**
- * Set the transport vlan for the pseudowire.
- *
- * @param vlan the vlan to use.
- */
- @Override
- public void setTransportVlan(VlanId vlan) {
- transportVlan = vlan;
- }
-
- /**
- * Returns the used path of the pseudowire.
- *
- * @return pathUsed
- */
- @Override
- public List<Link> pathUsed() {
- return pathUsed;
- }
-
- @Override
- public VlanId transportVlan() {
- return transportVlan;
- }
-
-
- /**
- * Returns the inter-co label.
- *
- * @return the mpls inter-co label
- */
- @Override
- public MplsLabel interCoLabel() {
- return interCoLabel;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(this.tunnelId, this.pwMode, this.sdTag, this.pwLabel, this.interCoLabel);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
-
- if (o instanceof DefaultL2Tunnel) {
- DefaultL2Tunnel that = (DefaultL2Tunnel) o;
- return this.tunnelId == that.tunnelId &&
- this.pwMode.equals(that.pwMode) &&
- this.sdTag.equals(that.sdTag) &&
- this.pwLabel.equals(that.pwLabel) &&
- this.interCoLabel.equals(that.interCoLabel);
- }
-
- return false;
- }
-
- @Override
- public String toString() {
- return MoreObjects.toStringHelper(this)
- .add("pwMode", pwMode())
- .add("sdTag", sdTag())
- .add("tunnelId", tunnelId())
- .add("pwLabel", pwLabel())
- .add("interCoLabel", interCoLabel())
- .add("transportVlan", transportVlan())
- .toString();
- }
-
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelDescription.java b/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelDescription.java
deleted file mode 100644
index 7a47972..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelDescription.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright 2016-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.pwaas;
-
-import com.google.common.base.MoreObjects;
-
-import java.util.Objects;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-/**
- * Helper class to carry the l2 tunnel
- * and its policy.
- */
-public class DefaultL2TunnelDescription implements L2TunnelDescription {
-
- /**
- * The l2 tunnel.
- */
- private L2Tunnel l2Tunnel;
-
- /**
- * The l2 tunnel policy.
- */
- private L2TunnelPolicy l2TunnelPolicy;
-
- /**
- * Creates a l2 tunnel description using the given info.
- *
- * @param l2Tunnel the l2 tunnel
- * @param l2TunnelPolicy the l2 tunnel description
- */
- public DefaultL2TunnelDescription(L2Tunnel l2Tunnel,
- L2TunnelPolicy l2TunnelPolicy) {
- checkNotNull(l2Tunnel);
- checkNotNull(l2TunnelPolicy);
-
- this.l2Tunnel = l2Tunnel;
- this.l2TunnelPolicy = l2TunnelPolicy;
- }
-
- /**
- * Creates an empty l2 tunnel description.
- */
- public DefaultL2TunnelDescription() {
- this.l2Tunnel = null;
- this.l2TunnelPolicy = null;
- }
-
- @Override
- public L2Tunnel l2Tunnel() {
- return l2Tunnel;
- }
-
- @Override
- public L2TunnelPolicy l2TunnelPolicy() {
- return l2TunnelPolicy;
- }
-
- @Override
- public void setL2Tunnel(L2Tunnel tunnel) {
- l2Tunnel = tunnel;
- }
-
- @Override
- public void setL2TunnelPolicy(L2TunnelPolicy policy) {
- l2TunnelPolicy = policy;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(this.l2Tunnel, this.l2TunnelPolicy);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
-
- if (o instanceof DefaultL2TunnelDescription) {
- DefaultL2TunnelDescription that = (DefaultL2TunnelDescription) o;
- // Equality is based on tunnel id and pw label
- // which is always the last label.
- return this.l2Tunnel.equals(that.l2Tunnel) &&
- this.l2TunnelPolicy.equals(that.l2TunnelPolicy);
- }
-
- return false;
- }
-
- @Override
- public String toString() {
- return MoreObjects.toStringHelper(this)
- .add("l2Tunnel", l2Tunnel())
- .add("l2TunnelPolicy", l2TunnelPolicy())
- .toString();
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelHandler.java b/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelHandler.java
deleted file mode 100644
index 99ff091..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelHandler.java
+++ /dev/null
@@ -1,1490 +0,0 @@
-/*
- * Copyright 2016-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.pwaas;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import org.apache.commons.lang3.RandomUtils;
-import org.onlab.packet.Ethernet;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.MplsLabel;
-import org.onlab.packet.VlanId;
-import org.onlab.util.KryoNamespace;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DefaultLink;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Link;
-import org.onosproject.net.Path;
-import org.onosproject.net.PortNumber;
-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.criteria.Criteria;
-import org.onosproject.net.flowobjective.DefaultFilteringObjective;
-import org.onosproject.net.flowobjective.DefaultForwardingObjective;
-import org.onosproject.net.flowobjective.DefaultNextObjective;
-import org.onosproject.net.flowobjective.DefaultObjectiveContext;
-import org.onosproject.net.flowobjective.FilteringObjective;
-import org.onosproject.net.flowobjective.ForwardingObjective;
-import org.onosproject.net.flowobjective.NextObjective;
-import org.onosproject.net.flowobjective.Objective;
-import org.onosproject.net.flowobjective.ObjectiveContext;
-import org.onosproject.net.flowobjective.ObjectiveError;
-import org.onosproject.net.topology.LinkWeigher;
-import org.onosproject.segmentrouting.SRLinkWeigher;
-import org.onosproject.segmentrouting.SegmentRoutingManager;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
-import org.onosproject.store.serializers.KryoNamespaces;
-import org.onosproject.store.service.ConsistentMap;
-import org.onosproject.store.service.DistributedLock;
-import org.onosproject.store.service.Serializer;
-import org.onosproject.store.service.StorageException;
-import org.onosproject.store.service.Versioned;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.stream.Collectors;
-
-import static org.onosproject.net.flowobjective.ForwardingObjective.Flag.VERSATILE;
-import static org.onosproject.segmentrouting.pwaas.L2TunnelHandler.Pipeline.INITIATION;
-import static org.onosproject.segmentrouting.pwaas.L2TunnelHandler.Pipeline.TERMINATION;
-import static org.onosproject.segmentrouting.pwaas.L2TunnelHandler.Result.*;
-import static org.onosproject.segmentrouting.pwaas.L2TunnelHandler.Direction.FWD;
-import static org.onosproject.segmentrouting.pwaas.L2TunnelHandler.Direction.REV;
-import static org.onosproject.segmentrouting.pwaas.PwaasUtil.*;
-
-/**
- * Handler for pseudowire management.
- */
-public class DefaultL2TunnelHandler implements L2TunnelHandler {
-
- private static final String LOCK_NAME = "l2-tunnel-handler-lock";
- private static final Logger log = LoggerFactory.getLogger(DefaultL2TunnelHandler.class);
-
- private final SegmentRoutingManager srManager;
- /**
- * To store the next objectives related to the initiation.
- */
- private final ConsistentMap<String, NextObjective> l2InitiationNextObjStore;
- /**
- * To store the next objectives related to the termination.
- */
- private final ConsistentMap<String, NextObjective> l2TerminationNextObjStore;
-
- /**
- * To store policies.
- */
- private final ConsistentMap<String, L2TunnelPolicy> l2PolicyStore;
-
- /**
- * To store tunnels.
- */
- private final ConsistentMap<String, L2Tunnel> l2TunnelStore;
-
- /**
- * To store pending tunnels that need to be installed.
- */
- private final ConsistentMap<String, L2Tunnel> pendingL2TunnelStore;
-
- /**
- * To store pending policies that need to be installed.
- */
- private final ConsistentMap<String, L2TunnelPolicy> pendingL2PolicyStore;
-
- private final KryoNamespace.Builder l2TunnelKryo;
-
- /**
- * Lock used when creating or removing pseudowires.
- */
- private final DistributedLock pwLock;
-
- private static final long LOCK_TIMEOUT = 2000;
-
- /**
- * Create a l2 tunnel handler for the deploy and
- * for the tear down of pseudo wires.
- *
- * @param segmentRoutingManager the segment routing manager
- */
- public DefaultL2TunnelHandler(SegmentRoutingManager segmentRoutingManager) {
- srManager = segmentRoutingManager;
- l2TunnelKryo = new KryoNamespace.Builder()
- .register(KryoNamespaces.API)
- .register(L2Tunnel.class,
- L2TunnelPolicy.class,
- DefaultL2Tunnel.class,
- DefaultL2TunnelPolicy.class,
- L2Mode.class,
- MplsLabel.class,
- VlanId.class,
- ConnectPoint.class);
-
- l2InitiationNextObjStore = srManager.
- storageService.
- <String, NextObjective>consistentMapBuilder().
- withName("onos-l2initiation-nextobj-store").
- withSerializer(Serializer.using(l2TunnelKryo.build())).
- build();
-
- l2TerminationNextObjStore = srManager.storageService.
- <String, NextObjective>consistentMapBuilder()
- .withName("onos-l2termination-nextobj-store")
- .withSerializer(Serializer.using(l2TunnelKryo.build()))
- .build();
-
- l2PolicyStore = srManager.storageService
- .<String, L2TunnelPolicy>consistentMapBuilder()
- .withName("onos-l2-policy-store")
- .withSerializer(Serializer.using(l2TunnelKryo.build()))
- .build();
-
- l2TunnelStore = srManager.storageService
- .<String, L2Tunnel>consistentMapBuilder()
- .withName("onos-l2-tunnel-store")
- .withSerializer(Serializer.using(l2TunnelKryo.build()))
- .build();
-
- pendingL2PolicyStore = srManager.storageService
- .<String, L2TunnelPolicy>consistentMapBuilder()
- .withName("onos-l2-pending-policy-store")
- .withSerializer(Serializer.using(l2TunnelKryo.build()))
- .build();
-
- pendingL2TunnelStore = srManager.storageService
- .<String, L2Tunnel>consistentMapBuilder()
- .withName("onos-l2-pending-tunnel-store")
- .withSerializer(Serializer.using(l2TunnelKryo.build()))
- .build();
-
- pwLock = srManager.storageService.lockBuilder()
- .withName(LOCK_NAME)
- .build()
- .asLock(LOCK_TIMEOUT);
- }
-
- /**
- * Used by manager only in initialization.
- */
- @Override
- public void init() {
- // Since we have no pseudowires in netcfg there
- // is nothing to do in initialization.
- // I leave it here because potentially we might need to
- // use it in the future.
- }
-
- @Override
- public Set<L2TunnelDescription> getL2Descriptions(boolean pending) {
- // get pending tunnels/policies OR installed tunnels/policies
- List<L2Tunnel> tunnels = pending ? getL2PendingTunnels() : getL2Tunnels();
- List<L2TunnelPolicy> policies = pending ? getL2PendingPolicies() : getL2Policies();
- return tunnels.stream()
- .map(l2Tunnel -> {
- L2TunnelPolicy policy = null;
- for (L2TunnelPolicy l2Policy : policies) {
- if (l2Policy.tunnelId() == l2Tunnel.tunnelId()) {
- policy = l2Policy;
- break;
- }
- }
-
- return new DefaultL2TunnelDescription(l2Tunnel, policy);
- })
- .collect(Collectors.toSet());
- }
-
- @Override
- public List<L2TunnelPolicy> getL2Policies() {
- return new ArrayList<>(l2PolicyStore
- .values()
- .stream()
- .map(Versioned::value)
- .collect(Collectors.toList()));
- }
-
- @Override
- public List<L2Tunnel> getL2Tunnels() {
- return new ArrayList<>(l2TunnelStore
- .values()
- .stream()
- .map(Versioned::value)
- .collect(Collectors.toList()));
- }
-
- @Override
- public List<L2TunnelPolicy> getL2PendingPolicies() {
- return new ArrayList<>(pendingL2PolicyStore
- .values()
- .stream()
- .map(Versioned::value)
- .collect(Collectors.toList()));
- }
-
- @Override
- public List<L2Tunnel> getL2PendingTunnels() {
- return new ArrayList<>(pendingL2TunnelStore
- .values()
- .stream()
- .map(Versioned::value)
- .collect(Collectors.toList()));
- }
-
- @Override
- public Result verifyGlobalValidity(L2TunnelDescription pwToAdd) {
-
- // get both added and pending pseudowires
- List<L2TunnelDescription> newPseudowires = new ArrayList<>();
- newPseudowires.addAll(getL2Descriptions(false));
- newPseudowires.addAll(getL2Descriptions(true));
- // add the new one
- newPseudowires.add(pwToAdd);
-
- return configurationValidity(newPseudowires);
- }
-
- @Override
- public ImmutableMap<String, NextObjective> getInitNext() {
- if (l2InitiationNextObjStore != null) {
- return ImmutableMap.copyOf(l2InitiationNextObjStore.asJavaMap());
- } else {
- return ImmutableMap.of();
- }
- }
-
- @Override
- public ImmutableMap<String, NextObjective> getTermNext() {
- if (l2TerminationNextObjStore != null) {
- return ImmutableMap.copyOf(l2TerminationNextObjStore.asJavaMap());
- } else {
- return ImmutableMap.of();
- }
- }
-
- @Override
- public void removeNextId(int nextId) {
- l2InitiationNextObjStore.entrySet().forEach(e -> {
- if (e.getValue().value().id() == nextId) {
- l2InitiationNextObjStore.remove(e.getKey());
- }
- });
-
- l2TerminationNextObjStore.entrySet().forEach(e -> {
- if (e.getValue().value().id() == nextId) {
- l2TerminationNextObjStore.remove(e.getKey());
- }
- });
- }
-
- /**
- * Returns the new vlan id for an ingress point of a
- * pseudowire. For double tagged, it is the outer,
- * For single tagged it is the single tag, and for
- * inner it is None.
- *
- * @param ingressOuter vlanid of ingress outer
- * @param ingressInner vlanid of ingress inner
- * @param egressOuter vlanid of egress outer
- * @param egressInner vlanid of egress inner
- * @return returns the vlan id which will be installed at vlan table 1.
- */
- private VlanId determineEgressVlan(VlanId ingressOuter, VlanId ingressInner,
- VlanId egressOuter, VlanId egressInner) {
- // validity of vlan combinations was checked at verifyPseudowire
- if (!(ingressOuter.equals(VlanId.NONE))) {
- return egressOuter;
- } else if (!(ingressInner.equals(VlanId.NONE))) {
- return egressInner;
- } else {
- return VlanId.vlanId("None");
- }
- }
-
- /**
- * Returns the devices existing on a given path.
- *
- * @param path The path to traverse.
- * @return The devices on the path with the order they
- * are traversed.
- */
- private List<DeviceId> getDevicesOnPath(List<Link> path) {
-
- // iterate over links and get all devices in the order
- // we find them
- List<DeviceId> deviceList = new ArrayList<>();
- for (Link link : path) {
- if (!deviceList.contains(link.src().deviceId())) {
- deviceList.add(link.src().deviceId());
- }
- if (!deviceList.contains(link.dst().deviceId())) {
- deviceList.add(link.dst().deviceId());
- }
- }
-
- return deviceList;
- }
-
- /**
- * Returns true if path is valid according to the current logic.
- * For example : leaf to spine pseudowires can be either leaf-spine or
- * leaf-spine-spine. However, in the configuration we might specify spine device
- * first which will result in spine-spine-leaf. If leafSpinePw == true we have one of these
- * two cases and need to provision for them.
- *
- * If we have a leaf to leaf pseudowire then all the intermediate devices must
- * be spines. However, in case of paired switches we can have two leafs interconnected
- * with each other directly.
- *
- * @param path the chosen path
- * @param leafSpinePw if it is a leaf to spine pseudowire
- * @return True if path size is valid, false otherwise.
- */
- private boolean isValidPath(List<Link> path, boolean leafSpinePw) {
-
- log.debug("Checking path validity for pseudowire.");
- List<DeviceId> devices = getDevicesOnPath(path);
- if (devices.size() < 2) {
- log.error("Path size for pseudowire should be greater than 1!");
- return false;
- }
-
- try {
- if (leafSpinePw) {
- // can either be leaf-spine-spine or leaf-spine
- // first device is leaf, all other must be spines
- log.debug("Devices on path are {} for leaf to spine pseudowire", devices);
- // if first device is a leaf then all other must be spines
- if (srManager.deviceConfiguration().isEdgeDevice(devices.get(0))) {
- devices.remove(0);
- for (DeviceId devId : devices) {
- log.debug("Device {} should be a spine!", devId);
- if (srManager.deviceConfiguration().isEdgeDevice(devId)) {
- return false;
- }
- }
- } else {
- // if first device is spine, last device must be a leaf
- // all other devices must be spines
- if (!srManager.deviceConfiguration().isEdgeDevice(devices.get(devices.size() - 1))) {
- return false;
- }
- devices.remove(devices.size() - 1);
- for (DeviceId devId : devices) {
- log.debug("Device {} should be a spine!", devId);
- if (srManager.deviceConfiguration().isEdgeDevice(devId)) {
- return false;
- }
- }
- }
- } else {
- // can either be leaf-leaf (paired leafs) / leaf-spine-leaf
- // or leaf-spine-spine-leaf
- log.debug("Devices on path are {} for leaf to leaf pseudowire", devices);
- // check first device, needs to be a leaf
- if (!srManager.deviceConfiguration().isEdgeDevice(devices.get(0))) {
- return false;
- }
- // check last device, needs to be a leaf
- if (!srManager.deviceConfiguration().isEdgeDevice(devices.get(devices.size() - 1))) {
- return false;
- }
- // remove these devices, rest must all be spines
- devices.remove(0);
- devices.remove(devices.size() - 1);
- for (DeviceId devId : devices) {
- log.debug("Device {} should be a spine!", devId);
- if (srManager.deviceConfiguration().isEdgeDevice(devId)) {
- return false;
- }
- }
-
- }
- } catch (DeviceConfigNotFoundException e) {
- log.error("Device not found in configuration : {}", e);
- return false;
- }
-
- return true;
- }
-
- /**
- * Adds a single pseudowire.
- *
- * @param pw The pseudowire to deploy
- * @return result of pseudowire deployment
- */
- public Result deployPseudowire(L2TunnelDescription pw) {
-
- try {
- // take the lock
- pwLock.lock();
- Result result;
- long l2TunnelId;
- log.debug("Pseudowire with {} deployment started, check log for any errors in this process!",
- pw.l2Tunnel().tunnelId());
- l2TunnelId = pw.l2Tunnel().tunnelId();
- // The tunnel id cannot be 0.
- if (l2TunnelId == 0) {
- log.warn("Tunnel id id must be > 0 in {}", l2TunnelId);
- return Result.WRONG_PARAMETERS
- .appendError("Tunnel id id must be > 0");
- }
-
- result = verifyGlobalValidity(pw);
- if (result != SUCCESS) {
- log.error("Global validity for pseudowire {} is wrong!", l2TunnelId);
- return result;
- }
-
- // leafSpinePw determines if this is a leaf-leaf
- // or leaf-spine pseudowire
- boolean leafSpinePw;
- ConnectPoint cp1 = pw.l2TunnelPolicy().cP1();
- ConnectPoint cp2 = pw.l2TunnelPolicy().cP2();
- try {
- // differentiate between leaf-leaf pseudowires and leaf-spine
- if (!srManager.deviceConfiguration().isEdgeDevice(cp1.deviceId()) &&
- !srManager.deviceConfiguration().isEdgeDevice(cp2.deviceId())) {
- log.error("Can not deploy pseudowire {} from spine to spine!", l2TunnelId);
- return Result.WRONG_PARAMETERS
- .appendError("Can not deploy pseudowire from spine to spine!");
- } else if (srManager.deviceConfiguration().isEdgeDevice(cp1.deviceId()) &&
- srManager.deviceConfiguration().isEdgeDevice(cp2.deviceId())) {
- leafSpinePw = false;
- } else {
- leafSpinePw = true;
- }
- } catch (DeviceConfigNotFoundException e) {
- log.error("Device for pseudowire {} connection points does not exist in the configuration", l2TunnelId);
- return Result.INTERNAL_ERROR
- .appendError("Device for pseudowire connection points does not exist in the configuration");
- }
-
- // reverse the policy in order for leaf switch to be at CP1
- // this will help us for re-using SRLinkWeigher for computing valid paths
- L2TunnelPolicy reversedPolicy = reverseL2TunnelPolicy(pw.l2TunnelPolicy());
- if (reversedPolicy == null) {
- log.error("Error in reversing policy, device configuration was not found for pseudowire {}.",
- l2TunnelId);
- return INTERNAL_ERROR
- .appendError("Device configuration not found when reversing the policy.");
- }
- pw.setL2TunnelPolicy(reversedPolicy);
-
- // get path here, need to use the same for fwd and rev direction
- List<Link> path = getPath(pw.l2TunnelPolicy().cP1(),
- pw.l2TunnelPolicy().cP2());
- if (path == null || path.isEmpty()) {
- log.error("Deploying process : No path between the connection points for pseudowire {}", l2TunnelId);
- return PATH_NOT_FOUND.appendError("No path between the connection points for pseudowire!");
- }
-
- Link fwdNextHop;
- Link revNextHop;
- if (!isValidPath(path, leafSpinePw)) {
- log.error("Deploying process : Path for pseudowire {} is not valid", l2TunnelId);
- return INTERNAL_ERROR.appendError("Internal error : path for pseudowire is not valid!");
- }
- // oneHope flag is used to determine if we need to
- // install transit mpls rules
- boolean oneHop = true;
- if (path.size() > 1) {
- oneHop = false;
- }
-
- fwdNextHop = path.get(0);
- revNextHop = reverseLink(path.get(path.size() - 1));
-
- pw.l2Tunnel().setPath(path);
- pw.l2Tunnel().setTransportVlan(srManager.getPwTransportVlan());
-
- // next hops for next objectives
- log.info("Deploying process : Establishing forward direction for pseudowire {}", l2TunnelId);
-
- VlanId egressVlan = determineEgressVlan(pw.l2TunnelPolicy().cP1OuterTag(),
- pw.l2TunnelPolicy().cP1InnerTag(),
- pw.l2TunnelPolicy().cP2OuterTag(),
- pw.l2TunnelPolicy().cP2InnerTag());
- result = deployPseudoWireInit(pw.l2Tunnel(),
- pw.l2TunnelPolicy().cP1(),
- pw.l2TunnelPolicy().cP2(),
- FWD,
- fwdNextHop,
- oneHop,
- egressVlan);
- if (result != SUCCESS) {
- log.error("Deploying process : Error in deploying pseudowire {} initiation for CP1", l2TunnelId);
- return Result.INTERNAL_ERROR.appendError("Error in deploying pseudowire initiation for CP1");
- }
-
- result = deployPolicy(l2TunnelId,
- pw.l2TunnelPolicy().cP1(),
- pw.l2TunnelPolicy().cP1InnerTag(),
- pw.l2TunnelPolicy().cP1OuterTag(),
- egressVlan,
- result.getNextId());
- if (result != SUCCESS) {
- log.error("Deploying process : Error in deploying pseudowire {} policy for CP1", l2TunnelId);
- return Result.INTERNAL_ERROR.appendError("Error in deploying pseudowire policy for CP1");
- }
-
- result = deployPseudoWireTerm(pw.l2Tunnel(),
- pw.l2TunnelPolicy().cP2(),
- egressVlan,
- FWD,
- oneHop);
-
- if (result != SUCCESS) {
- log.error("Deploying process : Error in deploying pseudowire {} termination for CP1", l2TunnelId);
- return Result.INTERNAL_ERROR.appendError("Error in deploying pseudowire termination for CP1");
- }
-
- // We establish the reverse tunnel.
- log.info("Deploying process : Establishing reverse direction for pseudowire {}", l2TunnelId);
- egressVlan = determineEgressVlan(pw.l2TunnelPolicy().cP2OuterTag(),
- pw.l2TunnelPolicy().cP2InnerTag(),
- pw.l2TunnelPolicy().cP1OuterTag(),
- pw.l2TunnelPolicy().cP1InnerTag());
-
- result = deployPseudoWireInit(pw.l2Tunnel(),
- pw.l2TunnelPolicy().cP2(),
- pw.l2TunnelPolicy().cP1(),
- REV,
- revNextHop,
- oneHop,
- egressVlan);
- if (result != SUCCESS) {
- log.error("Deploying process : Error in deploying pseudowire {} initiation for CP2", l2TunnelId);
- return Result.INTERNAL_ERROR
- .appendError("Error in deploying pseudowire initiation for CP2");
- }
-
- result = deployPolicy(l2TunnelId,
- pw.l2TunnelPolicy().cP2(),
- pw.l2TunnelPolicy().cP2InnerTag(),
- pw.l2TunnelPolicy().cP2OuterTag(),
- egressVlan,
- result.getNextId());
- if (result != SUCCESS) {
- log.error("Deploying process : Error in deploying policy {} for CP2", l2TunnelId);
- return Result.INTERNAL_ERROR
- .appendError("Deploying process : Error in deploying policy for CP2");
- }
-
- result = deployPseudoWireTerm(pw.l2Tunnel(),
- pw.l2TunnelPolicy().cP1(),
- egressVlan,
- REV,
- oneHop);
-
- if (result != SUCCESS) {
- log.error("Deploying process : Error in deploying pseudowire {} termination for CP2", l2TunnelId);
- return Result.INTERNAL_ERROR.appendError("Error in deploying pseudowire termination for CP2");
- }
-
- log.info("Deploying process : Updating relevant information for pseudowire {}", l2TunnelId);
-
- // Populate stores as the final step of the process
- l2TunnelStore.put(Long.toString(l2TunnelId), pw.l2Tunnel());
- l2PolicyStore.put(Long.toString(l2TunnelId), pw.l2TunnelPolicy());
-
- return Result.SUCCESS;
- } catch (StorageException.Timeout e) {
- log.error("Can not acquire distributed lock for pseudowire {}!", pw.l2Tunnel().tunnelId());
- return Result.INTERNAL_ERROR.appendError("Can not acquire distributed lock!");
- } finally {
- // release the lock
- pwLock.unlock();
- }
- }
-
- @Override
- public Result checkIfPwExists(long tunnelId, boolean pending) {
-
- List<L2TunnelDescription> pseudowires = getL2Descriptions(pending)
- .stream()
- .filter(pw -> pw.l2Tunnel().tunnelId() == tunnelId)
- .collect(Collectors.toList());
-
- if (pseudowires.size() == 0) {
- String store = ((pending) ? "pending" : "installed");
- log.debug("Pseudowire {} does not exist in {} store", tunnelId, store);
- return Result.WRONG_PARAMETERS.
- appendError("Pseudowire " + tunnelId + " does not exist in " + store);
- } else {
- return SUCCESS;
- }
- }
-
- /**
- * Tears down connection points of pseudowires. We can either tear down both connection points,
- * or each one of them.
- *
- * @param l2TunnelId The tunnel id for this pseudowire.
- * @param tearDownFirst Boolean, true if we want to tear down cp1
- * @param tearDownSecond Boolean, true if we want to tear down cp2
- * @param pending Boolean, if true remove only pseudowire from pending stores since no flows/groups
- * in the network, else remove flows/groups in the devices also.
- * @return Result of tearing down the pseudowire, SUCCESS if everything was ok
- * a descriptive error otherwise.
- */
- private Result tearDownConnectionPoints(long l2TunnelId, boolean tearDownFirst,
- boolean tearDownSecond, boolean pending) {
-
- Result res;
- CompletableFuture<ObjectiveError> fwdInitNextFuture = new CompletableFuture<>();
- CompletableFuture<ObjectiveError> fwdTermNextFuture = new CompletableFuture<>();
- CompletableFuture<ObjectiveError> revInitNextFuture = new CompletableFuture<>();
- CompletableFuture<ObjectiveError> revTermNextFuture = new CompletableFuture<>();
-
- if (l2TunnelId == 0) {
- log.error("Removal process : Tunnel id cannot be 0");
- return Result.WRONG_PARAMETERS.appendError("Pseudowire id can not be 0.");
- }
-
- res = checkIfPwExists(l2TunnelId, pending);
- if (res != Result.SUCCESS) {
- return res;
- }
-
- // remove and get the tunnel and the policy from the appropriate store
- // if null, return error.
- Versioned<L2Tunnel> l2TunnelVersioned = pending ?
- pendingL2TunnelStore.remove(Long.toString(l2TunnelId)) :
- l2TunnelStore.remove(Long.toString(l2TunnelId));
- Versioned<L2TunnelPolicy> l2TunnelPolicyVersioned = pending ?
- pendingL2PolicyStore.remove(Long.toString(l2TunnelId)) :
- l2PolicyStore.remove(Long.toString(l2TunnelId));
- if ((l2TunnelVersioned == null) || (l2TunnelPolicyVersioned == null)) {
- log.warn("Removal process : Policy and/or tunnel missing for tunnel id {}", l2TunnelId);
- return Result.INTERNAL_ERROR
- .appendError("Policy and/or tunnel missing for pseudowire!");
- }
-
- L2TunnelDescription pwToRemove = new DefaultL2TunnelDescription(l2TunnelVersioned.value(),
- l2TunnelPolicyVersioned.value());
-
- if (pending) {
- // no need to remove flows / groups for a pseudowire
- // in pending state
- return Result.SUCCESS;
- }
-
- // remove flows/groups involving with this pseudowire
- if (tearDownFirst) {
- log.info("Removal process : Tearing down forward direction of pseudowire {}", l2TunnelId);
-
- VlanId egressVlan = determineEgressVlan(pwToRemove.l2TunnelPolicy().cP1OuterTag(),
- pwToRemove.l2TunnelPolicy().cP1InnerTag(),
- pwToRemove.l2TunnelPolicy().cP2OuterTag(),
- pwToRemove.l2TunnelPolicy().cP2InnerTag());
- deletePolicy(l2TunnelId,
- pwToRemove.l2TunnelPolicy().cP1(),
- pwToRemove.l2TunnelPolicy().cP1InnerTag(),
- pwToRemove.l2TunnelPolicy().cP1OuterTag(),
- egressVlan,
- fwdInitNextFuture,
- FWD);
-
- fwdInitNextFuture.thenAcceptAsync(status -> {
- if (status == null) {
- // Finally we will tear down the pseudo wire.
- tearDownPseudoWireInit(l2TunnelId,
- pwToRemove.l2TunnelPolicy().cP1(),
- fwdTermNextFuture,
- FWD);
- }
- });
-
- fwdTermNextFuture.thenAcceptAsync(status -> {
- if (status == null) {
- tearDownPseudoWireTerm(pwToRemove.l2Tunnel(),
- pwToRemove.l2TunnelPolicy().cP2(),
- null,
- FWD);
- }
- });
- }
-
- if (tearDownSecond) {
- log.info("Removal process : Tearing down reverse direction of pseudowire {}", l2TunnelId);
-
- VlanId egressVlan = determineEgressVlan(pwToRemove.l2TunnelPolicy().cP2OuterTag(),
- pwToRemove.l2TunnelPolicy().cP2InnerTag(),
- pwToRemove.l2TunnelPolicy().cP1OuterTag(),
- pwToRemove.l2TunnelPolicy().cP1InnerTag());
-
- // We do the same operations on the reverse side.
- deletePolicy(l2TunnelId,
- pwToRemove.l2TunnelPolicy().cP2(),
- pwToRemove.l2TunnelPolicy().cP2InnerTag(),
- pwToRemove.l2TunnelPolicy().cP2OuterTag(),
- egressVlan,
- revInitNextFuture,
- REV);
-
- revInitNextFuture.thenAcceptAsync(status -> {
- if (status == null) {
- tearDownPseudoWireInit(l2TunnelId,
- pwToRemove.l2TunnelPolicy().cP2(),
- revTermNextFuture,
- REV);
- }
- });
-
- revTermNextFuture.thenAcceptAsync(status -> {
- if (status == null) {
- tearDownPseudoWireTerm(pwToRemove.l2Tunnel(),
- pwToRemove.l2TunnelPolicy().cP1(),
- null,
- REV);
- }
- });
- }
-
- return Result.SUCCESS;
- }
-
- /**
- * Helper function for removing a single pseudowire.
- *
- * Tries to remove pseudowire from any store it might reside (pending or installed).
- *
- * @param l2TunnelId the id of the pseudowire to tear down
- * @return Returns SUCCESS if no error is obeserved or an appropriate
- * error on a failure
- */
- public Result tearDownPseudowire(long l2TunnelId) {
-
- try {
- // take the lock
- pwLock.lock();
-
- if (checkIfPwExists(l2TunnelId, true) == Result.SUCCESS) {
- return tearDownConnectionPoints(l2TunnelId, true, true, true);
- } else if (checkIfPwExists(l2TunnelId, false) == Result.SUCCESS) {
- return tearDownConnectionPoints(l2TunnelId, true, true, false);
- } else {
- return Result.WRONG_PARAMETERS.appendError("Pseudowire with "
- + l2TunnelId
- + " did not reside in any store!");
- }
- } catch (StorageException.Timeout e) {
- log.error("Can not acquire distributed lock for pseudowire {}!", l2TunnelId);
- return Result.INTERNAL_ERROR.appendError("Can not acquire distributed lock!");
- } finally {
- // release the lock
- pwLock.unlock();
- }
- }
-
- @Override
- @Deprecated
- public void tearDown(Set<L2TunnelDescription> pwToRemove) {
-
- for (L2TunnelDescription currentL2Tunnel : pwToRemove) {
-
- long tunnelId = currentL2Tunnel.l2TunnelPolicy().tunnelId();
- log.info("Removing pseudowire {}", tunnelId);
-
- Result result = tearDownPseudowire(tunnelId);
- if (result != Result.SUCCESS) {
- log.error("Could not remove pseudowire {}!", tunnelId);
- }
- }
- }
-
- /**
- * Handles the policy establishment which consists in
- * create the filtering and forwarding objectives related
- * to the initiation and termination.
- *
- * @param tunnelId the tunnel id
- * @param ingress the ingress point
- * @param ingressInner the ingress inner tag
- * @param ingressOuter the ingress outer tag
- * @param egressVlan Vlan-id to set, depends on ingress vlan
- * combinations. For example, if pw is double tagged
- * then this is the value of the outer vlan, if single
- * tagged then it is the new value of the single tag.
- * Should be None for untagged traffic.
- * @param nextId the next objective id
- * @return the result of the operation
- */
- private Result deployPolicy(long tunnelId, ConnectPoint ingress, VlanId ingressInner,
- VlanId ingressOuter, VlanId egressVlan, int nextId) {
- log.debug("Starting deploying policy for pseudowire {}.", tunnelId);
-
- List<Objective> objectives = Lists.newArrayList();
- // We create the forwarding objective for supporting
- // the l2 tunnel.
- ForwardingObjective.Builder fwdBuilder = createInitFwdObjective(tunnelId, ingress.port(), nextId);
- // We create and add objective context.
- ObjectiveContext context = new DefaultObjectiveContext((objective) ->
- log.debug("FwdObj for tunnel {} populated", tunnelId),
- (objective, error) ->
- log.warn("Failed to populate fwdObj " +
- "for tunnel {} : {}",
- tunnelId, error));
- objectives.add(fwdBuilder.add(context));
-
- // We create the filtering objective to define the
- // permit traffic in the switch
- FilteringObjective.Builder filtBuilder = createFiltObjective(ingress.port(), ingressInner, ingressOuter);
-
- // We add the metadata.
- TrafficTreatment.Builder treatment = DefaultTrafficTreatment
- .builder()
- .setTunnelId(tunnelId)
- .setVlanId(egressVlan);
- filtBuilder.withMeta(treatment.build());
-
- // We create and add objective context.
- context = new DefaultObjectiveContext((objective) -> log.debug("FilterObj for tunnel {} populated", tunnelId),
- (objective, error) -> log.warn("Failed to populate filterObj for " +
- "tunnel {} : {}",
- tunnelId, error));
- objectives.add(filtBuilder.add(context));
-
- for (Objective objective : objectives) {
- if (objective instanceof ForwardingObjective) {
- srManager.flowObjectiveService.forward(ingress.deviceId(), (ForwardingObjective) objective);
- log.debug("Creating new FwdObj for initiation NextObj with id={} for tunnel {}", nextId, tunnelId);
- } else {
- srManager.flowObjectiveService.filter(ingress.deviceId(), (FilteringObjective) objective);
- log.debug("Creating new FiltObj for tunnel {}", tunnelId);
- }
- }
- return SUCCESS;
- }
-
- /**
- * Handles the tunnel establishment which consists in
- * create the next objectives related to the initiation.
- *
- * @param l2Tunnel the tunnel to deploy
- * @param ingress the ingress connect point
- * @param egress the egress connect point
- * @param direction the direction of the pw
- * @param nextHop next hop of the initiation point
- * @param oneHop if this pseudowire has only one link
- * @param termVlanId the termination vlan id
- * @return the result of the operation
- */
- private Result deployPseudoWireInit(L2Tunnel l2Tunnel, ConnectPoint ingress,
- ConnectPoint egress, Direction direction,
- Link nextHop, boolean oneHop, VlanId termVlanId) {
- log.debug("Started deploying init next objectives for pseudowire {} for tunnel {} -> {}.",
- l2Tunnel.tunnelId(), ingress, egress);
- if (nextHop == null) {
- log.warn("No path between ingress and egress connection points for tunnel {}", l2Tunnel.tunnelId());
- return WRONG_PARAMETERS;
- }
-
- // We create the next objective without the metadata
- // context and id. We check if it already exists in the
- // store. If not we store as it is in the store.
- NextObjective.Builder nextObjectiveBuilder = createNextObjective(INITIATION,
- nextHop.src(),
- nextHop.dst(),
- l2Tunnel,
- egress.deviceId(),
- oneHop,
- termVlanId);
-
- if (nextObjectiveBuilder == null) {
- return INTERNAL_ERROR;
- }
- // We set the metadata. We will use this metadata
- // to inform the driver we are doing a l2 tunnel.
- TrafficSelector metadata = DefaultTrafficSelector
- .builder()
- .matchTunnelId(l2Tunnel.tunnelId())
- .build();
- nextObjectiveBuilder.withMeta(metadata);
- int nextId = srManager.flowObjectiveService.allocateNextId();
- if (nextId < 0) {
- log.warn("Not able to allocate a next id for initiation");
- return INTERNAL_ERROR;
- }
- nextObjectiveBuilder.withId(nextId);
- String key = generateKey(l2Tunnel.tunnelId(), direction);
- l2InitiationNextObjStore.put(key, nextObjectiveBuilder.add());
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> log.debug("Initiation l2 tunnel rule for {} populated", l2Tunnel.tunnelId()),
- (objective, error) -> {
- log.warn("Failed to populate Initiation l2 tunnel rule for {}: {}", l2Tunnel.tunnelId(), error);
- srManager.invalidateNextObj(objective.id());
- });
- NextObjective nextObjective = nextObjectiveBuilder.add(context);
- srManager.flowObjectiveService.next(ingress.deviceId(), nextObjective);
- log.debug("Initiation next objective for {} not found. Creating new NextObj with id={}",
- l2Tunnel.tunnelId(), nextObjective.id());
- Result result = SUCCESS;
- result.setNextId(nextObjective.id());
- return result;
- }
-
- /**
- * Handles the tunnel termination, which consists in the creation
- * of a forwarding objective and a next objective.
- *
- * @param l2Tunnel the tunnel to terminate
- * @param egress the egress point
- * @param egressVlan the expected vlan at egress
- * @param direction the direction
- * @return the result of the operation
- */
- private Result deployPseudoWireTerm(L2Tunnel l2Tunnel, ConnectPoint egress,
- VlanId egressVlan, Direction direction,
- boolean oneHop) {
- log.debug("Started deploying termination objectives for pseudowire {} , direction {}.",
- l2Tunnel.tunnelId(), direction == FWD ? "forward" : "reverse");
-
- // We create the group relative to the termination.
- NextObjective.Builder nextObjectiveBuilder = createNextObjective(TERMINATION, egress, null,
- l2Tunnel, egress.deviceId(),
- oneHop,
- egressVlan);
- if (nextObjectiveBuilder == null) {
- return INTERNAL_ERROR;
- }
- TrafficSelector metadata = DefaultTrafficSelector
- .builder()
- .matchVlanId(egressVlan)
- .build();
- nextObjectiveBuilder.withMeta(metadata);
- int nextId = srManager.flowObjectiveService.allocateNextId();
- if (nextId < 0) {
- log.warn("Not able to allocate a next id for initiation");
- return INTERNAL_ERROR;
- }
- nextObjectiveBuilder.withId(nextId);
- String key = generateKey(l2Tunnel.tunnelId(), direction);
- l2TerminationNextObjStore.put(key, nextObjectiveBuilder.add());
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> log.debug("Termination l2 tunnel rule for {} populated", l2Tunnel.tunnelId()),
- (objective, error) -> {
- log.warn("Failed to populate termination l2 tunnel rule for {}: {}", l2Tunnel.tunnelId(), error);
- srManager.invalidateNextObj(objective.id());
- });
- NextObjective nextObjective = nextObjectiveBuilder.add(context);
- srManager.flowObjectiveService.next(egress.deviceId(), nextObjective);
- log.debug("Termination next objective for {} not found. Creating new NextObj with id={}",
- l2Tunnel.tunnelId(), nextObjective.id());
-
- // We create the flow relative to the termination.
- ForwardingObjective.Builder fwdBuilder = createTermFwdObjective(l2Tunnel.pwLabel(), l2Tunnel.tunnelId(),
- egress.port(), nextObjective.id());
- context = new DefaultObjectiveContext((objective) -> log.debug("FwdObj for tunnel termination {} populated",
- l2Tunnel.tunnelId()),
- (objective, error) -> log.warn("Failed to populate fwdrObj" +
- " for tunnel termination {} : {}",
- l2Tunnel.tunnelId(), error));
- srManager.flowObjectiveService.forward(egress.deviceId(), fwdBuilder.add(context));
- log.debug("Creating new FwdObj for termination NextObj with id={} for tunnel {}",
- nextId, l2Tunnel.tunnelId());
-
- return SUCCESS;
- }
-
-
- /**
- * Creates the filtering objective according to a given policy.
- *
- * @param inPort the in port
- * @param innerTag the inner vlan tag
- * @param outerTag the outer vlan tag
- * @return the filtering objective
- */
- private FilteringObjective.Builder createFiltObjective(PortNumber inPort, VlanId innerTag, VlanId outerTag) {
-
- log.debug("Creating connection point filtering objective for vlans {} / {}", outerTag, innerTag);
- return DefaultFilteringObjective
- .builder()
- .withKey(Criteria.matchInPort(inPort))
- .addCondition(Criteria.matchInnerVlanId(innerTag))
- .addCondition(Criteria.matchVlanId(outerTag))
- .withPriority(SegmentRoutingService.DEFAULT_PRIORITY)
- .permit()
- .fromApp(srManager.appId());
- }
-
- /**
- * Creates the forwarding objective for the termination.
- *
- * @param pwLabel the pseudo wire label
- * @param tunnelId the tunnel id
- * @param egressPort the egress port
- * @param nextId the next step
- * @return the forwarding objective to support the termination
- */
- private ForwardingObjective.Builder createTermFwdObjective(MplsLabel pwLabel, long tunnelId,
- PortNumber egressPort, int nextId) {
-
- log.debug("Creating forwarding objective for termination for tunnel {} : pwLabel {}, egressPort {}, nextId {}",
- tunnelId, pwLabel, egressPort, nextId);
- TrafficSelector.Builder trafficSelector = DefaultTrafficSelector.builder();
- TrafficTreatment.Builder trafficTreatment = DefaultTrafficTreatment.builder();
- // The flow has to match on the pw label and bos
- trafficSelector.matchEthType(Ethernet.MPLS_UNICAST);
- trafficSelector.matchMplsLabel(pwLabel);
- trafficSelector.matchMplsBos(true);
- // The flow has to decrement ttl, restore ttl in
- // pop mpls, set tunnel id and port.
- trafficTreatment.decMplsTtl();
- trafficTreatment.copyTtlIn();
- trafficTreatment.popMpls();
- trafficTreatment.setTunnelId(tunnelId);
- trafficTreatment.setOutput(egressPort);
-
- return DefaultForwardingObjective
- .builder()
- .fromApp(srManager.appId())
- .makePermanent()
- .nextStep(nextId)
- .withPriority(SegmentRoutingService.DEFAULT_PRIORITY)
- .withSelector(trafficSelector.build())
- .withTreatment(trafficTreatment.build())
- .withFlag(VERSATILE);
- }
-
- /**
- * Creates the forwarding objective for the initiation.
- *
- * @param tunnelId the tunnel id
- * @param inPort the input port
- * @param nextId the next step
- * @return the forwarding objective to support the initiation.
- */
- private ForwardingObjective.Builder createInitFwdObjective(long tunnelId, PortNumber inPort, int nextId) {
-
- log.debug("Creating forwarding objective for tunnel {} : Port {} , nextId {}", tunnelId, inPort, nextId);
- TrafficSelector.Builder trafficSelector = DefaultTrafficSelector.builder();
-
- // The flow has to match on the mpls logical
- // port and the tunnel id.
- trafficSelector.matchTunnelId(tunnelId);
- trafficSelector.matchInPort(inPort);
-
- return DefaultForwardingObjective
- .builder()
- .fromApp(srManager.appId())
- .makePermanent()
- .nextStep(nextId)
- .withPriority(SegmentRoutingService.DEFAULT_PRIORITY)
- .withSelector(trafficSelector.build())
- .withFlag(VERSATILE);
-
- }
-
- /**
- * Creates the next objective according to a given
- * pipeline. We don't set the next id and we don't
- * create the final meta to check if we are re-using
- * the same next objective for different tunnels.
- *
- * @param pipeline the pipeline to support
- * @param srcCp the source port
- * @param dstCp the destination port
- * @param l2Tunnel the tunnel to support
- * @param egressId the egress device id
- * @param oneHop if the pw only has one hop, push only pw label
- * @param termVlanId the outer vlan id of the packet exiting a termination point
- * @return the next objective to support the pipeline
- */
- private NextObjective.Builder createNextObjective(Pipeline pipeline, ConnectPoint srcCp,
- ConnectPoint dstCp, L2Tunnel l2Tunnel,
- DeviceId egressId, boolean oneHop,
- VlanId termVlanId) {
- log.debug("Creating {} next objective for pseudowire {}.",
- pipeline == TERMINATION ? "termination" : "inititation");
-
- NextObjective.Builder nextObjBuilder;
- TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
- if (pipeline == INITIATION) {
- nextObjBuilder = DefaultNextObjective
- .builder()
- .withType(NextObjective.Type.SIMPLE)
- .fromApp(srManager.appId());
- // The pw label is the bottom of stack. It has to
- // be different -1.
- if (l2Tunnel.pwLabel().toInt() == MplsLabel.MAX_MPLS) {
- log.error("Pw label not configured");
- return null;
- }
- treatmentBuilder.pushMpls();
- treatmentBuilder.setMpls(l2Tunnel.pwLabel());
- treatmentBuilder.setMplsBos(true);
- treatmentBuilder.copyTtlOut();
-
- // If the inter-co label is present we have to set the label.
- if (l2Tunnel.interCoLabel().toInt() != MplsLabel.MAX_MPLS) {
- treatmentBuilder.pushMpls();
- treatmentBuilder.setMpls(l2Tunnel.interCoLabel());
- treatmentBuilder.setMplsBos(false);
- treatmentBuilder.copyTtlOut();
- }
-
- // if not oneHop install transit mpls labels also
- if (!oneHop) {
- // We retrieve the sr label from the config
- // specific for pseudowire traffic
- // using the egress leaf device id.
- MplsLabel srLabel;
- try {
- srLabel = MplsLabel.mplsLabel(srManager.deviceConfiguration().getPWRoutingLabel(egressId));
-
- } catch (DeviceConfigNotFoundException e) {
- log.error("Sr label for pw traffic not configured");
- return null;
- }
-
- treatmentBuilder.pushMpls();
- treatmentBuilder.setMpls(srLabel);
- treatmentBuilder.setMplsBos(false);
- treatmentBuilder.copyTtlOut();
- }
-
- // We have to rewrite the src and dst mac address.
- MacAddress ingressMac;
- try {
- ingressMac = srManager.deviceConfiguration().getDeviceMac(srcCp.deviceId());
- } catch (DeviceConfigNotFoundException e) {
- log.error("Was not able to find the ingress mac");
- return null;
- }
- treatmentBuilder.setEthSrc(ingressMac);
- MacAddress neighborMac;
- try {
- neighborMac = srManager.deviceConfiguration().getDeviceMac(dstCp.deviceId());
- } catch (DeviceConfigNotFoundException e) {
- log.error("Was not able to find the neighbor mac");
- return null;
- }
- treatmentBuilder.setEthDst(neighborMac);
-
- // set the appropriate transport vlan from tunnel information
- treatmentBuilder.setVlanId(l2Tunnel.transportVlan());
- } else {
- // We create the next objective which
- // will be a simple l2 group.
- nextObjBuilder = DefaultNextObjective
- .builder()
- .withType(NextObjective.Type.SIMPLE)
- .fromApp(srManager.appId());
-
- // for termination point we use the outer vlan of the
- // encapsulated packet for the vlan
- treatmentBuilder.setVlanId(termVlanId);
- }
-
- treatmentBuilder.setOutput(srcCp.port());
- nextObjBuilder.addTreatment(treatmentBuilder.build());
- return nextObjBuilder;
- }
-
- /**
- * Reverse an l2 tunnel policy in order to have as CP1 the leaf switch,
- * in case one of the switches is a spine.
- *
- * This makes possible the usage of SRLinkWeigher for computing valid paths,
- * which cuts leaf-spine links from the path computation with a src different
- * than the source leaf.
- *
- * @param policy The policy to reverse, if needed
- * @return a l2TunnelPolicy containing the leaf at CP1, suitable for usage with
- * current SRLinkWeigher
- */
- private L2TunnelPolicy reverseL2TunnelPolicy(L2TunnelPolicy policy) {
-
- log.debug("Reversing policy for pseudowire.");
- try {
- // if cp1 is a leaf, just return
- if (srManager.deviceConfiguration().isEdgeDevice(policy.cP1().deviceId())) {
- return policy;
- } else {
- // return a policy with reversed cp1 and cp2, and also with reversed tags
- return new DefaultL2TunnelPolicy(policy.tunnelId(),
- policy.cP2(), policy.cP2InnerTag(), policy.cP2OuterTag(),
- policy.cP1(), policy.cP1InnerTag(), policy.cP1OuterTag());
-
- }
- } catch (DeviceConfigNotFoundException e) {
- // should never come here, since it has been checked before
- log.error("Configuration for device {}, does not exist!");
- return null;
- }
- }
-
- /**
- * Reverses a link.
- *
- * @param link link to be reversed
- * @return the reversed link
- */
- private Link reverseLink(Link link) {
-
- DefaultLink.Builder linkBuilder = DefaultLink.builder();
-
- linkBuilder.src(link.dst());
- linkBuilder.dst(link.src());
- linkBuilder.type(link.type());
- linkBuilder.providerId(link.providerId());
-
- return linkBuilder.build();
- }
-
- /**
- * Returns the path betwwen two connect points.
- *
- * @param srcCp source connect point
- * @param dstCp destination connect point
- * @return the path
- */
- private List<Link> getPath(ConnectPoint srcCp, ConnectPoint dstCp) {
-
- // use SRLinkWeigher to avoid pair links, and also
- // avoid going from the spine to the leaf and to the
- // spine again, we need to have the leaf as CP1 here.
- LinkWeigher srLw = new SRLinkWeigher(srManager, srcCp.deviceId(), new HashSet<Link>());
-
- Set<Path> paths = srManager.topologyService.
- getPaths(srManager.topologyService.currentTopology(),
- srcCp.deviceId(), dstCp.deviceId(), srLw);
-
- log.debug("Paths obtained from topology service {}", paths);
-
- // We randomly pick a path.
- if (paths.isEmpty()) {
- return null;
- }
- int size = paths.size();
- int index = RandomUtils.nextInt(0, size);
-
- List<Link> result = Iterables.get(paths, index).links();
- log.debug("Randomly picked a path {}", result);
-
- return result;
- }
-
- /**
- * Deletes a given policy using the parameter supplied.
- *
- * @param tunnelId the tunnel id
- * @param ingress the ingress point
- * @param ingressInner the ingress inner vlan id
- * @param ingressOuter the ingress outer vlan id
- * @param future to perform the async operation
- * @param direction the direction: forward or reverse
- */
- private void deletePolicy(long tunnelId, ConnectPoint ingress, VlanId ingressInner, VlanId ingressOuter,
- VlanId egressVlan, CompletableFuture<ObjectiveError> future, Direction direction) {
-
- String key = generateKey(tunnelId, direction);
- if (!l2InitiationNextObjStore.containsKey(key)) {
- log.error("Abort delete of policy for tunnel {}: next does not exist in the store", tunnelId);
- if (future != null) {
- future.complete(null);
- }
- return;
- }
- NextObjective nextObjective = l2InitiationNextObjStore.get(key).value();
- int nextId = nextObjective.id();
- List<Objective> objectives = Lists.newArrayList();
- // We create the forwarding objective.
- ForwardingObjective.Builder fwdBuilder = createInitFwdObjective(tunnelId, ingress.port(), nextId);
- ObjectiveContext context = new ObjectiveContext() {
- @Override
- public void onSuccess(Objective objective) {
- log.debug("Previous fwdObj for policy {} removed", tunnelId);
- if (future != null) {
- future.complete(null);
- }
- }
-
- @Override
- public void onError(Objective objective, ObjectiveError error) {
- log.error("Failed to remove previous fwdObj for policy {}: {}", tunnelId, error);
- if (future != null) {
- future.complete(error);
- }
- }
- };
- objectives.add(fwdBuilder.remove(context));
- // We create the filtering objective to define the
- // permit traffic in the switch
- FilteringObjective.Builder filtBuilder = createFiltObjective(ingress.port(), ingressInner, ingressOuter);
- TrafficTreatment.Builder treatment = DefaultTrafficTreatment
- .builder()
- .setTunnelId(tunnelId)
- .setVlanId(egressVlan);
- filtBuilder.withMeta(treatment.build());
- context = new DefaultObjectiveContext((objective) -> log.debug("FilterObj for policy {} revoked", tunnelId),
- (objective, error) ->
- log.warn("Failed to revoke filterObj for policy {}",
- tunnelId, error));
- objectives.add(filtBuilder.remove(context));
-
- for (Objective objective : objectives) {
- if (objective instanceof ForwardingObjective) {
- srManager.flowObjectiveService.forward(ingress.deviceId(), (ForwardingObjective) objective);
- } else {
- srManager.flowObjectiveService.filter(ingress.deviceId(), (FilteringObjective) objective);
- }
- }
- }
-
- /**
- * Deletes the pseudo wire initiation.
- *
- * @param l2TunnelId the tunnel id
- * @param ingress the ingress connect point
- * @param future to perform an async operation
- * @param direction the direction: reverse of forward
- */
- private void tearDownPseudoWireInit(long l2TunnelId, ConnectPoint ingress,
- CompletableFuture<ObjectiveError> future, Direction direction) {
- log.debug("Starting tearing dowing initation of pseudowire {} for direction {}.",
- l2TunnelId, direction == FWD ? "forward" : "reverse");
- String key = generateKey(l2TunnelId, direction);
- if (!l2InitiationNextObjStore.containsKey(key)) {
- log.error("Abort delete of {} for {}: next does not exist in the store", INITIATION, key);
- if (future != null) {
- future.complete(null);
- }
- return;
- }
-
- // un-comment in case you want to delete groups used by the pw
- // however, this will break the update of pseudowires cause the L2 interface group can
- // not be deleted (it is referenced by other groups)
- /*
- NextObjective nextObjective = l2InitiationNextObjStore.get(key).value();
- ObjectiveContext context = new ObjectiveContext() {
- @Override
- public void onSuccess(Objective objective) {
- log.debug("Previous {} next for {} removed", INITIATION, key);
- if (future != null) {
- future.complete(null);
- }
- }
-
- @Override
- public void onError(Objective objective, ObjectiveError error) {
- log.warn("Failed to remove previous {} next for {}: {}", INITIATION, key, error);
- if (future != null) {
- future.complete(error);
- }
- }
- };
- srManager.flowObjectiveService.next(ingress.deviceId(), (NextObjective) nextObjective.copy().remove(context));
- */
-
- future.complete(null);
- l2InitiationNextObjStore.remove(key);
- }
-
- /**
- * Deletes the pseudo wire termination.
- *
- * @param l2Tunnel the tunnel
- * @param egress the egress connect point
- * @param future the async task
- * @param direction the direction of the tunnel
- */
- private void tearDownPseudoWireTerm(L2Tunnel l2Tunnel,
- ConnectPoint egress,
- CompletableFuture<ObjectiveError> future,
- Direction direction) {
- log.debug("Starting tearing down termination for pseudowire {} direction {}.",
- l2Tunnel.tunnelId(), direction == FWD ? "forward" : "reverse");
- String key = generateKey(l2Tunnel.tunnelId(), direction);
- if (!l2TerminationNextObjStore.containsKey(key)) {
- log.error("Abort delete of {} for {}: next does not exist in the store", TERMINATION, key);
- if (future != null) {
- future.complete(null);
- }
- return;
- }
- NextObjective nextObjective = l2TerminationNextObjStore.get(key).value();
- ForwardingObjective.Builder fwdBuilder = createTermFwdObjective(l2Tunnel.pwLabel(),
- l2Tunnel.tunnelId(),
- egress.port(),
- nextObjective.id());
- ObjectiveContext context = new DefaultObjectiveContext((objective) ->
- log.debug("FwdObj for {} {}, " +
- "direction {} removed",
- TERMINATION,
- l2Tunnel.tunnelId(),
- direction),
- (objective, error) ->
- log.warn("Failed to remove fwdObj " +
- "for {} {}" +
- ", direction {}",
- TERMINATION,
- l2Tunnel.tunnelId(),
- error,
- direction));
- srManager.flowObjectiveService.forward(egress.deviceId(), fwdBuilder.remove(context));
-
- // un-comment in case you want to delete groups used by the pw
- // however, this will break the update of pseudowires cause the L2 interface group can
- // not be deleted (it is referenced by other groups)
- /*
- context = new ObjectiveContext() {
- @Override
- public void onSuccess(Objective objective) {
- log.debug("Previous {} next for {} removed", TERMINATION, key);
- if (future != null) {
- future.complete(null);
- }
- }
-
- @Override
- public void onError(Objective objective, ObjectiveError error) {
- log.warn("Failed to remove previous {} next for {}: {}", TERMINATION, key, error);
- if (future != null) {
- future.complete(error);
- }
- }
- };
- srManager.flowObjectiveService.next(egress.deviceId(), (NextObjective) nextObjective.copy().remove(context));
- */
-
- l2TerminationNextObjStore.remove(key);
- future.complete(null);
- }
-
- /**
- * Utilities to generate pw key.
- *
- * @param tunnelId the tunnel id
- * @param direction the direction of the pw
- * @return the key of the store
- */
- private String generateKey(long tunnelId, Direction direction) {
- return String.format("%s-%s", tunnelId, direction);
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelPolicy.java b/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelPolicy.java
deleted file mode 100644
index 4738744..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelPolicy.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright 2016-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.pwaas;
-
-import com.google.common.base.MoreObjects;
-import org.onlab.packet.VlanId;
-import org.onosproject.net.ConnectPoint;
-
-import java.util.Objects;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-/**
- * Implementation of the default l2 tunnel policy.
- */
-public class DefaultL2TunnelPolicy implements L2TunnelPolicy {
-
- /**
- * Id of the tunnel associated to this policy.
- */
- private long tunnelId;
- /**
- * First connect point.
- */
- private ConnectPoint cP1;
- /**
- * Second connect point.
- */
- private ConnectPoint cP2;
- /**
- * cP1 inner vlan tag. Used in QinQ packets.
- */
- private VlanId cP1InnerTag;
- /**
- * cP1 outer vlan tag.
- */
- private VlanId cP1OuterTag;
- /**
- * cP2 inner vlan tag. Used in QinQ packets.
- */
- private VlanId cP2InnerTag;
- /**
- * cP2 outer vlan tag.
- */
- private VlanId cP2OuterTag;
-
- /**
- * Creates a default l2 tunnel policy using
- * the given parameters.
- *
- * @param tunnelId the tunnel id
- * @param cP1 the first connect point
- * @param cP1InnerTag the cP1 inner tag
- * @param cP1OuterTag the cP1 outer tag
- * @param cP2 the second connect point
- * @param cP2InnerTag the cP2 inner tag
- * @param cP2OuterTag the cP2 outer tag
- */
- public DefaultL2TunnelPolicy(long tunnelId,
- ConnectPoint cP1, VlanId cP1InnerTag, VlanId cP1OuterTag,
- ConnectPoint cP2, VlanId cP2InnerTag, VlanId cP2OuterTag) {
- this.cP1 = checkNotNull(cP1);
- this.cP2 = checkNotNull(cP2);
- this.tunnelId = tunnelId;
- this.cP1InnerTag = cP1InnerTag;
- this.cP1OuterTag = cP1OuterTag;
- this.cP2InnerTag = cP2InnerTag;
- this.cP2OuterTag = cP2OuterTag;
- }
-
- /**
- * Creates a default l2 policy given the provided policy.
- * @param policy L2policy to replicate
- */
- public DefaultL2TunnelPolicy(DefaultL2TunnelPolicy policy) {
-
- this.cP1 = policy.cP1;
- this.cP2 = policy.cP2;
- this.tunnelId = policy.tunnelId;
- this.cP1InnerTag = policy.cP1InnerTag;
- this.cP1OuterTag = policy.cP1OuterTag;
- this.cP2InnerTag = policy.cP2InnerTag;
- this.cP2OuterTag = policy.cP2OuterTag;
- }
-
- @Override
- public ConnectPoint cP1() {
- return cP1;
- }
-
- @Override
- public ConnectPoint cP2() {
- return cP2;
- }
-
- @Override
- public VlanId cP1InnerTag() {
- return cP1InnerTag;
- }
-
- @Override
- public VlanId cP1OuterTag() {
- return cP1OuterTag;
- }
-
- @Override
- public VlanId cP2InnerTag() {
- return cP2InnerTag;
- }
-
- @Override
- public VlanId cP2OuterTag() {
- return cP2OuterTag;
- }
-
- @Override
- public long tunnelId() {
- return this.tunnelId;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(tunnelId,
- cP1,
- cP2,
- cP1InnerTag,
- cP1OuterTag,
- cP2InnerTag,
- cP2OuterTag
- );
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
-
- if (o instanceof DefaultL2TunnelPolicy) {
- DefaultL2TunnelPolicy that = (DefaultL2TunnelPolicy) o;
- if (this.tunnelId == that.tunnelId &&
- this.cP1.equals(that.cP1) &&
- this.cP2.equals(that.cP2) &&
- this.cP1InnerTag.equals(that.cP1InnerTag) &&
- this.cP1OuterTag.equals(that.cP1OuterTag) &&
- this.cP2InnerTag.equals(that.cP2InnerTag) &&
- this.cP2OuterTag.equals(that.cP2OuterTag)) {
- return true;
- }
- }
-
- return false;
- }
-
- @Override
- public String toString() {
- return MoreObjects.toStringHelper(this)
- .add("tunnelId", tunnelId())
- .add("cP1", cP1())
- .add("cP2", cP2())
- .add("cP1InnerTag", cP1InnerTag())
- .add("cP1OuterTag", cP1OuterTag())
- .add("cP2InnerTag", cP2InnerTag())
- .add("cP2OuterTag", cP2OuterTag())
- .toString();
- }
-
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2Mode.java b/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2Mode.java
deleted file mode 100644
index 685a606..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2Mode.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2016-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.pwaas;
-
-/**
- * Enum to identify mode of the pwaas.
- */
-public enum L2Mode {
- /**
- * Raw mode.
- */
- RAW,
- /**
- * Tagged mode. In this case the packet need
- * the sd tag.
- */
- TAGGED
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2Tunnel.java b/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2Tunnel.java
deleted file mode 100644
index 3e98480..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2Tunnel.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2016-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.pwaas;
-
-import org.onlab.packet.MplsLabel;
-import org.onlab.packet.VlanId;
-import org.onosproject.net.Link;
-
-import java.util.List;
-
-public interface L2Tunnel {
-
- /**
- * Return the mode of the l2 tunnel.
- *
- * @return The pw mode.
- */
- L2Mode pwMode();
-
- /**
- * Returns the service delimiting tag.
- *
- * @return the sd tag
- */
- VlanId sdTag();
-
- /**
- * Returns the id of the tunnel.
- *
- * @return the tunnel id
- */
- long tunnelId();
-
- /**
- * Return the label of the pseudowire.
- *
- * @return the pw label.
- */
- MplsLabel pwLabel();
-
- /**
- * Returns the path used by the pseudowire.
- *
- * @return The path that is used
- */
- List<Link> pathUsed();
-
- /**
- * Returns the transport vlan used by the pseudowire.
- *
- * @return The transport vlan
- */
- VlanId transportVlan();
-
- /**
- * Returns the inter-co label used by the pseudowire.
- *
- * @return The inter CO label.
- */
- MplsLabel interCoLabel();
-
- /**
- * Sets the path that this pw uses.
- *
- * @param path The apth to use
- */
- void setPath(List<Link> path);
-
- /**
- * Set the transport vlan that this pw will use.
- *
- * @param vlan The vlan to use.
- */
- void setTransportVlan(VlanId vlan);
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelDescription.java b/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelDescription.java
deleted file mode 100644
index 7be187a..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelDescription.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2016-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.pwaas;
-
-public interface L2TunnelDescription {
-
- /**
- * Returns the l2 tunnel.
- *
- * @return the l2 tunnel
- */
- L2Tunnel l2Tunnel();
-
- /**
- * Returns the l2 tunnel policy.
- *
- * @return the l2 tunnel policy.
- */
- L2TunnelPolicy l2TunnelPolicy();
-
- /**
- * Sets the l2 tunnel.
- *
- * @param tunnel the l2 tunnel to set.
- */
- void setL2Tunnel(L2Tunnel tunnel);
-
- /**
- * Sets the l2 policy.
- *
- * @param policy the policy to set.
- */
- void setL2TunnelPolicy(L2TunnelPolicy policy);
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelHandler.java b/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelHandler.java
deleted file mode 100644
index 2a003b3..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelHandler.java
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Copyright 2016-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.pwaas;
-
-import com.google.common.collect.ImmutableMap;
-import org.onosproject.net.flowobjective.NextObjective;
-
-import java.util.List;
-import java.util.Set;
-
-public interface L2TunnelHandler {
- void init();
-
- /**
- * Combines policies and tunnels to create descriptions.
- *
- * @param pending if it is true return pending to be installed pseudowires
- * from the appropriate store, else return installed pseudowires
- * @return Set of l2 tunnel descriptions.
- */
- Set<L2TunnelDescription> getL2Descriptions(boolean pending);
-
- /**
- * Returns a copy of the l2 policies that exist in the store.
- *
- * @return The l2 policies
- */
- List<L2TunnelPolicy> getL2Policies();
-
- /**
- * Returns a copy of the l2 tunnels that exist in the store.
- *
- * @return The l2 tunnels.
- */
- List<L2Tunnel> getL2Tunnels();
-
- /**
- * Returns a copy of the pending l2 policies that exist in the store.
- *
- * @return The l2 policies
- */
- List<L2TunnelPolicy> getL2PendingPolicies();
-
- /**
- * Helper function to handle the pw removal.
- * <p>
- * This method should for the mastership of the device because it is
- * used only from network configuration updates, thus we only want
- * one instance only to program each pseudowire.
- *
- * @param pwToRemove the pseudo wires to remove
- * @deprecated onos-1.12 Do not use this method.
- */
- @Deprecated
- void tearDown(Set<L2TunnelDescription> pwToRemove);
-
- /**
- * Returns a copy of the pending l2 tunnels that exist in the store.
- *
- * @return The l2 tunnels.
- */
- List<L2Tunnel> getL2PendingTunnels();
-
- /**
- * Verifies global validity for existing pseudowires, both ones in
- * the pending store and the ones installed.
- *
- * @param pwToAdd the new pseudowire to add
- * @return a Result describing the outcome
- */
- Result verifyGlobalValidity(L2TunnelDescription pwToAdd);
-
- /**
- * Check if pseudowire exists in the store.
- *
- * @param tunnelId The tunnel id to check for.
- * @param pending Check in pending store for pseudowires.
- * @return The result of the operation.
- */
- Result checkIfPwExists(long tunnelId, boolean pending);
-
- /**
- * Returns the PW init next objective store.
- *
- * @return current contents of the l2InitiationNextObjStore
- */
- ImmutableMap<String, NextObjective> getInitNext();
-
- /**
- * Returns the PW termination next objective store.
- *
- * @return current contents of the l2TerminationNextObjStore
- */
- ImmutableMap<String, NextObjective> getTermNext();
-
- /**
- * Removes given next ID from both PW init/term next obj store.
- *
- * @param nextId next ID
- */
- void removeNextId(int nextId);
-
- /**
- * Pwaas pipelines.
- */
- enum Pipeline {
- /**
- * The initiation pipeline.
- */
- INITIATION, /**
- * The termination pipeline.
- */
- TERMINATION
- }
-
- /**
- * Enum helper to carry results of various operations.
- */
- enum Result {
- /**
- * Happy ending scenario.
- */
- SUCCESS(0, "No error occurred"),
-
- /**
- * We have problems with the supplied parameters.
- */
- WRONG_PARAMETERS(1, "Wrong parameters"),
-
- /**
- * We have an internal error during the deployment
- * or removal phase.
- */
- INTERNAL_ERROR(3, "Internal error"),
-
- /**
- * No path found between the connection points.
- */
- PATH_NOT_FOUND(7, "Could not find valid path between connection points!"),
-
- /**
- * Error in global pseudowires configuration.
- */
- CONFIGURATION_ERROR(8, "Conflicting pseudowire configurations!");
-
- private final int code;
- private final String description;
-
- private String specificError;
- private int nextId;
-
- Result(int code, String description) {
- this.code = code;
- this.description = description;
- }
-
- public Result appendError(String error) {
- this.specificError = error;
- return this;
- }
-
- public String getSpecificError() {
- return specificError;
- }
-
- public String getDescription() {
- return description;
- }
-
- public int getNextId() {
- return nextId;
- }
-
- protected void setNextId(int nextId) {
- this.nextId = nextId;
- }
-
- @Override
- public String toString() {
- return code + ": " + description;
- }
- }
-
- /**
- * Enum helper for handling the direction of the pw.
- */
- enum Direction {
- /**
- * The forward direction of the pseudo wire.
- */
- FWD, /**
- * The reverse direction of the pseudo wire.
- */
- REV
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelPolicy.java b/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelPolicy.java
deleted file mode 100644
index 17be45b..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelPolicy.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2016-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.pwaas;
-
-import org.onlab.packet.VlanId;
-import org.onosproject.net.ConnectPoint;
-
-public interface L2TunnelPolicy {
-
- /**
- * Returns the first connect point of the policy.
- *
- * @return first connect point
- */
- ConnectPoint cP1();
-
- /**
- * Returns the second connect point of the policy.
- *
- * @return second connect point
- */
- ConnectPoint cP2();
-
- /**
- * Returns the cP1 inner vlan tag of the policy.
- *
- * @return cP1 inner vlan tag
- */
- VlanId cP1InnerTag();
-
- /**
- * Returns the cP1 outer vlan tag of the policy.
- *
- * @return cP1 outer vlan tag
- */
- VlanId cP1OuterTag();
-
- /**
- * Returns the cP2 inner vlan tag of the policy.
- *
- * @return cP2 inner vlan tag
- */
- VlanId cP2InnerTag();
-
- /**
- * Returns the cP2 outer vlan tag of the policy.
- *
- * @return cP2 outer vlan tag
- */
- VlanId cP2OuterTag();
-
- /**
- * Returns the tunnel ID of the policy.
- *
- * @return Tunnel ID
- */
- long tunnelId();
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/pwaas/PwaasUtil.java b/app/src/main/java/org/onosproject/segmentrouting/pwaas/PwaasUtil.java
deleted file mode 100644
index 7cb60a6..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/pwaas/PwaasUtil.java
+++ /dev/null
@@ -1,482 +0,0 @@
-/*
- * Copyright 2015-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.pwaas;
-
-import org.onlab.osgi.ServiceNotFoundException;
-import org.onlab.packet.MplsLabel;
-import org.onlab.packet.VlanId;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.net.ConnectPoint;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.intf.InterfaceService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import static com.google.common.base.Preconditions.checkArgument;
-
-/**
- * Utility class with static methods that help
- * parse pseudowire related information and also
- * verify that a pseudowire combination is valid.
- */
-public final class PwaasUtil {
-
- private static final Logger log = LoggerFactory.getLogger(PwaasUtil.class);
-
- private static DeviceService deviceService;
- private static InterfaceService intfService;
-
- // Suppress ExceptionInInitializerError and simply set the value to null,
- // such that unit tests have a chance to replace the variable with mocked service
- static {
- try {
- deviceService = AbstractShellCommand.get(DeviceService.class);
- } catch (NullPointerException | ServiceNotFoundException e) {
- deviceService = null;
- }
- try {
- intfService = AbstractShellCommand.get(InterfaceService.class);
- } catch (NullPointerException | ServiceNotFoundException e) {
- intfService = null;
- }
- }
-
- static final String ERR_SERVICE_UNAVAIL = "Service %s not available";
- static final String ERR_SAME_DEV =
- "Pseudowire connection points can not reside in the same node, in pseudowire %d.";
- static final String ERR_EMPTY_INNER_WHEN_OUTER_PRESENT =
- "Inner tag should not be empty when outer tag is set for pseudowire %d for %s.";
- static final String ERR_WILDCARD_VLAN =
- "Wildcard VLAN matching not yet supported for pseudowire %d.";
- static final String ERR_DOUBLE_TO_UNTAGGED =
- "Support for double tag <-> untag is not supported for pseudowire %d.";
- static final String ERR_DOUBLE_TO_SINGLE =
- "Support for double-tag<-> single-tag is not supported for pseudowire %d.";
- static final String ERR_SINGLE_TO_UNTAGGED =
- "single-tag <-> untag is not supported for pseudowire %d.";
- static final String ERR_VLAN_TRANSLATION =
- "We do not support VLAN translation for pseudowire %d.";
- static final String ERR_DEV_NOT_FOUND =
- "Device %s does not exist for pseudowire %d.";
- static final String ERR_PORT_NOT_FOUND =
- "Port %s of device %s does not exist for pseudowire %d.";
-
- private PwaasUtil() {
-
- }
-
- /**
- * Parses a vlan as a string. Returns the VlanId if
- * provided String can be parsed as an integer or is '' / '*'
- *
- * @param vlan string as read from configuration
- * @return VlanId null if error
- */
- public static VlanId parseVlan(String vlan) {
-
- if (vlan.equals("*") || vlan.equals("Any")) {
- return VlanId.vlanId("Any");
- } else if (vlan.equals("") || vlan.equals("None")) {
- return VlanId.vlanId("None");
- } else {
- return VlanId.vlanId(vlan);
- }
- }
-
- /**
- *
- * @param mode RAW or TAGGED
- * @return the L2Mode if input is correct
- */
- public static L2Mode parseMode(String mode) {
- checkArgument(mode.equals("RAW") || mode.equals("TAGGED"),
- "Invalid pseudowire mode of operation, should be TAGGED or RAW.");
- return L2Mode.valueOf(mode);
- }
-
- /**
- *
- * @param label the mpls label of the pseudowire
- * @return the MplsLabel
- * @throws IllegalArgumentException if label is invalid
- */
- public static MplsLabel parsePWLabel(String label) {
- return MplsLabel.mplsLabel(label);
- }
-
- /**
- * Parses a string as a pseudowire id - which is an integer.
- *
- * @param id The id of pw in string form
- * @return The id of pw as an Integer or null if it failed the conversion.
- */
- public static Integer parsePwId(String id) {
- return Integer.parseInt(id);
- }
-
- /**
- * Helper method to verify if the tunnel is whether or not
- * supported.
- *
- * @param l2Tunnel the tunnel to verify
- */
- private static void verifyTunnel(L2Tunnel l2Tunnel) {
-
- // Service delimiting tag not supported yet.
- if (!l2Tunnel.sdTag().equals(VlanId.NONE)) {
- throw new IllegalArgumentException(String.format("Service delimiting tag not supported yet for " +
- "pseudowire %d.", l2Tunnel.tunnelId()));
- }
-
- // Tag mode not supported yet.
- if (l2Tunnel.pwMode() == L2Mode.TAGGED) {
- throw new IllegalArgumentException(String.format("Tagged mode not supported yet for pseudowire %d.",
- l2Tunnel.tunnelId()));
- }
-
- // Raw mode without service delimiting tag
- // is the only mode supported for now.
- }
-
- /**
- * Helper method to verify if the policy is whether or not
- * supported and if policy will be successfully instantiated in the
- * network.
- *
- * @param cP1 pseudo wire endpoint 1
- * @param cP2 pseudo wire endpoint 2
- * @param ingressInner the ingress inner tag
- * @param ingressOuter the ingress outer tag
- * @param egressInner the egress inner tag
- * @param egressOuter the egress outer tag
- * @param tunnelId tunnel ID
- */
- static void verifyPolicy(ConnectPoint cP1,
- ConnectPoint cP2,
- VlanId ingressInner,
- VlanId ingressOuter,
- VlanId egressInner,
- VlanId egressOuter,
- Long tunnelId) {
-
- if (cP1.deviceId().equals(cP2.deviceId())) {
- throw new IllegalArgumentException(String.format(ERR_SAME_DEV, tunnelId));
- }
-
- // We can have multiple tags, all of them can be NONE,
- // indicating untagged traffic, however, the outer tag can
- // not have value if the inner tag is None
- if (ingressInner.equals(VlanId.NONE) && !ingressOuter.equals(VlanId.NONE)) {
- throw new IllegalArgumentException(String.format(ERR_EMPTY_INNER_WHEN_OUTER_PRESENT,
- tunnelId, "cp1"));
- }
-
- if (egressInner.equals(VlanId.NONE) && !egressOuter.equals(VlanId.NONE)) {
- throw new IllegalArgumentException(String.format(ERR_EMPTY_INNER_WHEN_OUTER_PRESENT,
- tunnelId, "cp2"));
- }
-
- if (ingressInner.equals(VlanId.ANY) ||
- ingressOuter.equals(VlanId.ANY) ||
- egressInner.equals(VlanId.ANY) ||
- egressOuter.equals(VlanId.ANY)) {
- throw new IllegalArgumentException(String.format(ERR_WILDCARD_VLAN, tunnelId));
- }
-
- if (((!ingressOuter.equals(VlanId.NONE) && !ingressInner.equals(VlanId.NONE)) &&
- (egressOuter.equals(VlanId.NONE) && egressInner.equals(VlanId.NONE)))
- || ((ingressOuter.equals(VlanId.NONE) && ingressInner.equals(VlanId.NONE)) &&
- (!egressOuter.equals(VlanId.NONE) && !egressInner.equals(VlanId.NONE)))) {
- throw new IllegalArgumentException(String.format(ERR_DOUBLE_TO_UNTAGGED, tunnelId));
- }
- if ((!ingressInner.equals(VlanId.NONE) &&
- ingressOuter.equals(VlanId.NONE) &&
- !egressOuter.equals(VlanId.NONE))
- || (egressOuter.equals(VlanId.NONE) &&
- !egressInner.equals(VlanId.NONE) &&
- !ingressOuter.equals(VlanId.NONE))) {
- throw new IllegalArgumentException(String.format(ERR_DOUBLE_TO_SINGLE, tunnelId));
- }
-
- if ((ingressInner.equals(VlanId.NONE) && !egressInner.equals(VlanId.NONE))
- || (!ingressInner.equals(VlanId.NONE) && egressInner.equals(VlanId.NONE))) {
- throw new IllegalArgumentException(String.format(ERR_SINGLE_TO_UNTAGGED, tunnelId));
- }
-
- // FIXME PW VLAN translation is not supported on Dune
- // Need to explore doing that in egress table later if there is a requirement
- if (!ingressInner.equals(egressInner) || !ingressOuter.equals(egressOuter)) {
- throw new IllegalArgumentException(String.format(ERR_VLAN_TRANSLATION, tunnelId));
- }
-
- if (deviceService == null) {
- throw new IllegalStateException(String.format(ERR_SERVICE_UNAVAIL, "DeviceService"));
- }
-
- // check if cp1 and port of cp1 exist
- if (deviceService.getDevice(cP1.deviceId()) == null) {
- throw new IllegalArgumentException(String.format(ERR_DEV_NOT_FOUND, cP1.deviceId(), tunnelId));
- }
-
- if (deviceService.getPort(cP1) == null) {
- throw new IllegalArgumentException(String.format(ERR_PORT_NOT_FOUND, cP1.port(),
- cP1.deviceId(), tunnelId));
- }
-
- // check if cp2 and port of cp2 exist
- if (deviceService.getDevice(cP2.deviceId()) == null) {
- throw new IllegalArgumentException(String.format(ERR_DEV_NOT_FOUND, cP2.deviceId(), tunnelId));
- }
-
- if (deviceService.getPort(cP2) == null) {
- throw new IllegalArgumentException(String.format(ERR_PORT_NOT_FOUND, cP2.port(),
- cP2.deviceId(), tunnelId));
- }
- }
-
- /**
- * Verifies that the pseudowires will not conflict with each other.
- *
- * Further, check if vlans for connect points are already used.
- *
- * @param tunnel Tunnel for pw
- * @param policy Policy for pw
- * @param labelSet Label set used so far with this configuration
- * @param vlanSet Vlan set used with this configuration
- * @param tunnelSet Tunnel set used with this configuration
- */
- private static void verifyGlobalValidity(L2Tunnel tunnel,
- L2TunnelPolicy policy,
- Set<MplsLabel> labelSet,
- Map<ConnectPoint, Set<VlanId>> vlanSet,
- Set<Long> tunnelSet) {
-
- if (tunnelSet.contains(tunnel.tunnelId())) {
- throw new IllegalArgumentException(String.valueOf(String.format("Tunnel Id %d already used by" +
- " another pseudowire, in " +
- "pseudowire %d!",
- tunnel.tunnelId(),
- tunnel.tunnelId())));
- }
- tunnelSet.add(tunnel.tunnelId());
-
- // check if tunnel id is used again
- ConnectPoint cP1 = policy.cP1();
- ConnectPoint cP2 = policy.cP2();
-
- // insert cps to hashmap if this is the first time seen
- if (!vlanSet.containsKey(cP1)) {
- vlanSet.put(cP1, new HashSet<VlanId>());
- }
- if (!vlanSet.containsKey(cP2)) {
- vlanSet.put(cP2, new HashSet<VlanId>());
- }
-
- // if single tagged or untagged vlan is the inner
- // if double tagged vlan is the outer
- VlanId vlanToCheckCP1;
- if (policy.cP1OuterTag().equals(VlanId.NONE)) {
- vlanToCheckCP1 = policy.cP1InnerTag();
- } else {
- vlanToCheckCP1 = policy.cP1OuterTag();
- }
-
- VlanId vlanToCheckCP2;
- if (policy.cP2OuterTag().equals(VlanId.NONE)) {
- vlanToCheckCP2 = policy.cP2InnerTag();
- } else {
- vlanToCheckCP2 = policy.cP2OuterTag();
- }
-
- if (labelSet.contains(tunnel.pwLabel())) {
- throw new IllegalArgumentException(String.valueOf(String.format("Label %s already used by another" +
- " pseudowire, in pseudowire %d!",
- tunnel.pwLabel(), tunnel.tunnelId())));
- }
- labelSet.add(tunnel.pwLabel());
-
- if (vlanSet.get(cP1).contains(vlanToCheckCP1)) {
- throw new IllegalArgumentException(String.valueOf(String.format("Vlan '%s' for cP1 %s already used " +
- "by another pseudowire, in " +
- "pseudowire" +
- " %d!", vlanToCheckCP1, cP1,
- tunnel.tunnelId())));
- }
- vlanSet.get(cP1).add(vlanToCheckCP1);
-
- if (vlanSet.get(cP2).contains(vlanToCheckCP2)) {
- throw new IllegalArgumentException(String.valueOf(String.format("Vlan '%s' for cP2 %s already used" +
- " by another pseudowire, in" +
- " pseudowire %d!", vlanToCheckCP2,
- cP2,
- tunnel.tunnelId())));
- }
- vlanSet.get(cP2).add(vlanToCheckCP2);
-
- if (intfService == null) {
- throw new IllegalStateException(String.format(ERR_SERVICE_UNAVAIL, "InterfaceService"));
- }
-
- // check that vlans for the connect points are not used
- intfService.getInterfacesByPort(cP1).stream()
- .forEach(intf -> {
-
- // check if tagged pw affects tagged interface
- if (intf.vlanTagged().contains(vlanToCheckCP1)) {
- throw new IllegalArgumentException(String.valueOf(String.format("Vlan '%s' for cP1 %s already" +
- " used for this" +
- " interface, in" +
- " pseudowire %d!",
- vlanToCheckCP1, cP1,
- tunnel.tunnelId())));
- }
-
- // if vlanNative != null this interface is configured with untagged traffic also
- // check if it collides with untagged interface
- if ((intf.vlanNative() != null) && vlanToCheckCP1.equals(VlanId.NONE)) {
- throw new IllegalArgumentException(String.valueOf(String.format("Untagged traffic for cP1 " +
- "%s already used " +
- "for this " +
- "interface, in " +
- "pseudowire " +
- "%d!", cP1,
- tunnel.tunnelId())));
- }
-
- // if vlanUntagged != null this interface is configured only with untagged traffic
- // check if it collides with untagged interface
- if ((intf.vlanUntagged() != null) && vlanToCheckCP1.equals(VlanId.NONE)) {
- throw new IllegalArgumentException(String.valueOf(String.format("Untagged traffic for " +
- "cP1 %s already" +
- " used for this" +
- " interface," +
- " in pseudowire %d!",
- cP1, tunnel.tunnelId())));
- }
- });
-
- intfService.getInterfacesByPort(cP2).stream()
- .forEach(intf -> {
- if (intf.vlanTagged().contains(vlanToCheckCP2)) {
- throw new IllegalArgumentException(String.valueOf(String.format("Vlan '%s' for cP2 %s " +
- " used for " +
- "this interface, " +
- "in pseudowire %d!",
- vlanToCheckCP2, cP2,
- tunnel.tunnelId())));
- }
-
- // if vlanNative != null this interface is configured with untagged traffic also
- // check if it collides with untagged interface
- if ((intf.vlanNative() != null) && vlanToCheckCP2.equals(VlanId.NONE)) {
- throw new IllegalArgumentException(String.valueOf(String.format("Untagged traffic " +
- "for cP2 %s " +
- "already " +
- "used for this" +
- " interface, " +
- "in pseudowire %d!",
- cP2, tunnel.tunnelId())));
- }
-
- // if vlanUntagged != null this interface is configured only with untagged traffic
- // check if it collides with untagged interface
- if ((intf.vlanUntagged() != null) && vlanToCheckCP2.equals(VlanId.NONE)) {
- throw new IllegalArgumentException(String.valueOf(String.format("Untagged traffic for cP2 %s" +
- " already" +
- " used for " +
- "this interface, " +
- "in pseudowire %d!",
- cP2, tunnel.tunnelId())));
- }
- });
-
- }
-
- /**
- * Helper method to verify the integrity of the pseudo wire.
- *
- * @param l2TunnelDescription the pseudo wire description
- */
- private static void verifyPseudoWire(L2TunnelDescription l2TunnelDescription,
- Set<MplsLabel> labelSet,
- Map<ConnectPoint, Set<VlanId>> vlanset,
- Set<Long> tunnelSet) {
-
- L2Tunnel l2Tunnel = l2TunnelDescription.l2Tunnel();
- L2TunnelPolicy l2TunnelPolicy = l2TunnelDescription.l2TunnelPolicy();
-
- verifyTunnel(l2Tunnel);
-
- verifyPolicy(
- l2TunnelPolicy.cP1(),
- l2TunnelPolicy.cP2(),
- l2TunnelPolicy.cP1InnerTag(),
- l2TunnelPolicy.cP1OuterTag(),
- l2TunnelPolicy.cP2InnerTag(),
- l2TunnelPolicy.cP2OuterTag(),
- l2Tunnel.tunnelId()
- );
-
- verifyGlobalValidity(l2Tunnel,
- l2TunnelPolicy,
- labelSet,
- vlanset,
- tunnelSet);
-
- }
-
- public static L2TunnelHandler.Result configurationValidity(List<L2TunnelDescription> pseudowires) {
-
- // structures to keep pw information
- // in order to see if instantiating them will create
- // problems
- Set<Long> tunIds = new HashSet<>();
- Set<MplsLabel> labelsUsed = new HashSet<>();
- Map<ConnectPoint, Set<VlanId>> vlanIds = new HashMap<>();
-
- // TODO : I know we should not use exceptions for flow control,
- // however this code was originally implemented in the configuration
- // addition where the exceptions were propagated and the configuration was
- // deemed not valid. I plan in the future to refactor the parts that
- // check the pseudowire validity.
- //
- // Ideally we would like to return a String which could also return to
- // the user issuing the rest request for adding the pseudowire.
- try {
- // check that pseudowires can be instantiated in the network
- // we try to guarantee that all the pws will work before
- // instantiating any of them
- for (L2TunnelDescription pw : pseudowires) {
- log.debug("Verifying pseudowire {}", pw);
- verifyPseudoWire(pw, labelsUsed, vlanIds, tunIds);
- }
-
- return L2TunnelHandler.Result.SUCCESS;
- } catch (Exception e) {
- log.error("Caught exception while validating pseudowire : {}", e.getMessage());
- return L2TunnelHandler.Result.CONFIGURATION_ERROR
- .appendError(e.getMessage());
- }
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/pwaas/package-info.java b/app/src/main/java/org/onosproject/segmentrouting/pwaas/package-info.java
deleted file mode 100644
index 463b163..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/pwaas/package-info.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2016-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.
- */
-
-/**
- * Set of resources implementing the Pwaas.
- */
-package org.onosproject.segmentrouting.pwaas;
\ No newline at end of file
diff --git a/app/src/main/java/org/onosproject/segmentrouting/storekey/DestinationSetNextObjectiveStoreKey.java b/app/src/main/java/org/onosproject/segmentrouting/storekey/DestinationSetNextObjectiveStoreKey.java
deleted file mode 100644
index 0baa769..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/storekey/DestinationSetNextObjectiveStoreKey.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2016-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/licedses/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.storekey;
-
-import java.util.Objects;
-
-import org.onosproject.net.DeviceId;
-import org.onosproject.segmentrouting.grouphandler.DestinationSet;
-
-import static com.google.common.base.MoreObjects.toStringHelper;
-
-/**
- * Key of Destination set next objective store.
- */
-public class DestinationSetNextObjectiveStoreKey {
- private final DeviceId deviceId;
- private final DestinationSet ds;
-
- /**
- * Constructs the key of destination set next objective store.
- *
- * @param deviceId device ID
- * @param ds destination set
- */
- public DestinationSetNextObjectiveStoreKey(DeviceId deviceId,
- DestinationSet ds) {
- this.deviceId = deviceId;
- this.ds = ds;
- }
-
- /**
- * Returns the device ID in the key.
- *
- * @return device ID
- */
- public DeviceId deviceId() {
- return this.deviceId;
- }
-
- /**
- * Returns the destination set in the key.
- *
- * @return destination set
- */
- public DestinationSet destinationSet() {
- return this.ds;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (!(o instanceof DestinationSetNextObjectiveStoreKey)) {
- return false;
- }
- DestinationSetNextObjectiveStoreKey that =
- (DestinationSetNextObjectiveStoreKey) o;
- return (Objects.equals(this.deviceId, that.deviceId) &&
- Objects.equals(this.ds, that.ds));
- }
-
- // The list of destination ids and label are used for comparison.
- @Override
- public int hashCode() {
- int result = 17;
- result = 31 * result + Objects.hashCode(this.deviceId)
- + Objects.hashCode(this.ds);
-
- return result;
- }
-
- @Override
- public String toString() {
- return toStringHelper(getClass())
- .add("deviceId", deviceId)
- .add("ds", ds)
- .toString();
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/storekey/MacVlanNextObjectiveStoreKey.java b/app/src/main/java/org/onosproject/segmentrouting/storekey/MacVlanNextObjectiveStoreKey.java
deleted file mode 100644
index 4a1ab78..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/storekey/MacVlanNextObjectiveStoreKey.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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.storekey;
-
-import org.onlab.packet.VlanId;
-import org.onlab.packet.MacAddress;
-import org.onosproject.net.DeviceId;
-
-import java.util.Objects;
-
-import static com.google.common.base.MoreObjects.toStringHelper;
-
-/**
- * Key of Device/Vlan/MacAddr to NextObjective store.
- */
-public class MacVlanNextObjectiveStoreKey {
- private final DeviceId deviceId;
- private final MacAddress macAddr;
- private final VlanId vlanId;
-
- /**
- * Constructs the key of the next objective store.
- *
- * @param deviceId device ID
- * @param macAddr mac of host
- * @param vlanId vlan of host
- */
- public MacVlanNextObjectiveStoreKey(DeviceId deviceId, MacAddress macAddr, VlanId vlanId) {
- this.deviceId = deviceId;
- this.macAddr = macAddr;
- this.vlanId = vlanId;
- }
-
- /**
- * Gets device id in this MacVlanNextObjectiveStoreKey.
- *
- * @return device id
- */
- public DeviceId deviceId() {
- return deviceId;
- }
-
- /**
- * Gets vlan information in this MacVlanNextObjectiveStoreKey.
- *
- * @return vlan information
- */
- public VlanId vlanId() {
- return vlanId;
- }
-
- /**
- * Gets mac information in this MacVlanNextObjectiveStoreKey.
- *
- * @return mac information
- */
- public MacAddress macAddr() {
- return macAddr;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (!(o instanceof MacVlanNextObjectiveStoreKey)) {
- return false;
- }
- MacVlanNextObjectiveStoreKey that =
- (MacVlanNextObjectiveStoreKey) o;
- return (Objects.equals(this.deviceId, that.deviceId) &&
- Objects.equals(this.vlanId, that.vlanId) &&
- Objects.equals(this.macAddr, that.macAddr));
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(deviceId, vlanId, macAddr);
- }
-
- @Override
- public String toString() {
- return toStringHelper(getClass())
- .add("deviceId", deviceId)
- .add("vlanId", vlanId)
- .add("macAddr", macAddr)
- .toString();
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/storekey/PortNextObjectiveStoreKey.java b/app/src/main/java/org/onosproject/segmentrouting/storekey/PortNextObjectiveStoreKey.java
deleted file mode 100644
index 1269bce..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/storekey/PortNextObjectiveStoreKey.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright 2016-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.storekey;
-
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.flow.TrafficSelector;
-import org.onosproject.net.flow.TrafficTreatment;
-
-import java.util.Objects;
-
-import static com.google.common.base.MoreObjects.toStringHelper;
-
-/**
- * Key of Device/Port to NextObjective store.
- *
- * Since there can be multiple next objectives to the same physical port,
- * we differentiate between them by including the treatment in the key.
- */
-public class PortNextObjectiveStoreKey {
- private final DeviceId deviceId;
- private final PortNumber portNum;
- private final TrafficTreatment treatment;
- private final TrafficSelector meta;
-
- /**
- * Constructs the key of port next objective store.
- *
- * @param deviceId device ID
- * @param portNum port number
- * @param treatment treatment that will be applied to the interface
- * @param meta optional data to pass to the driver
- */
- public PortNextObjectiveStoreKey(DeviceId deviceId, PortNumber portNum,
- TrafficTreatment treatment,
- TrafficSelector meta) {
- this.deviceId = deviceId;
- this.portNum = portNum;
- this.treatment = treatment;
- this.meta = meta;
- }
-
- /**
- * Gets device id in this PortNextObjectiveStoreKey.
- *
- * @return device id
- */
- public DeviceId deviceId() {
- return deviceId;
- }
-
- /**
- * Gets port information in this PortNextObjectiveStoreKey.
- *
- * @return port information
- */
- public PortNumber portNumber() {
- return portNum;
- }
-
- /**
- * Gets treatment information in this PortNextObjectiveStoreKey.
- *
- * @return treatment information
- */
- public TrafficTreatment treatment() {
- return treatment;
- }
-
- /**
- * Gets metadata information in this PortNextObjectiveStoreKey.
- *
- * @return meta information
- */
- public TrafficSelector meta() {
- return meta;
- }
-
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (!(o instanceof PortNextObjectiveStoreKey)) {
- return false;
- }
- PortNextObjectiveStoreKey that =
- (PortNextObjectiveStoreKey) o;
- return (Objects.equals(this.deviceId, that.deviceId) &&
- Objects.equals(this.portNum, that.portNum) &&
- Objects.equals(this.treatment, that.treatment) &&
- Objects.equals(this.meta, that.meta));
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(deviceId, portNum, treatment, meta);
- }
-
- @Override
- public String toString() {
- return toStringHelper(getClass())
- .add("deviceId", deviceId)
- .add("portNum", portNum)
- .add("treatment", treatment)
- .add("meta", meta)
- .toString();
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/storekey/VlanNextObjectiveStoreKey.java b/app/src/main/java/org/onosproject/segmentrouting/storekey/VlanNextObjectiveStoreKey.java
deleted file mode 100644
index 55a95cd..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/storekey/VlanNextObjectiveStoreKey.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2016-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.storekey;
-
-import org.onlab.packet.VlanId;
-import org.onosproject.net.DeviceId;
-
-import java.util.Objects;
-
-import static com.google.common.base.MoreObjects.toStringHelper;
-
-/**
- * Key of VLAN to NextObjective store.
- */
-public class VlanNextObjectiveStoreKey {
- private final DeviceId deviceId;
- private final VlanId vlanId;
-
- /**
- * Constructs the key of VLAN next objective store.
- *
- * @param deviceId device ID
- * @param vlanId VLAN information
- */
- public VlanNextObjectiveStoreKey(DeviceId deviceId,
- VlanId vlanId) {
- this.deviceId = deviceId;
- this.vlanId = vlanId;
- }
-
- /**
- * Gets device id in this VlanNextObjectiveStoreKey.
- *
- * @return device id
- */
- public DeviceId deviceId() {
- return this.deviceId;
- }
-
- /**
- * Gets vlan information in this VlanNextObjectiveStoreKey.
- *
- * @return vlan id
- */
- public VlanId vlanId() {
- return this.vlanId;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (!(o instanceof VlanNextObjectiveStoreKey)) {
- return false;
- }
- VlanNextObjectiveStoreKey that =
- (VlanNextObjectiveStoreKey) o;
- return (Objects.equals(this.deviceId, that.deviceId) &&
- Objects.equals(this.vlanId, that.vlanId));
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(deviceId, vlanId);
- }
-
- @Override
- public String toString() {
- return toStringHelper(getClass())
- .add("deviceId", deviceId)
- .add("vlanId", vlanId)
- .toString();
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/storekey/XConnectStoreKey.java b/app/src/main/java/org/onosproject/segmentrouting/storekey/XConnectStoreKey.java
deleted file mode 100644
index 0e90a22..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/storekey/XConnectStoreKey.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright 2016-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.storekey;
-
-import org.onlab.packet.VlanId;
-import org.onosproject.net.DeviceId;
-
-import java.util.Objects;
-
-/**
- * Key of VLAN cross-connect next objective store.
- */
-public class XConnectStoreKey {
- private final DeviceId deviceId;
- private final VlanId vlanId;
-
- /**
- * Constructs the key of cross-connect next objective store.
- *
- * @param deviceId device ID of the VLAN cross-connection
- * @param vlanId VLAN ID of the VLAN cross-connection
- */
- public XConnectStoreKey(DeviceId deviceId, VlanId vlanId) {
- this.deviceId = deviceId;
- this.vlanId = vlanId;
- }
-
- /**
- * Returns the device ID of this key.
- *
- * @return device ID
- */
- public DeviceId deviceId() {
- return this.deviceId;
- }
-
- /**
- * Returns the VLAN ID of this key.
- *
- * @return VLAN ID
- */
- public VlanId vlanId() {
- return this.vlanId;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (!(o instanceof XConnectStoreKey)) {
- return false;
- }
- XConnectStoreKey that =
- (XConnectStoreKey) o;
- return (Objects.equals(this.deviceId, that.deviceId) &&
- Objects.equals(this.vlanId, that.vlanId));
- }
-
- // The list of neighbor ids and label are used for comparison.
- @Override
- public int hashCode() {
- return Objects.hash(deviceId, vlanId);
- }
-
- @Override
- public String toString() {
- return "Device: " + deviceId + " VlanId: " + vlanId;
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/storekey/package-info.java b/app/src/main/java/org/onosproject/segmentrouting/storekey/package-info.java
deleted file mode 100644
index 44fc6a7..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/storekey/package-info.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2016-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.
- */
-
-/**
- * Key data structure of various stores used by Segment Routing.
- */
-package org.onosproject.segmentrouting.storekey;
\ No newline at end of file
diff --git a/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectCodec.java b/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectCodec.java
deleted file mode 100644
index 83421bc..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectCodec.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2018-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 com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.node.ArrayNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import com.google.common.collect.Sets;
-import org.onlab.packet.VlanId;
-import org.onosproject.codec.CodecContext;
-import org.onosproject.codec.JsonCodec;
-import org.onosproject.net.DeviceId;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.Set;
-
-/**
- * Codec for Xconnect.
- */
-public class XconnectCodec extends JsonCodec<XconnectDesc> {
- static final String DEVICE_ID = "deviceId";
- static final String VLAN_ID = "vlanId";
- static final String ENDPOINTS = "endpoints";
-
- private static Logger log = LoggerFactory.getLogger(XconnectCodec.class);
-
- @Override
- public ObjectNode encode(XconnectDesc desc, CodecContext context) {
- final ObjectNode result = context.mapper().createObjectNode();
- result.put(DEVICE_ID, desc.key().deviceId().toString());
- result.put(VLAN_ID, desc.key().vlanId().toShort());
- final ArrayNode portNode = result.putArray(ENDPOINTS);
- desc.endpoints().forEach(endpoint -> portNode.add(endpoint.toString()));
-
- return result;
- }
-
- @Override
- public XconnectDesc decode(ObjectNode json, CodecContext context) {
- DeviceId deviceId = DeviceId.deviceId(json.path(DEVICE_ID).asText());
- VlanId vlanId = VlanId.vlanId(json.path(VLAN_ID).asText());
-
- Set<XconnectEndpoint> endpoints = Sets.newHashSet();
- JsonNode endpointNodes = json.get(ENDPOINTS);
- if (endpointNodes != null) {
- endpointNodes.forEach(endpointNode -> endpoints.add(XconnectEndpoint.fromString(endpointNode.asText())));
- }
-
- XconnectKey key = new XconnectKey(deviceId, vlanId);
- return new XconnectDesc(key, endpoints);
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectDesc.java b/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectDesc.java
deleted file mode 100644
index a47823a..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectDesc.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright 2018-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 com.google.common.base.MoreObjects;
-
-import java.util.Objects;
-import java.util.Set;
-
-/**
- * Xconnect description.
- */
-public class XconnectDesc {
- private XconnectKey key;
- private Set<XconnectEndpoint> endpoints;
-
- /**
- * Constructs new Xconnect description with given device ID and VLAN ID.
- *
- * @param key Xconnect key
- * @param endpoints set of endpoints
- */
- public XconnectDesc(XconnectKey key, Set<XconnectEndpoint> endpoints) {
- this.key = key;
- this.endpoints = endpoints;
- }
-
- /**
- * Gets Xconnect key.
- *
- * @return Xconnect key
- */
- public XconnectKey key() {
- return key;
- }
-
- /**
- * Gets endpoints.
- *
- * @return set of endpoints
- */
- public Set<XconnectEndpoint> endpoints() {
- return endpoints;
- }
-
- @Override
- public boolean equals(final Object obj) {
- if (this == obj) {
- return true;
- }
- if (!(obj instanceof XconnectDesc)) {
- return false;
- }
- final XconnectDesc other = (XconnectDesc) obj;
- return Objects.equals(this.key, other.key) &&
- Objects.equals(this.endpoints, other.endpoints);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(key, endpoints);
- }
-
- @Override
- public String toString() {
- return MoreObjects.toStringHelper(getClass())
- .add("key", key)
- .add("endpoints", endpoints)
- .toString();
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectEndpoint.java b/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectEndpoint.java
deleted file mode 100644
index c7a2242..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectEndpoint.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectKey.java b/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectKey.java
deleted file mode 100644
index 7d433cd..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectKey.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2018-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 com.google.common.base.MoreObjects;
-import org.onlab.packet.VlanId;
-import org.onosproject.net.DeviceId;
-
-import java.util.Objects;
-
-/**
- * Xconnect key.
- */
-public class XconnectKey {
- private DeviceId deviceId;
- private VlanId vlanId;
-
- /**
- * Constructs new XconnectKey with given device ID and VLAN ID.
- *
- * @param deviceId device ID
- * @param vlanId vlan ID
- */
- public XconnectKey(DeviceId deviceId, VlanId vlanId) {
- this.deviceId = deviceId;
- this.vlanId = vlanId;
- }
-
- /**
- * Gets device ID.
- *
- * @return device ID of the Xconnect key
- */
- public DeviceId deviceId() {
- return deviceId;
- }
-
- /**
- * Gets VLAN ID.
- *
- * @return VLAN ID of the Xconnect key
- */
- public VlanId vlanId() {
- return vlanId;
- }
-
- @Override
- public boolean equals(final Object obj) {
- if (this == obj) {
- return true;
- }
- if (!(obj instanceof XconnectKey)) {
- return false;
- }
- final XconnectKey other = (XconnectKey) obj;
- return Objects.equals(this.deviceId, other.deviceId) &&
- Objects.equals(this.vlanId, other.vlanId);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(deviceId, vlanId);
- }
-
- @Override
- public String toString() {
- return MoreObjects.toStringHelper(getClass())
- .add("deviceId", deviceId)
- .add("vlanId", vlanId)
- .toString();
- }
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectLoadBalancerEndpoint.java b/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectLoadBalancerEndpoint.java
deleted file mode 100644
index 4172292..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectLoadBalancerEndpoint.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectPortEndpoint.java b/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectPortEndpoint.java
deleted file mode 100644
index f26eaf0..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectPortEndpoint.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectService.java b/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectService.java
deleted file mode 100644
index 2fe6488..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/XconnectService.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright 2018-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 com.google.common.collect.ImmutableMap;
-import org.onlab.packet.VlanId;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.PortNumber;
-
-import java.util.List;
-import java.util.Set;
-
-/**
- * VLAN cross connect between exactly two ports.
- */
-public interface XconnectService {
-
- /**
- * VLAN cross-connect ACL priority.
- */
- int XCONNECT_ACL_PRIORITY = 60000;
-
- /**
- * VLAN cross-connect Bridging priority.
- */
- int XCONNECT_PRIORITY = 1000;
-
- /**
- * Creates or updates Xconnect.
- *
- * @param deviceId device ID
- * @param vlanId VLAN ID
- * @param endpoints set of endpoints
- */
- void addOrUpdateXconnect(DeviceId deviceId, VlanId vlanId, Set<XconnectEndpoint> endpoints);
-
- /**
- * Deletes Xconnect.
- *
- * @param deviceId device ID
- * @param vlanId VLAN ID
- */
- void removeXonnect(DeviceId deviceId, VlanId vlanId);
-
- /**
- * Gets Xconnects.
- *
- * @return set of Xconnect descriptions
- */
- Set<XconnectDesc> getXconnects();
-
- /**
- * Check if there is Xconnect configured on given connect point.
- *
- * @param cp connect point
- * @return true if there is Xconnect configured on the connect point
- */
- boolean hasXconnect(ConnectPoint cp);
-
- /**
- * Gives xconnect VLAN of given port of a device.
- *
- * @param deviceId Device ID
- * @param port Port number
- * @return true if given VLAN vlanId is XConnect VLAN on device deviceId.
- */
- List<VlanId> getXconnectVlans(DeviceId deviceId, PortNumber port);
-
- /**
- * Checks given VLAN is XConnect VLAN in given device.
- *
- * @param deviceId Device ID
- * @param vlanId VLAN ID
- * @return true if given VLAN vlanId is XConnect VLAN on device deviceId.
- */
- boolean isXconnectVlan(DeviceId deviceId, VlanId vlanId);
-
- /**
- * Returns the Xconnect next objective store.
- *
- * @return current contents of the xconnectNextObjStore
- */
- ImmutableMap<XconnectKey, Integer> getNext();
-
- /**
- * Removes given next ID from Xconnect next objective store.
- *
- * @param nextId next ID
- */
- void removeNextId(int nextId);
-
- /**
- * Returns Xconnect next objective ID associated with group device + vlan.
- *
- * @param deviceId - Device ID
- * @param vlanId - VLAN ID
- * @return Current associated group ID
- */
- int getNextId(DeviceId deviceId, VlanId vlanId);
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/package-info.java b/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/package-info.java
deleted file mode 100644
index 56df706..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/xconnect/api/package-info.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2018-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.
- */
-
-/**
- * VLAN cross connect API.
- */
-package org.onosproject.segmentrouting.xconnect.api;
\ No newline at end of file
diff --git a/app/src/main/java/org/onosproject/segmentrouting/xconnect/impl/XconnectManager.java b/app/src/main/java/org/onosproject/segmentrouting/xconnect/impl/XconnectManager.java
deleted file mode 100644
index fecba5a..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/xconnect/impl/XconnectManager.java
+++ /dev/null
@@ -1,1346 +0,0 @@
-/*
- * Copyright 2018-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.impl;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.cache.Cache;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.RemovalNotification;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-import org.onlab.packet.Ethernet;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
-import org.onlab.util.KryoNamespace;
-import org.onosproject.cluster.ClusterService;
-import org.onosproject.cluster.LeadershipService;
-import org.onosproject.cluster.NodeId;
-import org.onosproject.codec.CodecService;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.core.CoreService;
-import org.onosproject.portloadbalancer.api.PortLoadBalancerEvent;
-import org.onosproject.portloadbalancer.api.PortLoadBalancerId;
-import org.onosproject.portloadbalancer.api.PortLoadBalancerListener;
-import org.onosproject.portloadbalancer.api.PortLoadBalancerService;
-import org.onosproject.mastership.MastershipService;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Host;
-import org.onosproject.net.HostLocation;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.Port;
-import org.onosproject.net.config.NetworkConfigRegistry;
-import org.onosproject.net.config.NetworkConfigService;
-import org.onosproject.net.device.DeviceEvent;
-import org.onosproject.net.device.DeviceListener;
-import org.onosproject.net.device.DeviceService;
-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.criteria.Criteria;
-import org.onosproject.net.flowobjective.DefaultFilteringObjective;
-import org.onosproject.net.flowobjective.DefaultForwardingObjective;
-import org.onosproject.net.flowobjective.DefaultNextObjective;
-import org.onosproject.net.flowobjective.DefaultNextTreatment;
-import org.onosproject.net.flowobjective.DefaultObjectiveContext;
-import org.onosproject.net.flowobjective.FilteringObjective;
-import org.onosproject.net.flowobjective.FlowObjectiveService;
-import org.onosproject.net.flowobjective.ForwardingObjective;
-import org.onosproject.net.flowobjective.IdNextTreatment;
-import org.onosproject.net.flowobjective.NextObjective;
-import org.onosproject.net.flowobjective.NextTreatment;
-import org.onosproject.net.flowobjective.Objective;
-import org.onosproject.net.flowobjective.ObjectiveContext;
-import org.onosproject.net.flowobjective.ObjectiveError;
-import org.onosproject.net.host.HostEvent;
-import org.onosproject.net.host.HostListener;
-import org.onosproject.net.host.HostService;
-import org.onosproject.net.intf.InterfaceService;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
-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;
-import org.onosproject.store.service.MapEvent;
-import org.onosproject.store.service.MapEventListener;
-import org.onosproject.store.service.Serializer;
-import org.onosproject.store.service.StorageService;
-import org.onosproject.store.service.Versioned;
-import org.osgi.service.component.annotations.Activate;
-import org.osgi.service.component.annotations.Component;
-import org.osgi.service.component.annotations.Deactivate;
-import org.osgi.service.component.annotations.Reference;
-import org.osgi.service.component.annotations.ReferenceCardinality;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.Serializable;
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-import java.util.Iterator;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-import java.util.function.BiConsumer;
-import java.util.function.Consumer;
-import java.util.stream.Collectors;
-
-import static java.util.concurrent.Executors.newScheduledThreadPool;
-import static org.onlab.util.Tools.groupedThreads;
-
-@Component(immediate = true, service = XconnectService.class)
-public class XconnectManager implements XconnectService {
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- private CoreService coreService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- private CodecService codecService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- private StorageService storageService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- public NetworkConfigService netCfgService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- public DeviceService deviceService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- public FlowObjectiveService flowObjectiveService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- private LeadershipService leadershipService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- private ClusterService clusterService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- public MastershipService mastershipService;
-
- @Reference(cardinality = ReferenceCardinality.OPTIONAL)
- public SegmentRoutingService srService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- public InterfaceService interfaceService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- HostService hostService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- private PortLoadBalancerService portLoadBalancerService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- public NetworkConfigRegistry cfgService;
-
- private static final String APP_NAME = "org.onosproject.xconnect";
- private static final String ERROR_NOT_LEADER = "Not leader controller";
- private static final String ERROR_NEXT_OBJ_BUILDER = "Unable to construct next objective builder";
- private static final String ERROR_NEXT_ID = "Unable to get next id";
- private static final String ERROR_NOT_EDGE_ROUTER = "Device is not Edge Router";
- private static final String ERROR_PORT_NOT_RANGE = "Ports for the device are not in the range";
-
- private static Logger log = LoggerFactory.getLogger(XconnectManager.class);
-
- private ApplicationId appId;
- 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<XconnectEndpoint>> xconnectListener = new XconnectMapListener();
- private ExecutorService xConnectExecutor;
-
- private final DeviceListener deviceListener = new InternalDeviceListener();
- private ExecutorService deviceEventExecutor;
-
- private final HostListener hostListener = new InternalHostListener();
- private ExecutorService hostEventExecutor;
-
- // Wait time for the cache
- private static final int WAIT_TIME_MS = 15000;
- //The cache is implemented as buffer for waiting the installation of PortLoadBalancer when present
- private Cache<PortLoadBalancerId, XconnectKey> portLoadBalancerCache;
- // Executor for the cache
- private ScheduledExecutorService portLoadBalancerExecutor;
- // We need to listen for some events to properly installed the xconnect with portloadbalancer
- private final PortLoadBalancerListener portLoadBalancerListener = new InternalPortLoadBalancerListener();
-
- @Activate
- void activate() {
- appId = coreService.registerApplication(APP_NAME);
- codecService.registerCodec(XconnectDesc.class, new XconnectCodec());
-
- KryoNamespace.Builder serializer = KryoNamespace.newBuilder()
- .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<XconnectEndpoint>>consistentMapBuilder()
- .withName("onos-sr-xconnect")
- .withRelaxedReadConsistency()
- .withSerializer(Serializer.using(serializer.build()))
- .build();
- xConnectExecutor = Executors.newSingleThreadScheduledExecutor(
- groupedThreads("sr-xconnect-event", "%d", log));
- xconnectStore.addListener(xconnectListener, xConnectExecutor);
-
- xconnectNextObjStore = storageService.<XconnectKey, Integer>consistentMapBuilder()
- .withName("onos-sr-xconnect-next")
- .withRelaxedReadConsistency()
- .withSerializer(Serializer.using(serializer.build()))
- .build();
-
- xconnectMulticastNextStore = storageService.<VlanNextObjectiveStoreKey, Integer>consistentMapBuilder()
- .withName("onos-sr-xconnect-l2multicast-next")
- .withSerializer(Serializer.using(serializer.build()))
- .build();
- xconnectMulticastPortsStore = storageService.<VlanNextObjectiveStoreKey, List<PortNumber>>consistentMapBuilder()
- .withName("onos-sr-xconnect-l2multicast-ports")
- .withSerializer(Serializer.using(serializer.build()))
- .build();
-
- deviceEventExecutor = Executors.newSingleThreadScheduledExecutor(
- groupedThreads("sr-xconnect-device-event", "%d", log));
- deviceService.addListener(deviceListener);
-
- hostEventExecutor = Executors.newSingleThreadExecutor(
- groupedThreads("sr-xconnect-host-event", "%d", log));
- hostService.addListener(hostListener);
-
- portLoadBalancerCache = CacheBuilder.newBuilder()
- .expireAfterWrite(WAIT_TIME_MS, TimeUnit.MILLISECONDS)
- .removalListener((RemovalNotification<PortLoadBalancerId, XconnectKey> notification) ->
- log.debug("PortLoadBalancer cache removal event. portLoadBalancerId={}, xConnectKey={}",
- notification.getKey(), notification.getValue())).build();
- portLoadBalancerExecutor = newScheduledThreadPool(1,
- groupedThreads("portLoadBalancerCacheWorker", "-%d", log));
- // Let's schedule the cleanup of the cache
- portLoadBalancerExecutor.scheduleAtFixedRate(portLoadBalancerCache::cleanUp, 0,
- WAIT_TIME_MS, TimeUnit.MILLISECONDS);
- portLoadBalancerService.addListener(portLoadBalancerListener);
-
- log.info("Started");
- }
-
- @Deactivate
- void deactivate() {
- xconnectStore.removeListener(xconnectListener);
- deviceService.removeListener(deviceListener);
- hostService.removeListener(hostListener);
- portLoadBalancerService.removeListener(portLoadBalancerListener);
- codecService.unregisterCodec(XconnectDesc.class);
-
- deviceEventExecutor.shutdown();
- hostEventExecutor.shutdown();
- xConnectExecutor.shutdown();
- portLoadBalancerExecutor.shutdown();
-
- log.info("Stopped");
- }
-
- @Override
- public void addOrUpdateXconnect(DeviceId deviceId, VlanId vlanId, Set<XconnectEndpoint> endpoints) {
- log.info("Adding or updating xconnect. deviceId={}, vlanId={}, endpoints={}",
- deviceId, vlanId, endpoints);
- SegmentRoutingDeviceConfig config = cfgService.getConfig(deviceId, SegmentRoutingDeviceConfig.class);
-
- List<PortNumber> devicePorts = deviceService.getPorts(deviceId).stream()
- .map(Port::number)
- .collect(Collectors.toList());
- if (!config.isEdgeRouter()) {
- throw new IllegalArgumentException(ERROR_NOT_EDGE_ROUTER);
- } else {
- Iterator<XconnectEndpoint> itr = endpoints.iterator();
- while (itr.hasNext()) {
- XconnectEndpoint ep = itr.next();
- // Note: we don't validate an endpoint with LOAD_BALANCER type
- if (ep.type() != XconnectEndpoint.Type.PORT) {
- continue;
- }
- if (!devicePorts.contains(((XconnectPortEndpoint) ep).port())) {
- throw new IllegalArgumentException(ERROR_PORT_NOT_RANGE);
- }
- }
- }
- final XconnectKey key = new XconnectKey(deviceId, vlanId);
- xconnectStore.put(key, endpoints);
- }
-
- @Override
- public void removeXonnect(DeviceId deviceId, VlanId vlanId) {
- log.info("Removing xconnect. deviceId={}, vlanId={}",
- deviceId, vlanId);
- final XconnectKey key = new XconnectKey(deviceId, vlanId);
- xconnectStore.remove(key);
-
- // Cleanup multicasting support, if any.
- srService.getPairDeviceId(deviceId).ifPresent(pairDeviceId ->
- cleanupL2MulticastRule(pairDeviceId, srService.getPairLocalPort(pairDeviceId).get(), vlanId, true)
- );
-
- }
-
- @Override
- public Set<XconnectDesc> getXconnects() {
- return xconnectStore.asJavaMap().entrySet().stream()
- .map(e -> new XconnectDesc(e.getKey(), e.getValue()))
- .collect(Collectors.toSet());
- }
-
- @Override
- public boolean hasXconnect(ConnectPoint cp) {
- return getXconnects().stream().anyMatch(desc ->
- 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.endpoints().stream().anyMatch(ep ->
- ep.type() == XconnectEndpoint.Type.PORT && ((XconnectPortEndpoint) ep).port().equals(port)))
- .map(XconnectDesc::key)
- .map(XconnectKey::vlanId)
- .collect(Collectors.toList());
- }
-
- @Override
- public boolean isXconnectVlan(DeviceId deviceId, VlanId vlanId) {
- XconnectKey key = new XconnectKey(deviceId, vlanId);
- return Versioned.valueOrNull(xconnectStore.get(key)) != null;
- }
-
- @Override
- public ImmutableMap<XconnectKey, Integer> getNext() {
- if (xconnectNextObjStore != null) {
- return ImmutableMap.copyOf(xconnectNextObjStore.asJavaMap());
- } else {
- return ImmutableMap.of();
- }
- }
-
- @Override
- public int getNextId(DeviceId deviceId, VlanId vlanId) {
- return Versioned.valueOrElse(xconnectNextObjStore.get(new XconnectKey(deviceId, vlanId)), -1);
- }
-
- @Override
- public void removeNextId(int nextId) {
- xconnectNextObjStore.entrySet().forEach(e -> {
- if (e.getValue().value() == nextId) {
- xconnectNextObjStore.remove(e.getKey());
- }
- });
- }
-
- private class XconnectMapListener implements MapEventListener<XconnectKey, Set<XconnectEndpoint>> {
- @Override
- public void event(MapEvent<XconnectKey, Set<XconnectEndpoint>> event) {
- XconnectKey key = event.key();
- Set<XconnectEndpoint> ports = Versioned.valueOrNull(event.newValue());
- Set<XconnectEndpoint> oldPorts = Versioned.valueOrNull(event.oldValue());
-
- switch (event.type()) {
- case INSERT:
- populateXConnect(key, ports);
- break;
- case UPDATE:
- updateXConnect(key, oldPorts, ports);
- break;
- case REMOVE:
- revokeXConnect(key, oldPorts);
- break;
- default:
- break;
- }
- }
- }
-
- private class InternalDeviceListener implements DeviceListener {
- // Offload the execution to an executor and then process the event
- // if this instance is the leader of the device
- @Override
- public void event(DeviceEvent event) {
- deviceEventExecutor.execute(() -> {
- DeviceId deviceId = event.subject().id();
- // Just skip if we are not the leader
- if (!isLocalLeader(deviceId)) {
- log.debug("Not the leader of {}. Skip event {}", deviceId, event);
- return;
- }
- // Populate or revoke according to the device availability
- if (deviceService.isAvailable(deviceId)) {
- init(deviceId);
- } else {
- cleanup(deviceId);
- }
- });
- }
- // We want to manage only a subset of events and if we are the leader
- @Override
- public boolean isRelevant(DeviceEvent event) {
- return event.type() == DeviceEvent.Type.DEVICE_ADDED ||
- event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
- event.type() == DeviceEvent.Type.DEVICE_UPDATED;
- }
- }
-
- private class InternalHostListener implements HostListener {
- @Override
- public void event(HostEvent event) {
- hostEventExecutor.execute(() -> {
-
- switch (event.type()) {
- case HOST_ADDED:
- case HOST_REMOVED:
- case HOST_UPDATED:
- log.trace("Unhandled host event type: {} received. Ignoring.", event.type());
- break;
- case HOST_MOVED:
- log.trace("Processing host event {}", event);
-
- Host host = event.subject();
- Set<HostLocation> prevLocations = event.prevSubject().locations();
- Set<HostLocation> newLocations = host.locations();
-
- // Dual-home host port failure
- // For each old location, in failed and paired devices update L2 vlan groups
- Sets.difference(prevLocations, newLocations).forEach(prevLocation -> {
-
- Optional<DeviceId> pairDeviceId = srService.getPairDeviceId(prevLocation.deviceId());
- Optional<PortNumber> pairLocalPort = srService.getPairLocalPort(prevLocation.deviceId());
-
- if (pairDeviceId.isPresent() && pairLocalPort.isPresent() && newLocations.stream()
- .anyMatch(location -> location.deviceId().equals(pairDeviceId.get())) &&
- hasXconnect(new ConnectPoint(prevLocation.deviceId(), prevLocation.port()))) {
-
- List<VlanId> xconnectVlans = getXconnectVlans(prevLocation.deviceId(),
- prevLocation.port());
- xconnectVlans.forEach(xconnectVlan -> {
- // Add single-home host into L2 multicast group at paired device side.
- // Also append ACL rule to forward traffic from paired port to L2 multicast group.
- newLocations.stream()
- .filter(location -> location.deviceId().equals(pairDeviceId.get()))
- .forEach(location -> populateL2Multicast(location.deviceId(),
- srService.getPairLocalPort(
- location.deviceId()).get(),
- xconnectVlan,
- Collections.singletonList(
- location.port())));
- // Ensure pair-port attached to xconnect vlan flooding group
- // at dual home failed device.
- updateL2Flooding(prevLocation.deviceId(), pairLocalPort.get(), xconnectVlan, true);
- });
- }
- });
-
- // Dual-home host port restoration
- // For each new location, reverse xconnect loop prevention groups.
- Sets.difference(newLocations, prevLocations).forEach(newLocation -> {
- final Optional<DeviceId> pairDeviceId = srService.getPairDeviceId(newLocation.deviceId());
- Optional<PortNumber> pairLocalPort = srService.getPairLocalPort(newLocation.deviceId());
- if (pairDeviceId.isPresent() && pairLocalPort.isPresent() &&
- hasXconnect((new ConnectPoint(newLocation.deviceId(), newLocation.port())))) {
-
- List<VlanId> xconnectVlans = getXconnectVlans(newLocation.deviceId(),
- newLocation.port());
- xconnectVlans.forEach(xconnectVlan -> {
- // Remove recovered dual homed port from vlan L2 multicast group
- prevLocations.stream()
- .filter(prevLocation -> prevLocation.deviceId().equals(pairDeviceId.get()))
- .forEach(prevLocation -> revokeL2Multicast(
- prevLocation.deviceId(),
- xconnectVlan,
- Collections.singletonList(newLocation.port()))
- );
-
- // Remove pair-port from vlan's flooding group at dual home
- // restored device, if needed.
- if (!hasAccessPortInMulticastGroup(new VlanNextObjectiveStoreKey(
- newLocation.deviceId(), xconnectVlan), pairLocalPort.get())) {
- updateL2Flooding(newLocation.deviceId(),
- pairLocalPort.get(),
- xconnectVlan,
- false);
-
- // Clean L2 multicast group at pair-device; also update store.
- cleanupL2MulticastRule(pairDeviceId.get(),
- srService.getPairLocalPort(pairDeviceId.get()).get(),
- xconnectVlan,
- false);
- }
- });
- }
- });
- break;
-
- default:
- log.warn("Unsupported host event type: {} received. Ignoring.", event.type());
- break;
- }
- });
- }
- }
-
- private void init(DeviceId deviceId) {
- getXconnects().stream()
- .filter(desc -> desc.key().deviceId().equals(deviceId))
- .forEach(desc -> populateXConnect(desc.key(), desc.endpoints()));
- }
-
- private void cleanup(DeviceId deviceId) {
- xconnectNextObjStore.entrySet().stream()
- .filter(entry -> entry.getKey().deviceId().equals(deviceId))
- .forEach(entry -> xconnectNextObjStore.remove(entry.getKey()));
- log.debug("{} is removed from xConnectNextObjStore", deviceId);
- }
-
- /**
- * Populates XConnect groups and flows for given key.
- *
- * @param key XConnect key
- * @param endpoints a set of endpoints to be cross-connected
- */
- private void populateXConnect(XconnectKey key, Set<XconnectEndpoint> endpoints) {
- if (!isLocalLeader(key.deviceId())) {
- log.debug("Abort populating XConnect {}: {}", key, ERROR_NOT_LEADER);
- return;
- }
-
- int nextId = populateNext(key, endpoints);
- if (nextId == -1) {
- log.warn("Fail to populateXConnect {}: {}", key, ERROR_NEXT_ID);
- return;
- }
- populateFilter(key, endpoints);
- populateFwd(key, nextId);
- populateAcl(key);
- }
-
- /**
- * Populates filtering objectives for given XConnect.
- *
- * @param key XConnect store key
- * @param endpoints XConnect endpoints
- */
- private void populateFilter(XconnectKey key, Set<XconnectEndpoint> endpoints) {
- // FIXME Improve the logic
- // If port 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 = 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 {} 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 endpoints XConnect endpoints
- * @return next id
- */
- private int populateNext(XconnectKey key, Set<XconnectEndpoint> endpoints) {
- int nextId = Versioned.valueOrElse(xconnectNextObjStore.get(key), -1);
- if (nextId != -1) {
- log.debug("NextObj for {} found, id={}", key, nextId);
- return nextId;
- } else {
- NextObjective.Builder nextObjBuilder = nextObjBuilder(key, endpoints);
- if (nextObjBuilder == null) {
- log.warn("Fail to populate {}: {}", key, ERROR_NEXT_OBJ_BUILDER);
- return -1;
- }
- ObjectiveContext nextContext = new DefaultObjectiveContext(
- // To serialize this with kryo
- (Serializable & Consumer<Objective>) (objective) ->
- log.debug("XConnect NextObj for {} added", key),
- (Serializable & BiConsumer<Objective, ObjectiveError>) (objective, error) -> {
- log.warn("Failed to add XConnect NextObj for {}: {}", key, error);
- srService.invalidateNextObj(objective.id());
- });
- NextObjective nextObj = nextObjBuilder.add(nextContext);
- flowObjectiveService.next(key.deviceId(), nextObj);
- xconnectNextObjStore.put(key, nextObj.id());
- log.debug("NextObj for {} not found. Creating new NextObj with id={}", key, nextObj.id());
- return nextObj.id();
- }
- }
-
- /**
- * Populates bridging forwarding objectives for given XConnect.
- *
- * @param key XConnect store key
- * @param nextId next objective id
- */
- private void populateFwd(XconnectKey key, int nextId) {
- ForwardingObjective.Builder fwdObjBuilder = fwdObjBuilder(key, nextId);
- ObjectiveContext fwdContext = new DefaultObjectiveContext(
- (objective) -> log.debug("XConnect FwdObj for {} populated", key),
- (objective, error) ->
- log.warn("Failed to populate XConnect FwdObj for {}: {}", key, error));
- flowObjectiveService.forward(key.deviceId(), fwdObjBuilder.add(fwdContext));
- }
-
- /**
- * Populates ACL forwarding objectives for given XConnect.
- *
- * @param key XConnect store key
- */
- private void populateAcl(XconnectKey key) {
- ForwardingObjective.Builder aclObjBuilder = aclObjBuilder(key.vlanId());
- ObjectiveContext aclContext = new DefaultObjectiveContext(
- (objective) -> log.debug("XConnect AclObj for {} populated", key),
- (objective, error) ->
- log.warn("Failed to populate XConnect AclObj for {}: {}", key, error));
- flowObjectiveService.forward(key.deviceId(), aclObjBuilder.add(aclContext));
- }
-
- /**
- * Revokes XConnect groups and flows for given key.
- *
- * @param key XConnect key
- * @param endpoints XConnect endpoints
- */
- private void revokeXConnect(XconnectKey key, Set<XconnectEndpoint> endpoints) {
- if (!isLocalLeader(key.deviceId())) {
- log.debug("Abort revoking XConnect {}: {}", key, ERROR_NOT_LEADER);
- return;
- }
-
- revokeFilter(key, endpoints);
- int nextId = Versioned.valueOrElse(xconnectNextObjStore.get(key), -1);
- if (nextId != -1) {
- revokeFwd(key, nextId, null);
- revokeNext(key, endpoints, nextId, null);
- } else {
- log.warn("NextObj for {} does not exist in the store.", key);
- }
- revokeFilter(key, endpoints);
- revokeAcl(key);
- }
-
- /**
- * Revokes filtering objectives for given XConnect.
- *
- * @param key XConnect store key
- * @param endpoints XConnect endpoints
- */
- private void revokeFilter(XconnectKey key, Set<XconnectEndpoint> endpoints) {
- // FIXME Improve the logic
- // If port 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 = 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 endpoints XConnect endpoints
- * @param nextId next objective id
- * @param nextFuture completable future for this next objective operation
- */
- private void revokeNext(XconnectKey key, Set<XconnectEndpoint> endpoints, int nextId,
- CompletableFuture<ObjectiveError> nextFuture) {
- ObjectiveContext context = new ObjectiveContext() {
- @Override
- public void onSuccess(Objective objective) {
- log.debug("Previous NextObj for {} removed", key);
- if (nextFuture != null) {
- nextFuture.complete(null);
- }
- }
-
- @Override
- public void onError(Objective objective, ObjectiveError error) {
- log.warn("Failed to remove previous NextObj for {}: {}", key, error);
- if (nextFuture != null) {
- nextFuture.complete(error);
- }
- srService.invalidateNextObj(objective.id());
- }
- };
-
- NextObjective.Builder nextObjBuilder = nextObjBuilder(key, endpoints, nextId);
- if (nextObjBuilder == null) {
- log.warn("Fail to revokeNext {}: {}", key, ERROR_NEXT_OBJ_BUILDER);
- return;
- }
- // Release the port load balancer if present
- endpoints.stream()
- .filter(endpoint -> endpoint.type() == XconnectEndpoint.Type.LOAD_BALANCER)
- .forEach(endpoint -> {
- String portLoadBalancerKey = String.valueOf(((XconnectLoadBalancerEndpoint) endpoint).key());
- portLoadBalancerService.release(new PortLoadBalancerId(key.deviceId(),
- Integer.parseInt(portLoadBalancerKey)), appId);
- });
- flowObjectiveService.next(key.deviceId(), nextObjBuilder.remove(context));
- xconnectNextObjStore.remove(key);
- }
-
- /**
- * Revokes bridging forwarding objectives for given XConnect.
- *
- * @param key XConnect store key
- * @param nextId next objective id
- * @param fwdFuture completable future for this forwarding objective operation
- */
- private void revokeFwd(XconnectKey key, int nextId, CompletableFuture<ObjectiveError> fwdFuture) {
- ForwardingObjective.Builder fwdObjBuilder = fwdObjBuilder(key, nextId);
- ObjectiveContext context = new ObjectiveContext() {
- @Override
- public void onSuccess(Objective objective) {
- log.debug("Previous FwdObj for {} removed", key);
- if (fwdFuture != null) {
- fwdFuture.complete(null);
- }
- }
-
- @Override
- public void onError(Objective objective, ObjectiveError error) {
- log.warn("Failed to remove previous FwdObj for {}: {}", key, error);
- if (fwdFuture != null) {
- fwdFuture.complete(error);
- }
- }
- };
- flowObjectiveService.forward(key.deviceId(), fwdObjBuilder.remove(context));
- }
-
- /**
- * Revokes ACL forwarding objectives for given XConnect.
- *
- * @param key XConnect store key
- */
- private void revokeAcl(XconnectKey key) {
- ForwardingObjective.Builder aclObjBuilder = aclObjBuilder(key.vlanId());
- ObjectiveContext aclContext = new DefaultObjectiveContext(
- (objective) -> log.debug("XConnect AclObj for {} populated", key),
- (objective, error) ->
- log.warn("Failed to populate XConnect AclObj for {}: {}", key, error));
- flowObjectiveService.forward(key.deviceId(), aclObjBuilder.remove(aclContext));
- }
-
- /**
- * Updates XConnect groups and flows for given key.
- *
- * @param key XConnect key
- * @param prevEndpoints previous XConnect endpoints
- * @param endpoints new XConnect endpoints
- */
- private void updateXConnect(XconnectKey key, Set<XconnectEndpoint> prevEndpoints,
- Set<XconnectEndpoint> endpoints) {
- if (!isLocalLeader(key.deviceId())) {
- log.debug("Abort updating XConnect {}: {}", key, ERROR_NOT_LEADER);
- return;
- }
- // NOTE: ACL flow doesn't include port information. No need to update it.
- // Pair port is built-in and thus not going to change. No need to update it.
-
- // remove old filter
- prevEndpoints.stream().filter(prevEndpoint -> !endpoints.contains(prevEndpoint)).forEach(prevEndpoint ->
- revokeFilter(key, ImmutableSet.of(prevEndpoint)));
- // install new filter
- endpoints.stream().filter(endpoint -> !prevEndpoints.contains(endpoint)).forEach(endpoint ->
- populateFilter(key, ImmutableSet.of(endpoint)));
-
- CompletableFuture<ObjectiveError> fwdFuture = new CompletableFuture<>();
- CompletableFuture<ObjectiveError> nextFuture = new CompletableFuture<>();
-
- int nextId = Versioned.valueOrElse(xconnectNextObjStore.get(key), -1);
- if (nextId != -1) {
- revokeFwd(key, nextId, fwdFuture);
-
- fwdFuture.thenAcceptAsync(fwdStatus -> {
- if (fwdStatus == null) {
- log.debug("Fwd removed. Now remove group {}", key);
- revokeNext(key, prevEndpoints, nextId, nextFuture);
- }
- });
-
- nextFuture.thenAcceptAsync(nextStatus -> {
- if (nextStatus == null) {
- log.debug("Installing new group and flow for {}", key);
- int newNextId = populateNext(key, endpoints);
- if (newNextId == -1) {
- log.warn("Fail to updateXConnect {}: {}", key, ERROR_NEXT_ID);
- return;
- }
- populateFwd(key, newNextId);
- }
- });
- } else {
- log.warn("NextObj for {} does not exist in the store.", key);
- }
- }
-
- /**
- * Creates a next objective builder for XConnect with given nextId.
- *
- * @param key XConnect key
- * @param endpoints XConnect endpoints
- * @param nextId next objective id
- * @return next objective builder
- */
- private NextObjective.Builder nextObjBuilder(XconnectKey key, Set<XconnectEndpoint> endpoints, int nextId) {
- TrafficSelector metadata =
- DefaultTrafficSelector.builder().matchVlanId(key.vlanId()).build();
- NextObjective.Builder nextObjBuilder = DefaultNextObjective
- .builder().withId(nextId)
- .withType(NextObjective.Type.BROADCAST).fromApp(appId)
- .withMeta(metadata);
-
- for (XconnectEndpoint endpoint : endpoints) {
- NextTreatment nextTreatment = getNextTreatment(key.deviceId(), endpoint, true);
- if (nextTreatment == null) {
- // If a PortLoadBalancer is used in the XConnect - putting on hold
- if (endpoint.type() == XconnectEndpoint.Type.LOAD_BALANCER) {
- log.warn("Unable to create nextObj. PortLoadBalancer not ready");
- String portLoadBalancerKey = String.valueOf(((XconnectLoadBalancerEndpoint) endpoint).key());
- portLoadBalancerCache.asMap().putIfAbsent(new PortLoadBalancerId(key.deviceId(),
- Integer.parseInt(portLoadBalancerKey)), key);
- } else {
- log.warn("Unable to create nextObj. Null NextTreatment");
- }
- return null;
- }
- nextObjBuilder.addTreatment(nextTreatment);
- }
-
- return nextObjBuilder;
- }
-
- /**
- * Creates a next objective builder for XConnect.
- *
- * @param key XConnect key
- * @param endpoints Xconnect endpoints
- * @return next objective builder
- */
- private NextObjective.Builder nextObjBuilder(XconnectKey key, Set<XconnectEndpoint> endpoints) {
- int nextId = flowObjectiveService.allocateNextId();
- return nextObjBuilder(key, endpoints, nextId);
- }
-
-
- /**
- * Creates a bridging forwarding objective builder for XConnect.
- *
- * @param key XConnect key
- * @param nextId next ID of the broadcast group for this XConnect key
- * @return forwarding objective builder
- */
- private ForwardingObjective.Builder fwdObjBuilder(XconnectKey key, int nextId) {
- /*
- * Driver should treat objectives with MacAddress.NONE and !VlanId.NONE
- * as the VLAN cross-connect broadcast rules
- */
- TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
- sbuilder.matchVlanId(key.vlanId());
- sbuilder.matchEthDst(MacAddress.NONE);
-
- ForwardingObjective.Builder fob = DefaultForwardingObjective.builder();
- fob.withFlag(ForwardingObjective.Flag.SPECIFIC)
- .withSelector(sbuilder.build())
- .nextStep(nextId)
- .withPriority(XCONNECT_PRIORITY)
- .fromApp(appId)
- .makePermanent();
- return fob;
- }
-
- /**
- * Creates an ACL forwarding objective builder for XConnect.
- *
- * @param vlanId cross connect VLAN id
- * @return forwarding objective builder
- */
- private ForwardingObjective.Builder aclObjBuilder(VlanId vlanId) {
- TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
- sbuilder.matchVlanId(vlanId);
-
- TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
-
- ForwardingObjective.Builder fob = DefaultForwardingObjective.builder();
- fob.withFlag(ForwardingObjective.Flag.VERSATILE)
- .withSelector(sbuilder.build())
- .withTreatment(tbuilder.build())
- .withPriority(XCONNECT_ACL_PRIORITY)
- .fromApp(appId)
- .makePermanent();
- return fob;
- }
-
- /**
- * Creates a filtering objective builder for XConnect.
- *
- * @param key XConnect key
- * @param port XConnect ports
- * @param filtered true if this is a filtered port
- * @return next objective builder
- */
- private FilteringObjective.Builder filterObjBuilder(XconnectKey key, PortNumber port, boolean filtered) {
- FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
- fob.withKey(Criteria.matchInPort(port))
- .addCondition(Criteria.matchEthDst(MacAddress.NONE))
- .withPriority(XCONNECT_PRIORITY);
- if (filtered) {
- fob.addCondition(Criteria.matchVlanId(key.vlanId()));
- } else {
- fob.addCondition(Criteria.matchVlanId(VlanId.ANY));
- }
- return fob.permit().fromApp(appId);
- }
-
- /**
- * Updates L2 flooding groups; add pair link into L2 flooding group of given xconnect vlan.
- *
- * @param deviceId Device ID
- * @param port Port details
- * @param vlanId VLAN ID
- * @param install Whether to add or revoke pair link addition to flooding group
- */
- private void updateL2Flooding(DeviceId deviceId, PortNumber port, VlanId vlanId, boolean install) {
- XconnectKey key = new XconnectKey(deviceId, vlanId);
- // Ensure leadership on device
- if (!isLocalLeader(deviceId)) {
- log.debug("Abort updating L2Flood {}: {}", key, ERROR_NOT_LEADER);
- return;
- }
-
- // Locate L2 flooding group details for given xconnect vlan
- int nextId = Versioned.valueOrElse(xconnectNextObjStore.get(key), -1);
- if (nextId == -1) {
- log.debug("XConnect vlan {} broadcast group for device {} doesn't exists. " +
- "Aborting pair group linking.", vlanId, deviceId);
- return;
- }
-
- // Add pairing-port group to flooding group
- TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
- // treatment.popVlan();
- treatment.setOutput(port);
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) ->
- log.debug("Pair port added/removed to vlan {} next objective {} on {}",
- vlanId, nextId, deviceId),
- (objective, error) ->
- log.warn("Failed adding/removing pair port to vlan {} next objective {} on {}." +
- "Error : {}", vlanId, nextId, deviceId, error)
- );
- NextObjective.Builder vlanNextObjectiveBuilder = DefaultNextObjective.builder()
- .withId(nextId)
- .withType(NextObjective.Type.BROADCAST)
- .fromApp(srService.appId())
- .withMeta(DefaultTrafficSelector.builder().matchVlanId(vlanId).build())
- .addTreatment(treatment.build());
- if (install) {
- flowObjectiveService.next(deviceId, vlanNextObjectiveBuilder.addToExisting(context));
- } else {
- flowObjectiveService.next(deviceId, vlanNextObjectiveBuilder.removeFromExisting(context));
- }
- log.debug("Submitted next objective {} for vlan: {} in device {}",
- nextId, vlanId, deviceId);
- }
-
- /**
- * Populate L2 multicast rule on given deviceId that matches given mac, given vlan and
- * output to given port's L2 mulitcast group.
- *
- * @param deviceId Device ID
- * @param pairPort Pair port number
- * @param vlanId VLAN ID
- * @param accessPorts List of access ports to be added into L2 multicast group
- */
- private void populateL2Multicast(DeviceId deviceId, PortNumber pairPort,
- VlanId vlanId, List<PortNumber> accessPorts) {
- // Ensure enough rights to program pair device
- if (!srService.shouldProgram(deviceId)) {
- log.debug("Abort populate L2Multicast {}-{}: {}", deviceId, vlanId, ERROR_NOT_LEADER);
- return;
- }
-
- boolean multicastGroupExists = true;
- int vlanMulticastNextId;
- VlanNextObjectiveStoreKey key = new VlanNextObjectiveStoreKey(deviceId, vlanId);
-
- // Step 1 : Populate single homed access ports into vlan's L2 multicast group
- NextObjective.Builder vlanMulticastNextObjBuilder = DefaultNextObjective
- .builder()
- .withType(NextObjective.Type.BROADCAST)
- .fromApp(srService.appId())
- .withMeta(DefaultTrafficSelector.builder().matchVlanId(vlanId)
- .matchEthDst(MacAddress.IPV4_MULTICAST).build());
- vlanMulticastNextId = getMulticastGroupNextObjectiveId(key);
- if (vlanMulticastNextId == -1) {
- // Vlan's L2 multicast group doesn't exist; create it, update store and add pair port as sub-group
- multicastGroupExists = false;
- vlanMulticastNextId = flowObjectiveService.allocateNextId();
- addMulticastGroupNextObjectiveId(key, vlanMulticastNextId);
- vlanMulticastNextObjBuilder.addTreatment(
- DefaultTrafficTreatment.builder().setOutput(pairPort).build()
- );
- }
- vlanMulticastNextObjBuilder.withId(vlanMulticastNextId);
- int nextId = vlanMulticastNextId;
- accessPorts.forEach(p -> {
- TrafficTreatment.Builder egressAction = DefaultTrafficTreatment.builder();
- // Do vlan popup action based on interface configuration
- if (interfaceService.getInterfacesByPort(new ConnectPoint(deviceId, p))
- .stream().noneMatch(i -> i.vlanTagged().contains(vlanId))) {
- egressAction.popVlan();
- }
- egressAction.setOutput(p);
- vlanMulticastNextObjBuilder.addTreatment(egressAction.build());
- addMulticastGroupPort(key, p);
- });
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) ->
- log.debug("L2 multicast group installed/updated. "
- + "NextObject Id {} on {} for subnet {} ",
- nextId, deviceId, vlanId),
- (objective, error) ->
- log.warn("L2 multicast group failed to install/update. "
- + " NextObject Id {} on {} for subnet {} : {}",
- nextId, deviceId, vlanId, error)
- );
- if (!multicastGroupExists) {
- flowObjectiveService.next(deviceId, vlanMulticastNextObjBuilder.add(context));
-
- // Step 2 : Populate ACL rule; selector = vlan + pair-port, output = vlan L2 multicast group
- TrafficSelector.Builder multicastSelector = DefaultTrafficSelector.builder();
- multicastSelector.matchEthType(Ethernet.TYPE_VLAN);
- multicastSelector.matchInPort(pairPort);
- multicastSelector.matchVlanId(vlanId);
- ForwardingObjective.Builder vlanMulticastForwardingObj = DefaultForwardingObjective.builder()
- .withFlag(ForwardingObjective.Flag.VERSATILE)
- .nextStep(vlanMulticastNextId)
- .withSelector(multicastSelector.build())
- .withPriority(100)
- .fromApp(srService.appId())
- .makePermanent();
- context = new DefaultObjectiveContext(
- (objective) -> log.debug("L2 multicasting versatile rule for device {}, port/vlan {}/{} populated",
- deviceId,
- pairPort,
- vlanId),
- (objective, error) -> log.warn("Failed to populate L2 multicasting versatile rule for device {}, " +
- "ports/vlan {}/{}: {}", deviceId, pairPort, vlanId, error));
- flowObjectiveService.forward(deviceId, vlanMulticastForwardingObj.add(context));
- } else {
- // L2_MULTICAST & BROADCAST are similar structure in subgroups; so going with BROADCAST type.
- vlanMulticastNextObjBuilder.withType(NextObjective.Type.BROADCAST);
- flowObjectiveService.next(deviceId, vlanMulticastNextObjBuilder.addToExisting(context));
- }
- }
-
- /**
- * Removes access ports from VLAN L2 multicast group on given deviceId.
- *
- * @param deviceId Device ID
- * @param vlanId VLAN ID
- * @param accessPorts List of access ports to be added into L2 multicast group
- */
- private void revokeL2Multicast(DeviceId deviceId, VlanId vlanId, List<PortNumber> accessPorts) {
- // Ensure enough rights to program pair device
- if (!srService.shouldProgram(deviceId)) {
- log.debug("Abort revoke L2Multicast {}-{}: {}", deviceId, vlanId, ERROR_NOT_LEADER);
- return;
- }
-
- VlanNextObjectiveStoreKey key = new VlanNextObjectiveStoreKey(deviceId, vlanId);
-
- int vlanMulticastNextId = getMulticastGroupNextObjectiveId(key);
- if (vlanMulticastNextId == -1) {
- return;
- }
- NextObjective.Builder vlanMulticastNextObjBuilder = DefaultNextObjective
- .builder()
- .withType(NextObjective.Type.BROADCAST)
- .fromApp(srService.appId())
- .withMeta(DefaultTrafficSelector.builder().matchVlanId(vlanId).build())
- .withId(vlanMulticastNextId);
- accessPorts.forEach(p -> {
- TrafficTreatment.Builder egressAction = DefaultTrafficTreatment.builder();
- // Do vlan popup action based on interface configuration
- if (interfaceService.getInterfacesByPort(new ConnectPoint(deviceId, p))
- .stream().noneMatch(i -> i.vlanTagged().contains(vlanId))) {
- egressAction.popVlan();
- }
- egressAction.setOutput(p);
- vlanMulticastNextObjBuilder.addTreatment(egressAction.build());
- removeMulticastGroupPort(key, p);
- });
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) ->
- log.debug("L2 multicast group installed/updated. "
- + "NextObject Id {} on {} for subnet {} ",
- vlanMulticastNextId, deviceId, vlanId),
- (objective, error) ->
- log.warn("L2 multicast group failed to install/update. "
- + " NextObject Id {} on {} for subnet {} : {}",
- vlanMulticastNextId, deviceId, vlanId, error)
- );
- flowObjectiveService.next(deviceId, vlanMulticastNextObjBuilder.removeFromExisting(context));
- }
-
- /**
- * Cleans up VLAN L2 multicast group on given deviceId. ACL rules for the group will also be deleted.
- * Normally multicast group is not removed if it contains access ports; which can be forced
- * by "force" flag
- *
- * @param deviceId Device ID
- * @param pairPort Pair port number
- * @param vlanId VLAN ID
- * @param force Forceful removal
- */
- private void cleanupL2MulticastRule(DeviceId deviceId, PortNumber pairPort, VlanId vlanId, boolean force) {
-
- // Ensure enough rights to program pair device
- if (!srService.shouldProgram(deviceId)) {
- log.debug("Abort cleanup L2Multicast {}-{}: {}", deviceId, vlanId, ERROR_NOT_LEADER);
- return;
- }
-
- VlanNextObjectiveStoreKey key = new VlanNextObjectiveStoreKey(deviceId, vlanId);
-
- // Ensure L2 multicast group doesn't contain access ports
- if (hasAccessPortInMulticastGroup(key, pairPort) && !force) {
- return;
- }
-
- // Load L2 multicast group details
- int vlanMulticastNextId = getMulticastGroupNextObjectiveId(key);
- if (vlanMulticastNextId == -1) {
- return;
- }
-
- // Step 1 : Clear ACL rule; selector = vlan + pair-port, output = vlan L2 multicast group
- TrafficSelector.Builder l2MulticastSelector = DefaultTrafficSelector.builder();
- l2MulticastSelector.matchEthType(Ethernet.TYPE_VLAN);
- l2MulticastSelector.matchInPort(pairPort);
- l2MulticastSelector.matchVlanId(vlanId);
- ForwardingObjective.Builder vlanMulticastForwardingObj = DefaultForwardingObjective.builder()
- .withFlag(ForwardingObjective.Flag.VERSATILE)
- .nextStep(vlanMulticastNextId)
- .withSelector(l2MulticastSelector.build())
- .withPriority(100)
- .fromApp(srService.appId())
- .makePermanent();
- ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> log.debug("L2 multicasting rule for device {}, port/vlan {}/{} deleted", deviceId,
- pairPort, vlanId),
- (objective, error) -> log.warn("Failed to delete L2 multicasting rule for device {}, " +
- "ports/vlan {}/{}: {}", deviceId, pairPort, vlanId, error));
- flowObjectiveService.forward(deviceId, vlanMulticastForwardingObj.remove(context));
-
- // Step 2 : Clear L2 multicast group associated with vlan
- NextObjective.Builder l2MulticastGroupBuilder = DefaultNextObjective
- .builder()
- .withId(vlanMulticastNextId)
- .withType(NextObjective.Type.BROADCAST)
- .fromApp(srService.appId())
- .withMeta(DefaultTrafficSelector.builder()
- .matchVlanId(vlanId)
- .matchEthDst(MacAddress.IPV4_MULTICAST).build())
- .addTreatment(DefaultTrafficTreatment.builder().popVlan().setOutput(pairPort).build());
- context = new DefaultObjectiveContext(
- (objective) ->
- log.debug("L2 multicast group with NextObject Id {} deleted on {} for subnet {} ",
- vlanMulticastNextId, deviceId, vlanId),
- (objective, error) ->
- log.warn("L2 multicast group with NextObject Id {} failed to delete on {} for subnet {} : {}",
- vlanMulticastNextId, deviceId, vlanId, error)
- );
- flowObjectiveService.next(deviceId, l2MulticastGroupBuilder.remove(context));
-
- // Finally clear store.
- removeMulticastGroup(key);
- }
-
- private int getMulticastGroupNextObjectiveId(VlanNextObjectiveStoreKey key) {
- return Versioned.valueOrElse(xconnectMulticastNextStore.get(key), -1);
- }
-
- private void addMulticastGroupNextObjectiveId(VlanNextObjectiveStoreKey key, int nextId) {
- if (nextId == -1) {
- return;
- }
- xconnectMulticastNextStore.put(key, nextId);
- }
-
- private void addMulticastGroupPort(VlanNextObjectiveStoreKey groupKey, PortNumber port) {
- xconnectMulticastPortsStore.compute(groupKey, (key, ports) -> {
- if (ports == null) {
- ports = Lists.newArrayList();
- }
- ports.add(port);
- return ports;
- });
- }
-
- private void removeMulticastGroupPort(VlanNextObjectiveStoreKey groupKey, PortNumber port) {
- xconnectMulticastPortsStore.compute(groupKey, (key, ports) -> {
- if (ports != null && !ports.isEmpty()) {
- ports.remove(port);
- }
- return ports;
- });
- }
-
- private void removeMulticastGroup(VlanNextObjectiveStoreKey groupKey) {
- xconnectMulticastPortsStore.remove(groupKey);
- xconnectMulticastNextStore.remove(groupKey);
- }
-
- private boolean hasAccessPortInMulticastGroup(VlanNextObjectiveStoreKey groupKey, PortNumber pairPort) {
- List<PortNumber> ports = Versioned.valueOrElse(xconnectMulticastPortsStore.get(groupKey), ImmutableList.of());
- return ports.stream().anyMatch(p -> !p.equals(pairPort));
- }
-
- // Custom-built function, when the device is not available we need a fallback mechanism
- private boolean isLocalLeader(DeviceId deviceId) {
- if (!mastershipService.isLocalMaster(deviceId)) {
- // When the device is available we just check the mastership
- if (deviceService.isAvailable(deviceId)) {
- return false;
- }
- // Fallback with Leadership service - device id is used as topic
- NodeId leader = leadershipService.runForLeadership(
- deviceId.toString()).leaderNodeId();
- // Verify if this node is the leader
- return clusterService.getLocalNode().id().equals(leader);
- }
- return true;
- }
-
- private Set<PortNumber> getPhysicalPorts(DeviceId deviceId, XconnectEndpoint endpoint) {
- if (endpoint.type() == XconnectEndpoint.Type.PORT) {
- PortNumber port = ((XconnectPortEndpoint) endpoint).port();
- return Sets.newHashSet(port);
- }
- if (endpoint.type() == XconnectEndpoint.Type.LOAD_BALANCER) {
- PortLoadBalancerId portLoadBalancerId = new PortLoadBalancerId(deviceId,
- ((XconnectLoadBalancerEndpoint) endpoint).key());
- Set<PortNumber> ports = portLoadBalancerService.getPortLoadBalancer(portLoadBalancerId).ports();
- return Sets.newHashSet(ports);
- }
- return Sets.newHashSet();
- }
-
- 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());
- }
- if (endpoint.type() == XconnectEndpoint.Type.LOAD_BALANCER) {
- PortLoadBalancerId portLoadBalancerId = new PortLoadBalancerId(deviceId,
- ((XconnectLoadBalancerEndpoint) endpoint).key());
- NextTreatment idNextTreatment = IdNextTreatment.of(portLoadBalancerService
- .getPortLoadBalancerNext(portLoadBalancerId));
- // Reserve only one time during next objective creation
- if (reserve) {
- if (!portLoadBalancerService.reserve(portLoadBalancerId, appId)) {
- log.warn("Reservation failed for {}", portLoadBalancerId);
- idNextTreatment = null;
- }
- }
- return idNextTreatment;
- }
- return null;
- }
-
- private class InternalPortLoadBalancerListener implements PortLoadBalancerListener {
- // Populate xconnect once portloadbalancer is available
- @Override
- public void event(PortLoadBalancerEvent event) {
- portLoadBalancerExecutor.execute(() -> dequeue(event.subject().portLoadBalancerId()));
- }
- // When we receive INSTALLED port load balancing is ready
- @Override
- public boolean isRelevant(PortLoadBalancerEvent event) {
- return event.type() == PortLoadBalancerEvent.Type.INSTALLED;
- }
- }
-
- // Invalidate the cache and re-start the xconnect installation
- private void dequeue(PortLoadBalancerId portLoadBalancerId) {
- XconnectKey xconnectKey = portLoadBalancerCache.getIfPresent(portLoadBalancerId);
- if (xconnectKey == null) {
- log.trace("{} not present in the cache", portLoadBalancerId);
- return;
- }
- log.debug("Dequeue {}", portLoadBalancerId);
- portLoadBalancerCache.invalidate(portLoadBalancerId);
- Set<XconnectEndpoint> endpoints = Versioned.valueOrNull(xconnectStore.get(xconnectKey));
- if (endpoints == null || endpoints.isEmpty()) {
- log.warn("Endpoints not found for XConnect {}", xconnectKey);
- return;
- }
- populateXConnect(xconnectKey, endpoints);
- log.trace("PortLoadBalancer cache size {}", portLoadBalancerCache.size());
- }
-
-}
diff --git a/app/src/main/java/org/onosproject/segmentrouting/xconnect/impl/package-info.java b/app/src/main/java/org/onosproject/segmentrouting/xconnect/impl/package-info.java
deleted file mode 100644
index 547e3bc..0000000
--- a/app/src/main/java/org/onosproject/segmentrouting/xconnect/impl/package-info.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2018-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.
- */
-
-/**
- * VLAN cross connect implementation.
- */
-package org.onosproject.segmentrouting.xconnect.impl;
\ No newline at end of file
diff --git a/app/src/test/java/org/onosproject/segmentrouting/AugmentedPortAuthTracker.java b/app/src/test/java/org/onosproject/segmentrouting/AugmentedPortAuthTracker.java
deleted file mode 100644
index cc214e3..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/AugmentedPortAuthTracker.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2017-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;
-
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.PortNumber;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * An augmented implementation of {@link PortAuthTracker}, so that we can
- * instrument its behavior for unit test assertions.
- */
-class AugmentedPortAuthTracker extends PortAuthTracker {
-
- // instrument blocking flow activity, so we can see when we get hits
- final List<ConnectPoint> installed = new ArrayList<>();
- final List<ConnectPoint> cleared = new ArrayList<>();
-
-
- void resetMetrics() {
- installed.clear();
- cleared.clear();
- }
-
- @Override
- void installBlockingFlow(DeviceId d, PortNumber p) {
- super.installBlockingFlow(d, p);
- installed.add(new ConnectPoint(d, p));
- }
-
- @Override
- void clearBlockingFlow(DeviceId d, PortNumber p) {
- super.clearBlockingFlow(d, p);
- cleared.add(new ConnectPoint(d, p));
- }
-}
diff --git a/app/src/test/java/org/onosproject/segmentrouting/DefaultRoutingHandlerTest.java b/app/src/test/java/org/onosproject/segmentrouting/DefaultRoutingHandlerTest.java
deleted file mode 100644
index a6278b2..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/DefaultRoutingHandlerTest.java
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * Copyright 2018-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;
-
-import com.google.common.collect.Sets;
-import org.junit.Before;
-import org.junit.Test;
-import org.onlab.packet.IpAddress;
-import org.onosproject.cluster.ClusterService;
-import org.onosproject.cluster.DefaultControllerNode;
-import org.onosproject.cluster.NodeId;
-import org.onosproject.mastership.MastershipService;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.device.DeviceService;
-import org.onosproject.segmentrouting.config.DeviceConfiguration;
-import org.onosproject.store.service.StorageService;
-import org.onosproject.store.service.TestConsistentMap;
-import org.onosproject.store.service.TestConsistentMultimap;
-
-import java.util.Optional;
-
-import static org.easymock.EasyMock.createMock;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.reset;
-import static org.junit.Assert.*;
-
-public class DefaultRoutingHandlerTest {
- private SegmentRoutingManager srManager;
- private DefaultRoutingHandler dfh;
-
- private static final DeviceId DEV1A = DeviceId.deviceId("of:1a");
- private static final DeviceId DEV1B = DeviceId.deviceId("of:1b");
- private static final DeviceId DEV2 = DeviceId.deviceId("of:2");
-
- private static final NodeId NODE1 = NodeId.nodeId("192.168.1.1");
- private static final NodeId NODE2 = NodeId.nodeId("192.168.1.2");
- private static final NodeId NODE3 = NodeId.nodeId("192.168.1.3");
- private static final IpAddress IP1 = IpAddress.valueOf("192.168.1.1");
- private static final IpAddress IP2 = IpAddress.valueOf("192.168.1.2");
- private static final IpAddress IP3 = IpAddress.valueOf("192.168.1.3");
-
- @Before
- public void setUp() {
- srManager = createMock(SegmentRoutingManager.class);
- srManager.storageService = createMock(StorageService.class);
- expect(srManager.storageService.consistentMapBuilder()).andReturn(new TestConsistentMap.Builder<>()).anyTimes();
- expect(srManager.storageService.consistentMultimapBuilder()).andReturn(
- new TestConsistentMultimap.Builder<>()).anyTimes();
- replay(srManager.storageService);
- srManager.routingRulePopulator = createMock(RoutingRulePopulator.class);
- srManager.deviceService = createMock(DeviceService.class);
- srManager.deviceConfiguration = createMock(DeviceConfiguration.class);
- srManager.mastershipService = createMock(MastershipService.class);
- srManager.clusterService = createMock(ClusterService.class);
- dfh = new DefaultRoutingHandler(srManager);
- }
-
- private void clearCache() {
- dfh.invalidateShouldProgramCache(DEV1A);
- dfh.invalidateShouldProgramCache(DEV1B);
- dfh.invalidateShouldProgramCache(DEV2);
- }
-
- // Node 1 is the master of switch 1A, 1B, and 2
- @Test
- public void testShouldHandleRoutingCase1() {
- expect(srManager.mastershipService.getMasterFor(DEV1A)).andReturn(NODE1).anyTimes();
- expect(srManager.mastershipService.getMasterFor(DEV1B)).andReturn(NODE1).anyTimes();
- expect(srManager.mastershipService.getMasterFor(DEV2)).andReturn(NODE1).anyTimes();
- replay(srManager.mastershipService);
-
- expect(srManager.getPairDeviceId(DEV1A)).andReturn(Optional.of(DEV1B)).anyTimes();
- expect(srManager.getPairDeviceId(DEV1B)).andReturn(Optional.of(DEV1A)).anyTimes();
- expect(srManager.getPairDeviceId(DEV2)).andReturn(Optional.empty()).anyTimes();
- replay(srManager);
-
- // Node 1 should program every device
- expect(srManager.clusterService.getLocalNode()).andReturn(new DefaultControllerNode(NODE1, IP1)).anyTimes();
- replay(srManager.clusterService);
- assertTrue(dfh.shouldProgram(DEV1A));
- assertTrue(dfh.shouldProgram(DEV1B));
- assertTrue(dfh.shouldProgram(DEV2));
-
- reset(srManager.clusterService);
- clearCache();
-
- // Node 2 should program no device
- expect(srManager.clusterService.getLocalNode()).andReturn(new DefaultControllerNode(NODE2, IP2)).anyTimes();
- replay(srManager.clusterService);
- assertFalse(dfh.shouldProgram(DEV1A));
- assertFalse(dfh.shouldProgram(DEV1B));
- assertFalse(dfh.shouldProgram(DEV2));
-
- reset(srManager.clusterService);
- clearCache();
-
- // Node 3 should program no device
- expect(srManager.clusterService.getLocalNode()).andReturn(new DefaultControllerNode(NODE3, IP3)).anyTimes();
- replay(srManager.clusterService);
- assertFalse(dfh.shouldProgram(DEV1A));
- assertFalse(dfh.shouldProgram(DEV1B));
- assertFalse(dfh.shouldProgram(DEV2));
- }
-
- // Node 1 is the master of switch 1A, 1B
- // Node 2 is the master of switch 2
- @Test
- public void testShouldHandleRoutingCase2() {
- expect(srManager.mastershipService.getMasterFor(DEV1A)).andReturn(NODE1).anyTimes();
- expect(srManager.mastershipService.getMasterFor(DEV1B)).andReturn(NODE1).anyTimes();
- expect(srManager.mastershipService.getMasterFor(DEV2)).andReturn(NODE2).anyTimes();
- replay(srManager.mastershipService);
-
- expect(srManager.getPairDeviceId(DEV1A)).andReturn(Optional.of(DEV1B)).anyTimes();
- expect(srManager.getPairDeviceId(DEV1B)).andReturn(Optional.of(DEV1A)).anyTimes();
- expect(srManager.getPairDeviceId(DEV2)).andReturn(Optional.empty()).anyTimes();
- replay(srManager);
-
- // Node 1 should program 1A, 1B
- expect(srManager.clusterService.getLocalNode()).andReturn(new DefaultControllerNode(NODE1, IP1)).anyTimes();
- replay(srManager.clusterService);
- assertTrue(dfh.shouldProgram(DEV1A));
- assertTrue(dfh.shouldProgram(DEV1B));
- assertFalse(dfh.shouldProgram(DEV2));
-
- reset(srManager.clusterService);
- clearCache();
-
- // Node 2 should program 2
- expect(srManager.clusterService.getLocalNode()).andReturn(new DefaultControllerNode(NODE2, IP2)).anyTimes();
- replay(srManager.clusterService);
- assertFalse(dfh.shouldProgram(DEV1A));
- assertFalse(dfh.shouldProgram(DEV1B));
- assertTrue(dfh.shouldProgram(DEV2));
-
- reset(srManager.clusterService);
- clearCache();
-
- // Node 3 should program no device
- expect(srManager.clusterService.getLocalNode()).andReturn(new DefaultControllerNode(NODE3, IP3)).anyTimes();
- replay(srManager.clusterService);
- assertFalse(dfh.shouldProgram(DEV1A));
- assertFalse(dfh.shouldProgram(DEV1B));
- assertFalse(dfh.shouldProgram(DEV2));
- }
-
- // Node 1 is the master of switch 1A
- // Node 2 is the master of switch 1B
- // Node 3 is the master of switch 2
- @Test
- public void testShouldHandleRoutingCase3() {
- expect(srManager.mastershipService.getMasterFor(DEV1A)).andReturn(NODE1).anyTimes();
- expect(srManager.mastershipService.getMasterFor(DEV1B)).andReturn(NODE2).anyTimes();
- expect(srManager.mastershipService.getMasterFor(DEV2)).andReturn(NODE3).anyTimes();
- replay(srManager.mastershipService);
-
- expect(srManager.getPairDeviceId(DEV1A)).andReturn(Optional.of(DEV1B)).anyTimes();
- expect(srManager.getPairDeviceId(DEV1B)).andReturn(Optional.of(DEV1A)).anyTimes();
- expect(srManager.getPairDeviceId(DEV2)).andReturn(Optional.empty()).anyTimes();
- replay(srManager);
-
- // Node 1 should program 1A, 1B
- expect(srManager.clusterService.getLocalNode()).andReturn(new DefaultControllerNode(NODE1, IP1)).anyTimes();
- replay(srManager.clusterService);
- assertTrue(dfh.shouldProgram(DEV1A));
- assertTrue(dfh.shouldProgram(DEV1B));
- assertFalse(dfh.shouldProgram(DEV2));
-
- reset(srManager.clusterService);
- clearCache();
-
- // Node 2 should program no device
- expect(srManager.clusterService.getLocalNode()).andReturn(new DefaultControllerNode(NODE2, IP2)).anyTimes();
- replay(srManager.clusterService);
- assertFalse(dfh.shouldProgram(DEV1A));
- assertFalse(dfh.shouldProgram(DEV1B));
- assertFalse(dfh.shouldProgram(DEV2));
-
- reset(srManager.clusterService);
- clearCache();
-
- // Node 3 should program 2
- expect(srManager.clusterService.getLocalNode()).andReturn(new DefaultControllerNode(NODE3, IP3)).anyTimes();
- replay(srManager.clusterService);
- assertFalse(dfh.shouldProgram(DEV1A));
- assertFalse(dfh.shouldProgram(DEV1B));
- assertTrue(dfh.shouldProgram(DEV2));
- }
-
- // Node 3 is the master of switch 1A, 1B, 2
- // Later on, node 1 becomes the master of 1A; Node 2 becomes the master of 1B.
- @Test
- public void testShouldHandleRoutingCase4() {
- expect(srManager.mastershipService.getMasterFor(DEV1A)).andReturn(NODE3).anyTimes();
- expect(srManager.mastershipService.getMasterFor(DEV1B)).andReturn(NODE3).anyTimes();
- expect(srManager.mastershipService.getMasterFor(DEV2)).andReturn(NODE3).anyTimes();
- replay(srManager.mastershipService);
-
- expect(srManager.getPairDeviceId(DEV1A)).andReturn(Optional.of(DEV1B)).anyTimes();
- expect(srManager.getPairDeviceId(DEV1B)).andReturn(Optional.of(DEV1A)).anyTimes();
- expect(srManager.getPairDeviceId(DEV2)).andReturn(Optional.empty()).anyTimes();
- replay(srManager);
-
- // Node 1 should program no device
- expect(srManager.clusterService.getLocalNode()).andReturn(new DefaultControllerNode(NODE1, IP1)).anyTimes();
- replay(srManager.clusterService);
- assertFalse(dfh.shouldProgram(DEV1A));
- assertFalse(dfh.shouldProgram(DEV1B));
- assertFalse(dfh.shouldProgram(DEV2));
-
- reset(srManager.clusterService);
- clearCache();
-
- // Node 2 should program no device
- expect(srManager.clusterService.getLocalNode()).andReturn(new DefaultControllerNode(NODE2, IP2)).anyTimes();
- replay(srManager.clusterService);
- assertFalse(dfh.shouldProgram(DEV1A));
- assertFalse(dfh.shouldProgram(DEV1B));
- assertFalse(dfh.shouldProgram(DEV2));
-
- reset(srManager.clusterService);
- clearCache();
-
- // Node 3 should program 1A, 1B and 2
- expect(srManager.clusterService.getLocalNode()).andReturn(new DefaultControllerNode(NODE3, IP3)).anyTimes();
- replay(srManager.clusterService);
- assertTrue(dfh.shouldProgram(DEV1A));
- assertTrue(dfh.shouldProgram(DEV1B));
- assertTrue(dfh.shouldProgram(DEV2));
-
- // Mastership of switch 1A moves to Node 1
- reset(srManager.mastershipService);
- expect(srManager.mastershipService.getMasterFor(DEV1A)).andReturn(NODE1).anyTimes();
- expect(srManager.mastershipService.getMasterFor(DEV1B)).andReturn(NODE2).anyTimes();
- expect(srManager.mastershipService.getMasterFor(DEV2)).andReturn(NODE3).anyTimes();
- replay(srManager.mastershipService);
-
- reset(srManager.clusterService);
- clearCache();
-
- // Node 1 should program 1A, 1B
- expect(srManager.clusterService.getLocalNode()).andReturn(new DefaultControllerNode(NODE1, IP1)).anyTimes();
- replay(srManager.clusterService);
- assertTrue(dfh.shouldProgram(DEV1A));
- assertTrue(dfh.shouldProgram(DEV1B));
- assertFalse(dfh.shouldProgram(DEV2));
-
- reset(srManager.clusterService);
- clearCache();
-
- // Node 2 should program no device
- expect(srManager.clusterService.getLocalNode()).andReturn(new DefaultControllerNode(NODE2, IP2)).anyTimes();
- replay(srManager.clusterService);
- assertFalse(dfh.shouldProgram(DEV1A));
- assertFalse(dfh.shouldProgram(DEV1B));
- assertFalse(dfh.shouldProgram(DEV2));
-
- reset(srManager.clusterService);
- clearCache();
-
- // Node 3 should program 2
- expect(srManager.clusterService.getLocalNode()).andReturn(new DefaultControllerNode(NODE3, IP3)).anyTimes();
- replay(srManager.clusterService);
- assertFalse(dfh.shouldProgram(DEV1A));
- assertFalse(dfh.shouldProgram(DEV1B));
- assertTrue(dfh.shouldProgram(DEV2));
- }
-
- // Node 1 is the master of 1A. 1B has no master
- // Node 2 becomes the master of 1B later
- @Test
- public void testShouldHandleRoutingCase5() {
- expect(srManager.mastershipService.getMasterFor(DEV1A)).andReturn(NODE1).anyTimes();
- expect(srManager.mastershipService.getMasterFor(DEV1B)).andReturn(null).anyTimes();
- replay(srManager.mastershipService);
-
- expect(srManager.getPairDeviceId(DEV1A)).andReturn(Optional.of(DEV1B)).anyTimes();
- expect(srManager.getPairDeviceId(DEV1B)).andReturn(Optional.of(DEV1A)).anyTimes();
- replay(srManager);
-
- // Node 1 should program both 1A and 1B
- expect(srManager.clusterService.getLocalNode()).andReturn(new DefaultControllerNode(NODE1, IP1)).anyTimes();
- replay(srManager.clusterService);
- assertTrue(dfh.shouldProgram(DEV1A));
- assertTrue(dfh.shouldProgram(DEV1B));
-
- reset(srManager.clusterService);
- clearCache();
-
- // Node 2 should program no device
- expect(srManager.clusterService.getLocalNode()).andReturn(new DefaultControllerNode(NODE2, IP2)).anyTimes();
- replay(srManager.clusterService);
- assertFalse(dfh.shouldProgram(DEV1A));
- assertFalse(dfh.shouldProgram(DEV1B));
-
- // Mastership of switch 1B moves to Node 2
- reset(srManager.mastershipService);
- expect(srManager.mastershipService.getMasterFor(DEV1A)).andReturn(NODE1).anyTimes();
- expect(srManager.mastershipService.getMasterFor(DEV1B)).andReturn(NODE2).anyTimes();
- replay(srManager.mastershipService);
-
- reset(srManager.clusterService);
- clearCache();
-
- // Node 1 should program 1A, 1B
- expect(srManager.clusterService.getLocalNode()).andReturn(new DefaultControllerNode(NODE1, IP1)).anyTimes();
- replay(srManager.clusterService);
- assertTrue(dfh.shouldProgram(DEV1A));
- assertTrue(dfh.shouldProgram(DEV1B));
-
- reset(srManager.clusterService);
- clearCache();
-
- // Node 2 should program no device
- expect(srManager.clusterService.getLocalNode()).andReturn(new DefaultControllerNode(NODE2, IP2)).anyTimes();
- replay(srManager.clusterService);
- assertFalse(dfh.shouldProgram(DEV1A));
- assertFalse(dfh.shouldProgram(DEV1B));
- }
-
- // Neither 1A or 1B has master
- @Test
- public void testShouldHandleRoutingCase6() {
- expect(srManager.mastershipService.getMasterFor(DEV1A)).andReturn(null).anyTimes();
- expect(srManager.mastershipService.getMasterFor(DEV1B)).andReturn(null).anyTimes();
- replay(srManager.mastershipService);
-
- expect(srManager.getPairDeviceId(DEV1A)).andReturn(Optional.of(DEV1B)).anyTimes();
- expect(srManager.getPairDeviceId(DEV1B)).andReturn(Optional.of(DEV1A)).anyTimes();
- replay(srManager);
-
- // Node 1 should program no device
- expect(srManager.clusterService.getLocalNode()).andReturn(new DefaultControllerNode(NODE1, IP1)).anyTimes();
- replay(srManager.clusterService);
- assertFalse(dfh.shouldProgram(DEV1A));
- assertFalse(dfh.shouldProgram(DEV1B));
-
- reset(srManager.clusterService);
- clearCache();
-
- // Node 2 should program no device
- expect(srManager.clusterService.getLocalNode()).andReturn(new DefaultControllerNode(NODE2, IP2)).anyTimes();
- replay(srManager.clusterService);
- assertFalse(dfh.shouldProgram(DEV1A));
- assertFalse(dfh.shouldProgram(DEV1B));
-
- assertFalse(dfh.shouldProgram.containsKey(Sets.newHashSet(DEV1A, DEV1B)));
- }
-}
\ No newline at end of file
diff --git a/app/src/test/java/org/onosproject/segmentrouting/HostHandlerTest.java b/app/src/test/java/org/onosproject/segmentrouting/HostHandlerTest.java
deleted file mode 100644
index d67cb07..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/HostHandlerTest.java
+++ /dev/null
@@ -1,1020 +0,0 @@
-/*
- * Copyright 2017-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;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import org.easymock.EasyMock;
-import org.junit.Before;
-import org.junit.Test;
-import org.onlab.packet.EthType;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
-import org.onlab.util.PredictableExecutor;
-import org.onosproject.net.config.ConfigApplyDelegate;
-import org.onosproject.net.host.HostProbingService;
-import org.onosproject.net.host.ProbeMode;
-import org.onosproject.net.intf.Interface;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DefaultHost;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Host;
-import org.onosproject.net.HostId;
-import org.onosproject.net.HostLocation;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.config.NetworkConfigRegistryAdapter;
-import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.host.HostEvent;
-import org.onosproject.net.host.InterfaceIpAddress;
-import org.onosproject.net.provider.ProviderId;
-import org.onosproject.routeservice.ResolvedRoute;
-import org.onosproject.routeservice.Route;
-import org.onosproject.routeservice.RouteInfo;
-import org.onosproject.routeservice.RouteService;
-import org.onosproject.routeservice.RouteTableId;
-import org.onosproject.segmentrouting.config.DeviceConfiguration;
-import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
-import org.onosproject.store.service.StorageService;
-import org.onosproject.store.service.TestConsistentMap;
-import org.onosproject.store.service.TestConsistentMultimap;
-
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-
-import static org.easymock.EasyMock.createMock;
-import static org.easymock.EasyMock.createNiceMock;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.expectLastCall;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.reset;
-import static org.easymock.EasyMock.verify;
-import static org.junit.Assert.*;
-import static org.onlab.util.Tools.groupedThreads;
-
-/**
- * Unit test for {@link HostHandler}.
- */
-public class HostHandlerTest {
- private HostHandler hostHandler;
-
- // Mocked routing and bridging tables
- private static final Map<MockBridgingTableKey, MockBridgingTableValue> BRIDGING_TABLE =
- Maps.newConcurrentMap();
- private static final Map<MockRoutingTableKey, MockRoutingTableValue> ROUTING_TABLE =
- Maps.newConcurrentMap();
- private static final Map<ConnectPoint, Set<IpPrefix>> SUBNET_TABLE = Maps.newConcurrentMap();
- // Mocked Next Id
- private static final Map<Integer, TrafficTreatment> NEXT_TABLE = Maps.newConcurrentMap();
-
- // Host Mac, VLAN
- private static final ProviderId PROVIDER_ID = ProviderId.NONE;
- private static final MacAddress HOST_MAC = MacAddress.valueOf("00:00:00:00:00:01");
- private static final VlanId HOST_VLAN_UNTAGGED = VlanId.NONE;
- private static final HostId HOST_ID_UNTAGGED = HostId.hostId(HOST_MAC, HOST_VLAN_UNTAGGED);
- private static final VlanId HOST_VLAN_TAGGED = VlanId.vlanId((short) 20);
- private static final HostId HOST_ID_TAGGED = HostId.hostId(HOST_MAC, HOST_VLAN_TAGGED);
- // Host IP
- private static final IpAddress HOST_IP11 = IpAddress.valueOf("10.0.1.1");
- private static final IpAddress HOST_IP21 = IpAddress.valueOf("10.0.2.1");
- private static final IpAddress HOST_IP12 = IpAddress.valueOf("10.0.1.2");
- private static final IpAddress HOST_IP13 = IpAddress.valueOf("10.0.1.3");
- private static final IpAddress HOST_IP14 = IpAddress.valueOf("10.0.1.4");
- private static final IpAddress HOST_IP33 = IpAddress.valueOf("10.0.3.3");
- // Device
- private static final DeviceId DEV1 = DeviceId.deviceId("of:0000000000000001");
- private static final DeviceId DEV2 = DeviceId.deviceId("of:0000000000000002");
- private static final DeviceId DEV3 = DeviceId.deviceId("of:0000000000000003");
- private static final DeviceId DEV4 = DeviceId.deviceId("of:0000000000000004");
- private static final DeviceId DEV5 = DeviceId.deviceId("of:0000000000000005");
- private static final DeviceId DEV6 = DeviceId.deviceId("of:0000000000000006");
- // Port
- private static final PortNumber P1 = PortNumber.portNumber(1);
- private static final PortNumber P2 = PortNumber.portNumber(2);
- private static final PortNumber P3 = PortNumber.portNumber(3);
- private static final PortNumber P9 = PortNumber.portNumber(9);
- // Connect Point
- private static final ConnectPoint CP11 = new ConnectPoint(DEV1, P1);
- private static final HostLocation HOST_LOC11 = new HostLocation(CP11, 0);
- private static final ConnectPoint CP12 = new ConnectPoint(DEV1, P2);
- private static final HostLocation HOST_LOC12 = new HostLocation(CP12, 0);
- private static final ConnectPoint CP13 = new ConnectPoint(DEV1, P3);
- private static final HostLocation HOST_LOC13 = new HostLocation(CP13, 0);
- private static final ConnectPoint CP21 = new ConnectPoint(DEV2, P1);
- private static final HostLocation HOST_LOC21 = new HostLocation(CP21, 0);
- private static final ConnectPoint CP22 = new ConnectPoint(DEV2, P2);
- private static final HostLocation HOST_LOC22 = new HostLocation(CP22, 0);
- // Connect Point for dual-homed host failover
- private static final ConnectPoint CP31 = new ConnectPoint(DEV3, P1);
- private static final HostLocation HOST_LOC31 = new HostLocation(CP31, 0);
- private static final ConnectPoint CP32 = new ConnectPoint(DEV3, P2);
- private static final HostLocation HOST_LOC32 = new HostLocation(CP32, 0);
- private static final ConnectPoint CP33 = new ConnectPoint(DEV3, P3);
- private static final HostLocation HOST_LOC33 = new HostLocation(CP33, 0);
- private static final ConnectPoint CP41 = new ConnectPoint(DEV4, P1);
- private static final HostLocation HOST_LOC41 = new HostLocation(CP41, 0);
- private static final ConnectPoint CP42 = new ConnectPoint(DEV4, P2);
- private static final HostLocation HOST_LOC42 = new HostLocation(CP42, 0);
- private static final ConnectPoint CP39 = new ConnectPoint(DEV3, P9);
- private static final ConnectPoint CP49 = new ConnectPoint(DEV4, P9);
- // Conenct Point for mastership test
- private static final ConnectPoint CP51 = new ConnectPoint(DEV5, P1);
- private static final HostLocation HOST_LOC51 = new HostLocation(CP51, 0);
- private static final ConnectPoint CP61 = new ConnectPoint(DEV6, P1);
- private static final HostLocation HOST_LOC61 = new HostLocation(CP61, 0);
- // Interface VLAN
- private static final VlanId INTF_VLAN_UNTAGGED = VlanId.vlanId((short) 10);
- private static final VlanId INTF_VLAN_TAGGED_1 = VlanId.vlanId((short) 20);
- private static final Set<VlanId> INTF_VLAN_TAGGED = Sets.newHashSet(INTF_VLAN_TAGGED_1);
- private static final VlanId INTF_VLAN_NATIVE = VlanId.vlanId((short) 30);
- private static final Set<VlanId> INTF_VLAN_PAIR = Sets.newHashSet(VlanId.vlanId((short) 10),
- VlanId.vlanId((short) 20), VlanId.vlanId((short) 30));
- private static final VlanId INTF_VLAN_OTHER = VlanId.vlanId((short) 40);
- // Interface subnet
- private static final IpPrefix INTF_PREFIX1 = IpPrefix.valueOf("10.0.1.254/24");
- private static final IpPrefix INTF_PREFIX2 = IpPrefix.valueOf("10.0.2.254/24");
- private static final IpPrefix INTF_PREFIX3 = IpPrefix.valueOf("10.0.3.254/24");
- private static final InterfaceIpAddress INTF_IP1 =
- new InterfaceIpAddress(INTF_PREFIX1.address(), INTF_PREFIX1);
- private static final InterfaceIpAddress INTF_IP2 =
- new InterfaceIpAddress(INTF_PREFIX2.address(), INTF_PREFIX2);
- private static final InterfaceIpAddress INTF_IP3 =
- new InterfaceIpAddress(INTF_PREFIX3.address(), INTF_PREFIX3);
- // Interfaces
- private static final Interface INTF11 =
- new Interface(null, CP11, Lists.newArrayList(INTF_IP1), MacAddress.NONE, null,
- INTF_VLAN_UNTAGGED, null, null);
- private static final Interface INTF12 =
- new Interface(null, CP12, Lists.newArrayList(INTF_IP1), MacAddress.NONE, null,
- INTF_VLAN_UNTAGGED, null, null);
- private static final Interface INTF13 =
- new Interface(null, CP13, Lists.newArrayList(INTF_IP2), MacAddress.NONE, null,
- null, INTF_VLAN_TAGGED, INTF_VLAN_NATIVE);
- private static final Interface INTF21 =
- new Interface(null, CP21, Lists.newArrayList(INTF_IP1), MacAddress.NONE, null,
- INTF_VLAN_UNTAGGED, null, null);
- private static final Interface INTF22 =
- new Interface(null, CP22, Lists.newArrayList(INTF_IP1), MacAddress.NONE, null,
- INTF_VLAN_UNTAGGED, null, null);
- private static final Interface INTF31 =
- new Interface(null, CP31, Lists.newArrayList(INTF_IP1), MacAddress.NONE, null,
- INTF_VLAN_UNTAGGED, null, null);
- private static final Interface INTF32 =
- new Interface(null, CP32, Lists.newArrayList(INTF_IP1), MacAddress.NONE, null,
- INTF_VLAN_UNTAGGED, null, null);
- private static final Interface INTF33 =
- new Interface(null, CP33, Lists.newArrayList(INTF_IP3), MacAddress.NONE, null,
- INTF_VLAN_OTHER, null, null);
- private static final Interface INTF39 =
- new Interface(null, CP39, Lists.newArrayList(INTF_IP1), MacAddress.NONE, null,
- null, INTF_VLAN_PAIR, null);
- private static final Interface INTF41 =
- new Interface(null, CP41, Lists.newArrayList(INTF_IP1), MacAddress.NONE, null,
- INTF_VLAN_UNTAGGED, null, null);
- private static final Interface INTF42 =
- new Interface(null, CP42, Lists.newArrayList(INTF_IP1), MacAddress.NONE, null,
- INTF_VLAN_UNTAGGED, null, null);
- private static final Interface INTF49 =
- new Interface(null, CP49, Lists.newArrayList(INTF_IP1), MacAddress.NONE, null,
- null, INTF_VLAN_PAIR, null);
- // Host
- private static final Host HOST1 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC,
- HOST_VLAN_UNTAGGED, Sets.newHashSet(HOST_LOC11, HOST_LOC21), Sets.newHashSet(HOST_IP11),
- false);
-
- // A set of hosts
- private static final Set<Host> HOSTS = Sets.newHashSet(HOST1);
- // A set of devices of which we have mastership
- private static final Set<DeviceId> LOCAL_DEVICES = Sets.newHashSet(DEV1, DEV2, DEV3, DEV4);
- // A set of interfaces
- private static final Set<Interface> INTERFACES = Sets.newHashSet(INTF11, INTF12, INTF13, INTF21,
- INTF22, INTF31, INTF32, INTF33, INTF39, INTF41, INTF42, INTF49);
-
- private MockHostProbingService mockLocationProbingService;
-
- @Before
- public void setUp() {
- // Initialize pairDevice and pairLocalPort config
- ObjectMapper mapper = new ObjectMapper();
- ConfigApplyDelegate delegate = config -> { };
-
- SegmentRoutingDeviceConfig dev3Config = new SegmentRoutingDeviceConfig();
- JsonNode dev3Tree = mapper.createObjectNode();
- dev3Config.init(DEV3, "host-handler-test", dev3Tree, mapper, delegate);
- dev3Config.setPairDeviceId(DEV4).setPairLocalPort(P9);
-
- SegmentRoutingDeviceConfig dev4Config = new SegmentRoutingDeviceConfig();
- JsonNode dev4Tree = mapper.createObjectNode();
- dev4Config.init(DEV4, "host-handler-test", dev4Tree, mapper, delegate);
- dev4Config.setPairDeviceId(DEV3).setPairLocalPort(P9);
-
- MockNetworkConfigRegistry mockNetworkConfigRegistry = new MockNetworkConfigRegistry();
- mockNetworkConfigRegistry.applyConfig(dev3Config);
- mockNetworkConfigRegistry.applyConfig(dev4Config);
-
- // Initialize Segment Routing Manager
- SegmentRoutingManager srManager = new MockSegmentRoutingManager(NEXT_TABLE);
- srManager.storageService = createMock(StorageService.class);
- expect(srManager.storageService.consistentMapBuilder()).andReturn(new TestConsistentMap.Builder<>()).anyTimes();
- expect(srManager.storageService.consistentMultimapBuilder()).andReturn(
- new TestConsistentMultimap.Builder<>()).anyTimes();
- replay(srManager.storageService);
- srManager.cfgService = new NetworkConfigRegistryAdapter();
- srManager.deviceConfiguration = new DeviceConfiguration(srManager);
- srManager.flowObjectiveService = new MockFlowObjectiveService(BRIDGING_TABLE, NEXT_TABLE);
- srManager.routingRulePopulator = new MockRoutingRulePopulator(srManager, ROUTING_TABLE);
- srManager.defaultRoutingHandler = new MockDefaultRoutingHandler(srManager, SUBNET_TABLE, ROUTING_TABLE);
- srManager.interfaceService = new MockInterfaceService(INTERFACES);
- srManager.mastershipService = new MockMastershipService(LOCAL_DEVICES);
- srManager.hostService = new MockHostService(HOSTS);
- srManager.cfgService = mockNetworkConfigRegistry;
- mockLocationProbingService = new MockHostProbingService();
- srManager.probingService = mockLocationProbingService;
- srManager.linkHandler = new MockLinkHandler(srManager);
-
- // Not important for most of the HostHandler test case. Simply return an empty set here
- srManager.routeService = createNiceMock(RouteService.class);
- expect(srManager.routeService.getRouteTables()).andReturn(Sets.newHashSet()).anyTimes();
- replay(srManager.routeService);
-
- hostHandler = new HostHandler(srManager);
- hostHandler.hostWorkers = new PredictableExecutor(
- 0, groupedThreads("onos/sr", "h-worker-%d"), true);
-
- ROUTING_TABLE.clear();
- BRIDGING_TABLE.clear();
- }
-
- @Test
- public void init() {
- hostHandler.init(DEV1);
- assertEquals(1, ROUTING_TABLE.size());
- assertNotNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
- assertEquals(1, BRIDGING_TABLE.size());
- assertNotNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
-
- hostHandler.init(DEV2);
- assertEquals(2, ROUTING_TABLE.size());
- assertNotNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
- assertNotNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV2, HOST_IP11.toIpPrefix())));
- assertEquals(2, BRIDGING_TABLE.size());
- assertNotNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
- assertNotNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)));
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testHostAddedAtWrongLocation() {
- hostHandler.processHostAddedAtLocation(HOST1, HOST_LOC13);
- }
-
-
- @Test()
- public void testHostAddedAtCorrectLocation() {
- hostHandler.processHostAddedAtLocation(HOST1, HOST_LOC11);
- assertEquals(1, ROUTING_TABLE.size());
- assertNotNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
- assertEquals(1, BRIDGING_TABLE.size());
- assertNotNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
- }
-
- @Test
- public void testHostAdded() {
- Host subject;
-
- // Untagged host discovered on untagged port
- // Expect: add one routing rule and one bridging rule
- subject = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC11), Sets.newHashSet(HOST_IP11), false);
- hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, subject));
- assertEquals(1, ROUTING_TABLE.size());
- assertNotNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
- assertEquals(1, BRIDGING_TABLE.size());
- assertNotNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
-
- // Untagged host discovered on tagged/native port
- // Expect: add one routing rule and one bridging rule
- subject = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC13), Sets.newHashSet(HOST_IP21), false);
- hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, subject));
- assertEquals(2, ROUTING_TABLE.size());
- assertNotNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP21.toIpPrefix())));
- assertEquals(2, BRIDGING_TABLE.size());
- assertNotNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_NATIVE)));
-
- // Tagged host discovered on untagged port
- // Expect: ignore the host. No rule is added.
- subject = new DefaultHost(PROVIDER_ID, HOST_ID_TAGGED, HOST_MAC, HOST_VLAN_TAGGED,
- Sets.newHashSet(HOST_LOC11), Sets.newHashSet(HOST_IP11), false);
- hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, subject));
- assertEquals(2, ROUTING_TABLE.size());
- assertEquals(2, BRIDGING_TABLE.size());
-
- // Tagged host discovered on tagged port with the same IP
- // Expect: update existing route, add one bridging rule
- subject = new DefaultHost(PROVIDER_ID, HOST_ID_TAGGED, HOST_MAC, HOST_VLAN_TAGGED,
- Sets.newHashSet(HOST_LOC13), Sets.newHashSet(HOST_IP21), false);
- hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, subject));
- assertEquals(2, ROUTING_TABLE.size());
- assertNotNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP21.toIpPrefix())));
- assertEquals(HOST_VLAN_TAGGED, ROUTING_TABLE.get(new MockRoutingTableKey(HOST_LOC13.deviceId(),
- HOST_IP21.toIpPrefix())).vlanId);
- assertEquals(3, BRIDGING_TABLE.size());
- assertNotNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, HOST_VLAN_TAGGED)));
- }
-
- @Test
- public void testDualHomedHostAdded() {
- // Add a dual-homed host that has 2 locations
- // Expect: add two routing rules and two bridging rules
- Host subject = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC11, HOST_LOC21), Sets.newHashSet(HOST_IP11), false);
- hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, subject));
- assertEquals(2, ROUTING_TABLE.size());
- assertNotNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
- assertNotNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV2, HOST_IP11.toIpPrefix())));
- assertEquals(2, BRIDGING_TABLE.size());
- assertNotNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
- assertNotNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)));
- }
-
- @Test
- public void testSingleHomedHostAddedOnPairLeaf() {
- Host host1 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC33), Sets.newHashSet(HOST_IP33), false);
-
- // Add a single-homed host with one location
- // Expect: the pair link should not be utilized
- hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, host1));
- assertEquals(1, ROUTING_TABLE.size());
- assertEquals(P3, ROUTING_TABLE.get(new MockRoutingTableKey(DEV3, HOST_IP33.toIpPrefix())).portNumber);
- assertEquals(1, BRIDGING_TABLE.size());
- assertEquals(P3, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV3, HOST_MAC, INTF_VLAN_OTHER)).portNumber);
- }
-
- @Test
- public void testDualHomedHostAddedOneByOne() {
- Host host1 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC31), Sets.newHashSet(HOST_IP11), false);
- Host host2 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC31, HOST_LOC41), Sets.newHashSet(HOST_IP11), false);
-
- // Add a dual-homed host with one location
- // Expect: the pair link is utilized temporarily before the second location is discovered
- hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, host1));
- assertEquals(2, ROUTING_TABLE.size());
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV3, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(P9, ROUTING_TABLE.get(new MockRoutingTableKey(DEV4, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(2, BRIDGING_TABLE.size());
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV3, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
- assertEquals(P9, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV4, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
- // Expect probe to be sent out on pair device
- assertTrue(mockLocationProbingService.verifyProbe(host1, CP41, ProbeMode.DISCOVER));
-
- // Add the second location of dual-homed host
- // Expect: no longer use the pair link
- hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host2, host1));
- assertEquals(2, ROUTING_TABLE.size());
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV3, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV4, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(2, BRIDGING_TABLE.size());
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV3, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV4, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
- }
-
- @Test
- public void testHostRemoved() {
- Host subject = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC11), Sets.newHashSet(HOST_IP11), false);
-
- // Add a host
- // Expect: add one routing rule and one bridging rule
- hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, subject));
- assertEquals(1, ROUTING_TABLE.size());
- assertNotNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
- assertEquals(1, BRIDGING_TABLE.size());
- assertNotNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
-
- // Remove the host
- // Expect: add the routing rule and the bridging rule
- hostHandler.processHostRemovedEvent(new HostEvent(HostEvent.Type.HOST_REMOVED, subject));
- assertEquals(0, ROUTING_TABLE.size());
- assertEquals(0, BRIDGING_TABLE.size());
- }
-
- @Test
- public void testDualHomedHostRemoved() {
- // Add a dual-homed host that has 2 locations
- // Expect: add two routing rules and two bridging rules
- Host subject = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC11, HOST_LOC21), Sets.newHashSet(HOST_IP11), false);
- hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, subject));
- assertEquals(2, ROUTING_TABLE.size());
- assertNotNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
- assertNotNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV2, HOST_IP11.toIpPrefix())));
- assertEquals(2, BRIDGING_TABLE.size());
- assertNotNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
- assertNotNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)));
-
- // Remove a dual-homed host that has 2 locations
- // Expect: all routing and bridging rules are removed
- hostHandler.processHostRemovedEvent(new HostEvent(HostEvent.Type.HOST_REMOVED, subject));
- assertEquals(0, ROUTING_TABLE.size());
- assertEquals(0, BRIDGING_TABLE.size());
- }
-
- @Test
- public void testHostMoved() {
- Host host1 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC11), Sets.newHashSet(HOST_IP11), false);
- Host host2 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC21), Sets.newHashSet(HOST_IP11), false);
- Host host3 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC13), Sets.newHashSet(HOST_IP11), false);
-
- // Add a host
- // Expect: add one new routing rule, one new bridging rule
- hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, host1));
- assertEquals(1, ROUTING_TABLE.size());
- assertNotNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
- assertNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP21.toIpPrefix())));
- assertNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP13.toIpPrefix())));
- assertEquals(1, BRIDGING_TABLE.size());
- assertNotNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
- assertNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)));
-
- // Move the host to CP13, which has different subnet setting
- // Expect: remove routing rule. Change vlan in bridging rule.
- hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host3, host1));
- assertEquals(0, ROUTING_TABLE.size());
- assertEquals(1, BRIDGING_TABLE.size());
- assertNotNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_NATIVE)));
- assertNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
-
- // Move the host to CP21, which has same subnet setting
- // Expect: add a new routing rule. Change vlan in bridging rule.
- hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host2, host3));
- assertEquals(1, ROUTING_TABLE.size());
- assertNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
- assertNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
- assertNotNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV2, HOST_IP11.toIpPrefix())));
- assertEquals(1, BRIDGING_TABLE.size());
- assertNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
- assertNotNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)));
- }
-
- @Test
- public void testDualHomedHostMoved() {
- Host host1 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC11, HOST_LOC21), Sets.newHashSet(HOST_IP11, HOST_IP12), false);
- Host host2 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC12, HOST_LOC22), Sets.newHashSet(HOST_IP11, HOST_IP12), false);
- Host host3 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC11, HOST_LOC21), Sets.newHashSet(HOST_IP13, HOST_IP14), false);
- Host host4 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC11, HOST_LOC22), Sets.newHashSet(HOST_IP12, HOST_IP13), false);
- Host host5 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC12, HOST_LOC21), Sets.newHashSet(HOST_IP11, HOST_IP12), false);
-
-
- // Add a host with IP11, IP12 and LOC11, LOC21
- // Expect: 4 routing rules and 2 bridging rules
- hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, host1));
- assertEquals(4, ROUTING_TABLE.size());
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP12.toIpPrefix())).portNumber);
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV2, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV2, HOST_IP12.toIpPrefix())).portNumber);
- assertEquals(2, BRIDGING_TABLE.size());
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
-
- // Move the host to LOC12, LOC21 and keep the IP
- // Expect: 4 routing rules and 2 bridging rules all at the new location
- hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host5, host1));
- assertEquals(4, ROUTING_TABLE.size());
- assertEquals(P2, ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(P2, ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP12.toIpPrefix())).portNumber);
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV2, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV2, HOST_IP12.toIpPrefix())).portNumber);
- assertEquals(2, BRIDGING_TABLE.size());
- assertEquals(P2, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
-
- // Move the host to LOC12, LOC22 and keep the IP
- // Expect: 4 routing rules and 2 bridging rules all at the new location
- hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host2, host5));
- assertEquals(4, ROUTING_TABLE.size());
- assertEquals(P2, ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(P2, ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP12.toIpPrefix())).portNumber);
- assertEquals(P2, ROUTING_TABLE.get(new MockRoutingTableKey(DEV2, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(P2, ROUTING_TABLE.get(new MockRoutingTableKey(DEV2, HOST_IP12.toIpPrefix())).portNumber);
- assertEquals(2, BRIDGING_TABLE.size());
- assertEquals(P2, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
- assertEquals(P2, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
-
- // Move the host to LOC11, LOC21 and change the IP to IP13, IP14 at the same time
- // Expect: 4 routing rules and 2 bridging rules all at the new location
- hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host3, host2));
- assertEquals(4, ROUTING_TABLE.size());
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP13.toIpPrefix())).portNumber);
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP14.toIpPrefix())).portNumber);
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV2, HOST_IP13.toIpPrefix())).portNumber);
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV2, HOST_IP14.toIpPrefix())).portNumber);
- assertEquals(2, BRIDGING_TABLE.size());
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
-
- // Move the host to LOC11, LOC22 and change the IP to IP12, IP13 at the same time
- // Expect: 4 routing rules and 2 bridging rules all at the new location
- hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host4, host3));
- assertEquals(4, ROUTING_TABLE.size());
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP12.toIpPrefix())).portNumber);
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP13.toIpPrefix())).portNumber);
- assertEquals(P2, ROUTING_TABLE.get(new MockRoutingTableKey(DEV2, HOST_IP12.toIpPrefix())).portNumber);
- assertEquals(P2, ROUTING_TABLE.get(new MockRoutingTableKey(DEV2, HOST_IP13.toIpPrefix())).portNumber);
- assertEquals(2, BRIDGING_TABLE.size());
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
- assertEquals(P2, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
- }
-
- @Test
- public void testDualHomedHostMoveTransient() {
- Host host1 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC31, HOST_LOC41), Sets.newHashSet(HOST_IP11), false);
- Host host2 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC32, HOST_LOC41), Sets.newHashSet(HOST_IP11), false);
- hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, host1));
-
- // Mock DefaultRoutingHandler
- DefaultRoutingHandler mockDefaultRoutingHandler = createMock(DefaultRoutingHandler.class);
- hostHandler.srManager.defaultRoutingHandler = mockDefaultRoutingHandler;
-
- // Host moved from [1A/1, 1B/1] to [1A/2, 1B/1]
- // We should expect only one bridging flow and one routing flow programmed on 1A
-
- expect(mockDefaultRoutingHandler.populateBridging(DEV3, P2, HOST_MAC, HOST_VLAN_UNTAGGED))
- .andReturn(CompletableFuture.completedFuture(null)).once();
- expect(mockDefaultRoutingHandler.populateRoute(DEV3, HOST_IP11.toIpPrefix(),
- HOST_MAC, HOST_VLAN_UNTAGGED, P2, true))
- .andReturn(CompletableFuture.completedFuture(null)).once();
- replay(mockDefaultRoutingHandler);
-
- hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host2, host1));
- verify(mockDefaultRoutingHandler);
- }
-
- @Test
- public void testHostMoveToInvalidLocation() {
- Host host1 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC11), Sets.newHashSet(HOST_IP11), false);
- Host host2 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC51), Sets.newHashSet(HOST_IP11), false);
-
- // Add a host
- // Expect: add one new routing rule, one new bridging rule
- hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, host1));
- assertEquals(1, ROUTING_TABLE.size());
- assertNotNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
- assertNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP21.toIpPrefix())));
- assertEquals(1, BRIDGING_TABLE.size());
- assertNotNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
- assertNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)));
-
- // Move the host to an invalid location
- // Expect: Old flow is removed. New flow is not created
- hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host2, host1));
- assertEquals(0, ROUTING_TABLE.size());
- assertEquals(0, BRIDGING_TABLE.size());
-
- // Move the host to a valid location
- // Expect: add one new routing rule, one new bridging rule
- hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host1, host2));
- assertEquals(1, ROUTING_TABLE.size());
- assertNotNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
- assertNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP21.toIpPrefix())));
- assertEquals(1, BRIDGING_TABLE.size());
- assertNotNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
- assertNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)));
- }
-
- @Test
- public void testDualHomedHostMoveToInvalidLocation() {
- Host host1 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC11, HOST_LOC21), Sets.newHashSet(HOST_IP11), false);
- Host host2 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC11, HOST_LOC51), Sets.newHashSet(HOST_IP11), false);
- Host host3 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC61, HOST_LOC51), Sets.newHashSet(HOST_IP11), false);
-
- // Add a host
- // Expect: add two new routing rules, two new bridging rules
- hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, host1));
- assertEquals(2, ROUTING_TABLE.size());
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV2, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(2, BRIDGING_TABLE.size());
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
-
- // Move first host location to an invalid location
- // Expect: One routing and one bridging flow
- hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host2, host1));
- assertEquals(1, ROUTING_TABLE.size());
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(1, BRIDGING_TABLE.size());
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
-
- // Move second host location to an invalid location
- // Expect: No routing or bridging rule
- hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host3, host2));
- assertEquals(0, ROUTING_TABLE.size());
- assertEquals(0, BRIDGING_TABLE.size());
-
- // Move second host location back to a valid location
- // Expect: One routing and one bridging flow
- hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host2, host3));
- assertEquals(1, ROUTING_TABLE.size());
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(1, BRIDGING_TABLE.size());
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
-
- // Move first host location back to a valid location
- // Expect: Two routing and two bridging flow
- hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host1, host2));
- assertEquals(2, ROUTING_TABLE.size());
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV2, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(2, BRIDGING_TABLE.size());
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
- }
-
- @Test
- public void testDualHomingSingleLocationFail() {
- Host host1 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC31, HOST_LOC41), Sets.newHashSet(HOST_IP11, HOST_IP12), false);
- Host host2 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC31), Sets.newHashSet(HOST_IP11, HOST_IP12), false);
-
- // Add a host
- // Expect: add four new routing rules, two new bridging rules
- hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, host1));
- assertEquals(4, ROUTING_TABLE.size());
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV3, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV3, HOST_IP12.toIpPrefix())).portNumber);
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV4, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV4, HOST_IP12.toIpPrefix())).portNumber);
- assertEquals(2, BRIDGING_TABLE.size());
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV3, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV4, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
-
- // Host becomes single-homed
- // Expect: redirect flows from host location to pair link
- hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host2, host1));
- assertEquals(4, ROUTING_TABLE.size());
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV3, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV3, HOST_IP12.toIpPrefix())).portNumber);
- assertEquals(P9, ROUTING_TABLE.get(new MockRoutingTableKey(DEV4, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(P9, ROUTING_TABLE.get(new MockRoutingTableKey(DEV4, HOST_IP12.toIpPrefix())).portNumber);
- assertEquals(2, BRIDGING_TABLE.size());
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV3, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
- assertEquals(P9, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV4, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
-
- // Host becomes dual-homed again
- // Expect: Redirect flows from pair link back to host location
- hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host1, host2));
- assertEquals(4, ROUTING_TABLE.size());
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV3, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV3, HOST_IP12.toIpPrefix())).portNumber);
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV4, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV4, HOST_IP12.toIpPrefix())).portNumber);
- assertEquals(2, BRIDGING_TABLE.size());
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV3, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV4, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
- }
-
- @Test
- public void testDualHomingBothLocationFail() {
- Host host1 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC31, HOST_LOC41), Sets.newHashSet(HOST_IP11, HOST_IP12), false);
- Host host2 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC31), Sets.newHashSet(HOST_IP11, HOST_IP12), false);
-
- // Add a host
- // Expect: add four new routing rules, two new bridging rules
- hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, host1));
- assertEquals(4, ROUTING_TABLE.size());
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV3, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV3, HOST_IP12.toIpPrefix())).portNumber);
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV4, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV4, HOST_IP12.toIpPrefix())).portNumber);
- assertEquals(2, BRIDGING_TABLE.size());
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV3, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV4, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
-
- // Host becomes single-homed
- // Expect: redirect flows from host location to pair link
- hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host2, host1));
- assertEquals(4, ROUTING_TABLE.size());
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV3, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV3, HOST_IP12.toIpPrefix())).portNumber);
- assertEquals(P9, ROUTING_TABLE.get(new MockRoutingTableKey(DEV4, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(P9, ROUTING_TABLE.get(new MockRoutingTableKey(DEV4, HOST_IP12.toIpPrefix())).portNumber);
- assertEquals(2, BRIDGING_TABLE.size());
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV3, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
- assertEquals(P9, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV4, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
-
- // Host loses both locations
- // Expect: Remove last location and all previous redirection flows
- hostHandler.processHostRemovedEvent(new HostEvent(HostEvent.Type.HOST_REMOVED, host2));
- assertEquals(0, ROUTING_TABLE.size());
- assertEquals(0, BRIDGING_TABLE.size());
- }
-
- @Test
- public void testHostUpdated() {
- Host host1 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC11), Sets.newHashSet(HOST_IP11), false);
- Host host2 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC11), Sets.newHashSet(HOST_IP21), false);
- Host host3 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC11), Sets.newHashSet(HOST_IP12), false);
-
- // Add a host
- // Expect: add one new routing rule. Add one new bridging rule.
- hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, host1));
- assertEquals(1, ROUTING_TABLE.size());
- assertNotNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
- assertNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP21.toIpPrefix())));
- assertNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP12.toIpPrefix())));
- assertEquals(1, BRIDGING_TABLE.size());
- assertNotNull(BRIDGING_TABLE.get(new MockBridgingTableKey(HOST_LOC11.deviceId(), HOST_MAC,
- INTF_VLAN_UNTAGGED)));
-
- // Update the host IP to same subnet
- // Expect: update routing rule with new IP. No change to bridging rule.
- hostHandler.processHostUpdatedEvent(new HostEvent(HostEvent.Type.HOST_UPDATED, host3, host1));
- assertEquals(1, ROUTING_TABLE.size());
- assertNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
- assertNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP21.toIpPrefix())));
- assertNotNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP12.toIpPrefix())));
- assertEquals(1, BRIDGING_TABLE.size());
- assertNotNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
-
- // Update the host IP to different subnet
- // Expect: Remove routing rule. No change to bridging rule.
- hostHandler.processHostUpdatedEvent(new HostEvent(HostEvent.Type.HOST_UPDATED, host2, host3));
- assertEquals(0, ROUTING_TABLE.size());
- assertEquals(1, BRIDGING_TABLE.size());
- assertNotNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
- }
-
- @Test
- public void testDelayedIpAndLocation() {
- Host host1 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC31), Sets.newHashSet(), false);
- Host host2 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC31), Sets.newHashSet(HOST_IP11), false);
- Host host3 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC31, HOST_LOC41), Sets.newHashSet(HOST_IP11), false);
-
- // Add a dual-home host with only one location and no IP
- // Expect: only bridging redirection works
- hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, host1));
- assertEquals(0, ROUTING_TABLE.size());
- assertEquals(2, BRIDGING_TABLE.size());
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV3, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
- assertEquals(P9, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV4, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
-
- // Discover IP
- // Expect: routing redirection should also work
- hostHandler.processHostUpdatedEvent(new HostEvent(HostEvent.Type.HOST_UPDATED, host2, host1));
- assertEquals(2, ROUTING_TABLE.size());
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV3, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(P9, ROUTING_TABLE.get(new MockRoutingTableKey(DEV4, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(2, BRIDGING_TABLE.size());
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV3, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
- assertEquals(P9, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV4, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
- // Expect probe to be sent out on pair device
- assertTrue(mockLocationProbingService.verifyProbe(host2, CP41, ProbeMode.DISCOVER));
-
- // Discover location
- // Expect: cancel all redirections
- hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host3, host2));
- assertEquals(2, ROUTING_TABLE.size());
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV3, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV4, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(2, BRIDGING_TABLE.size());
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV3, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV4, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV4, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV4, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
- }
-
- @Test
- public void testDelayedIpAndLocation2() {
- Host host1 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC31), Sets.newHashSet(), false);
- Host host2 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC31, HOST_LOC41), Sets.newHashSet(), false);
- Host host3 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC31, HOST_LOC41), Sets.newHashSet(HOST_IP11), false);
-
- // Add a dual-home host with only one location and no IP
- // Expect: only bridging redirection works
- hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, host1));
- assertEquals(0, ROUTING_TABLE.size());
- assertEquals(2, BRIDGING_TABLE.size());
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV3, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
- assertEquals(P9, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV4, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
-
- // Discover Location
- // Expect: cancel bridging redirections
- hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host2, host1));
- assertEquals(0, ROUTING_TABLE.size());
- assertEquals(2, BRIDGING_TABLE.size());
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV3, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV4, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
-
- // Discover IP
- // Expect: add IP rules to both location
- hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_UPDATED, host3, host2));
- assertEquals(2, ROUTING_TABLE.size());
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV3, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV4, HOST_IP11.toIpPrefix())).portNumber);
- assertEquals(2, BRIDGING_TABLE.size());
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV3, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
- assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV4, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
- }
-
- @Test
- public void testDualHomedHostUpdated() {
- Host host1 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC11, HOST_LOC21), Sets.newHashSet(HOST_IP11, HOST_IP12), false);
- Host host2 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC11, HOST_LOC21), Sets.newHashSet(HOST_IP11, HOST_IP21), false);
- Host host3 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC11, HOST_LOC21), Sets.newHashSet(HOST_IP13, HOST_IP14), false);
-
- // Add a dual-homed host with two locations and two IPs
- // Expect: add four new routing rules. Add two new bridging rules
- hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, host1));
- assertEquals(4, ROUTING_TABLE.size());
- assertNotNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
- assertNotNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP12.toIpPrefix())));
- assertNotNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV2, HOST_IP11.toIpPrefix())));
- assertNotNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV2, HOST_IP12.toIpPrefix())));
- assertEquals(2, BRIDGING_TABLE.size());
- assertNotNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
- assertNotNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)));
-
- // Update both host IPs
- // Expect: update routing rules with new IP. No change to bridging rule.
- hostHandler.processHostUpdatedEvent(new HostEvent(HostEvent.Type.HOST_UPDATED, host3, host1));
- assertEquals(4, ROUTING_TABLE.size());
- assertNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
- assertNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP12.toIpPrefix())));
- assertNotNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP13.toIpPrefix())));
- assertNotNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP14.toIpPrefix())));
- assertNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV2, HOST_IP11.toIpPrefix())));
- assertNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV2, HOST_IP12.toIpPrefix())));
- assertNotNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV2, HOST_IP13.toIpPrefix())));
- assertNotNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV2, HOST_IP14.toIpPrefix())));
- assertEquals(2, BRIDGING_TABLE.size());
- assertNotNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
- assertNotNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)));
-
- // Update one of the host IP to different subnet
- // Expect: update routing rule with new IP. No change to bridging rule.
- hostHandler.processHostUpdatedEvent(new HostEvent(HostEvent.Type.HOST_UPDATED, host2, host3));
- assertEquals(2, ROUTING_TABLE.size());
- assertNotNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
- assertNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP21.toIpPrefix())));
- assertNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP12.toIpPrefix())));
- assertNotNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV2, HOST_IP11.toIpPrefix())));
- assertNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV2, HOST_IP21.toIpPrefix())));
- assertNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV2, HOST_IP12.toIpPrefix())));
- assertEquals(2, BRIDGING_TABLE.size());
- assertNotNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
- assertNotNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)));
- }
-
- @Test
- public void testVlanForPairPort() {
- assertEquals(INTF_VLAN_UNTAGGED, hostHandler.vlanForPairPort(VlanId.NONE, CP11));
- assertEquals(INTF_VLAN_NATIVE, hostHandler.vlanForPairPort(VlanId.NONE, CP13));
- assertEquals(INTF_VLAN_TAGGED_1, hostHandler.vlanForPairPort(INTF_VLAN_TAGGED_1, CP13));
- assertNull(hostHandler.vlanForPairPort(INTF_VLAN_UNTAGGED, CP11));
- assertNull(hostHandler.vlanForPairPort(INTF_VLAN_UNTAGGED, CP13));
- assertNull(hostHandler.vlanForPairPort(VlanId.NONE, CP51));
- assertNull(hostHandler.vlanForPairPort(INTF_VLAN_UNTAGGED, CP51));
- }
-
- @Test
- public void testHostRemovedWithRouteRemoved() {
- Host subject = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC11), Sets.newHashSet(HOST_IP11), false);
-
- // Add a host
- // Expect: add one routing rule and one bridging rule
- hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, subject));
- assertEquals(1, ROUTING_TABLE.size());
- assertNotNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
- assertEquals(1, BRIDGING_TABLE.size());
- assertNotNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
-
- IpPrefix prefix = IpPrefix.valueOf("55.55.55.0/24");
-
- // Setting up mock route service
- RouteService routeService = hostHandler.srManager.routeService;
- reset(routeService);
-
- IpAddress nextHopIp2 = IpAddress.valueOf("20.0.0.1");
- MacAddress nextHopMac2 = MacAddress.valueOf("00:22:33:44:55:66");
- VlanId nextHopVlan2 = VlanId.NONE;
-
- Route r1 = new Route(Route.Source.STATIC, prefix, HOST_IP11);
- ResolvedRoute rr1 = new ResolvedRoute(r1, HOST_MAC, VlanId.NONE);
- Route r2 = new Route(Route.Source.STATIC, prefix, nextHopIp2);
- ResolvedRoute rr2 = new ResolvedRoute(r2, nextHopMac2, nextHopVlan2);
- RouteInfo routeInfo = new RouteInfo(prefix, rr1, Sets.newHashSet(rr1, rr2));
- RouteTableId routeTableId = new RouteTableId("ipv4");
-
- expect(routeService.getRouteTables()).andReturn(Sets.newHashSet(routeTableId));
- expect(routeService.getRoutes(routeTableId)).andReturn(Sets.newHashSet(routeInfo));
- replay(routeService);
-
- // Setting up mock device configuration
- hostHandler.srManager.deviceConfiguration = EasyMock.createNiceMock(DeviceConfiguration.class);
- DeviceConfiguration deviceConfiguration = hostHandler.srManager.deviceConfiguration;
- expect(deviceConfiguration.inSameSubnet(CP11, HOST_IP11)).andReturn(true);
- deviceConfiguration.removeSubnet(CP11, prefix);
- expectLastCall();
- replay(deviceConfiguration);
-
- // Remove the host
- // Expect: add the routing rule and the bridging rule
- hostHandler.processHostRemovedEvent(new HostEvent(HostEvent.Type.HOST_REMOVED, subject));
- assertEquals(0, ROUTING_TABLE.size());
- assertEquals(0, BRIDGING_TABLE.size());
-
- // Expect: subnet is removed from device config
- verify(deviceConfiguration);
- }
-
- @Test
- public void testHostProbing() {
- // Case: [1A/1, 1B/1] -> [1A/2, 1B/1]
- // Expect: DISCOVER probe should be sent to every port on 1B that has the same VLAN as 1A/2
- // VERIFY probe should be sent to 1B/1
- Host host1 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC31, HOST_LOC41), Sets.newHashSet(HOST_IP11), false);
- Host host2 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
- Sets.newHashSet(HOST_LOC32, HOST_LOC41), Sets.newHashSet(HOST_IP11), false);
- hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, host1));
-
- hostHandler.srManager.probingService = createMock(HostProbingService.class);
- hostHandler.srManager.probingService.probeHost(host2, CP41, ProbeMode.DISCOVER);
- expectLastCall();
- hostHandler.srManager.probingService.probeHost(host2, CP42, ProbeMode.DISCOVER);
- expectLastCall();
- hostHandler.srManager.probingService.probeHost(host2, CP41, ProbeMode.VERIFY);
- expectLastCall();
- replay(hostHandler.srManager.probingService);
-
- hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host2, host1));
-
- verify(hostHandler.srManager.probingService);
- }
-
- @Test
- public void testEffectiveLocations() {
- Host regularHost = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_TAGGED,
- Sets.newHashSet(HOST_LOC11, HOST_LOC12), Sets.newHashSet(HOST_IP11), false);
- Host auxHost = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_TAGGED,
- Sets.newHashSet(HOST_LOC11, HOST_LOC12), Sets.newHashSet(HOST_LOC21, HOST_LOC22),
- Sets.newHashSet(HOST_IP11), VlanId.NONE, EthType.EtherType.UNKNOWN.ethType(), false, false);
-
- assertEquals(Sets.newHashSet(HOST_LOC11, HOST_LOC12), hostHandler.effectiveLocations(regularHost));
- assertEquals(Sets.newHashSet(HOST_LOC21, HOST_LOC22), hostHandler.effectiveLocations(auxHost));
- }
-}
diff --git a/app/src/test/java/org/onosproject/segmentrouting/IcmpHandlerTest.java b/app/src/test/java/org/onosproject/segmentrouting/IcmpHandlerTest.java
deleted file mode 100644
index 68472de..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/IcmpHandlerTest.java
+++ /dev/null
@@ -1,795 +0,0 @@
-/*
- * 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;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ArrayNode;
-import com.google.common.collect.ImmutableSet;
-import org.junit.Before;
-import org.junit.Test;
-import org.onlab.packet.Ethernet;
-import org.onlab.packet.ICMP;
-import org.onlab.packet.ICMP6;
-import org.onlab.packet.IPv4;
-import org.onlab.packet.IPv6;
-import org.onlab.packet.MPLS;
-import org.onosproject.TestApplicationId;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.net.config.ConfigApplyDelegate;
-import org.onosproject.net.config.basics.InterfaceConfig;
-import org.onosproject.net.device.DeviceService;
-import org.onosproject.segmentrouting.config.DeviceConfiguration;
-import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
-import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
-
-import java.util.Collections;
-
-import static org.easymock.EasyMock.*;
-import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.*;
-import static org.onlab.packet.ICMP.*;
-import static org.onlab.packet.ICMP6.ECHO_REPLY;
-import static org.onosproject.segmentrouting.TestUtils.*;
-
-/**
- * Tests for IcmpHandler.
- */
-public class IcmpHandlerTest {
-
- private IcmpHandler icmpHandler;
- private MockPacketService packetService;
- private SegmentRoutingManager segmentRoutingManager;
- private ApplicationId testApplicationId = TestApplicationId.create("test");
-
- @Before
- public void setUp() {
-
- // Init
- ObjectMapper mapper = new ObjectMapper();
- ConfigApplyDelegate delegate = config -> { };
-
- // Setup configuration for app
- SegmentRoutingAppConfig appConfig = new SegmentRoutingAppConfig();
- JsonNode appTree = mapper.createObjectNode();
- appConfig.init(testApplicationId, "icmp-handler-test", appTree, mapper, delegate);
- appConfig.setSuppressSubnet(Collections.emptySet());
-
- // Setup configuration for the devices
- SegmentRoutingDeviceConfig remoteLeafConfig = new SegmentRoutingDeviceConfig();
- JsonNode remoteLeafTree = mapper.createObjectNode();
- remoteLeafConfig.init(REMOTE_LEAF, "icmp-handler-test", remoteLeafTree, mapper, delegate);
- remoteLeafConfig.setNodeSidIPv4(REMOTE_LEAF_SID4)
- .setNodeSidIPv6(REMOTE_LEAF_SID6)
- .setRouterIpv4(REMOTE_LEAF_LB4)
- .setRouterIpv6(REMOTE_LEAF_LB6)
- .setIsEdgeRouter(true)
- .setRouterMac(REMOTE_MAC.toString());
- SegmentRoutingDeviceConfig localLeafConfig = new SegmentRoutingDeviceConfig();
- JsonNode localLeafTree = mapper.createObjectNode();
- localLeafConfig.init(LOCAL_LEAF, "icmp-handler-test", localLeafTree, mapper, delegate);
- localLeafConfig.setNodeSidIPv4(LOCAL_LEAF_SID4)
- .setRouterIpv4(LOCAL_LEAF_LB4)
- .setNodeSidIPv6(LOCAL_LEAF_SID6)
- .setRouterIpv6(LOCAL_LEAF_LB6)
- .setIsEdgeRouter(true)
- .setRouterMac(LOCAL_MAC.toString());
- SegmentRoutingDeviceConfig localLeaf1Config = new SegmentRoutingDeviceConfig();
- JsonNode localLeaf1Tree = mapper.createObjectNode();
- localLeaf1Config.init(LOCAL_LEAF1, "icmp-handler-test", localLeaf1Tree, mapper, delegate);
- localLeaf1Config.setNodeSidIPv4(LOCAL_LEAF1_SID4)
- .setRouterIpv4(LOCAL_LEAF1_LB4)
- .setNodeSidIPv6(LOCAL_LEAF1_SID6)
- .setRouterIpv6(LOCAL_LEAF1_LB6)
- .setIsEdgeRouter(true)
- .setRouterMac(LOCAL_MAC1.toString())
- .setPairDeviceId(LOCAL_LEAF2)
- .setPairLocalPort(P3);
- SegmentRoutingDeviceConfig localLeaf2Config = new SegmentRoutingDeviceConfig();
- JsonNode localLeaf2Tree = mapper.createObjectNode();
- localLeaf2Config.init(LOCAL_LEAF2, "icmp-handler-test", localLeaf2Tree, mapper, delegate);
- localLeaf2Config.setNodeSidIPv4(LOCAL_LEAF2_SID4)
- .setRouterIpv4(LOCAL_LEAF2_LB4)
- .setNodeSidIPv6(LOCAL_LEAF2_SID6)
- .setRouterIpv6(LOCAL_LEAF2_LB6)
- .setIsEdgeRouter(true)
- .setRouterMac(LOCAL_MAC2.toString())
- .setPairDeviceId(LOCAL_LEAF1)
- .setPairLocalPort(P3);
-
- // Setup configuration for ports
- InterfaceConfig remoteLeafPorts1Config = new InterfaceConfig();
- ArrayNode remoteLeafPorts1Tree = mapper.createArrayNode();
- remoteLeafPorts1Config.init(CP12, "icmp-handler-test", remoteLeafPorts1Tree, mapper, delegate);
- remoteLeafPorts1Config.addInterface(INTF1);
- InterfaceConfig remoteLeafPorts2Config = new InterfaceConfig();
- ArrayNode remoteLeafPorts2Tree = mapper.createArrayNode();
- remoteLeafPorts2Config.init(CP13, "icmp-handler-test", remoteLeafPorts2Tree, mapper, delegate);
- remoteLeafPorts2Config.addInterface(INTF2);
- InterfaceConfig localLeafPortsConfig = new InterfaceConfig();
- ArrayNode localLeafPortsTree = mapper.createArrayNode();
- localLeafPortsConfig.init(CP1011, "icmp-handler-test", localLeafPortsTree, mapper, delegate);
- localLeafPortsConfig.addInterface(INTF111);
- InterfaceConfig localLeaf1PortsConfig = new InterfaceConfig();
- ArrayNode localLeaf1PortsTree = mapper.createArrayNode();
- localLeaf1PortsConfig.init(CP2011, "icmp-handler-test", localLeaf1PortsTree, mapper, delegate);
- localLeaf1PortsConfig.addInterface(INTF211);
- InterfaceConfig localLeaf2Ports1Config = new InterfaceConfig();
- ArrayNode localLeaf2Ports1Tree = mapper.createArrayNode();
- localLeaf2Ports1Config.init(CP2021, "icmp-handler-test", localLeaf2Ports1Tree, mapper, delegate);
- localLeaf2Ports1Config.addInterface(INTF212);
- InterfaceConfig localLeaf2Ports2Config = new InterfaceConfig();
- ArrayNode localLeaf2Ports2Tree = mapper.createArrayNode();
- localLeaf2Ports2Config.init(CP2024, "icmp-handler-test", localLeaf2Ports2Tree, mapper, delegate);
- localLeaf2Ports2Config.addInterface(INTF213);
-
- // Apply config
- MockNetworkConfigRegistry mockNetworkConfigRegistry = new MockNetworkConfigRegistry();
-
- mockNetworkConfigRegistry.applyConfig(remoteLeafConfig);
- mockNetworkConfigRegistry.applyConfig(remoteLeafPorts1Config);
- mockNetworkConfigRegistry.applyConfig(remoteLeafPorts2Config);
- mockNetworkConfigRegistry.applyConfig(localLeafConfig);
- mockNetworkConfigRegistry.applyConfig(localLeafPortsConfig);
- mockNetworkConfigRegistry.applyConfig(localLeaf1Config);
- mockNetworkConfigRegistry.applyConfig(localLeaf1PortsConfig);
- mockNetworkConfigRegistry.applyConfig(localLeaf2Config);
- mockNetworkConfigRegistry.applyConfig(localLeaf2Ports1Config);
- mockNetworkConfigRegistry.applyConfig(localLeaf2Ports2Config);
-
- segmentRoutingManager = new SegmentRoutingManager();
- segmentRoutingManager.appId = testApplicationId;
- packetService = new MockPacketService();
- segmentRoutingManager.packetService = packetService;
- segmentRoutingManager.cfgService = mockNetworkConfigRegistry;
- segmentRoutingManager.neighbourResolutionService = new MockNeighbourResolutionService();
- segmentRoutingManager.interfaceService = new MockInterfaceService(ImmutableSet.of(
- INTF1, INTF2, INTF111, INTF211, INTF212, INTF213));
- segmentRoutingManager.deviceConfiguration = new DeviceConfiguration(segmentRoutingManager);
- segmentRoutingManager.ipHandler = new IpHandler(segmentRoutingManager);
- segmentRoutingManager.deviceService = createMock(DeviceService.class);
- segmentRoutingManager.routeService = new MockRouteService(ROUTE_STORE);
- segmentRoutingManager.hostService = new MockHostService(Collections.emptySet());
- icmpHandler = new IcmpHandler(segmentRoutingManager);
- }
-
- // Ping to our gateway
- @Test
- public void testPing4MyGateway() {
- // Expected behavior
- expect(segmentRoutingManager.deviceService.isAvailable(REMOTE_LEAF))
- .andReturn(true)
- .times(1);
- replay(segmentRoutingManager.deviceService);
-
- // Process
- icmpHandler.processIcmp(ETH_REQ_IPV4_MY, CP12);
-
- // Verify packet-out
- Ethernet ethernet = packetService.getEthernetPacket(ETH_REQ_IPV4_MY.getSourceMAC());
- assertNotNull(ethernet);
- assertThat(ethernet.getSourceMAC(), is(ETH_REQ_IPV4_MY.getDestinationMAC()));
- assertThat(ethernet.getDestinationMAC(), is(ETH_REQ_IPV4_MY.getSourceMAC()));
- assertTrue(ethernet.getPayload() instanceof IPv4);
- IPv4 ip = (IPv4) ethernet.getPayload();
- assertThat(ip.getSourceAddress(), is(DST_IPV4.toInt()));
- assertThat(ip.getDestinationAddress(), is(SRC_IPV4_MY.toInt()));
- assertTrue(ip.getPayload() instanceof ICMP);
- ICMP icmp = (ICMP) ip.getPayload();
- assertThat(icmp.getIcmpType(), is(TYPE_ECHO_REPLY));
- assertThat(icmp.getIcmpCode(), is(CODE_ECHO_REPLY));
- // Verify behavior
- verify(segmentRoutingManager.deviceService);
- }
-
- // Ping6 to our gateway
- @Test
- public void testPing6MyGateway() {
- // Expected behavior
- expect(segmentRoutingManager.deviceService.isAvailable(REMOTE_LEAF))
- .andReturn(true)
- .times(1);
- replay(segmentRoutingManager.deviceService);
-
- // Process
- icmpHandler.processIcmpv6(ETH_REQ_IPV6_MY, CP12);
-
- // Verify packet-out
- Ethernet ethernet = packetService.getEthernetPacket(ETH_REQ_IPV6_MY.getSourceMAC());
- assertNotNull(ethernet);
- assertThat(ethernet.getSourceMAC(), is(ETH_REQ_IPV6_MY.getDestinationMAC()));
- assertThat(ethernet.getDestinationMAC(), is(ETH_REQ_IPV6_MY.getSourceMAC()));
- assertTrue(ethernet.getPayload() instanceof IPv6);
- IPv6 ip = (IPv6) ethernet.getPayload();
- assertThat(ip.getSourceAddress(), is(DST_IPV6.toOctets()));
- assertThat(ip.getDestinationAddress(), is(SRC_IPV6_MY.toOctets()));
- assertTrue(ip.getPayload() instanceof ICMP6);
- ICMP6 icmp = (ICMP6) ip.getPayload();
- assertThat(icmp.getIcmpType(), is(ECHO_REPLY));
- // Verify behavior
- verify(segmentRoutingManager.deviceService);
- }
-
- // Ping to a gateway attached to our leaf
- @Test
- public void testPing4LocalGateway() {
- // Expected behavior
- expect(segmentRoutingManager.deviceService.isAvailable(REMOTE_LEAF))
- .andReturn(true)
- .times(1);
- replay(segmentRoutingManager.deviceService);
-
- // Process
- icmpHandler.processIcmp(ETH_REQ_IPV4_LOCAL, CP12);
-
- // Verify packet-out
- Ethernet ethernet = packetService.getEthernetPacket(ETH_REQ_IPV4_LOCAL.getSourceMAC());
- assertNotNull(ethernet);
- assertThat(ethernet.getSourceMAC(), is(ETH_REQ_IPV4_LOCAL.getDestinationMAC()));
- assertThat(ethernet.getDestinationMAC(), is(ETH_REQ_IPV4_LOCAL.getSourceMAC()));
- assertTrue(ethernet.getPayload() instanceof IPv4);
- IPv4 ip = (IPv4) ethernet.getPayload();
- assertThat(ip.getSourceAddress(), is(DST_IPV4_LOCAL.toInt()));
- assertThat(ip.getDestinationAddress(), is(SRC_IPV4_MY.toInt()));
- assertTrue(ip.getPayload() instanceof ICMP);
- ICMP icmp = (ICMP) ip.getPayload();
- assertThat(icmp.getIcmpType(), is(TYPE_ECHO_REPLY));
- assertThat(icmp.getIcmpCode(), is(CODE_ECHO_REPLY));
- // Verify behavior
- verify(segmentRoutingManager.deviceService);
- }
-
- // Ping6 to a gateway attached to our leaf
- @Test
- public void testPing6LocalGateway() {
- // Expected behavior
- expect(segmentRoutingManager.deviceService.isAvailable(REMOTE_LEAF))
- .andReturn(true)
- .times(1);
- replay(segmentRoutingManager.deviceService);
-
- // Process
- icmpHandler.processIcmpv6(ETH_REQ_IPV6_LOCAL, CP12);
-
- // Verify packet-out
- Ethernet ethernet = packetService.getEthernetPacket(ETH_REQ_IPV6_LOCAL.getSourceMAC());
- assertNotNull(ethernet);
- assertThat(ethernet.getSourceMAC(), is(ETH_REQ_IPV6_LOCAL.getDestinationMAC()));
- assertThat(ethernet.getDestinationMAC(), is(ETH_REQ_IPV6_LOCAL.getSourceMAC()));
- assertTrue(ethernet.getPayload() instanceof IPv6);
- IPv6 ip = (IPv6) ethernet.getPayload();
- assertThat(ip.getSourceAddress(), is(DST_IPV6_LOCAL.toOctets()));
- assertThat(ip.getDestinationAddress(), is(SRC_IPV6_MY.toOctets()));
- assertTrue(ip.getPayload() instanceof ICMP6);
- ICMP6 icmp = (ICMP6) ip.getPayload();
- assertThat(icmp.getIcmpType(), is(ECHO_REPLY));
- // Verify behavior
- verify(segmentRoutingManager.deviceService);
- }
-
- // Ping to a gateway attached only to the pair leaf (routing through spine)
- @Test
- public void testPing4RemoteGatewaySamePair() {
- // Expected behavior
- expect(segmentRoutingManager.deviceService.isAvailable(LOCAL_LEAF1))
- .andReturn(true)
- .times(1);
- expect(segmentRoutingManager.deviceService.isAvailable(LOCAL_LEAF2))
- .andReturn(true)
- .times(1);
- replay(segmentRoutingManager.deviceService);
-
- // Process
- icmpHandler.processIcmp(ETH_REQ_IPV4_SAME, CP2025);
-
- // Verify packet-out
- Ethernet ethernet = packetService.getEthernetPacket(ETH_REQ_IPV4_SAME.getSourceMAC());
- assertNotNull(ethernet);
- assertThat(ethernet.getSourceMAC(), is(ETH_REQ_IPV4_SAME.getDestinationMAC()));
- assertThat(ethernet.getDestinationMAC(), is(ETH_REQ_IPV4_SAME.getSourceMAC()));
- assertTrue(ethernet.getPayload() instanceof MPLS);
- MPLS mpls = (MPLS) ethernet.getPayload();
- assertThat(mpls.getLabel(), is(LOCAL_LEAF1_SID4));
- assertTrue(mpls.getPayload() instanceof IPv4);
- IPv4 ip = (IPv4) mpls.getPayload();
- assertThat(ip.getSourceAddress(), is(DST_IPV4_SAME.toInt()));
- assertThat(ip.getDestinationAddress(), is(SRC_IPV41.toInt()));
- assertTrue(ip.getPayload() instanceof ICMP);
- ICMP icmp = (ICMP) ip.getPayload();
- assertThat(icmp.getIcmpType(), is(TYPE_ECHO_REPLY));
- assertThat(icmp.getIcmpCode(), is(CODE_ECHO_REPLY));
- // Verify behavior
- verify(segmentRoutingManager.deviceService);
- }
-
- // Ping6 to a gateway attached only to the pair leaf (routing through spine)
- @Test
- public void testPing6RemoteGatewaySamePair() {
- // Expected behavior
- expect(segmentRoutingManager.deviceService.isAvailable(LOCAL_LEAF1))
- .andReturn(true)
- .times(1);
- expect(segmentRoutingManager.deviceService.isAvailable(LOCAL_LEAF2))
- .andReturn(true)
- .times(1);
- replay(segmentRoutingManager.deviceService);
-
- // Process
- icmpHandler.processIcmpv6(ETH_REQ_IPV6_SAME, CP2025);
-
- // Verify packet-out
- Ethernet ethernet = packetService.getEthernetPacket(ETH_REQ_IPV6_SAME.getSourceMAC());
- assertNotNull(ethernet);
- assertThat(ethernet.getSourceMAC(), is(ETH_REQ_IPV6_SAME.getDestinationMAC()));
- assertThat(ethernet.getDestinationMAC(), is(ETH_REQ_IPV6_SAME.getSourceMAC()));
- assertTrue(ethernet.getPayload() instanceof MPLS);
- MPLS mpls = (MPLS) ethernet.getPayload();
- assertThat(mpls.getLabel(), is(LOCAL_LEAF1_SID6));
- assertTrue(mpls.getPayload() instanceof IPv6);
- IPv6 ip = (IPv6) mpls.getPayload();
- assertThat(ip.getSourceAddress(), is(DST_IPV6_SAME.toOctets()));
- assertThat(ip.getDestinationAddress(), is(SRC_IPV61.toOctets()));
- assertTrue(ip.getPayload() instanceof ICMP6);
- ICMP6 icmp = (ICMP6) ip.getPayload();
- assertThat(icmp.getIcmpType(), is(ECHO_REPLY));
- // Verify behavior
- verify(segmentRoutingManager.deviceService);
- }
-
- // Ping to a gateway but destination leaf is down
- @Test
- public void testPing4RemoteGatewayLeafDown() {
- // Expected behavior
- expect(segmentRoutingManager.deviceService.isAvailable(LOCAL_LEAF))
- .andReturn(false)
- .times(1);
- replay(segmentRoutingManager.deviceService);
-
- // Process
- icmpHandler.processIcmp(ETH_REQ_IPV4, CP11);
-
- // Verify packet-out
- Ethernet ethernet = packetService.getEthernetPacket(ETH_REQ_IPV4.getSourceMAC());
- assertNull(ethernet);
-
- // Verify behavior
- verify(segmentRoutingManager.deviceService);
- }
-
- // Ping6 to a gateway but destination leaf is down
- @Test
- public void testPing6RemoteGatewayLeafDown() {
- // Expected behavior
- expect(segmentRoutingManager.deviceService.isAvailable(LOCAL_LEAF))
- .andReturn(false)
- .times(1);
- replay(segmentRoutingManager.deviceService);
-
- // Process
- icmpHandler.processIcmpv6(ETH_REQ_IPV6, CP11);
-
- // Verify packet-out
- Ethernet ethernet = packetService.getEthernetPacket(ETH_REQ_IPV6.getSourceMAC());
- assertNull(ethernet);
-
- // Verify behavior
- verify(segmentRoutingManager.deviceService);
- }
-
- // Ping to a gateway but one of the destination leaf is down
- @Test
- public void testPing4RemoteGatewayLeaf1Down() {
- // Expected behavior
- expect(segmentRoutingManager.deviceService.isAvailable(LOCAL_LEAF1))
- .andReturn(false)
- .times(1);
- expect(segmentRoutingManager.deviceService.isAvailable(LOCAL_LEAF2))
- .andReturn(true)
- .times(1);
- replay(segmentRoutingManager.deviceService);
-
- // Process
- icmpHandler.processIcmp(ETH_REQ_IPV41, CP11);
-
- // Verify packet-out
- Ethernet ethernet = packetService.getEthernetPacket(ETH_REQ_IPV41.getSourceMAC());
- assertNotNull(ethernet);
- assertThat(ethernet.getSourceMAC(), is(ETH_REQ_IPV41.getDestinationMAC()));
- assertThat(ethernet.getDestinationMAC(), is(ETH_REQ_IPV41.getSourceMAC()));
- assertThat(ethernet.getEtherType(), is(Ethernet.MPLS_UNICAST));
- assertTrue(ethernet.getPayload() instanceof MPLS);
- MPLS mpls = (MPLS) ethernet.getPayload();
- assertThat(mpls.getLabel(), is(LOCAL_LEAF2_SID4));
- assertTrue(mpls.getPayload() instanceof IPv4);
- IPv4 ip = (IPv4) mpls.getPayload();
- assertThat(ip.getSourceAddress(), is(DST_IPV4.toInt()));
- assertThat(ip.getDestinationAddress(), is(SRC_IPV41.toInt()));
- assertTrue(ip.getPayload() instanceof ICMP);
- ICMP icmp = (ICMP) ip.getPayload();
- assertThat(icmp.getIcmpType(), is(TYPE_ECHO_REPLY));
- assertThat(icmp.getIcmpCode(), is(CODE_ECHO_REPLY));
- // Verify behavior
- verify(segmentRoutingManager.deviceService);
- }
-
- // Ping6 to a gateway but one of the destination leaf is down
- @Test
- public void testPing6RemoteGatewayLeaf2Down() {
- // Expected behavior
- expect(segmentRoutingManager.deviceService.isAvailable(LOCAL_LEAF1))
- .andReturn(true)
- .times(1);
- expect(segmentRoutingManager.deviceService.isAvailable(LOCAL_LEAF2))
- .andReturn(false)
- .times(1);
- replay(segmentRoutingManager.deviceService);
-
- // Process
- icmpHandler.processIcmpv6(ETH_REQ_IPV61, CP11);
-
- // Verify packet-out
- Ethernet ethernet = packetService.getEthernetPacket(ETH_REQ_IPV61.getSourceMAC());
- assertNotNull(ethernet);
- assertThat(ethernet.getSourceMAC(), is(ETH_REQ_IPV61.getDestinationMAC()));
- assertThat(ethernet.getDestinationMAC(), is(ETH_REQ_IPV61.getSourceMAC()));
- assertThat(ethernet.getEtherType(), is(Ethernet.MPLS_UNICAST));
- assertTrue(ethernet.getPayload() instanceof MPLS);
- MPLS mpls = (MPLS) ethernet.getPayload();
- assertThat(mpls.getLabel(), is(LOCAL_LEAF1_SID6));
- assertTrue(mpls.getPayload() instanceof IPv6);
- IPv6 ip = (IPv6) mpls.getPayload();
- assertThat(ip.getSourceAddress(), is(DST_IPV6.toOctets()));
- assertThat(ip.getDestinationAddress(), is(SRC_IPV61.toOctets()));
- assertTrue(ip.getPayload() instanceof ICMP6);
- ICMP6 icmp = (ICMP6) ip.getPayload();
- assertThat(icmp.getIcmpType(), is(ECHO_REPLY));
- // Verify behavior
- verify(segmentRoutingManager.deviceService);
- }
-
- // Ping6 to a link local address
- @Test
- public void testPing6LinkLocalAddress() {
- // Process
- icmpHandler.processIcmpv6(ETH_REQ_IPV6_LL, CP12);
-
- // Verify packet-out
- Ethernet ethernet = packetService.getEthernetPacket(ETH_REQ_IPV6_LL.getSourceMAC());
- assertNotNull(ethernet);
- assertThat(ethernet.getSourceMAC(), is(ETH_REQ_IPV6_LL.getDestinationMAC()));
- assertThat(ethernet.getDestinationMAC(), is(ETH_REQ_IPV6_LL.getSourceMAC()));
- assertTrue(ethernet.getPayload() instanceof IPv6);
- IPv6 ip = (IPv6) ethernet.getPayload();
- assertThat(ip.getSourceAddress(), is(DST_IPV6_LL.toOctets()));
- assertThat(ip.getDestinationAddress(), is(SRC_IPV6_LL.toOctets()));
- assertTrue(ip.getPayload() instanceof ICMP6);
- ICMP6 icmp = (ICMP6) ip.getPayload();
- assertThat(icmp.getIcmpType(), is(ECHO_REPLY));
- }
-
- // Ping to the looback of our leaf
- @Test
- public void testPing4Loopback() {
- // Expected behavior
- expect(segmentRoutingManager.deviceService.isAvailable(REMOTE_LEAF))
- .andReturn(true)
- .times(1);
- replay(segmentRoutingManager.deviceService);
-
- // Process
- icmpHandler.processIcmp(ETH_REQ_IPV4_LOOPBACK, CP12);
-
- // Verify packet-out
- Ethernet ethernet = packetService.getEthernetPacket(ETH_REQ_IPV4_LOOPBACK.getSourceMAC());
- assertNotNull(ethernet);
- assertThat(ethernet.getSourceMAC(), is(ETH_REQ_IPV4_LOOPBACK.getDestinationMAC()));
- assertThat(ethernet.getDestinationMAC(), is(ETH_REQ_IPV4_LOOPBACK.getSourceMAC()));
- assertTrue(ethernet.getPayload() instanceof IPv4);
- IPv4 ip = (IPv4) ethernet.getPayload();
- assertThat(ip.getSourceAddress(), is(DST_IPV4_LOOPBACK.toInt()));
- assertThat(ip.getDestinationAddress(), is(SRC_IPV4_MY.toInt()));
- assertTrue(ip.getPayload() instanceof ICMP);
- ICMP icmp = (ICMP) ip.getPayload();
- assertThat(icmp.getIcmpType(), is(TYPE_ECHO_REPLY));
- assertThat(icmp.getIcmpCode(), is(CODE_ECHO_REPLY));
- // Verify behavior
- verify(segmentRoutingManager.deviceService);
- }
-
- // Ping6 to the looback of our leaf
- @Test
- public void testPing6Loopback() {
- // Expected behavior
- expect(segmentRoutingManager.deviceService.isAvailable(REMOTE_LEAF))
- .andReturn(true)
- .times(1);
- replay(segmentRoutingManager.deviceService);
-
- // Process
- icmpHandler.processIcmpv6(ETH_REQ_IPV6_LOOPBACK, CP12);
-
- // Verify packet-out
- Ethernet ethernet = packetService.getEthernetPacket(ETH_REQ_IPV6_LOOPBACK.getSourceMAC());
- assertNotNull(ethernet);
- assertThat(ethernet.getSourceMAC(), is(ETH_REQ_IPV6_LOOPBACK.getDestinationMAC()));
- assertThat(ethernet.getDestinationMAC(), is(ETH_REQ_IPV6_LOOPBACK.getSourceMAC()));
- assertTrue(ethernet.getPayload() instanceof IPv6);
- IPv6 ip = (IPv6) ethernet.getPayload();
- assertThat(ip.getSourceAddress(), is(DST_IPV6_LOOPBACK.toOctets()));
- assertThat(ip.getDestinationAddress(), is(SRC_IPV6_MY.toOctets()));
- assertTrue(ip.getPayload() instanceof ICMP6);
- ICMP6 icmp = (ICMP6) ip.getPayload();
- assertThat(icmp.getIcmpType(), is(ECHO_REPLY));
- // Verify behavior
- verify(segmentRoutingManager.deviceService);
- }
-
- // Ping to the looback of our leaf (pair)
- @Test
- public void testPing4LoopbackPair() {
- // Expected behavior
- expect(segmentRoutingManager.deviceService.isAvailable(LOCAL_LEAF1))
- .andReturn(true)
- .times(1);
- expect(segmentRoutingManager.deviceService.isAvailable(LOCAL_LEAF2))
- .andReturn(true)
- .times(1);
- replay(segmentRoutingManager.deviceService);
-
- // Process
- icmpHandler.processIcmp(ETH_REQ_IPV4_LOOPBACK_PAIR, CP2011);
-
- // Verify packet-out
- Ethernet ethernet = packetService.getEthernetPacket(ETH_REQ_IPV4_LOOPBACK_PAIR.getSourceMAC());
- assertNotNull(ethernet);
- assertThat(ethernet.getSourceMAC(), is(ETH_REQ_IPV4_LOOPBACK_PAIR.getDestinationMAC()));
- assertThat(ethernet.getDestinationMAC(), is(ETH_REQ_IPV4_LOOPBACK_PAIR.getSourceMAC()));
- assertTrue(ethernet.getPayload() instanceof IPv4);
- IPv4 ip = (IPv4) ethernet.getPayload();
- assertThat(ip.getSourceAddress(), is(DST_IPV4_LOOPBACK_PAIR.toInt()));
- assertThat(ip.getDestinationAddress(), is(SRC_IPV41.toInt()));
- assertTrue(ip.getPayload() instanceof ICMP);
- ICMP icmp = (ICMP) ip.getPayload();
- assertThat(icmp.getIcmpType(), is(TYPE_ECHO_REPLY));
- assertThat(icmp.getIcmpCode(), is(CODE_ECHO_REPLY));
- // Verify behavior
- verify(segmentRoutingManager.deviceService);
- }
-
- // Ping6 to the looback of our leaf (pair)
- @Test
- public void testPing6LoopbackPair() {
- // Expected behavior
- expect(segmentRoutingManager.deviceService.isAvailable(LOCAL_LEAF1))
- .andReturn(true)
- .times(1);
- expect(segmentRoutingManager.deviceService.isAvailable(LOCAL_LEAF2))
- .andReturn(true)
- .times(1);
- replay(segmentRoutingManager.deviceService);
-
- // Process
- icmpHandler.processIcmpv6(ETH_REQ_IPV6_LOOPBACK_PAIR, CP2021);
-
- // Verify packet-out
- Ethernet ethernet = packetService.getEthernetPacket(ETH_REQ_IPV6_LOOPBACK_PAIR.getSourceMAC());
- assertNotNull(ethernet);
- assertThat(ethernet.getSourceMAC(), is(ETH_REQ_IPV6_LOOPBACK_PAIR.getDestinationMAC()));
- assertThat(ethernet.getDestinationMAC(), is(ETH_REQ_IPV6_LOOPBACK_PAIR.getSourceMAC()));
- assertTrue(ethernet.getPayload() instanceof IPv6);
- IPv6 ip = (IPv6) ethernet.getPayload();
- assertThat(ip.getSourceAddress(), is(DST_IPV6_LOOPBACK_PAIR.toOctets()));
- assertThat(ip.getDestinationAddress(), is(SRC_IPV61.toOctets()));
- assertTrue(ip.getPayload() instanceof ICMP6);
- ICMP6 icmp = (ICMP6) ip.getPayload();
- assertThat(icmp.getIcmpType(), is(ECHO_REPLY));
- // Verify behavior
- verify(segmentRoutingManager.deviceService);
- }
-
- // Ping to the loopback of the leaf but hashing of the bond interfaces sends to wrong leaf
- @Test
- public void testPing4LoopbackPairDifferentLeaf() {
- // Expected behavior
- expect(segmentRoutingManager.deviceService.isAvailable(LOCAL_LEAF1))
- .andReturn(true)
- .times(1);
- expect(segmentRoutingManager.deviceService.isAvailable(LOCAL_LEAF2))
- .andReturn(true)
- .times(1);
- replay(segmentRoutingManager.deviceService);
-
- // Process
- icmpHandler.processIcmp(ETH_REQ_IPV4_LOOPBACK_PAIR, CP2021);
-
- // Verify packet-out
- Ethernet ethernet = packetService.getEthernetPacket(ETH_REQ_IPV4_LOOPBACK_PAIR.getSourceMAC());
- assertNotNull(ethernet);
- assertThat(ethernet.getSourceMAC(), is(ETH_REQ_IPV4_LOOPBACK_PAIR.getDestinationMAC()));
- assertThat(ethernet.getDestinationMAC(), is(ETH_REQ_IPV4_LOOPBACK_PAIR.getSourceMAC()));
- assertTrue(ethernet.getPayload() instanceof IPv4);
- IPv4 ip = (IPv4) ethernet.getPayload();
- assertThat(ip.getSourceAddress(), is(DST_IPV4_LOOPBACK_PAIR.toInt()));
- assertThat(ip.getDestinationAddress(), is(SRC_IPV41.toInt()));
- assertTrue(ip.getPayload() instanceof ICMP);
- ICMP icmp = (ICMP) ip.getPayload();
- assertThat(icmp.getIcmpType(), is(TYPE_ECHO_REPLY));
- assertThat(icmp.getIcmpCode(), is(CODE_ECHO_REPLY));
- // Verify behavior
- verify(segmentRoutingManager.deviceService);
- }
-
- // Ping6 to the loopback of the leaf but hashing of the bond interfaces sends to wrong leaf
- @Test
- public void testPing6LoopbackPairDifferentLeaf() {
- // Expected behavior
- expect(segmentRoutingManager.deviceService.isAvailable(LOCAL_LEAF1))
- .andReturn(true)
- .times(1);
- expect(segmentRoutingManager.deviceService.isAvailable(LOCAL_LEAF2))
- .andReturn(true)
- .times(1);
- replay(segmentRoutingManager.deviceService);
-
- // Process
- icmpHandler.processIcmpv6(ETH_REQ_IPV6_LOOPBACK_PAIR, CP2011);
-
- // Verify packet-out
- Ethernet ethernet = packetService.getEthernetPacket(ETH_REQ_IPV6_LOOPBACK_PAIR.getSourceMAC());
- assertNotNull(ethernet);
- assertThat(ethernet.getSourceMAC(), is(ETH_REQ_IPV6_LOOPBACK_PAIR.getDestinationMAC()));
- assertThat(ethernet.getDestinationMAC(), is(ETH_REQ_IPV6_LOOPBACK_PAIR.getSourceMAC()));
- assertTrue(ethernet.getPayload() instanceof IPv6);
- IPv6 ip = (IPv6) ethernet.getPayload();
- assertThat(ip.getSourceAddress(), is(DST_IPV6_LOOPBACK_PAIR.toOctets()));
- assertThat(ip.getDestinationAddress(), is(SRC_IPV61.toOctets()));
- assertTrue(ip.getPayload() instanceof ICMP6);
- ICMP6 icmp = (ICMP6) ip.getPayload();
- assertThat(icmp.getIcmpType(), is(ECHO_REPLY));
- // Verify behavior
- verify(segmentRoutingManager.deviceService);
- }
-
- // Ping loopback of a destination that is down but
- // hashing of the bond interfaces sends to other leaf
- @Test
- public void testPing4LoopbackPairDifferentLeafDown() {
- // Expected behavior
- expect(segmentRoutingManager.deviceService.isAvailable(LOCAL_LEAF1))
- .andReturn(false)
- .times(1);
- expect(segmentRoutingManager.deviceService.isAvailable(LOCAL_LEAF2))
- .andReturn(true)
- .times(1);
- replay(segmentRoutingManager.deviceService);
-
- // Process
- icmpHandler.processIcmp(ETH_REQ_IPV4_LOOPBACK_PAIR, CP2021);
-
- // Verify packet-out
- Ethernet ethernet = packetService.getEthernetPacket(ETH_REQ_IPV4_LOOPBACK_PAIR.getSourceMAC());
- assertNotNull(ethernet);
- assertThat(ethernet.getSourceMAC(), is(ETH_REQ_IPV4_LOOPBACK_PAIR.getDestinationMAC()));
- assertThat(ethernet.getDestinationMAC(), is(ETH_REQ_IPV4_LOOPBACK_PAIR.getSourceMAC()));
- assertTrue(ethernet.getPayload() instanceof IPv4);
- IPv4 ip = (IPv4) ethernet.getPayload();
- assertThat(ip.getSourceAddress(), is(DST_IPV4_LOOPBACK_PAIR.toInt()));
- assertThat(ip.getDestinationAddress(), is(SRC_IPV41.toInt()));
- assertTrue(ip.getPayload() instanceof ICMP);
- ICMP icmp = (ICMP) ip.getPayload();
- assertThat(icmp.getIcmpType(), is(TYPE_ECHO_REPLY));
- assertThat(icmp.getIcmpCode(), is(CODE_ECHO_REPLY));
- // Verify behavior
- verify(segmentRoutingManager.deviceService);
- }
-
- // Ping6 loopback of a destination that is down but
- // hashing of the bond interfaces sends to other leaf
- @Test
- public void testPing6LoopbackPairDifferentLeafDown() {
- // Expected behavior
- expect(segmentRoutingManager.deviceService.isAvailable(LOCAL_LEAF1))
- .andReturn(true)
- .times(1);
- expect(segmentRoutingManager.deviceService.isAvailable(LOCAL_LEAF2))
- .andReturn(false)
- .times(1);
- replay(segmentRoutingManager.deviceService);
-
- // Process
- icmpHandler.processIcmpv6(ETH_REQ_IPV6_LOOPBACK_PAIR, CP2011);
-
- // Verify packet-out
- Ethernet ethernet = packetService.getEthernetPacket(ETH_REQ_IPV6_LOOPBACK_PAIR.getSourceMAC());
- assertNotNull(ethernet);
- assertThat(ethernet.getSourceMAC(), is(ETH_REQ_IPV6_LOOPBACK_PAIR.getDestinationMAC()));
- assertThat(ethernet.getDestinationMAC(), is(ETH_REQ_IPV6_LOOPBACK_PAIR.getSourceMAC()));
- assertTrue(ethernet.getPayload() instanceof IPv6);
- IPv6 ip = (IPv6) ethernet.getPayload();
- assertThat(ip.getSourceAddress(), is(DST_IPV6_LOOPBACK_PAIR.toOctets()));
- assertThat(ip.getDestinationAddress(), is(SRC_IPV61.toOctets()));
- assertTrue(ip.getPayload() instanceof ICMP6);
- ICMP6 icmp = (ICMP6) ip.getPayload();
- assertThat(icmp.getIcmpType(), is(ECHO_REPLY));
- // Verify behavior
- verify(segmentRoutingManager.deviceService);
- }
-
- // Ping to a dh gateway
- @Test
- public void testPing4GatewayPair() {
- // Expected behavior
- expect(segmentRoutingManager.deviceService.isAvailable(LOCAL_LEAF1))
- .andReturn(true)
- .times(1);
- expect(segmentRoutingManager.deviceService.isAvailable(LOCAL_LEAF2))
- .andReturn(true)
- .times(1);
- replay(segmentRoutingManager.deviceService);
-
- // Process
- icmpHandler.processIcmp(ETH_REQ_IPV4_GATEWAY_PAIR, CP2011);
-
- // Verify packet-out
- Ethernet ethernet = packetService.getEthernetPacket(ETH_REQ_IPV4_GATEWAY_PAIR.getSourceMAC());
- assertNotNull(ethernet);
- assertThat(ethernet.getSourceMAC(), is(ETH_REQ_IPV4_GATEWAY_PAIR.getDestinationMAC()));
- assertThat(ethernet.getDestinationMAC(), is(ETH_REQ_IPV4_GATEWAY_PAIR.getSourceMAC()));
- assertTrue(ethernet.getPayload() instanceof IPv4);
- IPv4 ip = (IPv4) ethernet.getPayload();
- assertThat(ip.getSourceAddress(), is(DST_IPV4_GATEWAY_PAIR.toInt()));
- assertThat(ip.getDestinationAddress(), is(SRC_IPV41.toInt()));
- assertTrue(ip.getPayload() instanceof ICMP);
- ICMP icmp = (ICMP) ip.getPayload();
- assertThat(icmp.getIcmpType(), is(TYPE_ECHO_REPLY));
- assertThat(icmp.getIcmpCode(), is(CODE_ECHO_REPLY));
- // Verify behavior
- verify(segmentRoutingManager.deviceService);
- }
-
- // Ping6 to a dh gateway
- @Test
- public void testPing6GatewayPair() {
- // Expected behavior
- expect(segmentRoutingManager.deviceService.isAvailable(LOCAL_LEAF1))
- .andReturn(true)
- .times(1);
- expect(segmentRoutingManager.deviceService.isAvailable(LOCAL_LEAF2))
- .andReturn(true)
- .times(1);
- replay(segmentRoutingManager.deviceService);
-
- // Process
- icmpHandler.processIcmpv6(ETH_REQ_IPV6_GATEWAY_PAIR, CP2021);
-
- // Verify packet-out
- Ethernet ethernet = packetService.getEthernetPacket(ETH_REQ_IPV6_GATEWAY_PAIR.getSourceMAC());
- assertNotNull(ethernet);
- assertThat(ethernet.getSourceMAC(), is(ETH_REQ_IPV6_GATEWAY_PAIR.getDestinationMAC()));
- assertThat(ethernet.getDestinationMAC(), is(ETH_REQ_IPV6_GATEWAY_PAIR.getSourceMAC()));
- assertTrue(ethernet.getPayload() instanceof IPv6);
- IPv6 ip = (IPv6) ethernet.getPayload();
- assertThat(ip.getSourceAddress(), is(DST_IPV6_GATEWAY_PAIR.toOctets()));
- assertThat(ip.getDestinationAddress(), is(SRC_IPV61.toOctets()));
- assertTrue(ip.getPayload() instanceof ICMP6);
- ICMP6 icmp = (ICMP6) ip.getPayload();
- assertThat(icmp.getIcmpType(), is(ECHO_REPLY));
- // Verify behavior
- verify(segmentRoutingManager.deviceService);
- }
-
-}
diff --git a/app/src/test/java/org/onosproject/segmentrouting/MockBridgingTableKey.java b/app/src/test/java/org/onosproject/segmentrouting/MockBridgingTableKey.java
deleted file mode 100644
index a90b1cf..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/MockBridgingTableKey.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2017-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;
-
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
-import org.onosproject.net.DeviceId;
-
-import java.util.Objects;
-
-/**
- * Mock Bridging Table Key.
- */
-class MockBridgingTableKey {
- DeviceId deviceId;
- MacAddress macAddress;
- VlanId vlanId;
-
- MockBridgingTableKey(DeviceId deviceId, MacAddress macAddress, VlanId vlanId) {
- this.deviceId = deviceId;
- this.macAddress = macAddress;
- this.vlanId = vlanId;
- }
-
- @Override
- public boolean equals(final Object obj) {
- if (this == obj) {
- return true;
- }
- if (!(obj instanceof MockBridgingTableKey)) {
- return false;
- }
- final MockBridgingTableKey other = (MockBridgingTableKey) obj;
- return Objects.equals(this.macAddress, other.macAddress) &&
- Objects.equals(this.deviceId, other.deviceId) &&
- Objects.equals(this.vlanId, other.vlanId);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(macAddress, vlanId);
- }
-}
\ No newline at end of file
diff --git a/app/src/test/java/org/onosproject/segmentrouting/MockBridgingTableValue.java b/app/src/test/java/org/onosproject/segmentrouting/MockBridgingTableValue.java
deleted file mode 100644
index 68b0db8..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/MockBridgingTableValue.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2017-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;
-
-import org.onosproject.net.PortNumber;
-
-import java.util.Objects;
-
-/**
- * Mock Bridging Table Value.
- */
-class MockBridgingTableValue {
- boolean popVlan;
- PortNumber portNumber;
-
- MockBridgingTableValue(boolean popVlan, PortNumber portNumber) {
- this.popVlan = popVlan;
- this.portNumber = portNumber;
- }
-
- @Override
- public boolean equals(final Object obj) {
- if (this == obj) {
- return true;
- }
- if (!(obj instanceof MockBridgingTableValue)) {
- return false;
- }
- final MockBridgingTableValue other = (MockBridgingTableValue) obj;
- return Objects.equals(this.popVlan, other.popVlan) &&
- Objects.equals(this.portNumber, other.portNumber);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(popVlan, portNumber);
- }
-}
\ No newline at end of file
diff --git a/app/src/test/java/org/onosproject/segmentrouting/MockDefaultRoutingHandler.java b/app/src/test/java/org/onosproject/segmentrouting/MockDefaultRoutingHandler.java
deleted file mode 100644
index 0002948..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/MockDefaultRoutingHandler.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2017-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;
-
-import org.onlab.packet.IpPrefix;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
-
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Mock Default Routing Handler.
- */
-public class MockDefaultRoutingHandler extends DefaultRoutingHandler {
- private Map<ConnectPoint, Set<IpPrefix>> subnetTable;
- private Map<MockRoutingTableKey, MockRoutingTableValue> routingTable;
-
- MockDefaultRoutingHandler(SegmentRoutingManager srManager,
- Map<ConnectPoint, Set<IpPrefix>> subnetTable,
- Map<MockRoutingTableKey, MockRoutingTableValue> routingTable) {
- super(srManager);
- this.subnetTable = subnetTable;
- this.routingTable = routingTable;
- }
-
- @Override
- protected void populateSubnet(Set<ConnectPoint> cpts, Set<IpPrefix> subnets) {
- subnetTable.forEach((k, v) -> {
- if (!cpts.contains(k)) {
- subnetTable.get(k).removeAll(subnets);
- if (subnetTable.get(k).isEmpty()) {
- subnetTable.remove(k);
- }
- }
- });
-
- cpts.forEach(cpt -> subnetTable.put(cpt, subnets));
- }
-
- @Override
- protected boolean revokeSubnet(Set<IpPrefix> subnets) {
- for (Map.Entry<ConnectPoint, Set<IpPrefix>> entry : subnetTable.entrySet()) {
- entry.getValue().removeAll(subnets);
- if (entry.getValue().isEmpty()) {
- subnetTable.remove(entry.getKey());
- }
- }
- routingTable.entrySet().removeIf(e -> subnets.contains(e.getKey().ipPrefix));
- return true;
- }
-
- @Override
- protected boolean shouldProgram(DeviceId deviceId) {
- return true;
- }
-}
\ No newline at end of file
diff --git a/app/src/test/java/org/onosproject/segmentrouting/MockDevice.java b/app/src/test/java/org/onosproject/segmentrouting/MockDevice.java
deleted file mode 100644
index 0abbf2a..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/MockDevice.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 2016-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;
-
-import org.onosproject.net.Annotations;
-import org.onosproject.net.DefaultDevice;
-import org.onosproject.net.DeviceId;
-/**
- * Test fixture for the device service.
- */
-public class MockDevice extends DefaultDevice {
-
- public MockDevice(DeviceId id, Annotations annotations) {
- super(null, id, null, null, null, null, null, null, annotations);
- }
- }
-
diff --git a/app/src/test/java/org/onosproject/segmentrouting/MockDeviceService.java b/app/src/test/java/org/onosproject/segmentrouting/MockDeviceService.java
deleted file mode 100644
index 1d173f6..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/MockDeviceService.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2016-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;
-
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DefaultPort;
-import org.onosproject.net.Port;
-import org.onosproject.net.device.DeviceListener;
-import org.onosproject.net.device.DeviceServiceAdapter;
-import org.onosproject.net.Device;
-import org.onosproject.net.DeviceId;
-
-/**
- * Test fixture for the device service.
- */
-public class MockDeviceService extends DeviceServiceAdapter {
- private List<Device> devices = new LinkedList<>();
- private DeviceListener listener;
-
- public void addDevice(Device dev) {
- devices.add(dev);
- }
-
- public void addMultipleDevices(Set<Device> devicesToAdd) {
- devicesToAdd.forEach(dev -> devices.add(dev));
- }
-
- @Override
- public Device getDevice(DeviceId deviceId) {
- for (Device dev : devices) {
- if (dev.id().equals(deviceId)) {
- return dev;
- }
- }
- return null;
- }
-
- @Override
- public Port getPort(ConnectPoint cp) {
- return new DefaultPort(null, null, false);
- }
-
- @Override
- public Iterable<Device> getAvailableDevices() {
- return devices;
- }
-
- @Override
- public void addListener(DeviceListener listener) {
- this.listener = listener;
- }
-
- /**
- * Get the listener.
- */
- public DeviceListener getListener() {
- return listener;
- }
-
-}
diff --git a/app/src/test/java/org/onosproject/segmentrouting/MockFlowObjectiveService.java b/app/src/test/java/org/onosproject/segmentrouting/MockFlowObjectiveService.java
deleted file mode 100644
index 0f2d7a9..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/MockFlowObjectiveService.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2017-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;
-
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.flow.TrafficSelector;
-import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.flow.criteria.Criterion;
-import org.onosproject.net.flow.criteria.EthCriterion;
-import org.onosproject.net.flow.criteria.VlanIdCriterion;
-import org.onosproject.net.flow.instructions.Instruction;
-import org.onosproject.net.flow.instructions.Instructions;
-import org.onosproject.net.flow.instructions.L2ModificationInstruction;
-import org.onosproject.net.flowobjective.FlowObjectiveServiceAdapter;
-import org.onosproject.net.flowobjective.ForwardingObjective;
-import org.onosproject.net.flowobjective.Objective;
-import org.onosproject.net.flowobjective.ObjectiveError;
-
-import java.util.Map;
-
-/**
- * Mock Flow Objective Service.
- */
-public class MockFlowObjectiveService extends FlowObjectiveServiceAdapter {
- private Map<MockBridgingTableKey, MockBridgingTableValue> bridgingTable;
- private Map<Integer, TrafficTreatment> nextTable;
-
- MockFlowObjectiveService(Map<MockBridgingTableKey, MockBridgingTableValue> bridgingTable,
- Map<Integer, TrafficTreatment> nextTable) {
- this.bridgingTable = bridgingTable;
- this.nextTable = nextTable;
- }
-
- @Override
- public void forward(DeviceId deviceId, ForwardingObjective forwardingObjective) {
- TrafficSelector selector = forwardingObjective.selector();
- TrafficTreatment treatment = nextTable.get(forwardingObjective.nextId());
- MacAddress macAddress = ((EthCriterion) selector.getCriterion(Criterion.Type.ETH_DST)).mac();
- VlanId vlanId = ((VlanIdCriterion) selector.getCriterion(Criterion.Type.VLAN_VID)).vlanId();
-
- boolean popVlan = treatment.allInstructions().stream()
- .filter(instruction -> instruction.type().equals(Instruction.Type.L2MODIFICATION))
- .anyMatch(instruction -> ((L2ModificationInstruction) instruction).subtype()
- .equals(L2ModificationInstruction.L2SubType.VLAN_POP));
- PortNumber portNumber = treatment.allInstructions().stream()
- .filter(instruction -> instruction.type().equals(Instruction.Type.OUTPUT))
- .map(instruction -> ((Instructions.OutputInstruction) instruction).port()).findFirst().orElse(null);
- if (portNumber == null) {
- throw new IllegalArgumentException();
- }
-
- Objective.Operation op = forwardingObjective.op();
-
- MockBridgingTableKey btKey = new MockBridgingTableKey(deviceId, macAddress, vlanId);
- MockBridgingTableValue btValue = new MockBridgingTableValue(popVlan, portNumber);
-
- if (op.equals(Objective.Operation.ADD)) {
- bridgingTable.put(btKey, btValue);
- forwardingObjective.context().ifPresent(context -> context.onSuccess(forwardingObjective));
- } else if (op.equals(Objective.Operation.REMOVE)) {
- bridgingTable.remove(btKey, btValue);
- forwardingObjective.context().ifPresent(context -> context.onSuccess(forwardingObjective));
- } else {
- forwardingObjective.context().ifPresent(context ->
- context.onError(forwardingObjective, ObjectiveError.UNKNOWN));
- throw new IllegalArgumentException();
- }
- }
-}
diff --git a/app/src/test/java/org/onosproject/segmentrouting/MockHostProbingService.java b/app/src/test/java/org/onosproject/segmentrouting/MockHostProbingService.java
deleted file mode 100644
index 807db0c..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/MockHostProbingService.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2017-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;
-
-import com.google.common.collect.Lists;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.Host;
-import org.onosproject.net.host.HostProbingService;
-import org.onosproject.net.host.ProbeMode;
-
-import java.util.List;
-import java.util.Objects;
-
-public class MockHostProbingService implements HostProbingService {
- List<Probe> probes;
-
- private class Probe {
- private Host host;
- private ConnectPoint connectPoint;
- private ProbeMode probeMode;
-
- Probe(Host host, ConnectPoint connectPoint, ProbeMode probeMode) {
- this.host = host;
- this.connectPoint = connectPoint;
- this.probeMode = probeMode;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (!(o instanceof Probe)) {
- return false;
- }
- Probe that = (Probe) o;
- return (Objects.equals(this.host, that.host) &&
- Objects.equals(this.connectPoint, that.connectPoint) &&
- Objects.equals(this.probeMode, that.probeMode));
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(host, connectPoint, probeMode);
- }
- }
-
- MockHostProbingService() {
- probes = Lists.newArrayList();
- }
-
- boolean verifyProbe(Host host, ConnectPoint connectPoint, ProbeMode probeMode) {
- Probe probe = new Probe(host, connectPoint, probeMode);
- return probes.contains(probe);
- }
-
- @Override
- public void probeHost(Host host, ConnectPoint connectPoint, ProbeMode probeMode) {
- probes.add(new Probe(host, connectPoint, probeMode));
- }
-}
diff --git a/app/src/test/java/org/onosproject/segmentrouting/MockHostService.java b/app/src/test/java/org/onosproject/segmentrouting/MockHostService.java
deleted file mode 100644
index e8c4701..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/MockHostService.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2017-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;
-
-import com.google.common.collect.ImmutableSet;
-import org.onosproject.net.Host;
-import org.onosproject.net.HostId;
-import org.onosproject.net.host.HostServiceAdapter;
-
-import java.util.Set;
-
-/**
- * Mock Host Service.
- */
-public class MockHostService extends HostServiceAdapter {
- private Set<Host> hosts;
-
- MockHostService(Set<Host> hosts) {
- this.hosts = ImmutableSet.copyOf(hosts);
- }
-
- @Override
- public Set<Host> getHosts() {
- return hosts;
- }
-
- @Override
- public Host getHost(HostId hostId) {
- return hosts.stream().filter(host -> hostId.equals(host.id())).findFirst().orElse(null);
- }
-}
diff --git a/app/src/test/java/org/onosproject/segmentrouting/MockInterfaceService.java b/app/src/test/java/org/onosproject/segmentrouting/MockInterfaceService.java
deleted file mode 100644
index 6e170b0..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/MockInterfaceService.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2017-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;
-
-import com.google.common.collect.ImmutableSet;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.VlanId;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.intf.Interface;
-import org.onosproject.net.intf.impl.InterfaceManager;
-
-import java.util.Set;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import static java.util.stream.Collectors.toSet;
-
-/**
- * Mock Interface Service.
- */
-public class MockInterfaceService extends InterfaceManager {
- private Set<Interface> interfaces;
-
- MockInterfaceService(Set<Interface> interfaces) {
- this.interfaces = ImmutableSet.copyOf(interfaces);
- }
-
- @Override
- public Set<Interface> getInterfacesByPort(ConnectPoint cp) {
- return interfaces.stream().filter(intf -> cp.equals(intf.connectPoint()))
- .collect(Collectors.toSet());
- }
-
- @Override
- public Set<Interface> getInterfaces() {
- return interfaces;
- }
-
- @Override
- public Interface getMatchingInterface(IpAddress ip) {
- return getMatchingInterfacesStream(ip).findFirst().orElse(null);
- }
-
- @Override
- public Set<Interface> getMatchingInterfaces(IpAddress ip) {
- return getMatchingInterfacesStream(ip).collect(toSet());
- }
-
- private Stream<Interface> getMatchingInterfacesStream(IpAddress ip) {
- return interfaces.stream()
- .filter(intf -> intf.ipAddressesList().stream()
- .anyMatch(intfIp -> intfIp.subnetAddress().contains(ip)));
- }
-
- @Override
- public boolean isConfigured(ConnectPoint connectPoint) {
- Set<Interface> intfs = getInterfacesByPort(connectPoint);
- if (intfs == null) {
- return false;
- }
- for (Interface intf : intfs) {
- if (!intf.ipAddressesList().isEmpty() || intf.vlan() != VlanId.NONE
- || intf.vlanNative() != VlanId.NONE
- || intf.vlanUntagged() != VlanId.NONE
- || !intf.vlanTagged().isEmpty()) {
- return true;
- }
- }
- return false;
- }
-}
diff --git a/app/src/test/java/org/onosproject/segmentrouting/MockLinkHandler.java b/app/src/test/java/org/onosproject/segmentrouting/MockLinkHandler.java
deleted file mode 100644
index fe5df5d..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/MockLinkHandler.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2017-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;
-
-import org.onosproject.net.HostLocation;
-
-/**
- * Mocks the LinkHandler in SR.
- *
- */
-public class MockLinkHandler extends LinkHandler {
-
- MockLinkHandler(SegmentRoutingManager srManager) {
- super(srManager, null);
- }
-
- @Override
- void checkUplinksForHost(HostLocation loc) {
- // currently does nothing - can be extended to be a useful mock when
- // implementing unit tests for link handling
- }
-}
diff --git a/app/src/test/java/org/onosproject/segmentrouting/MockMastershipService.java b/app/src/test/java/org/onosproject/segmentrouting/MockMastershipService.java
deleted file mode 100644
index 5494e27..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/MockMastershipService.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2017-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;
-
-import com.google.common.collect.ImmutableSet;
-import org.onosproject.mastership.MastershipServiceAdapter;
-import org.onosproject.net.DeviceId;
-
-import java.util.Set;
-
-/**
- * Mock Mastership Service.
- */
-public class MockMastershipService extends MastershipServiceAdapter {
- // A set of devices of which we have mastership.
- private Set<DeviceId> localDevices;
-
- MockMastershipService(Set<DeviceId> localDevices) {
- this.localDevices = ImmutableSet.copyOf(localDevices);
- }
-
- @Override
- public boolean isLocalMaster(DeviceId deviceId) {
- return localDevices.contains(deviceId);
- }
-}
diff --git a/app/src/test/java/org/onosproject/segmentrouting/MockNeighbourResolutionService.java b/app/src/test/java/org/onosproject/segmentrouting/MockNeighbourResolutionService.java
deleted file mode 100644
index 5a41149..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/MockNeighbourResolutionService.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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;
-
-import org.onosproject.core.ApplicationId;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.intf.Interface;
-import org.onosproject.net.neighbour.NeighbourHandlerRegistration;
-import org.onosproject.net.neighbour.NeighbourMessageHandler;
-import org.onosproject.net.neighbour.NeighbourResolutionService;
-
-import java.util.Collection;
-import java.util.Map;
-
-/**
- * Mock Neighbour Resolution Service.
- */
-public class MockNeighbourResolutionService implements NeighbourResolutionService {
- @Override
- public void registerNeighbourHandler(ConnectPoint connectPoint,
- NeighbourMessageHandler handler, ApplicationId appId) {
-
- }
-
- @Override
- public void registerNeighbourHandler(Interface intf,
- NeighbourMessageHandler handler, ApplicationId appId) {
-
- }
-
- @Override
- public void unregisterNeighbourHandler(ConnectPoint connectPoint,
- NeighbourMessageHandler handler, ApplicationId appId) {
-
- }
-
- @Override
- public void unregisterNeighbourHandler(Interface intf,
- NeighbourMessageHandler handler, ApplicationId appId) {
-
- }
-
- @Override
- public void unregisterNeighbourHandlers(ApplicationId appId) {
-
- }
-
- @Override
- public Map<ConnectPoint, Collection<NeighbourHandlerRegistration>> getHandlerRegistrations() {
- return null;
- }
-}
diff --git a/app/src/test/java/org/onosproject/segmentrouting/MockNetworkConfigRegistry.java b/app/src/test/java/org/onosproject/segmentrouting/MockNetworkConfigRegistry.java
deleted file mode 100644
index 12d57ea..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/MockNetworkConfigRegistry.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2017-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;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.JsonNodeFactory;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.config.Config;
-import org.onosproject.net.config.NetworkConfigRegistryAdapter;
-import org.onosproject.net.config.basics.BasicDeviceConfig;
-
-import java.util.Objects;
-import java.util.Set;
-
-/**
- * Mock Network Config Registry.
- */
-class MockNetworkConfigRegistry extends NetworkConfigRegistryAdapter {
- private Set<Config> configs = Sets.newHashSet();
-
- void applyConfig(Config config) {
- configs.add(config);
- }
-
- @Override
- public <S, C extends Config<S>> C getConfig(S subject, Class<C> configClass) {
- Config c = configs.stream()
- .filter(config -> subject.equals(config.subject()))
- .filter(config -> configClass.equals(config.getClass()))
- .findFirst().orElse(null);
- return (C) c;
- }
-
- @Override
- public <S, C extends Config<S>> C addConfig(S subject, Class<C> configClass) {
- Config c = configs.stream()
- .filter(config -> subject.equals(config.subject()))
- .filter(config -> configClass.equals(config.getClass()))
- .findFirst().orElseGet(() -> {
- if (configClass.equals(BasicDeviceConfig.class)) {
- BasicDeviceConfig deviceConfig = new BasicDeviceConfig();
- ObjectMapper mapper = new ObjectMapper();
- deviceConfig.init((DeviceId) subject, ((DeviceId) subject).toString(),
- JsonNodeFactory.instance.objectNode(), mapper, config -> {
- });
- return deviceConfig;
- }
- return null;
- });
- return (C) c;
- }
-
- @Override
- public <S, C extends Config<S>> Set<S> getSubjects(Class<S> subject, Class<C> configClass) {
- ImmutableSet.Builder<S> builder = ImmutableSet.builder();
- String cName = configClass.getName();
- configs.forEach(k -> {
- if (subject.isInstance(k.subject()) && Objects.equals(cName, k.getClass().getName())) {
- builder.add((S) k.subject());
- }
- });
- return builder.build();
- }
-}
\ No newline at end of file
diff --git a/app/src/test/java/org/onosproject/segmentrouting/MockPacketService.java b/app/src/test/java/org/onosproject/segmentrouting/MockPacketService.java
deleted file mode 100644
index 73a8b65..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/MockPacketService.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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;
-
-import com.google.common.collect.Maps;
-import org.apache.commons.lang3.tuple.Pair;
-import org.onlab.packet.DeserializationException;
-import org.onlab.packet.Ethernet;
-import org.onlab.packet.MacAddress;
-import org.onosproject.net.packet.OutboundPacket;
-import org.onosproject.net.packet.PacketServiceAdapter;
-
-import java.util.Map;
-
-/**
- * Mock Packet Service.
- * It is used for tests related to packet-ins management.
- */
-public class MockPacketService extends PacketServiceAdapter {
-
- private final Map<MacAddress, Pair<OutboundPacket, Ethernet>> outBoundPackets = Maps.newHashMap();
-
- @Override
- public void emit(OutboundPacket packet) {
- try {
- Ethernet ethernetPacket = Ethernet.deserializer().deserialize(packet.data().array(),
- packet.data().arrayOffset(),
- packet.data().array().length);
- outBoundPackets.put(ethernetPacket.getDestinationMAC(), Pair.of(packet, ethernetPacket));
- } catch (DeserializationException e) {
-
- }
- }
-
- Ethernet getEthernetPacket(MacAddress key) {
- Pair<OutboundPacket, Ethernet> pair = outBoundPackets.get(key);
- return pair != null ? pair.getRight() : null;
- }
-}
diff --git a/app/src/test/java/org/onosproject/segmentrouting/MockRouteService.java b/app/src/test/java/org/onosproject/segmentrouting/MockRouteService.java
deleted file mode 100644
index c3730dd..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/MockRouteService.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2017-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;
-
-import com.google.common.collect.Sets;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.IpPrefix;
-import org.onosproject.routeservice.ResolvedRoute;
-import org.onosproject.routeservice.RouteInfo;
-import org.onosproject.routeservice.RouteServiceAdapter;
-import org.onosproject.routeservice.RouteTableId;
-
-import java.util.Collection;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/**
- * Mock Route Service.
- * We assume there is only one routing table named "default".
- */
-public class MockRouteService extends RouteServiceAdapter {
- private Map<IpPrefix, Set<ResolvedRoute>> routeStore;
-
- MockRouteService(Map<IpPrefix, Set<ResolvedRoute>> routeStore) {
- this.routeStore = routeStore;
- }
-
- @Override
- public Collection<RouteInfo> getRoutes(RouteTableId id) {
- return routeStore.entrySet().stream().map(e -> {
- IpPrefix prefix = e.getKey();
- Set<ResolvedRoute> resolvedRoutes = e.getValue();
- ResolvedRoute bestRoute = resolvedRoutes.stream().findFirst().orElse(null);
- return new RouteInfo(prefix, bestRoute, resolvedRoutes);
- }).collect(Collectors.toSet());
- }
-
- @Override
- public Collection<RouteTableId> getRouteTables() {
- return Sets.newHashSet(new RouteTableId("default"));
- }
-
- @Override
- public Optional<ResolvedRoute> longestPrefixLookup(IpAddress ip) {
- return this.routeStore.get(ip.toIpPrefix()).stream()
- .findFirst();
- }
-}
\ No newline at end of file
diff --git a/app/src/test/java/org/onosproject/segmentrouting/MockRoutingRulePopulator.java b/app/src/test/java/org/onosproject/segmentrouting/MockRoutingRulePopulator.java
deleted file mode 100644
index 4d222d8..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/MockRoutingRulePopulator.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2017-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;
-
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.flowobjective.Objective;
-
-import java.util.Map;
-import java.util.concurrent.CompletableFuture;
-
-/**
- * Mock Routing Rule Populator.
- */
-public class MockRoutingRulePopulator extends RoutingRulePopulator {
- private Map<MockRoutingTableKey, MockRoutingTableValue> routingTable;
-
- MockRoutingRulePopulator(SegmentRoutingManager srManager,
- Map<MockRoutingTableKey, MockRoutingTableValue> routingTable) {
- super(srManager);
- this.routingTable = routingTable;
- }
-
- @Override
- public CompletableFuture<Objective> populateRoute(DeviceId deviceId, IpPrefix prefix, MacAddress hostMac,
- VlanId hostVlanId, PortNumber outPort, boolean directHost) {
- MockRoutingTableKey rtKey = new MockRoutingTableKey(deviceId, prefix);
- MockRoutingTableValue rtValue = new MockRoutingTableValue(outPort, hostMac, hostVlanId);
- routingTable.put(rtKey, rtValue);
- return CompletableFuture.completedFuture(null);
- }
-
- @Override
- public CompletableFuture<Objective> revokeRoute(DeviceId deviceId, IpPrefix prefix,
- MacAddress hostMac, VlanId hostVlanId, PortNumber outPort, boolean directHost) {
- MockRoutingTableKey rtKey = new MockRoutingTableKey(deviceId, prefix);
- MockRoutingTableValue rtValue = new MockRoutingTableValue(outPort, hostMac, hostVlanId);
- routingTable.remove(rtKey, rtValue);
- return CompletableFuture.completedFuture(null);
- }
-}
diff --git a/app/src/test/java/org/onosproject/segmentrouting/MockRoutingTableKey.java b/app/src/test/java/org/onosproject/segmentrouting/MockRoutingTableKey.java
deleted file mode 100644
index 4f09c2a..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/MockRoutingTableKey.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2017-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;
-
-import org.onlab.packet.IpPrefix;
-import org.onosproject.net.DeviceId;
-
-import java.util.Objects;
-
-/**
- * Mock Routing Table Key.
- */
-class MockRoutingTableKey {
- DeviceId deviceId;
- IpPrefix ipPrefix;
-
- MockRoutingTableKey(DeviceId deviceId, IpPrefix ipPrefix) {
- this.deviceId = deviceId;
- this.ipPrefix = ipPrefix;
- }
-
- @Override
- public boolean equals(final Object obj) {
- if (this == obj) {
- return true;
- }
- if (!(obj instanceof MockRoutingTableKey)) {
- return false;
- }
- final MockRoutingTableKey other = (MockRoutingTableKey) obj;
- return Objects.equals(this.deviceId, other.deviceId) &&
- Objects.equals(this.ipPrefix, other.ipPrefix);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(deviceId, ipPrefix);
- }
-}
\ No newline at end of file
diff --git a/app/src/test/java/org/onosproject/segmentrouting/MockRoutingTableValue.java b/app/src/test/java/org/onosproject/segmentrouting/MockRoutingTableValue.java
deleted file mode 100644
index 5842d2d..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/MockRoutingTableValue.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2017-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;
-
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
-import org.onosproject.net.PortNumber;
-
-import java.util.Objects;
-
-/**
- * Mock Routing Table Value.
- */
-class MockRoutingTableValue {
- PortNumber portNumber;
- MacAddress macAddress;
- VlanId vlanId;
-
- MockRoutingTableValue(PortNumber portNumber, MacAddress macAddress, VlanId vlanId) {
- this.portNumber = portNumber;
- this.macAddress = macAddress;
- this.vlanId = vlanId;
- }
-
- @Override
- public boolean equals(final Object obj) {
- if (this == obj) {
- return true;
- }
- if (!(obj instanceof MockRoutingTableValue)) {
- return false;
- }
- final MockRoutingTableValue other = (MockRoutingTableValue) obj;
- return Objects.equals(this.portNumber, other.portNumber) &&
- Objects.equals(this.macAddress, other.macAddress) &&
- Objects.equals(this.vlanId, other.vlanId);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(portNumber, macAddress, vlanId);
- }
-}
-
diff --git a/app/src/test/java/org/onosproject/segmentrouting/MockSegmentRoutingManager.java b/app/src/test/java/org/onosproject/segmentrouting/MockSegmentRoutingManager.java
deleted file mode 100644
index ad098b4..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/MockSegmentRoutingManager.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2017-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;
-
-import org.onosproject.core.DefaultApplicationId;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.flow.TrafficSelector;
-import org.onosproject.net.flow.TrafficTreatment;
-
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * Mock Segment Routing Manager.
- */
-public class MockSegmentRoutingManager extends SegmentRoutingManager {
- private Map<Integer, TrafficTreatment> nextTable;
- private AtomicInteger atomicNextId = new AtomicInteger();
-
- MockSegmentRoutingManager(Map<Integer, TrafficTreatment> nextTable) {
- appId = new DefaultApplicationId(1, SegmentRoutingManager.APP_NAME);
- this.nextTable = nextTable;
- }
-
- @Override
- public int getPortNextObjectiveId(DeviceId deviceId, PortNumber portNum,
- TrafficTreatment treatment,
- TrafficSelector meta,
- boolean createIfMissing) {
- int nextId = atomicNextId.incrementAndGet();
- nextTable.put(nextId, treatment);
- return nextId;
- }
-}
diff --git a/app/src/test/java/org/onosproject/segmentrouting/PortAuthTrackerTest.java b/app/src/test/java/org/onosproject/segmentrouting/PortAuthTrackerTest.java
deleted file mode 100644
index 6ab4bad..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/PortAuthTrackerTest.java
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Copyright 2017-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;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import org.junit.Before;
-import org.junit.Test;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.core.DefaultApplicationId;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.PortNumber;
-import org.onosproject.segmentrouting.PortAuthTracker.BlockState;
-import org.onosproject.segmentrouting.config.BlockedPortsConfig;
-import org.onosproject.segmentrouting.config.BlockedPortsConfigTest;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.onosproject.net.ConnectPoint.deviceConnectPoint;
-import static org.onosproject.net.DeviceId.deviceId;
-import static org.onosproject.net.PortNumber.portNumber;
-import static org.onosproject.segmentrouting.PortAuthTracker.BlockState.AUTHENTICATED;
-import static org.onosproject.segmentrouting.PortAuthTracker.BlockState.BLOCKED;
-import static org.onosproject.segmentrouting.PortAuthTracker.BlockState.UNCHECKED;
-
-/**
- * Unit Tests for {@link PortAuthTracker}.
- */
-public class PortAuthTrackerTest {
- private static final ApplicationId APP_ID = new DefaultApplicationId(1, "foo");
- private static final String KEY = "blocked";
- private static final ObjectMapper MAPPER = new ObjectMapper();
- private static final String PATH_CFG = "/blocked-ports.json";
- private static final String PATH_CFG_ALT = "/blocked-ports-alt.json";
-
- private static final String DEV1 = "of:0000000000000001";
- private static final String DEV3 = "of:0000000000000003";
- private static final String DEV4 = "of:0000000000000004";
-
- private BlockedPortsConfig cfg;
- private AugmentedPortAuthTracker tracker;
-
- private void print(String s) {
- System.out.println(s);
- }
-
- private void print(Object o) {
- print(o.toString());
- }
-
- private void print(String fmt, Object... params) {
- print(String.format(fmt, params));
- }
-
- private void title(String s) {
- print("=== %s ===", s);
- }
-
- private BlockedPortsConfig makeConfig(String path) throws IOException {
- InputStream blockedPortsJson = BlockedPortsConfigTest.class
- .getResourceAsStream(path);
- JsonNode node = MAPPER.readTree(blockedPortsJson);
- BlockedPortsConfig cfg = new BlockedPortsConfig();
- cfg.init(APP_ID, KEY, node, MAPPER, null);
- return cfg;
- }
-
- ConnectPoint cp(String devId, int port) {
- return ConnectPoint.deviceConnectPoint(devId + "/" + port);
- }
-
- @Before
- public void setUp() throws IOException {
- cfg = makeConfig(PATH_CFG);
- tracker = new AugmentedPortAuthTracker();
- }
-
- private void verifyPortState(String devId, int first, BlockState... states) {
- DeviceId dev = deviceId(devId);
- int last = first + states.length;
- int pn = first;
- int i = 0;
- while (pn < last) {
- PortNumber pnum = portNumber(pn);
- BlockState actual = tracker.currentState(dev, pnum);
- print("%s/%s [%s] --> %s", devId, pn, states[i], actual);
- assertEquals("oops: " + devId + "/" + pn + "~" + actual,
- states[i], actual);
- pn++;
- i++;
- }
- }
-
- @Test
- public void basic() {
- title("basic");
- print(tracker);
- print(cfg);
-
- assertEquals("wrong entry count", 0, tracker.entryCount());
-
- // let's assume that the net config just got loaded..
- tracker.configurePortBlocking(cfg);
- assertEquals("wrong entry count", 13, tracker.entryCount());
-
- verifyPortState(DEV1, 1, BLOCKED, BLOCKED, BLOCKED, BLOCKED, UNCHECKED);
- verifyPortState(DEV1, 6, UNCHECKED, BLOCKED, BLOCKED, BLOCKED, UNCHECKED);
-
- verifyPortState(DEV3, 1, UNCHECKED, UNCHECKED, UNCHECKED);
- verifyPortState(DEV3, 6, UNCHECKED, BLOCKED, BLOCKED, BLOCKED, UNCHECKED);
-
- verifyPortState(DEV4, 1, BLOCKED, UNCHECKED, UNCHECKED, UNCHECKED, BLOCKED);
- }
-
- @Test
- public void logonLogoff() {
- title("logonLogoff");
-
- tracker.configurePortBlocking(cfg);
- assertEquals("wrong entry count", 13, tracker.entryCount());
- verifyPortState(DEV1, 1, BLOCKED, BLOCKED, BLOCKED);
-
- ConnectPoint cp = deviceConnectPoint(DEV1 + "/2");
- tracker.radiusAuthorize(cp);
- print("");
- verifyPortState(DEV1, 1, BLOCKED, AUTHENTICATED, BLOCKED);
-
- tracker.radiusLogoff(cp);
- print("");
- verifyPortState(DEV1, 1, BLOCKED, BLOCKED, BLOCKED);
- }
-
- @Test
- public void installedFlows() {
- title("installed flows");
-
- assertEquals(0, tracker.installed.size());
- tracker.configurePortBlocking(cfg);
- assertEquals(13, tracker.installed.size());
-
- assertTrue(tracker.installed.contains(cp(DEV1, 1)));
- assertTrue(tracker.installed.contains(cp(DEV3, 7)));
- assertTrue(tracker.installed.contains(cp(DEV4, 5)));
- }
-
- @Test
- public void flowsLogonLogoff() {
- title("flows logon logoff");
-
- tracker.configurePortBlocking(cfg);
-
- // let's pick a connect point from the configuration
- ConnectPoint cp = cp(DEV4, 5);
-
- assertTrue(tracker.installed.contains(cp));
- assertEquals(0, tracker.cleared.size());
-
- tracker.resetMetrics();
- tracker.radiusAuthorize(cp);
- // verify we requested the blocking flow to be cleared
- assertTrue(tracker.cleared.contains(cp));
-
- tracker.resetMetrics();
- assertEquals(0, tracker.installed.size());
- tracker.radiusLogoff(cp);
- // verify we requested the blocking flow to be reinstated
- assertTrue(tracker.installed.contains(cp));
- }
-
- @Test
- public void uncheckedPortIgnored() {
- title("unchecked port ignored");
-
- tracker.configurePortBlocking(cfg);
- tracker.resetMetrics();
-
- // let's pick a connect point NOT in the configuration
- ConnectPoint cp = cp(DEV4, 2);
- assertEquals(BlockState.UNCHECKED, tracker.currentState(cp));
-
- assertEquals(0, tracker.installed.size());
- assertEquals(0, tracker.cleared.size());
- tracker.radiusAuthorize(cp);
- assertEquals(0, tracker.installed.size());
- assertEquals(0, tracker.cleared.size());
- tracker.radiusLogoff(cp);
- assertEquals(0, tracker.installed.size());
- assertEquals(0, tracker.cleared.size());
- }
-
- @Test
- public void reconfiguration() throws IOException {
- title("reconfiguration");
-
- /* see 'blocked-ports.json' and 'blocked-ports-alt.json'
-
- cfg: "1": ["1-4", "7-9"],
- "3": ["7-9"],
- "4": ["1", "5", "9"]
-
- alt: "1": ["1-9"],
- "3": ["7"],
- "4": ["1"]
- */
- tracker.configurePortBlocking(cfg);
- // dev1: ports 5 and 6 are NOT configured in the original CFG
- assertFalse(tracker.installed.contains(cp(DEV1, 5)));
- assertFalse(tracker.installed.contains(cp(DEV1, 6)));
-
- tracker.resetMetrics();
- assertEquals(0, tracker.installed.size());
- assertEquals(0, tracker.cleared.size());
-
- BlockedPortsConfig alt = makeConfig(PATH_CFG_ALT);
- tracker.configurePortBlocking(alt);
-
- // dev1: ports 5 and 6 ARE configured in the alternate CFG
- assertTrue(tracker.installed.contains(cp(DEV1, 5)));
- assertTrue(tracker.installed.contains(cp(DEV1, 6)));
-
- // also, check for the ports that were decommissioned
- assertTrue(tracker.cleared.contains(cp(DEV3, 8)));
- assertTrue(tracker.cleared.contains(cp(DEV3, 9)));
- assertTrue(tracker.cleared.contains(cp(DEV4, 5)));
- assertTrue(tracker.cleared.contains(cp(DEV4, 9)));
- }
-}
diff --git a/app/src/test/java/org/onosproject/segmentrouting/RouteHandlerTest.java b/app/src/test/java/org/onosproject/segmentrouting/RouteHandlerTest.java
deleted file mode 100644
index f2a439b..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/RouteHandlerTest.java
+++ /dev/null
@@ -1,660 +0,0 @@
-/*
- * Copyright 2017-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;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import org.junit.Before;
-import org.junit.Test;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
-import org.onosproject.net.config.ConfigApplyDelegate;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DefaultHost;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Host;
-import org.onosproject.net.HostId;
-import org.onosproject.net.HostLocation;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.config.NetworkConfigRegistryAdapter;
-import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.host.HostEvent;
-import org.onosproject.net.host.HostService;
-import org.onosproject.net.host.InterfaceIpAddress;
-import org.onosproject.net.intf.Interface;
-import org.onosproject.net.provider.ProviderId;
-import org.onosproject.routeservice.ResolvedRoute;
-import org.onosproject.routeservice.Route;
-import org.onosproject.routeservice.RouteEvent;
-import org.onosproject.segmentrouting.config.DeviceConfiguration;
-import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
-import org.onosproject.segmentrouting.phasedrecovery.api.PhasedRecoveryService;
-import org.onosproject.store.service.StorageService;
-import org.onosproject.store.service.TestConsistentMap;
-import org.onosproject.store.service.TestConsistentMultimap;
-
-import java.util.Map;
-import java.util.Set;
-
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.reset;
-import static org.junit.Assert.*;
-import static org.easymock.EasyMock.createMock;
-import static org.easymock.EasyMock.expectLastCall;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.verify;
-
-/**
- * Unit test for {@link RouteHandler}.
- */
-public class RouteHandlerTest {
- private SegmentRoutingManager srManager;
- private RouteHandler routeHandler;
- private HostService hostService;
-
- // Mocked routing and bridging tables
- private static final Map<MockBridgingTableKey, MockBridgingTableValue> BRIDGING_TABLE =
- Maps.newConcurrentMap();
- private static final Map<MockRoutingTableKey, MockRoutingTableValue> ROUTING_TABLE =
- Maps.newConcurrentMap();
- private static final Map<ConnectPoint, Set<IpPrefix>> SUBNET_TABLE = Maps.newConcurrentMap();
- // Mocked Next Id
- private static final Map<Integer, TrafficTreatment> NEXT_TABLE = Maps.newConcurrentMap();
- private static final Map<IpPrefix, Set<ResolvedRoute>> ROUTE_STORE = Maps.newConcurrentMap();
-
- private static final IpPrefix P1 = IpPrefix.valueOf("10.0.0.0/24");
-
- // Single homed router 1
- private static final IpAddress N1 = IpAddress.valueOf("10.0.1.1");
- private static final MacAddress M1 = MacAddress.valueOf("00:00:00:00:00:01");
- private static final VlanId V1 = VlanId.vlanId((short) 1);
- private static final ConnectPoint CP1 = ConnectPoint.deviceConnectPoint("of:0000000000000001/1");
- private static final Route R1 = new Route(Route.Source.STATIC, P1, N1);
- private static final ResolvedRoute RR1 = new ResolvedRoute(R1, M1, V1);
- private static final Route DHCP_R1 = new Route(Route.Source.DHCP, P1, N1);
- private static final ResolvedRoute DHCP_RR1 = new ResolvedRoute(DHCP_R1, M1, V1);
-
- // Single homed router 2
- private static final IpAddress N2 = IpAddress.valueOf("10.0.2.1");
- private static final MacAddress M2 = MacAddress.valueOf("00:00:00:00:00:02");
- private static final VlanId V2 = VlanId.vlanId((short) 2);
- private static final ConnectPoint CP2 = ConnectPoint.deviceConnectPoint("of:0000000000000002/2");
- private static final Route R2 = new Route(Route.Source.STATIC, P1, N2);
- private static final ResolvedRoute RR2 = new ResolvedRoute(R2, M2, V2);
-
- // Dual homed router 1
- private static final IpAddress N3 = IpAddress.valueOf("10.0.3.1");
- private static final MacAddress M3 = MacAddress.valueOf("00:00:00:00:00:03");
- private static final VlanId V3 = VlanId.vlanId((short) 3);
- private static final Route R3 = new Route(Route.Source.STATIC, P1, N3);
- private static final ResolvedRoute RR3 = new ResolvedRoute(R3, M3, V3);
- private static final Route DHCP_R3 = new Route(Route.Source.DHCP, P1, N3);
- private static final ResolvedRoute DHCP_RR3 = new ResolvedRoute(DHCP_R3, M3, V3);
-
- // Single homed router 3
- private static final IpAddress N4 = IpAddress.valueOf("10.0.4.1");
- private static final MacAddress M4 = MacAddress.valueOf("00:00:00:00:00:04");
- private static final VlanId V4 = VlanId.vlanId((short) 4);
- private static final ConnectPoint CP4 = ConnectPoint.deviceConnectPoint("of:0000000000000004/4");
- private static final Route R4 = new Route(Route.Source.STATIC, P1, N4);
- private static final ResolvedRoute RR4 = new ResolvedRoute(R4, M4, V4);
-
- // Hosts
- private static final Host H1 = new DefaultHost(ProviderId.NONE, HostId.hostId(M1, V1), M1, V1,
- Sets.newHashSet(new HostLocation(CP1, 0)), Sets.newHashSet(N1), false);
- private static final Host H2 = new DefaultHost(ProviderId.NONE, HostId.hostId(M2, V2), M2, V2,
- Sets.newHashSet(new HostLocation(CP2, 0)), Sets.newHashSet(N2), false);
- private static final Host H3D = new DefaultHost(ProviderId.NONE, HostId.hostId(M3, V3), M3, V3,
- Sets.newHashSet(new HostLocation(CP1, 0), new HostLocation(CP2, 0)), Sets.newHashSet(N3), false);
- private static final Host H3S = new DefaultHost(ProviderId.NONE, HostId.hostId(M3, V3), M3, V3,
- Sets.newHashSet(new HostLocation(CP1, 0)), Sets.newHashSet(N3), false);
- private static final Host H4 = new DefaultHost(ProviderId.NONE, HostId.hostId(M4, V4), M4, V4,
- Sets.newHashSet(new HostLocation(CP4, 0)), Sets.newHashSet(N4), false);
-
- // Pair Local Port
- private static final PortNumber P9 = PortNumber.portNumber(9);
-
- // A set of hosts
- private static final Set<Host> HOSTS = Sets.newHashSet(H1, H2, H3D, H4);
- private static final Set<Host> HOSTS_ONE_FAIL = Sets.newHashSet(H1, H2, H3S);
- private static final Set<Host> HOSTS_BOTH_FAIL = Sets.newHashSet(H1, H2);
- // A set of devices of which we have mastership
- private static final Set<DeviceId> LOCAL_DEVICES = Sets.newHashSet(CP1.deviceId(), CP2.deviceId());
- // A set of interfaces
- private static final InterfaceIpAddress IF_IP1 =
- new InterfaceIpAddress(IpAddress.valueOf("10.0.1.254"), IpPrefix.valueOf("10.0.1.254/24"));
- private static final InterfaceIpAddress IF_IP3 =
- new InterfaceIpAddress(IpAddress.valueOf("10.0.3.254"), IpPrefix.valueOf("10.0.3.254/24"));
- private static final Interface IF_CP1 = new Interface("if-cp1", CP1, Lists.newArrayList(IF_IP1, IF_IP3),
- null, null, null, null, null);
- private static final Interface IF_CP2 = new Interface("if-cp2", CP2, Lists.newArrayList(IF_IP1, IF_IP3),
- null, null, null, null, null);
- private static final Set<Interface> INTERFACES = Sets.newHashSet(IF_CP1, IF_CP2);
-
- @Before
- public void setUp() {
- ObjectMapper mapper = new ObjectMapper();
- ConfigApplyDelegate delegate = config -> { };
-
- SegmentRoutingDeviceConfig dev1Config = new SegmentRoutingDeviceConfig();
- JsonNode dev1Tree = mapper.createObjectNode();
- dev1Config.init(CP1.deviceId(), "host-handler-test", dev1Tree, mapper, delegate);
- dev1Config.setPairDeviceId(CP2.deviceId()).setPairLocalPort(P9);
-
- SegmentRoutingDeviceConfig dev2Config = new SegmentRoutingDeviceConfig();
- JsonNode dev2Tree = mapper.createObjectNode();
- dev2Config.init(CP2.deviceId(), "host-handler-test", dev2Tree, mapper, delegate);
- dev2Config.setPairDeviceId(CP1.deviceId()).setPairLocalPort(P9);
-
- MockNetworkConfigRegistry mockNetworkConfigRegistry = new MockNetworkConfigRegistry();
- mockNetworkConfigRegistry.applyConfig(dev1Config);
- mockNetworkConfigRegistry.applyConfig(dev2Config);
-
- // Initialize Segment Routing Manager
- srManager = new MockSegmentRoutingManager(NEXT_TABLE);
- srManager.storageService = createMock(StorageService.class);
- expect(srManager.storageService.consistentMapBuilder()).andReturn(new TestConsistentMap.Builder<>()).anyTimes();
- expect(srManager.storageService.consistentMultimapBuilder()).andReturn(
- new TestConsistentMultimap.Builder<>()).anyTimes();
- replay(srManager.storageService);
- srManager.cfgService = new NetworkConfigRegistryAdapter();
- srManager.deviceConfiguration = createMock(DeviceConfiguration.class);
- srManager.flowObjectiveService = new MockFlowObjectiveService(BRIDGING_TABLE, NEXT_TABLE);
- srManager.routingRulePopulator = new MockRoutingRulePopulator(srManager, ROUTING_TABLE);
- srManager.defaultRoutingHandler = new MockDefaultRoutingHandler(srManager, SUBNET_TABLE, ROUTING_TABLE);
- srManager.interfaceService = new MockInterfaceService(INTERFACES);
- srManager.mastershipService = new MockMastershipService(LOCAL_DEVICES);
- hostService = new MockHostService(HOSTS);
- srManager.hostService = hostService;
- srManager.cfgService = mockNetworkConfigRegistry;
- srManager.routeService = new MockRouteService(ROUTE_STORE);
- srManager.phasedRecoveryService = createMock(PhasedRecoveryService.class);
- expect(srManager.phasedRecoveryService.isEnabled()).andReturn(true).anyTimes();
- replay(srManager.phasedRecoveryService);
-
- routeHandler = new RouteHandler(srManager);
-
- ROUTING_TABLE.clear();
- BRIDGING_TABLE.clear();
- SUBNET_TABLE.clear();
- }
-
- @Test
- public void init() {
- ROUTE_STORE.put(P1, Sets.newHashSet(RR1));
-
- routeHandler.init(CP1.deviceId());
-
- assertEquals(1, ROUTING_TABLE.size());
- MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
- assertEquals(M1, rtv1.macAddress);
- assertEquals(V1, rtv1.vlanId);
- assertEquals(CP1.port(), rtv1.portNumber);
-
- assertEquals(1, SUBNET_TABLE.size());
- }
-
- @Test
- public void initTwoNextHops() {
- ROUTE_STORE.put(P1, Sets.newHashSet(RR1, RR2));
-
- routeHandler.init(CP1.deviceId());
-
- assertEquals(2, ROUTING_TABLE.size());
- MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
- assertEquals(M1, rtv1.macAddress);
- assertEquals(V1, rtv1.vlanId);
- assertEquals(CP1.port(), rtv1.portNumber);
- MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
- assertEquals(M2, rtv2.macAddress);
- assertEquals(V2, rtv2.vlanId);
- assertEquals(CP2.port(), rtv2.portNumber);
-
- assertEquals(2, SUBNET_TABLE.size());
- }
-
- // Only one of two dual-homed next hops present.
- // Expect one routing table to be programmed with direct flow.
- // The other is not programmed, not even for subnet
- @Test
- public void initDhcpRouteSingleDualHomeNextHop() {
- ROUTE_STORE.put(P1, Sets.newHashSet(DHCP_RR1));
-
- routeHandler.init(CP1.deviceId());
-
- assertEquals(1, ROUTING_TABLE.size());
- MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
- assertEquals(M1, rtv1.macAddress);
- assertEquals(V1, rtv1.vlanId);
- assertEquals(CP1.port(), rtv1.portNumber);
-
- assertEquals(1, SUBNET_TABLE.size());
- }
-
- // Both dual-homed next hops present.
- // Expect both routing table to be programmed with direct flow
- @Test
- public void initDhcpRouteBothDualHomeNextHop() {
- ROUTE_STORE.put(P1, Sets.newHashSet(DHCP_RR3));
-
- routeHandler.init(CP1.deviceId());
-
- assertEquals(2, ROUTING_TABLE.size());
- MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
- assertEquals(M3, rtv1.macAddress);
- assertEquals(V3, rtv1.vlanId);
- assertEquals(CP1.port(), rtv1.portNumber);
-
- MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
- assertEquals(M3, rtv2.macAddress);
- assertEquals(V3, rtv2.vlanId);
- assertEquals(CP2.port(), rtv2.portNumber);
-
- assertEquals(2, SUBNET_TABLE.size());
- }
-
- @Test
- public void processRouteAdded() {
- reset(srManager.deviceConfiguration);
- srManager.deviceConfiguration.addSubnet(CP1, P1);
- expectLastCall().once();
- replay(srManager.deviceConfiguration);
-
- RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1));
- routeHandler.processRouteAdded(re);
-
- assertEquals(1, ROUTING_TABLE.size());
- MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
- assertEquals(M1, rtv1.macAddress);
- assertEquals(V1, rtv1.vlanId);
- assertEquals(CP1.port(), rtv1.portNumber);
-
- assertEquals(1, SUBNET_TABLE.size());
- assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
-
- verify(srManager.deviceConfiguration);
- }
-
- @Test
- public void processRouteUpdated() {
- processRouteAdded();
-
- reset(srManager.deviceConfiguration);
- srManager.deviceConfiguration.removeSubnet(CP1, P1);
- expectLastCall().once();
- srManager.deviceConfiguration.addSubnet(CP2, P1);
- expectLastCall().once();
- replay(srManager.deviceConfiguration);
-
- RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_UPDATED, RR2, RR1, Sets.newHashSet(RR2),
- Sets.newHashSet(RR1));
- routeHandler.processRouteUpdated(re);
-
- // Note: We shouldn't remove the old nexthop during the occasion of route update
- // since the populate subnet will take care of it and point it to an ECMP group
- assertEquals(2, ROUTING_TABLE.size());
- MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
- assertEquals(M2, rtv2.macAddress);
- assertEquals(V2, rtv2.vlanId);
- assertEquals(CP2.port(), rtv2.portNumber);
-
- assertEquals(1, SUBNET_TABLE.size());
- assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
-
- verify(srManager.deviceConfiguration);
- }
-
- @Test
- public void processRouteRemoved() {
- processRouteAdded();
-
- reset(srManager.deviceConfiguration);
- srManager.deviceConfiguration.removeSubnet(CP1, P1);
- expectLastCall().once();
- replay(srManager.deviceConfiguration);
-
- RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR1, Sets.newHashSet(RR1));
- routeHandler.processRouteRemoved(re);
-
- assertEquals(0, ROUTING_TABLE.size());
- assertEquals(0, SUBNET_TABLE.size());
-
- verify(srManager.deviceConfiguration);
- }
-
- @Test
- public void testTwoSingleHomedAdded() {
- reset(srManager.deviceConfiguration);
- srManager.deviceConfiguration.addSubnet(CP1, P1);
- expectLastCall().once();
- srManager.deviceConfiguration.addSubnet(CP2, P1);
- expectLastCall().once();
- replay(srManager.deviceConfiguration);
-
- RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1, RR2));
- routeHandler.processRouteAdded(re);
-
- assertEquals(2, ROUTING_TABLE.size());
- MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
- MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
- assertEquals(M1, rtv1.macAddress);
- assertEquals(M2, rtv2.macAddress);
- assertEquals(V1, rtv1.vlanId);
- assertEquals(V2, rtv2.vlanId);
- assertEquals(CP1.port(), rtv1.portNumber);
- assertEquals(CP2.port(), rtv2.portNumber);
-
- assertEquals(2, SUBNET_TABLE.size());
- assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
- assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
-
- verify(srManager.deviceConfiguration);
- }
-
- @Test
- public void testOneDualHomedAdded() {
- reset(srManager.deviceConfiguration);
- srManager.deviceConfiguration.addSubnet(CP1, P1);
- expectLastCall().once();
- srManager.deviceConfiguration.addSubnet(CP2, P1);
- expectLastCall().once();
- replay(srManager.deviceConfiguration);
-
- RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR3, Sets.newHashSet(RR3));
- routeHandler.processRouteAdded(re);
-
- assertEquals(2, ROUTING_TABLE.size());
- MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
- MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
- assertEquals(M3, rtv1.macAddress);
- assertEquals(M3, rtv2.macAddress);
- assertEquals(V3, rtv1.vlanId);
- assertEquals(V3, rtv2.vlanId);
- assertEquals(CP1.port(), rtv1.portNumber);
- assertEquals(CP2.port(), rtv2.portNumber);
-
- assertEquals(2, SUBNET_TABLE.size());
- assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
- assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
-
- verify(srManager.deviceConfiguration);
- }
-
- @Test
- public void testOneSingleHomedToTwoSingleHomed() {
- processRouteAdded();
-
- reset(srManager.deviceConfiguration);
- srManager.deviceConfiguration.addSubnet(CP2, P1);
- expectLastCall().once();
- replay(srManager.deviceConfiguration);
-
- RouteEvent re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
- Sets.newHashSet(RR1, RR2), Sets.newHashSet(RR1));
- routeHandler.processAlternativeRoutesChanged(re);
-
- assertEquals(2, ROUTING_TABLE.size());
- MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
- MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
- assertEquals(M1, rtv1.macAddress);
- assertEquals(M2, rtv2.macAddress);
- assertEquals(V1, rtv1.vlanId);
- assertEquals(V2, rtv2.vlanId);
- assertEquals(CP1.port(), rtv1.portNumber);
- assertEquals(CP2.port(), rtv2.portNumber);
-
- assertEquals(2, SUBNET_TABLE.size());
- assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
- assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
-
- verify(srManager.deviceConfiguration);
- }
-
- @Test
- public void testTwoSingleHomedToOneSingleHomed() {
- testTwoSingleHomedAdded();
-
- reset(srManager.deviceConfiguration);
- srManager.deviceConfiguration.removeSubnet(CP2, P1);
- expectLastCall().once();
- replay(srManager.deviceConfiguration);
-
- RouteEvent re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
- Sets.newHashSet(RR1), Sets.newHashSet(RR1, RR2));
- routeHandler.processAlternativeRoutesChanged(re);
-
- // Note: We shouldn't remove the old nexthop during the occasion of route update
- // since the populate subnet will take care of it and point it to an ECMP group
- assertEquals(2, ROUTING_TABLE.size());
- MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
- assertEquals(M1, rtv1.macAddress);
- assertEquals(V1, rtv1.vlanId);
- assertEquals(CP1.port(), rtv1.portNumber);
-
- assertEquals(1, SUBNET_TABLE.size());
- assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
-
- verify(srManager.deviceConfiguration);
- }
-
- // TODO Add test cases for two single homed next hop at same location
-
- @Test
- public void testDualHomedSingleLocationFail() {
- testOneDualHomedAdded();
-
- ROUTE_STORE.put(P1, Sets.newHashSet(RR3));
-
- reset(srManager.deviceConfiguration);
- expect(srManager.deviceConfiguration.getBatchedSubnets(H3D.id()))
- .andReturn(Lists.<Set<IpPrefix>>newArrayList(Sets.newHashSet(P1)));
- srManager.deviceConfiguration.removeSubnet(CP2, P1);
- expectLastCall().once();
- replay(srManager.deviceConfiguration);
-
- HostEvent he = new HostEvent(HostEvent.Type.HOST_MOVED, H3S, H3D);
- routeHandler.processHostMovedEvent(he);
-
- // We do not remove the route on CP2. Instead, we let the subnet population overrides it
- assertEquals(2, ROUTING_TABLE.size());
- MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
- assertEquals(M3, rtv1.macAddress);
- assertEquals(V3, rtv1.vlanId);
- assertEquals(CP1.port(), rtv1.portNumber);
-
- // ECMP route table hasn't changed
- assertEquals(1, SUBNET_TABLE.size());
- assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
-
- verify(srManager.deviceConfiguration);
- }
-
- @Test
- public void testDualHomedBothLocationFail() {
- testDualHomedSingleLocationFail();
-
- hostService = new MockHostService(HOSTS_ONE_FAIL);
-
- reset(srManager.deviceConfiguration);
- srManager.deviceConfiguration.removeSubnet(CP1, P1);
- expectLastCall().once();
- srManager.deviceConfiguration.removeSubnet(CP2, P1);
- expectLastCall().once();
- replay(srManager.deviceConfiguration);
-
- RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR3, Sets.newHashSet(RR3));
- routeHandler.processRouteRemoved(re);
-
- assertEquals(0, ROUTING_TABLE.size());
- assertEquals(0, SUBNET_TABLE.size());
-
- verify(srManager.deviceConfiguration);
- }
-
- @Test
- public void testSingleHomedToDualHomed() {
- testDualHomedSingleLocationFail();
-
- reset(srManager.deviceConfiguration);
- expect(srManager.deviceConfiguration.getBatchedSubnets(H3S.id()))
- .andReturn(Lists.<Set<IpPrefix>>newArrayList(Sets.newHashSet(P1)));
- srManager.deviceConfiguration.addSubnet(CP2, P1);
- expectLastCall().once();
- replay(srManager.deviceConfiguration);
-
- HostEvent he = new HostEvent(HostEvent.Type.HOST_MOVED, H3D, H3S);
- routeHandler.processHostMovedEvent(he);
-
- assertEquals(2, ROUTING_TABLE.size());
- MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
- MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
- assertEquals(M3, rtv1.macAddress);
- assertEquals(M3, rtv2.macAddress);
- assertEquals(V3, rtv1.vlanId);
- assertEquals(V3, rtv2.vlanId);
- assertEquals(CP1.port(), rtv1.portNumber);
- assertEquals(CP2.port(), rtv2.portNumber);
-
- assertEquals(2, SUBNET_TABLE.size());
- assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
- assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
-
- verify(srManager.deviceConfiguration);
- }
-
- @Test
- public void testTwoSingleHomedRemoved() {
- testTwoSingleHomedAdded();
-
- hostService = new MockHostService(HOSTS_BOTH_FAIL);
-
- reset(srManager.deviceConfiguration);
- srManager.deviceConfiguration.removeSubnet(CP1, P1);
- expectLastCall().once();
- srManager.deviceConfiguration.removeSubnet(CP2, P1);
- expectLastCall().once();
- replay(srManager.deviceConfiguration);
-
- RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR1, Sets.newHashSet(RR1, RR2));
- routeHandler.processRouteRemoved(re);
-
- assertEquals(0, ROUTING_TABLE.size());
- assertEquals(0, SUBNET_TABLE.size());
-
- verify(srManager.deviceConfiguration);
- }
-
- @Test
- public void testOneDualHomeRemoved() {
- testOneDualHomedAdded();
-
- reset(srManager.deviceConfiguration);
- srManager.deviceConfiguration.removeSubnet(CP1, P1);
- expectLastCall().once();
- srManager.deviceConfiguration.removeSubnet(CP2, P1);
- expectLastCall().once();
- replay(srManager.deviceConfiguration);
-
- RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR3, Sets.newHashSet(RR3));
- routeHandler.processRouteRemoved(re);
-
- assertEquals(0, ROUTING_TABLE.size());
- assertEquals(0, SUBNET_TABLE.size());
-
- verify(srManager.deviceConfiguration);
- }
-
- @Test
- public void testMoreThanTwoNextHop() {
- // next hop = CP1, CP2
- reset(srManager.deviceConfiguration);
- srManager.deviceConfiguration.addSubnet(CP1, P1);
- srManager.deviceConfiguration.addSubnet(CP2, P1);
- expectLastCall().once();
- replay(srManager.deviceConfiguration);
-
- RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1, RR2));
- routeHandler.processRouteAdded(re);
-
- assertEquals(2, ROUTING_TABLE.size());
- MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
- assertEquals(M1, rtv1.macAddress);
- assertEquals(V1, rtv1.vlanId);
- assertEquals(CP1.port(), rtv1.portNumber);
- MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
- assertEquals(M2, rtv2.macAddress);
- assertEquals(V2, rtv2.vlanId);
- assertEquals(CP2.port(), rtv2.portNumber);
-
- assertEquals(2, SUBNET_TABLE.size());
- assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
- assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
-
- verify(srManager.deviceConfiguration);
-
- // next hop = CP1, CP2, CP4 (invalid)
- re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
- Sets.newHashSet(RR1, RR2, RR4), Sets.newHashSet(RR1, RR2));
- routeHandler.processAlternativeRoutesChanged(re);
-
- assertEquals(2, ROUTING_TABLE.size());
- rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
- assertEquals(M1, rtv1.macAddress);
- assertEquals(V1, rtv1.vlanId);
- assertEquals(CP1.port(), rtv1.portNumber);
- rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
- assertEquals(M2, rtv2.macAddress);
- assertEquals(V2, rtv2.vlanId);
- assertEquals(CP2.port(), rtv2.portNumber);
-
- assertEquals(2, SUBNET_TABLE.size());
- assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
- assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
-
- // next hop = CP2, CP4
- reset(srManager.deviceConfiguration);
- srManager.deviceConfiguration.addSubnet(CP2, P1);
- srManager.deviceConfiguration.addSubnet(CP4, P1);
- expectLastCall().once();
- replay(srManager.deviceConfiguration);
-
- re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
- Sets.newHashSet(RR2, RR4), Sets.newHashSet(RR1, RR2, RR4));
- routeHandler.processAlternativeRoutesChanged(re);
-
- assertEquals(2, ROUTING_TABLE.size());
- rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
- assertEquals(M2, rtv1.macAddress);
- assertEquals(V2, rtv1.vlanId);
- assertEquals(CP2.port(), rtv1.portNumber);
- rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP4.deviceId(), P1));
- assertEquals(M4, rtv2.macAddress);
- assertEquals(V4, rtv2.vlanId);
- assertEquals(CP4.port(), rtv2.portNumber);
-
- assertEquals(2, SUBNET_TABLE.size());
- assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
- assertTrue(SUBNET_TABLE.get(CP4).contains(P1));
-
- verify(srManager.deviceConfiguration);
- }
-}
diff --git a/app/src/test/java/org/onosproject/segmentrouting/RoutingRulePopulatorTest.java b/app/src/test/java/org/onosproject/segmentrouting/RoutingRulePopulatorTest.java
deleted file mode 100644
index c8afeef..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/RoutingRulePopulatorTest.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright 2018-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;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import org.easymock.EasyMock;
-import org.junit.Before;
-import org.junit.Test;
-import org.onlab.packet.VlanId;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DefaultDevice;
-import org.onosproject.net.DefaultPort;
-import org.onosproject.net.Device;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Port;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.intf.Interface;
-import org.onosproject.net.intf.InterfaceService;
-import org.onosproject.net.provider.ProviderId;
-import org.onosproject.segmentrouting.config.DeviceConfiguration;
-
-import java.util.List;
-import java.util.Set;
-
-import static org.easymock.EasyMock.anyObject;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-import static org.junit.Assert.*;
-
-public class RoutingRulePopulatorTest {
- private RoutingRulePopulator rrp;
- private SegmentRoutingManager srManager;
- private InterfaceService interfaceService;
- private DeviceService deviceService;
-
- private final DeviceId devId1 = DeviceId.deviceId("of:1");
- private final Device dev1 = new DefaultDevice(ProviderId.NONE, devId1, Device.Type.SWITCH,
- null, null, null, null, null);
-
- private final PortNumber p1 = PortNumber.portNumber(1);
- private final PortNumber p2 = PortNumber.portNumber(2);
- private final PortNumber p3 = PortNumber.portNumber(3);
- private final PortNumber p4 = PortNumber.portNumber(4);
- private final PortNumber p5 = PortNumber.portNumber(5);
-
- private final VlanId v10 = VlanId.vlanId((short) 10);
- private final VlanId v20 = VlanId.vlanId((short) 20);
- private VlanId vInt;
-
- private final Interface u10 = new Interface(null, new ConnectPoint(devId1, p1),
- null, null, null, v10, null, null);
- private final Interface t10 = new Interface(null, new ConnectPoint(devId1, p2),
- null, null, null, null, Sets.newHashSet(v10), null);
- private final Interface t10n20 = new Interface(null, new ConnectPoint(devId1, p3),
- null, null, null, null, Sets.newHashSet(v10), v20);
-
- @Before
- public void setUp() throws Exception {
- Set<Interface> interfaces = Sets.newHashSet(u10, t10, t10n20);
- interfaceService = new MockInterfaceService(interfaces);
- deviceService = EasyMock.createMock(DeviceService.class);
- srManager = new MockSegmentRoutingManager(Maps.newHashMap());
- srManager.deviceConfiguration = EasyMock.createMock(DeviceConfiguration.class);
- srManager.interfaceService = interfaceService;
- srManager.deviceService = deviceService;
- vInt = srManager.getDefaultInternalVlan();
- rrp = new RoutingRulePopulator(srManager);
- }
-
- // All ports are enabled
- @Test
- public void testNoMoreEnabledPortCase1() throws Exception {
- Port port1 = new DefaultPort(dev1, p1, true);
- Port port2 = new DefaultPort(dev1, p2, true);
- Port port3 = new DefaultPort(dev1, p3, true);
- Port port4 = new DefaultPort(dev1, p4, true);
- Port port5 = new DefaultPort(dev1, p5, true);
- List<Port> ports = Lists.newArrayList(port1, port2, port3, port4, port5);
-
- expect(deviceService.getPorts(anyObject(DeviceId.class))).andReturn(ports).anyTimes();
- replay(deviceService);
- assertFalse(rrp.noMoreEnabledPort(devId1, v10));
- assertFalse(rrp.noMoreEnabledPort(devId1, v20));
- assertFalse(rrp.noMoreEnabledPort(devId1, vInt));
- }
-
- // Disable port 1
- @Test
- public void testNoMoreEnabledPortCase2() throws Exception {
- Port port1 = new DefaultPort(dev1, p1, false);
- Port port2 = new DefaultPort(dev1, p2, true);
- Port port3 = new DefaultPort(dev1, p3, true);
- Port port4 = new DefaultPort(dev1, p4, true);
- Port port5 = new DefaultPort(dev1, p5, true);
- List<Port> ports = Lists.newArrayList(port1, port2, port3, port4, port5);
-
- expect(deviceService.getPorts(anyObject(DeviceId.class))).andReturn(ports).anyTimes();
- replay(deviceService);
- assertFalse(rrp.noMoreEnabledPort(devId1, v10));
- assertFalse(rrp.noMoreEnabledPort(devId1, v20));
- assertFalse(rrp.noMoreEnabledPort(devId1, vInt));
- }
-
- // Disable port 1 and 3
- @Test
- public void testNoMoreEnabledPortCase3() throws Exception {
- Port port1 = new DefaultPort(dev1, p1, false);
- Port port2 = new DefaultPort(dev1, p2, true);
- Port port3 = new DefaultPort(dev1, p3, false);
- Port port4 = new DefaultPort(dev1, p4, true);
- Port port5 = new DefaultPort(dev1, p5, true);
- List<Port> ports = Lists.newArrayList(port1, port2, port3, port4, port5);
-
- expect(deviceService.getPorts(anyObject(DeviceId.class))).andReturn(ports).anyTimes();
- replay(deviceService);
- assertFalse(rrp.noMoreEnabledPort(devId1, v10));
- assertTrue(rrp.noMoreEnabledPort(devId1, v20));
- assertFalse(rrp.noMoreEnabledPort(devId1, vInt));
- }
-
- // Disable port 1 to 3
- @Test
- public void testNoMoreEnabledPortCase4() throws Exception {
- Port port1 = new DefaultPort(dev1, p1, false);
- Port port2 = new DefaultPort(dev1, p2, false);
- Port port3 = new DefaultPort(dev1, p3, false);
- Port port4 = new DefaultPort(dev1, p4, true);
- Port port5 = new DefaultPort(dev1, p5, true);
- List<Port> ports = Lists.newArrayList(port1, port2, port3, port4, port5);
-
- expect(deviceService.getPorts(anyObject(DeviceId.class))).andReturn(ports).anyTimes();
- replay(deviceService);
- assertTrue(rrp.noMoreEnabledPort(devId1, v10));
- assertTrue(rrp.noMoreEnabledPort(devId1, v20));
- assertFalse(rrp.noMoreEnabledPort(devId1, vInt));
- }
-
- // Disable port 1 to 4
- @Test
- public void testNoMoreEnabledPortCase5() throws Exception {
- Port port1 = new DefaultPort(dev1, p1, false);
- Port port2 = new DefaultPort(dev1, p2, false);
- Port port3 = new DefaultPort(dev1, p3, false);
- Port port4 = new DefaultPort(dev1, p4, false);
- Port port5 = new DefaultPort(dev1, p5, true);
- List<Port> ports = Lists.newArrayList(port1, port2, port3, port4, port5);
-
- expect(deviceService.getPorts(anyObject(DeviceId.class))).andReturn(ports).anyTimes();
- replay(deviceService);
- assertTrue(rrp.noMoreEnabledPort(devId1, v10));
- assertTrue(rrp.noMoreEnabledPort(devId1, v20));
- assertFalse(rrp.noMoreEnabledPort(devId1, vInt));
- }
-
- // Disable all ports
- @Test
- public void testNoMoreEnabledPortCase6() throws Exception {
- Port port1 = new DefaultPort(dev1, p1, false);
- Port port2 = new DefaultPort(dev1, p2, false);
- Port port3 = new DefaultPort(dev1, p3, false);
- Port port4 = new DefaultPort(dev1, p4, false);
- Port port5 = new DefaultPort(dev1, p5, false);
- List<Port> ports = Lists.newArrayList(port1, port2, port3, port4, port5);
-
- expect(deviceService.getPorts(anyObject(DeviceId.class))).andReturn(ports).anyTimes();
- replay(deviceService);
- assertTrue(rrp.noMoreEnabledPort(devId1, v10));
- assertTrue(rrp.noMoreEnabledPort(devId1, v20));
- assertTrue(rrp.noMoreEnabledPort(devId1, vInt));
- }
-}
\ No newline at end of file
diff --git a/app/src/test/java/org/onosproject/segmentrouting/TestUtils.java b/app/src/test/java/org/onosproject/segmentrouting/TestUtils.java
deleted file mode 100644
index 339b2c8..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/TestUtils.java
+++ /dev/null
@@ -1,460 +0,0 @@
-/*
- * 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;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.host.InterfaceIpAddress;
-import org.onosproject.net.intf.Interface;
-import org.onosproject.routeservice.ResolvedRoute;
-import org.onosproject.routeservice.Route;
-import org.onlab.packet.Ethernet;
-import org.onlab.packet.ICMP;
-import org.onlab.packet.ICMP6;
-import org.onlab.packet.IPv4;
-import org.onlab.packet.IPv6;
-import org.onlab.packet.Ip4Address;
-import org.onlab.packet.Ip6Address;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
-import org.onlab.packet.ICMPEcho;
-
-import java.util.Map;
-import java.util.Set;
-
-import static org.onlab.packet.ICMP.TYPE_ECHO_REQUEST;
-import static org.onlab.packet.ICMP6.ECHO_REQUEST;
-import static org.onlab.packet.IPv4.PROTOCOL_ICMP;
-import static org.onosproject.routeservice.Route.Source.STATIC;
-
-/**
- * Utilities class for unit tests.
- */
-public final class TestUtils {
-
- private TestUtils() {
-
- }
-
- // Device configuration section
- static final DeviceId REMOTE_LEAF = DeviceId.deviceId("of:0000000000000001");
- static final int REMOTE_LEAF_SID4 = 1;
- static final String REMOTE_LEAF_LB4 = "192.168.0.1";
- static final int REMOTE_LEAF_SID6 = 10;
- static final String REMOTE_LEAF_LB6 = "2000::c0a8:1";
- private static final PortNumber P1 = PortNumber.portNumber(1);
- static final MacAddress REMOTE_MAC = MacAddress.valueOf("00:00:00:00:00:02");
-
- static final DeviceId LOCAL_LEAF = DeviceId.deviceId("of:0000000000000101");
- static final int LOCAL_LEAF_SID4 = 101;
- static final String LOCAL_LEAF_LB4 = "192.168.0.101";
- static final int LOCAL_LEAF_SID6 = 111;
- static final String LOCAL_LEAF_LB6 = "2000::c0a8:101";
- static final MacAddress LOCAL_MAC = MacAddress.valueOf("00:00:00:00:01:01");
-
- // Configure a pair
- static final DeviceId LOCAL_LEAF1 = DeviceId.deviceId("of:0000000000000201");
- static final int LOCAL_LEAF1_SID4 = 201;
- static final String LOCAL_LEAF1_LB4 = "192.168.0.201";
- static final int LOCAL_LEAF1_SID6 = 211;
- static final String LOCAL_LEAF1_LB6 = "2000::c0a8:201";
- static final MacAddress LOCAL_MAC1 = MacAddress.valueOf("00:00:00:00:02:01");
-
- static final DeviceId LOCAL_LEAF2 = DeviceId.deviceId("of:0000000000000202");
- static final int LOCAL_LEAF2_SID4 = 202;
- static final String LOCAL_LEAF2_LB4 = "192.168.0.202";
- static final int LOCAL_LEAF2_SID6 = 212;
- static final String LOCAL_LEAF2_LB6 = "2000::c0a8:202";
- static final MacAddress LOCAL_MAC2 = MacAddress.valueOf("00:00:00:00:02:02");
-
- // Pair port
- static final PortNumber P3 = PortNumber.portNumber(3);
-
- // Ports configuration section
- static final ConnectPoint CP11 = new ConnectPoint(REMOTE_LEAF, P1);
- private static final PortNumber P2 = PortNumber.portNumber(2);
- static final ConnectPoint CP12 = new ConnectPoint(REMOTE_LEAF, P2);
- private static final IpAddress IP4_1 = IpAddress.valueOf("10.0.0.254");
- private static final IpPrefix PREFIX4_1 = IpPrefix.valueOf("10.0.0.254/24");
- private static final IpAddress IP6_1 = IpAddress.valueOf("2000::ff");
- private static final IpPrefix PREFIX6_1 = IpPrefix.valueOf("2000::ff/120");
- private static final InterfaceIpAddress INTF_IP4_1 = new InterfaceIpAddress(
- IP4_1, PREFIX4_1);
- private static final InterfaceIpAddress INTF_IP6_1 = new InterfaceIpAddress(
- IP6_1, PREFIX6_1);
- private static final VlanId INTF_VLAN_UNTAGGED = VlanId.vlanId((short) 10);
- static final Interface INTF1 = new Interface(
- "INTF1", CP12, Lists.newArrayList(INTF_IP4_1, INTF_IP6_1), MacAddress.NONE,
- null, INTF_VLAN_UNTAGGED, null, null);
- static final ConnectPoint CP13 = new ConnectPoint(REMOTE_LEAF, P3);
- private static final IpAddress IP4_2 = IpAddress.valueOf("10.0.3.254");
- private static final IpPrefix PREFIX4_2 = IpPrefix.valueOf("10.0.3.254/24");
- private static final IpAddress IP6_2 = IpAddress.valueOf("2000::3ff");
- private static final IpPrefix PREFIX6_2 = IpPrefix.valueOf("2000::3ff/120");
- private static final InterfaceIpAddress INTF_IP4_2 = new InterfaceIpAddress(
- IP4_2, PREFIX4_2);
- private static final InterfaceIpAddress INTF_IP6_2 = new InterfaceIpAddress(
- IP6_2, PREFIX6_2);
- static final Interface INTF2 = new Interface(
- "INTF2", CP13, Lists.newArrayList(INTF_IP4_2, INTF_IP6_2), MacAddress.NONE,
- null, INTF_VLAN_UNTAGGED, null, null);
-
- static final ConnectPoint CP1011 = new ConnectPoint(LOCAL_LEAF, P1);
- private static final IpAddress IP4_11 = IpAddress.valueOf("10.0.1.254");
- private static final IpPrefix PREFIX4_11 = IpPrefix.valueOf("10.0.1.254/24");
- private static final InterfaceIpAddress INTF_IP4_11 = new InterfaceIpAddress(
- IP4_11, PREFIX4_11);
- private static final IpAddress IP6_11 = IpAddress.valueOf("2000::1ff");
- private static final IpPrefix PREFIX6_11 = IpPrefix.valueOf("2000::1ff/120");
- private static final InterfaceIpAddress INTF_IP6_11 = new InterfaceIpAddress(
- IP6_11, PREFIX6_11);
- static final Interface INTF111 = new Interface(
- "INTF111", CP1011, Lists.newArrayList(INTF_IP4_11, INTF_IP6_11), MacAddress.NONE, null,
- INTF_VLAN_UNTAGGED, null, null);
-
- static final ConnectPoint CP2011 = new ConnectPoint(LOCAL_LEAF1, P1);
- private static final IpAddress IP4_21 = IpAddress.valueOf("10.0.2.254");
- private static final IpPrefix PREFIX4_21 = IpPrefix.valueOf("10.0.2.254/24");
- private static final InterfaceIpAddress INTF_IP4_21 = new InterfaceIpAddress(
- IP4_21, PREFIX4_21);
- private static final IpAddress IP6_21 = IpAddress.valueOf("2000::2ff");
- private static final IpPrefix PREFIX6_21 = IpPrefix.valueOf("2000::2ff/120");
- private static final InterfaceIpAddress INTF_IP6_21 = new InterfaceIpAddress(
- IP6_21, PREFIX6_21);
- static final Interface INTF211 = new Interface(
- "INTF211", CP2011, Lists.newArrayList(INTF_IP4_21, INTF_IP6_21), MacAddress.NONE, null,
- INTF_VLAN_UNTAGGED, null, null);
-
- static final ConnectPoint CP2021 = new ConnectPoint(LOCAL_LEAF2, P1);
- private static final IpAddress IP4_22 = IpAddress.valueOf("10.0.2.254");
- private static final IpPrefix PREFIX4_22 = IpPrefix.valueOf("10.0.2.254/24");
- private static final InterfaceIpAddress INTF_IP4_22 = new InterfaceIpAddress(
- IP4_22, PREFIX4_22);
- private static final IpAddress IP6_22 = IpAddress.valueOf("2000::2ff");
- private static final IpPrefix PREFIX6_22 = IpPrefix.valueOf("2000::2ff/120");
- private static final InterfaceIpAddress INTF_IP6_22 = new InterfaceIpAddress(
- IP6_22, PREFIX6_22);
- static final Interface INTF212 = new Interface(
- "INTF212", CP2021, Lists.newArrayList(INTF_IP4_22, INTF_IP6_22), MacAddress.NONE, null,
- INTF_VLAN_UNTAGGED, null, null);
- private static final PortNumber P4 = PortNumber.portNumber(4);
- static final ConnectPoint CP2024 = new ConnectPoint(LOCAL_LEAF2, P4);
- private static final PortNumber P5 = PortNumber.portNumber(5);
- static final ConnectPoint CP2025 = new ConnectPoint(LOCAL_LEAF2, P5);
- private static final IpAddress IP4_23 = IpAddress.valueOf("10.0.4.254");
- private static final IpPrefix PREFIX4_23 = IpPrefix.valueOf("10.0.4.254/24");
- private static final InterfaceIpAddress INTF_IP4_23 = new InterfaceIpAddress(
- IP4_23, PREFIX4_23);
- private static final IpAddress IP6_23 = IpAddress.valueOf("2000::4ff");
- private static final IpPrefix PREFIX6_23 = IpPrefix.valueOf("2000::4ff/120");
- private static final InterfaceIpAddress INTF_IP6_23 = new InterfaceIpAddress(
- IP6_23, PREFIX6_23);
- static final Interface INTF213 = new Interface(
- "INTF212", CP2024, Lists.newArrayList(INTF_IP4_23, INTF_IP6_23), MacAddress.NONE, null,
- INTF_VLAN_UNTAGGED, null, null);
-
- // Packet-ins section
- private static final MacAddress SRC_MAC = MacAddress.valueOf("00:00:00:00:00:01");
-
- private static final ICMPEcho ICMP_ECHO = new ICMPEcho()
- .setIdentifier((short) 0)
- .setSequenceNum((short) 0);
-
- private static final ICMP ICMP_REQUEST = (ICMP) new ICMP()
- .setIcmpType(TYPE_ECHO_REQUEST)
- .setPayload(ICMP_ECHO);
-
- private static final Ip4Address SRC_IPV4 = Ip4Address.valueOf("10.0.1.1");
- static final Ip4Address DST_IPV4 = Ip4Address.valueOf("10.0.0.254");
-
- private static final IPv4 IPV4_REQUEST = (IPv4) new IPv4()
- .setDestinationAddress(DST_IPV4.toInt())
- .setSourceAddress(SRC_IPV4.toInt())
- .setTtl((byte) 64)
- .setProtocol(PROTOCOL_ICMP)
- .setPayload(ICMP_REQUEST);
-
- static final Ethernet ETH_REQ_IPV4 = (Ethernet) new Ethernet()
- .setEtherType(Ethernet.TYPE_IPV4)
- .setDestinationMACAddress(REMOTE_MAC)
- .setSourceMACAddress(SRC_MAC)
- .setPayload(IPV4_REQUEST);
-
- private static final ICMP6 ICMP6_REQUEST = new ICMP6()
- .setIcmpType(ECHO_REQUEST);
-
- private static final Ip6Address SRC_IPV6 = Ip6Address.valueOf("2000::101");
- static final Ip6Address DST_IPV6 = Ip6Address.valueOf("2000::ff");
-
- private static final IPv6 IPV6_REQUEST = (IPv6) new IPv6()
- .setDestinationAddress(DST_IPV6.toOctets())
- .setSourceAddress(SRC_IPV6.toOctets())
- .setHopLimit((byte) 255)
- .setNextHeader(IPv6.PROTOCOL_ICMP6)
- .setPayload(ICMP6_REQUEST);
-
- static final Ethernet ETH_REQ_IPV6 = (Ethernet) new Ethernet()
- .setEtherType(Ethernet.TYPE_IPV6)
- .setDestinationMACAddress(REMOTE_MAC)
- .setSourceMACAddress(SRC_MAC)
- .setPayload(IPV6_REQUEST);
-
- static final Ip4Address SRC_IPV41 = Ip4Address.valueOf("10.0.2.1");
-
- private static final IPv4 IPV41_REQUEST = (IPv4) new IPv4()
- .setDestinationAddress(DST_IPV4.toInt())
- .setSourceAddress(SRC_IPV41.toInt())
- .setTtl((byte) 64)
- .setProtocol(PROTOCOL_ICMP)
- .setPayload(ICMP_REQUEST);
-
- static final Ethernet ETH_REQ_IPV41 = (Ethernet) new Ethernet()
- .setEtherType(Ethernet.TYPE_IPV4)
- .setDestinationMACAddress(REMOTE_MAC)
- .setSourceMACAddress(SRC_MAC)
- .setPayload(IPV41_REQUEST);
-
- static final Ip6Address SRC_IPV61 = Ip6Address.valueOf("2000::201");
-
- private static final IPv6 IPV61_REQUEST = (IPv6) new IPv6()
- .setDestinationAddress(DST_IPV6.toOctets())
- .setSourceAddress(SRC_IPV61.toOctets())
- .setHopLimit((byte) 255)
- .setNextHeader(IPv6.PROTOCOL_ICMP6)
- .setPayload(ICMP6_REQUEST);
-
- static final Ethernet ETH_REQ_IPV61 = (Ethernet) new Ethernet()
- .setEtherType(Ethernet.TYPE_IPV6)
- .setDestinationMACAddress(REMOTE_MAC)
- .setSourceMACAddress(SRC_MAC)
- .setPayload(IPV61_REQUEST);
-
- private static final MacAddress SRC_MAC_MY = MacAddress.valueOf("00:01:00:00:00:01");
- static final Ip4Address SRC_IPV4_MY = Ip4Address.valueOf("10.0.0.1");
-
- private static final IPv4 IPV4_REQUEST_MY = (IPv4) new IPv4()
- .setDestinationAddress(DST_IPV4.toInt())
- .setSourceAddress(SRC_IPV4_MY.toInt())
- .setTtl((byte) 64)
- .setProtocol(PROTOCOL_ICMP)
- .setPayload(ICMP_REQUEST);
-
- static final Ethernet ETH_REQ_IPV4_MY = (Ethernet) new Ethernet()
- .setEtherType(Ethernet.TYPE_IPV4)
- .setDestinationMACAddress(REMOTE_MAC)
- .setSourceMACAddress(SRC_MAC_MY)
- .setPayload(IPV4_REQUEST_MY);
-
- static final Ip6Address SRC_IPV6_MY = Ip6Address.valueOf("2000::1");
-
- private static final IPv6 IPV6_REQUEST_MY = (IPv6) new IPv6()
- .setDestinationAddress(DST_IPV6.toOctets())
- .setSourceAddress(SRC_IPV6_MY.toOctets())
- .setHopLimit((byte) 255)
- .setNextHeader(IPv6.PROTOCOL_ICMP6)
- .setPayload(ICMP6_REQUEST);
-
- static final Ethernet ETH_REQ_IPV6_MY = (Ethernet) new Ethernet()
- .setEtherType(Ethernet.TYPE_IPV6)
- .setDestinationMACAddress(REMOTE_MAC)
- .setSourceMACAddress(SRC_MAC_MY)
- .setPayload(IPV6_REQUEST_MY);
-
- static final Ip4Address DST_IPV4_LOCAL = Ip4Address.valueOf("10.0.3.254");
-
- private static final IPv4 IPV4_REQUEST_LOCAL = (IPv4) new IPv4()
- .setDestinationAddress(DST_IPV4_LOCAL.toInt())
- .setSourceAddress(SRC_IPV4_MY.toInt())
- .setTtl((byte) 64)
- .setProtocol(PROTOCOL_ICMP)
- .setPayload(ICMP_REQUEST);
-
- static final Ethernet ETH_REQ_IPV4_LOCAL = (Ethernet) new Ethernet()
- .setEtherType(Ethernet.TYPE_IPV4)
- .setDestinationMACAddress(REMOTE_MAC)
- .setSourceMACAddress(SRC_MAC_MY)
- .setPayload(IPV4_REQUEST_LOCAL);
-
- static final Ip6Address DST_IPV6_LOCAL = Ip6Address.valueOf("2000::3ff");
-
- private static final IPv6 IPV6_REQUEST_LOCAL = (IPv6) new IPv6()
- .setDestinationAddress(DST_IPV6_LOCAL.toOctets())
- .setSourceAddress(SRC_IPV6_MY.toOctets())
- .setHopLimit((byte) 255)
- .setNextHeader(IPv6.PROTOCOL_ICMP6)
- .setPayload(ICMP6_REQUEST);
-
- static final Ethernet ETH_REQ_IPV6_LOCAL = (Ethernet) new Ethernet()
- .setEtherType(Ethernet.TYPE_IPV6)
- .setDestinationMACAddress(REMOTE_MAC)
- .setSourceMACAddress(SRC_MAC_MY)
- .setPayload(IPV6_REQUEST_LOCAL);
-
- static final Ip4Address DST_IPV4_SAME = Ip4Address.valueOf("10.0.4.254");
-
- private static final IPv4 IPV4_REQUEST_SAME = (IPv4) new IPv4()
- .setDestinationAddress(DST_IPV4_SAME.toInt())
- .setSourceAddress(SRC_IPV41.toInt())
- .setTtl((byte) 64)
- .setProtocol(PROTOCOL_ICMP)
- .setPayload(ICMP_REQUEST);
-
- static final Ethernet ETH_REQ_IPV4_SAME = (Ethernet) new Ethernet()
- .setEtherType(Ethernet.TYPE_IPV4)
- .setDestinationMACAddress(LOCAL_MAC2)
- .setSourceMACAddress(SRC_MAC)
- .setPayload(IPV4_REQUEST_SAME);
-
- static final Ip6Address DST_IPV6_SAME = Ip6Address.valueOf("2000::4ff");
-
- private static final IPv6 IPV6_REQUEST_SAME = (IPv6) new IPv6()
- .setDestinationAddress(DST_IPV6_SAME.toOctets())
- .setSourceAddress(SRC_IPV61.toOctets())
- .setHopLimit((byte) 255)
- .setNextHeader(IPv6.PROTOCOL_ICMP6)
- .setPayload(ICMP6_REQUEST);
-
- static final Ethernet ETH_REQ_IPV6_SAME = (Ethernet) new Ethernet()
- .setEtherType(Ethernet.TYPE_IPV6)
- .setDestinationMACAddress(LOCAL_MAC2)
- .setSourceMACAddress(SRC_MAC)
- .setPayload(IPV6_REQUEST_SAME);
-
- static final Ip6Address DST_IPV6_LL = Ip6Address.valueOf(
- IPv6.getLinkLocalAddress(MacAddress.NONE.toBytes()));
- static final Ip6Address SRC_IPV6_LL = Ip6Address.valueOf(
- IPv6.getLinkLocalAddress(SRC_MAC_MY.toBytes()));
-
- private static final IPv6 IPV6_REQUEST_LL = (IPv6) new IPv6()
- .setDestinationAddress(DST_IPV6_LL.toOctets())
- .setSourceAddress(SRC_IPV6_LL.toOctets())
- .setHopLimit((byte) 255)
- .setNextHeader(IPv6.PROTOCOL_ICMP6)
- .setPayload(ICMP6_REQUEST);
-
- static final Ethernet ETH_REQ_IPV6_LL = (Ethernet) new Ethernet()
- .setEtherType(Ethernet.TYPE_IPV6)
- .setDestinationMACAddress(MacAddress.NONE)
- .setSourceMACAddress(SRC_MAC_MY)
- .setPayload(IPV6_REQUEST_LL);
-
- static final Ip4Address DST_IPV4_LOOPBACK = Ip4Address.valueOf(REMOTE_LEAF_LB4);
-
- private static final IPv4 IPV4_REQUEST_LOOPBACK = (IPv4) new IPv4()
- .setDestinationAddress(DST_IPV4_LOOPBACK.toInt())
- .setSourceAddress(SRC_IPV4_MY.toInt())
- .setTtl((byte) 64)
- .setProtocol(PROTOCOL_ICMP)
- .setPayload(ICMP_REQUEST);
-
- static final Ethernet ETH_REQ_IPV4_LOOPBACK = (Ethernet) new Ethernet()
- .setEtherType(Ethernet.TYPE_IPV4)
- .setDestinationMACAddress(REMOTE_MAC)
- .setSourceMACAddress(SRC_MAC_MY)
- .setPayload(IPV4_REQUEST_LOOPBACK);
-
- static final Ip6Address DST_IPV6_LOOPBACK = Ip6Address.valueOf(REMOTE_LEAF_LB6);
-
- private static final IPv6 IPV6_REQUEST_LOOPBACK = (IPv6) new IPv6()
- .setDestinationAddress(DST_IPV6_LOOPBACK.toOctets())
- .setSourceAddress(SRC_IPV6_MY.toOctets())
- .setHopLimit((byte) 255)
- .setNextHeader(IPv6.PROTOCOL_ICMP6)
- .setPayload(ICMP6_REQUEST);
-
- static final Ethernet ETH_REQ_IPV6_LOOPBACK = (Ethernet) new Ethernet()
- .setEtherType(Ethernet.TYPE_IPV6)
- .setDestinationMACAddress(REMOTE_MAC)
- .setSourceMACAddress(SRC_MAC_MY)
- .setPayload(IPV6_REQUEST_LOOPBACK);
-
- static final Ip4Address DST_IPV4_LOOPBACK_PAIR = Ip4Address.valueOf(LOCAL_LEAF1_LB4);
-
- private static final IPv4 IPV4_REQUEST_LOOPBACK_PAIR = (IPv4) new IPv4()
- .setDestinationAddress(DST_IPV4_LOOPBACK_PAIR.toInt())
- .setSourceAddress(SRC_IPV41.toInt())
- .setTtl((byte) 64)
- .setProtocol(PROTOCOL_ICMP)
- .setPayload(ICMP_REQUEST);
-
- static final Ethernet ETH_REQ_IPV4_LOOPBACK_PAIR = (Ethernet) new Ethernet()
- .setEtherType(Ethernet.TYPE_IPV4)
- .setDestinationMACAddress(LOCAL_MAC1)
- .setSourceMACAddress(SRC_MAC)
- .setPayload(IPV4_REQUEST_LOOPBACK_PAIR);
-
- static final Ip6Address DST_IPV6_LOOPBACK_PAIR = Ip6Address.valueOf(LOCAL_LEAF2_LB6);
-
- private static final IPv6 IPV6_REQUEST_LOOPBACK_PAIR = (IPv6) new IPv6()
- .setDestinationAddress(DST_IPV6_LOOPBACK_PAIR.toOctets())
- .setSourceAddress(SRC_IPV61.toOctets())
- .setHopLimit((byte) 255)
- .setNextHeader(IPv6.PROTOCOL_ICMP6)
- .setPayload(ICMP6_REQUEST);
-
- static final Ethernet ETH_REQ_IPV6_LOOPBACK_PAIR = (Ethernet) new Ethernet()
- .setEtherType(Ethernet.TYPE_IPV6)
- .setDestinationMACAddress(LOCAL_MAC2)
- .setSourceMACAddress(SRC_MAC)
- .setPayload(IPV6_REQUEST_LOOPBACK_PAIR);
-
- static final Ip4Address DST_IPV4_GATEWAY_PAIR = Ip4Address.valueOf("10.0.2.254");
-
- private static final IPv4 IPV4_REQUEST_GATEWAY_PAIR = (IPv4) new IPv4()
- .setDestinationAddress(DST_IPV4_GATEWAY_PAIR.toInt())
- .setSourceAddress(SRC_IPV41.toInt())
- .setTtl((byte) 64)
- .setProtocol(PROTOCOL_ICMP)
- .setPayload(ICMP_REQUEST);
-
- static final Ethernet ETH_REQ_IPV4_GATEWAY_PAIR = (Ethernet) new Ethernet()
- .setEtherType(Ethernet.TYPE_IPV4)
- .setDestinationMACAddress(LOCAL_MAC1)
- .setSourceMACAddress(SRC_MAC)
- .setPayload(IPV4_REQUEST_GATEWAY_PAIR);
-
- static final Ip6Address DST_IPV6_GATEWAY_PAIR = Ip6Address.valueOf("2000::2ff");
-
- private static final IPv6 IPV6_REQUEST_GATEWAY_PAIR = (IPv6) new IPv6()
- .setDestinationAddress(DST_IPV6_GATEWAY_PAIR.toOctets())
- .setSourceAddress(SRC_IPV61.toOctets())
- .setHopLimit((byte) 255)
- .setNextHeader(IPv6.PROTOCOL_ICMP6)
- .setPayload(ICMP6_REQUEST);
-
- static final Ethernet ETH_REQ_IPV6_GATEWAY_PAIR = (Ethernet) new Ethernet()
- .setEtherType(Ethernet.TYPE_IPV6)
- .setDestinationMACAddress(LOCAL_MAC2)
- .setSourceMACAddress(SRC_MAC)
- .setPayload(IPV6_REQUEST_GATEWAY_PAIR);
-
- // Resolved route
- private static final ResolvedRoute IPV4_ROUTE = new ResolvedRoute(
- new Route(STATIC, SRC_IPV4.toIpPrefix(), SRC_IPV4), MacAddress.NONE);
- private static final ResolvedRoute IPV6_ROUTE = new ResolvedRoute(
- new Route(STATIC, SRC_IPV6.toIpPrefix(), SRC_IPV6), MacAddress.NONE);
- static final Map<IpPrefix, Set<ResolvedRoute>> ROUTE_STORE = ImmutableMap.of(SRC_IPV4.toIpPrefix(),
- Sets.newHashSet(IPV4_ROUTE),
- SRC_IPV6.toIpPrefix(),
- Sets.newHashSet(IPV6_ROUTE));
-}
diff --git a/app/src/test/java/org/onosproject/segmentrouting/config/DeviceConfigurationTest.java b/app/src/test/java/org/onosproject/segmentrouting/config/DeviceConfigurationTest.java
deleted file mode 100644
index 1674f6c..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/config/DeviceConfigurationTest.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * 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.config;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.JsonNodeFactory;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-import org.junit.Before;
-import org.junit.Test;
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.config.NetworkConfigRegistry;
-import org.onosproject.net.config.basics.BasicDeviceConfig;
-import org.onosproject.net.config.basics.InterfaceConfig;
-import org.onosproject.net.host.InterfaceIpAddress;
-import org.onosproject.net.intf.Interface;
-import org.onosproject.net.intf.InterfaceService;
-import org.onosproject.net.neighbour.NeighbourResolutionService;
-import org.onosproject.segmentrouting.SegmentRoutingManager;
-
-import java.io.InputStream;
-import java.util.List;
-import java.util.Set;
-
-import static org.easymock.EasyMock.anyObject;
-import static org.easymock.EasyMock.createMock;
-import static org.easymock.EasyMock.eq;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.expectLastCall;
-import static org.easymock.EasyMock.replay;
-import static org.junit.Assert.*;
-
-public class DeviceConfigurationTest {
- private static final DeviceId DEV1 = DeviceId.deviceId("of:1");
- private static final String CONFIG_KEY = "segmentrouting";
- private static final PortNumber PORT1 = PortNumber.portNumber(1);
- private static final PortNumber PORT2 = PortNumber.portNumber(2);
- private static final ConnectPoint CP1 = new ConnectPoint(DEV1, PORT1);
- private static final ConnectPoint CP2 = new ConnectPoint(DEV1, PORT2);
- private static final MacAddress MAC1 = MacAddress.valueOf("00:11:22:33:44:55");
- private static final VlanId VLAN1 = VlanId.vlanId((short) 10);
- private static final VlanId VLAN2 = VlanId.vlanId((short) 20);
- private static final IpPrefix PREFIX1 = IpPrefix.valueOf("10.0.1.254/24");
- private static final IpPrefix PREFIX2 = IpPrefix.valueOf("10.0.2.254/24");
- private static final IpPrefix ROUTE1 = IpPrefix.valueOf("20.0.1.254/24");
- private static final InterfaceIpAddress INTF1_IP = new InterfaceIpAddress(PREFIX1.address(), PREFIX1);
- private static final InterfaceIpAddress INTF2_IP = new InterfaceIpAddress(PREFIX2.address(), PREFIX2);
- private static final List<InterfaceIpAddress> IP_LIST1 = Lists.newArrayList(INTF1_IP);
- private static final List<InterfaceIpAddress> IP_LIST2 = Lists.newArrayList(INTF2_IP);
- private static final Interface INTF1 = new Interface("mock-intf1", CP1, IP_LIST1, MAC1,
- null, VLAN1, null, null);
- private static final Interface INTF2 = new Interface("mock-intf2", CP2, IP_LIST2, MAC1,
- null, VLAN2, null, null);
- private static final Set<Interface> INTERFACES = Sets.newHashSet(INTF1, INTF2);
-
- private DeviceConfiguration devConfig;
-
- private NetworkConfigRegistry networkConfigService;
-
- @Before
- public void setUp() throws Exception {
- InterfaceService interfaceService;
- networkConfigService = null;
- NeighbourResolutionService neighbourResolutionService;
- SegmentRoutingManager srManager;
-
- // Mock device netcfg
- InputStream jsonStream = SegmentRoutingDeviceConfigTest.class.getResourceAsStream("/device.json");
- ObjectMapper mapper = new ObjectMapper();
- JsonNode jsonNode = mapper.readTree(jsonStream);
- SegmentRoutingDeviceConfig srDevConfig = new SegmentRoutingDeviceConfig();
- srDevConfig.init(DEV1, CONFIG_KEY, jsonNode, mapper, config -> { });
- BasicDeviceConfig basicDeviceConfig = new BasicDeviceConfig();
- basicDeviceConfig.init(DEV1, DEV1.toString(), JsonNodeFactory.instance.objectNode(), mapper, config -> { });
- BasicDeviceConfig purgeOnDisconnectConfig = basicDeviceConfig.purgeOnDisconnection(true);
-
-
- // Mock interface netcfg
- jsonStream = InterfaceConfig.class.getResourceAsStream("/interface1.json");
- jsonNode = mapper.readTree(jsonStream);
- InterfaceConfig interfaceConfig1 = new InterfaceConfig();
- interfaceConfig1.init(CP1, CONFIG_KEY, jsonNode, mapper, config -> { });
- jsonStream = InterfaceConfig.class.getResourceAsStream("/interface2.json");
- jsonNode = mapper.readTree(jsonStream);
- InterfaceConfig interfaceConfig2 = new InterfaceConfig();
- interfaceConfig2.init(CP1, CONFIG_KEY, jsonNode, mapper, config -> { });
-
- networkConfigService = createMock(NetworkConfigRegistry.class);
- expect(networkConfigService.getSubjects(DeviceId.class, SegmentRoutingDeviceConfig.class))
- .andReturn(Sets.newHashSet(DEV1)).anyTimes();
- expect(networkConfigService.getConfig(DEV1, SegmentRoutingDeviceConfig.class))
- .andReturn(srDevConfig).anyTimes();
- expect(networkConfigService.addConfig(DEV1, BasicDeviceConfig.class))
- .andReturn(basicDeviceConfig).anyTimes();
- expect(networkConfigService.getConfig(DEV1, BasicDeviceConfig.class))
- .andReturn(basicDeviceConfig).anyTimes();
- expect(networkConfigService.applyConfig(DEV1, BasicDeviceConfig.class, purgeOnDisconnectConfig.node()))
- .andReturn(purgeOnDisconnectConfig).anyTimes();
- expect(networkConfigService.getSubjects(ConnectPoint.class, InterfaceConfig.class))
- .andReturn(Sets.newHashSet(CP1, CP2)).anyTimes();
- expect(networkConfigService.getConfig(CP1, InterfaceConfig.class)).andReturn(interfaceConfig1).anyTimes();
- expect(networkConfigService.getConfig(CP2, InterfaceConfig.class)).andReturn(interfaceConfig2).anyTimes();
- expect(networkConfigService.applyConfig(eq(CP1), eq(InterfaceConfig.class), anyObject()))
- .andReturn(interfaceConfig1).anyTimes();
- expect(networkConfigService.applyConfig(eq(CP2), eq(InterfaceConfig.class), anyObject()))
- .andReturn(interfaceConfig2).anyTimes();
- expect(networkConfigService.getConfig(null, SegmentRoutingAppConfig.class)).andReturn(null).anyTimes();
- replay(networkConfigService);
-
- interfaceService = createMock(InterfaceService.class);
- expect(interfaceService.getInterfaces()).andReturn(INTERFACES).anyTimes();
- expect(interfaceService.getInterfacesByPort(CP1)).andReturn(Sets.newHashSet(INTF1)).anyTimes();
- expect(interfaceService.getInterfacesByPort(CP2)).andReturn(Sets.newHashSet(INTF2)).anyTimes();
- replay(interfaceService);
-
- neighbourResolutionService = createMock(NeighbourResolutionService.class);
- neighbourResolutionService.registerNeighbourHandler(anyObject(ConnectPoint.class), anyObject(), anyObject());
- expectLastCall().anyTimes();
- replay(neighbourResolutionService);
-
- srManager = new SegmentRoutingManager();
- srManager.interfaceService = interfaceService;
- srManager.cfgService = networkConfigService;
- srManager.neighbourResolutionService = neighbourResolutionService;
-
- devConfig = new DeviceConfiguration(srManager);
- devConfig.addSubnet(CP2, ROUTE1);
- }
-
- @Test
- public void getConfiguredSubnets() {
- Set<IpPrefix> expect = Sets.newHashSet(PREFIX1, PREFIX2);
- assertEquals(expect, devConfig.getConfiguredSubnets(DEV1));
- }
-
- @Test
- public void getSubnets() {
- Set<IpPrefix> expect = Sets.newHashSet(PREFIX1, PREFIX2, ROUTE1);
- assertEquals(expect, devConfig.getSubnets(DEV1));
- }
-
- @Test
- public void getPortSubnets() {
- assertEquals(Sets.newHashSet(PREFIX1), devConfig.getPortSubnets(DEV1, PORT1));
- assertEquals(Sets.newHashSet(PREFIX2), devConfig.getPortSubnets(DEV1, PORT2));
- }
-
- @Test
- public void inSameSubnet() {
- assertTrue(devConfig.inSameSubnet(DEV1, PREFIX1.address()));
- assertTrue(devConfig.inSameSubnet(DEV1, PREFIX2.address()));
- assertFalse(devConfig.inSameSubnet(DEV1, ROUTE1.address()));
- }
-
- @Test
- public void getPurgeOnDisconnect() {
- assertNotNull(networkConfigService.getConfig(DEV1, BasicDeviceConfig.class));
- assertTrue(networkConfigService.getConfig(DEV1, BasicDeviceConfig.class).purgeOnDisconnection());
- }
-}
\ No newline at end of file
diff --git a/app/src/test/java/org/onosproject/segmentrouting/grouphandler/DestinationSetTest.java b/app/src/test/java/org/onosproject/segmentrouting/grouphandler/DestinationSetTest.java
deleted file mode 100644
index b41fe07..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/grouphandler/DestinationSetTest.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright 2017-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.grouphandler;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.onosproject.net.DeviceId;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-public class DestinationSetTest {
- DestinationSet ds1, ds2, ds3, ds4, ds5, ds6;
- DeviceId d201, d202;
- int el201, el202;
-
- @Before
- public void setUp() {
- d201 = DeviceId.deviceId("of:0000000000000201");
- d202 = DeviceId.deviceId("of:0000000000000202");
- el201 = 201;
- el202 = 202;
- ds1 = DestinationSet.createTypePushNone(d201);
- ds2 = DestinationSet.createTypePushBos(el201, d201);
- ds3 = DestinationSet.createTypePushBos(el201, d201, el202, d202);
- ds4 = DestinationSet.createTypePushBos(DestinationSet.NO_EDGE_LABEL, d201,
- DestinationSet.NO_EDGE_LABEL, d202);
- ds5 = DestinationSet.createTypePopNotBos(d201);
- ds6 = DestinationSet.createTypeSwapBos(el201, d201);
- }
-
- @Test
- public void testIsValid() {
- assertTrue(!ds1.notBos());
- assertTrue(!ds1.swap());
- assertTrue(ds1.getEdgeLabel(d201) == DestinationSet.NO_EDGE_LABEL);
- assertTrue(ds1.getDestinationSwitches().size() == 1);
-
- assertTrue(!ds2.notBos());
- assertTrue(!ds2.swap());
- assertTrue(ds2.getEdgeLabel(d201) == el201);
- assertTrue(ds2.getDestinationSwitches().size() == 1);
-
- assertTrue(!ds3.notBos());
- assertTrue(!ds3.swap());
- assertTrue(ds3.getEdgeLabel(d201) == el201);
- assertTrue(ds3.getEdgeLabel(d202) == el202);
- assertTrue(ds3.getDestinationSwitches().size() == 2);
-
- assertTrue(!ds4.notBos());
- assertTrue(!ds4.swap());
- assertTrue(ds4.getEdgeLabel(d201) == DestinationSet.NO_EDGE_LABEL);
- assertTrue(ds4.getEdgeLabel(d202) == DestinationSet.NO_EDGE_LABEL);
- assertTrue(ds4.getDestinationSwitches().size() == 2);
-
- assertFalse(ds1.equals(ds2));
- assertFalse(ds1.equals(ds4));
- assertFalse(ds3.equals(ds4));
- assertFalse(ds2.equals(ds3));
- assertFalse(ds1.equals(ds3));
-
- assertFalse(ds1.equals(ds5));
- assertFalse(ds2.equals(ds6));
- }
-
-
- @Test
- public void testOneDestinationWithoutLabel() {
- DestinationSet testds = DestinationSet.createTypePushNone(d201);
- assertTrue(testds.equals(ds1)); // match
-
- testds = DestinationSet.createTypePopNotBos(d201);
- assertFalse(testds.equals(ds1)); // wrong notBos
- assertTrue(testds.equals(ds5)); // correct notBos
-
- testds = DestinationSet.createTypePushNone(d202);
- assertFalse(testds.equals(ds1)); //wrong device
-
- testds = DestinationSet.createTypePushBos(el201, d201);
- assertFalse(testds.equals(ds1)); // wrong label
-
- testds = DestinationSet.createTypePushBos(-1, d201, -1, d202);
- assertFalse(testds.equals(ds1)); // 2-devs should not match
-
- testds = DestinationSet.createTypeSwapBos(el201, d201);
- assertFalse(testds.equals(ds1)); // wrong type and label
- assertTrue(testds.equals(ds6)); // correct swap
-
- testds = DestinationSet.createTypeSwapNotBos(el201, d201);
- assertFalse(testds.equals(ds6)); // wrong notbos
- }
-
-
-
- @Test
- public void testOneDestinationWithLabel() {
- DestinationSet testds = DestinationSet.createTypePushBos(203, d202);
- assertFalse(testds.equals(ds2)); //wrong label
-
- testds = DestinationSet.createTypePushBos(201, d202);
- assertFalse(testds.equals(ds2)); //wrong device
-
- testds = DestinationSet.createTypePushBos(201, DeviceId.deviceId("of:0000000000000201"));
- assertTrue(testds.equals(ds2)); // match
-
- testds = DestinationSet.createTypePushNone(d201);
- assertFalse(testds.equals(ds2)); // wrong label
-
- testds = DestinationSet.createTypePushBos(el201, d201, el202, d202);
- assertFalse(testds.equals(ds1)); // 2-devs should not match
- }
-
- @Test
- public void testDestPairWithLabel() {
- DestinationSet testds = DestinationSet.createTypePushBos(el201, d201, el202, d202);
- assertTrue(testds.equals(ds3)); // match same switches, same order
- assertTrue(testds.hashCode() == ds3.hashCode());
-
- testds = DestinationSet.createTypePushBos(el202, d202, el201, d201);
- assertTrue(testds.equals(ds3)); // match same switches, order reversed
- assertTrue(testds.hashCode() == ds3.hashCode());
-
- testds = DestinationSet.createTypePushBos(el202, d202);
- assertFalse(testds.equals(ds3)); // one less switch should not match
- assertFalse(testds.hashCode() == ds3.hashCode());
-
- testds = DestinationSet.createTypePushBos(el201, d201);
- assertFalse(testds.equals(ds3)); // one less switch should not match
- assertFalse(testds.hashCode() == ds3.hashCode());
-
- testds = DestinationSet.createTypePushBos(el201, d201, 0, DeviceId.NONE);
- assertFalse(testds.equals(ds3)); // one less switch should not match
- assertFalse(testds.hashCode() == ds3.hashCode());
-
- testds = DestinationSet.createTypePushBos(el201, d202, el201, d201);
- assertFalse(testds.equals(ds3)); // wrong labels
- assertFalse(testds.hashCode() == ds3.hashCode());
-
- testds = DestinationSet.createTypePushBos(el202, d202, el201, d202);
- assertFalse(testds.equals(ds3)); // wrong device
- assertFalse(testds.hashCode() == ds3.hashCode());
-
- testds = DestinationSet.createTypePushBos(
- el202, DeviceId.deviceId("of:0000000000000205"),
- el201, d201);
- assertFalse(testds.equals(ds3)); // wrong device
- assertFalse(testds.hashCode() == ds3.hashCode());
- }
-
- @Test
- public void testDestPairWithoutLabel() {
- DestinationSet testds = DestinationSet.createTypePushBos(-1, d201, -1, d202);
- assertTrue(testds.equals(ds4)); // match same switches, same order
- assertTrue(testds.hashCode() == ds4.hashCode());
-
- testds = DestinationSet.createTypePushBos(-1, d202, -1, d201);
- assertTrue(testds.equals(ds4)); // match same switches, order reversed
- assertTrue(testds.hashCode() == ds4.hashCode());
-
- testds = DestinationSet.createTypePushBos(-1, d202);
- assertFalse(testds.equals(ds4)); // one less switch should not match
- assertFalse(testds.hashCode() == ds4.hashCode());
-
- testds = DestinationSet.createTypePushBos(-1, d201);
- assertFalse(testds.equals(ds4)); // one less switch should not match
- assertFalse(testds.hashCode() == ds4.hashCode());
-
- testds = DestinationSet.createTypePushBos(-1, d201, 0, DeviceId.NONE);
- assertFalse(testds.equals(ds4)); // one less switch should not match
- assertFalse(testds.hashCode() == ds4.hashCode());
-
- testds = DestinationSet.createTypePushBos(el201, d201, -1, d202);
- assertFalse(testds.equals(ds4)); // wrong labels
- assertFalse(testds.hashCode() == ds4.hashCode());
-
- testds = DestinationSet.createTypePushBos(-1, d202, -1, d202);
- assertFalse(testds.equals(ds4)); // wrong device
- assertFalse(testds.hashCode() == ds4.hashCode());
-
- testds = DestinationSet.createTypePushBos(
- -1, DeviceId.deviceId("of:0000000000000205"),
- -1, d201);
- assertFalse(testds.equals(ds4)); // wrong device
- assertFalse(testds.hashCode() == ds4.hashCode());
- }
-
-}
diff --git a/app/src/test/java/org/onosproject/segmentrouting/pwaas/PwaasUtilTest.java b/app/src/test/java/org/onosproject/segmentrouting/pwaas/PwaasUtilTest.java
deleted file mode 100644
index 1d9f07e..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/pwaas/PwaasUtilTest.java
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Copyright 2018-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.pwaas;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.onlab.junit.TestUtils;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DefaultPort;
-import org.onosproject.net.Device;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Port;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.intf.Interface;
-import org.onosproject.net.intf.InterfaceService;
-import org.onosproject.segmentrouting.MockDevice;
-
-import static org.easymock.EasyMock.createNiceMock;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-
-public class PwaasUtilTest {
- private static final DeviceId DID1 = DeviceId.deviceId("of:1");
- private static final DeviceId DID2 = DeviceId.deviceId("of:2");
- private static final DeviceId DID99 = DeviceId.deviceId("of:99");
- private static final PortNumber PN1 = PortNumber.portNumber(1);
- private static final PortNumber PN2 = PortNumber.portNumber(2);
- private static final PortNumber PN99 = PortNumber.portNumber(99);
- private static final ConnectPoint CP11 = new ConnectPoint(DID1, PN1);
- private static final ConnectPoint CP12 = new ConnectPoint(DID1, PN2);
- private static final ConnectPoint CP21 = new ConnectPoint(DID2, PN1);
- private static final ConnectPoint CP22 = new ConnectPoint(DID2, PN2);
- private static final VlanId V1 = VlanId.vlanId((short) 1);
- private static final VlanId V2 = VlanId.vlanId((short) 2);
- private static final Device D1 = new MockDevice(DID1, null);
- private static final Device D2 = new MockDevice(DID2, null);
- private static final Port P11 = new DefaultPort(D1, PN1, true);
- private static final Port P12 = new DefaultPort(D1, PN2, true);
- private static final Port P21 = new DefaultPort(D2, PN1, true);
- private static final Port P22 = new DefaultPort(D2, PN2, true);
- private static final Interface I11 = new Interface("I11", CP11, Lists.newArrayList(), MacAddress.NONE,
- VlanId.NONE, VlanId.NONE, Sets.newHashSet(VlanId.NONE), VlanId.NONE);
- private static final Interface I12 = new Interface("I12", CP12, Lists.newArrayList(), MacAddress.NONE,
- VlanId.NONE, VlanId.NONE, Sets.newHashSet(VlanId.NONE), VlanId.NONE);
- private static final Interface I21 = new Interface("I21", CP21, Lists.newArrayList(), MacAddress.NONE,
- VlanId.NONE, VlanId.NONE, Sets.newHashSet(VlanId.NONE), VlanId.NONE);
- private static final Interface I22 = new Interface("I22", CP22, Lists.newArrayList(), MacAddress.NONE,
- VlanId.NONE, VlanId.NONE, Sets.newHashSet(VlanId.NONE), VlanId.NONE);
-
- private ConnectPoint cp1;
- private ConnectPoint cp2;
- private VlanId ingressInner;
- private VlanId ingressOuter;
- private VlanId egressInner;
- private VlanId egressOuter;
- private static final Long TUNNEL_ID = (long) 1234;
-
- @Before
- public void setUp() {
- DeviceService deviceService = createNiceMock(DeviceService.class);
- InterfaceService intfService = createNiceMock(InterfaceService.class);
- TestUtils.setField(PwaasUtil.class, "deviceService", deviceService);
- TestUtils.setField(PwaasUtil.class, "intfService", intfService);
-
- expect(deviceService.getDevice(DID1)).andReturn(D1).anyTimes();
- expect(deviceService.getDevice(DID2)).andReturn(D2).anyTimes();
- expect(deviceService.getPort(CP11)).andReturn(P11).anyTimes();
- expect(deviceService.getPort(CP12)).andReturn(P12).anyTimes();
- expect(deviceService.getPort(CP21)).andReturn(P21).anyTimes();
- expect(deviceService.getPort(CP22)).andReturn(P22).anyTimes();
- expect(intfService.getInterfacesByPort(CP11)).andReturn(Sets.newHashSet(I11)).anyTimes();
- expect(intfService.getInterfacesByPort(CP12)).andReturn(Sets.newHashSet(I12)).anyTimes();
- expect(intfService.getInterfacesByPort(CP21)).andReturn(Sets.newHashSet(I21)).anyTimes();
- expect(intfService.getInterfacesByPort(CP22)).andReturn(Sets.newHashSet(I22)).anyTimes();
- replay(deviceService);
- replay(intfService);
- }
-
- @Rule
- public final ExpectedException exception = ExpectedException.none();
-
- @Test
- public void verifyPolicy() {
- cp1 = new ConnectPoint(DID1, PN1);
- cp2 = new ConnectPoint(DID2, PN2);
- ingressInner = V1;
- ingressOuter = V2;
- egressInner = V1;
- egressOuter = V2;
- PwaasUtil.verifyPolicy(cp1, cp2, ingressInner, ingressOuter, egressInner, egressOuter, TUNNEL_ID);
-
- ingressInner = VlanId.NONE;
- ingressOuter = VlanId.NONE;
- egressInner = VlanId.NONE;
- egressOuter = VlanId.NONE;
- PwaasUtil.verifyPolicy(cp1, cp2, ingressInner, ingressOuter, egressInner, egressOuter, TUNNEL_ID);
- }
-
- @Test
- public void verifyPolicyOnSameDevice() {
- cp1 = new ConnectPoint(DID1, PN1);
- cp2 = new ConnectPoint(DID1, PN2);
- ingressInner = VlanId.NONE;
- ingressOuter = VlanId.NONE;
- egressInner = VlanId.NONE;
- egressOuter = VlanId.NONE;
- exception.expect(IllegalArgumentException.class);
- exception.expectMessage(String.format(PwaasUtil.ERR_SAME_DEV, TUNNEL_ID));
- PwaasUtil.verifyPolicy(cp1, cp2, ingressInner, ingressOuter, egressInner, egressOuter, TUNNEL_ID);
- }
-
- @Test
- public void verifyPolicyEmptyInnerCp1() {
- cp1 = new ConnectPoint(DID1, PN1);
- cp2 = new ConnectPoint(DID2, PN2);
- ingressInner = VlanId.NONE;
- ingressOuter = V1;
- egressInner = VlanId.NONE;
- egressOuter = VlanId.NONE;
- exception.expect(IllegalArgumentException.class);
- exception.expectMessage(String.format(PwaasUtil.ERR_EMPTY_INNER_WHEN_OUTER_PRESENT, TUNNEL_ID, "cp1"));
- PwaasUtil.verifyPolicy(cp1, cp2, ingressInner, ingressOuter, egressInner, egressOuter, TUNNEL_ID);
- }
-
- @Test
- public void verifyPolicyEmptyInnerCp2() {
- cp1 = new ConnectPoint(DID1, PN1);
- cp2 = new ConnectPoint(DID2, PN2);
- ingressInner = VlanId.NONE;
- ingressOuter = VlanId.NONE;
- egressInner = VlanId.NONE;
- egressOuter = V1;
- exception.expect(IllegalArgumentException.class);
- exception.expectMessage(String.format(PwaasUtil.ERR_EMPTY_INNER_WHEN_OUTER_PRESENT, TUNNEL_ID, "cp2"));
- PwaasUtil.verifyPolicy(cp1, cp2, ingressInner, ingressOuter, egressInner, egressOuter, TUNNEL_ID);
- }
-
- @Test
- public void verifyPolicyVlanWildcard() {
- cp1 = new ConnectPoint(DID1, PN1);
- cp2 = new ConnectPoint(DID2, PN2);
- ingressInner = VlanId.ANY;
- ingressOuter = VlanId.NONE;
- egressInner = VlanId.NONE;
- egressOuter = VlanId.NONE;
- exception.expect(IllegalArgumentException.class);
- exception.expectMessage(String.format(PwaasUtil.ERR_WILDCARD_VLAN, TUNNEL_ID));
- PwaasUtil.verifyPolicy(cp1, cp2, ingressInner, ingressOuter, egressInner, egressOuter, TUNNEL_ID);
- }
-
-
- @Test
- public void verifyPolicyDeviceServiceNotAvailable() {
- TestUtils.setField(PwaasUtil.class, "deviceService", null);
- cp1 = new ConnectPoint(DID1, PN1);
- cp2 = new ConnectPoint(DID2, PN2);
- ingressInner = V1;
- ingressOuter = V2;
- egressInner = V1;
- egressOuter = V2;
- exception.expect(IllegalStateException.class);
- exception.expectMessage(String.format(PwaasUtil.ERR_SERVICE_UNAVAIL, "DeviceService"));
- PwaasUtil.verifyPolicy(cp1, cp2, ingressInner, ingressOuter, egressInner, egressOuter, TUNNEL_ID);
- }
-
- @Test
- public void verifyPolicyDoubleToUntagged() {
- cp1 = new ConnectPoint(DID1, PN1);
- cp2 = new ConnectPoint(DID2, PN2);
- ingressInner = V1;
- ingressOuter = V2;
- egressInner = VlanId.NONE;
- egressOuter = VlanId.NONE;
- exception.expect(IllegalArgumentException.class);
- exception.expectMessage(String.format(PwaasUtil.ERR_DOUBLE_TO_UNTAGGED, TUNNEL_ID));
- PwaasUtil.verifyPolicy(cp1, cp2, ingressInner, ingressOuter, egressInner, egressOuter, TUNNEL_ID);
- }
-
- @Test
- public void verifyPolicyDoubleToSingle() {
- cp1 = new ConnectPoint(DID1, PN1);
- cp2 = new ConnectPoint(DID2, PN2);
- ingressInner = V1;
- ingressOuter = V2;
- egressInner = V1;
- egressOuter = VlanId.NONE;
- exception.expect(IllegalArgumentException.class);
- exception.expectMessage(String.format(PwaasUtil.ERR_DOUBLE_TO_SINGLE, TUNNEL_ID));
- PwaasUtil.verifyPolicy(cp1, cp2, ingressInner, ingressOuter, egressInner, egressOuter, TUNNEL_ID);
- }
-
- @Test
- public void verifyPolicySingleToUntagged() {
- cp1 = new ConnectPoint(DID1, PN1);
- cp2 = new ConnectPoint(DID2, PN2);
- ingressInner = V1;
- ingressOuter = VlanId.NONE;
- egressInner = VlanId.NONE;
- egressOuter = VlanId.NONE;
- exception.expect(IllegalArgumentException.class);
- exception.expectMessage(String.format(PwaasUtil.ERR_SINGLE_TO_UNTAGGED, TUNNEL_ID));
- PwaasUtil.verifyPolicy(cp1, cp2, ingressInner, ingressOuter, egressInner, egressOuter, TUNNEL_ID);
- }
-
- @Test
- public void verifyPolicyVlanTranslation() {
- cp1 = new ConnectPoint(DID1, PN1);
- cp2 = new ConnectPoint(DID2, PN2);
- ingressInner = V1;
- ingressOuter = VlanId.NONE;
- egressInner = V2;
- egressOuter = VlanId.NONE;
- exception.expect(IllegalArgumentException.class);
- exception.expectMessage(String.format(PwaasUtil.ERR_VLAN_TRANSLATION, TUNNEL_ID));
- PwaasUtil.verifyPolicy(cp1, cp2, ingressInner, ingressOuter, egressInner, egressOuter, TUNNEL_ID);
- }
-
- @Test
- public void verifyPolicyDeviceNotFound() {
- cp1 = new ConnectPoint(DID99, PN1);
- cp2 = new ConnectPoint(DID2, PN2);
- ingressInner = V1;
- ingressOuter = V2;
- egressInner = V1;
- egressOuter = V2;
- exception.expect(IllegalArgumentException.class);
- exception.expectMessage(String.format(PwaasUtil.ERR_DEV_NOT_FOUND, DID99, TUNNEL_ID));
- PwaasUtil.verifyPolicy(cp1, cp2, ingressInner, ingressOuter, egressInner, egressOuter, TUNNEL_ID);
- }
-
- @Test
- public void verifyPolicyPortNotFound() {
- cp1 = new ConnectPoint(DID1, PN99);
- cp2 = new ConnectPoint(DID2, PN2);
- ingressInner = V1;
- ingressOuter = V2;
- egressInner = V1;
- egressOuter = V2;
- exception.expect(IllegalArgumentException.class);
- exception.expectMessage(String.format(PwaasUtil.ERR_PORT_NOT_FOUND, PN99, DID1, TUNNEL_ID));
- PwaasUtil.verifyPolicy(cp1, cp2, ingressInner, ingressOuter, egressInner, egressOuter, TUNNEL_ID);
- }
-}
\ No newline at end of file
diff --git a/app/src/test/java/org/onosproject/segmentrouting/xconnect/api/XconnectCodecTest.java b/app/src/test/java/org/onosproject/segmentrouting/xconnect/api/XconnectCodecTest.java
deleted file mode 100644
index bac9ff4..0000000
--- a/app/src/test/java/org/onosproject/segmentrouting/xconnect/api/XconnectCodecTest.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * 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 com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import com.google.common.collect.Sets;
-import org.junit.Before;
-import org.junit.Test;
-import org.onlab.packet.VlanId;
-import org.onosproject.codec.CodecContext;
-import org.onosproject.codec.JsonCodec;
-import org.onosproject.codec.impl.MockCodecContext;
-import org.onosproject.net.DeviceId;
-
-import java.io.InputStream;
-import java.util.Set;
-
-import static org.junit.Assert.*;
-
-public class XconnectCodecTest {
- private static final DeviceId DEVICE_ID = DeviceId.deviceId("of:1");
- private static final VlanId VLAN_VID = VlanId.vlanId((short) 10);
- private static final XconnectKey KEY = new XconnectKey(DEVICE_ID, VLAN_VID);
- private static final XconnectEndpoint EP1 = XconnectEndpoint.fromString("1");
- private static final XconnectEndpoint EP2 = XconnectEndpoint.fromString("2");
- private static final XconnectEndpoint EP3 = XconnectEndpoint.fromString("LB:5");
-
- private CodecContext context;
- private JsonCodec<XconnectDesc> codec;
-
- @Before
- public void setUp() throws Exception {
- context = new MockCodecContext();
- codec = new XconnectCodec();
- }
-
- @Test
- public void testEncodePort() throws Exception {
- Set<XconnectEndpoint> endpoints1 = Sets.newHashSet(EP1, EP2);
- XconnectDesc desc1 = new XconnectDesc(KEY, endpoints1);
-
- ObjectMapper mapper = new ObjectMapper();
- InputStream jsonStream1 = XconnectCodecTest.class.getResourceAsStream("/xconnect1.json");
- JsonNode expected = mapper.readTree(jsonStream1);
-
- JsonNode actual = codec.encode(desc1, context);
-
- assertEquals(expected.get(XconnectCodec.DEVICE_ID), actual.get(XconnectCodec.DEVICE_ID));
- assertEquals(expected.get(XconnectCodec.VLAN_ID).asInt(), actual.get(XconnectCodec.VLAN_ID).asInt());
- assertEquals(expected.get(XconnectCodec.ENDPOINTS), actual.get(XconnectCodec.ENDPOINTS));
- }
-
- @Test
- public void testDecodePort() throws Exception {
- Set<XconnectEndpoint> endpoints1 = Sets.newHashSet(EP1, EP2);
- XconnectDesc expected = new XconnectDesc(KEY, endpoints1);
-
- ObjectMapper mapper = new ObjectMapper();
- InputStream jsonStream1 = XconnectCodecTest.class.getResourceAsStream("/xconnect1.json");
- ObjectNode objectNode = mapper.readTree(jsonStream1).deepCopy();
-
- XconnectDesc actual = codec.decode(objectNode, context);
-
- assertEquals(expected, actual);
- }
-
- @Test
- public void testEncodeLb() throws Exception {
- Set<XconnectEndpoint> endpoints1 = Sets.newHashSet(EP1, EP3);
- XconnectDesc desc1 = new XconnectDesc(KEY, endpoints1);
-
- ObjectMapper mapper = new ObjectMapper();
- InputStream jsonStream1 = XconnectCodecTest.class.getResourceAsStream("/xconnect2.json");
- JsonNode expected = mapper.readTree(jsonStream1);
-
- JsonNode actual = codec.encode(desc1, context);
-
- assertEquals(expected.get(XconnectCodec.DEVICE_ID), actual.get(XconnectCodec.DEVICE_ID));
- assertEquals(expected.get(XconnectCodec.VLAN_ID).asInt(), actual.get(XconnectCodec.VLAN_ID).asInt());
- assertEquals(expected.get(XconnectCodec.ENDPOINTS), actual.get(XconnectCodec.ENDPOINTS));
- }
-
- @Test
- public void testDecodeLb() throws Exception {
- Set<XconnectEndpoint> endpoints1 = Sets.newHashSet(EP1, EP3);
- XconnectDesc expected = new XconnectDesc(KEY, endpoints1);
-
- ObjectMapper mapper = new ObjectMapper();
- InputStream jsonStream1 = XconnectCodecTest.class.getResourceAsStream("/xconnect2.json");
- ObjectNode objectNode = mapper.readTree(jsonStream1).deepCopy();
-
- XconnectDesc actual = codec.decode(objectNode, context);
-
- assertEquals(expected, actual);
- }
-}
\ No newline at end of file
diff --git a/app/src/test/resources/interface1.json b/app/src/test/resources/interface1.json
deleted file mode 100644
index 0f7123f..0000000
--- a/app/src/test/resources/interface1.json
+++ /dev/null
@@ -1,6 +0,0 @@
-[
- {
- "ips" : [ "10.0.1.254/24" ],
- "vlan-untagged": 10
- }
-]
\ No newline at end of file
diff --git a/app/src/test/resources/interface2.json b/app/src/test/resources/interface2.json
deleted file mode 100644
index 114fbf5..0000000
--- a/app/src/test/resources/interface2.json
+++ /dev/null
@@ -1,6 +0,0 @@
-[
- {
- "ips" : [ "10.0.2.254/24" ],
- "vlan-untagged": 20
- }
-]
\ No newline at end of file
diff --git a/app/src/test/resources/pwaas-conflicting-vlan.json b/app/src/test/resources/pwaas-conflicting-vlan.json
deleted file mode 100644
index fac162d..0000000
--- a/app/src/test/resources/pwaas-conflicting-vlan.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "1": {
- "cP1": "of:0000000000000001/1",
- "cP2": "of:0000000000000002/2",
- "cP1InnerTag": "10",
- "cP1OuterTag": "20",
- "cP2InnerTag": "11",
- "cP2OuterTag": "21",
- "mode": "RAW",
- "sdTag": "",
- "pwLabel": "255"
- },
- "20": {
- "cP1": "of:0000000000000001/1",
- "cP2": "of:0000000000000002/2",
- "cP1InnerTag": "100",
- "cP1OuterTag": "",
- "cP2InnerTag": "21",
- "cP2OuterTag": "",
- "mode": "RAW",
- "sdTag": "",
- "pwLabel": "1255"
- }
-}
diff --git a/app/src/test/resources/pwaas-invalid-mode.json b/app/src/test/resources/pwaas-invalid-mode.json
deleted file mode 100644
index af0a9d1..0000000
--- a/app/src/test/resources/pwaas-invalid-mode.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "1": {
- "cP1": "of:0000000000000001/1",
- "cP2": "of:0000000000000011/1",
- "cP1InnerTag": "10",
- "cP1OuterTag": "20",
- "cP2InnerTag": "11",
- "cP2OuterTag": "",
- "mode": "UNDEFINED_MODED",
- "sdTag": "40",
- "pwLabel": "255"
- }
-}
diff --git a/app/src/test/resources/pwaas-invalid-pwlabel.json b/app/src/test/resources/pwaas-invalid-pwlabel.json
deleted file mode 100644
index 66697f5..0000000
--- a/app/src/test/resources/pwaas-invalid-pwlabel.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "1": {
- "cP1": "of:0000000000000001/1",
- "cP2": "of:0000000000000011/1",
- "cP1InnerTag": "10",
- "cP1OuterTag": "20",
- "cP2InnerTag": "11",
- "cP2OuterTag": "",
- "mode": "1",
- "sdTag": "40",
- "pwLabel": "255.555551"
- }
-}
diff --git a/app/src/test/resources/pwaas-invalid-vlan.json b/app/src/test/resources/pwaas-invalid-vlan.json
deleted file mode 100644
index b556e06..0000000
--- a/app/src/test/resources/pwaas-invalid-vlan.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "1": {
- "cP1": "of:0000000000000001/1",
- "cP2": "of:0000000000000002/2",
- "cP1InnerTag": "10",
- "cP1OuterTag": "20",
- "cP2InnerTag": "11",
- "cP2OuterTag": "21",
- "mode": "RAW",
- "sdTag": "",
- "pwLabel": "255"
- },
- "20": {
- "cP1": "of:0000000000000001/1",
- "cP2": "of:0000000000000002/2",
- "cP1InnerTag": "100",
- "cP1OuterTag": "200.55",
- "cP2InnerTag": "1100",
- "cP2OuterTag": "210",
- "mode": "RAW",
- "sdTag": "",
- "pwLabel": "1255"
- }
-}
diff --git a/app/src/test/resources/pwaas.json b/app/src/test/resources/pwaas.json
deleted file mode 100644
index 2a58b4e..0000000
--- a/app/src/test/resources/pwaas.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "1": {
- "cP1": "of:0000000000000001/1",
- "cP2": "of:0000000000000002/1",
- "cP1InnerTag": "10",
- "cP1OuterTag": "20",
- "cP2InnerTag": "10",
- "cP2OuterTag": "21",
- "mode": "RAW",
- "sdTag": "",
- "pwLabel": "255"
- },
- "20": {
- "cP1": "of:0000000000000001/1",
- "cP2": "of:0000000000000002/1",
- "cP1InnerTag": "100",
- "cP1OuterTag": "200",
- "cP2InnerTag": "100",
- "cP2OuterTag": "210",
- "mode": "RAW",
- "sdTag": "",
- "pwLabel": "1255"
- }
-}
diff --git a/app/src/test/resources/xconnect1.json b/app/src/test/resources/xconnect1.json
deleted file mode 100644
index d8990d4..0000000
--- a/app/src/test/resources/xconnect1.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "deviceId": "of:1",
- "vlanId": 10,
- "endpoints": ["1", "2"]
-}
diff --git a/app/src/test/resources/xconnect2.json b/app/src/test/resources/xconnect2.json
deleted file mode 100644
index 61919da..0000000
--- a/app/src/test/resources/xconnect2.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "deviceId": "of:1",
- "vlanId": 10,
- "endpoints": ["1", "LB:5"]
-}