Refactored OpenstackRouting to support multiple gateway nodes
Change-Id: I6870ca9a4fd6f6b1cf2d2be72f52ef87827e1d2c
diff --git a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/AbstractVmHandler.java b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/AbstractVmHandler.java
new file mode 100644
index 0000000..58b89a6
--- /dev/null
+++ b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/AbstractVmHandler.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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.openstacknetworking;
+
+import org.onlab.osgi.DefaultServiceDirectory;
+import org.onlab.osgi.ServiceDirectory;
+import org.onlab.packet.Ip4Address;
+import org.onlab.util.Tools;
+import org.onosproject.core.CoreService;
+import org.onosproject.mastership.MastershipService;
+import org.onosproject.net.Host;
+import org.onosproject.net.host.HostEvent;
+import org.onosproject.net.host.HostListener;
+import org.onosproject.net.host.HostService;
+import org.slf4j.Logger;
+
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.stream.Collectors;
+
+import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
+import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.openstacknetworking.Constants.*;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Provides abstract virtual machine handler.
+ */
+public abstract class AbstractVmHandler {
+ protected final Logger log = getLogger(getClass());
+
+ protected final ExecutorService eventExecutor = newSingleThreadScheduledExecutor(
+ groupedThreads(this.getClass().getSimpleName(), "event-handler"));
+
+ protected CoreService coreService;
+ protected MastershipService mastershipService;
+ protected HostService hostService;
+
+ protected HostListener hostListener = new InternalHostListener();
+
+ protected void activate() {
+ ServiceDirectory services = new DefaultServiceDirectory();
+ coreService = services.get(CoreService.class);
+ mastershipService = services.get(MastershipService.class);
+ hostService = services.get(HostService.class);
+ hostService.addListener(hostListener);
+
+ log.info("Started");
+ }
+
+ protected void deactivate() {
+ hostService.removeListener(hostListener);
+ eventExecutor.shutdown();
+
+ log.info("Stopped");
+ }
+
+ /**
+ * Performs any action when a host is detected.
+ *
+ * @param host detected host
+ */
+ protected abstract void hostDetected(Host host);
+
+ /**
+ * Performs any action when a host is removed.
+ *
+ * @param host removed host
+ */
+ protected abstract void hostRemoved(Host host);
+
+ protected boolean isValidHost(Host host) {
+ return !host.ipAddresses().isEmpty() &&
+ host.annotations().value(VXLAN_ID) != null &&
+ host.annotations().value(NETWORK_ID) != null &&
+ host.annotations().value(TENANT_ID) != null &&
+ host.annotations().value(PORT_ID) != null;
+ }
+
+ protected Set<Host> getVmsInDifferentCnode(Host host) {
+ return Tools.stream(hostService.getHosts())
+ .filter(h -> !h.location().deviceId().equals(host.location().deviceId()))
+ .filter(this::isValidHost)
+ .filter(h -> Objects.equals(getVni(h), getVni(host)))
+ .collect(Collectors.toSet());
+ }
+
+ protected Optional<Host> getVmByPortId(String portId) {
+ return Tools.stream(hostService.getHosts())
+ .filter(this::isValidHost)
+ .filter(host -> host.annotations().value(PORT_ID).equals(portId))
+ .findFirst();
+ }
+
+ protected Ip4Address getIp(Host host) {
+ return host.ipAddresses().stream().findFirst().get().getIp4Address();
+ }
+
+ protected String getVni(Host host) {
+ return host.annotations().value(VXLAN_ID);
+ }
+
+ protected String getTenantId(Host host) {
+ return host.annotations().value(TENANT_ID);
+ }
+
+ private class InternalHostListener implements HostListener {
+
+ @Override
+ public void event(HostEvent event) {
+ Host host = event.subject();
+ if (!mastershipService.isLocalMaster(host.location().deviceId())) {
+ // do not allow to proceed without mastership
+ return;
+ }
+
+ if (!isValidHost(host)) {
+ log.debug("Invalid host event, ignore it {}", host);
+ return;
+ }
+
+ switch (event.type()) {
+ case HOST_UPDATED:
+ case HOST_ADDED:
+ eventExecutor.execute(() -> hostDetected(host));
+ break;
+ case HOST_REMOVED:
+ eventExecutor.execute(() -> hostRemoved(host));
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
diff --git a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/Constants.java b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/Constants.java
index 54334b9..dbcb521 100644
--- a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/Constants.java
+++ b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/Constants.java
@@ -28,23 +28,27 @@
private Constants() {
}
- public static final String APP_ID = "org.onosproject.openstackswitching";
+ public static final String SWITCHING_APP_ID = "org.onosproject.openstackswitching";
+ public static final String ROUTING_APP_ID = "org.onosproject.openstackrouting";
- public static final String PORTNAME_PREFIX_VM = "tap";
- public static final String PORTNAME_PREFIX_ROUTER = "qr-";
- public static final String PORTNAME_PREFIX_TUNNEL = "vxlan";
+ public static final String DEVICE_OWNER_ROUTER_INTERFACE = "network:router_interface";
+ public static final String DEVICE_OWNER_ROUTER_GATEWAY = "network:router_gateway";
+ public static final String DEVICE_OWNER_FLOATING_IP = "network:floatingip";
- public static final MacAddress GATEWAY_MAC = MacAddress.valueOf("1f:1f:1f:1f:1f:1f");
+ public static final String PORT_NAME_PREFIX_VM = "tap";
+ public static final String PORT_NAME_PREFIX_TUNNEL = "vxlan";
- // TODO: Please change these valuses following the way vrouter is implemented
- public static final MacAddress GW_EXT_INT_MAC = MacAddress.valueOf("56:e6:30:a6:8c:e5");
- public static final MacAddress PHY_ROUTER_MAC = MacAddress.valueOf("00:00:00:00:01:01");
+ public static final String DEFAULT_GATEWAY_MAC_STR = "fe:00:00:00:00:02";
+ public static final MacAddress DEFAULT_GATEWAY_MAC = MacAddress.valueOf(DEFAULT_GATEWAY_MAC_STR);
+ // TODO make this configurable
+ public static final MacAddress DEFAULT_EXTERNAL_ROUTER_MAC = MacAddress.valueOf("fe:00:00:00:00:01");
public static final Ip4Address DNS_SERVER_IP = Ip4Address.valueOf("8.8.8.8");
public static final IpPrefix IP_PREFIX_ANY = Ip4Prefix.valueOf("0.0.0.0/0");
public static final int DHCP_INFINITE_LEASE = -1;
public static final String NETWORK_ID = "networkId";
+ public static final String SUBNET_ID = "subnetId";
public static final String PORT_ID = "portId";
public static final String VXLAN_ID = "vxlanId";
public static final String TENANT_ID = "tenantId";
@@ -55,4 +59,8 @@
public static final int TUNNELTAG_RULE_PRIORITY = 30000;
public static final int ACL_RULE_PRIORITY = 30000;
+ public static final int ROUTING_RULE_PRIORITY = 25000;
+ public static final int FLOATING_RULE_PRIORITY = 42000;
+ public static final int PNAT_RULE_PRIORITY = 26000;
+ public static final int PNAT_TIMEOUT = 120;
}
\ No newline at end of file
diff --git a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/OpenstackFloatingIpService.java b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/OpenstackFloatingIpService.java
new file mode 100644
index 0000000..5f9f6b3
--- /dev/null
+++ b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/OpenstackFloatingIpService.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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.openstacknetworking;
+
+import org.onosproject.openstackinterface.OpenstackFloatingIP;
+
+/**
+ * Handles floating IP update requests from OpenStack.
+ */
+public interface OpenstackFloatingIpService {
+
+ enum Action {
+ ASSOCIATE,
+ DISSASSOCIATE
+ }
+
+ /**
+ * Handles floating IP create request from OpenStack.
+ *
+ * @param floatingIp floating IP information
+ */
+ void createFloatingIp(OpenstackFloatingIP floatingIp);
+
+ /**
+ * Handles floating IP update request from OpenStack.
+ *
+ * @param floatingIp floating IP information
+ */
+ void updateFloatingIp(OpenstackFloatingIP floatingIp);
+
+ /**
+ * Handles floating IP remove request from OpenStack.
+ *
+ * @param floatingIpId floating ip identifier
+ */
+ void deleteFloatingIp(String floatingIpId);
+}
diff --git a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/OpenstackRoutingService.java b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/OpenstackRoutingService.java
index 327d9e4..9923e6f 100644
--- a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/OpenstackRoutingService.java
+++ b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/OpenstackRoutingService.java
@@ -15,76 +15,49 @@
*/
package org.onosproject.openstacknetworking;
-import org.onosproject.openstackinterface.OpenstackFloatingIP;
import org.onosproject.openstackinterface.OpenstackRouter;
import org.onosproject.openstackinterface.OpenstackRouterInterface;
/**
- * Supports L3 management REST API for openstack.
+ * Handles router update requests from OpenStack.
*/
public interface OpenstackRoutingService {
/**
- * Stores the floating IP information created by openstack.
+ * Handles the router create request from OpenStack.
*
- * @param openstackFloatingIp Floating IP information
+ * @param osRouter router information
*/
- void createFloatingIP(OpenstackFloatingIP openstackFloatingIp);
+ void createRouter(OpenstackRouter osRouter);
/**
- * Updates flow rules corresponding to the floating IP information updated by openstack.
+ * Handles the router update request from OpenStack.
+ * Update router is called when the name, administrative state, or the external
+ * gateway setting is updated. The external gateway update is the only case
+ * that openstack routing service cares.
*
- * @param openstackFloatingIp Floating IP information
+ * @param osRouter router information
*/
- void updateFloatingIP(OpenstackFloatingIP openstackFloatingIp);
+ void updateRouter(OpenstackRouter osRouter);
/**
- * Removes flow rules corresponding to floating IP information removed by openstack.
+ * Handles the router remove request from OpenStack.
*
- * @param id Deleted Floating IP`s ID
+ * @param osRouterId identifier of the router
*/
- void deleteFloatingIP(String id);
+ void removeRouter(String osRouterId);
/**
- * Stores the router information created by openstack.
+ * Handles router interface add request from OpenStack.
*
- * @param openstackRouter Router information
+ * @param osInterface router interface information
*/
- void createRouter(OpenstackRouter openstackRouter);
+ void addRouterInterface(OpenstackRouterInterface osInterface);
/**
- * Updates flow rules corresponding to the router information updated by openstack.
+ * Handles router interface remove request from OpenStack.
*
- * @param openstackRouter Router information
+ * @param osInterface router interface information
*/
- void updateRouter(OpenstackRouter openstackRouter);
-
- /**
- * Removes flow rules corresponding to the router information removed by openstack.
- *
- * @param id Deleted router`s ID
- */
- void deleteRouter(String id);
-
- /**
- * Updates flow rules corresponding to the router information updated by openstack.
- *
- * @param openstackRouterInterface Router interface information
- */
- void updateRouterInterface(OpenstackRouterInterface openstackRouterInterface);
-
- /**
- * Removes flow rules corresponding to the router information removed by openstack.
- *
- * @param openstackRouterInterface Router interface information
- */
- void removeRouterInterface(OpenstackRouterInterface openstackRouterInterface);
-
- /**
- * Returns network id for routerInterface.
- *
- * @param portId routerInterface`s port id
- * @return network id
- */
- String networkIdForRouterInterface(String portId);
+ void removeRouterInterface(OpenstackRouterInterface osInterface);
}
diff --git a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/RulePopulatorUtil.java b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/RulePopulatorUtil.java
new file mode 100644
index 0000000..d220b8c
--- /dev/null
+++ b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/RulePopulatorUtil.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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.openstacknetworking;
+
+import org.onlab.packet.Ip4Address;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.instructions.ExtensionPropertyException;
+import org.onosproject.net.flow.instructions.ExtensionTreatment;
+import org.onosproject.net.flowobjective.DefaultForwardingObjective;
+import org.onosproject.net.flowobjective.FlowObjectiveService;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.slf4j.Logger;
+
+import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Provides common methods to help populating flow rules for SONA applications.
+ */
+public final class RulePopulatorUtil {
+
+ protected static final Logger log = getLogger(RulePopulatorUtil.class);
+
+ private static final String TUNNEL_DST = "tunnelDst";
+
+ private RulePopulatorUtil() {
+ }
+
+ /**
+ * Returns tunnel destination extension treatment object.
+ *
+ * @param deviceService driver service
+ * @param deviceId device id to apply this treatment
+ * @param remoteIp tunnel destination ip address
+ * @return extension treatment
+ */
+ public static ExtensionTreatment buildExtension(DeviceService deviceService,
+ DeviceId deviceId,
+ Ip4Address remoteIp) {
+ Device device = deviceService.getDevice(deviceId);
+ if (device != null && !device.is(ExtensionTreatmentResolver.class)) {
+ log.error("The extension treatment is not supported");
+ return null;
+ }
+
+ ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
+ ExtensionTreatment treatment = resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
+ try {
+ treatment.setPropertyValue(TUNNEL_DST, remoteIp);
+ return treatment;
+ } catch (ExtensionPropertyException e) {
+ log.warn("Failed to get tunnelDst extension treatment for {}", deviceId);
+ return null;
+ }
+ }
+
+ /**
+ * Removes flow rules with the supplied information.
+ *
+ * @param flowObjectiveService flow objective service
+ * @param appId application id
+ * @param deviceId device id to remove this flow rule
+ * @param selector traffic selector
+ * @param flag flag
+ * @param priority priority
+ */
+ public static void removeRule(FlowObjectiveService flowObjectiveService,
+ ApplicationId appId,
+ DeviceId deviceId,
+ TrafficSelector selector,
+ ForwardingObjective.Flag flag,
+ int priority) {
+ ForwardingObjective fo = DefaultForwardingObjective.builder()
+ .withSelector(selector)
+ .withTreatment(DefaultTrafficTreatment.builder().build())
+ .withFlag(flag)
+ .withPriority(priority)
+ .fromApp(appId)
+ .remove();
+
+ flowObjectiveService.forward(deviceId, fo);
+ }
+}