CORD-248 Provide host management network connectivity to a VM
Change-Id: I6f632e118bd11f4f469aae0476d2d35fc2b7c3eb
diff --git a/src/main/java/org/opencord/cordvtn/impl/CordVtnArpProxy.java b/src/main/java/org/opencord/cordvtn/impl/CordVtnArpProxy.java
index 9e8d313..1697f1a 100644
--- a/src/main/java/org/opencord/cordvtn/impl/CordVtnArpProxy.java
+++ b/src/main/java/org/opencord/cordvtn/impl/CordVtnArpProxy.java
@@ -28,6 +28,8 @@
import org.onlab.packet.Ip4Address;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
import org.onosproject.net.packet.PacketProcessor;
import org.onosproject.xosclient.api.VtnService;
import org.opencord.cordvtn.api.CordVtnConfig;
@@ -50,6 +52,7 @@
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onosproject.xosclient.api.VtnServiceApi.NetworkType.PRIVATE;
+import static org.onosproject.xosclient.api.VtnServiceApi.ServiceType.MANAGEMENT;
import static org.slf4j.LoggerFactory.getLogger;
/**
@@ -62,6 +65,9 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected PacketService packetService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CordVtnNodeManager nodeManager;
+
private final PacketProcessor packetProcessor = new InternalPacketProcessor();
private final Map<Ip4Address, MacAddress> gateways = Maps.newConcurrentMap();
@@ -132,31 +138,26 @@
/**
* Emits ARP reply with fake MAC address for a given ARP request.
- * It only handles requests for the registered service IPs, and the other
- * requests can be handled by other ARP handlers like openstackSwitching or
- * proxyArp, for example.
+ * It only handles requests for the registered gateway IPs and host IPs.
*
* @param context packet context
* @param ethPacket ethernet packet
*/
- private void processArpPacket(PacketContext context, Ethernet ethPacket) {
+ private void processArpRequest(PacketContext context, Ethernet ethPacket) {
ARP arpPacket = (ARP) ethPacket.getPayload();
- if (arpPacket.getOpCode() != ARP.OP_REQUEST) {
- return;
- }
-
Ip4Address targetIp = Ip4Address.valueOf(arpPacket.getTargetProtocolAddress());
MacAddress gatewayMac = gateways.get(targetIp);
- MacAddress replyMac = gatewayMac != null ? gatewayMac : getMacFromHostService(targetIp);
+ MacAddress replyMac = gatewayMac != null ? gatewayMac :
+ getMacFromHostService(targetIp);
if (replyMac.equals(MacAddress.NONE)) {
- log.debug("Failed to find MAC for {}", targetIp.toString());
- context.block();
+ log.trace("Failed to find MAC for {}", targetIp);
+ forwardManagementArpRequest(context, ethPacket);
return;
}
- log.trace("Send ARP reply for {} with {}", targetIp.toString(), replyMac.toString());
+ log.trace("Send ARP reply for {} with {}", targetIp, replyMac);
Ethernet ethReply = ARP.buildArpReply(
targetIp,
replyMac,
@@ -174,6 +175,62 @@
context.block();
}
+ private void processArpReply(PacketContext context, Ethernet ethPacket) {
+ ARP arpPacket = (ARP) ethPacket.getPayload();
+ Ip4Address targetIp = Ip4Address.valueOf(arpPacket.getTargetProtocolAddress());
+
+ DeviceId deviceId = context.inPacket().receivedFrom().deviceId();
+ Host host = hostService.getHostsByIp(targetIp).stream()
+ .filter(h -> h.location().deviceId().equals(deviceId))
+ .findFirst()
+ .orElse(null);
+
+ if (host == null) {
+ // do nothing for the unknown ARP reply
+ log.trace("No host found for {} in {}", targetIp, deviceId);
+ context.block();
+ return;
+ }
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(host.location().port())
+ .build();
+
+ packetService.emit(new DefaultOutboundPacket(
+ deviceId,
+ treatment,
+ ByteBuffer.wrap(ethPacket.serialize())));
+
+ context.block();
+ }
+
+ private void forwardManagementArpRequest(PacketContext context, Ethernet ethPacket) {
+ DeviceId deviceId = context.inPacket().receivedFrom().deviceId();
+ PortNumber hostMgmtPort = nodeManager.hostManagementPort(deviceId);
+ Host host = hostService.getConnectedHosts(context.inPacket().receivedFrom())
+ .stream()
+ .findFirst().orElse(null);
+
+ if (host == null ||
+ !Instance.of(host).serviceType().equals(MANAGEMENT) ||
+ hostMgmtPort == null) {
+ context.block();
+ return;
+ }
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(hostMgmtPort)
+ .build();
+
+ packetService.emit(new DefaultOutboundPacket(
+ context.inPacket().receivedFrom().deviceId(),
+ treatment,
+ ByteBuffer.wrap(ethPacket.serialize())));
+
+ log.trace("Forward ARP request to management network");
+ context.block();
+ }
+
/**
* Emits gratuitous ARP when a gateway mac address has been changed.
*
@@ -183,7 +240,7 @@
private void sendGratuitousArp(IpAddress gatewayIp, Set<Instance> instances) {
MacAddress gatewayMac = gateways.get(gatewayIp.getIp4Address());
if (gatewayMac == null) {
- log.debug("Gateway {} is not registered to ARP proxy", gatewayIp.toString());
+ log.debug("Gateway {} is not registered to ARP proxy", gatewayIp);
return;
}
@@ -246,7 +303,7 @@
.orElse(null);
if (host != null) {
- log.trace("Found MAC from host service for {}", targetIp.toString());
+ log.trace("Found MAC from host service for {}", targetIp);
return host.mac();
} else {
return MacAddress.NONE;
@@ -264,7 +321,18 @@
if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
return;
}
- processArpPacket(context, ethPacket);
+
+ ARP arpPacket = (ARP) ethPacket.getPayload();
+ switch (arpPacket.getOpCode()) {
+ case ARP.OP_REQUEST:
+ processArpRequest(context, ethPacket);
+ break;
+ case ARP.OP_REPLY:
+ processArpReply(context, ethPacket);
+ break;
+ default:
+ break;
+ }
}
}
diff --git a/src/main/java/org/opencord/cordvtn/impl/CordVtnNodeManager.java b/src/main/java/org/opencord/cordvtn/impl/CordVtnNodeManager.java
index df3d336..c45fef3 100644
--- a/src/main/java/org/opencord/cordvtn/impl/CordVtnNodeManager.java
+++ b/src/main/java/org/opencord/cordvtn/impl/CordVtnNodeManager.java
@@ -28,6 +28,7 @@
import org.onosproject.cluster.ClusterService;
import org.onosproject.cluster.LeadershipService;
import org.onosproject.cluster.NodeId;
+import org.onosproject.net.AnnotationKeys;
import org.onosproject.net.behaviour.BridgeDescription;
import org.onosproject.net.behaviour.DefaultBridgeDescription;
import org.onosproject.net.behaviour.InterfaceConfig;
@@ -73,6 +74,7 @@
import java.util.List;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;
@@ -314,12 +316,9 @@
log.warn("Failed to get node for {}", deviceId);
return null;
}
- Port port = deviceService.getPorts(deviceId).stream()
- .filter(p -> portName(p).contains(node.dataIface()) &&
- p.isEnabled())
- .findFirst().orElse(null);
- return port == null ? null : port.number();
+ Optional<PortNumber> port = getPortNumber(deviceId, node.dataIface());
+ return port.isPresent() ? port.get() : null;
}
/**
@@ -344,11 +343,39 @@
* @return port number
*/
public PortNumber tunnelPort(DeviceId deviceId) {
- Port port = deviceService.getPorts(deviceId).stream()
- .filter(p -> portName(p).contains(DEFAULT_TUNNEL))
- .findFirst().orElse(null);
+ Optional<PortNumber> port = getPortNumber(deviceId, DEFAULT_TUNNEL);
+ return port.isPresent() ? port.get() : null;
+ }
- return port == null ? null : port.number();
+ /**
+ * Returns host management interface port number if exists.
+ *
+ * @param deviceId integration bridge device id
+ * @return port number; null if it does not exist
+ */
+ public PortNumber hostManagementPort(DeviceId deviceId) {
+ CordVtnNode node = nodeByBridgeId(deviceId);
+ if (node == null) {
+ log.warn("Failed to get node for {}", deviceId);
+ return null;
+ }
+
+ if (node.hostMgmtIface().isPresent()) {
+ Optional<PortNumber> port = getPortNumber(deviceId, node.hostMgmtIface().get());
+ return port.isPresent() ? port.get() : null;
+ } else {
+ return null;
+ }
+ }
+
+ private Optional<PortNumber> getPortNumber(DeviceId deviceId, String portName) {
+ PortNumber port = deviceService.getPorts(deviceId).stream()
+ .filter(p -> p.annotations().value(AnnotationKeys.PORT_NAME).equals(portName) &&
+ p.isEnabled())
+ .map(Port::number)
+ .findAny()
+ .orElse(null);
+ return Optional.ofNullable(port);
}
/**
@@ -398,8 +425,7 @@
ovsdbClient.disconnect();
}
- pipeline.initPipeline(node, dataPort(node.integrationBridgeId()),
- tunnelPort(node.integrationBridgeId()));
+ pipeline.initPipeline(node);
// adds existing instances to the host list
deviceService.getPorts(node.integrationBridgeId()).stream()
diff --git a/src/main/java/org/opencord/cordvtn/impl/CordVtnPipeline.java b/src/main/java/org/opencord/cordvtn/impl/CordVtnPipeline.java
index 2aa9f1f..4e01d2b 100644
--- a/src/main/java/org/opencord/cordvtn/impl/CordVtnPipeline.java
+++ b/src/main/java/org/opencord/cordvtn/impl/CordVtnPipeline.java
@@ -27,7 +27,8 @@
import org.onlab.packet.IpAddress;
import org.onlab.packet.TpPort;
import org.onlab.packet.VlanId;
-import org.onlab.util.ItemNotFoundException;
+import org.onosproject.net.AnnotationKeys;
+import org.onosproject.net.Port;
import org.opencord.cordvtn.api.Constants;
import org.opencord.cordvtn.api.CordVtnNode;
import org.onosproject.core.ApplicationId;
@@ -50,8 +51,11 @@
import org.onosproject.net.flow.instructions.ExtensionTreatment;
import org.slf4j.Logger;
+import java.util.Optional;
+
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
+import static org.opencord.cordvtn.api.Constants.DEFAULT_TUNNEL;
import static org.slf4j.LoggerFactory.getLogger;
/**
@@ -91,6 +95,8 @@
public static final int VXLAN_UDP_PORT = 4789;
public static final VlanId VLAN_WAN = VlanId.vlanId((short) 500);
+ public static final String PROPERTY_TUNNEL_DST = "tunnelDst";
+
private ApplicationId appId;
@Activate
@@ -115,19 +121,84 @@
* Installs table miss rule to a give device.
*
* @param node cordvtn node
- * @param dataPort data plane port number
- * @param tunnelPort tunnel port number
*/
- public void initPipeline(CordVtnNode node, PortNumber dataPort, PortNumber tunnelPort) {
+ public void initPipeline(CordVtnNode node) {
checkNotNull(node);
- processTableZero(node.integrationBridgeId(), dataPort, node.dataIp().ip());
- processInPortTable(node.integrationBridgeId(), tunnelPort, dataPort);
- processAccessTypeTable(node.integrationBridgeId(), dataPort);
- processVlanTable(node.integrationBridgeId(), dataPort);
+ Optional<PortNumber> dataPort = getPortNumber(node.integrationBridgeId(), node.dataIface());
+ Optional<PortNumber> tunnelPort = getPortNumber(node.integrationBridgeId(), DEFAULT_TUNNEL);
+ if (!dataPort.isPresent() || !tunnelPort.isPresent()) {
+ log.warn("Node is not in COMPLETE state");
+ return;
+ }
+
+ Optional<PortNumber> hostMgmtPort = Optional.empty();
+ if (node.hostMgmtIface().isPresent()) {
+ hostMgmtPort = getPortNumber(node.integrationBridgeId(), node.hostMgmtIface().get());
+ }
+
+ processTableZero(node.integrationBridgeId(),
+ dataPort.get(),
+ node.dataIp().ip(),
+ node.localMgmtIp().ip());
+
+ processInPortTable(node.integrationBridgeId(),
+ tunnelPort.get(),
+ dataPort.get(),
+ hostMgmtPort);
+
+ processAccessTypeTable(node.integrationBridgeId(), dataPort.get());
+ processVlanTable(node.integrationBridgeId(), dataPort.get());
}
- private void processTableZero(DeviceId deviceId, PortNumber dataPort, IpAddress dataIp) {
+ private void processTableZero(DeviceId deviceId, PortNumber dataPort, IpAddress dataIp,
+ IpAddress localMgmtIp) {
+ vxlanShuttleRule(deviceId, dataPort, dataIp);
+ localManagementBaseRule(deviceId, localMgmtIp.getIp4Address());
+
+ // take all vlan tagged packet to the VLAN table
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchVlanId(VlanId.ANY)
+ .build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .transition(TABLE_VLAN)
+ .build();
+
+ FlowRule flowRule = DefaultFlowRule.builder()
+ .fromApp(appId)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .withPriority(PRIORITY_MANAGEMENT)
+ .forDevice(deviceId)
+ .forTable(TABLE_ZERO)
+ .makePermanent()
+ .build();
+
+ processFlowRule(true, flowRule);
+
+ // take all other packets to the next table
+ selector = DefaultTrafficSelector.builder()
+ .build();
+
+ treatment = DefaultTrafficTreatment.builder()
+ .transition(TABLE_IN_PORT)
+ .build();
+
+ flowRule = DefaultFlowRule.builder()
+ .fromApp(appId)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .withPriority(PRIORITY_ZERO)
+ .forDevice(deviceId)
+ .forTable(TABLE_ZERO)
+ .makePermanent()
+ .build();
+
+ processFlowRule(true, flowRule);
+ }
+
+ private void vxlanShuttleRule(DeviceId deviceId, PortNumber dataPort, IpAddress dataIp) {
// take vxlan packet out onto the physical port
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchInPort(PortNumber.LOCAL)
@@ -218,52 +289,98 @@
.build();
processFlowRule(true, flowRule);
+ }
- // take all else to the next table
- selector = DefaultTrafficSelector.builder()
+ private void localManagementBaseRule(DeviceId deviceId, Ip4Address localMgmtIp) {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_ARP)
+ .matchArpTpa(localMgmtIp)
.build();
- treatment = DefaultTrafficTreatment.builder()
- .transition(TABLE_IN_PORT)
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(PortNumber.LOCAL)
.build();
- flowRule = DefaultFlowRule.builder()
+ FlowRule flowRule = DefaultFlowRule.builder()
.fromApp(appId)
.withSelector(selector)
.withTreatment(treatment)
- .withPriority(PRIORITY_ZERO)
+ .withPriority(CordVtnPipeline.PRIORITY_MANAGEMENT)
.forDevice(deviceId)
- .forTable(TABLE_ZERO)
+ .forTable(CordVtnPipeline.TABLE_ZERO)
.makePermanent()
.build();
processFlowRule(true, flowRule);
- // take all vlan tagged packet to the VLAN table
selector = DefaultTrafficSelector.builder()
- .matchVlanId(VlanId.ANY)
+ .matchInPort(PortNumber.LOCAL)
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPSrc(localMgmtIp.toIpPrefix())
.build();
treatment = DefaultTrafficTreatment.builder()
- .transition(TABLE_VLAN)
+ .transition(CordVtnPipeline.TABLE_DST_IP)
.build();
flowRule = DefaultFlowRule.builder()
.fromApp(appId)
.withSelector(selector)
.withTreatment(treatment)
- .withPriority(PRIORITY_MANAGEMENT)
+ .withPriority(CordVtnPipeline.PRIORITY_MANAGEMENT)
.forDevice(deviceId)
- .forTable(TABLE_ZERO)
+ .forTable(CordVtnPipeline.TABLE_ZERO)
+ .makePermanent()
+ .build();
+
+ processFlowRule(true, flowRule);
+
+ selector = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPDst(localMgmtIp.toIpPrefix())
+ .build();
+
+ treatment = DefaultTrafficTreatment.builder()
+ .setOutput(PortNumber.LOCAL)
+ .build();
+
+ flowRule = DefaultFlowRule.builder()
+ .fromApp(appId)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .withPriority(CordVtnPipeline.PRIORITY_MANAGEMENT)
+ .forDevice(deviceId)
+ .forTable(CordVtnPipeline.TABLE_ZERO)
+ .makePermanent()
+ .build();
+
+ processFlowRule(true, flowRule);
+
+ selector = DefaultTrafficSelector.builder()
+ .matchInPort(PortNumber.LOCAL)
+ .matchEthType(Ethernet.TYPE_ARP)
+ .matchArpSpa(localMgmtIp)
+ .build();
+
+ treatment = DefaultTrafficTreatment.builder()
+ .setOutput(PortNumber.CONTROLLER)
+ .build();
+
+ flowRule = DefaultFlowRule.builder()
+ .fromApp(appId)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .withPriority(CordVtnPipeline.PRIORITY_MANAGEMENT)
+ .forDevice(deviceId)
+ .forTable(CordVtnPipeline.TABLE_ZERO)
.makePermanent()
.build();
processFlowRule(true, flowRule);
}
- private void processInPortTable(DeviceId deviceId, PortNumber tunnelPort, PortNumber dataPort) {
- checkNotNull(tunnelPort);
-
+ private void processInPortTable(DeviceId deviceId, PortNumber tunnelPort, PortNumber dataPort,
+ Optional<PortNumber> hostMgmtPort) {
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchInPort(tunnelPort)
.build();
@@ -303,6 +420,28 @@
.build();
processFlowRule(true, flowRule);
+
+ if (hostMgmtPort.isPresent()) {
+ selector = DefaultTrafficSelector.builder()
+ .matchInPort(hostMgmtPort.get())
+ .build();
+
+ treatment = DefaultTrafficTreatment.builder()
+ .transition(TABLE_DST_IP)
+ .build();
+
+ flowRule = DefaultFlowRule.builder()
+ .fromApp(appId)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .withPriority(PRIORITY_DEFAULT)
+ .forDevice(deviceId)
+ .forTable(TABLE_IN_PORT)
+ .makePermanent()
+ .build();
+
+ processFlowRule(true, flowRule);
+ }
}
private void processAccessTypeTable(DeviceId deviceId, PortNumber dataPort) {
@@ -384,23 +523,30 @@
}
public ExtensionTreatment tunnelDstTreatment(DeviceId deviceId, Ip4Address remoteIp) {
- try {
- Device device = deviceService.getDevice(deviceId);
- if (!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());
- treatment.setPropertyValue("tunnelDst", remoteIp);
- return treatment;
- } catch (ItemNotFoundException | UnsupportedOperationException |
- ExtensionPropertyException e) {
- log.error("Failed to get extension instruction {}", deviceId);
+ 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(PROPERTY_TUNNEL_DST, remoteIp);
+ return treatment;
+ } catch (ExtensionPropertyException e) {
+ log.warn("Failed to get tunnelDst extension treatment for {}", deviceId);
+ return null;
+ }
+ }
+
+ private Optional<PortNumber> getPortNumber(DeviceId deviceId, String portName) {
+ PortNumber port = deviceService.getPorts(deviceId).stream()
+ .filter(p -> p.annotations().value(AnnotationKeys.PORT_NAME).equals(portName) &&
+ p.isEnabled())
+ .map(Port::number)
+ .findAny()
+ .orElse(null);
+ return Optional.ofNullable(port);
}
}
diff --git a/src/main/java/org/opencord/cordvtn/impl/InstanceManager.java b/src/main/java/org/opencord/cordvtn/impl/InstanceManager.java
index 6269e98..d43a8c6 100644
--- a/src/main/java/org/opencord/cordvtn/impl/InstanceManager.java
+++ b/src/main/java/org/opencord/cordvtn/impl/InstanceManager.java
@@ -70,7 +70,7 @@
import static org.onlab.util.Tools.groupedThreads;
import static org.onosproject.dhcp.IpAssignment.AssignmentStatus.Option_RangeNotEnforced;
import static org.onosproject.net.AnnotationKeys.PORT_NAME;
-import static org.onosproject.xosclient.api.VtnServiceApi.NetworkType.MANAGEMENT;
+import static org.onosproject.xosclient.api.VtnServiceApi.ServiceType.MANAGEMENT;
import static org.opencord.cordvtn.api.Constants.*;
import static org.slf4j.LoggerFactory.getLogger;
@@ -247,7 +247,7 @@
.domainServer(DEFAULT_DNS)
.assignmentStatus(Option_RangeNotEnforced);
- if (service.networkType() != MANAGEMENT) {
+ if (service.serviceType() != MANAGEMENT) {
ipBuilder = ipBuilder.routerAddress(service.serviceIp().getIp4Address());
}
diff --git a/src/main/java/org/opencord/cordvtn/impl/handler/ManagementInstanceHandler.java b/src/main/java/org/opencord/cordvtn/impl/handler/ManagementInstanceHandler.java
index fe30781..7a77b98 100644
--- a/src/main/java/org/opencord/cordvtn/impl/handler/ManagementInstanceHandler.java
+++ b/src/main/java/org/opencord/cordvtn/impl/handler/ManagementInstanceHandler.java
@@ -32,6 +32,7 @@
import org.opencord.cordvtn.impl.AbstractInstanceHandler;
import org.opencord.cordvtn.api.Instance;
import org.opencord.cordvtn.api.InstanceHandler;
+import org.opencord.cordvtn.impl.CordVtnNodeManager;
import org.opencord.cordvtn.impl.CordVtnPipeline;
import java.util.Optional;
@@ -47,6 +48,9 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CordVtnPipeline pipeline;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CordVtnNodeManager nodeManager;
+
@Activate
protected void activate() {
serviceType = Optional.of(MANAGEMENT);
@@ -60,116 +64,56 @@
@Override
public void instanceDetected(Instance instance) {
- log.info("Instance is detected {}", instance);
-
VtnService service = getVtnService(instance.serviceId());
if (service == null) {
log.warn("Failed to get VtnService for {}", instance);
return;
}
- localMgmtNetworkRules(instance, service, true);
+
+ switch (service.networkType()) {
+ case MANAGEMENT_LOCAL:
+ log.info("LOCAL management instance detected {}", instance);
+ localManagementRules(instance, true);
+ break;
+ case MANAGEMENT_HOSTS:
+ log.info("HOSTS management instance detected {}", instance);
+ hostsManagementRules(instance, true);
+ break;
+ default:
+ break;
+ }
}
@Override
public void instanceRemoved(Instance instance) {
- log.info("Instance is removed {}", instance);
-
VtnService service = getVtnService(instance.serviceId());
if (service == null) {
log.warn("Failed to get VtnService for {}", instance);
return;
}
- // TODO check if any stale management network rules are
- localMgmtNetworkRules(instance, service, false);
- }
-
- private void localMgmtNetworkRules(Instance instance, VtnService service, boolean install) {
- managementPerInstanceRule(instance, install);
- if (install) {
- managementBaseRule(instance, service, true);
- } else if (!hostService.getConnectedHosts(instance.deviceId()).stream()
- .filter(host -> Instance.of(host).serviceId().equals(service.id()))
- .findAny()
- .isPresent()) {
- managementBaseRule(instance, service, false);
+ switch (service.networkType()) {
+ case MANAGEMENT_LOCAL:
+ log.info("LOCAL management instance removed {}", instance);
+ localManagementRules(instance, false);
+ break;
+ case MANAGEMENT_HOSTS:
+ log.info("HOSTS management instance removed {}", instance);
+ hostsManagementRules(instance, false);
+ break;
+ default:
+ break;
}
}
- private void managementBaseRule(Instance instance, VtnService service, boolean install) {
+ private void localManagementRules(Instance instance, boolean install) {
TrafficSelector selector = DefaultTrafficSelector.builder()
- .matchEthType(Ethernet.TYPE_ARP)
- .matchArpTpa(service.serviceIp().getIp4Address())
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPDst(instance.ipAddress().toIpPrefix())
.build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
- .setOutput(PortNumber.LOCAL)
- .build();
-
- FlowRule flowRule = DefaultFlowRule.builder()
- .fromApp(appId)
- .withSelector(selector)
- .withTreatment(treatment)
- .withPriority(CordVtnPipeline.PRIORITY_MANAGEMENT)
- .forDevice(instance.deviceId())
- .forTable(CordVtnPipeline.TABLE_ZERO)
- .makePermanent()
- .build();
-
- pipeline.processFlowRule(install, flowRule);
-
- selector = DefaultTrafficSelector.builder()
- .matchInPort(PortNumber.LOCAL)
- .matchEthType(Ethernet.TYPE_IPV4)
- .matchIPDst(service.subnet())
- .build();
-
- treatment = DefaultTrafficTreatment.builder()
- .transition(CordVtnPipeline.TABLE_DST_IP)
- .build();
-
- flowRule = DefaultFlowRule.builder()
- .fromApp(appId)
- .withSelector(selector)
- .withTreatment(treatment)
- .withPriority(CordVtnPipeline.PRIORITY_MANAGEMENT)
- .forDevice(instance.deviceId())
- .forTable(CordVtnPipeline.TABLE_ZERO)
- .makePermanent()
- .build();
-
- pipeline.processFlowRule(install, flowRule);
-
- selector = DefaultTrafficSelector.builder()
- .matchEthType(Ethernet.TYPE_IPV4)
- .matchIPDst(service.serviceIp().toIpPrefix())
- .build();
-
- treatment = DefaultTrafficTreatment.builder()
- .setOutput(PortNumber.LOCAL)
- .build();
-
- flowRule = DefaultFlowRule.builder()
- .fromApp(appId)
- .withSelector(selector)
- .withTreatment(treatment)
- .withPriority(CordVtnPipeline.PRIORITY_MANAGEMENT)
- .forDevice(instance.deviceId())
- .forTable(CordVtnPipeline.TABLE_ZERO)
- .makePermanent()
- .build();
-
- pipeline.processFlowRule(install, flowRule);
- }
-
- private void managementPerInstanceRule(Instance instance, boolean install) {
- TrafficSelector selector = DefaultTrafficSelector.builder()
- .matchInPort(PortNumber.LOCAL)
- .matchEthType(Ethernet.TYPE_ARP)
- .matchArpTpa(instance.ipAddress().getIp4Address())
- .build();
-
- TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setEthDst(instance.mac())
.setOutput(instance.portNumber())
.build();
@@ -177,9 +121,37 @@
.fromApp(appId)
.withSelector(selector)
.withTreatment(treatment)
+ .withPriority(CordVtnPipeline.PRIORITY_DEFAULT)
+ .forDevice(instance.deviceId())
+ .forTable(CordVtnPipeline.TABLE_DST_IP)
+ .makePermanent()
+ .build();
+
+ pipeline.processFlowRule(install, flowRule);
+ }
+
+ private void hostsManagementRules(Instance instance, boolean install) {
+ PortNumber hostMgmtPort = nodeManager.hostManagementPort(instance.deviceId());
+ if (hostMgmtPort == null) {
+ log.warn("Can not find host management port in {}", instance.deviceId());
+ return;
+ }
+
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchInPort(instance.portNumber())
+ .build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(hostMgmtPort)
+ .build();
+
+ FlowRule flowRule = DefaultFlowRule.builder()
+ .fromApp(appId)
+ .withSelector(selector)
+ .withTreatment(treatment)
.withPriority(CordVtnPipeline.PRIORITY_MANAGEMENT)
.forDevice(instance.deviceId())
- .forTable(CordVtnPipeline.TABLE_ZERO)
+ .forTable(CordVtnPipeline.TABLE_IN_PORT)
.makePermanent()
.build();