org.onosproject.incubator.net.virtual.impl.provider.DefaultVirtualPacketProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.onosproject.incubator.net.virtual.impl.provider.DefaultVirtualPacketProvider.java

Source

/*
 * 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.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;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Modified;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.packet.Ethernet;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.incubator.net.virtual.NetworkId;
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.VirtualPort;
import org.onosproject.incubator.net.virtual.provider.AbstractVirtualProvider;
import org.onosproject.incubator.net.virtual.provider.VirtualPacketProvider;
import org.onosproject.incubator.net.virtual.provider.VirtualPacketProviderService;
import org.onosproject.incubator.net.virtual.provider.VirtualProviderRegistryService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flow.instructions.Instructions;
import org.onosproject.net.packet.DefaultInboundPacket;
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.net.provider.ProviderId;
import org.osgi.service.component.ComponentContext;
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;

import static org.slf4j.LoggerFactory.getLogger;

@Component(immediate = true)
public class DefaultVirtualPacketProvider extends AbstractVirtualProvider implements VirtualPacketProvider {

    private static final int PACKET_PROCESSOR_PRIORITY = 1;
    private static final PacketPriority VIRTUAL_PACKET_PRIORITY = PacketPriority.REACTIVE;

    private final Logger log = getLogger(getClass());

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected PacketService packetService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected CoreService coreService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected VirtualNetworkAdminService vnaService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected VirtualProviderRegistryService providerRegistryService;

    ApplicationId appId;
    InternalPacketProcessor processor;

    private Map<VirtualPacketContext, PacketContext> contextMap;

    private Set<NetworkId> requestsSet = Sets.newHashSet();

    /**
     * Creates a provider with the supplied identifier.
     *
     */
    public DefaultVirtualPacketProvider() {
        super(new ProviderId("virtual-packet", "org.onosproject.virtual.virtual-packet"));
    }

    @Activate
    public void activate() {
        appId = coreService.registerApplication("org.onosproject.virtual.virtual-packet");
        providerRegistryService.registerProvider(this);

        contextMap = Maps.newConcurrentMap();

        log.info("Started");
    }

    @Deactivate
    public void deactivate() {
        if (processor != null) {
            packetService.removeProcessor(processor);
        }
        log.info("Stopped");
    }

    @Modified
    protected void modified(ComponentContext context) {
        Dictionary<?, ?> properties = context.getProperties();
    }

    @Override
    public void emit(NetworkId networkId, OutboundPacket packet) {
        packetService.emit(devirtualize(networkId, packet));
    }

    @Override
    public void startPacketHandling(NetworkId networkId) {
        requestsSet.add(networkId);

        if (processor == null) {
            processor = new InternalPacketProcessor();
            packetService.addProcessor(processor, PACKET_PROCESSOR_PRIORITY);
        }
    }

    @Override
    public void stopPacketHandling(NetworkId networkId) {
        requestsSet.remove(networkId);

        if (requestsSet.isEmpty()) {
            packetService.removeProcessor(processor);
            processor = null;
        }
    }

    /**
     * Translate the requested physical PacketContext into a virtual PacketContext.
     * See {@link org.onosproject.net.packet.OutboundPacket}
     *
     * @param context A physical PacketContext be translated
     * @return A translated virtual PacketContext
     */
    private VirtualPacketContext virtualize(PacketContext context) {

        VirtualPort vPort = getMappedVirtualPort(context.inPacket().receivedFrom());

        if (vPort != null) {
            ConnectPoint cp = new ConnectPoint(vPort.element().id(), vPort.number());

            Ethernet eth = context.inPacket().parsed();
            eth.setVlanID(Ethernet.VLAN_UNTAGGED);

            InboundPacket inPacket = new DefaultInboundPacket(cp, eth, ByteBuffer.wrap(eth.serialize()));

            DefaultOutboundPacket outPkt = new DefaultOutboundPacket(cp.deviceId(),
                    DefaultTrafficTreatment.builder().build(), ByteBuffer.wrap(eth.serialize()));

            VirtualPacketContext vContext = new VirtualPacketContext(context.time(), inPacket, outPkt, false,
                    vPort.networkId(), this);

            contextMap.put(vContext, context);

            return vContext;
        } else {
            return null;
        }

    }

    /**
     * Find the corresponding virtual port with the physical port.
     *
     * @param cp the connect point for the physical network
     * @return a virtual port
     */
    private VirtualPort getMappedVirtualPort(ConnectPoint cp) {
        Set<TenantId> tIds = vnaService.getTenantIds();

        Set<VirtualNetwork> vNetworks = new HashSet<>();
        tIds.forEach(tid -> vNetworks.addAll(vnaService.getVirtualNetworks(tid)));

        for (VirtualNetwork vNet : vNetworks) {
            Set<VirtualDevice> vDevices = vnaService.getVirtualDevices(vNet.id());

            Set<VirtualPort> vPorts = new HashSet<>();
            vDevices.forEach(dev -> vPorts.addAll(vnaService.getVirtualPorts(dev.networkId(), dev.id())));

            VirtualPort vPort = vPorts.stream().filter(vp -> vp.realizedBy().equals(cp)).findFirst().orElse(null);

            if (vPort != null) {
                return vPort;
            }
        }

        return null;
    }

    /**
     * Translate the requested a virtual outbound packet into
     * a physical OutboundPacket.
     * See {@link org.onosproject.net.packet.PacketContext}
     *
     * @param packet A OutboundPacket to be translated
     * @return de-virtualized (physical) OutboundPacket
     */
    private OutboundPacket devirtualize(NetworkId networkId, OutboundPacket packet) {
        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().filter(i -> i.type() != Instruction.Type.OUTPUT)
                .forEach(i -> commonTreatmentBuilder.add(i));
        TrafficTreatment commonTreatment = commonTreatmentBuilder.build();

        TrafficTreatment treatment = DefaultTrafficTreatment.builder(commonTreatment).setOutput(egressPoint.port())
                .build();

        OutboundPacket outboundPacket = new DefaultOutboundPacket(egressPoint.deviceId(), treatment, packet.data());
        return outboundPacket;
    }

    /**
     * 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}
     *
     * @param context A handled packet context
     */
    public void devirtualizeContext(VirtualPacketContext context) {
        NetworkId networkId = context.getNetworkId();

        TrafficTreatment vTreatment = context.treatmentBuilder().build();

        DeviceId sendThrough = context.outPacket().sendThrough();

        PortNumber vOutPortNum = vTreatment.allInstructions().stream()
                .filter(i -> i.type() == Instruction.Type.OUTPUT)
                .map(i -> ((Instructions.OutputInstruction) i).port()).findFirst().get();

        TrafficTreatment.Builder commonTreatmentBuilder = DefaultTrafficTreatment.builder();
        vTreatment.allInstructions().stream().filter(i -> i.type() != Instruction.Type.OUTPUT)
                .forEach(i -> commonTreatmentBuilder.add(i));
        TrafficTreatment commonTreatment = commonTreatmentBuilder.build();

        if (!vOutPortNum.isLogical()) {
            TrafficTreatment treatment = DefaultTrafficTreatment.builder().addTreatment(commonTreatment)
                    .setOutput(vOutPortNum).build();

            emit(networkId, new DefaultOutboundPacket(sendThrough, treatment, context.outPacket().data()));
        } else {
            if (vOutPortNum == PortNumber.FLOOD) {
                Set<VirtualPort> vPorts = vnaService.getVirtualPorts(networkId, sendThrough);

                Set<VirtualPort> outPorts = vPorts.stream()
                        .filter(vp -> vp.number() != context.inPacket().receivedFrom().port())
                        .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()));
                }
            }
        }
    }

    private final class InternalPacketProcessor implements PacketProcessor {

        @Override
        public void process(PacketContext context) {
            VirtualPacketContext vContexts = virtualize(context);

            if (vContexts == null) {
                return;
            }

            VirtualPacketProviderService service = (VirtualPacketProviderService) providerRegistryService
                    .getProviderService(vContexts.getNetworkId(), VirtualPacketProvider.class);
            if (service != null) {
                service.processPacket(vContexts);
            }
        }
    }
}