[ONOS-6616] Revise VirtualPacketContext and DefaultVirtualPacketProvider

The constructor of VirtualPacketContext needs a parameter of DefaultVirtualPacketProvider type.
It is not flexible for us to use another packet provider to replace the default virtual packet provider.

To improve the code flexibility, I think it is better for us to use an interface type parameter in a method.

It alse seems redundant to use emit() method of DefaultVirtualPacketProvider in devirtualizeContext().
Thus, I think it will be more efficient to use core PacketService in VirtualPacketContext
when triger send() method.

Some other bugs are fixed.

Change-Id: I161a8929dc4e5a1d2ad716bc5da8b0b6f84340a9
This commit is contained in:
Harold Huang 2017-06-07 22:39:37 +08:00 committed by Yoonseon Han
parent 10b69e8d67
commit bee92f62f7
3 changed files with 157 additions and 84 deletions

View File

@ -0,0 +1,31 @@
/*
* Copyright 2015-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.incubator.net.virtual;
import org.onosproject.net.packet.PacketContext;
/**
* Represents context for processing an inbound packet for a virtual network,
* and (optionally) emitting a corresponding outbound packet.
*/
public interface VirtualPacketContext extends PacketContext {
/**
* Returns the network identifier.
*
* @return network id
*/
NetworkId networkId();
}

View File

@ -17,18 +17,19 @@
package org.onosproject.incubator.net.virtual.impl.provider;
import org.onosproject.incubator.net.virtual.NetworkId;
import org.onosproject.incubator.net.virtual.VirtualPacketContext;
import org.onosproject.net.packet.DefaultPacketContext;
import org.onosproject.net.packet.InboundPacket;
import org.onosproject.net.packet.OutboundPacket;
/**
* Represents context for processing an inbound packet for a virtual network
* and (optionally) emitting a corresponding outbound packet.
* The translation of context is handled by VirtualPacketProvider.
*Default implementation of a virtual packet context.
*/
public class VirtualPacketContext extends DefaultPacketContext {
private DefaultVirtualPacketProvider dvpp;
public class DefaultVirtualPacketContext extends DefaultPacketContext
implements VirtualPacketContext {
private NetworkId networkId;
private DefaultVirtualPacketProvider dvpp;
/**
* Creates a new packet context.
@ -38,13 +39,13 @@ public class VirtualPacketContext extends DefaultPacketContext {
* @param outPkt outbound packet
* @param block whether the context is blocked or not
* @param networkId virtual network ID where this context is handled
* @param dvpp The pointer for DefaultVirtualPacketProvider
* @param dvpp pointer to default virtual packet provider
*/
protected VirtualPacketContext(long time, InboundPacket inPkt,
OutboundPacket outPkt, boolean block,
NetworkId networkId,
DefaultVirtualPacketProvider dvpp) {
protected DefaultVirtualPacketContext(long time, InboundPacket inPkt,
OutboundPacket outPkt, boolean block,
NetworkId networkId,
DefaultVirtualPacketProvider dvpp) {
super(time, inPkt, outPkt, block);
this.networkId = networkId;
@ -54,11 +55,12 @@ public class VirtualPacketContext extends DefaultPacketContext {
@Override
public void send() {
if (!this.block()) {
dvpp.devirtualizeContext(this);
dvpp.send(this);
}
}
public NetworkId getNetworkId() {
@Override
public NetworkId networkId() {
return networkId;
}
}

View File

@ -16,7 +16,6 @@
package org.onosproject.incubator.net.virtual.impl.provider;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
@ -32,6 +31,7 @@ import org.onosproject.incubator.net.virtual.TenantId;
import org.onosproject.incubator.net.virtual.VirtualDevice;
import org.onosproject.incubator.net.virtual.VirtualNetwork;
import org.onosproject.incubator.net.virtual.VirtualNetworkAdminService;
import org.onosproject.incubator.net.virtual.VirtualPacketContext;
import org.onosproject.incubator.net.virtual.VirtualPort;
import org.onosproject.incubator.net.virtual.provider.AbstractVirtualProvider;
import org.onosproject.incubator.net.virtual.provider.VirtualPacketProvider;
@ -59,7 +59,6 @@ import org.slf4j.Logger;
import java.nio.ByteBuffer;
import java.util.Dictionary;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@ -87,10 +86,8 @@ public class DefaultVirtualPacketProvider extends AbstractVirtualProvider
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected VirtualProviderRegistryService providerRegistryService;
ApplicationId appId;
InternalPacketProcessor processor;
private Map<VirtualPacketContext, PacketContext> contextMap;
private ApplicationId appId;
private InternalPacketProcessor processor;
private Set<NetworkId> requestsSet = Sets.newHashSet();
@ -106,8 +103,6 @@ public class DefaultVirtualPacketProvider extends AbstractVirtualProvider
appId = coreService.registerApplication("org.onosproject.virtual.virtual-packet");
providerRegistryService.registerProvider(this);
contextMap = Maps.newConcurrentMap();
log.info("Started");
}
@ -128,7 +123,8 @@ public class DefaultVirtualPacketProvider extends AbstractVirtualProvider
@Override
public void emit(NetworkId networkId, OutboundPacket packet) {
packetService.emit(devirtualize(networkId, packet));
devirtualize(networkId, packet)
.forEach(outboundPacket -> packetService.emit(outboundPacket));
}
@Override
@ -149,9 +145,22 @@ public class DefaultVirtualPacketProvider extends AbstractVirtualProvider
}
}
/**
* Send the outbound packet of a virtual context.
* This method is designed to support Context's send() method that invoked
* by applications.
* See {@link org.onosproject.net.packet.PacketContext}
*
* @param virtualPacketContext virtual packet context
*/
protected void send(VirtualPacketContext virtualPacketContext) {
devirtualizeContext(virtualPacketContext)
.forEach(outboundPacket -> packetService.emit(outboundPacket));
}
/**
* Translate the requested physical PacketContext into a virtual PacketContext.
* See {@link org.onosproject.net.packet.OutboundPacket}
* See {@link org.onosproject.net.packet.PacketContext}
*
* @param context A physical PacketContext be translated
* @return A translated virtual PacketContext
@ -177,12 +186,10 @@ public class DefaultVirtualPacketProvider extends AbstractVirtualProvider
ByteBuffer.wrap(eth.serialize()));
VirtualPacketContext vContext =
new VirtualPacketContext(context.time(), inPacket, outPkt,
false, vPort.networkId(),
new DefaultVirtualPacketContext(context.time(), inPacket, outPkt,
context.isHandled(), vPort.networkId(),
this);
contextMap.put(vContext, context);
return vContext;
} else {
return null;
@ -222,33 +229,18 @@ public class DefaultVirtualPacketProvider extends AbstractVirtualProvider
}
/**
* Translate the requested a virtual outbound packet into
* a physical OutboundPacket.
* See {@link org.onosproject.net.packet.PacketContext}
* Translate the requested virtual outbound packet into
* a set of physical OutboundPacket.
* See {@link org.onosproject.net.packet.OutboundPacket}
*
* @param packet A OutboundPacket to be translated
* @return de-virtualized (physical) OutboundPacket
* @param packet an OutboundPacket to be translated
* @return a set of de-virtualized (physical) OutboundPacket
*/
private OutboundPacket devirtualize(NetworkId networkId, OutboundPacket packet) {
private Set<OutboundPacket> devirtualize(NetworkId networkId, OutboundPacket packet) {
Set<OutboundPacket> outboundPackets = new HashSet<>();
Set<VirtualPort> vPorts = vnaService
.getVirtualPorts(networkId, packet.sendThrough());
PortNumber vOutPortNum = packet.treatment().allInstructions().stream()
.filter(i -> i.type() == Instruction.Type.OUTPUT)
.map(i -> ((Instructions.OutputInstruction) i).port())
.findFirst().get();
Optional<ConnectPoint> optionalCpOut = vPorts.stream()
.filter(v -> v.number().equals(vOutPortNum))
.map(v -> v.realizedBy())
.findFirst();
if (!optionalCpOut.isPresent()) {
log.warn("Port {} is not realized yet, in Network {}, Device {}",
vOutPortNum, networkId, packet.sendThrough());
return null;
}
ConnectPoint egressPoint = optionalCpOut.get();
TrafficTreatment.Builder commonTreatmentBuilder
= DefaultTrafficTreatment.builder();
packet.treatment().allInstructions().stream()
@ -256,31 +248,69 @@ public class DefaultVirtualPacketProvider extends AbstractVirtualProvider
.forEach(i -> commonTreatmentBuilder.add(i));
TrafficTreatment commonTreatment = commonTreatmentBuilder.build();
TrafficTreatment treatment = DefaultTrafficTreatment
.builder(commonTreatment)
.setOutput(egressPoint.port()).build();
PortNumber vOutPortNum = packet.treatment().allInstructions().stream()
.filter(i -> i.type() == Instruction.Type.OUTPUT)
.map(i -> ((Instructions.OutputInstruction) i).port())
.findFirst().get();
OutboundPacket outboundPacket = new DefaultOutboundPacket(
egressPoint.deviceId(), treatment, packet.data());
return outboundPacket;
if (!vOutPortNum.isLogical()) {
Optional<ConnectPoint> optionalCpOut = vPorts.stream()
.filter(v -> v.number().equals(vOutPortNum))
.map(v -> v.realizedBy())
.findFirst();
if (!optionalCpOut.isPresent()) {
log.warn("Port {} is not realized yet, in Network {}, Device {}",
vOutPortNum, networkId, packet.sendThrough());
return outboundPackets;
}
ConnectPoint egressPoint = optionalCpOut.get();
TrafficTreatment treatment = DefaultTrafficTreatment
.builder(commonTreatment)
.setOutput(egressPoint.port()).build();
OutboundPacket outboundPacket = new DefaultOutboundPacket(
egressPoint.deviceId(), treatment, packet.data());
outboundPackets.add(outboundPacket);
} else {
if (vOutPortNum == PortNumber.FLOOD) {
for (VirtualPort outPort : vPorts) {
ConnectPoint cpOut = outPort.realizedBy();
if (cpOut != null) {
TrafficTreatment treatment = DefaultTrafficTreatment
.builder(commonTreatment)
.setOutput(cpOut.port()).build();
OutboundPacket outboundPacket = new DefaultOutboundPacket(
cpOut.deviceId(), treatment, packet.data());
outboundPackets.add(outboundPacket);
} else {
log.warn("Port {} is not realized yet, in Network {}, Device {}",
outPort.number(), networkId, packet.sendThrough());
}
}
}
}
return outboundPackets;
}
/**
* Translate the requested a virtual Packet Context into
* a physical Packet Context.
* This method is designed to support Context's send() method that invoked
* by applications.
* See {@link org.onosproject.net.packet.PacketContext}
* Translate the requested virtual packet context into
* a set of physical outbound packets.
*
* @param context A handled packet context
* @param context A handled virtual packet context
*/
public void devirtualizeContext(VirtualPacketContext context) {
NetworkId networkId = context.getNetworkId();
private Set<OutboundPacket> devirtualizeContext(VirtualPacketContext context) {
Set<OutboundPacket> outboundPackets = new HashSet<>();
NetworkId networkId = context.networkId();
TrafficTreatment vTreatment = context.treatmentBuilder().build();
DeviceId sendThrough = context.outPacket().sendThrough();
Set<VirtualPort> vPorts = vnaService
.getVirtualPorts(networkId, sendThrough);
PortNumber vOutPortNum = vTreatment.allInstructions().stream()
.filter(i -> i.type() == Instruction.Type.OUTPUT)
.map(i -> ((Instructions.OutputInstruction) i).port())
@ -294,20 +324,26 @@ public class DefaultVirtualPacketProvider extends AbstractVirtualProvider
TrafficTreatment commonTreatment = commonTreatmentBuilder.build();
if (!vOutPortNum.isLogical()) {
TrafficTreatment treatment = DefaultTrafficTreatment
.builder()
.addTreatment(commonTreatment)
.setOutput(vOutPortNum)
.build();
Optional<ConnectPoint> optionalCpOut = vPorts.stream()
.filter(v -> v.number().equals(vOutPortNum))
.map(v -> v.realizedBy())
.findFirst();
if (!optionalCpOut.isPresent()) {
log.warn("Port {} is not realized yet, in Network {}, Device {}",
vOutPortNum, networkId, sendThrough);
return outboundPackets;
}
ConnectPoint egressPoint = optionalCpOut.get();
emit(networkId, new DefaultOutboundPacket(sendThrough,
treatment,
context.outPacket().data()));
TrafficTreatment treatment = DefaultTrafficTreatment
.builder(commonTreatment)
.setOutput(egressPoint.port()).build();
OutboundPacket outboundPacket = new DefaultOutboundPacket(
egressPoint.deviceId(), treatment, context.outPacket().data());
outboundPackets.add(outboundPacket);
} else {
if (vOutPortNum == PortNumber.FLOOD) {
Set<VirtualPort> vPorts = vnaService
.getVirtualPorts(networkId, sendThrough);
Set<VirtualPort> outPorts = vPorts.stream()
.filter(vp -> !vp.number().isLogical())
.filter(vp -> vp.number() !=
@ -315,18 +351,22 @@ public class DefaultVirtualPacketProvider extends AbstractVirtualProvider
.collect(Collectors.toSet());
for (VirtualPort outPort : outPorts) {
TrafficTreatment treatment = DefaultTrafficTreatment
.builder()
.addTreatment(commonTreatment)
.setOutput(outPort.number())
.build();
emit(networkId, new DefaultOutboundPacket(sendThrough,
treatment,
context.outPacket().data()));
ConnectPoint cpOut = outPort.realizedBy();
if (cpOut != null) {
TrafficTreatment treatment = DefaultTrafficTreatment
.builder(commonTreatment)
.setOutput(cpOut.port()).build();
OutboundPacket outboundPacket = new DefaultOutboundPacket(
cpOut.deviceId(), treatment, context.outPacket().data());
outboundPackets.add(outboundPacket);
} else {
log.warn("Port {} is not realized yet, in Network {}, Device {}",
outPort.number(), networkId, sendThrough);
}
}
}
}
return outboundPackets;
}
private final class InternalPacketProcessor implements PacketProcessor {
@ -341,7 +381,7 @@ public class DefaultVirtualPacketProvider extends AbstractVirtualProvider
VirtualPacketProviderService service =
(VirtualPacketProviderService) providerRegistryService
.getProviderService(vContexts.getNetworkId(),
.getProviderService(vContexts.networkId(),
VirtualPacketProvider.class);
if (service != null) {
service.processPacket(vContexts);