Refactored OpenstackRouting to support multiple gateway nodes
Change-Id: I6870ca9a4fd6f6b1cf2d2be72f52ef87827e1d2c
diff --git a/apps/openstackinterface/api/src/main/java/org/onosproject/openstackinterface/OpenstackRouterInterface.java b/apps/openstackinterface/api/src/main/java/org/onosproject/openstackinterface/OpenstackRouterInterface.java
index 797c9a8..93d9b47 100644
--- a/apps/openstackinterface/api/src/main/java/org/onosproject/openstackinterface/OpenstackRouterInterface.java
+++ b/apps/openstackinterface/api/src/main/java/org/onosproject/openstackinterface/OpenstackRouterInterface.java
@@ -20,7 +20,7 @@
import static com.google.common.base.Preconditions.checkNotNull;
/**
- * An Openstack Neutron Router Interface Model.
+ * An OpenStack Neutron router interface model.
*/
public final class OpenstackRouterInterface {
private final String id;
@@ -37,9 +37,9 @@
}
/**
- * Returns Router Interface ID.
+ * Returns router interface ID.
*
- * @return router interface ID
+ * @return router interface id
*/
public String id() {
return id;
@@ -48,7 +48,7 @@
/**
* Returns tenant ID.
*
- * @return tenant ID
+ * @return tenant id
*/
public String tenantId() {
return tenantId;
@@ -57,7 +57,7 @@
/**
* Returns subnet ID.
*
- * @return subnet ID
+ * @return subnet id
*/
public String subnetId() {
return subnetId;
@@ -66,7 +66,7 @@
/**
* Returns port ID.
*
- * @return port ID
+ * @return port id
*/
public String portId() {
return portId;
@@ -96,7 +96,16 @@
}
/**
- * An Openstack Router Interface Builder class.
+ * Returns OpenStack router interface builder.
+ *
+ * @return openstack router interface builder
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * An OpenStack Router interface builder class.
*/
public static final class Builder {
private String id;
@@ -105,10 +114,10 @@
private String portId;
/**
- * Sets Router Interface ID.
+ * Sets router interface ID.
*
- * @param id router interface ID
- * @return Builder object
+ * @param id router interface id
+ * @return builder object
*/
public Builder id(String id) {
this.id = id;
@@ -119,7 +128,7 @@
* Sets tenant ID.
*
* @param tenantId tenant ID
- * @return Builder object
+ * @return builder object
*/
public Builder tenantId(String tenantId) {
this.tenantId = tenantId;
@@ -130,7 +139,7 @@
* Sets subnet ID.
*
* @param subnetId subnet ID
- * @return Builder object
+ * @return builder object
*/
public Builder subnetId(String subnetId) {
this.subnetId = subnetId;
@@ -141,7 +150,7 @@
* Sets port ID.
*
* @param portId port ID
- * @return Builder object
+ * @return builder object
*/
public Builder portId(String portId) {
this.portId = portId;
@@ -149,14 +158,13 @@
}
/**
- * Builds an Openstack Router Interface object.
+ * Builds an OpenStack router interface object.
*
- * @return OpenstackRouterInterface object
+ * @return openstack router interface object
*/
public OpenstackRouterInterface build() {
return new OpenstackRouterInterface(checkNotNull(id), checkNotNull(tenantId),
checkNotNull(subnetId), checkNotNull(portId));
}
-
}
}
diff --git a/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/AbstractVmHandler.java b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/AbstractVmHandler.java
similarity index 92%
rename from apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/AbstractVmHandler.java
rename to apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/AbstractVmHandler.java
index d7b7a8a..58b89a6 100644
--- a/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/AbstractVmHandler.java
+++ b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/AbstractVmHandler.java
@@ -13,20 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.onosproject.openstacknetworking.switching;
+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.ApplicationId;
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.onosproject.openstacknetworking.Constants;
import org.slf4j.Logger;
import java.util.Objects;
@@ -53,7 +51,6 @@
protected MastershipService mastershipService;
protected HostService hostService;
- protected ApplicationId appId;
protected HostListener hostListener = new InternalHostListener();
protected void activate() {
@@ -61,8 +58,6 @@
coreService = services.get(CoreService.class);
mastershipService = services.get(MastershipService.class);
hostService = services.get(HostService.class);
-
- appId = coreService.registerApplication(Constants.APP_ID);
hostService.addListener(hostListener);
log.info("Started");
@@ -75,9 +70,19 @@
log.info("Stopped");
}
- abstract void hostDetected(Host host);
+ /**
+ * Performs any action when a host is detected.
+ *
+ * @param host detected host
+ */
+ protected abstract void hostDetected(Host host);
- abstract void hostRemoved(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() &&
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);
+ }
+}
diff --git a/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackFloatingIPHandler.java b/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackFloatingIPHandler.java
deleted file mode 100644
index 3d1c013..0000000
--- a/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackFloatingIPHandler.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.routing;
-
-import org.onosproject.net.Host;
-import org.onosproject.openstackinterface.OpenstackFloatingIP;
-
-/**
- * Handle FloatingIP Event for Managing Flow Rules In Openstack Nodes.
- */
-public class OpenstackFloatingIPHandler implements Runnable {
-
- public enum Action {
- ASSOCIATE,
- DISSASSOCIATE
- }
-
- private final OpenstackFloatingIP floatingIP;
- private final OpenstackRoutingRulePopulator rulePopulator;
- private final Host host;
- private final Action action;
-
-
- OpenstackFloatingIPHandler(OpenstackRoutingRulePopulator rulePopulator,
- OpenstackFloatingIP openstackFloatingIP, Action action, Host host) {
- this.floatingIP = openstackFloatingIP;
- this.rulePopulator = rulePopulator;
- this.action = action;
- this.host = host;
- }
-
- @Override
- public void run() {
- if (action == Action.ASSOCIATE) {
- rulePopulator.populateFloatingIpRules(floatingIP);
- } else {
- rulePopulator.removeFloatingIpRules(floatingIP, host);
- }
- }
-}
diff --git a/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackFloatingIpManager.java b/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackFloatingIpManager.java
new file mode 100644
index 0000000..ba60fe8
--- /dev/null
+++ b/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackFloatingIpManager.java
@@ -0,0 +1,329 @@
+/*
+ * 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.routing;
+
+import com.google.common.base.Strings;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IpAddress;
+import org.onlab.util.KryoNamespace;
+import org.onlab.util.Tools;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Host;
+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.flowobjective.DefaultForwardingObjective;
+import org.onosproject.net.flowobjective.FlowObjectiveService;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.net.host.HostService;
+import org.onosproject.openstackinterface.OpenstackFloatingIP;
+import org.onosproject.openstacknetworking.Constants;
+import org.onosproject.openstacknetworking.OpenstackFloatingIpService;
+import org.onosproject.openstacknetworking.RulePopulatorUtil;
+import org.onosproject.openstacknode.OpenstackNode;
+import org.onosproject.openstacknode.OpenstackNodeEvent;
+import org.onosproject.openstacknode.OpenstackNodeListener;
+import org.onosproject.openstacknode.OpenstackNodeService;
+import org.onosproject.scalablegateway.api.GatewayNode;
+import org.onosproject.scalablegateway.api.ScalableGatewayService;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.ExecutorService;
+
+import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
+import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.openstacknetworking.Constants.*;
+import static org.onosproject.openstacknetworking.RulePopulatorUtil.buildExtension;
+import static org.onosproject.openstacknode.OpenstackNodeService.NodeType.GATEWAY;
+
+
+@Service
+@Component(immediate = true)
+public class OpenstackFloatingIpManager implements OpenstackFloatingIpService {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected HostService hostService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DeviceService deviceService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected FlowObjectiveService flowObjectiveService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected StorageService storageService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected OpenstackNodeService nodeService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected ScalableGatewayService gatewayService;
+
+ private static final String NOT_ASSOCIATED = "null";
+ private static final KryoNamespace.Builder FLOATING_IP_SERIALIZER =
+ KryoNamespace.newBuilder().register(KryoNamespaces.API);
+
+ private final ExecutorService eventExecutor = newSingleThreadScheduledExecutor(
+ groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
+ private final InternalNodeListener nodeListener = new InternalNodeListener();
+ private ConsistentMap<IpAddress, Host> floatingIpMap;
+
+ private ApplicationId appId;
+
+ @Activate
+ protected void activate() {
+ appId = coreService.registerApplication(ROUTING_APP_ID);
+ nodeService.addListener(nodeListener);
+ floatingIpMap = storageService.<IpAddress, Host>consistentMapBuilder()
+ .withSerializer(Serializer.using(FLOATING_IP_SERIALIZER.build()))
+ .withName("openstackrouting-floatingip")
+ .withApplicationId(appId)
+ .build();
+
+ log.info("Started");
+ }
+
+ @Deactivate
+ protected void deactivate() {
+ nodeService.removeListener(nodeListener);
+ log.info("Stopped");
+ }
+
+ @Override
+ public void createFloatingIp(OpenstackFloatingIP floatingIp) {
+ }
+
+ @Override
+ public void updateFloatingIp(OpenstackFloatingIP floatingIp) {
+ if (Strings.isNullOrEmpty(floatingIp.portId()) ||
+ floatingIp.portId().equals(NOT_ASSOCIATED)) {
+ eventExecutor.execute(() -> disassociateFloatingIp(floatingIp));
+ } else {
+ eventExecutor.execute(() -> associateFloatingIp(floatingIp));
+ }
+ }
+
+ @Override
+ public void deleteFloatingIp(String floatingIpId) {
+ }
+
+ private void associateFloatingIp(OpenstackFloatingIP floatingIp) {
+ Optional<Host> associatedVm = Tools.stream(hostService.getHosts())
+ .filter(host -> Objects.equals(
+ host.annotations().value(PORT_ID),
+ floatingIp.portId()))
+ .findAny();
+ if (!associatedVm.isPresent()) {
+ log.warn("Failed to associate floating IP({}) to port:{}",
+ floatingIp.floatingIpAddress(),
+ floatingIp.portId());
+ return;
+ }
+
+ floatingIpMap.put(floatingIp.floatingIpAddress(), associatedVm.get());
+ populateFloatingIpRules(floatingIp.floatingIpAddress(), associatedVm.get());
+
+ log.info("Associated floating IP {} to fixed IP {}",
+ floatingIp.floatingIpAddress(), floatingIp.fixedIpAddress());
+ }
+
+ private void disassociateFloatingIp(OpenstackFloatingIP floatingIp) {
+ Versioned<Host> associatedVm = floatingIpMap.remove(floatingIp.floatingIpAddress());
+ if (associatedVm == null) {
+ log.warn("Failed to disassociate floating IP({})",
+ floatingIp.floatingIpAddress());
+ // No VM is actually associated with the floating IP, do nothing
+ return;
+ }
+
+ removeFloatingIpRules(floatingIp.floatingIpAddress(), associatedVm.value());
+ log.info("Disassociated floating IP {} from fixed IP {}",
+ floatingIp.floatingIpAddress(),
+ associatedVm.value().ipAddresses());
+ }
+
+ private void populateFloatingIpRules(IpAddress floatingIp, Host associatedVm) {
+ populateFloatingIpIncomingRules(floatingIp, associatedVm);
+ populateFloatingIpOutgoingRules(floatingIp, associatedVm);
+ }
+
+ private void removeFloatingIpRules(IpAddress floatingIp, Host associatedVm) {
+ Optional<IpAddress> fixedIp = associatedVm.ipAddresses().stream().findFirst();
+ if (!fixedIp.isPresent()) {
+ log.warn("Failed to remove floating IP({}) from {}",
+ floatingIp, associatedVm);
+ return;
+ }
+
+ TrafficSelector.Builder sOutgoingBuilder = DefaultTrafficSelector.builder();
+ TrafficSelector.Builder sIncomingBuilder = DefaultTrafficSelector.builder();
+
+ sOutgoingBuilder.matchEthType(Ethernet.TYPE_IPV4)
+ .matchTunnelId(Long.valueOf(associatedVm.annotations().value(VXLAN_ID)))
+ .matchIPSrc(fixedIp.get().toIpPrefix());
+
+ sIncomingBuilder.matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPDst(floatingIp.toIpPrefix());
+
+ gatewayService.getGatewayDeviceIds().stream().forEach(deviceId -> {
+ RulePopulatorUtil.removeRule(
+ flowObjectiveService,
+ appId,
+ deviceId,
+ sOutgoingBuilder.build(),
+ ForwardingObjective.Flag.VERSATILE,
+ FLOATING_RULE_PRIORITY);
+
+ RulePopulatorUtil.removeRule(
+ flowObjectiveService,
+ appId,
+ deviceId,
+ sIncomingBuilder.build(),
+ ForwardingObjective.Flag.VERSATILE,
+ FLOATING_RULE_PRIORITY);
+ });
+ }
+
+ private void populateFloatingIpIncomingRules(IpAddress floatingIp, Host associatedVm) {
+ DeviceId cnodeId = associatedVm.location().deviceId();
+ Optional<IpAddress> dataIp = nodeService.dataIp(cnodeId);
+ Optional<IpAddress> fixedIp = associatedVm.ipAddresses().stream().findFirst();
+
+ if (!fixedIp.isPresent() || !dataIp.isPresent()) {
+ log.warn("Failed to associate floating IP({})", floatingIp);
+ return;
+ }
+
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPDst(floatingIp.toIpPrefix())
+ .build();
+
+ gatewayService.getGatewayDeviceIds().stream().forEach(gnodeId -> {
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
+ .setEthDst(associatedVm.mac())
+ .setIpDst(associatedVm.ipAddresses().stream().findFirst().get())
+ .setTunnelId(Long.valueOf(associatedVm.annotations().value(VXLAN_ID)))
+ .extension(buildExtension(deviceService, cnodeId, dataIp.get().getIp4Address()),
+ cnodeId)
+ .setOutput(nodeService.tunnelPort(gnodeId).get())
+ .build();
+
+ ForwardingObjective fo = DefaultForwardingObjective.builder()
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(FLOATING_RULE_PRIORITY)
+ .fromApp(appId)
+ .add();
+
+ flowObjectiveService.forward(gnodeId, fo);
+ });
+ }
+
+ private void populateFloatingIpOutgoingRules(IpAddress floatingIp, Host associatedVm) {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .matchTunnelId(Long.valueOf(associatedVm.annotations().value(VXLAN_ID)))
+ .matchIPSrc(associatedVm.ipAddresses().stream().findFirst().get().toIpPrefix())
+ .build();
+
+ gatewayService.getGatewayDeviceIds().stream().forEach(gnodeId -> {
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setIpSrc(floatingIp)
+ .setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
+ .setEthDst(Constants.DEFAULT_EXTERNAL_ROUTER_MAC)
+ .setOutput(gatewayService.getUplinkPort(gnodeId))
+ .build();
+
+ ForwardingObjective fo = DefaultForwardingObjective.builder()
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(FLOATING_RULE_PRIORITY)
+ .fromApp(appId)
+ .add();
+
+ flowObjectiveService.forward(gnodeId, fo);
+ });
+ }
+
+ private void reloadFloatingIpRules() {
+ floatingIpMap.entrySet().stream().forEach(entry -> {
+ IpAddress floatingIp = entry.getKey();
+ Host associatedVm = entry.getValue().value();
+
+ populateFloatingIpRules(floatingIp, associatedVm);
+ log.debug("Reload floating IP {} mapped to {}",
+ floatingIp, associatedVm.ipAddresses());
+ });
+ }
+
+ // TODO apply existing floating IPs on service start-up by handling host event
+ // TODO consider the case that port with associated floating IP is attached to a VM
+
+ private class InternalNodeListener implements OpenstackNodeListener {
+
+ @Override
+ public void event(OpenstackNodeEvent event) {
+ OpenstackNode node = event.node();
+
+ switch (event.type()) {
+ case COMPLETE:
+ if (node.type() == GATEWAY) {
+ log.info("GATEWAY node {} detected", node.hostname());
+ GatewayNode gnode = GatewayNode.builder()
+ .gatewayDeviceId(node.intBridge())
+ .dataIpAddress(node.dataIp().getIp4Address())
+ .uplinkIntf(node.externalPortName().get())
+ .build();
+ gatewayService.addGatewayNode(gnode);
+ eventExecutor.execute(OpenstackFloatingIpManager.this::reloadFloatingIpRules);
+ }
+ break;
+ case INIT:
+ case DEVICE_CREATED:
+ case INCOMPLETE:
+ default:
+ break;
+ }
+ }
+ }
+}
diff --git a/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackIcmpHandler.java b/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackIcmpHandler.java
index 7db84bb..b6bf09a 100644
--- a/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackIcmpHandler.java
+++ b/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackIcmpHandler.java
@@ -16,322 +16,319 @@
package org.onosproject.openstacknetworking.routing;
import com.google.common.collect.Maps;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.packet.Ethernet;
import org.onlab.packet.ICMP;
import org.onlab.packet.IPv4;
import org.onlab.packet.Ip4Address;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.MacAddress;
import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Host;
-import org.onosproject.net.Port;
-import org.onosproject.net.PortNumber;
-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.host.HostService;
import org.onosproject.net.packet.DefaultOutboundPacket;
+import org.onosproject.net.packet.InboundPacket;
import org.onosproject.net.packet.OutboundPacket;
import org.onosproject.net.packet.PacketContext;
import org.onosproject.net.packet.PacketPriority;
+import org.onosproject.net.packet.PacketProcessor;
import org.onosproject.net.packet.PacketService;
+import org.onosproject.openstackinterface.OpenstackRouter;
import org.onosproject.openstacknetworking.Constants;
import org.onosproject.openstackinterface.OpenstackInterfaceService;
import org.onosproject.openstackinterface.OpenstackPort;
import org.onosproject.openstacknode.OpenstackNode;
+import org.onosproject.openstacknode.OpenstackNodeEvent;
+import org.onosproject.openstacknode.OpenstackNodeListener;
import org.onosproject.openstacknode.OpenstackNodeService;
import org.onosproject.scalablegateway.api.ScalableGatewayService;
import org.slf4j.Logger;
import java.nio.ByteBuffer;
import java.util.Map;
+import java.util.Objects;
import java.util.Optional;
+import java.util.concurrent.ExecutorService;
-import static com.google.common.base.Preconditions.checkNotNull;
-
+import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
+import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.openstacknetworking.Constants.*;
+import static org.onosproject.openstacknode.OpenstackNodeService.NodeType.GATEWAY;
import static org.slf4j.LoggerFactory.getLogger;
/**
- * Handle ICMP packet sent from Openstack Gateway nodes.
+ * Handle ICMP packet sent from OpenStack Gateway nodes.
+ * For a request to any private network gateway IPs, it generates fake reply.
+ * For a request to the external network, it does source NAT with a public IP and
+ * forward the request to the external only if the request instance has external
+ * connection setups.
*/
+@Component(immediate = true)
public class OpenstackIcmpHandler {
protected final Logger log = getLogger(getClass());
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
- private static final String NETWORK_ROUTER_INTERFACE = "network:router_interface";
- private static final String PORTNAME = "portName";
- private static final String NETWORK_ROUTER_GATEWAY = "network:router_gateway";
- private static final String NETWORK_FLOATING_IP = "network:floatingip";
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected PacketService packetService;
- private final PacketService packetService;
- private final DeviceService deviceService;
- private final ScalableGatewayService gatewayService;
- private final HostService hostService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected HostService hostService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected OpenstackInterfaceService openstackService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected ScalableGatewayService gatewayService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected OpenstackNodeService nodeService;
+
+ private final ExecutorService eventExecutor = newSingleThreadScheduledExecutor(
+ groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
+ private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
+ private final InternalNodeListener nodeListener = new InternalNodeListener();
private final Map<String, Host> icmpInfoMap = Maps.newHashMap();
- private final OpenstackInterfaceService openstackService;
- private final OpenstackNodeService nodeService;
- /**
- * Default constructor.
- *
- * @param packetService packet service
- * @param deviceService device service
- * @param openstackService openstackInterface service
- */
- OpenstackIcmpHandler(PacketService packetService,
- DeviceService deviceService,
- HostService hostService,
- OpenstackInterfaceService openstackService,
- OpenstackNodeService nodeService,
- ScalableGatewayService gatewayService
- ) {
- this.packetService = packetService;
- this.deviceService = deviceService;
- this.hostService = hostService;
- this.openstackService = checkNotNull(openstackService);
- this.nodeService = nodeService;
- this.gatewayService = gatewayService;
+ ApplicationId appId;
+
+ @Activate
+ protected void activate() {
+ appId = coreService.registerApplication(ROUTING_APP_ID);
+ packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
+ nodeService.addListener(nodeListener);
+ requestPacket(appId);
+
+ log.info("Started");
}
- /**
- * Requests ICMP packet.
- *
- * @param appId Application Id
- */
- public void requestPacket(ApplicationId appId) {
+ @Deactivate
+ protected void deactivate() {
+ packetService.removeProcessor(packetProcessor);
+ log.info("Stopped");
+ }
+
+ private void requestPacket(ApplicationId appId) {
TrafficSelector icmpSelector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchIPProtocol(IPv4.PROTOCOL_ICMP)
.build();
- // TODO: Return the correct gateway node
- Optional<OpenstackNode> gwNode = nodeService.nodes().stream()
- .filter(n -> n.type().equals(OpenstackNodeService.NodeType.GATEWAY))
- .findFirst();
-
- if (!gwNode.isPresent()) {
- log.warn("No Gateway is defined.");
- return;
- }
-
- packetService.requestPackets(icmpSelector,
- PacketPriority.CONTROL,
- appId,
- Optional.of(gwNode.get().intBridge()));
+ gatewayService.getGatewayDeviceIds().stream().forEach(gateway -> {
+ packetService.requestPackets(icmpSelector,
+ PacketPriority.CONTROL,
+ appId,
+ Optional.of(gateway));
+ log.debug("Requested ICMP packet on {}", gateway);
+ });
}
- /**
- * Handles ICMP packet.
- *
- * @param context packet context
- * @param ethernet ethernet
- */
- public void processIcmpPacket(PacketContext context, Ethernet ethernet) {
- checkNotNull(context, "context can not be null");
- checkNotNull(ethernet, "ethernet can not be null");
-
+ private void processIcmpPacket(PacketContext context, Ethernet ethernet) {
IPv4 ipPacket = (IPv4) ethernet.getPayload();
-
- log.debug("icmpEvent called from ip {}, mac {}", Ip4Address.valueOf(ipPacket.getSourceAddress()).toString(),
- ethernet.getSourceMAC().toString());
+ log.trace("Processing ICMP packet from ip {}, mac {}",
+ Ip4Address.valueOf(ipPacket.getSourceAddress()),
+ ethernet.getSourceMAC());
ICMP icmp = (ICMP) ipPacket.getPayload();
short icmpId = getIcmpId(icmp);
- DeviceId deviceId = context.inPacket().receivedFrom().deviceId();
- PortNumber portNumber = context.inPacket().receivedFrom().port();
- if (icmp.getIcmpType() == ICMP.TYPE_ECHO_REQUEST) {
- //TODO: Considers icmp between internal subnets which are belonged to the same router.
- Optional<Host> host = hostService.getHostsByMac(ethernet.getSourceMAC()).stream().findFirst();
- if (!host.isPresent()) {
- log.warn("No host found for MAC {}", ethernet.getSourceMAC());
- return;
- }
+ DeviceId srcDevice = context.inPacket().receivedFrom().deviceId();
+ switch (icmp.getIcmpType()) {
+ case ICMP.TYPE_ECHO_REQUEST:
+ Optional<Host> reqHost = hostService.getHostsByMac(ethernet.getSourceMAC())
+ .stream().findFirst();
+ if (!reqHost.isPresent()) {
+ log.warn("No host found for MAC {}", ethernet.getSourceMAC());
+ return;
+ }
- IpAddress gatewayIp = IpAddress.valueOf(host.get().annotations().value(Constants.GATEWAY_IP));
- if (ipPacket.getDestinationAddress() == gatewayIp.getIp4Address().toInt()) {
- processIcmpPacketSentToGateway(ipPacket, icmp, host.get());
- } else {
- Ip4Address pNatIpAddress = pNatIpForPort(host.get());
- checkNotNull(pNatIpAddress, "pNatIpAddress can not be null");
+ // TODO Considers icmp between internal subnets belong to the same router.
+ // TODO do we have to support ICMP reply for non-existing gateway?
+ Ip4Address gatewayIp = Ip4Address.valueOf(
+ reqHost.get().annotations().value(Constants.GATEWAY_IP));
+ if (Objects.equals(ipPacket.getDestinationAddress(), gatewayIp.toInt())) {
+ processRequestToGateway(ipPacket, reqHost.get());
+ } else {
+ Optional<Ip4Address> srcNatIp = getSrcNatIp(reqHost.get());
+ if (!srcNatIp.isPresent()) {
+ log.trace("VM {} has no external connection", reqHost.get());
+ return;
+ }
- sendRequestPacketToExt(ipPacket, icmp, deviceId, pNatIpAddress);
-
+ sendRequestToExternal(ipPacket, srcDevice, srcNatIp.get());
+ String icmpInfoKey = String.valueOf(icmpId)
+ .concat(String.valueOf(srcNatIp.get().toInt()))
+ .concat(String.valueOf(ipPacket.getDestinationAddress()));
+ icmpInfoMap.putIfAbsent(icmpInfoKey, reqHost.get());
+ }
+ break;
+ case ICMP.TYPE_ECHO_REPLY:
String icmpInfoKey = String.valueOf(icmpId)
- .concat(String.valueOf(pNatIpAddress.toInt()))
- .concat(String.valueOf(ipPacket.getDestinationAddress()));
- icmpInfoMap.putIfAbsent(icmpInfoKey, host.get());
- }
- } else if (icmp.getIcmpType() == ICMP.TYPE_ECHO_REPLY) {
- String icmpInfoKey = String.valueOf(icmpId)
- .concat(String.valueOf(ipPacket.getDestinationAddress()))
- .concat(String.valueOf(ipPacket.getSourceAddress()));
+ .concat(String.valueOf(ipPacket.getDestinationAddress()))
+ .concat(String.valueOf(ipPacket.getSourceAddress()));
- processResponsePacketFromExternalToHost(ipPacket, icmp, icmpInfoMap.get(icmpInfoKey));
-
- icmpInfoMap.remove(icmpInfoKey);
+ processReplyFromExternal(ipPacket, icmpInfoMap.get(icmpInfoKey));
+ icmpInfoMap.remove(icmpInfoKey);
+ break;
+ default:
+ break;
}
}
- private void processIcmpPacketSentToExtenal(IPv4 icmpRequestIpv4, ICMP icmpRequest,
- int destAddr, MacAddress destMac,
- DeviceId deviceId, PortNumber portNumber) {
- icmpRequest.setChecksum((short) 0);
- icmpRequest.setIcmpType(ICMP.TYPE_ECHO_REPLY).resetChecksum();
- icmpRequestIpv4.setSourceAddress(icmpRequestIpv4.getDestinationAddress())
- .setDestinationAddress(destAddr).resetChecksum();
- icmpRequestIpv4.setPayload(icmpRequest);
- Ethernet icmpResponseEth = new Ethernet();
- icmpResponseEth.setEtherType(Ethernet.TYPE_IPV4)
- // TODO: Get the correct GW MAC
- .setSourceMACAddress(Constants.GW_EXT_INT_MAC)
- .setDestinationMACAddress(destMac).setPayload(icmpRequestIpv4);
- TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(portNumber).build();
- OutboundPacket packet = new DefaultOutboundPacket(deviceId,
- treatment, ByteBuffer.wrap(icmpResponseEth.serialize()));
- packetService.emit(packet);
+ // TODO do we have to handle the request to the fake gateway?
+ private void processRequestToGateway(IPv4 ipPacket, Host reqHost) {
+ ICMP icmpReq = (ICMP) ipPacket.getPayload();
+ icmpReq.setChecksum((short) 0);
+ icmpReq.setIcmpType(ICMP.TYPE_ECHO_REPLY).resetChecksum();
+
+ ipPacket.setSourceAddress(ipPacket.getDestinationAddress())
+ .setDestinationAddress(ipPacket.getSourceAddress())
+ .resetChecksum();
+
+ ipPacket.setPayload(icmpReq);
+ Ethernet icmpReply = new Ethernet();
+ icmpReply.setEtherType(Ethernet.TYPE_IPV4)
+ .setSourceMACAddress(Constants.DEFAULT_GATEWAY_MAC)
+ .setDestinationMACAddress(reqHost.mac())
+ .setPayload(icmpReq);
+
+ sendReply(icmpReply, reqHost);
}
- private void processIcmpPacketSentToGateway(IPv4 icmpRequestIpv4, ICMP icmpRequest,
- Host host) {
- icmpRequest.setChecksum((short) 0);
- icmpRequest.setIcmpType(ICMP.TYPE_ECHO_REPLY)
- .resetChecksum();
-
- Ip4Address ipAddress = host.ipAddresses().stream().findAny().get().getIp4Address();
- icmpRequestIpv4.setSourceAddress(icmpRequestIpv4.getDestinationAddress())
- .setDestinationAddress(ipAddress.toInt())
- .resetChecksum();
-
- icmpRequestIpv4.setPayload(icmpRequest);
-
- Ethernet icmpResponseEth = new Ethernet();
-
- icmpResponseEth.setEtherType(Ethernet.TYPE_IPV4)
- .setSourceMACAddress(Constants.GATEWAY_MAC)
- .setDestinationMACAddress(host.mac())
- .setPayload(icmpRequestIpv4);
-
- sendResponsePacketToHost(icmpResponseEth, host);
- }
-
- private void sendRequestPacketToExt(IPv4 icmpRequestIpv4, ICMP icmpRequest, DeviceId deviceId,
- Ip4Address pNatIpAddress) {
- icmpRequest.resetChecksum();
- icmpRequestIpv4.setSourceAddress(pNatIpAddress.toInt())
- .resetChecksum();
- icmpRequestIpv4.setPayload(icmpRequest);
+ private void sendRequestToExternal(IPv4 ipPacket, DeviceId srcDevice, Ip4Address srcNatIp) {
+ ICMP icmpReq = (ICMP) ipPacket.getPayload();
+ icmpReq.resetChecksum();
+ ipPacket.setSourceAddress(srcNatIp.toInt()).resetChecksum();
+ ipPacket.setPayload(icmpReq);
Ethernet icmpRequestEth = new Ethernet();
-
icmpRequestEth.setEtherType(Ethernet.TYPE_IPV4)
- // TODO: Get the correct one - Scalable Gateway ...
- .setSourceMACAddress(Constants.GW_EXT_INT_MAC)
- .setDestinationMACAddress(Constants.PHY_ROUTER_MAC)
- .setPayload(icmpRequestIpv4);
-
- // TODO: Return the correct gateway node
- Optional<OpenstackNode> gwNode = nodeService.nodes().stream()
- .filter(n -> n.type().equals(OpenstackNodeService.NodeType.GATEWAY))
- .findFirst();
-
- if (!gwNode.isPresent()) {
- log.warn("No Gateway is defined.");
- return;
- }
+ .setSourceMACAddress(DEFAULT_GATEWAY_MAC)
+ .setDestinationMACAddress(DEFAULT_EXTERNAL_ROUTER_MAC)
+ .setPayload(ipPacket);
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
- // FIXME: please double check this.
- .setOutput(getPortForAnnotationPortName(gwNode.get().intBridge(),
- // FIXME: please double check this.
- org.onosproject.openstacknode.Constants.PATCH_INTG_BRIDGE))
+ .setOutput(gatewayService.getUplinkPort(srcDevice))
.build();
- OutboundPacket packet = new DefaultOutboundPacket(deviceId,
- treatment, ByteBuffer.wrap(icmpRequestEth.serialize()));
+ OutboundPacket packet = new DefaultOutboundPacket(
+ srcDevice,
+ treatment,
+ ByteBuffer.wrap(icmpRequestEth.serialize()));
packetService.emit(packet);
}
- private void processResponsePacketFromExternalToHost(IPv4 icmpResponseIpv4, ICMP icmpResponse,
- Host host) {
- icmpResponse.resetChecksum();
+ private void processReplyFromExternal(IPv4 ipPacket, Host dstHost) {
+ ICMP icmpReply = (ICMP) ipPacket.getPayload();
+ icmpReply.resetChecksum();
- Ip4Address ipAddress = host.ipAddresses().stream().findFirst().get().getIp4Address();
- icmpResponseIpv4.setDestinationAddress(ipAddress.toInt())
+ Ip4Address ipAddress = dstHost.ipAddresses().stream().findFirst().get().getIp4Address();
+ ipPacket.setDestinationAddress(ipAddress.toInt())
.resetChecksum();
- icmpResponseIpv4.setPayload(icmpResponse);
+ ipPacket.setPayload(icmpReply);
Ethernet icmpResponseEth = new Ethernet();
-
icmpResponseEth.setEtherType(Ethernet.TYPE_IPV4)
- .setSourceMACAddress(Constants.GATEWAY_MAC)
- .setDestinationMACAddress(host.mac())
- .setPayload(icmpResponseIpv4);
+ .setSourceMACAddress(Constants.DEFAULT_GATEWAY_MAC)
+ .setDestinationMACAddress(dstHost.mac())
+ .setPayload(ipPacket);
- sendResponsePacketToHost(icmpResponseEth, host);
+ sendReply(icmpResponseEth, dstHost);
}
- private void sendResponsePacketToHost(Ethernet icmpResponseEth, Host host) {
-
+ private void sendReply(Ethernet icmpReply, Host dstHost) {
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
- .setOutput(host.location().port())
+ .setOutput(dstHost.location().port())
.build();
- OutboundPacket packet = new DefaultOutboundPacket(host.location().deviceId(),
- treatment, ByteBuffer.wrap(icmpResponseEth.serialize()));
+ OutboundPacket packet = new DefaultOutboundPacket(
+ dstHost.location().deviceId(),
+ treatment,
+ ByteBuffer.wrap(icmpReply.serialize()));
packetService.emit(packet);
}
+ private Optional<Ip4Address> getSrcNatIp(Host host) {
+ // TODO cache external gateway IP for each network because
+ // asking Neutron for every ICMP request is a bad idea
+ Optional<OpenstackPort> osPort = openstackService.ports().stream()
+ .filter(port -> port.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE) &&
+ Objects.equals(host.annotations().value(NETWORK_ID),
+ port.networkId()))
+ .findAny();
+ if (!osPort.isPresent()) {
+ return Optional.empty();
+ }
+
+ OpenstackRouter osRouter = openstackService.router(osPort.get().deviceId());
+ if (osRouter == null) {
+ return Optional.empty();
+ }
+
+ return osRouter.gatewayExternalInfo().externalFixedIps()
+ .values().stream().findAny();
+ }
+
private short getIcmpId(ICMP icmp) {
return ByteBuffer.wrap(icmp.serialize(), 4, 2).getShort();
}
- private Ip4Address pNatIpForPort(Host host) {
+ private class InternalPacketProcessor implements PacketProcessor {
- OpenstackPort openstackPort = openstackService.ports().stream()
- .filter(p -> p.deviceOwner().equals(NETWORK_ROUTER_INTERFACE) &&
- p.networkId().equals(host.annotations().value(Constants.NETWORK_ID)))
- .findAny().orElse(null);
+ @Override
+ public void process(PacketContext context) {
+ if (context.isHandled()) {
+ return;
+ } else if (!gatewayService.getGatewayDeviceIds().contains(
+ context.inPacket().receivedFrom().deviceId())) {
+ // return if the packet is not from gateway nodes
+ return;
+ }
- checkNotNull(openstackPort, "openstackPort can not be null");
+ InboundPacket pkt = context.inPacket();
+ Ethernet ethernet = pkt.parsed();
+ if (ethernet == null || ethernet.getEtherType() == Ethernet.TYPE_ARP) {
+ return;
+ }
- return openstackService.router(openstackPort.deviceId())
- .gatewayExternalInfo().externalFixedIps().values()
- .stream().findAny().orElse(null);
- }
-
- private PortNumber getPortForAnnotationPortName(DeviceId deviceId, String match) {
- Port port = deviceService.getPorts(deviceId).stream()
- .filter(p -> p.annotations().value(PORTNAME).equals(match))
- .findAny().orElse(null);
-
- checkNotNull(port, "port cannot be null");
-
- return port.number();
- }
-
- private boolean requestToOpenstackRoutingNetwork(int destAddr) {
- OpenstackPort port = openstackService.ports().stream()
- .filter(p -> p.deviceOwner().equals(NETWORK_ROUTER_GATEWAY) ||
- p.deviceOwner().equals(NETWORK_FLOATING_IP))
- .filter(p -> p.fixedIps().containsValue(
- Ip4Address.valueOf(destAddr)))
- .findAny().orElse(null);
- if (port == null) {
- return false;
+ IPv4 iPacket = (IPv4) ethernet.getPayload();
+ if (iPacket.getProtocol() == IPv4.PROTOCOL_ICMP) {
+ eventExecutor.execute(() -> processIcmpPacket(context, ethernet));
+ }
}
- return true;
}
- private Map<DeviceId, PortNumber> getExternalInfo() {
- Map<DeviceId, PortNumber> externalInfoMap = Maps.newHashMap();
- gatewayService.getGatewayDeviceIds().forEach(deviceId ->
- externalInfoMap.putIfAbsent(deviceId, gatewayService.getUplinkPort(deviceId)));
- return externalInfoMap;
+
+ private class InternalNodeListener implements OpenstackNodeListener {
+
+ @Override
+ public void event(OpenstackNodeEvent event) {
+ OpenstackNode node = event.node();
+
+ switch (event.type()) {
+ case COMPLETE:
+ if (node.type() == GATEWAY) {
+ log.info("GATEWAY node {} detected", node.hostname());
+ eventExecutor.execute(() -> requestPacket(appId));
+ }
+ break;
+ case INIT:
+ case DEVICE_CREATED:
+ case INCOMPLETE:
+ default:
+ break;
+ }
+ }
}
}
diff --git a/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackPnatHandler.java b/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackPnatHandler.java
index 5af208d..3b40aee 100644
--- a/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackPnatHandler.java
+++ b/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackPnatHandler.java
@@ -15,109 +15,156 @@
*/
package org.onosproject.openstacknetworking.routing;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IPv4;
import org.onlab.packet.Ip4Address;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.TCP;
+import org.onlab.packet.TpPort;
import org.onlab.packet.UDP;
+import org.onlab.util.KryoNamespace;
+import org.onlab.util.Tools;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
import org.onosproject.net.DeviceId;
-import org.onosproject.net.Port;
+import org.onosproject.net.Host;
+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.flowobjective.DefaultForwardingObjective;
+import org.onosproject.net.flowobjective.FlowObjectiveService;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.net.host.HostService;
import org.onosproject.net.packet.DefaultOutboundPacket;
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.openstackinterface.OpenstackInterfaceService;
import org.onosproject.openstackinterface.OpenstackPort;
import org.onosproject.openstackinterface.OpenstackRouter;
-import org.onosproject.scalablegateway.api.GatewayNode;
+import org.onosproject.openstacknetworking.RulePopulatorUtil;
+import org.onosproject.openstacknode.OpenstackNodeService;
import org.onosproject.scalablegateway.api.ScalableGatewayService;
+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.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.ExecutorService;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.onlab.osgi.DefaultServiceDirectory.getService;
-
+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;
/**
- * Handle NAT packet processing for Managing Flow Rules In Openstack Nodes.
+ * Handle NAT packet processing for managing flow rules in openstack nodes.
*/
-public class OpenstackPnatHandler implements Runnable {
+@Component(immediate = true)
+public class OpenstackPnatHandler {
+ private final Logger log = getLogger(getClass());
- volatile PacketContext context;
- private final Logger log = LoggerFactory.getLogger(getClass());
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
- private final OpenstackRoutingRulePopulator rulePopulator;
- private final int portNum;
- private final OpenstackPort openstackPort;
- private final Port port;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected PacketService packetService;
- private static final String DEVICE_OWNER_ROUTER_INTERFACE = "network:router_interface";
- private static final String EXTERNAL_PORT_NULL = "There is no external port in this deviceId []";
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected HostService hostService;
- OpenstackPnatHandler(OpenstackRoutingRulePopulator rulePopulator, PacketContext context,
- int portNum, OpenstackPort openstackPort, Port port) {
- this.rulePopulator = checkNotNull(rulePopulator);
- this.context = checkNotNull(context);
- this.portNum = checkNotNull(portNum);
- this.openstackPort = checkNotNull(openstackPort);
- this.port = checkNotNull(port);
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected StorageService storageService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected FlowObjectiveService flowObjectiveService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DeviceService deviceService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected OpenstackInterfaceService openstackService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected OpenstackNodeService nodeService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected ScalableGatewayService gatewayService;
+
+ private static final KryoNamespace.Builder NUMBER_SERIALIZER = KryoNamespace.newBuilder()
+ .register(KryoNamespaces.API);
+
+ private static final int PNAT_PORT_EXPIRE_TIME = 1200 * 1000;
+ private static final int TP_PORT_MINIMUM_NUM = 1024;
+ private static final int TP_PORT_MAXIMUM_NUM = 65535;
+
+ private final ExecutorService eventExecutor = newSingleThreadScheduledExecutor(
+ groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
+ private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
+
+ private ConsistentMap<Integer, String> tpPortNumMap;
+ private ApplicationId appId;
+
+ @Activate
+ protected void activate() {
+ appId = coreService.registerApplication(ROUTING_APP_ID);
+ tpPortNumMap = storageService.<Integer, String>consistentMapBuilder()
+ .withSerializer(Serializer.using(NUMBER_SERIALIZER.build()))
+ .withName("openstackrouting-tpportnum")
+ .withApplicationId(appId)
+ .build();
+
+ packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
+ log.info("Started");
}
- @Override
- public void run() {
- InboundPacket inboundPacket = context.inPacket();
- Ethernet ethernet = checkNotNull(inboundPacket.parsed());
+ @Deactivate
+ protected void deactivate() {
+ packetService.removeProcessor(packetProcessor);
+ log.info("Stopped");
+ }
- //TODO: Considers IPV6
- if (ethernet.getEtherType() != Ethernet.TYPE_IPV4) {
- log.warn("Now, we just consider IP version 4");
+ private void processPnatPacket(PacketContext context, Ethernet ethernet) {
+ IPv4 iPacket = (IPv4) ethernet.getPayload();
+ InboundPacket inboundPacket = context.inPacket();
+
+ int srcPort = getPortNum(ethernet.getSourceMAC(), iPacket.getDestinationAddress());
+ OpenstackPort osPort = getOpenstackPort(ethernet.getSourceMAC());
+ if (osPort == null) {
+ return;
+ }
+ Ip4Address externalGatewayIp = getExternalGatewayIp(osPort);
+ if (externalGatewayIp == null) {
return;
}
- OpenstackRouter router = getOpenstackRouter(openstackPort);
+ populatePnatFlowRules(context.inPacket(),
+ osPort,
+ TpPort.tpPort(srcPort),
+ externalGatewayIp);
- MacAddress externalMac = MacAddress.NONE;
- MacAddress routerMac = MacAddress.NONE;
-
- rulePopulator.populatePnatFlowRules(inboundPacket, openstackPort, portNum,
- getExternalIp(router), externalMac, routerMac);
-
- packetOut((Ethernet) ethernet.clone(), inboundPacket.receivedFrom().deviceId(), portNum, router);
+ packetOut((Ethernet) ethernet.clone(),
+ inboundPacket.receivedFrom().deviceId(),
+ srcPort,
+ externalGatewayIp);
}
- private OpenstackRouter getOpenstackRouter(OpenstackPort openstackPort) {
- OpenstackInterfaceService networkingService = getService(OpenstackInterfaceService.class);
-
- OpenstackPort port = networkingService.ports()
- .stream()
- .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
- .filter(p -> checkSameSubnet(p, openstackPort))
- .findAny()
- .orElse(null);
-
- return checkNotNull(networkingService.router(port.deviceId()));
- }
-
- private boolean checkSameSubnet(OpenstackPort p, OpenstackPort openstackPort) {
- String key1 = checkNotNull(p.fixedIps().keySet().stream().findFirst().orElse(null)).toString();
- String key2 = checkNotNull(openstackPort.fixedIps().keySet().stream().findFirst().orElse(null)).toString();
- return key1.equals(key2) ? true : false;
- }
-
- private Ip4Address getExternalIp(OpenstackRouter router) {
- return router.gatewayExternalInfo().externalFixedIps().values().stream().findAny().orElse(null);
- }
-
- private void packetOut(Ethernet ethernet, DeviceId deviceId, int portNum, OpenstackRouter router) {
- PacketService packetService = getService(PacketService.class);
-
+ private void packetOut(Ethernet ethernet, DeviceId deviceId, int portNum, Ip4Address externalIp) {
IPv4 iPacket = (IPv4) ethernet.getPayload();
-
TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
switch (iPacket.getProtocol()) {
@@ -136,26 +183,251 @@
iPacket.setPayload(udpPacket);
break;
default:
- log.error("Temporally, this method can process UDP and TCP protocol.");
+ log.trace("Temporally, this method can process UDP and TCP protocol.");
return;
}
- iPacket.setSourceAddress(getExternalIp(router).toString());
+ iPacket.setSourceAddress(externalIp.toString());
iPacket.resetChecksum();
iPacket.setParent(ethernet);
ethernet.setPayload(iPacket);
- ScalableGatewayService gatewayService = getService(ScalableGatewayService.class);
- GatewayNode gatewayNode = gatewayService.getGatewayNode(deviceId);
- if (gatewayNode.getUplinkIntf() == null) {
- log.error(EXTERNAL_PORT_NULL, deviceId.toString());
+ treatment.setOutput(gatewayService.getUplinkPort(deviceId));
+ ethernet.resetChecksum();
+ packetService.emit(new DefaultOutboundPacket(
+ deviceId,
+ treatment.build(),
+ ByteBuffer.wrap(ethernet.serialize())));
+ }
+
+ private int getPortNum(MacAddress sourceMac, int destinationAddress) {
+ int portNum = findUnusedPortNum();
+ if (portNum == 0) {
+ clearPortNumMap();
+ portNum = findUnusedPortNum();
+ }
+ tpPortNumMap.put(portNum, sourceMac.toString().concat(":").concat(String.valueOf(destinationAddress)));
+ return portNum;
+ }
+
+ private int findUnusedPortNum() {
+ for (int i = TP_PORT_MINIMUM_NUM; i < TP_PORT_MAXIMUM_NUM; i++) {
+ if (!tpPortNumMap.containsKey(i)) {
+ return i;
+ }
+ }
+ return 0;
+ }
+
+ private void clearPortNumMap() {
+ tpPortNumMap.entrySet().forEach(e -> {
+ if (System.currentTimeMillis() - e.getValue().creationTime() > PNAT_PORT_EXPIRE_TIME) {
+ tpPortNumMap.remove(e.getKey());
+ }
+ });
+ }
+
+ // TODO there can be multiple routers connected to a particular openstack port
+ // TODO cache router information
+ private Ip4Address getExternalGatewayIp(OpenstackPort osPort) {
+ Optional<OpenstackPort> routerPort = openstackService.ports().stream()
+ .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
+ .filter(p -> checkSameSubnet(p, osPort))
+ .findAny();
+ if (!routerPort.isPresent()) {
+ log.warn("No router is connected to network {}", osPort.networkId());
+ return null;
+ }
+
+ OpenstackRouter osRouter = openstackService.router(routerPort.get().deviceId());
+ if (osRouter == null) {
+ log.warn("Failed to get OpenStack router {}",
+ routerPort.get().deviceId());
+ return null;
+ }
+
+ return osRouter.gatewayExternalInfo().externalFixedIps().values()
+ .stream().findAny().orElse(null);
+ }
+
+ private OpenstackPort getOpenstackPort(MacAddress srcMac) {
+ Optional<Host> host = hostService.getHostsByMac(srcMac).stream()
+ .filter(h -> h.annotations().value(PORT_ID) != null)
+ .findAny();
+ if (!host.isPresent()) {
+ log.warn("Failed to find a host with MAC:{}", srcMac);
+ return null;
+ }
+ return openstackService.port(host.get().annotations().value(PORT_ID));
+ }
+
+ private boolean checkSameSubnet(OpenstackPort osPortA, OpenstackPort osPortB) {
+ return osPortA.fixedIps().keySet().stream()
+ .anyMatch(subnetId -> osPortB.fixedIps().keySet().contains(subnetId));
+ }
+
+ private void populatePnatFlowRules(InboundPacket inboundPacket,
+ OpenstackPort osPort,
+ TpPort patPort,
+ Ip4Address externalIp) {
+ long vni = getVni(osPort.networkId());
+ populatePnatIncomingFlowRules(vni, externalIp, patPort, inboundPacket);
+ populatePnatOutgoingFlowRules(vni, externalIp, patPort, inboundPacket);
+ }
+
+ private long getVni(String netId) {
+ // TODO remove this and use host vxlan annotation if applicable
+ return Long.parseLong(openstackService.network(netId).segmentId());
+ }
+
+ private void populatePnatOutgoingFlowRules(long vni, Ip4Address externalIp, TpPort patPort,
+ InboundPacket inboundPacket) {
+ IPv4 iPacket = (IPv4) inboundPacket.parsed().getPayload();
+
+ TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+ sBuilder.matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPProtocol(iPacket.getProtocol())
+ .matchTunnelId(vni)
+ .matchIPSrc(IpPrefix.valueOf(iPacket.getSourceAddress(), 32))
+ .matchIPDst(IpPrefix.valueOf(iPacket.getDestinationAddress(), 32));
+
+ TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+ switch (iPacket.getProtocol()) {
+ case IPv4.PROTOCOL_TCP:
+ TCP tcpPacket = (TCP) iPacket.getPayload();
+ sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getSourcePort()))
+ .matchTcpDst(TpPort.tpPort(tcpPacket.getDestinationPort()));
+ tBuilder.setTcpSrc(patPort)
+ .setEthDst(DEFAULT_EXTERNAL_ROUTER_MAC);
+ break;
+ case IPv4.PROTOCOL_UDP:
+ UDP udpPacket = (UDP) iPacket.getPayload();
+ sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getSourcePort()))
+ .matchUdpDst(TpPort.tpPort(udpPacket.getDestinationPort()));
+ tBuilder.setUdpSrc(patPort)
+ .setEthDst(DEFAULT_EXTERNAL_ROUTER_MAC);
+
+ break;
+ default:
+ log.debug("Unsupported IPv4 protocol {}");
+ break;
+ }
+
+ tBuilder.setIpSrc(externalIp);
+ gatewayService.getGatewayNodes().stream().forEach(gateway -> {
+ TrafficTreatment.Builder tmpBuilder = tBuilder;
+ tmpBuilder.setOutput(gatewayService.getUplinkPort(gateway.getGatewayDeviceId()));
+ ForwardingObjective fo = DefaultForwardingObjective.builder()
+ .withSelector(sBuilder.build())
+ .withTreatment(tmpBuilder.build())
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(PNAT_RULE_PRIORITY)
+ .makeTemporary(PNAT_TIMEOUT)
+ .fromApp(appId)
+ .add();
+
+ flowObjectiveService.forward(gateway.getGatewayDeviceId(), fo);
+ });
+ }
+
+ private void populatePnatIncomingFlowRules(long vni, Ip4Address externalIp, TpPort patPort,
+ InboundPacket inboundPacket) {
+ IPv4 iPacket = (IPv4) inboundPacket.parsed().getPayload();
+ IpAddress internalIp = IpAddress.valueOf(iPacket.getSourceAddress());
+
+ TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+ sBuilder.matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPProtocol(iPacket.getProtocol())
+ .matchIPDst(IpPrefix.valueOf(externalIp, 32))
+ .matchIPSrc(IpPrefix.valueOf(iPacket.getDestinationAddress(), 32));
+
+ TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+ tBuilder.setTunnelId(vni)
+ .setEthDst(inboundPacket.parsed().getSourceMAC())
+ .setIpDst(internalIp);
+
+ switch (iPacket.getProtocol()) {
+ case IPv4.PROTOCOL_TCP:
+ TCP tcpPacket = (TCP) iPacket.getPayload();
+ sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getDestinationPort()))
+ .matchTcpDst(patPort);
+ tBuilder.setTcpDst(TpPort.tpPort(tcpPacket.getSourcePort()));
+ break;
+ case IPv4.PROTOCOL_UDP:
+ UDP udpPacket = (UDP) iPacket.getPayload();
+ sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getDestinationPort()))
+ .matchUdpDst(patPort);
+ tBuilder.setUdpDst(TpPort.tpPort(udpPacket.getSourcePort()));
+ break;
+ default:
+ break;
+ }
+
+ Optional<Host> srcVm = Tools.stream(hostService.getHostsByIp(internalIp))
+ .filter(host -> Objects.equals(
+ host.annotations().value(VXLAN_ID),
+ String.valueOf(vni)))
+ .findFirst();
+ if (!srcVm.isPresent()) {
+ log.warn("Failed to find source VM with IP {}", internalIp);
return;
}
- treatment.setOutput(gatewayService.getUplinkPort(deviceId));
- ethernet.resetChecksum();
+ gatewayService.getGatewayDeviceIds().stream().forEach(deviceId -> {
+ DeviceId srcDeviceId = srcVm.get().location().deviceId();
+ TrafficTreatment.Builder tmpBuilder = tBuilder;
+ tmpBuilder.extension(RulePopulatorUtil.buildExtension(
+ deviceService,
+ deviceId,
+ nodeService.dataIp(srcDeviceId).get().getIp4Address()), deviceId)
+ .setOutput(nodeService.tunnelPort(deviceId).get());
- packetService.emit(new DefaultOutboundPacket(deviceId, treatment.build(),
- ByteBuffer.wrap(ethernet.serialize())));
+ ForwardingObjective fo = DefaultForwardingObjective.builder()
+ .withSelector(sBuilder.build())
+ .withTreatment(tmpBuilder.build())
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(PNAT_RULE_PRIORITY)
+ .makeTemporary(PNAT_TIMEOUT)
+ .fromApp(appId)
+ .add();
+
+ flowObjectiveService.forward(deviceId, fo);
+ });
+ }
+
+ private class InternalPacketProcessor implements PacketProcessor {
+
+ @Override
+ public void process(PacketContext context) {
+ if (context.isHandled()) {
+ return;
+ } else if (!gatewayService.getGatewayDeviceIds().contains(
+ context.inPacket().receivedFrom().deviceId())) {
+ // return if the packet is not from gateway nodes
+ return;
+ }
+
+ InboundPacket pkt = context.inPacket();
+ Ethernet ethernet = pkt.parsed();
+ if (ethernet == null || ethernet.getEtherType() == Ethernet.TYPE_ARP) {
+ return;
+ }
+
+ IPv4 iPacket = (IPv4) ethernet.getPayload();
+ switch (iPacket.getProtocol()) {
+ case IPv4.PROTOCOL_ICMP:
+ break;
+ case IPv4.PROTOCOL_UDP:
+ UDP udpPacket = (UDP) iPacket.getPayload();
+ if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
+ udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
+ // don't process DHCP
+ break;
+ }
+ default:
+ eventExecutor.execute(() -> processPnatPacket(context, ethernet));
+ break;
+ }
+ }
}
}
\ No newline at end of file
diff --git a/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingArpHandler.java b/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingArpHandler.java
index 2c9a304..e31f410 100644
--- a/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingArpHandler.java
+++ b/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingArpHandler.java
@@ -15,99 +15,74 @@
*/
package org.onosproject.openstacknetworking.routing;
-import com.google.common.collect.Lists;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.packet.ARP;
-import org.onlab.packet.EthType;
import org.onlab.packet.Ethernet;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.net.DeviceId;
-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.packet.DefaultOutboundPacket;
+import org.onosproject.net.packet.InboundPacket;
import org.onosproject.net.packet.PacketContext;
-import org.onosproject.net.packet.PacketPriority;
+import org.onosproject.net.packet.PacketProcessor;
import org.onosproject.net.packet.PacketService;
import org.onosproject.openstackinterface.OpenstackInterfaceService;
import org.onosproject.openstackinterface.OpenstackPort;
import org.onosproject.scalablegateway.api.ScalableGatewayService;
import org.onosproject.openstacknetworking.Constants;
-import org.onosproject.openstacknode.OpenstackNodeService;
import org.slf4j.Logger;
import java.nio.ByteBuffer;
-import java.util.List;
-import java.util.Optional;
+import java.util.concurrent.ExecutorService;
-import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.concurrent.Executors.newSingleThreadExecutor;
+import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.openstacknetworking.Constants.DEVICE_OWNER_FLOATING_IP;
+import static org.onosproject.openstacknetworking.Constants.DEVICE_OWNER_ROUTER_GATEWAY;
import static org.slf4j.LoggerFactory.getLogger;
/**
- * Handle ARP packet sent from Openstack Gateway nodes.
+ * Handle ARP, ICMP and NAT packets from gateway nodes.
*/
+@Component(immediate = true)
public class OpenstackRoutingArpHandler {
- protected final Logger log = getLogger(getClass());
+ private final Logger log = getLogger(getClass());
- private final PacketService packetService;
- private final OpenstackInterfaceService openstackService;
- private final ScalableGatewayService gatewayService;
- private final OpenstackNodeService nodeService;
- private static final String NETWORK_ROUTER_GATEWAY = "network:router_gateway";
- private static final String NETWORK_FLOATING_IP = "network:floatingip";
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected PacketService packetService;
- /**
- * Default constructor.
- *
- * @param packetService packet service
- * @param openstackService openstackInterface service
- * @param gatewayService gateway service
- * @param nodeService openstackNodeService
- */
- OpenstackRoutingArpHandler(PacketService packetService, OpenstackInterfaceService openstackService,
- OpenstackNodeService nodeService, ScalableGatewayService gatewayService) {
- this.packetService = packetService;
- this.openstackService = checkNotNull(openstackService);
- this.nodeService = nodeService;
- this.gatewayService = gatewayService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected OpenstackInterfaceService openstackService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected ScalableGatewayService gatewayService;
+
+ private final ExecutorService executorService =
+ newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "packet-event", log));
+
+ private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
+
+ @Activate
+ protected void activate() {
+ packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
+ log.info("Started");
}
- /**
- * Requests ARP packet to GatewayNode.
- *
- * @param appId application id
- */
- public void requestPacket(ApplicationId appId) {
-
- TrafficSelector arpSelector = DefaultTrafficSelector.builder()
- .matchEthType(EthType.EtherType.ARP.ethType().toShort())
- .build();
-
- getExternalInfo().forEach(deviceId ->
- packetService.requestPackets(arpSelector,
- PacketPriority.CONTROL,
- appId,
- Optional.of(deviceId))
- );
+ @Deactivate
+ protected void deactivate() {
+ packetService.removeProcessor(packetProcessor);
+ log.info("Stopped");
}
- /**
- * Handles ARP packet.
- *
- * @param context packet context
- * @param ethernet ethernet
- */
- public void processArpPacketFromRouter(PacketContext context, Ethernet ethernet) {
- checkNotNull(context, "context can not be null");
- checkNotNull(ethernet, "ethernet can not be null");
-
-
+ private void processArpPacket(PacketContext context, Ethernet ethernet) {
ARP arp = (ARP) ethernet.getPayload();
-
- log.debug("arpEvent called from {} to {}",
+ log.trace("arpEvent called from {} to {}",
Ip4Address.valueOf(arp.getSenderProtocolAddress()).toString(),
Ip4Address.valueOf(arp.getTargetProtocolAddress()).toString());
@@ -116,13 +91,11 @@
}
IpAddress targetIp = Ip4Address.valueOf(arp.getTargetProtocolAddress());
-
if (getTargetMacForTargetIp(targetIp.getIp4Address()) == MacAddress.NONE) {
- return;
+ return;
}
- // FIXME: Set the correct gateway
- MacAddress targetMac = Constants.GW_EXT_INT_MAC;
+ MacAddress targetMac = Constants.DEFAULT_EXTERNAL_ROUTER_MAC;
Ethernet ethReply = ARP.buildArpReply(targetIp.getIp4Address(),
targetMac, ethernet);
@@ -136,22 +109,35 @@
ByteBuffer.wrap(ethReply.serialize())));
}
+ private class InternalPacketProcessor implements PacketProcessor {
+
+ @Override
+ public void process(PacketContext context) {
+ if (context.isHandled()) {
+ return;
+ } else if (!gatewayService.getGatewayDeviceIds().contains(
+ context.inPacket().receivedFrom().deviceId())) {
+ // return if the packet is not from gateway nodes
+ return;
+ }
+
+ InboundPacket pkt = context.inPacket();
+ Ethernet ethernet = pkt.parsed();
+ if (ethernet != null &&
+ ethernet.getEtherType() == Ethernet.TYPE_ARP) {
+ executorService.execute(() -> processArpPacket(context, ethernet));
+ }
+ }
+ }
+
+ // TODO make a cache for the MAC, not a good idea to REST call every time it gets ARP request
private MacAddress getTargetMacForTargetIp(Ip4Address targetIp) {
OpenstackPort port = openstackService.ports().stream()
- .filter(p -> p.deviceOwner().equals(NETWORK_ROUTER_GATEWAY) ||
- p.deviceOwner().equals(NETWORK_FLOATING_IP))
+ .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_GATEWAY) ||
+ p.deviceOwner().equals(DEVICE_OWNER_FLOATING_IP))
.filter(p -> p.fixedIps().containsValue(targetIp.getIp4Address()))
.findAny().orElse(null);
- if (port == null) {
- return MacAddress.NONE;
- }
- return port.macAddress();
- }
-
- private List<DeviceId> getExternalInfo() {
- List<DeviceId> externalInfoList = Lists.newArrayList();
- gatewayService.getGatewayDeviceIds().forEach(externalInfoList::add);
- return externalInfoList;
+ return port == null ? MacAddress.NONE : port.macAddress();
}
}
diff --git a/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingManager.java b/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingManager.java
index 9f19a28..09b4b8a 100644
--- a/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingManager.java
+++ b/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingManager.java
@@ -15,8 +15,7 @@
*/
package org.onosproject.openstacknetworking.routing;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
+import com.google.common.collect.ImmutableSet;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
@@ -24,82 +23,62 @@
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
import org.onlab.packet.Ethernet;
-import org.onlab.packet.IPv4;
import org.onlab.packet.Ip4Address;
-import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
-import org.onlab.packet.UDP;
-import org.onlab.util.KryoNamespace;
+import org.onlab.util.Tools;
import org.onosproject.core.ApplicationId;
-import org.onosproject.core.CoreService;
-import org.onosproject.mastership.MastershipService;
-import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.core.GroupId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Host;
-import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.driver.DriverService;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flowobjective.DefaultForwardingObjective;
import org.onosproject.net.flowobjective.FlowObjectiveService;
-import org.onosproject.net.host.DefaultHostDescription;
-import org.onosproject.net.host.HostDescription;
-import org.onosproject.net.host.HostEvent;
-import org.onosproject.net.host.HostListener;
-import org.onosproject.net.host.HostProvider;
-import org.onosproject.net.host.HostProviderRegistry;
-import org.onosproject.net.host.HostProviderService;
-import org.onosproject.net.host.HostService;
-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.provider.AbstractProvider;
-import org.onosproject.net.provider.ProviderId;
-import org.onosproject.openstackinterface.OpenstackFloatingIP;
+import org.onosproject.net.flowobjective.ForwardingObjective;
import org.onosproject.openstackinterface.OpenstackInterfaceService;
+import org.onosproject.openstackinterface.OpenstackNetwork;
import org.onosproject.openstackinterface.OpenstackPort;
import org.onosproject.openstackinterface.OpenstackRouter;
import org.onosproject.openstackinterface.OpenstackRouterInterface;
-import org.onosproject.openstacknetworking.OpenstackRoutingService;
-import org.onosproject.scalablegateway.api.ScalableGatewayService;
-import org.onosproject.openstacknetworking.routing.OpenstackFloatingIPHandler.Action;
+import org.onosproject.openstackinterface.OpenstackSubnet;
+import org.onosproject.openstacknetworking.AbstractVmHandler;
import org.onosproject.openstacknetworking.Constants;
+import org.onosproject.openstacknetworking.OpenstackRoutingService;
+import org.onosproject.openstacknetworking.RulePopulatorUtil;
import org.onosproject.openstacknode.OpenstackNode;
import org.onosproject.openstacknode.OpenstackNodeEvent;
import org.onosproject.openstacknode.OpenstackNodeListener;
import org.onosproject.openstacknode.OpenstackNodeService;
-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.scalablegateway.api.GatewayNode;
+import org.onosproject.scalablegateway.api.ScalableGatewayService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.Collection;
-import java.util.List;
+import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
import java.util.stream.Collectors;
-import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
import static org.onlab.util.Tools.groupedThreads;
-import static org.onosproject.net.AnnotationKeys.PORT_NAME;
+import static org.onosproject.openstacknetworking.Constants.*;
+import static org.onosproject.openstacknetworking.RulePopulatorUtil.buildExtension;
+import static org.onosproject.openstacknode.OpenstackNodeService.NodeType.COMPUTE;
+import static org.onosproject.openstacknode.OpenstackNodeService.NodeType.GATEWAY;
@Component(immediate = true)
@Service
-/**
- * Populates flow rules about L3 functionality for VMs in Openstack.
- */
-public class OpenstackRoutingManager implements OpenstackRoutingService {
+public class OpenstackRoutingManager extends AbstractVmHandler implements OpenstackRoutingService {
private final Logger log = LoggerFactory.getLogger(getClass());
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected CoreService coreService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected PacketService packetService;
+ protected FlowObjectiveService flowObjectiveService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceService deviceService;
@@ -108,620 +87,392 @@
protected OpenstackInterfaceService openstackService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected FlowObjectiveService flowObjectiveService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected DriverService driverService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected StorageService storageService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected HostService hostService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected HostProviderRegistry hostProviderRegistry;
+ protected OpenstackNodeService nodeService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected ScalableGatewayService gatewayService;
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected OpenstackNodeService nodeService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected MastershipService mastershipService;
+ private final ExecutorService eventExecutor = newSingleThreadScheduledExecutor(
+ groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
+ private final InternalNodeListener nodeListener = new InternalNodeListener();
private ApplicationId appId;
- private ConsistentMap<Integer, String> tpPortNumMap; // Map<PortNum, allocated VM`s Mac & destionation Ip address>
- private ConsistentMap<String, OpenstackFloatingIP> floatingIpMap; // Map<FloatingIp`s Id, FloatingIp object>
- // Map<RouterInterface`s portId, Corresponded port`s network id>
- private ConsistentMap<String, String> routerInterfaceMap;
- private static final ProviderId PID = new ProviderId("of", "org.onosproject.openstackroutering", true);
- private static final String APP_ID = "org.onosproject.openstackrouting";
- private static final String DEVICE_OWNER_ROUTER_INTERFACE = "network:router_interface";
- private static final String FLOATING_IP_MAP_NAME = "openstackrouting-floatingip";
- private static final String TP_PORT_MAP_NAME = "openstackrouting-tpportnum";
- private static final String ROUTER_INTERFACE_MAP_NAME = "openstackrouting-routerinterface";
- private static final String COLON = ":";
- private static final int PNAT_PORT_EXPIRE_TIME = 1200 * 1000;
- private static final int TP_PORT_MINIMUM_NUM = 1024;
- private static final int TP_PORT_MAXIMUM_NUM = 65535;
-
- private static final KryoNamespace.Builder FLOATING_IP_SERIALIZER = KryoNamespace.newBuilder()
- .register(KryoNamespaces.API)
- .register(OpenstackFloatingIP.FloatingIpStatus.class)
- .register(OpenstackFloatingIP.class);
-
- private static final KryoNamespace.Builder NUMBER_SERIALIZER = KryoNamespace.newBuilder()
- .register(KryoNamespaces.API);
-
- private static final KryoNamespace.Builder ROUTER_INTERFACE_SERIALIZER = KryoNamespace.newBuilder()
- .register(KryoNamespaces.API);
-
- private InternalPacketProcessor internalPacketProcessor = new InternalPacketProcessor();
- private InternalHostListener internalHostListener = new InternalHostListener();
- private InternalOpenstackNodeListener internalNodeListener = new InternalOpenstackNodeListener();
- private ExecutorService l3EventExecutorService =
- Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "L3-event"));
- private ExecutorService icmpEventExecutorService =
- Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "icmp-event"));
- private ExecutorService arpEventExecutorService =
- Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "arp-event"));
- private OpenstackIcmpHandler openstackIcmpHandler;
- private OpenstackRoutingArpHandler openstackArpHandler;
- private OpenstackRoutingRulePopulator rulePopulator;
-
- private HostProviderService hostProviderService;
- private final HostProvider hostProvider = new InternalHostProvider();
@Activate
protected void activate() {
- appId = coreService.registerApplication(APP_ID);
- hostService.addListener(internalHostListener);
- nodeService.addListener(internalNodeListener);
- hostProviderService = hostProviderRegistry.register(hostProvider);
-
- floatingIpMap = storageService.<String, OpenstackFloatingIP>consistentMapBuilder()
- .withSerializer(Serializer.using(FLOATING_IP_SERIALIZER.build()))
- .withName(FLOATING_IP_MAP_NAME)
- .withApplicationId(appId)
- .build();
- tpPortNumMap = storageService.<Integer, String>consistentMapBuilder()
- .withSerializer(Serializer.using(NUMBER_SERIALIZER.build()))
- .withName(TP_PORT_MAP_NAME)
- .withApplicationId(appId)
- .build();
- routerInterfaceMap = storageService.<String, String>consistentMapBuilder()
- .withSerializer(Serializer.using(ROUTER_INTERFACE_SERIALIZER.build()))
- .withName(ROUTER_INTERFACE_MAP_NAME)
- .withApplicationId(appId)
- .build();
-
- log.info("started");
+ super.activate();
+ appId = coreService.registerApplication(ROUTING_APP_ID);
+ nodeService.addListener(nodeListener);
}
@Deactivate
protected void deactivate() {
- packetService.removeProcessor(internalPacketProcessor);
- hostService.removeListener(internalHostListener);
- nodeService.removeListener(internalNodeListener);
-
- l3EventExecutorService.shutdown();
- icmpEventExecutorService.shutdown();
- arpEventExecutorService.shutdown();
-
- floatingIpMap.clear();
- tpPortNumMap.clear();
- routerInterfaceMap.clear();
-
+ nodeService.removeListener(nodeListener);
log.info("stopped");
}
-
@Override
- public void createFloatingIP(OpenstackFloatingIP openstackFloatingIp) {
- floatingIpMap.put(openstackFloatingIp.id(), openstackFloatingIp);
+ public void createRouter(OpenstackRouter osRouter) {
}
@Override
- public void updateFloatingIP(OpenstackFloatingIP openstackFloatingIp) {
- if (!floatingIpMap.containsKey(openstackFloatingIp.id())) {
- log.warn("There`s no information about {} in FloatingIpMap", openstackFloatingIp.id());
+ public void updateRouter(OpenstackRouter osRouter) {
+ if (osRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
+ openstackService.ports().stream()
+ .filter(osPort -> osPort.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE) &&
+ osPort.deviceId().equals(osRouter.id()))
+ .forEach(osPort -> setExternalConnection(osRouter, osPort.networkId()));
+
+ log.info("Connected external gateway {} to router {}",
+ osRouter.gatewayExternalInfo().externalFixedIps(),
+ osRouter.name());
+ } else {
+ openstackService.ports().stream()
+ .filter(osPort -> osPort.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE) &&
+ osPort.deviceId().equals(osRouter.id()))
+ .forEach(osPort -> unsetExternalConnection(osRouter, osPort.networkId()));
+
+ log.info("Disconnected external gateway from router {}",
+ osRouter.name());
+ }
+ }
+
+ @Override
+ public void removeRouter(String osRouterId) {
+ // TODO implement this
+ }
+
+ @Override
+ public void addRouterInterface(OpenstackRouterInterface routerIface) {
+ OpenstackRouter osRouter = openstackRouter(routerIface.id());
+ OpenstackPort osPort = openstackService.port(routerIface.portId());
+ if (osRouter == null || osPort == null) {
+ log.warn("Failed to add router interface {}", routerIface);
return;
}
- if (openstackFloatingIp.portId() == null || openstackFloatingIp.portId().equals("null")) {
- OpenstackFloatingIP floatingIp = floatingIpMap.get(openstackFloatingIp.id()).value();
- // XXX When the VM has been removed, host information has been removed or not ???
- Optional<Host> host = hostService.getHostsByIp(openstackFloatingIp.fixedIpAddress().getIp4Address())
- .stream()
- .findFirst();
- if (!host.isPresent()) {
- log.warn("No Host info with the VM IP the Floating IP address {} is found",
- openstackFloatingIp.floatingIpAddress());
- return;
- }
- l3EventExecutorService.execute(
- new OpenstackFloatingIPHandler(rulePopulator, floatingIp, Action.DISSASSOCIATE, host.get()));
- floatingIpMap.replace(floatingIp.id(), openstackFloatingIp);
- registerFloatingIpToHostService(openstackFloatingIp, Action.DISSASSOCIATE);
- } else {
- floatingIpMap.put(openstackFloatingIp.id(), openstackFloatingIp);
- l3EventExecutorService.execute(
- new OpenstackFloatingIPHandler(rulePopulator, openstackFloatingIp, Action.ASSOCIATE, null));
- registerFloatingIpToHostService(openstackFloatingIp, Action.ASSOCIATE);
+
+ setRoutes(osRouter, Optional.empty());
+ if (osRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
+ setExternalConnection(osRouter, osPort.networkId());
}
+ log.info("Connected {} to router {}", osPort.fixedIps(), osRouter.name());
}
@Override
- public void deleteFloatingIP(String id) {
- floatingIpMap.remove(id);
- }
-
- @Override
- public void createRouter(OpenstackRouter openstackRouter) {
- }
-
- @Override
- public void updateRouter(OpenstackRouter openstackRouter) {
- if (openstackRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
- checkExternalConnection(openstackRouter, getOpenstackRouterInterface(openstackRouter));
- } else {
- unsetExternalConnection();
- }
- }
-
- private void unsetExternalConnection() {
- Collection<OpenstackRouter> internalRouters = getExternalRouter(false);
- internalRouters.forEach(r ->
- getOpenstackRouterInterface(r).forEach(i -> rulePopulator.removeExternalRules(i)));
- }
-
- private Collection<OpenstackRouter> getExternalRouter(boolean externalConnection) {
- List<OpenstackRouter> routers;
- if (externalConnection) {
- routers = openstackService.routers()
- .stream()
- .filter(r -> (r.gatewayExternalInfo().externalFixedIps().size() > 0))
- .collect(Collectors.toList());
- } else {
- routers = openstackService.routers()
- .stream()
- .filter(r -> (r.gatewayExternalInfo().externalFixedIps().size() == 0))
- .collect(Collectors.toList());
- }
- return routers;
- }
-
- @Override
- public void deleteRouter(String id) {
- //TODO : In now, there`s nothing to do for deleteRouter process. It is reserved.
- }
-
- @Override
- public void updateRouterInterface(OpenstackRouterInterface routerInterface) {
- List<OpenstackRouterInterface> routerInterfaces = Lists.newArrayList();
- routerInterfaces.add(routerInterface);
- checkExternalConnection(getOpenstackRouter(routerInterface.id()), routerInterfaces);
- setL3Connection(getOpenstackRouter(routerInterface.id()), null);
- routerInterfaceMap.put(routerInterface.portId(), openstackService.port(routerInterface.portId()).networkId());
- }
-
- /**
- * Set flow rules for traffic between two different subnets when more than one subnets
- * connected to a router.
- *
- * @param openstackRouter OpenstackRouter Info
- * @param openstackPort OpenstackPort Info
- */
- private void setL3Connection(OpenstackRouter openstackRouter, OpenstackPort openstackPort) {
- Collection<OpenstackRouterInterface> interfaceList = getOpenstackRouterInterface(openstackRouter);
-
- if (interfaceList.size() < 2) {
+ public void removeRouterInterface(OpenstackRouterInterface routerIface) {
+ OpenstackRouter osRouter = openstackService.router(routerIface.id());
+ if (osRouter == null) {
+ log.warn("Failed to remove router interface {}", routerIface);
return;
}
- if (openstackPort == null) {
- interfaceList.forEach(i -> {
- OpenstackPort interfacePort = openstackService.port(i.portId());
- openstackService.ports()
- .stream()
- .filter(p -> p.networkId().equals(interfacePort.networkId())
- && !p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
- .forEach(p -> rulePopulator.populateL3Rules(p,
- getL3ConnectionList(p.networkId(), interfaceList)));
- });
- } else {
- rulePopulator.populateL3Rules(openstackPort, getL3ConnectionList(openstackPort.networkId(), interfaceList));
+ OpenstackSubnet osSubnet = openstackService.subnet(routerIface.subnetId());
+ OpenstackNetwork osNet = openstackService.network(osSubnet.networkId());
+
+ unsetRoutes(osRouter, osNet);
+ if (osRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
+ unsetExternalConnection(osRouter, osNet.id());
}
-
+ log.info("Disconnected {} from router {}", osSubnet.cidr(), osRouter.name());
}
- private List<OpenstackRouterInterface> getL3ConnectionList(String networkId,
- Collection<OpenstackRouterInterface> interfaceList) {
- List<OpenstackRouterInterface> targetList = Lists.newArrayList();
- interfaceList.forEach(i -> {
- OpenstackPort port = openstackService.port(i.portId());
- if (!port.networkId().equals(networkId)) {
- targetList.add(i);
- }
- });
- return targetList;
- }
-
- @Override
- public void removeRouterInterface(OpenstackRouterInterface routerInterface) {
- OpenstackRouter router = openstackService.router(routerInterface.id());
- Collection<OpenstackRouterInterface> interfaceList = getOpenstackRouterInterface(router);
- if (interfaceList.size() == 1) {
- List<OpenstackRouterInterface> newList = Lists.newArrayList();
- newList.add(routerInterface);
- interfaceList.forEach(i -> removeL3RulesForRouterInterface(i, router, newList));
- }
- removeL3RulesForRouterInterface(routerInterface, router, null);
- rulePopulator.removeExternalRules(routerInterface);
- routerInterfaceMap.remove(routerInterface.portId());
- }
-
- private void removeL3RulesForRouterInterface(OpenstackRouterInterface routerInterface, OpenstackRouter router,
- List<OpenstackRouterInterface> newList) {
- if (!routerInterfaceMap.containsKey(routerInterface.portId())) {
- log.warn("No router interface information found for {}", routerInterface.portId());
+ private void setExternalConnection(OpenstackRouter osRouter, String osNetId) {
+ if (!osRouter.gatewayExternalInfo().isEnablePnat()) {
+ log.debug("Source NAT is disabled");
return;
}
- openstackService.ports(routerInterfaceMap.get(routerInterface.portId()).value()).forEach(p -> {
- Ip4Address vmIp = (Ip4Address) p.fixedIps().values().toArray()[0];
- if (newList == null) {
- rulePopulator.removeL3Rules(vmIp,
- getL3ConnectionList(p.networkId(), getOpenstackRouterInterface(router)));
- } else {
- rulePopulator.removeL3Rules(vmIp, newList);
- }
- }
- );
+
+ // FIXME router interface is subnet specific, not network
+ OpenstackNetwork osNet = openstackService.network(osNetId);
+ populateExternalRules(osNet);
}
- @Override
- public String networkIdForRouterInterface(String portId) {
- return routerInterfaceMap.get(portId).value();
- }
-
- private Collection<OpenstackFloatingIP> associatedFloatingIps() {
- List<OpenstackFloatingIP> fIps = Lists.newArrayList();
- floatingIpMap.values()
- .stream()
- .filter(fIp -> fIp.value().portId() != null)
- .forEach(fIp -> fIps.add(fIp.value()));
- return fIps;
- }
-
- private void reloadInitL3Rules() {
-
- l3EventExecutorService.execute(() ->
- openstackService.ports()
- .stream()
- .forEach(p ->
- {
- if (p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE)) {
- updateRouterInterface(portToRouterInterface(p));
- } else {
- Optional<Ip4Address> vmIp = p.fixedIps().values().stream().findAny();
- if (vmIp.isPresent()) {
- OpenstackFloatingIP floatingIP = getOpenstackFloatingIp(vmIp.get());
- if (floatingIP != null) {
- updateFloatingIP(floatingIP);
- }
- }
- }
- })
- );
- }
-
- private OpenstackRouterInterface portToRouterInterface(OpenstackPort p) {
- OpenstackRouterInterface.Builder osBuilder = new OpenstackRouterInterface.Builder()
- .id(checkNotNull(p.deviceId()))
- .tenantId(checkNotNull(openstackService.network(p.networkId()).tenantId()))
- .subnetId(checkNotNull(p.fixedIps().keySet().stream().findFirst().orElse(null)).toString())
- .portId(checkNotNull(p.id()));
-
- return osBuilder.build();
- }
-
- private class InternalPacketProcessor implements PacketProcessor {
-
- @Override
- public void process(PacketContext context) {
-
- DeviceId senderDeviceId = context.inPacket().receivedFrom().deviceId();
- if (!nodeService.routerBridge(senderDeviceId).isPresent()) {
- log.warn("No router bridge for {} is found.", senderDeviceId);
- return;
- }
- if (context.isHandled()) {
- return;
- } else if (!checkGatewayNode(context.inPacket().receivedFrom().deviceId())) {
- return;
- }
-
- InboundPacket pkt = context.inPacket();
- Ethernet ethernet = pkt.parsed();
-
- //TODO: Considers IPv6 later.
- if (ethernet == null) {
- return;
- } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
- IPv4 iPacket = (IPv4) ethernet.getPayload();
- switch (iPacket.getProtocol()) {
- case IPv4.PROTOCOL_ICMP:
-
- icmpEventExecutorService.execute(() ->
- openstackIcmpHandler.processIcmpPacket(context, ethernet));
- break;
- case IPv4.PROTOCOL_UDP:
- // don't process DHCP
- UDP udpPacket = (UDP) iPacket.getPayload();
- if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
- udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
- break;
- }
- default:
- int portNum = getPortNum(ethernet.getSourceMAC(), iPacket.getDestinationAddress());
- DeviceId deviceId = pkt.receivedFrom().deviceId();
- Port port = null;
- port = deviceService.getPort(deviceId,
- gatewayService.getUplinkPort(deviceId));
- if (port != null) {
- OpenstackPort openstackPort = getOpenstackPort(ethernet.getSourceMAC(),
- Ip4Address.valueOf(iPacket.getSourceAddress()));
- l3EventExecutorService.execute(new OpenstackPnatHandler(rulePopulator, context,
- portNum, openstackPort, port));
-
- } else {
- log.warn("There`s no external interface");
- }
-
- break;
- }
- } else if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
- arpEventExecutorService.execute(() ->
- openstackArpHandler.processArpPacketFromRouter(context, ethernet));
- }
+ private void unsetExternalConnection(OpenstackRouter osRouter, String osNetId) {
+ if (!osRouter.gatewayExternalInfo().isEnablePnat()) {
+ log.debug("Source NAT is disabled");
+ return;
}
- private int getPortNum(MacAddress sourceMac, int destinationAddress) {
- int portNum = findUnusedPortNum();
- if (portNum == 0) {
- clearPortNumMap();
- portNum = findUnusedPortNum();
- }
- tpPortNumMap.put(portNum, sourceMac.toString().concat(COLON).concat(String.valueOf(destinationAddress)));
- return portNum;
- }
-
- private int findUnusedPortNum() {
- for (int i = TP_PORT_MINIMUM_NUM; i < TP_PORT_MAXIMUM_NUM; i++) {
- if (!tpPortNumMap.containsKey(i)) {
- return i;
- }
- }
- return 0;
- }
-
+ // FIXME router interface is subnet specific, not network
+ OpenstackNetwork osNet = openstackService.network(osNetId);
+ removeExternalRules(osNet);
}
- private boolean checkGatewayNode(DeviceId deviceId) {
- return gatewayService.getGatewayDeviceIds().contains(deviceId);
+ private void setRoutes(OpenstackRouter osRouter, Optional<Host> host) {
+ Set<OpenstackNetwork> routableNets = routableNetworks(osRouter.id());
+ if (routableNets.size() < 2) {
+ // no other subnet interface is connected to this router, do nothing
+ return;
+ }
+
+ // FIXME router interface is subnet specific, not network
+ Set<String> routableNetIds = routableNets.stream()
+ .map(OpenstackNetwork::id)
+ .collect(Collectors.toSet());
+
+ Set<Host> hosts = host.isPresent() ? ImmutableSet.of(host.get()) :
+ Tools.stream(hostService.getHosts())
+ .filter(h -> routableNetIds.contains(h.annotations().value(NETWORK_ID)))
+ .collect(Collectors.toSet());
+
+ hosts.stream().forEach(h -> populateRoutingRules(h, routableNets));
}
- private void clearPortNumMap() {
- tpPortNumMap.entrySet().forEach(e -> {
- if (System.currentTimeMillis() - e.getValue().creationTime() > PNAT_PORT_EXPIRE_TIME) {
- tpPortNumMap.remove(e.getKey());
- }
+ private void unsetRoutes(OpenstackRouter osRouter, OpenstackNetwork osNet) {
+ // FIXME router interface is subnet specific, not network
+ Set<OpenstackNetwork> routableNets = routableNetworks(osRouter.id());
+ Tools.stream(hostService.getHosts())
+ .filter(h -> Objects.equals(
+ h.annotations().value(NETWORK_ID), osNet.id()))
+ .forEach(h -> removeRoutingRules(h, routableNets));
+
+ routableNets.stream().forEach(n -> {
+ Tools.stream(hostService.getHosts())
+ .filter(h -> Objects.equals(
+ h.annotations().value(NETWORK_ID),
+ n.id()))
+ .forEach(h -> removeRoutingRules(h, ImmutableSet.of(osNet)));
+ log.debug("Removed between {} to {}", n.name(), osNet.name());
});
}
- private Optional<Port> getExternalPort(DeviceId deviceId, String interfaceName) {
- return deviceService.getPorts(deviceId)
- .stream()
- .filter(p -> p.annotations().value(PORT_NAME).equals(interfaceName))
- .findAny();
- }
-
- private void checkExternalConnection(OpenstackRouter router,
- Collection<OpenstackRouterInterface> interfaces) {
- checkNotNull(router, "Router can not be null");
- checkNotNull(interfaces, "routerInterfaces can not be null");
- Ip4Address externalIp = router.gatewayExternalInfo().externalFixedIps()
- .values().stream().findFirst().orElse(null);
- if ((externalIp == null) || (!router.gatewayExternalInfo().isEnablePnat())) {
- log.debug("Not satisfied to set pnat configuration");
- return;
- }
- interfaces.forEach(this::initiateL3Rule);
- }
-
- private Optional<OpenstackRouter> getRouterfromExternalIp(Ip4Address externalIp) {
- return getExternalRouter(true)
- .stream()
- .filter(r -> r.gatewayExternalInfo()
- .externalFixedIps()
- .values()
- .stream()
- .findAny()
- .get()
- .equals(externalIp))
- .findAny();
- }
-
- private void initiateL3Rule(OpenstackRouterInterface routerInterface) {
- long vni = Long.parseLong(openstackService.network(openstackService
- .port(routerInterface.portId()).networkId()).segmentId());
- rulePopulator.populateExternalRules(vni);
- }
-
- private Collection<OpenstackRouterInterface> getOpenstackRouterInterface(OpenstackRouter router) {
- List<OpenstackRouterInterface> interfaces = Lists.newArrayList();
- openstackService.ports()
- .stream()
- .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE)
- && p.deviceId().equals(router.id()))
- .forEach(p -> interfaces.add(portToRouterInterface(p)));
- return interfaces;
- }
-
- private OpenstackRouter getOpenstackRouter(String id) {
+ private OpenstackRouter openstackRouter(String routerId) {
return openstackService.routers().stream().filter(r ->
- r.id().equals(id)).iterator().next();
+ r.id().equals(routerId)).iterator().next();
}
- private OpenstackPort getOpenstackPort(MacAddress sourceMac, Ip4Address ip4Address) {
- OpenstackPort openstackPort = openstackService.ports().stream()
- .filter(p -> p.macAddress().equals(sourceMac)).iterator().next();
- return openstackPort.fixedIps().values().stream().filter(ip ->
- ip.equals(ip4Address)).count() > 0 ? openstackPort : null;
- }
-
- private OpenstackFloatingIP getOpenstackFloatingIp(Ip4Address vmIp) {
- Optional<OpenstackFloatingIP> floatingIp = floatingIpMap.asJavaMap().values().stream()
- .filter(f -> f.portId() != null && f.fixedIpAddress().equals(vmIp))
- .findAny();
-
- if (floatingIp.isPresent()) {
- return floatingIp.get();
- }
- log.debug("There is no floating IP information for VM IP {}", vmIp);
-
- return null;
- }
-
- private Optional<OpenstackPort> getRouterInterfacePort(String networkId) {
-
- return openstackService.ports()
- .stream()
- .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE)
- && p.networkId().equals(networkId))
+ private Optional<OpenstackPort> routerIfacePort(String osNetId) {
+ // FIXME router interface is subnet specific, not network
+ return openstackService.ports().stream()
+ .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE) &&
+ p.networkId().equals(osNetId))
.findAny();
}
- // TODO: Remove the function and the related codes when vRouter is running on different ONOS instance.
- private void registerFloatingIpToHostService(OpenstackFloatingIP openstackFloatingIp, Action action) {
+ private Set<OpenstackNetwork> routableNetworks(String osRouterId) {
+ // FIXME router interface is subnet specific, not network
+ return openstackService.ports().stream()
+ .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE) &&
+ p.deviceId().equals(osRouterId))
+ .map(p -> openstackService.network(p.networkId()))
+ .collect(Collectors.toSet());
+ }
- Optional<Host> hostOptional = hostService.getHostsByIp(openstackFloatingIp.fixedIpAddress())
- .stream()
- .findFirst();
- if (!hostOptional.isPresent()) {
- log.warn("No host with IP {} is registered and cannot add the floating IP. ",
- openstackFloatingIp.floatingIpAddress());
+ private void populateExternalRules(OpenstackNetwork osNet) {
+ populateCnodeToGateway(Long.valueOf(osNet.segmentId()));
+ populateGatewayToController(Long.valueOf(osNet.segmentId()));
+ }
+
+ private void removeExternalRules(OpenstackNetwork osNet) {
+ TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+ sBuilder.matchEthType(Ethernet.TYPE_IPV4)
+ .matchTunnelId(Long.valueOf(osNet.segmentId()))
+ .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
+
+ nodeService.completeNodes().stream().forEach(node -> {
+ ForwardingObjective.Flag flag = node.type().equals(GATEWAY) ?
+ ForwardingObjective.Flag.VERSATILE :
+ ForwardingObjective.Flag.SPECIFIC;
+
+ RulePopulatorUtil.removeRule(
+ flowObjectiveService,
+ appId,
+ node.intBridge(),
+ sBuilder.build(),
+ flag,
+ ROUTING_RULE_PRIORITY);
+ });
+ }
+
+ private void populateRoutingRules(Host host, Set<OpenstackNetwork> osNets) {
+ String osNetId = host.annotations().value(NETWORK_ID);
+ if (osNetId == null) {
return;
}
- Host host = hostOptional.get();
- Set<IpAddress> ipAddresses = Sets.newHashSet();
- if (action == Action.ASSOCIATE) {
- ipAddresses.add(openstackFloatingIp.floatingIpAddress());
+ DeviceId localDevice = host.location().deviceId();
+ PortNumber localPort = host.location().port();
+ if (!nodeService.dataIp(localDevice).isPresent()) {
+ log.warn("Failed to populate L3 rules");
+ return;
}
- HostDescription hostDescription =
- new DefaultHostDescription(host.mac(), host.vlan(), host.location(), ipAddresses,
- (DefaultAnnotations) host.annotations());
+ // TODO improve pipeline, do we have to install access rules between networks
+ // for every single VMs?
+ osNets.stream().filter(osNet -> !osNet.id().equals(osNetId)).forEach(osNet -> {
+ populateRoutingRulestoSameNode(
+ host.ipAddresses().stream().findFirst().get().getIp4Address(),
+ host.mac(),
+ localPort, localDevice,
+ Long.valueOf(osNet.segmentId()));
- hostProviderService.hostDetected(host.id(), hostDescription, false);
+ nodeService.completeNodes().stream()
+ .filter(node -> node.type().equals(COMPUTE))
+ .filter(node -> !node.intBridge().equals(localDevice))
+ .forEach(node -> populateRoutingRulestoDifferentNode(
+ host.ipAddresses().stream().findFirst().get().getIp4Address(),
+ Long.valueOf(osNet.segmentId()),
+ node.intBridge(),
+ nodeService.dataIp(localDevice).get().getIp4Address()));
+ });
}
- private class InternalHostListener implements HostListener {
-
- private void hostDetected(Host host) {
- String portId = host.annotations().value(Constants.PORT_ID);
- OpenstackPort openstackPort = openstackService.port(portId);
- if (openstackPort == null) {
- log.warn("No OpenstackPort information found from OpenStack for port ID {}", portId);
- return;
- }
-
- Optional<OpenstackPort> routerPort = getRouterInterfacePort(openstackPort.networkId());
- if (routerPort.isPresent()) {
- OpenstackRouterInterface routerInterface = portToRouterInterface(routerPort.get());
- l3EventExecutorService.execute(() ->
- setL3Connection(getOpenstackRouter(routerInterface.id()), openstackPort));
-
- }
+ private void removeRoutingRules(Host host, Set<OpenstackNetwork> osNets) {
+ String osNetId = host.annotations().value(NETWORK_ID);
+ if (osNetId == null) {
+ return;
}
- private void hostRemoved(Host host) {
- String portId = host.annotations().value(Constants.PORT_ID);
- OpenstackPort openstackPort = openstackService.port(portId);
- if (openstackPort == null) {
- log.warn("No OpenstackPort information found from OpenStack for port ID {}", portId);
- return;
- }
+ osNets.stream().filter(osNet -> !osNet.id().equals(osNetId)).forEach(osNet -> {
+ TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+ sBuilder.matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPDst(host.ipAddresses().stream().findFirst().get().toIpPrefix())
+ .matchTunnelId(Long.valueOf(osNet.segmentId()));
- Optional<OpenstackPort> routerPort = getRouterInterfacePort(openstackPort.networkId());
- if (routerPort.isPresent()) {
- OpenstackRouterInterface routerInterface = portToRouterInterface(routerPort.get());
- IpAddress ipAddress = host.ipAddresses().stream().findFirst().get();
- l3EventExecutorService.execute(() -> rulePopulator.removeL3Rules(ipAddress.getIp4Address(),
- getL3ConnectionList(host.annotations().value(Constants.NETWORK_ID),
- getOpenstackRouterInterface(getOpenstackRouter(routerInterface.id())))));
- }
- }
-
- private boolean isValidHost(Host host) {
- return !host.ipAddresses().isEmpty() &&
- host.annotations().value(Constants.VXLAN_ID) != null &&
- host.annotations().value(Constants.NETWORK_ID) != null &&
- host.annotations().value(Constants.TENANT_ID) != null &&
- host.annotations().value(Constants.PORT_ID) != null;
- }
-
- @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:
- l3EventExecutorService.execute(() -> hostDetected(host));
- break;
- case HOST_REMOVED:
- l3EventExecutorService.execute(() -> hostRemoved(host));
- break;
- default:
- break;
- }
- }
+ nodeService.completeNodes().stream()
+ .filter(node -> node.type().equals(COMPUTE))
+ .forEach(node -> RulePopulatorUtil.removeRule(
+ flowObjectiveService,
+ appId,
+ node.intBridge(),
+ sBuilder.build(),
+ ForwardingObjective.Flag.SPECIFIC,
+ ROUTING_RULE_PRIORITY));
+ });
+ log.debug("Removed routing rule from {} to {}", host, osNets);
}
- private class InternalOpenstackNodeListener implements OpenstackNodeListener {
+ private void populateGatewayToController(long vni) {
+ TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+ TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
- private void nodeComplete() {
+ sBuilder.matchEthType(Ethernet.TYPE_IPV4)
+ .matchTunnelId(vni)
+ .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
+ tBuilder.setOutput(PortNumber.CONTROLLER);
- rulePopulator = new OpenstackRoutingRulePopulator(appId, openstackService, flowObjectiveService,
- deviceService, driverService, nodeService, gatewayService);
- openstackIcmpHandler = new OpenstackIcmpHandler(packetService, deviceService, hostService,
- openstackService, nodeService, gatewayService);
- openstackArpHandler = new OpenstackRoutingArpHandler(packetService, openstackService, nodeService,
- gatewayService);
+ ForwardingObjective fo = DefaultForwardingObjective.builder()
+ .withSelector(sBuilder.build())
+ .withTreatment(tBuilder.build())
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(ROUTING_RULE_PRIORITY)
+ .fromApp(appId)
+ .add();
- // Packet handlers must be started AFTER all initialization processes.
- packetService.addProcessor(internalPacketProcessor, PacketProcessor.director(1));
+ gatewayService.getGatewayDeviceIds().stream()
+ .forEach(deviceId -> flowObjectiveService.forward(deviceId, fo));
+ }
- openstackIcmpHandler.requestPacket(appId);
- openstackArpHandler.requestPacket(appId);
+ private void populateCnodeToGateway(long vni) {
+ nodeService.completeNodes().stream()
+ .filter(node -> node.type().equals(COMPUTE))
+ .forEach(node -> populateRuleToGateway(
+ node.intBridge(),
+ gatewayService.getGatewayGroupId(node.intBridge()),
+ vni));
+ }
- openstackService.floatingIps().stream()
- .forEach(f -> floatingIpMap.put(f.id(), f));
+ private void populateRuleToGateway(DeviceId deviceId, GroupId groupId, long vni) {
+ TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+ TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
- reloadInitL3Rules();
+ sBuilder.matchEthType(Ethernet.TYPE_IPV4)
+ .matchTunnelId(vni)
+ .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
+
+ tBuilder.group(groupId);
+ ForwardingObjective fo = DefaultForwardingObjective.builder()
+ .withSelector(sBuilder.build())
+ .withTreatment(tBuilder.build())
+ .withFlag(ForwardingObjective.Flag.SPECIFIC)
+ .withPriority(ROUTING_RULE_PRIORITY)
+ .fromApp(appId)
+ .add();
+
+ flowObjectiveService.forward(deviceId, fo);
+ }
+
+ private void populateRoutingRulestoDifferentNode(Ip4Address vmIp, long vni,
+ DeviceId deviceId, Ip4Address hostIp) {
+ TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+ TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+
+ sBuilder.matchEthType(Ethernet.TYPE_IPV4)
+ .matchTunnelId(vni)
+ .matchIPDst(vmIp.toIpPrefix());
+ tBuilder.extension(buildExtension(deviceService, deviceId, hostIp), deviceId)
+ .setOutput(nodeService.tunnelPort(deviceId).get());
+
+ ForwardingObjective fo = DefaultForwardingObjective.builder()
+ .withSelector(sBuilder.build())
+ .withTreatment(tBuilder.build())
+ .withPriority(ROUTING_RULE_PRIORITY)
+ .withFlag(ForwardingObjective.Flag.SPECIFIC)
+ .fromApp(appId)
+ .add();
+
+ flowObjectiveService.forward(deviceId, fo);
+ }
+
+ private void populateRoutingRulestoSameNode(Ip4Address vmIp, MacAddress vmMac,
+ PortNumber port, DeviceId deviceId, long vni) {
+ TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+ TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+
+ sBuilder.matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPDst(vmIp.toIpPrefix())
+ .matchTunnelId(vni);
+
+ tBuilder.setEthDst(vmMac)
+ .setOutput(port);
+
+ ForwardingObjective fo = DefaultForwardingObjective.builder()
+ .withSelector(sBuilder.build())
+ .withTreatment(tBuilder.build())
+ .withPriority(ROUTING_RULE_PRIORITY)
+ .withFlag(ForwardingObjective.Flag.SPECIFIC)
+ .fromApp(appId)
+ .add();
+
+ flowObjectiveService.forward(deviceId, fo);
+ }
+
+ private void reloadRoutingRules() {
+ eventExecutor.execute(() -> openstackService.ports().stream()
+ .filter(osPort -> osPort.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
+ .forEach(osPort -> {
+ OpenstackRouter osRouter = openstackRouter(osPort.deviceId());
+ setRoutes(osRouter, Optional.empty());
+ if (osRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
+ setExternalConnection(osRouter, osPort.networkId());
+ }
+ }));
+ }
+
+ @Override
+ protected void hostDetected(Host host) {
+ String osNetId = host.annotations().value(NETWORK_ID);
+ Optional<OpenstackPort> routerIface = routerIfacePort(osNetId);
+ if (!routerIface.isPresent()) {
+ return;
}
+ eventExecutor.execute(() -> setRoutes(
+ openstackRouter(routerIface.get().deviceId()),
+ Optional.of(host)));
+ }
+
+ @Override
+ protected void hostRemoved(Host host) {
+ String osNetId = host.annotations().value(NETWORK_ID);
+ Optional<OpenstackPort> routerIface = routerIfacePort(osNetId);
+ if (!routerIface.isPresent()) {
+ return;
+ }
+ Set<OpenstackNetwork> routableNets = routableNetworks(routerIface.get().deviceId());
+ eventExecutor.execute(() -> removeRoutingRules(host, routableNets));
+ }
+
+ private class InternalNodeListener implements OpenstackNodeListener {
@Override
public void event(OpenstackNodeEvent event) {
@@ -730,28 +481,22 @@
switch (event.type()) {
case COMPLETE:
log.info("COMPLETE node {} detected", node.hostname());
- l3EventExecutorService.execute(() -> nodeComplete());
+ if (node.type() == GATEWAY) {
+ GatewayNode gnode = GatewayNode.builder()
+ .gatewayDeviceId(node.intBridge())
+ .dataIpAddress(node.dataIp().getIp4Address())
+ .uplinkIntf(node.externalPortName().get())
+ .build();
+ gatewayService.addGatewayNode(gnode);
+ }
+ eventExecutor.execute(OpenstackRoutingManager.this::reloadRoutingRules);
break;
+ case INIT:
+ case DEVICE_CREATED:
case INCOMPLETE:
- break;
default:
break;
}
}
}
-
- private class InternalHostProvider extends AbstractProvider implements HostProvider {
-
- /**
- * Creates a provider with the supplier identifier.
- */
- protected InternalHostProvider() {
- super(PID);
- }
-
- @Override
- public void triggerProbe(Host host) {
- // nothing to do
- }
- }
}
diff --git a/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingRulePopulator.java b/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingRulePopulator.java
deleted file mode 100644
index 875cf98..0000000
--- a/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingRulePopulator.java
+++ /dev/null
@@ -1,693 +0,0 @@
-/*
- * 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.routing;
-
-import com.google.common.collect.Lists;
-import org.onlab.packet.Ethernet;
-import org.onlab.packet.IPv4;
-import org.onlab.packet.Ip4Address;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.TCP;
-import org.onlab.packet.TpPort;
-import org.onlab.packet.UDP;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.core.GroupId;
-import org.onosproject.net.Device;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Host;
-import org.onosproject.net.Port;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
-import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.driver.DefaultDriverData;
-import org.onosproject.net.driver.DefaultDriverHandler;
-import org.onosproject.net.driver.Driver;
-import org.onosproject.net.driver.DriverHandler;
-import org.onosproject.net.driver.DriverService;
-import org.onosproject.net.flow.DefaultTrafficSelector;
-import org.onosproject.net.flow.DefaultTrafficTreatment;
-import org.onosproject.net.flow.TrafficSelector;
-import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.flow.instructions.ExtensionPropertyException;
-import org.onosproject.net.flow.instructions.ExtensionTreatment;
-import org.onosproject.net.flow.instructions.ExtensionTreatmentType;
-import org.onosproject.net.flowobjective.DefaultForwardingObjective;
-import org.onosproject.net.flowobjective.FlowObjectiveService;
-import org.onosproject.net.flowobjective.ForwardingObjective;
-import org.onosproject.net.packet.InboundPacket;
-import org.onosproject.openstackinterface.OpenstackInterfaceService;
-import org.onosproject.openstackinterface.OpenstackPort;
-import org.onosproject.openstackinterface.OpenstackRouterInterface;
-import org.onosproject.openstackinterface.OpenstackSubnet;
-import org.onosproject.openstackinterface.OpenstackFloatingIP;
-import org.onosproject.openstacknetworking.Constants;
-import org.onosproject.openstacknetworking.OpenstackRoutingService;
-import org.onosproject.scalablegateway.api.ScalableGatewayService;
-import org.onosproject.openstacknode.OpenstackNode;
-import org.onosproject.openstacknode.OpenstackNodeService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.List;
-import java.util.Optional;
-import java.util.stream.StreamSupport;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.onlab.osgi.DefaultServiceDirectory.getService;
-import static org.onosproject.net.AnnotationKeys.PORT_NAME;
-
-/**
- * Populates Routing Flow Rules.
- */
-public class OpenstackRoutingRulePopulator {
-
- private final Logger log = LoggerFactory.getLogger(getClass());
-
- private final ApplicationId appId;
- private final FlowObjectiveService flowObjectiveService;
- private final OpenstackInterfaceService openstackService;
- private final DeviceService deviceService;
- private final DriverService driverService;
- private final ScalableGatewayService gatewayService;
- private final OpenstackNodeService nodeService;
-
- private static final String PORTNAME_PREFIX_TUNNEL = "vxlan";
- private static final String PORTNAME_PREFIX_VM = "tap";
-
- private static final String PORTNOTNULL = "Port can not be null";
- private static final String DEVICENOTNULL = "Device can not be null";
- private static final String TUNNEL_DESTINATION = "tunnelDst";
- private static final int ROUTING_RULE_PRIORITY = 25000;
- private static final int FLOATING_RULE_PRIORITY = 42000;
- private static final int PNAT_RULE_PRIORITY = 26000;
- private static final int PNAT_TIMEOUT = 120;
- private static final int PREFIX_LENGTH = 32;
-
- private InboundPacket inboundPacket;
- private OpenstackPort openstackPort;
- private int portNum;
- private MacAddress externalInterface;
- private MacAddress externalRouter;
-
- /**
- * The constructor of openstackRoutingRulePopulator.
- *
- * @param appId Caller`s appId
- * @param openstackService Opestack REST request handler
- * @param flowObjectiveService FlowObjectiveService
- * @param deviceService DeviceService
- * @param driverService DriverService
- * @param nodeService openstack node service
- * @param gatewayService scalable gateway service
- */
- public OpenstackRoutingRulePopulator(ApplicationId appId,
- OpenstackInterfaceService openstackService,
- FlowObjectiveService flowObjectiveService,
- DeviceService deviceService,
- DriverService driverService,
- OpenstackNodeService nodeService,
- ScalableGatewayService gatewayService) {
- this.appId = appId;
- this.flowObjectiveService = flowObjectiveService;
- this.openstackService = checkNotNull(openstackService);
- this.deviceService = deviceService;
- this.driverService = driverService;
- this.gatewayService = gatewayService;
- this.nodeService = nodeService;
- }
-
- /**
- * Populates flow rules for Pnat configurations.
- *
- * @param inboundPacket Packet-in event packet
- * @param openstackPort Target VM information
- * @param portNum Pnat port number
- * @param externalIp external ip address
- * @param externalInterfaceMacAddress Gateway external interface macaddress
- * @param externalRouterMacAddress Outer(physical) router`s macaddress
- */
- public void populatePnatFlowRules(InboundPacket inboundPacket, OpenstackPort openstackPort, int portNum,
- Ip4Address externalIp, MacAddress externalInterfaceMacAddress,
- MacAddress externalRouterMacAddress) {
- this.inboundPacket = inboundPacket;
- this.openstackPort = openstackPort;
- this.portNum = portNum;
- this.externalInterface = externalInterfaceMacAddress;
- this.externalRouter = externalRouterMacAddress;
-
- long vni = getVni(openstackPort.networkId());
-
- populatePnatIncomingFlowRules(vni, externalIp);
- populatePnatOutgoingFlowRules(vni, externalIp);
- }
-
- private void populatePnatOutgoingFlowRules(long vni, Ip4Address externalIp) {
- IPv4 iPacket = (IPv4) inboundPacket.parsed().getPayload();
-
- TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
- sBuilder.matchEthType(Ethernet.TYPE_IPV4)
- .matchIPProtocol(iPacket.getProtocol())
- .matchTunnelId(vni)
- .matchIPSrc(IpPrefix.valueOf(iPacket.getSourceAddress(), 32))
- .matchIPDst(IpPrefix.valueOf(iPacket.getDestinationAddress(), 32));
-
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
-
- switch (iPacket.getProtocol()) {
- case IPv4.PROTOCOL_TCP:
- TCP tcpPacket = (TCP) iPacket.getPayload();
- sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getSourcePort()))
- .matchTcpDst(TpPort.tpPort(tcpPacket.getDestinationPort()));
- tBuilder.setTcpSrc(TpPort.tpPort(portNum));
- break;
- case IPv4.PROTOCOL_UDP:
- UDP udpPacket = (UDP) iPacket.getPayload();
- sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getSourcePort()))
- .matchUdpDst(TpPort.tpPort(udpPacket.getDestinationPort()));
- tBuilder.setUdpSrc(TpPort.tpPort(portNum));
- break;
- default:
- log.debug("Unsupported IPv4 protocol {}");
- break;
- }
-
- tBuilder.setIpSrc(externalIp);
- gatewayService.getGatewayNodes().forEach(node -> {
- tBuilder.setOutput(gatewayService.getUplinkPort(node.getGatewayDeviceId()));
- ForwardingObjective fo = DefaultForwardingObjective.builder()
- .withSelector(sBuilder.build())
- .withTreatment(tBuilder.build())
- .withFlag(ForwardingObjective.Flag.VERSATILE)
- .withPriority(PNAT_RULE_PRIORITY)
- .makeTemporary(PNAT_TIMEOUT)
- .fromApp(appId)
- .add();
-
- flowObjectiveService.forward(node.getGatewayDeviceId(), fo);
- });
-
- }
-
- private Port getPortOfExternalInterface() {
- return deviceService.getPorts(getGatewayNode().id()).stream()
- .filter(p -> p.annotations().value(PORT_NAME)
- .equals(org.onosproject.openstacknode.Constants.PATCH_INTG_BRIDGE))
- .findAny().orElse(null);
- }
-
-
- private void populatePnatIncomingFlowRules(long vni, Ip4Address externalIp) {
- IPv4 iPacket = (IPv4) inboundPacket.parsed().getPayload();
-
- TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
- sBuilder.matchEthType(Ethernet.TYPE_IPV4)
- .matchIPProtocol(iPacket.getProtocol())
- .matchIPDst(IpPrefix.valueOf(externalIp, 32))
- .matchIPSrc(IpPrefix.valueOf(iPacket.getDestinationAddress(), 32));
-
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
- tBuilder.setTunnelId(vni)
- .setEthDst(inboundPacket.parsed().getSourceMAC())
- .setIpDst(IpAddress.valueOf(iPacket.getSourceAddress()));
-
- switch (iPacket.getProtocol()) {
- case IPv4.PROTOCOL_TCP:
- TCP tcpPacket = (TCP) iPacket.getPayload();
- sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getDestinationPort()))
- .matchTcpDst(TpPort.tpPort(portNum));
- tBuilder.setTcpDst(TpPort.tpPort(tcpPacket.getSourcePort()));
- break;
- case IPv4.PROTOCOL_UDP:
- UDP udpPacket = (UDP) iPacket.getPayload();
- sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getDestinationPort()))
- .matchUdpDst(TpPort.tpPort(portNum));
- tBuilder.setUdpDst(TpPort.tpPort(udpPacket.getSourcePort()));
- break;
- default:
- break;
- }
-
- getGatewayNodeList().forEach(node -> {
- DeviceId deviceId = node.id();
- tBuilder.extension(buildNiciraExtenstion(deviceId,
- getHostIpfromOpenstackPort(openstackPort).getIp4Address()), deviceId)
- .setOutput(getTunnelPort(deviceId));
-
- ForwardingObjective fo = DefaultForwardingObjective.builder()
- .withSelector(sBuilder.build())
- .withTreatment(tBuilder.build())
- .withFlag(ForwardingObjective.Flag.VERSATILE)
- .withPriority(PNAT_RULE_PRIORITY)
- .makeTemporary(PNAT_TIMEOUT)
- .fromApp(appId)
- .add();
-
- flowObjectiveService.forward(deviceId, fo);
- });
- }
-
- private List<Device> getGatewayNodeList() {
- List<Device> devices = Lists.newArrayList();
- gatewayService.getGatewayDeviceIds().forEach(deviceId ->
- devices.add(checkNotNull(deviceService.getDevice(deviceId))));
- return devices;
- }
-
- private IpAddress getHostIpfromOpenstackPort(OpenstackPort openstackPort) {
- Device device = getDevicefromOpenstackPort(openstackPort);
-
- Optional<IpAddress> ipAddress = nodeService.dataIp(device.id());
- if (!ipAddress.isPresent()) {
- log.warn("No IP address found for device {}", device.id());
- return null;
- }
-
- return ipAddress.get();
- }
-
- private Device getDevicefromOpenstackPort(OpenstackPort openstackPort) {
- String openstackPortName = PORTNAME_PREFIX_VM + openstackPort.id().substring(0, 11);
- Device device = StreamSupport.stream(deviceService.getDevices().spliterator(), false)
- .filter(d -> findPortinDevice(d.id(), openstackPortName))
- .iterator()
- .next();
- checkNotNull(device, DEVICENOTNULL);
- return device;
- }
-
- private boolean findPortinDevice(DeviceId deviceId, String openstackPortName) {
- Port port = deviceService.getPorts(deviceId)
- .stream()
- .filter(p -> p.isEnabled() && p.annotations().value(PORT_NAME).equals(openstackPortName))
- .findAny()
- .orElse(null);
- return port != null;
- }
-
- /**
- * Builds Nicira extension for tagging remoteIp of vxlan.
- *
- * @param deviceId Device Id of vxlan source device
- * @param hostIp Remote Ip of vxlan destination device
- * @return NiciraExtension Treatment
- */
- public ExtensionTreatment buildNiciraExtenstion(DeviceId deviceId, Ip4Address hostIp) {
- Driver driver = driverService.getDriver(deviceId);
- DriverHandler driverHandler = new DefaultDriverHandler(new DefaultDriverData(driver, deviceId));
- ExtensionTreatmentResolver resolver = driverHandler.behaviour(ExtensionTreatmentResolver.class);
-
- ExtensionTreatment extensionInstruction =
- resolver.getExtensionInstruction(
- ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST.type());
-
- try {
- extensionInstruction.setPropertyValue(TUNNEL_DESTINATION, hostIp);
- } catch (ExtensionPropertyException e) {
- log.error("Error setting Nicira extension setting {}", e);
- }
-
- return extensionInstruction;
- }
-
- /**
- * Returns port number of vxlan tunnel.
- *
- * @param deviceId Target Device Id
- * @return PortNumber
- */
- public PortNumber getTunnelPort(DeviceId deviceId) {
- Port port = deviceService.getPorts(deviceId).stream()
- .filter(p -> p.annotations().value(PORT_NAME).equals(PORTNAME_PREFIX_TUNNEL))
- .findAny().orElse(null);
-
- if (port == null) {
- log.error("No TunnelPort was created.");
- return null;
- }
- return port.number();
-
- }
-
- /**
- * Populates flow rules from openstackComputeNode to GatewayNode.
- *
- * @param vni Target network
- */
- public void populateExternalRules(long vni) {
-
- // 1. computeNode to gateway
- populateComputeNodeRules(vni);
- // 2. gatewayNode to controller
- populateRuleGatewaytoController(vni);
- }
-
- private void populateRuleGatewaytoController(long vni) {
- TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
-
- sBuilder.matchEthType(Ethernet.TYPE_IPV4)
- .matchTunnelId(vni)
- .matchEthDst(Constants.GATEWAY_MAC);
- tBuilder.setOutput(PortNumber.CONTROLLER);
-
- ForwardingObjective fo = DefaultForwardingObjective.builder()
- .withSelector(sBuilder.build())
- .withTreatment(tBuilder.build())
- .withFlag(ForwardingObjective.Flag.VERSATILE)
- .withPriority(ROUTING_RULE_PRIORITY)
- .fromApp(appId)
- .add();
-
- getGatewayNodeList().forEach(device -> flowObjectiveService.forward(device.id(), fo));
- }
-
- private void populateComputeNodeRules(long vni) {
- StreamSupport.stream(deviceService.getDevices().spliterator(), false)
- .filter(d -> isTypeOf(d.id(), OpenstackNodeService.NodeType.COMPUTE))
- .forEach(d -> populateRuleToGatewayBySgw(d.id(),
- gatewayService.getGatewayGroupId(d.id()), vni));
- }
-
- private void populateRuleToGatewayBySgw(DeviceId deviceId, GroupId groupId, long vni) {
- TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
-
- sBuilder.matchEthType(Ethernet.TYPE_IPV4)
- .matchTunnelId(vni)
- .matchEthDst(Constants.GATEWAY_MAC);
-
- tBuilder.group(groupId);
-
- ForwardingObjective fo = DefaultForwardingObjective.builder()
- .withSelector(sBuilder.build())
- .withTreatment(tBuilder.build())
- .withFlag(ForwardingObjective.Flag.SPECIFIC)
- .withPriority(ROUTING_RULE_PRIORITY)
- .fromApp(appId)
- .add();
-
- flowObjectiveService.forward(deviceId, fo);
- }
-
- private Device getGatewayNode() {
-
- // TODO Return the correct gateway node
- Optional<OpenstackNode> gwNode = nodeService.nodes().stream()
- .filter(n -> n.type().equals(OpenstackNodeService.NodeType.GATEWAY))
- .findFirst();
-
- if (!gwNode.isPresent()) {
- log.warn("No Gateway is defined.");
- return null;
- }
-
- return deviceService.getDevice(gwNode.get().intBridge());
- }
-
- private boolean isTypeOf(DeviceId deviceId, OpenstackNodeService.NodeType type) {
-
- Optional<OpenstackNode> node = nodeService.nodes().stream()
- .filter(n -> n.intBridge().equals(deviceId) ||
- (n.routerBridge().isPresent() && n.routerBridge().get().equals(deviceId)))
- .filter(n -> n.type().equals(type))
- .findFirst();
-
- if (node.isPresent()) {
- return true;
- }
-
- return false;
- }
-
- private long getVni(String netId) {
- return Long.parseLong(openstackService.network(netId).segmentId());
- }
-
- /**
- * Remove flow rules for external connection.
- *
- * @param routerInterface Corresponding routerInterface
- */
- public void removeExternalRules(OpenstackRouterInterface routerInterface) {
- OpenstackSubnet openstackSubnet = openstackService.subnet(routerInterface.subnetId());
- TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
- sBuilder.matchEthType(Ethernet.TYPE_IPV4)
- .matchTunnelId(getVni(openstackSubnet.networkId()))
- .matchEthDst(Constants.GATEWAY_MAC);
-
- StreamSupport.stream(deviceService.getDevices().spliterator(), false)
- .forEach(d -> {
- ForwardingObjective.Flag flag = isTypeOf(d.id(), OpenstackNodeService.NodeType.GATEWAY) ?
- ForwardingObjective.Flag.VERSATILE :
- ForwardingObjective.Flag.SPECIFIC;
- removeRule(d.id(), sBuilder, flag, ROUTING_RULE_PRIORITY);
- });
-
- }
-
- private void removeRule(DeviceId deviceId, TrafficSelector.Builder sBuilder,
- ForwardingObjective.Flag flag, int priority) {
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
-
- ForwardingObjective fo = DefaultForwardingObjective.builder()
- .withSelector(sBuilder.build())
- .withTreatment(tBuilder.build())
- .withFlag(flag)
- .withPriority(priority)
- .fromApp(appId)
- .remove();
-
- flowObjectiveService.forward(deviceId, fo);
- }
-
- /**
- * Populates flow rules for floatingIp configuration.
- *
- * @param floatingIP Corresponding floating ip information
- */
- public void populateFloatingIpRules(OpenstackFloatingIP floatingIP) {
- OpenstackPort port = openstackService.port(floatingIP.portId());
- //1. incoming rules
- populateFloatingIpIncomingRules(floatingIP, port);
- //2. outgoing rules
- populateFloatingIpOutgoingRules(floatingIP, port);
- }
-
- private void populateFloatingIpIncomingRules(OpenstackFloatingIP floatingIP, OpenstackPort port) {
- TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
-
- sBuilder.matchEthType(Ethernet.TYPE_IPV4)
- .matchIPDst(IpPrefix.valueOf(floatingIP.floatingIpAddress(), PREFIX_LENGTH));
-
- DeviceId gatewayDeviceId = DeviceId.deviceId(port.deviceId());
- Optional<IpAddress> ipAddress = nodeService.dataIp(gatewayDeviceId);
- if (!ipAddress.isPresent()) {
- log.warn("No IP address found for device {}", port.deviceId());
- return;
- }
- tBuilder.setEthSrc(Constants.GATEWAY_MAC)
- .setEthDst(port.macAddress())
- .setIpDst(floatingIP.fixedIpAddress())
- .setTunnelId(getVni(port.networkId()))
- .extension(buildNiciraExtenstion(gatewayDeviceId,
- ipAddress.get().getIp4Address()), gatewayDeviceId)
- .setOutput(getTunnelPort(gatewayDeviceId));
-
- ForwardingObjective fo = DefaultForwardingObjective.builder()
- .withSelector(sBuilder.build())
- .withTreatment(tBuilder.build())
- .withFlag(ForwardingObjective.Flag.VERSATILE)
- .withPriority(FLOATING_RULE_PRIORITY)
- .fromApp(appId)
- .add();
-
- flowObjectiveService.forward(getGatewayNode().id(), fo);
- }
-
- private void populateFloatingIpOutgoingRules(OpenstackFloatingIP floatingIP, OpenstackPort port) {
- TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
-
- sBuilder.matchEthType(Ethernet.TYPE_IPV4)
- .matchTunnelId(getVni(port.networkId()))
- .matchIPSrc(IpPrefix.valueOf(floatingIP.fixedIpAddress(), 32));
-
- getGatewayNodeList().forEach(device -> {
- DeviceId deviceId = device.id();
- tBuilder.setIpSrc(floatingIP.floatingIpAddress())
- .setEthSrc(Constants.GW_EXT_INT_MAC)
- .setEthDst(Constants.PHY_ROUTER_MAC)
- .setOutput(getExternalPortNum(deviceId));
-
- ForwardingObjective fo = DefaultForwardingObjective.builder()
- .withSelector(sBuilder.build())
- .withTreatment(tBuilder.build())
- .withFlag(ForwardingObjective.Flag.VERSATILE)
- .withPriority(FLOATING_RULE_PRIORITY)
- .fromApp(appId)
- .add();
-
- flowObjectiveService.forward(deviceId, fo);
- });
- }
-
- private PortNumber getExternalPortNum(DeviceId deviceId) {
- return checkNotNull(gatewayService.getUplinkPort(deviceId), PORTNOTNULL);
- }
-
- /**
- * Removes flow rules for floating ip configuration.
- *
- * @param floatingIp Corresponding floating ip information
- * @param host host information for vm to remove
- */
- public void removeFloatingIpRules(OpenstackFloatingIP floatingIp, Host host) {
- TrafficSelector.Builder sOutgoingBuilder = DefaultTrafficSelector.builder();
- TrafficSelector.Builder sIncomingBuilder = DefaultTrafficSelector.builder();
-
- // XXX FloatingIp.tenant_id() == host.vxlan_id ???
- sOutgoingBuilder.matchEthType(Ethernet.TYPE_IPV4)
- .matchTunnelId(Integer.parseInt(host.annotations().value(Constants.VXLAN_ID)))
- .matchIPSrc(IpPrefix.valueOf(floatingIp.fixedIpAddress(), PREFIX_LENGTH));
-
- sIncomingBuilder.matchEthType(Ethernet.TYPE_IPV4)
- .matchIPDst(IpPrefix.valueOf(floatingIp.floatingIpAddress(), PREFIX_LENGTH));
-
- getGatewayNodeList().forEach(device -> {
- removeRule(device.id(), sOutgoingBuilder, ForwardingObjective.Flag.VERSATILE, FLOATING_RULE_PRIORITY);
- removeRule(device.id(), sIncomingBuilder, ForwardingObjective.Flag.VERSATILE, FLOATING_RULE_PRIORITY);
- });
- }
-
- /**
- * Populates L3 rules for east to west traffic.
- *
- * @param openstackPort target VM
- * @param targetList target openstackRouterInterfaces
- */
- public void populateL3Rules(OpenstackPort openstackPort, List<OpenstackRouterInterface> targetList) {
- Device device = getDevicefromOpenstackPort(openstackPort);
- Port port = getPortFromOpenstackPort(device, openstackPort);
- Ip4Address vmIp = openstackPort.fixedIps().values().iterator().next();
-
- if (port == null) {
- return;
- }
-
- targetList.forEach(routerInterface -> {
- long vni = getVni(openstackService.port(routerInterface.portId()).networkId());
-
- if (vmIp == null) {
- return;
- }
-
- populateL3RulestoSameNode(vmIp, openstackPort, port, device, vni);
-
- deviceService.getAvailableDevices().forEach(d -> {
- if (!d.equals(device) && !d.equals(getGatewayNode())) {
- populateL3RulestoDifferentNode(vmIp, vni, d.id(),
- getHostIpfromOpenstackPort(openstackPort).getIp4Address());
- }
- });
- });
- }
-
- private void populateL3RulestoDifferentNode(Ip4Address vmIp, long vni, DeviceId deviceId, Ip4Address hostIp) {
- TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
-
- sBuilder.matchEthType(Ethernet.TYPE_IPV4)
- .matchTunnelId(vni)
- .matchIPDst(vmIp.toIpPrefix());
- tBuilder.extension(buildNiciraExtenstion(deviceId, hostIp), deviceId)
- .setOutput(getTunnelPort(deviceId));
-
- ForwardingObjective fo = DefaultForwardingObjective.builder()
- .withSelector(sBuilder.build())
- .withTreatment(tBuilder.build())
- .withPriority(ROUTING_RULE_PRIORITY)
- .withFlag(ForwardingObjective.Flag.SPECIFIC)
- .fromApp(appId)
- .add();
-
- flowObjectiveService.forward(deviceId, fo);
- }
-
- private void populateL3RulestoSameNode(Ip4Address vmIp, OpenstackPort p, Port port, Device device, long vni) {
- TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
-
- sBuilder.matchEthType(Ethernet.TYPE_IPV4)
- .matchIPDst(vmIp.toIpPrefix())
- .matchTunnelId(vni);
-
- tBuilder.setEthDst(p.macAddress())
- .setOutput(port.number());
-
- ForwardingObjective fo = DefaultForwardingObjective.builder()
- .withSelector(sBuilder.build())
- .withTreatment(tBuilder.build())
- .withPriority(ROUTING_RULE_PRIORITY)
- .withFlag(ForwardingObjective.Flag.SPECIFIC)
- .fromApp(appId)
- .add();
-
- flowObjectiveService.forward(device.id(), fo);
- }
-
- private Port getPortFromOpenstackPort(Device device, OpenstackPort p) {
- String openstackPortName = PORTNAME_PREFIX_VM + p.id().substring(0, 11);
- return deviceService.getPorts(device.id())
- .stream()
- .filter(pt -> pt.annotations().value(PORT_NAME).equals(openstackPortName))
- .findAny()
- .orElse(null);
- }
-
- /**
- * Removes L3 rules for routerInterface events.
- *
- * @param vmIp Corresponding Vm ip
- * @param routerInterfaces Corresponding routerInterfaces
- */
- public void removeL3Rules(Ip4Address vmIp, List<OpenstackRouterInterface> routerInterfaces) {
- if (vmIp == null) {
- return;
- }
-
- OpenstackRoutingService routingService = getService(OpenstackRoutingService.class);
-
- deviceService.getAvailableDevices().forEach(d -> {
- if (isTypeOf(d.id(), OpenstackNodeService.NodeType.COMPUTE)) {
- routerInterfaces.forEach(routerInterface -> {
- String networkId = routingService.networkIdForRouterInterface(routerInterface.portId());
- long vni = getVni(networkId);
-
- TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
-
- sBuilder.matchEthType(Ethernet.TYPE_IPV4)
- .matchIPDst(vmIp.toIpPrefix())
- .matchTunnelId(vni);
-
- removeRule(d.id(), sBuilder, ForwardingObjective.Flag.SPECIFIC, ROUTING_RULE_PRIORITY);
- });
- }
- });
- }
-}
diff --git a/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/package-info.java b/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/package-info.java
index 78d05a9..67fd1a5 100644
--- a/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/package-info.java
+++ b/apps/openstacknetworking/routing/src/main/java/org/onosproject/openstacknetworking/routing/package-info.java
@@ -15,6 +15,8 @@
*/
/**
- * Application for OpenstackRouting.
+ * Implements OpenStack L3 service plugin, which routes packets between subnets,
+ * forwards packets from internal networks to external ones, and accesses instances
+ * from external networks through floating IPs.
*/
-package org.onosproject.openstacknetworking.routing;
\ No newline at end of file
+package org.onosproject.openstacknetworking.routing;
diff --git a/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSecurityGroupRulePopulator.java b/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSecurityGroupManager.java
similarity index 97%
rename from apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSecurityGroupRulePopulator.java
rename to apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSecurityGroupManager.java
index 82a5bac..e06b7fa 100644
--- a/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSecurityGroupRulePopulator.java
+++ b/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSecurityGroupManager.java
@@ -30,6 +30,7 @@
import org.onlab.packet.IpPrefix;
import org.onlab.packet.TpPort;
import org.onlab.util.Tools;
+import org.onosproject.core.ApplicationId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Host;
import org.onosproject.net.flow.DefaultTrafficSelector;
@@ -43,6 +44,7 @@
import org.onosproject.openstackinterface.OpenstackSecurityGroup;
import org.onosproject.openstackinterface.OpenstackSecurityGroupRule;
import org.onosproject.openstacknetworking.OpenstackSecurityGroupService;
+import org.onosproject.openstacknetworking.AbstractVmHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -60,7 +62,7 @@
*/
@Component(immediate = true)
@Service
-public class OpenstackSecurityGroupRulePopulator extends AbstractVmHandler
+public class OpenstackSecurityGroupManager extends AbstractVmHandler
implements OpenstackSecurityGroupService {
private final Logger log = LoggerFactory.getLogger(getClass());
@@ -77,10 +79,12 @@
private static final String ETHTYPE_IPV4 = "IPV4";
private final Map<Host, Set<SecurityGroupRule>> securityGroupRuleMap = Maps.newConcurrentMap();
+ private ApplicationId appId;
@Activate
protected void activate() {
super.activate();
+ appId = coreService.registerApplication(SWITCHING_APP_ID);
}
@Deactivate
@@ -96,7 +100,7 @@
Optional<Host> host = getVmByPortId(osPort.id());
if (!host.isPresent()) {
- log.warn("No host found with {}", osPort);
+ log.debug("No host found with {}", osPort.id());
return;
}
eventExecutor.execute(() -> updateSecurityGroupRules(host.get(), true));
diff --git a/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackArpHandler.java b/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingArpHandler.java
similarity index 96%
rename from apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackArpHandler.java
rename to apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingArpHandler.java
index c31bfd9..c35371f 100644
--- a/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackArpHandler.java
+++ b/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingArpHandler.java
@@ -40,6 +40,7 @@
import org.onosproject.openstackinterface.OpenstackInterfaceService;
import org.onosproject.openstackinterface.OpenstackNetwork;
import org.onosproject.openstackinterface.OpenstackPort;
+import org.onosproject.openstacknetworking.AbstractVmHandler;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -54,12 +55,11 @@
* Handles ARP packet from VMs.
*/
@Component(immediate = true)
-public final class OpenstackArpHandler extends AbstractVmHandler {
+public final class OpenstackSwitchingArpHandler extends AbstractVmHandler {
private final Logger log = LoggerFactory.getLogger(getClass());
private static final String GATEWAY_MAC = "gatewayMac";
- private static final String DEFAULT_GATEWAY_MAC = "1f:1f:1f:1f:1f:1f";
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected PacketService packetService;
@@ -67,9 +67,9 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected OpenstackInterfaceService openstackService;
- @Property(name = GATEWAY_MAC, value = DEFAULT_GATEWAY_MAC,
+ @Property(name = GATEWAY_MAC, value = DEFAULT_GATEWAY_MAC_STR,
label = "Fake MAC address for virtual network subnet gateway")
- private String gatewayMac = DEFAULT_GATEWAY_MAC;
+ private String gatewayMac = DEFAULT_GATEWAY_MAC_STR;
private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
private final Set<Ip4Address> gateways = Sets.newConcurrentHashSet();
diff --git a/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingHostManager.java b/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingHostManager.java
new file mode 100644
index 0000000..2d6621a
--- /dev/null
+++ b/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingHostManager.java
@@ -0,0 +1,318 @@
+/*
+ * 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.switching;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.Sets;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.VlanId;
+import org.onosproject.core.CoreService;
+import org.onosproject.dhcp.DhcpService;
+import org.onosproject.dhcp.IpAssignment;
+import org.onosproject.mastership.MastershipService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.Device;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.net.HostLocation;
+import org.onosproject.net.Port;
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.host.DefaultHostDescription;
+import org.onosproject.net.host.HostDescription;
+import org.onosproject.net.host.HostProvider;
+import org.onosproject.net.host.HostProviderRegistry;
+import org.onosproject.net.host.HostProviderService;
+import org.onosproject.net.host.HostService;
+import org.onosproject.net.provider.AbstractProvider;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.openstackinterface.OpenstackInterfaceService;
+import org.onosproject.openstackinterface.OpenstackNetwork;
+import org.onosproject.openstackinterface.OpenstackPort;
+import org.onosproject.openstackinterface.OpenstackSubnet;
+import org.onosproject.openstacknode.OpenstackNode;
+import org.onosproject.openstacknode.OpenstackNodeEvent;
+import org.onosproject.openstacknode.OpenstackNodeListener;
+import org.onosproject.openstacknode.OpenstackNodeService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Date;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.dhcp.IpAssignment.AssignmentStatus.Option_RangeNotEnforced;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.net.AnnotationKeys.PORT_NAME;
+import static org.onosproject.openstacknetworking.Constants.*;
+
+@Service
+@Component(immediate = true)
+public final class OpenstackSwitchingHostManager extends AbstractProvider
+ implements HostProvider {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DeviceService deviceService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected HostProviderRegistry hostProviderRegistry;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DhcpService dhcpService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected HostService hostService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected MastershipService mastershipService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected OpenstackInterfaceService openstackService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected OpenstackNodeService openstackNodeService;
+
+ private final ExecutorService deviceEventExecutor =
+ Executors.newSingleThreadExecutor(groupedThreads("onos/openstackswitching", "device-event"));
+ private final ExecutorService configEventExecutor =
+ Executors.newSingleThreadExecutor(groupedThreads("onos/openstackswitching", "config-event"));
+ private final InternalDeviceListener internalDeviceListener = new InternalDeviceListener();
+ private final InternalOpenstackNodeListener internalNodeListener = new InternalOpenstackNodeListener();
+
+ private HostProviderService hostProvider;
+
+ /**
+ * Creates OpenStack switching host provider.
+ */
+ public OpenstackSwitchingHostManager() {
+ super(new ProviderId("host", SWITCHING_APP_ID));
+ }
+
+ @Activate
+ protected void activate() {
+ coreService.registerApplication(SWITCHING_APP_ID);
+ deviceService.addListener(internalDeviceListener);
+ openstackNodeService.addListener(internalNodeListener);
+ hostProvider = hostProviderRegistry.register(this);
+
+ log.info("Started");
+ }
+
+ @Deactivate
+ protected void deactivate() {
+ hostProviderRegistry.unregister(this);
+ deviceService.removeListener(internalDeviceListener);
+ openstackNodeService.removeListener(internalNodeListener);
+
+ deviceEventExecutor.shutdown();
+ configEventExecutor.shutdown();
+
+ log.info("Stopped");
+ }
+
+ @Override
+ public void triggerProbe(Host host) {
+ // no probe is required
+ }
+
+ private void processPortAdded(Port port) {
+ // TODO check the node state is COMPLETE
+ OpenstackPort osPort = openstackService.port(port);
+ if (osPort == null) {
+ log.warn("Failed to get OpenStack port for {}", port);
+ return;
+ }
+
+ OpenstackNetwork osNet = openstackService.network(osPort.networkId());
+ if (osNet == null) {
+ log.warn("Failed to get OpenStack network {}",
+ osPort.networkId());
+ return;
+ }
+
+ registerDhcpInfo(osPort);
+ ConnectPoint connectPoint = new ConnectPoint(port.element().id(), port.number());
+ // TODO remove gateway IP from host annotation
+ Map.Entry<String, Ip4Address> fixedIp = osPort.fixedIps().entrySet().stream().findFirst().get();
+
+ // Added CREATE_TIME intentionally to trigger HOST_UPDATED event for the
+ // existing instances.
+ DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
+ .set(NETWORK_ID, osPort.networkId())
+ .set(SUBNET_ID, fixedIp.getKey())
+ .set(PORT_ID, osPort.id())
+ .set(VXLAN_ID, osNet.segmentId())
+ .set(TENANT_ID, osNet.tenantId())
+ // TODO remove gateway IP from host annotation
+ .set(GATEWAY_IP, fixedIp.getValue().toString())
+ .set(CREATE_TIME, String.valueOf(System.currentTimeMillis()));
+
+ HostDescription hostDesc = new DefaultHostDescription(
+ osPort.macAddress(),
+ VlanId.NONE,
+ new HostLocation(connectPoint, System.currentTimeMillis()),
+ Sets.newHashSet(osPort.fixedIps().values()),
+ annotations.build());
+
+ HostId hostId = HostId.hostId(osPort.macAddress());
+ hostProvider.hostDetected(hostId, hostDesc, false);
+ }
+
+ private void processPortRemoved(Port port) {
+ ConnectPoint connectPoint = new ConnectPoint(port.element().id(), port.number());
+ removeHosts(connectPoint);
+ }
+
+ private void removeHosts(ConnectPoint connectPoint) {
+ hostService.getConnectedHosts(connectPoint).stream()
+ .forEach(host -> {
+ dhcpService.removeStaticMapping(host.mac());
+ hostProvider.hostVanished(host.id());
+ });
+ }
+
+ private void registerDhcpInfo(OpenstackPort openstackPort) {
+ checkNotNull(openstackPort);
+ checkArgument(!openstackPort.fixedIps().isEmpty());
+
+ OpenstackSubnet openstackSubnet = openstackService.subnets().stream()
+ .filter(n -> n.networkId().equals(openstackPort.networkId()))
+ .findFirst().orElse(null);
+ if (openstackSubnet == null) {
+ log.warn("Failed to find subnet for {}", openstackPort);
+ return;
+ }
+
+ Ip4Address ipAddress = openstackPort.fixedIps().values().stream().findFirst().get();
+ IpPrefix subnetPrefix = IpPrefix.valueOf(openstackSubnet.cidr());
+ Ip4Address broadcast = Ip4Address.makeMaskedAddress(
+ ipAddress,
+ subnetPrefix.prefixLength());
+
+ // TODO: supports multiple DNS servers
+ Ip4Address domainServer = openstackSubnet.dnsNameservers().isEmpty() ?
+ DNS_SERVER_IP : openstackSubnet.dnsNameservers().get(0);
+
+ IpAssignment ipAssignment = IpAssignment.builder()
+ .ipAddress(ipAddress)
+ .leasePeriod(DHCP_INFINITE_LEASE)
+ .timestamp(new Date())
+ .subnetMask(Ip4Address.makeMaskPrefix(subnetPrefix.prefixLength()))
+ .broadcast(broadcast)
+ .domainServer(domainServer)
+ .assignmentStatus(Option_RangeNotEnforced)
+ .routerAddress(Ip4Address.valueOf(openstackSubnet.gatewayIp()))
+ .build();
+
+ dhcpService.setStaticMapping(openstackPort.macAddress(), ipAssignment);
+ }
+
+ private class InternalDeviceListener implements DeviceListener {
+
+ @Override
+ public void event(DeviceEvent event) {
+ Device device = event.subject();
+ if (!mastershipService.isLocalMaster(device.id())) {
+ // do not allow to proceed without mastership
+ return;
+ }
+
+ Port port = event.port();
+ if (port == null) {
+ return;
+ }
+
+ String portName = port.annotations().value(PORT_NAME);
+ if (Strings.isNullOrEmpty(portName) ||
+ !portName.startsWith(PORT_NAME_PREFIX_VM)) {
+ // handles VM connected port event only
+ return;
+ }
+
+ switch (event.type()) {
+ case PORT_UPDATED:
+ if (!event.port().isEnabled()) {
+ deviceEventExecutor.execute(() -> processPortRemoved(event.port()));
+ }
+ break;
+ case PORT_ADDED:
+ deviceEventExecutor.execute(() -> processPortAdded(event.port()));
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ private class InternalOpenstackNodeListener implements OpenstackNodeListener {
+
+ @Override
+ public void event(OpenstackNodeEvent event) {
+ OpenstackNode node = event.node();
+ // TODO check leadership of the node and make only the leader process
+
+ switch (event.type()) {
+ case COMPLETE:
+ log.info("COMPLETE node {} detected", node.hostname());
+
+ // adds existing VMs running on the complete state node
+ deviceService.getPorts(node.intBridge()).stream()
+ .filter(port -> port.annotations().value(PORT_NAME)
+ .startsWith(PORT_NAME_PREFIX_VM) &&
+ port.isEnabled())
+ .forEach(port -> {
+ deviceEventExecutor.execute(() -> processPortAdded(port));
+ log.info("VM is detected on {}", port);
+ });
+
+ // removes stale VMs
+ hostService.getHosts().forEach(host -> {
+ if (deviceService.getPort(host.location().deviceId(),
+ host.location().port()) == null) {
+ deviceEventExecutor.execute(() -> removeHosts(host.location()));
+ log.info("Removed stale VM {}", host.location());
+ }
+ });
+ break;
+ case INCOMPLETE:
+ log.warn("{} is changed to INCOMPLETE state", node);
+ break;
+ case INIT:
+ case DEVICE_CREATED:
+ default:
+ break;
+ }
+ }
+ }
+}
diff --git a/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingManager.java b/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingManager.java
index 55fce2c..59b41ff 100644
--- a/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingManager.java
+++ b/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingManager.java
@@ -1,319 +1,273 @@
/*
- * 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.
- */
+* 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.switching;
-import com.google.common.base.Strings;
-import com.google.common.collect.Sets;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
-import org.apache.felix.scr.annotations.Service;
+import org.onlab.packet.Ethernet;
import org.onlab.packet.Ip4Address;
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.VlanId;
-import org.onosproject.core.CoreService;
-import org.onosproject.dhcp.DhcpService;
-import org.onosproject.dhcp.IpAssignment;
-import org.onosproject.mastership.MastershipService;
-import org.onosproject.net.ConnectPoint;
-import org.onosproject.net.DefaultAnnotations;
-import org.onosproject.net.Device;
+import org.onlab.packet.IpAddress;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.DeviceId;
import org.onosproject.net.Host;
-import org.onosproject.net.HostId;
-import org.onosproject.net.HostLocation;
-import org.onosproject.net.Port;
-import org.onosproject.net.device.DeviceEvent;
-import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.host.DefaultHostDescription;
-import org.onosproject.net.host.HostDescription;
-import org.onosproject.net.host.HostProvider;
-import org.onosproject.net.host.HostProviderRegistry;
-import org.onosproject.net.host.HostProviderService;
-import org.onosproject.net.host.HostService;
-import org.onosproject.net.provider.AbstractProvider;
-import org.onosproject.net.provider.ProviderId;
-import org.onosproject.openstackinterface.OpenstackInterfaceService;
-import org.onosproject.openstackinterface.OpenstackNetwork;
-import org.onosproject.openstackinterface.OpenstackPort;
-import org.onosproject.openstackinterface.OpenstackSubnet;
-import org.onosproject.openstacknode.OpenstackNode;
-import org.onosproject.openstacknode.OpenstackNodeEvent;
-import org.onosproject.openstacknode.OpenstackNodeListener;
+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.DefaultForwardingObjective;
+import org.onosproject.net.flowobjective.FlowObjectiveService;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.openstacknetworking.AbstractVmHandler;
import org.onosproject.openstacknode.OpenstackNodeService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.Date;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
+import java.util.Objects;
+import java.util.Optional;
-import static org.onlab.util.Tools.groupedThreads;
-import static org.onosproject.dhcp.IpAssignment.AssignmentStatus.Option_RangeNotEnforced;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.onosproject.net.AnnotationKeys.PORT_NAME;
import static org.onosproject.openstacknetworking.Constants.*;
+import static org.onosproject.openstacknetworking.RulePopulatorUtil.buildExtension;
-@Service
-@Component(immediate = true)
/**
- * Populates forwarding rules for VMs created by Openstack.
+ * Populates switching flow rules.
*/
-public final class OpenstackSwitchingManager extends AbstractProvider
- implements HostProvider {
+@Component(immediate = true)
+public final class OpenstackSwitchingManager extends AbstractVmHandler {
private final Logger log = LoggerFactory.getLogger(getClass());
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected CoreService coreService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceService deviceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected HostProviderRegistry hostProviderRegistry;
+ protected FlowObjectiveService flowObjectiveService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected DhcpService dhcpService;
+ protected OpenstackNodeService nodeService;
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected HostService hostService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected MastershipService mastershipService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected OpenstackInterfaceService openstackService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected OpenstackNodeService openstackNodeService;
-
- private final ExecutorService deviceEventExecutor =
- Executors.newSingleThreadExecutor(groupedThreads("onos/openstackswitching", "device-event"));
- private final ExecutorService configEventExecutor =
- Executors.newSingleThreadExecutor(groupedThreads("onos/openstackswitching", "config-event"));
- private final InternalDeviceListener internalDeviceListener = new InternalDeviceListener();
- private final InternalOpenstackNodeListener internalNodeListener = new InternalOpenstackNodeListener();
-
- private HostProviderService hostProvider;
-
- /**
- * Creates OpenStack switching host provider.
- */
- public OpenstackSwitchingManager() {
- super(new ProviderId("host", APP_ID));
- }
+ private ApplicationId appId;
@Activate
protected void activate() {
- coreService.registerApplication(APP_ID);
- deviceService.addListener(internalDeviceListener);
- openstackNodeService.addListener(internalNodeListener);
- hostProvider = hostProviderRegistry.register(this);
-
- log.info("Started");
+ super.activate();
+ appId = coreService.registerApplication(SWITCHING_APP_ID);
}
@Deactivate
protected void deactivate() {
- hostProviderRegistry.unregister(this);
- deviceService.removeListener(internalDeviceListener);
- openstackNodeService.removeListener(internalNodeListener);
+ super.deactivate();
+ }
- deviceEventExecutor.shutdown();
- configEventExecutor.shutdown();
+ private void populateSwitchingRules(Host host) {
+ populateFlowRulesForTunnelTag(host);
+ populateFlowRulesForTrafficToSameCnode(host);
+ populateFlowRulesForTrafficToDifferentCnode(host);
- log.info("Stopped");
+ log.debug("Populated switching rule for {}", host);
+ }
+
+ private void populateFlowRulesForTunnelTag(Host host) {
+ TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+ TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+
+ sBuilder.matchEthType(Ethernet.TYPE_IPV4)
+ .matchInPort(host.location().port());
+
+ tBuilder.setTunnelId(Long.valueOf(getVni(host)));
+
+ ForwardingObjective fo = DefaultForwardingObjective.builder()
+ .withSelector(sBuilder.build())
+ .withTreatment(tBuilder.build())
+ .withPriority(TUNNELTAG_RULE_PRIORITY)
+ .withFlag(ForwardingObjective.Flag.SPECIFIC)
+ .fromApp(appId)
+ .add();
+
+ flowObjectiveService.forward(host.location().deviceId(), fo);
+ }
+
+ private void populateFlowRulesForTrafficToSameCnode(Host host) {
+ //For L2 Switching Case
+ TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+ TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+
+ sBuilder.matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPDst(getIp(host).toIpPrefix())
+ .matchTunnelId(Long.valueOf(getVni(host)));
+
+ tBuilder.setOutput(host.location().port());
+
+ ForwardingObjective fo = DefaultForwardingObjective.builder()
+ .withSelector(sBuilder.build())
+ .withTreatment(tBuilder.build())
+ .withPriority(SWITCHING_RULE_PRIORITY)
+ .withFlag(ForwardingObjective.Flag.SPECIFIC)
+ .fromApp(appId)
+ .add();
+
+ flowObjectiveService.forward(host.location().deviceId(), fo);
+ }
+
+ private void populateFlowRulesForTrafficToDifferentCnode(Host host) {
+ Ip4Address localVmIp = getIp(host);
+ DeviceId localDeviceId = host.location().deviceId();
+ Optional<IpAddress> localDataIp = nodeService.dataIp(localDeviceId);
+
+ if (!localDataIp.isPresent()) {
+ log.debug("Failed to get data IP for device {}",
+ host.location().deviceId());
+ return;
+ }
+
+ String vni = getVni(host);
+ getVmsInDifferentCnode(host).forEach(remoteVm -> {
+ Optional<IpAddress> remoteDataIp = nodeService.dataIp(remoteVm.location().deviceId());
+ if (remoteDataIp.isPresent()) {
+ setVxLanFlowRule(vni,
+ localDeviceId,
+ remoteDataIp.get().getIp4Address(),
+ getIp(remoteVm));
+
+ setVxLanFlowRule(vni,
+ remoteVm.location().deviceId(),
+ localDataIp.get().getIp4Address(),
+ localVmIp);
+ }
+ });
+ }
+
+ private void setVxLanFlowRule(String vni, DeviceId deviceId, Ip4Address remoteIp,
+ Ip4Address vmIp) {
+ Optional<PortNumber> tunnelPort = nodeService.tunnelPort(deviceId);
+ if (!tunnelPort.isPresent()) {
+ log.warn("Failed to get tunnel port from {}", deviceId);
+ return;
+ }
+
+ TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+ TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+
+ sBuilder.matchEthType(Ethernet.TYPE_IPV4)
+ .matchTunnelId(Long.parseLong(vni))
+ .matchIPDst(vmIp.toIpPrefix());
+ tBuilder.extension(buildExtension(deviceService, deviceId, remoteIp), deviceId)
+ .setOutput(tunnelPort.get());
+
+ ForwardingObjective fo = DefaultForwardingObjective.builder()
+ .withSelector(sBuilder.build())
+ .withTreatment(tBuilder.build())
+ .withPriority(SWITCHING_RULE_PRIORITY)
+ .withFlag(ForwardingObjective.Flag.SPECIFIC)
+ .fromApp(appId)
+ .add();
+
+ flowObjectiveService.forward(deviceId, fo);
+ }
+
+ private void removeSwitchingRules(Host host) {
+ removeFlowRuleForTunnelTag(host);
+ removeFlowRuleForVMsInSameCnode(host);
+ removeFlowRuleForVMsInDiffrentCnode(host);
+
+ log.debug("Removed switching rule for {}", host);
+ }
+
+ private void removeFlowRuleForTunnelTag(Host host) {
+ TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+ TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+
+ sBuilder.matchEthType(Ethernet.TYPE_IPV4)
+ .matchInPort(host.location().port());
+
+ ForwardingObjective fo = DefaultForwardingObjective.builder()
+ .withSelector(sBuilder.build())
+ .withTreatment(tBuilder.build())
+ .withPriority(TUNNELTAG_RULE_PRIORITY)
+ .withFlag(ForwardingObjective.Flag.SPECIFIC)
+ .fromApp(appId)
+ .remove();
+
+ flowObjectiveService.forward(host.location().deviceId(), fo);
+ }
+
+ private void removeFlowRuleForVMsInSameCnode(Host host) {
+ TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+ sBuilder.matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPDst(getIp(host).toIpPrefix())
+ .matchTunnelId(Long.valueOf(getVni(host)));
+
+ ForwardingObjective fo = DefaultForwardingObjective.builder()
+ .withSelector(sBuilder.build())
+ .withTreatment(DefaultTrafficTreatment.builder().build())
+ .withFlag(ForwardingObjective.Flag.SPECIFIC)
+ .withPriority(SWITCHING_RULE_PRIORITY)
+ .fromApp(appId)
+ .remove();
+
+ flowObjectiveService.forward(host.location().deviceId(), fo);
+ }
+
+ private void removeFlowRuleForVMsInDiffrentCnode(Host host) {
+ DeviceId deviceId = host.location().deviceId();
+ final boolean anyPortRemainedInSameCnode = hostService.getConnectedHosts(deviceId)
+ .stream()
+ .filter(this::isValidHost)
+ .anyMatch(h -> Objects.equals(getVni(h), getVni(host)));
+
+ getVmsInDifferentCnode(host).forEach(h -> {
+ removeVxLanFlowRule(h.location().deviceId(), getIp(host), getVni(host));
+ if (!anyPortRemainedInSameCnode) {
+ removeVxLanFlowRule(deviceId, getIp(h), getVni(host));
+ }
+ });
+ }
+
+ private void removeVxLanFlowRule(DeviceId deviceId, Ip4Address vmIp, String vni) {
+ TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+
+ sBuilder.matchEthType(Ethernet.TYPE_IPV4)
+ .matchTunnelId(Long.valueOf(vni))
+ .matchIPDst(vmIp.toIpPrefix());
+
+ ForwardingObjective fo = DefaultForwardingObjective.builder()
+ .withSelector(sBuilder.build())
+ .withTreatment(DefaultTrafficTreatment.builder().build())
+ .withFlag(ForwardingObjective.Flag.SPECIFIC)
+ .withPriority(SWITCHING_RULE_PRIORITY)
+ .fromApp(appId)
+ .remove();
+
+ flowObjectiveService.forward(deviceId, fo);
}
@Override
- public void triggerProbe(Host host) {
- // no probe is required
+ protected void hostDetected(Host host) {
+ populateSwitchingRules(host);
+ log.info("Added new virtual machine to switching service {}", host);
}
- private void processPortAdded(Port port) {
- // TODO check the node state is COMPLETE
- OpenstackPort osPort = openstackService.port(port);
- if (osPort == null) {
- log.warn("Failed to get OpenStack port for {}", port);
- return;
- }
-
- OpenstackNetwork osNet = openstackService.network(osPort.networkId());
- if (osNet == null) {
- log.warn("Failed to get OpenStack network {}",
- osPort.networkId());
- return;
- }
-
- registerDhcpInfo(osPort);
- ConnectPoint connectPoint = new ConnectPoint(port.element().id(), port.number());
- // TODO remove this and openstackPortInfo
- String gatewayIp = osNet.subnets().stream().findFirst().get().gatewayIp();
-
- // Added CREATE_TIME intentionally to trigger HOST_UPDATED event for the
- // existing instances.
- DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
- .set(NETWORK_ID, osPort.networkId())
- .set(PORT_ID, osPort.id())
- .set(VXLAN_ID, osNet.segmentId())
- .set(TENANT_ID, osNet.tenantId())
- // TODO remove this and openstackPortInfo
- .set(GATEWAY_IP, gatewayIp)
- .set(CREATE_TIME, String.valueOf(System.currentTimeMillis()));
-
- HostDescription hostDesc = new DefaultHostDescription(
- osPort.macAddress(),
- VlanId.NONE,
- new HostLocation(connectPoint, System.currentTimeMillis()),
- Sets.newHashSet(osPort.fixedIps().values()),
- annotations.build());
-
- HostId hostId = HostId.hostId(osPort.macAddress());
- hostProvider.hostDetected(hostId, hostDesc, false);
- }
-
- private void processPortRemoved(Port port) {
- ConnectPoint connectPoint = new ConnectPoint(port.element().id(), port.number());
- removeHosts(connectPoint);
- }
-
- private void removeHosts(ConnectPoint connectPoint) {
- hostService.getConnectedHosts(connectPoint).stream()
- .forEach(host -> {
- dhcpService.removeStaticMapping(host.mac());
- hostProvider.hostVanished(host.id());
- });
- }
-
- private void registerDhcpInfo(OpenstackPort openstackPort) {
- checkNotNull(openstackPort);
- checkArgument(!openstackPort.fixedIps().isEmpty());
-
- OpenstackSubnet openstackSubnet = openstackService.subnets().stream()
- .filter(n -> n.networkId().equals(openstackPort.networkId()))
- .findFirst().orElse(null);
- if (openstackSubnet == null) {
- log.warn("Failed to find subnet for {}", openstackPort);
- return;
- }
-
- Ip4Address ipAddress = openstackPort.fixedIps().values().stream().findFirst().get();
- IpPrefix subnetPrefix = IpPrefix.valueOf(openstackSubnet.cidr());
- Ip4Address broadcast = Ip4Address.makeMaskedAddress(
- ipAddress,
- subnetPrefix.prefixLength());
-
- // TODO: supports multiple DNS servers
- Ip4Address domainServer = openstackSubnet.dnsNameservers().isEmpty() ?
- DNS_SERVER_IP : openstackSubnet.dnsNameservers().get(0);
-
- IpAssignment ipAssignment = IpAssignment.builder()
- .ipAddress(ipAddress)
- .leasePeriod(DHCP_INFINITE_LEASE)
- .timestamp(new Date())
- .subnetMask(Ip4Address.makeMaskPrefix(subnetPrefix.prefixLength()))
- .broadcast(broadcast)
- .domainServer(domainServer)
- .assignmentStatus(Option_RangeNotEnforced)
- .routerAddress(Ip4Address.valueOf(openstackSubnet.gatewayIp()))
- .build();
-
- dhcpService.setStaticMapping(openstackPort.macAddress(), ipAssignment);
- }
-
- private class InternalDeviceListener implements DeviceListener {
-
- @Override
- public void event(DeviceEvent event) {
- Device device = event.subject();
- if (!mastershipService.isLocalMaster(device.id())) {
- // do not allow to proceed without mastership
- return;
- }
-
- Port port = event.port();
- if (port == null) {
- return;
- }
-
- String portName = port.annotations().value(PORT_NAME);
- if (Strings.isNullOrEmpty(portName) ||
- !portName.startsWith(PORTNAME_PREFIX_VM)) {
- // handles VM connected port event only
- return;
- }
-
- switch (event.type()) {
- case PORT_UPDATED:
- if (!event.port().isEnabled()) {
- deviceEventExecutor.execute(() -> processPortRemoved(event.port()));
- }
- break;
- case PORT_ADDED:
- deviceEventExecutor.execute(() -> processPortAdded(event.port()));
- break;
- default:
- break;
- }
- }
- }
-
- private class InternalOpenstackNodeListener implements OpenstackNodeListener {
-
- @Override
- public void event(OpenstackNodeEvent event) {
- OpenstackNode node = event.node();
- // TODO check leadership of the node and make only the leader process
-
- switch (event.type()) {
- case COMPLETE:
- log.info("COMPLETE node {} detected", node.hostname());
-
- // adds existing VMs running on the complete state node
- deviceService.getPorts(node.intBridge()).stream()
- .filter(port -> port.annotations().value(PORT_NAME)
- .startsWith(PORTNAME_PREFIX_VM) &&
- port.isEnabled())
- .forEach(port -> {
- deviceEventExecutor.execute(() -> processPortAdded(port));
- log.info("VM is detected on {}", port);
- });
-
- // removes stale VMs
- hostService.getHosts().forEach(host -> {
- if (deviceService.getPort(host.location().deviceId(),
- host.location().port()) == null) {
- deviceEventExecutor.execute(() -> removeHosts(host.location()));
- log.info("Removed stale VM {}", host.location());
- }
- });
- break;
- case INCOMPLETE:
- log.warn("{} is changed to INCOMPLETE state", node);
- break;
- case INIT:
- case DEVICE_CREATED:
- default:
- break;
- }
- }
+ @Override
+ protected void hostRemoved(Host host) {
+ removeSwitchingRules(host);
+ log.info("Removed virtual machine from switching service {}", host);
}
}
diff --git a/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingRulePopulator.java b/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingRulePopulator.java
deleted file mode 100644
index b3707a8..0000000
--- a/apps/openstacknetworking/switching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingRulePopulator.java
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
-* 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.switching;
-
-import org.apache.felix.scr.annotations.Activate;
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Deactivate;
-import org.apache.felix.scr.annotations.Reference;
-import org.apache.felix.scr.annotations.ReferenceCardinality;
-import org.onlab.packet.Ethernet;
-import org.onlab.packet.Ip4Address;
-import org.onlab.packet.IpAddress;
-import org.onosproject.net.Device;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Host;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
-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.instructions.ExtensionTreatment;
-import org.onosproject.net.flow.instructions.ExtensionPropertyException;
-import org.onosproject.net.flowobjective.DefaultForwardingObjective;
-import org.onosproject.net.flowobjective.FlowObjectiveService;
-import org.onosproject.net.flowobjective.ForwardingObjective;
-import org.onosproject.openstacknode.OpenstackNodeService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.Objects;
-import java.util.Optional;
-
-import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
-import static org.onosproject.openstacknetworking.Constants.*;
-
-/**
- * Populates switching flow rules.
- */
-@Component(immediate = true)
-public final class OpenstackSwitchingRulePopulator extends AbstractVmHandler {
-
- private final Logger log = LoggerFactory.getLogger(getClass());
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected DeviceService deviceService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected FlowObjectiveService flowObjectiveService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected OpenstackNodeService nodeService;
-
-
- private static final String TUNNEL_DST = "tunnelDst";
-
- @Activate
- protected void activate() {
- super.activate();
- }
-
- @Deactivate
- protected void deactivate() {
- super.deactivate();
- }
-
- private void populateSwitchingRules(Host host) {
- populateFlowRulesForTunnelTag(host);
- populateFlowRulesForTrafficToSameCnode(host);
- populateFlowRulesForTrafficToDifferentCnode(host);
-
- log.debug("Populated switching rule for {}", host);
- }
-
- private void populateFlowRulesForTunnelTag(Host host) {
- TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
-
- sBuilder.matchEthType(Ethernet.TYPE_IPV4)
- .matchInPort(host.location().port());
-
- tBuilder.setTunnelId(Long.valueOf(getVni(host)));
-
- ForwardingObjective fo = DefaultForwardingObjective.builder()
- .withSelector(sBuilder.build())
- .withTreatment(tBuilder.build())
- .withPriority(TUNNELTAG_RULE_PRIORITY)
- .withFlag(ForwardingObjective.Flag.SPECIFIC)
- .fromApp(appId)
- .add();
-
- flowObjectiveService.forward(host.location().deviceId(), fo);
- }
-
- private void populateFlowRulesForTrafficToSameCnode(Host host) {
- //For L2 Switching Case
- TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
-
- sBuilder.matchEthType(Ethernet.TYPE_IPV4)
- .matchIPDst(getIp(host).toIpPrefix())
- .matchTunnelId(Long.valueOf(getVni(host)));
-
- tBuilder.setOutput(host.location().port());
-
- ForwardingObjective fo = DefaultForwardingObjective.builder()
- .withSelector(sBuilder.build())
- .withTreatment(tBuilder.build())
- .withPriority(SWITCHING_RULE_PRIORITY)
- .withFlag(ForwardingObjective.Flag.SPECIFIC)
- .fromApp(appId)
- .add();
-
- flowObjectiveService.forward(host.location().deviceId(), fo);
- }
-
- private void populateFlowRulesForTrafficToDifferentCnode(Host host) {
- Ip4Address localVmIp = getIp(host);
- DeviceId localDeviceId = host.location().deviceId();
- Optional<IpAddress> localDataIp = nodeService.dataIp(localDeviceId);
-
- if (!localDataIp.isPresent()) {
- log.debug("Failed to get data IP for device {}",
- host.location().deviceId());
- return;
- }
-
- String vni = getVni(host);
- getVmsInDifferentCnode(host).forEach(remoteVm -> {
- Optional<IpAddress> remoteDataIp = nodeService.dataIp(remoteVm.location().deviceId());
- if (remoteDataIp.isPresent()) {
- setVxLanFlowRule(vni,
- localDeviceId,
- remoteDataIp.get().getIp4Address(),
- getIp(remoteVm));
-
- setVxLanFlowRule(vni,
- remoteVm.location().deviceId(),
- localDataIp.get().getIp4Address(),
- localVmIp);
- }
- });
- }
-
- private void setVxLanFlowRule(String vni, DeviceId deviceId, Ip4Address remoteIp,
- Ip4Address vmIp) {
- Optional<PortNumber> tunnelPort = nodeService.tunnelPort(deviceId);
- if (!tunnelPort.isPresent()) {
- log.warn("Failed to get tunnel port from {}", deviceId);
- return;
- }
-
- TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
-
- sBuilder.matchEthType(Ethernet.TYPE_IPV4)
- .matchTunnelId(Long.parseLong(vni))
- .matchIPDst(vmIp.toIpPrefix());
- tBuilder.extension(buildNiciraExtenstion(deviceId, remoteIp), deviceId)
- .setOutput(tunnelPort.get());
-
- ForwardingObjective fo = DefaultForwardingObjective.builder()
- .withSelector(sBuilder.build())
- .withTreatment(tBuilder.build())
- .withPriority(SWITCHING_RULE_PRIORITY)
- .withFlag(ForwardingObjective.Flag.SPECIFIC)
- .fromApp(appId)
- .add();
-
- flowObjectiveService.forward(deviceId, fo);
- }
-
- private void removeSwitchingRules(Host host) {
- removeFlowRuleForTunnelTag(host);
- removeFlowRuleForVMsInSameCnode(host);
- removeFlowRuleForVMsInDiffrentCnode(host);
-
- log.debug("Removed switching rule for {}", host);
- }
-
- private void removeFlowRuleForTunnelTag(Host host) {
- TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
-
- sBuilder.matchEthType(Ethernet.TYPE_IPV4)
- .matchInPort(host.location().port());
-
- ForwardingObjective fo = DefaultForwardingObjective.builder()
- .withSelector(sBuilder.build())
- .withTreatment(tBuilder.build())
- .withPriority(TUNNELTAG_RULE_PRIORITY)
- .withFlag(ForwardingObjective.Flag.SPECIFIC)
- .fromApp(appId)
- .remove();
-
- flowObjectiveService.forward(host.location().deviceId(), fo);
- }
-
- private void removeFlowRuleForVMsInSameCnode(Host host) {
- TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
- sBuilder.matchEthType(Ethernet.TYPE_IPV4)
- .matchIPDst(getIp(host).toIpPrefix())
- .matchTunnelId(Long.valueOf(getVni(host)));
-
- ForwardingObjective fo = DefaultForwardingObjective.builder()
- .withSelector(sBuilder.build())
- .withTreatment(DefaultTrafficTreatment.builder().build())
- .withFlag(ForwardingObjective.Flag.SPECIFIC)
- .withPriority(SWITCHING_RULE_PRIORITY)
- .fromApp(appId)
- .remove();
-
- flowObjectiveService.forward(host.location().deviceId(), fo);
- }
-
- private void removeFlowRuleForVMsInDiffrentCnode(Host host) {
- DeviceId deviceId = host.location().deviceId();
- final boolean anyPortRemainedInSameCnode = hostService.getConnectedHosts(deviceId)
- .stream()
- .filter(this::isValidHost)
- .anyMatch(h -> Objects.equals(getVni(h), getVni(host)));
-
- getVmsInDifferentCnode(host).forEach(h -> {
- removeVxLanFlowRule(h.location().deviceId(), getIp(host), getVni(host));
- if (!anyPortRemainedInSameCnode) {
- removeVxLanFlowRule(deviceId, getIp(h), getVni(host));
- }
- });
- }
-
- private void removeVxLanFlowRule(DeviceId deviceId, Ip4Address vmIp, String vni) {
- TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
-
- sBuilder.matchEthType(Ethernet.TYPE_IPV4)
- .matchTunnelId(Long.valueOf(vni))
- .matchIPDst(vmIp.toIpPrefix());
-
- ForwardingObjective fo = DefaultForwardingObjective.builder()
- .withSelector(sBuilder.build())
- .withTreatment(DefaultTrafficTreatment.builder().build())
- .withFlag(ForwardingObjective.Flag.SPECIFIC)
- .withPriority(SWITCHING_RULE_PRIORITY)
- .fromApp(appId)
- .remove();
-
- flowObjectiveService.forward(deviceId, fo);
- }
-
- private ExtensionTreatment buildNiciraExtenstion(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;
- }
- }
-
- @Override
- protected void hostDetected(Host host) {
- populateSwitchingRules(host);
- log.info("Added new virtual machine to switching service {}", host);
- }
-
- @Override
- protected void hostRemoved(Host host) {
- removeSwitchingRules(host);
- log.info("Removed virtual machine from switching service {}", host);
- }
-}
diff --git a/apps/openstacknetworking/web/src/main/java/org/onosproject/openstacknetworking/web/OpensatckRouterWebResource.java b/apps/openstacknetworking/web/src/main/java/org/onosproject/openstacknetworking/web/OpensatckRouterWebResource.java
index d73ff4f..3d66674 100644
--- a/apps/openstacknetworking/web/src/main/java/org/onosproject/openstacknetworking/web/OpensatckRouterWebResource.java
+++ b/apps/openstacknetworking/web/src/main/java/org/onosproject/openstacknetworking/web/OpensatckRouterWebResource.java
@@ -126,7 +126,7 @@
OpenstackRoutingService routingService
= getService(OpenstackRoutingService.class);
- routingService.updateRouterInterface(openstackRouterInterface);
+ routingService.addRouterInterface(openstackRouterInterface);
log.debug("REST API AddRouterInterface is called from router {} portId: {}, subnetId: {}, tenantId: {}",
openstackRouterInterface.id(), openstackRouterInterface.portId(),
@@ -147,7 +147,7 @@
checkNotNull(id);
OpenstackRoutingService routingService
= getService(OpenstackRoutingService.class);
- routingService.deleteRouter(id);
+ routingService.removeRouter(id);
log.debug("REST API DELETE routers is called {}", id);
return Response.noContent().build();
diff --git a/apps/openstacknetworking/web/src/main/java/org/onosproject/openstacknetworking/web/OpenstackFloatingIpWebResource.java b/apps/openstacknetworking/web/src/main/java/org/onosproject/openstacknetworking/web/OpenstackFloatingIpWebResource.java
index bd6c2c9..3382620 100644
--- a/apps/openstacknetworking/web/src/main/java/org/onosproject/openstacknetworking/web/OpenstackFloatingIpWebResource.java
+++ b/apps/openstacknetworking/web/src/main/java/org/onosproject/openstacknetworking/web/OpenstackFloatingIpWebResource.java
@@ -20,7 +20,7 @@
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onosproject.openstackinterface.OpenstackFloatingIP;
import org.onosproject.openstackinterface.web.OpenstackFloatingIpCodec;
-import org.onosproject.openstacknetworking.OpenstackRoutingService;
+import org.onosproject.openstacknetworking.OpenstackFloatingIpService;
import org.onosproject.rest.AbstractWebResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -45,8 +45,7 @@
public class OpenstackFloatingIpWebResource extends AbstractWebResource {
private final Logger log = LoggerFactory.getLogger(getClass());
- private static final OpenstackFloatingIpCodec FLOATING_IP_CODEC
- = new OpenstackFloatingIpCodec();
+ private static final OpenstackFloatingIpCodec FLOATING_IP_CODEC = new OpenstackFloatingIpCodec();
/**
* Create FloatingIP.
@@ -64,20 +63,15 @@
ObjectMapper mapper = new ObjectMapper();
ObjectNode floatingIpNode = (ObjectNode) mapper.readTree(input);
- OpenstackFloatingIP osFloatingIp =
- FLOATING_IP_CODEC.decode(floatingIpNode, this);
-
- OpenstackRoutingService routingService =
- getService(OpenstackRoutingService.class);
-
- routingService.createFloatingIP(osFloatingIp);
+ OpenstackFloatingIP osFloatingIp = FLOATING_IP_CODEC.decode(floatingIpNode, this);
+ OpenstackFloatingIpService floatingIpService =
+ getService(OpenstackFloatingIpService.class);
+ floatingIpService.createFloatingIp(osFloatingIp);
log.debug("REST API CREATE floatingip called");
-
return Response.status(Response.Status.OK).build();
} catch (Exception e) {
log.error("createFloatingIp failed with {}", e.toString());
-
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString())
.build();
}
@@ -102,20 +96,15 @@
ObjectMapper mapper = new ObjectMapper();
ObjectNode floatingIpNode = (ObjectNode) mapper.readTree(input);
- OpenstackFloatingIP osFloatingIp =
- FLOATING_IP_CODEC.decode(floatingIpNode, this);
-
- OpenstackRoutingService routingService =
- getService(OpenstackRoutingService.class);
-
- routingService.updateFloatingIP(osFloatingIp);
+ OpenstackFloatingIP osFloatingIp = FLOATING_IP_CODEC.decode(floatingIpNode, this);
+ OpenstackFloatingIpService floatingIpService =
+ getService(OpenstackFloatingIpService.class);
+ floatingIpService.updateFloatingIp(osFloatingIp);
log.debug("REST API UPDATE floatingip called {}", id);
-
return Response.status(Response.Status.OK).build();
} catch (Exception e) {
log.error("updateFloatingIp failed with {}", e.toString());
-
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString())
.build();
}
@@ -133,12 +122,11 @@
public Response deleteFloatingIp(@PathParam("id") String id) {
checkNotNull(id);
- OpenstackRoutingService routingService =
- getService(OpenstackRoutingService.class);
- routingService.deleteFloatingIP(id);
+ OpenstackFloatingIpService floatingIpService =
+ getService(OpenstackFloatingIpService.class);
+ floatingIpService.deleteFloatingIp(id);
log.debug("REST API DELETE floatingip is called {}", id);
-
return Response.noContent().build();
}
diff --git a/apps/openstacknetworking/web/src/main/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResource.java b/apps/openstacknetworking/web/src/main/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResource.java
index 4dd2533..87dd4a3 100644
--- a/apps/openstacknetworking/web/src/main/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResource.java
+++ b/apps/openstacknetworking/web/src/main/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResource.java
@@ -79,7 +79,6 @@
sgService.updateSecurityGroup(osPort);
return Response.status(Response.Status.OK).build();
-
} catch (IOException e) {
log.error("UpdatePort post process failed due to {}", e.getMessage());
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNode.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNode.java
index 42edd72..2d73a85 100644
--- a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNode.java
+++ b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNode.java
@@ -28,6 +28,7 @@
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.openstacknode.Constants.PATCH_INTG_BRIDGE;
import static org.onosproject.openstacknode.OpenstackNodeEvent.NodeState.INIT;
/**
@@ -182,6 +183,20 @@
return DeviceId.deviceId("ovsdb:" + managementIp.toString());
}
+ /**
+ * Returns the name of the port connected to the external network.
+ * It returns valid value only if the node is gateway node.
+ *
+ * @return external port name
+ */
+ public Optional<String> externalPortName() {
+ if (type == NodeType.GATEWAY) {
+ return Optional.of(PATCH_INTG_BRIDGE);
+ } else {
+ return Optional.empty();
+ }
+ }
+
@Override
public boolean equals(Object obj) {
if (this == obj) {