[ONOS-4426] Upgrade Vtn Module when access same network segment
Change-Id: Id0d00e9d0e93d1baf4ff20560469316fee5a3186
diff --git a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/manager/impl/VtnManager.java b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/manager/impl/VtnManager.java
index 06c3769..8f46dbe 100644
--- a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/manager/impl/VtnManager.java
+++ b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/manager/impl/VtnManager.java
@@ -18,6 +18,7 @@
import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
import static org.slf4j.LoggerFactory.getLogger;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -27,6 +28,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
@@ -36,14 +38,19 @@
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.ARP;
+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.util.KryoNamespace;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.mastership.MastershipService;
import org.onosproject.net.AnnotationKeys;
+import org.onosproject.net.ConnectPoint;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Host;
@@ -61,7 +68,12 @@
import org.onosproject.net.driver.DriverHandler;
import org.onosproject.net.driver.DriverService;
import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.TrafficTreatment.Builder;
+import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flow.instructions.ExtensionTreatment;
import org.onosproject.net.flowobjective.Objective;
import org.onosproject.net.group.DefaultGroupBucket;
@@ -75,6 +87,12 @@
import org.onosproject.net.host.HostEvent;
import org.onosproject.net.host.HostListener;
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.PacketProcessor;
+import org.onosproject.net.packet.PacketService;
import org.onosproject.store.serializers.KryoNamespaces;
import org.onosproject.store.service.ConsistentMap;
import org.onosproject.store.service.EventuallyConsistentMap;
@@ -96,13 +114,16 @@
import org.onosproject.vtn.table.impl.L3ForwardServiceImpl;
import org.onosproject.vtn.table.impl.SnatServiceImpl;
import org.onosproject.vtn.util.DataPathIdGenerator;
+import org.onosproject.vtn.util.IpUtil;
import org.onosproject.vtn.util.VtnConfig;
import org.onosproject.vtn.util.VtnData;
import org.onosproject.vtnrsc.AllowedAddressPair;
import org.onosproject.vtnrsc.BindingHostId;
+import org.onosproject.vtnrsc.DefaultFloatingIp;
import org.onosproject.vtnrsc.DefaultVirtualPort;
import org.onosproject.vtnrsc.FixedIp;
import org.onosproject.vtnrsc.FloatingIp;
+import org.onosproject.vtnrsc.FloatingIpId;
import org.onosproject.vtnrsc.RouterId;
import org.onosproject.vtnrsc.RouterInterface;
import org.onosproject.vtnrsc.SecurityGroup;
@@ -183,6 +204,9 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected RouterInterfaceService routerInterfaceService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected FlowRuleService flowRuleService;
+
private ApplicationId appId;
private ClassifierService classifierService;
private L2ForwardService l2ForwardService;
@@ -207,8 +231,12 @@
private static final String EX_PORT_OF_DEVICE = "exPortOfDevice";
private static final String EX_PORT_MAP = "exPortMap";
private static final String DEFAULT_IP = "0.0.0.0";
+ private static final String FLOATINGSTORE = "vtn-floatingIp";
private static final String USERDATA_IP = "169.254.169.254";
private static final int SUBNET_NUM = 2;
+ private static final int SNAT_TABLE = 40;
+ private static final int SNAT_DEFAULT_RULE_PRIORITY = 0;
+ private static final byte[] ZERO_MAC_ADDRESS = MacAddress.ZERO.toBytes();
private EventuallyConsistentMap<VirtualPortId, VirtualPort> vPortStore;
private EventuallyConsistentMap<IpAddress, Boolean> switchesOfController;
@@ -216,8 +244,13 @@
private EventuallyConsistentMap<SubnetId, Map<HostId, Host>> hostsOfSubnet;
private EventuallyConsistentMap<TenantRouter, Boolean> routerInfFlagOfTenantRouter;
private EventuallyConsistentMap<DeviceId, Port> exPortOfDevice;
+ private EventuallyConsistentMap<IpAddress, FloatingIp> floatingIpStore;
private static ConsistentMap<String, String> exPortMap;
+ private VtnL3PacketProcessor l3PacketProcessor = new VtnL3PacketProcessor();
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected PacketService packetService;
+
@Activate
public void activate() {
appId = coreService.registerApplication(APP_ID);
@@ -238,18 +271,29 @@
.register(TenantNetworkId.class)
.register(Host.class)
.register(TenantNetwork.class)
+ .register(TenantNetworkId.class)
.register(TenantId.class)
.register(SubnetId.class)
.register(VirtualPortId.class)
.register(VirtualPort.State.class)
.register(AllowedAddressPair.class)
.register(FixedIp.class)
+ .register(FloatingIp.class)
+ .register(FloatingIpId.class)
+ .register(FloatingIp.Status.class)
+ .register(UUID.class)
+ .register(DefaultFloatingIp.class)
.register(BindingHostId.class)
.register(SecurityGroup.class)
.register(IpAddress.class)
.register(DefaultVirtualPort.class)
.register(RouterId.class)
.register(TenantRouter.class);
+ floatingIpStore = storageService
+ .<IpAddress, FloatingIp>eventuallyConsistentMapBuilder()
+ .withName(FLOATINGSTORE).withSerializer(serializer)
+ .withTimestampProvider((k, v) -> clockService.getTimestamp())
+ .build();
vPortStore = storageService
.<VirtualPortId, VirtualPort>eventuallyConsistentMapBuilder()
@@ -295,6 +339,7 @@
.withSerializer(Serializer.using(Arrays.asList(KryoNamespaces.API)))
.build();
+ packetService.addProcessor(l3PacketProcessor, PacketProcessor.director(0));
log.info("Started");
}
@@ -464,6 +509,9 @@
// Save external port
Port export = getExPort(device.id());
if (export != null) {
+ classifierService.programExportPortArpClassifierRules(export,
+ device.id(),
+ type);
exPortOfDevice.put(device.id(), export);
}
switchOfLocalHostPorts.put(device.id(), new NetworkOfLocalHostPorts());
@@ -867,11 +915,14 @@
@Override
public void onFloatingIpDetected(VtnRscEventFeedback l3Feedback) {
+ floatingIpStore.put(l3Feedback.floatingIp().floatingIp(),
+ l3Feedback.floatingIp());
programFloatingIpEvent(l3Feedback, VtnRscEvent.Type.FLOATINGIP_BIND);
}
@Override
public void onFloatingIpVanished(VtnRscEventFeedback l3Feedback) {
+ floatingIpStore.remove(l3Feedback.floatingIp().floatingIp());
programFloatingIpEvent(l3Feedback, VtnRscEvent.Type.FLOATINGIP_UNBIND);
}
@@ -1100,8 +1151,6 @@
List gwIpMac = getGwIpAndMac(vmPort);
IpAddress dstVmGwIp = (IpAddress) gwIpMac.get(0);
MacAddress dstVmGwMac = (MacAddress) gwIpMac.get(1);
- List fGwIpMac = getGwIpAndMac(fipPort);
- MacAddress fGwMac = (MacAddress) fGwIpMac.get(1);
TenantNetwork vmNetwork = tenantNetworkService
.getNetwork(vmPort.networkId());
TenantNetwork fipNetwork = tenantNetworkService
@@ -1109,26 +1158,26 @@
// L3 downlink traffic flow
MacAddress exPortMac = MacAddress.valueOf(exPort.annotations()
.value(AnnotationKeys.PORT_MAC));
- classifierService.programArpClassifierRules(deviceId, floatingIp.floatingIp(),
- fipNetwork.segmentationId(),
- operation);
classifierService.programL3ExPortClassifierRules(deviceId, exPort.number(),
floatingIp.floatingIp(), operation);
- DriverHandler handler = driverService.createHandler(deviceId);
- arpService.programArpRules(handler, deviceId, floatingIp.floatingIp(),
- fipNetwork.segmentationId(), exPortMac,
- operation);
dnatService.programRules(deviceId, floatingIp.floatingIp(),
- fGwMac, floatingIp.fixedIp(),
+ exPortMac, floatingIp.fixedIp(),
l3vni, operation);
+ Subnet subnet = getSubnetOfFloatingIP(floatingIp);
+ IpPrefix ipPrefix = subnet.cidr();
+ snatService.programSnatSameSegmentUploadControllerRules(deviceId, l3vni,
+ floatingIp.fixedIp(),
+ floatingIp.floatingIp(),
+ ipPrefix,
+ operation);
// L3 uplink traffic flow
if (operation == Objective.Operation.ADD) {
sendNorthSouthL3Flows(deviceId, floatingIp, dstVmGwIp, dstVmGwMac,
l3vni, vmNetwork, vmPort, host, operation);
- l2ForwardService.programLocalOut(deviceId,
- fipNetwork.segmentationId(),
- exPort.number(), fGwMac, operation);
+ l2ForwardService
+ .programExternalOut(deviceId, fipNetwork.segmentationId(),
+ exPort.number(), exPortMac, operation);
} else if (operation == Objective.Operation.REMOVE) {
if (hostFlag || (!hostFlag
&& routerInfFlagOfTenantRouter.get(tenantRouter) == null)) {
@@ -1147,15 +1196,13 @@
}
}
if (exPortFlag) {
- l2ForwardService.programLocalOut(deviceId,
- fipNetwork.segmentationId(),
- exPort.number(), fGwMac, operation);
+ l2ForwardService.programExternalOut(deviceId,
+ fipNetwork.segmentationId(),
+ exPort.number(), exPortMac,
+ operation);
}
+ removeRulesInSnat(deviceId, floatingIp.fixedIp());
}
- snatService.programRules(deviceId, l3vni, floatingIp.fixedIp(),
- fGwMac, exPortMac,
- floatingIp.floatingIp(),
- fipNetwork.segmentationId(), operation);
}
private Port getExPort(DeviceId deviceId) {
@@ -1280,4 +1327,306 @@
public static void setExPortName(String name) {
exPortMap.put(EX_PORT_KEY, name);
}
+
+ /**
+ * Packet processor responsible for forwarding packets along their paths.
+ */
+ private class VtnL3PacketProcessor implements PacketProcessor {
+
+ @Override
+ public void process(PacketContext context) {
+ InboundPacket pkt = context.inPacket();
+ ConnectPoint connectPoint = pkt.receivedFrom();
+ DeviceId deviceId = connectPoint.deviceId();
+ Ethernet ethPkt = pkt.parsed();
+ if (ethPkt == null) {
+ return;
+ }
+ if (ethPkt.getEtherType() == Ethernet.TYPE_ARP) {
+ ARP arpPacket = (ARP) ethPkt.getPayload();
+ if ((arpPacket.getOpCode() == ARP.OP_REQUEST)) {
+ arprequestProcess(arpPacket, deviceId);
+ } else if (arpPacket.getOpCode() == ARP.OP_REPLY) {
+ arpresponceProcess(arpPacket, deviceId);
+ }
+ } else if (ethPkt.getEtherType() == Ethernet.TYPE_IPV4) {
+ if (ethPkt.getDestinationMAC().isMulticast()) {
+ return;
+ }
+ IPv4 ip = (IPv4) ethPkt.getPayload();
+ upStreamPacketProcessor(ip, deviceId);
+
+ } else {
+ return;
+ }
+ }
+
+ private void arprequestProcess(ARP arpPacket, DeviceId deviceId) {
+ MacAddress dstMac = MacAddress
+ .valueOf(arpPacket.getSenderHardwareAddress());
+ IpAddress srcIp = IpAddress.valueOf(IPv4
+ .toIPv4Address(arpPacket.getTargetProtocolAddress()));
+ IpAddress dstIp = IpAddress.valueOf(IPv4
+ .toIPv4Address(arpPacket.getSenderProtocolAddress()));
+ FloatingIp floatingIp = floatingIpStore.get(srcIp);
+ if (floatingIp == null) {
+ return;
+ }
+ DeviceId deviceIdOfFloatingIp = getDeviceIdOfFloatingIP(floatingIp);
+ if (!deviceId.equals(deviceIdOfFloatingIp)) {
+ return;
+ }
+ Port exPort = exPortOfDevice.get(deviceId);
+ MacAddress srcMac = MacAddress.valueOf(exPort.annotations()
+ .value(AnnotationKeys.PORT_MAC));
+ if (!downloadSnatRules(deviceId, srcMac, srcIp, dstMac, dstIp,
+ floatingIp)) {
+ return;
+ }
+ Ethernet ethernet = buildArpResponse(dstIp, dstMac, srcIp, srcMac);
+ if (ethernet != null) {
+ sendPacketOut(deviceId, exPort.number(), ethernet);
+ }
+ }
+
+ private void arpresponceProcess(ARP arpPacket, DeviceId deviceId) {
+ MacAddress srcMac = MacAddress
+ .valueOf(arpPacket.getTargetHardwareAddress());
+ MacAddress dstMac = MacAddress
+ .valueOf(arpPacket.getSenderHardwareAddress());
+ IpAddress srcIp = IpAddress.valueOf(IPv4
+ .toIPv4Address(arpPacket.getTargetProtocolAddress()));
+ IpAddress dstIp = IpAddress.valueOf(IPv4
+ .toIPv4Address(arpPacket.getSenderProtocolAddress()));
+ FloatingIp floatingIp = floatingIpStore.get(srcIp);
+ if (floatingIp == null) {
+ return;
+ }
+ DeviceId deviceIdOfFloatingIp = getDeviceIdOfFloatingIP(floatingIp);
+ if (!deviceId.equals(deviceIdOfFloatingIp)) {
+ return;
+ }
+ if (!downloadSnatRules(deviceId, srcMac, srcIp, dstMac, dstIp,
+ floatingIp)) {
+ return;
+ }
+ }
+
+ private void upStreamPacketProcessor(IPv4 ipPacket, DeviceId deviceId) {
+ IpAddress srcIp = IpAddress.valueOf(ipPacket.getSourceAddress());
+ IpAddress dstIp = IpAddress.valueOf(ipPacket.getDestinationAddress());
+ FloatingIp floatingIp = null;
+ Collection<FloatingIp> floatingIps = floatingIpService
+ .getFloatingIps();
+ Set<FloatingIp> floatingIpSet = Sets.newHashSet(floatingIps)
+ .stream().collect(Collectors.toSet());
+ for (FloatingIp f : floatingIpSet) {
+ IpAddress fixIp = f.fixedIp();
+ if (fixIp != null && fixIp.equals(srcIp)) {
+ floatingIp = f;
+ break;
+ }
+ }
+ if (floatingIp == null) {
+ return;
+ }
+ Subnet subnet = getSubnetOfFloatingIP(floatingIp);
+ IpAddress gwIp = subnet.gatewayIp();
+ Port exportPort = exPortOfDevice.get(deviceId);
+ MacAddress exPortMac = MacAddress.valueOf(exportPort.annotations()
+ .value(AnnotationKeys.PORT_MAC));
+ IpPrefix ipPrefix = subnet.cidr();
+ if (ipPrefix == null) {
+ return;
+ }
+ int mask = ipPrefix.prefixLength();
+ if (mask <= 0) {
+ return;
+ }
+ Ethernet ethernet = null;
+ // if the same ip segment
+ if (IpUtil.checkSameSegment(floatingIp.floatingIp(), dstIp, mask)) {
+ ethernet = buildArpRequest(dstIp, floatingIp.floatingIp(),
+ exPortMac);
+ } else {
+ ethernet = buildArpRequest(gwIp, floatingIp.floatingIp(),
+ exPortMac);
+ }
+ if (ethernet != null) {
+ sendPacketOut(deviceId, exportPort.number(), ethernet);
+ }
+ }
+ }
+
+ private Ethernet buildArpRequest(IpAddress targetIp, IpAddress sourceIp,
+ MacAddress sourceMac) {
+ ARP arp = new ARP();
+ arp.setHardwareType(ARP.HW_TYPE_ETHERNET)
+ .setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
+ .setProtocolType(ARP.PROTO_TYPE_IP)
+ .setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH)
+ .setOpCode(ARP.OP_REQUEST);
+
+ arp.setSenderHardwareAddress(sourceMac.toBytes())
+ .setSenderProtocolAddress(sourceIp.getIp4Address().toInt())
+ .setTargetHardwareAddress(ZERO_MAC_ADDRESS)
+ .setTargetProtocolAddress(targetIp.getIp4Address().toInt());
+
+ Ethernet ethernet = new Ethernet();
+ ethernet.setEtherType(Ethernet.TYPE_ARP)
+ .setDestinationMACAddress(MacAddress.BROADCAST)
+ .setSourceMACAddress(sourceMac)
+ .setPayload(arp);
+
+ ethernet.setPad(true);
+ return ethernet;
+ }
+
+ private Ethernet buildArpResponse(IpAddress targetIp, MacAddress targetMac,
+ IpAddress sourceIp, MacAddress sourceMac) {
+ ARP arp = new ARP();
+ arp.setHardwareType(ARP.HW_TYPE_ETHERNET)
+ .setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
+ .setProtocolType(ARP.PROTO_TYPE_IP)
+ .setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH)
+ .setOpCode(ARP.OP_REPLY);
+
+ arp.setSenderHardwareAddress(sourceMac.toBytes())
+ .setSenderProtocolAddress(sourceIp.getIp4Address().toInt())
+ .setTargetHardwareAddress(targetMac.toBytes())
+ .setTargetProtocolAddress(targetIp.getIp4Address().toInt());
+
+ Ethernet ethernet = new Ethernet();
+ ethernet.setEtherType(Ethernet.TYPE_ARP)
+ .setDestinationMACAddress(targetMac)
+ .setSourceMACAddress(sourceMac)
+ .setPayload(arp);
+
+ ethernet.setPad(true);
+
+ return ethernet;
+ }
+
+ private void sendPacketOut(DeviceId deviceId, PortNumber portNumber,
+ Ethernet payload) {
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(portNumber).build();
+ OutboundPacket packet = new DefaultOutboundPacket(deviceId, treatment,
+ ByteBuffer
+ .wrap(payload
+ .serialize()));
+ packetService.emit(packet);
+ }
+
+ private Subnet getSubnetOfFloatingIP(FloatingIp floatingIp) {
+ DeviceId exVmPortId = DeviceId
+ .deviceId(floatingIp.id().floatingIpId().toString());
+ Collection<VirtualPort> exVmPortList = virtualPortService
+ .getPorts(exVmPortId);
+ VirtualPort exVmPort = null;
+ if (exVmPortList != null) {
+ exVmPort = exVmPortList.iterator().next();
+ }
+ if (exVmPort == null) {
+ return null;
+ }
+ Set<FixedIp> fixedIps = exVmPort.fixedIps();
+ SubnetId subnetId = null;
+ for (FixedIp f : fixedIps) {
+ IpAddress fp = f.ip();
+ if (fp.equals(floatingIp.floatingIp())) {
+ subnetId = f.subnetId();
+ break;
+ }
+ }
+ if (subnetId == null) {
+ return null;
+ }
+ Subnet subnet = subnetService.getSubnet(subnetId);
+ return subnet;
+ }
+
+ private DeviceId getDeviceIdOfFloatingIP(FloatingIp floatingIp) {
+ VirtualPortId vmPortId = floatingIp.portId();
+ VirtualPort vmPort = virtualPortService.getPort(vmPortId);
+ if (vmPort == null) {
+ vmPort = VtnData.getPort(vPortStore, vmPortId);
+ }
+ Set<Host> hostSet = hostService.getHostsByMac(vmPort.macAddress());
+ Host host = null;
+ for (Host h : hostSet) {
+ String ifaceid = h.annotations().value(IFACEID);
+ if (ifaceid != null && ifaceid.equals(vmPortId.portId())) {
+ host = h;
+ break;
+ }
+ }
+ if (host == null) {
+ return null;
+ } else {
+ return host.location().deviceId();
+ }
+ }
+
+ private boolean downloadSnatRules(DeviceId deviceId, MacAddress srcMac,
+ IpAddress srcIp, MacAddress dstMac,
+ IpAddress dstIp, FloatingIp floatingIp) {
+ TenantNetwork exNetwork = tenantNetworkService
+ .getNetwork(floatingIp.networkId());
+ IpAddress fixedIp = floatingIp.fixedIp();
+ VirtualPortId vmPortId = floatingIp.portId();
+ VirtualPort vmPort = virtualPortService.getPort(vmPortId);
+ if (vmPort == null) {
+ vmPort = VtnData.getPort(vPortStore, vmPortId);
+ }
+ Subnet subnet = getSubnetOfFloatingIP(floatingIp);
+ IpPrefix ipPrefix = subnet.cidr();
+ IpAddress gwIp = subnet.gatewayIp();
+ if (ipPrefix == null) {
+ return false;
+ }
+ int mask = ipPrefix.prefixLength();
+ if (mask <= 0) {
+ return false;
+ }
+ TenantRouter tenantRouter = TenantRouter
+ .tenantRouter(floatingIp.tenantId(), floatingIp.routerId());
+ SegmentationId l3vni = vtnRscService.getL3vni(tenantRouter);
+ // if the same ip segment
+ if (IpUtil.checkSameSegment(srcIp, dstIp, mask)) {
+ snatService.programSnatSameSegmentRules(deviceId, l3vni, fixedIp,
+ dstIp, dstMac, srcMac,
+ srcIp,
+ exNetwork.segmentationId(),
+ Objective.Operation.ADD);
+ if (dstIp.equals(gwIp)) {
+ snatService
+ .programSnatDiffSegmentRules(deviceId, l3vni, fixedIp,
+ dstMac, srcMac, srcIp,
+ exNetwork.segmentationId(),
+ Objective.Operation.ADD);
+ }
+ }
+ return true;
+ }
+
+ private void removeRulesInSnat(DeviceId deviceId, IpAddress fixedIp) {
+ for (FlowEntry f : flowRuleService.getFlowEntries(deviceId)) {
+ if (f.tableId() == SNAT_TABLE
+ && f.priority() > SNAT_DEFAULT_RULE_PRIORITY) {
+ String srcIp = f.selector()
+ .getCriterion(Criterion.Type.IPV4_SRC).toString();
+ int priority = f.priority();
+ if (srcIp != null && srcIp.contains(fixedIp.toString())) {
+ log.info("Match snat rules bob");
+ TrafficSelector selector = f.selector();
+ TrafficTreatment treatment = f.treatment();
+ snatService.removeSnatRules(deviceId, selector, treatment,
+ priority,
+ Objective.Operation.REMOVE);
+
+ }
+ }
+ }
+ }
}
diff --git a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/ClassifierService.java b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/ClassifierService.java
index 75df9b0..dc04a9a 100644
--- a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/ClassifierService.java
+++ b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/ClassifierService.java
@@ -20,8 +20,10 @@
import org.onlab.packet.MacAddress;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.DeviceId;
+import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.flowobjective.Objective;
+import org.onosproject.net.flowobjective.Objective.Operation;
import org.onosproject.vtnrsc.SegmentationId;
/**
@@ -134,4 +136,16 @@
IpAddress dstIp, MacAddress dstmac,
SegmentationId actionVni,
Objective.Operation type);
+
+ /**
+ * Assemble the export port Arp Classifier table rules.
+ * Match: export port.
+ * Action: upload packet to controller.
+ *
+ * @param exportPort export port of ovs
+ * @param deviceId Device Id
+ * @param type the operation type of the flow rules
+ */
+ void programExportPortArpClassifierRules(Port exportPort, DeviceId deviceId,
+ Operation type);
}
diff --git a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/L2ForwardService.java b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/L2ForwardService.java
index d313995..577bab3 100644
--- a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/L2ForwardService.java
+++ b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/L2ForwardService.java
@@ -79,6 +79,21 @@
Objective.Operation type);
/**
+ * The external out rule that message matches Table(50).
+ * Match: external port mac and vnid.
+ * Action: output external port.
+ *
+ * @param deviceId Device Id
+ * @param segmentationId the vnid of the host belong to
+ * @param outPort the ingress port of the external port
+ * @param sourceMac the mac of the external port
+ * @param type the operation of the flow
+ */
+ void programExternalOut(DeviceId deviceId, SegmentationId segmentationId,
+ PortNumber outPort, MacAddress sourceMac,
+ Objective.Operation type);
+
+ /**
* The tunnel out rule that message matches Table(50).
* Match: host mac and vnid.
* Action: output tunnel port.
diff --git a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/SnatService.java b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/SnatService.java
index 7e2939b..dd6f811 100644
--- a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/SnatService.java
+++ b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/SnatService.java
@@ -16,8 +16,11 @@
package org.onosproject.vtn.table;
import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onosproject.net.DeviceId;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flowobjective.Objective;
import org.onosproject.vtnrsc.SegmentationId;
@@ -30,6 +33,25 @@
/**
* Assemble the SNAT table rules.
+ * Match: ipv4 type, vnid, destination ip and source ip.
+ * Action: set eth_src, set eth_dst, set ip_src, set vnid and goto L2Forward Table(50).
+ *
+ * @param deviceId Device Id
+ * @param matchVni the vni of L3 network
+ * @param srcIP source ip
+ * @param dstIP destination ip
+ * @param ethDst external gateway mac
+ * @param ethSrc external port mac
+ * @param ipSrc floating ip
+ * @param actionVni external network VNI
+ * @param type the operation type of the flow rules
+ */
+ void programSnatSameSegmentRules(DeviceId deviceId, SegmentationId matchVni,
+ IpAddress srcIP, IpAddress dstIP, MacAddress ethDst,
+ MacAddress ethSrc, IpAddress ipSrc,
+ SegmentationId actionVni, Objective.Operation type);
+ /**
+ * Assemble the SNAT table rules.
* Match: ipv4 type, vnid and source ip.
* Action: set eth_src, set eth_dst, set ip_src, set vnid and goto L2Forward Table(50).
*
@@ -42,8 +64,39 @@
* @param actionVni external network VNI
* @param type the operation type of the flow rules
*/
- void programRules(DeviceId deviceId, SegmentationId matchVni,
+ void programSnatDiffSegmentRules(DeviceId deviceId, SegmentationId matchVni,
IpAddress srcIP, MacAddress ethDst,
MacAddress ethSrc, IpAddress ipSrc,
SegmentationId actionVni, Objective.Operation type);
+
+ /**
+ * Assemble the SNAT table rules.
+ * Match: ipv4 type, vnid, destination ip and source ip.
+ * Action: upload to controller.
+ *
+ * @param deviceId Device Id
+ * @param matchVni the vni of L3 network
+ * @param srcIP source ip
+ * @param dstIP destination ip
+ * @param type the operation type of the flow rules
+ */
+ void programSnatSameSegmentUploadControllerRules(DeviceId deviceId,
+ SegmentationId matchVni,
+ IpAddress srcIP,
+ IpAddress dstIP,
+ IpPrefix prefix,
+ Objective.Operation type);
+
+ /**
+ * Remove the SNAT table rules.
+ *
+ * @param deviceId Device Id
+ * @param selector selector of rules
+ * @param treatment treatment of rules
+ * @param priority priority of rules
+ * @param type the operation type of the flow rules
+ */
+ void removeSnatRules(DeviceId deviceId, TrafficSelector selector,
+ TrafficTreatment treatment, int priority,
+ Objective.Operation type);
}
diff --git a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/impl/ClassifierServiceImpl.java b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/impl/ClassifierServiceImpl.java
index c41aafe..17471f6 100644
--- a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/impl/ClassifierServiceImpl.java
+++ b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/impl/ClassifierServiceImpl.java
@@ -28,6 +28,7 @@
import org.onlab.packet.MacAddress;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.DeviceId;
+import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
@@ -40,6 +41,7 @@
import org.onosproject.net.flowobjective.ForwardingObjective;
import org.onosproject.net.flowobjective.ForwardingObjective.Flag;
import org.onosproject.net.flowobjective.Objective;
+import org.onosproject.net.flowobjective.Objective.Operation;
import org.onosproject.vtn.table.ClassifierService;
import org.onosproject.vtnrsc.SegmentationId;
import org.slf4j.Logger;
@@ -242,4 +244,24 @@
flowObjectiveService.forward(deviceId, objective.remove());
}
}
+
+ @Override
+ public void programExportPortArpClassifierRules(Port exportPort,
+ DeviceId deviceId,
+ Operation type) {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchEthType(EtherType.ARP.ethType().toShort())
+ .matchInPort(exportPort.number()).build();
+ TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+ treatment.add(Instructions.createOutput(PortNumber.CONTROLLER));
+ ForwardingObjective.Builder objective = DefaultForwardingObjective
+ .builder().withTreatment(treatment.build())
+ .withSelector(selector).fromApp(appId).withFlag(Flag.SPECIFIC)
+ .withPriority(L3_CLASSIFIER_PRIORITY);
+ if (type.equals(Objective.Operation.ADD)) {
+ flowObjectiveService.forward(deviceId, objective.add());
+ } else {
+ flowObjectiveService.forward(deviceId, objective.remove());
+ }
+ }
}
diff --git a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/impl/L2ForwardServiceImpl.java b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/impl/L2ForwardServiceImpl.java
index c19a38a..a91b29e 100644
--- a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/impl/L2ForwardServiceImpl.java
+++ b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/impl/L2ForwardServiceImpl.java
@@ -176,6 +176,28 @@
}
@Override
+ public void programExternalOut(DeviceId deviceId,
+ SegmentationId segmentationId,
+ PortNumber outPort, MacAddress sourceMac,
+ Objective.Operation type) {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchTunnelId(Long.parseLong(segmentationId.toString()))
+ .matchEthSrc(sourceMac).build();
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(outPort).build();
+ ForwardingObjective.Builder objective = DefaultForwardingObjective
+ .builder().withTreatment(treatment).withSelector(selector)
+ .fromApp(appId).withFlag(Flag.SPECIFIC)
+ .withPriority(MAC_PRIORITY);
+ if (type.equals(Objective.Operation.ADD)) {
+ flowObjectiveService.forward(deviceId, objective.add());
+ } else {
+ flowObjectiveService.forward(deviceId, objective.remove());
+ }
+
+ }
+
+ @Override
public void programTunnelOut(DeviceId deviceId,
SegmentationId segmentationId,
PortNumber tunnelOutPort, MacAddress dstMac,
diff --git a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/impl/SnatServiceImpl.java b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/impl/SnatServiceImpl.java
index 40cd350..cd28ed8 100644
--- a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/impl/SnatServiceImpl.java
+++ b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/table/impl/SnatServiceImpl.java
@@ -16,7 +16,6 @@
package org.onosproject.vtn.table.impl;
import static com.google.common.base.Preconditions.checkNotNull;
-import static org.slf4j.LoggerFactory.getLogger;
import org.onlab.osgi.DefaultServiceDirectory;
import org.onlab.osgi.ServiceDirectory;
@@ -26,26 +25,29 @@
import org.onlab.packet.MacAddress;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.instructions.Instructions;
import org.onosproject.net.flowobjective.DefaultForwardingObjective;
import org.onosproject.net.flowobjective.FlowObjectiveService;
import org.onosproject.net.flowobjective.ForwardingObjective;
import org.onosproject.net.flowobjective.ForwardingObjective.Flag;
import org.onosproject.net.flowobjective.Objective;
+import org.onosproject.net.flowobjective.Objective.Operation;
import org.onosproject.vtn.table.SnatService;
import org.onosproject.vtnrsc.SegmentationId;
-import org.slf4j.Logger;
/**
* Provides implementation of SnatService.
*/
public class SnatServiceImpl implements SnatService {
- private final Logger log = getLogger(getClass());
- private static final int SNAT_PRIORITY = 0xffff;
+ private static final int SNAT_SAME_SEG_PRIORITY = 0xffff;
+ private static final int SNAT_SAME_SEG_CON_PRIORITY = 0xfff0;
+ private static final int SNAT_DIFF_SEG_PRIORITY = 0xffe0;
private static final int PREFIC_LENGTH = 32;
private final FlowObjectiveService flowObjectiveService;
@@ -63,7 +65,32 @@
}
@Override
- public void programRules(DeviceId deviceId, SegmentationId matchVni,
+ public void programSnatSameSegmentRules(DeviceId deviceId, SegmentationId matchVni,
+ IpAddress srcIP, IpAddress dstIP, MacAddress ethDst,
+ MacAddress ethSrc, IpAddress ipSrc,
+ SegmentationId actionVni, Objective.Operation type) {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .matchTunnelId(Long.parseLong(matchVni.segmentationId()))
+ .matchIPSrc(IpPrefix.valueOf(srcIP, PREFIC_LENGTH))
+ .matchIPDst(IpPrefix.valueOf(dstIP, PREFIC_LENGTH)).build();
+
+ TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+ treatment.setEthDst(ethDst).setEthSrc(ethSrc).setIpSrc(ipSrc)
+ .setTunnelId(Long.parseLong(actionVni.segmentationId()));
+ ForwardingObjective.Builder objective = DefaultForwardingObjective
+ .builder().withTreatment(treatment.build())
+ .withSelector(selector).fromApp(appId).withFlag(Flag.SPECIFIC)
+ .withPriority(SNAT_SAME_SEG_PRIORITY);
+ if (type.equals(Objective.Operation.ADD)) {
+ flowObjectiveService.forward(deviceId, objective.add());
+ } else {
+ flowObjectiveService.forward(deviceId, objective.remove());
+ }
+ }
+
+ @Override
+ public void programSnatDiffSegmentRules(DeviceId deviceId, SegmentationId matchVni,
IpAddress srcIP, MacAddress ethDst,
MacAddress ethSrc, IpAddress ipSrc,
SegmentationId actionVni, Objective.Operation type) {
@@ -78,12 +105,51 @@
ForwardingObjective.Builder objective = DefaultForwardingObjective
.builder().withTreatment(treatment.build())
.withSelector(selector).fromApp(appId).withFlag(Flag.SPECIFIC)
- .withPriority(SNAT_PRIORITY);
+ .withPriority(SNAT_DIFF_SEG_PRIORITY);
if (type.equals(Objective.Operation.ADD)) {
- log.debug("RouteRules-->ADD");
flowObjectiveService.forward(deviceId, objective.add());
} else {
- log.debug("RouteRules-->REMOVE");
+ flowObjectiveService.forward(deviceId, objective.remove());
+ }
+ }
+
+ @Override
+ public void programSnatSameSegmentUploadControllerRules(DeviceId deviceId,
+ SegmentationId matchVni,
+ IpAddress srcIP,
+ IpAddress dstIP,
+ IpPrefix prefix,
+ Operation type) {
+
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .matchTunnelId(Long.parseLong(matchVni.segmentationId()))
+ .matchIPSrc(IpPrefix.valueOf(srcIP, PREFIC_LENGTH))
+ .matchIPDst(IpPrefix.valueOf(dstIP, prefix.prefixLength()))
+ .build();
+ TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+ treatment.add(Instructions.createOutput(PortNumber.CONTROLLER));
+ ForwardingObjective.Builder objective = DefaultForwardingObjective
+ .builder().withTreatment(treatment.build())
+ .withSelector(selector).fromApp(appId).withFlag(Flag.SPECIFIC)
+ .withPriority(SNAT_SAME_SEG_CON_PRIORITY);
+ if (type.equals(Objective.Operation.ADD)) {
+ flowObjectiveService.forward(deviceId, objective.add());
+ } else {
+ flowObjectiveService.forward(deviceId, objective.remove());
+ }
+ }
+
+ @Override
+ public void removeSnatRules(DeviceId deviceId, TrafficSelector selector,
+ TrafficTreatment treatment, int priority,
+ Objective.Operation type) {
+ ForwardingObjective.Builder objective = DefaultForwardingObjective
+ .builder().withTreatment(treatment).withSelector(selector)
+ .fromApp(appId).withFlag(Flag.SPECIFIC).withPriority(priority);
+ if (type.equals(Objective.Operation.ADD)) {
+ flowObjectiveService.forward(deviceId, objective.add());
+ } else {
flowObjectiveService.forward(deviceId, objective.remove());
}
}
diff --git a/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/util/IpUtil.java b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/util/IpUtil.java
new file mode 100644
index 0000000..82865c5
--- /dev/null
+++ b/apps/vtn/vtnmgr/src/main/java/org/onosproject/vtn/util/IpUtil.java
@@ -0,0 +1,52 @@
+/*
+ * 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.vtn.util;
+
+import org.onlab.packet.IpAddress;
+
+/**
+ * IpUtil utility class.
+ */
+public final class IpUtil {
+
+ private IpUtil() {
+ }
+
+ /**
+ * check source Ip and destination Ip in same Subnet.
+ *
+ * @param srcIp source Ip
+ * @param dstIp destination
+ * @param masks netmask length
+ * @return boolean
+ */
+ public static boolean checkSameSegment(IpAddress srcIp, IpAddress dstIp,
+ int mask) {
+ String[] ips = srcIp.toString().split("\\.");
+ int ipAddr = (Integer.parseInt(ips[0]) << 24)
+ | (Integer.parseInt(ips[1]) << 16)
+ | (Integer.parseInt(ips[2]) << 8)
+ | Integer.parseInt(ips[3]);
+ int netmask = 0xFFFFFFFF << (32 - mask);
+ String[] cidrIps = dstIp.toString().split("\\.");
+ int cidrIpAddr = (Integer.parseInt(cidrIps[0]) << 24)
+ | (Integer.parseInt(cidrIps[1]) << 16)
+ | (Integer.parseInt(cidrIps[2]) << 8)
+ | Integer.parseInt(cidrIps[3]);
+
+ return (ipAddr & netmask) == (cidrIpAddr & netmask);
+ }
+}