| /* |
| * Copyright 2018-present 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.odtn; |
| |
| import com.google.common.collect.ImmutableList; |
| import org.onlab.util.Frequency; |
| import org.onosproject.drivers.odtn.impl.DeviceConnectionCache; |
| import org.onosproject.drivers.odtn.impl.FlowRuleParser; |
| import org.onosproject.net.DeviceId; |
| import org.onosproject.net.Port; |
| import org.onosproject.net.PortNumber; |
| import org.onosproject.net.device.DeviceService; |
| import org.onosproject.net.driver.AbstractHandlerBehaviour; |
| import org.onosproject.net.flow.DefaultFlowEntry; |
| import org.onosproject.net.flow.FlowEntry; |
| import org.onosproject.net.flow.FlowRule; |
| import org.onosproject.net.flow.FlowRuleProgrammable; |
| import org.onosproject.netconf.DatastoreId; |
| import org.onosproject.netconf.NetconfController; |
| import org.onosproject.netconf.NetconfException; |
| import org.onosproject.netconf.NetconfSession; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.List; |
| |
| import static com.google.common.base.Preconditions.checkNotNull; |
| import static org.onosproject.odtn.behaviour.OdtnDeviceDescriptionDiscovery.OC_NAME; |
| |
| /** |
| * Implementation of FlowRuleProgrammable interface for |
| * OpenConfig terminal devices. |
| */ |
| public class NokiaFlowRuleProgrammable |
| extends AbstractHandlerBehaviour implements FlowRuleProgrammable { |
| |
| private static final Logger log = |
| LoggerFactory.getLogger(NokiaFlowRuleProgrammable.class); |
| |
| /** |
| * Apply the flow entries specified in the collection rules. |
| * |
| * @param rules A collection of Flow Rules to be applied |
| * @return The collection of added Flow Entries |
| */ |
| @Override |
| public Collection<FlowRule> applyFlowRules(Collection<FlowRule> rules) { |
| NetconfSession session = getNetconfSession(); |
| if (session == null) { |
| openConfigError("null session"); |
| return ImmutableList.of(); |
| } |
| List<FlowRule> added = new ArrayList<>(); |
| for (FlowRule r : rules) { |
| try { |
| String connectionId = applyFlowRule(session, r); |
| getConnectionCache().add(did(), connectionId, r); |
| added.add(r); |
| } catch (Exception e) { |
| openConfigError("Error {}", e); |
| continue; |
| } |
| } |
| openConfigLog("applyFlowRules added {}", added.size()); |
| return added; |
| } |
| |
| /** |
| * Get the flow entries that are present on the device. |
| * |
| * @return A collection of Flow Entries |
| */ |
| @Override |
| public Collection<FlowEntry> getFlowEntries() { |
| DeviceConnectionCache cache = getConnectionCache(); |
| if (cache.get(did()) == null) { |
| return ImmutableList.of(); |
| } |
| |
| List<FlowEntry> entries = new ArrayList<>(); |
| for (FlowRule r : cache.get(did())) { |
| entries.add( |
| new DefaultFlowEntry(r, FlowEntry.FlowEntryState.ADDED, 0, 0, 0)); |
| } |
| return entries; |
| } |
| |
| /** |
| * Remove the specified flow rules. |
| * |
| * @param rules A collection of Flow Rules to be removed |
| * @return The collection of removed Flow Entries |
| */ |
| @Override |
| public Collection<FlowRule> removeFlowRules(Collection<FlowRule> rules) { |
| NetconfSession session = getNetconfSession(); |
| if (session == null) { |
| openConfigError("null session"); |
| return ImmutableList.of(); |
| } |
| List<FlowRule> removed = new ArrayList<>(); |
| for (FlowRule r : rules) { |
| try { |
| String connectionId = removeFlowRule(session, r); |
| getConnectionCache().remove(did(), connectionId); |
| removed.add(r); |
| } catch (Exception e) { |
| openConfigError("Error {}", e); |
| continue; |
| } |
| } |
| openConfigLog("removedFlowRules removed {}", removed.size()); |
| return removed; |
| } |
| |
| private DeviceConnectionCache getConnectionCache() { |
| return DeviceConnectionCache.init(); |
| } |
| |
| /** |
| * Helper method to get the device id. |
| */ |
| private DeviceId did() { |
| return data().deviceId(); |
| } |
| |
| /** |
| * Helper method to log from this class adding DeviceId. |
| */ |
| private void openConfigLog(String format, Object... arguments) { |
| log.info("OPENCONFIG {}: " + format, did(), arguments); |
| } |
| |
| /** |
| * Helper method to log an error from this class adding DeviceId. |
| */ |
| private void openConfigError(String format, Object... arguments) { |
| log.error("OPENCONFIG {}: " + format, did(), arguments); |
| } |
| |
| |
| /** |
| * Helper method to get the Netconf Session. |
| */ |
| private NetconfSession getNetconfSession() { |
| NetconfController controller = |
| checkNotNull(handler().get(NetconfController.class)); |
| return controller.getNetconfDevice(did()).getSession(); |
| } |
| |
| private void setOpticalChannelFrequency(NetconfSession session, |
| String optChannel, Frequency freq) |
| throws NetconfException { |
| String[] textStr = optChannel.split("-"); |
| StringBuilder sb = new StringBuilder(); |
| sb.append( |
| "<components xmlns='http://openconfig.net/yang/platform'>" |
| + "<component operation='merge'>" |
| + "<name>" + "OCH-" + textStr[1] + "-" + textStr[2] + "-" + textStr[3] + "</name>" |
| + "<oc-opt-term:optical-channel " |
| + |
| " xmlns:oc-opt-term='http://openconfig.net/yang/terminal-device'>" |
| + " <oc-opt-term:config>" |
| + " <oc-opt-term:frequency>" + (long) freq.asMHz() + |
| "</oc-opt-term:frequency>" |
| + " </oc-opt-term:config>" |
| + " </oc-opt-term:optical-channel>" |
| + "</component>" |
| + "</components>"); |
| |
| boolean ok = |
| session.editConfig(DatastoreId.RUNNING, null, sb.toString()); |
| if (!ok) { |
| throw new NetconfException("error writing channel frequency"); |
| } |
| } |
| |
| /** |
| * Get the OpenConfig component name for the OpticalChannel component. |
| * |
| * @param portNumber ONOS port number of the Line port (). |
| * @return the channel component name or null |
| */ |
| private String getOpticalChannel(PortNumber portNumber) { |
| Port clientPort = handler().get(DeviceService.class).getPort(did(), portNumber); |
| return clientPort.annotations().value(OC_NAME); |
| } |
| |
| /** |
| * Apply the flowrule. |
| * |
| * Note: only bidirectional are supported as of now, |
| * given OpenConfig note (below). In consequence, only the |
| * TX rules are actually mapped to netconf ops. |
| * <p> |
| * https://github.com/openconfig/public/blob/master/release/models |
| * /optical-transport/openconfig-terminal-device.yang |
| * <p> |
| * Directionality: |
| * To maintain simplicity in the model, the configuration is |
| * described from client-to-line direction. The assumption is that |
| * equivalent reverse configuration is implicit, resulting in |
| * the same line-to-client configuration. |
| * |
| * @param session The Netconf session. |
| * @param r Flow Rules to be applied. |
| * @return the optical channel + the frequency or just channel as identifier fo the config installed on the device |
| * @throws NetconfException if exchange goes wrong |
| */ |
| protected String applyFlowRule(NetconfSession session, FlowRule r) throws NetconfException { |
| FlowRuleParser frp = new FlowRuleParser(r); |
| if (!frp.isReceiver()) { |
| String optChannel = getOpticalChannel(frp.getPortNumber()); |
| setOpticalChannelFrequency(session, optChannel, |
| frp.getCentralFrequency()); |
| return optChannel + ":" + frp.getCentralFrequency().asGHz(); |
| } |
| return String.valueOf(frp.getCentralFrequency().asGHz()); |
| } |
| |
| |
| protected String removeFlowRule(NetconfSession session, FlowRule r) |
| throws NetconfException { |
| FlowRuleParser frp = new FlowRuleParser(r); |
| if (!frp.isReceiver()) { |
| String optChannel = getOpticalChannel(frp.getPortNumber()); |
| setOpticalChannelFrequency(session, optChannel, Frequency.ofMHz(0)); |
| return optChannel + ":" + frp.getCentralFrequency().asGHz(); |
| } |
| return String.valueOf(frp.getCentralFrequency().asGHz()); |
| } |
| } |