org.onosproject.drivers.oplink.OplinkOpticalPowerConfig.java Source code

Java tutorial

Introduction

Here is the source code for org.onosproject.drivers.oplink.OplinkOpticalPowerConfig.java

Source

/*
 * Copyright 2016 Open Networking Foundation
 *
 * 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.drivers.oplink;

import com.google.common.collect.Range;
import org.apache.commons.configuration.HierarchicalConfiguration;
import org.onosproject.driver.extensions.OplinkAttenuation;
import org.onosproject.net.Device;
import org.onosproject.net.Direction;
import org.onosproject.net.OchSignal;
import org.onosproject.net.PortNumber;
import org.onosproject.net.behaviour.PowerConfig;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.driver.AbstractHandlerBehaviour;
import org.onosproject.net.flow.DefaultFlowRule;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.FlowRuleService;
import org.onosproject.net.flow.TrafficTreatment;
import org.slf4j.Logger;

import java.util.Optional;

import static org.onosproject.drivers.oplink.OplinkOpticalUtility.POWER_MULTIPLIER;
import static org.onosproject.drivers.oplink.OplinkOpticalUtility.RANGE_ATT;
import static org.onosproject.drivers.oplink.OplinkOpticalUtility.RANGE_GENERAL;
import static org.onosproject.drivers.oplink.OplinkNetconfUtility.*;
import static org.slf4j.LoggerFactory.getLogger;

/**
 * Get current or target port/channel power from an Oplink optical netconf device.
 * Set target port power or channel attenuation to an optical netconf device.
 */
public class OplinkOpticalPowerConfig<T> extends AbstractHandlerBehaviour implements PowerConfig<T> {

    // key
    public static final String KEY_CHNUM = "wavelength-number";
    public static final String KEY_CHPWR = "wavelength-power";
    public static final String KEY_CHSTATS = "wavelength-stats";
    public static final String KEY_OCMSTATS = "ocm-stats";
    public static final String KEY_PORTDIRECT_RX = "rx";
    public static final String KEY_PORTDIRECT_TX = "tx";
    public static final String KEY_PORTTARPWR = "port-target-power";
    public static final String KEY_PORTCURPWR = "port-current-power";
    public static final String KEY_PORTPROPERTY = "port-property";
    public static final String KEY_PORTPWRCAPMINRX = "port-power-capability-min-rx";
    public static final String KEY_PORTPWRCAPMAXRX = "port-power-capability-max-rx";
    public static final String KEY_PORTPWRCAPMINTX = "port-power-capability-min-tx";
    public static final String KEY_PORTPWRCAPMAXTX = "port-power-capability-max-tx";
    public static final String KEY_PORTS_PORT = String.format("%s.%s", KEY_DATA_PORTS, KEY_PORT);
    public static final String KEY_PORTS_PORT_PROPERTY = String.format("%s.%s", KEY_PORTS_PORT, KEY_PORTPROPERTY);
    public static final String KEY_OCMS = "ocms";
    // log
    private static final Logger log = getLogger(OplinkOpticalPowerConfig.class);

    @Override
    public Optional<Long> getTargetPower(PortNumber port, T component) {
        return Optional.ofNullable(acquireTargetPower(port, component));
    }

    @Override
    public void setTargetPower(PortNumber port, T component, long power) {
        if (component instanceof OchSignal) {
            setChannelTargetPower(port, (OchSignal) component, power);
        } else {
            setPortTargetPower(port, power);
        }
    }

    @Override
    public Optional<Long> currentPower(PortNumber port, T component) {
        return Optional.ofNullable(acquireCurrentPower(port, component));
    }

    @Override
    public Optional<Range<Long>> getTargetPowerRange(PortNumber port, T component) {
        return Optional.ofNullable(getTxPowerRange(port, component));
    }

    @Override
    public Optional<Range<Long>> getInputPowerRange(PortNumber port, T component) {
        return Optional.ofNullable(getRxPowerRange(port, component));
    }

    private String getPortPowerFilter(PortNumber port, String selection) {
        return new StringBuilder(xmlOpen(KEY_OPENOPTICALDEV_XMLNS)).append(xmlOpen(KEY_PORTS))
                .append(xml(KEY_PORTID, Long.toString(port.toLong()))).append(xmlOpen(KEY_PORT))
                .append(xmlEmpty(selection)).append(xmlClose(KEY_PORT)).append(xmlClose(KEY_PORTS))
                .append(xmlClose(KEY_OPENOPTICALDEV)).toString();
    }

    private String getChannelPowerFilter(PortNumber port, OchSignal channel) {
        return new StringBuilder(xmlOpen(KEY_OPENOPTICALDEV_XMLNS)).append(xmlOpen(KEY_OCMS))
                .append(xml(KEY_PORTID, Long.toString(port.toLong()))).append(xmlOpen(KEY_OCMSTATS))
                .append(xml(KEY_CHNUM, Integer.toString(channel.spacingMultiplier()))).append(xmlEmpty(KEY_CHSTATS))
                .append(xmlClose(KEY_OCMSTATS)).append(xmlClose(KEY_OCMS)).append(xmlClose(KEY_OPENOPTICALDEV))
                .toString();
    }

    private String getChannelAttenuationFilter(PortNumber port, OchSignal channel) {
        return new StringBuilder(xmlOpen(KEY_OPENOPTICALDEV_XMLNS)).append(xmlOpen(KEY_CONNS))
                .append(xml(KEY_CONNID, Integer.toString(channel.spacingMultiplier()))).append(xmlEmpty(KEY_CHATT))
                .append(xmlClose(KEY_CONNS)).append(xmlClose(KEY_OPENOPTICALDEV)).toString();
    }

    private String getPowerRangeFilter(PortNumber port, String direction) {
        return new StringBuilder(xmlOpen(KEY_OPENOPTICALDEV_XMLNS)).append(xmlOpen(KEY_PORTS))
                .append(xml(KEY_PORTID, Long.toString(port.toLong()))).append(xmlOpen(KEY_PORT))
                .append(xml(KEY_PORTDIRECT, direction)).append(xmlEmpty(KEY_PORTPROPERTY))
                .append(xmlClose(KEY_PORT)).append(xmlClose(KEY_PORTS)).append(xmlClose(KEY_OPENOPTICALDEV))
                .toString();
    }

    private Long acquireTargetPower(PortNumber port, T component) {
        if (component instanceof OchSignal) {
            return acquireChannelAttenuation(port, (OchSignal) component);
        }
        log.debug("Get port{} target power...", port);
        return acquirePortPower(port, KEY_PORTTARPWR);
    }

    private Long acquireCurrentPower(PortNumber port, T component) {
        if (component instanceof OchSignal) {
            return acquireChannelPower(port, (OchSignal) component);
        }
        log.debug("Get port{} current power...", port);
        return acquirePortPower(port, KEY_PORTCURPWR);
    }

    private Long acquirePortPower(PortNumber port, String selection) {
        String reply = netconfGet(handler(), getPortPowerFilter(port, selection));
        HierarchicalConfiguration info = configAt(reply, KEY_PORTS_PORT);
        if (info == null) {
            return null;
        }
        return (long) (info.getDouble(selection) * POWER_MULTIPLIER);
    }

    private Long acquireChannelAttenuation(PortNumber port, OchSignal channel) {
        log.debug("Get port{} channel{} attenuation...", port, channel.channelSpacing());
        String reply = netconfGet(handler(), getChannelAttenuationFilter(port, channel));
        HierarchicalConfiguration info = configAt(reply, KEY_CONNS);
        if (info == null) {
            return null;
        }
        return (long) (info.getDouble(KEY_CHATT) * POWER_MULTIPLIER);
    }

    private Long acquireChannelPower(PortNumber port, OchSignal channel) {
        log.debug("Get port{} channel{} power...", port, channel.channelSpacing());
        String reply = netconfGet(handler(), getChannelPowerFilter(port, channel));
        HierarchicalConfiguration info = configAt(reply, KEY_DATA_CONNS);
        if (info == null) {
            return null;
        }
        return (long) (info.getDouble(KEY_CHPWR) * POWER_MULTIPLIER);
    }

    private boolean setPortTargetPower(PortNumber port, long power) {
        log.debug("Set port{} target power...", port);
        String cfg = new StringBuilder(xmlOpen(KEY_OPENOPTICALDEV_XMLNS)).append(xmlOpen(KEY_PORTS))
                .append(xml(KEY_PORTID, Long.toString(port.toLong()))).append(xmlOpen(KEY_PORT))
                .append(xml(KEY_PORTTARPWR, Long.toString(power))).append(xmlClose(KEY_PORT))
                .append(xmlClose(KEY_PORTS)).append(xmlClose(KEY_OPENOPTICALDEV)).toString();
        return netconfEditConfig(handler(), CFG_MODE_MERGE, cfg);
    }

    private boolean setChannelTargetPower(PortNumber port, OchSignal channel, long power) {
        log.debug("Set port{} channel{} attenuation.", port, channel.channelSpacing());
        FlowRuleService service = handler().get(FlowRuleService.class);
        Iterable<FlowEntry> entries = service.getFlowEntries(data().deviceId());
        for (FlowEntry entry : entries) {
            OplinkCrossConnect crossConnect = OplinkOpticalUtility.fromFlowRule(this, entry);
            // The channel port might be input port or output port.
            if ((port.equals(crossConnect.getInPort()) || port.equals(crossConnect.getOutPort()))
                    && channel.spacingMultiplier() == crossConnect.getChannel()) {
                log.debug("Flow is found, modify the flow with attenuation.");
                // Modify attenuation in treatment
                TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(crossConnect.getOutPort())
                        .extension(new OplinkAttenuation((int) power), data().deviceId()).build();
                // Apply the new flow rule
                service.applyFlowRules(DefaultFlowRule.builder().forDevice(data().deviceId()).makePermanent()
                        .withSelector(entry.selector()).withTreatment(treatment).withPriority(entry.priority())
                        .withCookie(entry.id().value()).build());
                return true;
            }
        }
        return false;
    }

    private Range<Long> getPowerRange(PortNumber port, String directionKey, String minKey, String maxKey) {
        // TODO
        // Optical protection switch does not support power range configuration, it'll reply error.
        // To prevent replying error log flooding from netconf session when polling all ports information,
        // use general power range of [-60, 60] instead.
        if (handler().get(DeviceService.class).getDevice(data().deviceId()).type() == Device.Type.FIBER_SWITCH) {
            return RANGE_GENERAL;
        }
        String reply = netconfGet(handler(), getPowerRangeFilter(port, directionKey));
        HierarchicalConfiguration info = configAt(reply, KEY_PORTS_PORT_PROPERTY);
        if (info == null) {
            return null;
        }
        long minPower = (long) (info.getDouble(minKey) * POWER_MULTIPLIER);
        long maxPower = (long) (info.getDouble(maxKey) * POWER_MULTIPLIER);
        return Range.closed(minPower, maxPower);
    }

    private Range<Long> getTxPowerRange(PortNumber port, T component) {
        if (component instanceof Direction) {
            log.debug("Get target port{} power range...", port);
            return getPowerRange(port, KEY_PORTDIRECT_TX, KEY_PORTPWRCAPMINTX, KEY_PORTPWRCAPMAXTX);
        } else {
            log.debug("Get channel attenuation range...");
            return RANGE_ATT;
        }
    }

    private Range<Long> getRxPowerRange(PortNumber port, T component) {
        log.debug("Get input port{} power range...", port);
        return getPowerRange(port, KEY_PORTDIRECT_RX, KEY_PORTPWRCAPMINRX, KEY_PORTPWRCAPMAXRX);
    }
}