blob: 9ac2504e2077014a1915529c77fc79d12c8978e9 [file] [log] [blame]
Laszlo Papp5f092c42018-01-12 17:31:55 +00001/*
2 * Copyright 2018 Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Laszlo Papp86455232018-03-13 14:32:56 +000017package org.onosproject.drivers.polatis.openflow;
Laszlo Papp5f092c42018-01-12 17:31:55 +000018
19import com.google.common.collect.Range;
20import org.onosproject.net.DeviceId;
21import org.onosproject.net.PortNumber;
22import org.onosproject.net.behaviour.PowerConfig;
23import org.onosproject.net.driver.AbstractHandlerBehaviour;
24
25import org.onosproject.openflow.controller.Dpid;
26import org.onosproject.openflow.controller.OpenFlowController;
27import org.onosproject.openflow.controller.OpenFlowSwitch;
28
29import org.projectfloodlight.openflow.protocol.OFPortConfig;
30import org.projectfloodlight.openflow.protocol.OFPortDesc;
31import org.projectfloodlight.openflow.protocol.OFPortDescProp;
32import org.projectfloodlight.openflow.protocol.OFPortDescPropOptical;
33import org.projectfloodlight.openflow.protocol.OFPortMod;
34import org.projectfloodlight.openflow.protocol.OFPortModProp;
35import org.projectfloodlight.openflow.protocol.OFPortModPropOptical;
36import org.projectfloodlight.openflow.protocol.ver14.OFOpticalPortFeaturesSerializerVer14;
37import org.projectfloodlight.openflow.types.OFPort;
38
39import org.slf4j.Logger;
40
41import java.util.ArrayList;
42import java.util.Collections;
43import java.util.EnumSet;
44import java.util.List;
45import java.util.Optional;
46import java.util.Set;
47
48import static org.onosproject.openflow.controller.Dpid.dpid;
49import static org.slf4j.LoggerFactory.getLogger;
50
51/**
52 * Get current or target port/channel power from an openflow device.
53 * Set target port power or channel attenuation to an openflow device.
54 */
55public class OpenFlowPowerConfig<T> extends AbstractHandlerBehaviour
Andrea Campanelladadf6402019-08-07 15:24:11 +020056 implements PowerConfig<T> {
Laszlo Papp5f092c42018-01-12 17:31:55 +000057
58 private static final Logger log = getLogger(OpenFlowPowerConfig.class);
59
60 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +020061 public Optional<Double> getTargetPower(PortNumber port, T component) {
Laszlo Papp5f092c42018-01-12 17:31:55 +000062 // TODO: OpenFlow does not seem to have the concept of retrieving this
63 // information as only the current power is returned in the port stats
64 // reply. This can be different from the configured value. Perhaps, the
65 // settings in annotations or building a lookup table with the latest
66 // settings could be options.
67 return Optional.empty();
68 }
69
70 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +020071 public void setTargetPower(PortNumber port, T component, double power) {
Laszlo Papp5f092c42018-01-12 17:31:55 +000072 setPortTargetPower(port, power);
73 }
74
75 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +020076 public Optional<Double> currentPower(PortNumber port, T component) {
Laszlo Papp5f092c42018-01-12 17:31:55 +000077 // TODO: Ideally, this needs to read the port stats output for real-time
78 // data or as a short-term workaround, it could get the last read value
79 // from the port stats polling.
80 return null;
81 }
82
83 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +020084 public Optional<Range<Double>> getTargetPowerRange(PortNumber port, T component) {
Laszlo Papp5f092c42018-01-12 17:31:55 +000085 for (OFPortDesc pd : getPortDescs()) {
86 if (pd.getPortNo().getPortNumber() == port.toLong()) {
87 for (OFPortDescProp prop : pd.getProperties()) {
88 if (prop instanceof OFPortDescPropOptical) {
89 OFPortDescPropOptical oprop = (OFPortDescPropOptical) prop;
Andrea Campanelladadf6402019-08-07 15:24:11 +020090 double txMin = oprop.getTxPwrMin();
91 double txMax = oprop.getTxPwrMax();
Laszlo Papp5f092c42018-01-12 17:31:55 +000092 return Optional.of(Range.closed(txMin, txMax));
93 }
94 }
95 }
96 }
97 return Optional.empty();
98 }
99
100 private List<OFPortDesc> getPortDescs() {
101 final Dpid dpid = dpid(handler().data().deviceId().uri());
102 OpenFlowSwitch sw = handler().get(OpenFlowController.class).getSwitch(dpid);
103 return sw.getPorts();
104 }
105
106 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200107 public Optional<Range<Double>> getInputPowerRange(PortNumber port, T component) {
Laszlo Papp5f092c42018-01-12 17:31:55 +0000108 log.warn("Unsupported as OpenFlow does not seem to have the concept of input (presumably rx) power range.");
109 return Optional.empty();
110 }
111
112 @Override
113 public List<PortNumber> getPorts(T component) {
114 List<PortNumber> ports = new ArrayList<>();
115 for (OFPortDesc pd : getPortDescs()) {
116 for (OFPortDescProp prop : pd.getProperties()) {
117 // Note: Power monitor detection can actually be more complex
118 // than this. It is possible that the power is not
119 // configurable, but it is readable. In this case, the best
120 // bet is probably to check rx/tx power info valid in the
121 // port stats reply, unfortunately.
122 if (prop instanceof OFPortDescPropOptical) {
123 ports.add(PortNumber.portNumber(pd.getPortNo().getPortNumber()));
124 break;
125 }
126 }
127 }
128 return ports;
129 }
130
131 private OFPortMod.Builder makePortMod(OpenFlowSwitch sw, PortNumber portNumber,
Andrea Campanelladadf6402019-08-07 15:24:11 +0200132 boolean enable) {
Laszlo Papp5f092c42018-01-12 17:31:55 +0000133 OFPortMod.Builder pmb = sw.factory().buildPortMod();
134 OFPort port = OFPort.of((int) portNumber.toLong());
135 pmb.setPortNo(port);
136 Set<OFPortConfig> portConfig = EnumSet.noneOf(OFPortConfig.class);
137 if (!enable) {
138 portConfig.add(OFPortConfig.PORT_DOWN);
139 }
140 pmb.setConfig(portConfig);
141 Set<OFPortConfig> portMask = EnumSet.noneOf(OFPortConfig.class);
142 portMask.add(OFPortConfig.PORT_DOWN);
143 pmb.setMask(portMask);
144 pmb.setAdvertise(0x0);
145 for (OFPortDesc pd : sw.getPorts()) {
146 if (pd.getPortNo().equals(port)) {
147 pmb.setHwAddr(pd.getHwAddr());
148 break;
149 }
150 }
151 return pmb;
152 }
153
Andrea Campanelladadf6402019-08-07 15:24:11 +0200154 private boolean setPortTargetPower(PortNumber port, double power) {
Laszlo Papp5f092c42018-01-12 17:31:55 +0000155 DeviceId deviceId = handler().data().deviceId();
156 final Dpid dpid = dpid(deviceId.uri());
157 OpenFlowSwitch sw = handler().get(OpenFlowController.class).getSwitch(dpid);
158 if (sw == null || !sw.isConnected()) {
159 log.error("Failed to change port on device {}", deviceId);
160 return false;
161 }
162 boolean enable = false;
163 for (OFPortDesc pd : getPortDescs()) {
164 if (pd.getPortNo().getPortNumber() == port.toLong()) {
165 enable = pd.getConfig().contains(OFPortConfig.PORT_DOWN);
166 break;
167 }
168 }
169 OFPortMod.Builder pmb = makePortMod(sw, port, enable);
Andrea Campanelladadf6402019-08-07 15:24:11 +0200170 double configure = OFOpticalPortFeaturesSerializerVer14.TX_PWR_VAL;
Laszlo Papp5f092c42018-01-12 17:31:55 +0000171 OFPortModPropOptical.Builder property = sw.factory().buildPortModPropOptical();
Andrea Campanelladadf6402019-08-07 15:24:11 +0200172 property.setTxPwr((long) power);
Laszlo Papp5f092c42018-01-12 17:31:55 +0000173
174 List<OFPortModProp> properties = new ArrayList<>();
175 properties.add(property.build());
176 pmb.setProperties(properties);
177
178 sw.sendMsg(Collections.singletonList(pmb.build()));
179 // TODO: We would need to report false in case of port mod failure.
180 return true;
181 }
182}