org.onosproject.driver.optical.handshaker.OplinkHandshakerUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.onosproject.driver.optical.handshaker.OplinkHandshakerUtil.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.driver.optical.handshaker;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.onosproject.drivers.optical.OpticalAdjacencyLinkService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.Annotations;
import org.onosproject.net.DefaultAnnotations;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Link;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DefaultPortDescription;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.device.PortDescription;
import org.onosproject.net.link.DefaultLinkDescription;
import org.onosproject.net.link.LinkService;
import org.onosproject.net.optical.OpticalAnnotations;
import org.onosproject.openflow.controller.Dpid;
import org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver;
import org.projectfloodlight.openflow.protocol.OFCircuitPortsRequest;
import org.projectfloodlight.openflow.protocol.OFExpExtAdId;
import org.projectfloodlight.openflow.protocol.OFExpPortAdidOtn;
import org.projectfloodlight.openflow.protocol.OFExpPortAdjacency;
import org.projectfloodlight.openflow.protocol.OFExpPortAdjacencyId;
import org.projectfloodlight.openflow.protocol.OFExpPortAdjacencyRequest;
import org.projectfloodlight.openflow.protocol.OFOplinkPortPower;
import org.projectfloodlight.openflow.protocol.OFOplinkPortPowerRequest;

import org.slf4j.Logger;

import static org.slf4j.LoggerFactory.getLogger;

/**
 * Oplink handshaker utility.
 */
public class OplinkHandshakerUtil {

    // Parent driver instance
    private OpenFlowSwitchDriver driver;
    // Total count of opspec in OFExpPortAdidOtn
    private static final int OPSPEC_BYTES = 32;
    // Bit count of id in opspec
    private static final int OPSPEC_ID_BITS = 4;
    // Start byte position of mac info
    private static final int OPSPEC_MAC_POS = 18;
    // Bit offset for mac
    private static final int OPSPEC_MAC_BIT_OFF = 16;
    // Start byte position of port info
    private static final int OPSPEC_PORT_POS = 24;
    // Right bit offset for mac
    private static final int OPSPEC_PORT_BIT_OFF = 32;

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

    /**
     * Create a new OplinkHandshakerUtil.
     * @param driver parent driver instance
     */
    public OplinkHandshakerUtil(OpenFlowSwitchDriver driver) {
        this.driver = driver;
    }

    /**
     * Creates an oplink port power request OF message.
     *
     * @return OF message of oplink port power request
     */
    public OFOplinkPortPowerRequest buildPortPowerRequest() {
        OFOplinkPortPowerRequest request = driver.factory().buildOplinkPortPowerRequest()
                .setXid(driver.getNextTransactionId()).build();
        return request;
    }

    /**
     * Creates port adjacency request OF message.
     *
     * @return OF message of oplink port adjacency request
     */
    public OFExpPortAdjacencyRequest buildPortAdjacencyRequest() {
        OFExpPortAdjacencyRequest request = driver.factory().buildExpPortAdjacencyRequest()
                .setXid(driver.getNextTransactionId()).build();
        return request;
    }

    /**
     * Creates an oplink port description request OF message.
     *
     * @return OF message of oplink port description request
     */
    public OFCircuitPortsRequest buildCircuitPortsRequest() {
        OFCircuitPortsRequest request = driver.factory().buildCircuitPortsRequest()
                .setXid(driver.getNextTransactionId()).build();
        return request;
    }

    /**
     * Creates port descriptions with current power.
     *
     * @param portPowers current power
     * @return port descriptions
     */
    public List<PortDescription> buildPortPowerDescriptions(List<OFOplinkPortPower> portPowers) {
        DeviceService deviceService = driver.handler().get(DeviceService.class);
        List<Port> ports = deviceService.getPorts(driver.data().deviceId());
        HashMap<Long, OFOplinkPortPower> powerMap = new HashMap<>(portPowers.size());
        // Get each port power value
        portPowers.forEach(power -> powerMap.put((long) power.getPort(), power));
        final List<PortDescription> portDescs = new ArrayList<>();
        for (Port port : ports) {
            DefaultAnnotations.Builder builder = DefaultAnnotations.builder();
            builder.putAll(port.annotations());
            OFOplinkPortPower power = powerMap.get(port.number().toLong());
            if (power != null) {
                // power value is actually signed-short value, down casting to recover sign bit.
                builder.set(OpticalAnnotations.CURRENT_POWER, Short.toString((short) power.getPowerValue()));
            }
            portDescs.add(new DefaultPortDescription(port.number(), port.isEnabled(), port.type(), port.portSpeed(),
                    builder.build()));
        }
        return portDescs;
    }

    /**
     * Creates port descriptions with adjacency.
     *
     * @param portAds adjacency information
     * @return port descriptions
     */
    public List<PortDescription> buildPortAdjacencyDescriptions(List<OFExpPortAdjacency> portAds) {
        DeviceService deviceService = driver.handler().get(DeviceService.class);
        List<Port> ports = deviceService.getPorts(driver.data().deviceId());
        // Map port's number with port's adjacency
        HashMap<Long, OFExpPortAdjacency> adMap = new HashMap<>(portAds.size());
        portAds.forEach(ad -> adMap.put((long) ad.getPortNo().getPortNumber(), ad));
        List<PortDescription> portDescs = new ArrayList<>();
        for (Port port : ports) {
            DefaultAnnotations.Builder builder = DefaultAnnotations.builder();
            Annotations oldAnnotations = port.annotations();
            builder.putAll(oldAnnotations);
            OFExpPortAdjacency ad = adMap.get(port.number().toLong());
            OplinkPortAdjacency neighbor = getNeighbor(ad);
            if (!linkValidation(deviceService, neighbor)) {
                // no neighbors found
                builder.remove(OpticalAnnotations.NEIGHBOR_ID);
                builder.remove(OpticalAnnotations.NEIGHBOR_PORT);
                removeLink(port.number());
            } else {
                // neighbor discovered, add to port descriptions
                String newId = neighbor.getDeviceId().toString();
                String newPort = neighbor.getPort().toString();
                // Check if annotation already exists
                if (!newId.equals(oldAnnotations.value(OpticalAnnotations.NEIGHBOR_ID))
                        || !newPort.equals(oldAnnotations.value(OpticalAnnotations.NEIGHBOR_PORT))) {
                    builder.set(OpticalAnnotations.NEIGHBOR_ID, newId);
                    builder.set(OpticalAnnotations.NEIGHBOR_PORT, newPort);
                }
                addLink(port.number(), neighbor);
            }
            portDescs.add(new DefaultPortDescription(port.number(), port.isEnabled(), port.type(), port.portSpeed(),
                    builder.build()));
        }
        return portDescs;
    }

    private OplinkPortAdjacency getNeighbor(OFExpPortAdjacency ad) {
        // Check input parameter
        if (ad == null) {
            return null;
        }
        // Get adjacency properties
        for (OFExpPortAdjacencyId adid : ad.getProperties()) {
            List<OFExpExtAdId> otns = adid.getAdId();
            if (otns != null && otns.size() > 0) {
                OFExpPortAdidOtn otn = (OFExpPortAdidOtn) otns.get(0);
                // ITU-T G.7714 ETH MAC Format (in second 16 bytes of the following)
                // |---------------------------------------------------------------------------|
                // | Other format (16 bytes)                                                   |
                // |---------------------------------------------------------------------------|
                // | Header (2 bytes) | ID (4 BITS) | MAC (6 bytes) | Port (4 bytes) | Unused  |
                // |---------------------------------------------------------------------------|
                ByteBuf buffer = Unpooled.buffer(OPSPEC_BYTES);
                otn.getOpspec().write32Bytes(buffer);
                long mac = buffer.getLong(OPSPEC_MAC_POS) << OPSPEC_ID_BITS >>> OPSPEC_MAC_BIT_OFF;
                int port = (int) (buffer.getLong(OPSPEC_PORT_POS) << OPSPEC_ID_BITS >>> OPSPEC_PORT_BIT_OFF);
                // Oplink does not use the 4 most significant bytes of Dpid so Dpid can be
                // constructed from MAC address
                return new OplinkPortAdjacency(DeviceId.deviceId(Dpid.uri(new Dpid(mac))),
                        PortNumber.portNumber(port));
            }
        }
        // Returns null if no properties found
        return null;
    }

    private boolean linkValidation(DeviceService deviceService, OplinkPortAdjacency neighbor) {
        // check neighbor object
        if (neighbor == null) {
            return false;
        }
        // check src device is validate or not
        if (!deviceService.isAvailable(neighbor.getDeviceId())) {
            log.debug("Invalid adjacency device. devId = {}", neighbor.getDeviceId());
            return false;
        }
        // check src port is validate or not
        if (deviceService.getPort(neighbor.getDeviceId(), neighbor.getPort()) == null) {
            log.debug("Invalid adjacency port. devId = {}, port = {}", neighbor.getDeviceId(), neighbor.getPort());
            return false;
        }
        // validate link
        return true;
    }

    // Add incoming link with port
    private void addLink(PortNumber portNumber, OplinkPortAdjacency neighbor) {
        ConnectPoint dst = new ConnectPoint(driver.handler().data().deviceId(), portNumber);
        Set<Link> links = driver.handler().get(LinkService.class).getIngressLinks(dst);
        // find out if the new report link is the same as before
        for (Link link : links) {
            if (link.src().port().equals(neighbor.getPort())) {
                return;
            }
        }
        OpticalAdjacencyLinkService adService = driver.handler().get(OpticalAdjacencyLinkService.class);
        // remove the old link of destination connect point
        if (!links.isEmpty()) {
            log.debug("Remove link of destination {}.", dst);
            adService.linksVanished(dst);
        }
        // add the new link
        ConnectPoint src = new ConnectPoint(neighbor.getDeviceId(), neighbor.getPort());
        log.debug("Add link from {} to {}.", src, dst);
        adService.linkDetected(new DefaultLinkDescription(src, dst, Link.Type.OPTICAL));
    }

    // Remove incoming link with port if there are any.
    private void removeLink(PortNumber portNumber) {
        ConnectPoint dst = new ConnectPoint(driver.handler().data().deviceId(), portNumber);
        // Check so only incoming links are removed
        Set<Link> links = driver.handler().get(LinkService.class).getIngressLinks(dst);
        // If link exists, remove it, otherwise return
        if (links.isEmpty()) {
            return;
        }
        log.debug("Remove link for {}.", dst);
        driver.handler().get(OpticalAdjacencyLinkService.class).linksVanished(dst);
    }

    private class OplinkPortAdjacency {
        private DeviceId deviceId;
        private PortNumber portNumber;

        public OplinkPortAdjacency(DeviceId deviceId, PortNumber portNumber) {
            this.deviceId = deviceId;
            this.portNumber = portNumber;
        }

        public DeviceId getDeviceId() {
            return deviceId;
        }

        public PortNumber getPort() {
            return portNumber;
        }
    }
}