Added FLAT type network
Change-Id: I9b81adac1193cc2f133072683a0c970d2834c157
diff --git a/src/main/java/org/opencord/cordvtn/api/net/ServiceNetwork.java b/src/main/java/org/opencord/cordvtn/api/net/ServiceNetwork.java
index 122ccfe..3a00a3d 100644
--- a/src/main/java/org/opencord/cordvtn/api/net/ServiceNetwork.java
+++ b/src/main/java/org/opencord/cordvtn/api/net/ServiceNetwork.java
@@ -26,13 +26,46 @@
public interface ServiceNetwork {
enum NetworkType {
+ /**
+ * Isolated tenant network.
+ */
PRIVATE,
+ /**
+ * Provider network that offers connectivity to external network via L3.
+ * This network relies on the physical network infrastructure or vRouter
+ * for gateway and first hop routing service.
+ */
PUBLIC,
+ /**
+ * Provider network that offers connectivity to the physical network via L2.
+ * This network runs over the physical data network and allows physical
+ * machines and virtual instances in a same broadcast domain.
+ */
+ FLAT,
+ /**
+ * Virtual instance management network that offers connectivity to head node.
+ * This network runs over the physical management network, and cannot be
+ * part of service chain.
+ */
MANAGEMENT_HOST,
+ /**
+ * Virtual instance management network that offers limited connectivity
+ * between the virtual instance and the host machine.
+ * This network does not span compute nodes, and cannot be part of
+ * service chain.
+ */
MANAGEMENT_LOCAL,
+ /**
+ * Special network for R-CORD vSG.
+ * This network type is deprecated in favor of ServicePort VLAN.
+ */
@Deprecated
VSG,
- ACCESS_AGENT
+ /**
+ * Special network for R-CORD access agent.
+ * This network cannot be part of service chain.
+ */
+ ACCESS_AGENT,
}
enum DependencyType {
diff --git a/src/main/java/org/opencord/cordvtn/impl/CordVtnArpProxy.java b/src/main/java/org/opencord/cordvtn/impl/CordVtnArpProxy.java
index 192a16e..e507de5 100644
--- a/src/main/java/org/opencord/cordvtn/impl/CordVtnArpProxy.java
+++ b/src/main/java/org/opencord/cordvtn/impl/CordVtnArpProxy.java
@@ -60,8 +60,10 @@
import org.opencord.cordvtn.api.core.ServiceNetworkListener;
import org.opencord.cordvtn.api.core.ServiceNetworkService;
import org.opencord.cordvtn.api.net.ServiceNetwork;
+import org.opencord.cordvtn.api.net.ServiceNetwork.NetworkType;
import org.opencord.cordvtn.api.node.CordVtnNode;
import org.opencord.cordvtn.api.node.CordVtnNodeService;
+import org.opencord.cordvtn.api.node.CordVtnNodeState;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
@@ -259,8 +261,7 @@
getMacFromHostService(targetIp);
if (replyMac.equals(MacAddress.NONE)) {
- log.trace("Failed to find MAC for {}", targetIp);
- forwardManagementArpRequest(context, ethPacket);
+ forwardArpRequest(context, ethPacket);
return;
}
@@ -310,33 +311,46 @@
context.block();
}
- private void forwardManagementArpRequest(PacketContext context, Ethernet ethPacket) {
+ private void forwardArpRequest(PacketContext context, Ethernet ethPacket) {
DeviceId deviceId = context.inPacket().receivedFrom().deviceId();
- PortNumber hostMgmtPort = hostMgmtPort(deviceId);
- Host host = hostService.getHost(HostId.hostId(ethPacket.getSourceMAC()));
+ PortNumber inputPort = context.inPacket().receivedFrom().port();
- if (host == null ||
- Instance.of(host).netType() != MANAGEMENT_HOST ||
- hostMgmtPort == null) {
+ Host host = hostService.getHost(HostId.hostId(ethPacket.getSourceMAC()));
+ NetworkType networkType = Instance.of(host).netType();
+ if (host == null || (networkType != MANAGEMENT_HOST &&
+ networkType != FLAT)) {
+ context.block();
+ log.trace("Failed to handle ARP request");
+ return;
+ }
+
+ PortNumber outputPort = networkType == MANAGEMENT_HOST ?
+ hostMgmtPort(deviceId) : dataPort(deviceId);
+ if (inputPort.equals(outputPort)) {
context.block();
return;
}
- TrafficTreatment treatment = DefaultTrafficTreatment.builder()
- .setOutput(hostMgmtPort)
- .build();
+ if (outputPort != null) {
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(outputPort)
+ .build();
- packetService.emit(new DefaultOutboundPacket(
- context.inPacket().receivedFrom().deviceId(),
- treatment,
- ByteBuffer.wrap(ethPacket.serialize())));
+ packetService.emit(new DefaultOutboundPacket(
+ context.inPacket().receivedFrom().deviceId(),
+ treatment,
+ ByteBuffer.wrap(ethPacket.serialize())));
+ } else {
+ log.trace("Failed to handle ARP request");
+ }
context.block();
}
private PortNumber hostMgmtPort(DeviceId deviceId) {
CordVtnNode node = nodeService.node(deviceId);
- if (node == null || node.hostManagementInterface() == null) {
+ if (node == null || node.state() != CordVtnNodeState.COMPLETE ||
+ node.hostManagementInterface() == null) {
return null;
}
Optional<Port> port = deviceService.getPorts(deviceId).stream()
@@ -344,7 +358,21 @@
.equals(node.hostManagementInterface()) &&
p.isEnabled())
.findAny();
- return port.isPresent() ? port.get().number() : null;
+ return port.map(Port::number).orElse(null);
+ }
+
+ private PortNumber dataPort(DeviceId deviceId) {
+ CordVtnNode node = nodeService.node(deviceId);
+ if (node == null || node.state() != CordVtnNodeState.COMPLETE ||
+ node.dataInterface() == null) {
+ return null;
+ }
+ Optional<Port> port = deviceService.getPorts(deviceId).stream()
+ .filter(p -> p.annotations().value(PORT_NAME)
+ .equals(node.dataInterface()) &&
+ p.isEnabled())
+ .findAny();
+ return port.map(Port::number).orElse(null);
}
/**
@@ -465,8 +493,17 @@
ServiceNetwork snet = event.subject();
switch (event.type()) {
case SERVICE_NETWORK_CREATED:
+ if (snet.type() == PRIVATE || snet.type() == VSG) {
+ addGateway(snet.serviceIp(), privateGatewayMac);
+ }
+ break;
case SERVICE_NETWORK_UPDATED:
- addGateway(snet.serviceIp(), privateGatewayMac);
+ if (snet.type() == PRIVATE || snet.type() == VSG) {
+ addGateway(snet.serviceIp(), privateGatewayMac);
+ } else {
+ // don't service ARP for the other network gateway
+ removeGateway(snet.serviceIp());
+ }
break;
case SERVICE_NETWORK_REMOVED:
removeGateway(snet.serviceIp());
@@ -488,9 +525,7 @@
return;
}
- config.publicGateways().entrySet().forEach(entry -> {
- addGateway(entry.getKey(), entry.getValue());
- });
+ config.publicGateways().forEach(this::addGateway);
// TODO send gratuitous arp in case the MAC is changed
}
diff --git a/src/main/java/org/opencord/cordvtn/impl/handler/FlatInstanceHandler.java b/src/main/java/org/opencord/cordvtn/impl/handler/FlatInstanceHandler.java
new file mode 100644
index 0000000..6c2c6f4
--- /dev/null
+++ b/src/main/java/org/opencord/cordvtn/impl/handler/FlatInstanceHandler.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opencord.cordvtn.impl.handler;
+
+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;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.flow.DefaultFlowRule;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.opencord.cordvtn.api.core.CordVtnPipeline;
+import org.opencord.cordvtn.api.core.Instance;
+import org.opencord.cordvtn.api.core.InstanceHandler;
+import org.opencord.cordvtn.api.core.ServiceNetworkService;
+import org.opencord.cordvtn.api.net.ServiceNetwork;
+import org.opencord.cordvtn.api.node.CordVtnNodeService;
+
+import static org.opencord.cordvtn.api.core.CordVtnPipeline.PRIORITY_DEFAULT;
+import static org.opencord.cordvtn.api.core.CordVtnPipeline.TABLE_ACCESS;
+import static org.opencord.cordvtn.api.core.CordVtnPipeline.TABLE_DST;
+import static org.opencord.cordvtn.api.net.ServiceNetwork.NetworkType.FLAT;
+
+/**
+ * Provides provider network connectivity to the instance.
+ */
+@Component(immediate = true)
+public class FlatInstanceHandler extends AbstractInstanceHandler implements InstanceHandler {
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected ServiceNetworkService snetService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CordVtnNodeService nodeService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CordVtnPipeline pipeline;
+
+ @Activate
+ protected void activate() {
+ netTypes = ImmutableSet.of(FLAT);
+ super.activate();
+ }
+
+ @Deactivate
+ protected void deactivate() {
+ super.deactivate();
+ }
+
+ @Override
+ public void instanceDetected(Instance instance) {
+ log.info("FLAT network instance is detected {}", instance);
+
+ ServiceNetwork snet = snetService.serviceNetwork(instance.netId());
+ populateDstIpRule(instance, true);
+ populateDstRangeRule(instance.deviceId(),
+ getServiceNetwork(instance).subnet(), true);
+ populateDirectAccessRule(snet.subnet(), true);
+ populateIsolationRule(snet.subnet(), true);
+ populateInPortRule(instance, true);
+ }
+
+ @Override
+ public void instanceRemoved(Instance instance) {
+ log.info("FLAT network instance is removed {}", instance);
+
+ populateDstIpRule(instance, false);
+ if (getInstances(instance.netId()).isEmpty()) {
+ populateDstRangeRule(instance.deviceId(),
+ getServiceNetwork(instance).subnet(), false);
+ ServiceNetwork snet = snetService.serviceNetwork(instance.netId());
+ populateDirectAccessRule(snet.subnet(), false);
+ populateIsolationRule(snet.subnet(), false);
+ }
+ populateInPortRule(instance, false);
+ }
+
+ private void populateInPortRule(Instance instance, boolean install) {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchInPort(instance.portNumber())
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPSrc(instance.ipAddress().toIpPrefix())
+ .build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .transition(CordVtnPipeline.TABLE_ACCESS)
+ .build();
+
+ FlowRule flowRule = DefaultFlowRule.builder()
+ .fromApp(appId)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .withPriority(CordVtnPipeline.PRIORITY_DEFAULT)
+ .forDevice(instance.deviceId())
+ .forTable(CordVtnPipeline.TABLE_IN_PORT)
+ .makePermanent()
+ .build();
+
+ pipeline.processFlowRule(install, flowRule);
+
+ selector = DefaultTrafficSelector.builder()
+ .matchInPort(instance.portNumber())
+ .build();
+
+ treatment = DefaultTrafficTreatment.builder()
+ .transition(CordVtnPipeline.TABLE_IN_SERVICE)
+ .build();
+
+ flowRule = DefaultFlowRule.builder()
+ .fromApp(appId)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .withPriority(CordVtnPipeline.PRIORITY_LOW)
+ .forDevice(instance.deviceId())
+ .forTable(CordVtnPipeline.TABLE_IN_PORT)
+ .makePermanent()
+ .build();
+
+ pipeline.processFlowRule(install, flowRule);
+ }
+
+ private void populateDirectAccessRule(IpPrefix serviceIpRange, boolean install) {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPSrc(serviceIpRange)
+ .matchIPDst(serviceIpRange)
+ .build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .transition(TABLE_DST)
+ .build();
+
+ nodeService.completeNodes().forEach(node -> {
+ DeviceId deviceId = node.integrationBridgeId();
+ FlowRule flowRuleDirect = DefaultFlowRule.builder()
+ .fromApp(appId)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .withPriority(PRIORITY_DEFAULT)
+ .forDevice(deviceId)
+ .forTable(TABLE_ACCESS)
+ .makePermanent()
+ .build();
+
+ pipeline.processFlowRule(install, flowRuleDirect);
+ });
+ }
+
+ private void populateIsolationRule(IpPrefix serviceIpRange, boolean install) {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPDst(serviceIpRange)
+ .build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .drop()
+ .build();
+
+ nodeService.completeNodes().forEach(node -> {
+ FlowRule flowRuleDirect = DefaultFlowRule.builder()
+ .fromApp(appId)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .withPriority(CordVtnPipeline.PRIORITY_LOW)
+ .forDevice(node.integrationBridgeId())
+ .forTable(CordVtnPipeline.TABLE_ACCESS)
+ .makePermanent()
+ .build();
+
+ pipeline.processFlowRule(install, flowRuleDirect);
+ });
+ }
+
+ private void populateDstIpRule(Instance instance, boolean install) {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPDst(instance.ipAddress().toIpPrefix())
+ .build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(instance.portNumber())
+ .build();
+
+ FlowRule flowRule = DefaultFlowRule.builder()
+ .fromApp(appId)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .withPriority(CordVtnPipeline.PRIORITY_DEFAULT)
+ .forDevice(instance.deviceId())
+ .forTable(CordVtnPipeline.TABLE_DST)
+ .makePermanent()
+ .build();
+
+ pipeline.processFlowRule(install, flowRule);
+ }
+
+ private void populateDstRangeRule(DeviceId deviceId, IpPrefix dstIpRange, boolean install) {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPDst(dstIpRange)
+ .build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(dataPort(deviceId))
+ .build();
+
+ FlowRule flowRule = DefaultFlowRule.builder()
+ .fromApp(appId)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .withPriority(CordVtnPipeline.PRIORITY_LOW)
+ .forDevice(deviceId)
+ .forTable(CordVtnPipeline.TABLE_DST)
+ .makePermanent()
+ .build();
+
+ pipeline.processFlowRule(install, flowRule);
+ }
+}