blob: b0dc68d73f2d7390ed1ba09bf73e4ba7eec3ab46 [file] [log] [blame]
yjimmyy646aa022016-07-05 12:09:50 -07001/*
2 * Copyright 2016 Open Networking Laboratory
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
17package org.onosproject.driver.optical.power;
18
yjimmyycfcb0532016-07-11 16:03:48 -070019import java.util.List;
yjimmyy646aa022016-07-05 12:09:50 -070020import java.util.Optional;
21
yjimmyycfcb0532016-07-11 16:03:48 -070022import org.onosproject.driver.extensions.OplinkAttenuation;
23import org.onosproject.net.OchSignal;
yjimmyy646aa022016-07-05 12:09:50 -070024import org.onosproject.net.driver.AbstractHandlerBehaviour;
25import org.onosproject.net.Direction;
26import org.onosproject.net.Port;
27import org.onosproject.net.PortNumber;
28import org.onosproject.net.behaviour.PowerConfig;
29import org.onosproject.net.device.DeviceService;
yjimmyycfcb0532016-07-11 16:03:48 -070030import org.onosproject.net.flow.DefaultFlowRule;
31import org.onosproject.net.flow.DefaultTrafficTreatment;
32import org.onosproject.net.flow.FlowEntry;
33import org.onosproject.net.flow.FlowRule;
34import org.onosproject.net.flow.FlowRuleService;
35import org.onosproject.net.flow.TrafficSelector;
36import org.onosproject.net.flow.TrafficTreatment;
37import org.onosproject.net.flow.criteria.Criterion;
38import org.onosproject.net.flow.criteria.OchSignalCriterion;
39import org.onosproject.net.flow.criteria.PortCriterion;
40import org.onosproject.net.flow.instructions.ExtensionTreatment;
41import org.onosproject.net.flow.instructions.ExtensionTreatmentType;
42import org.onosproject.net.flow.instructions.Instruction;
43import org.onosproject.net.flow.instructions.Instructions;
yjimmyyb94f93b2016-07-11 16:03:48 -070044import org.onosproject.net.optical.OpticalAnnotations;
yjimmyy646aa022016-07-05 12:09:50 -070045import org.onosproject.openflow.controller.Dpid;
46import org.onosproject.openflow.controller.OpenFlowController;
47import org.onosproject.openflow.controller.OpenFlowSwitch;
48import org.slf4j.Logger;
49import org.slf4j.LoggerFactory;
50
51/**
52 * Port Power (Gain and attenuation) implementation for Oplink ROADM.
53 *
54 * An Oplink ROADM port exposes OchSignal resources.
55 * Optical Power can be set at port level or channel/wavelength level (attenuation).
56 *
57 */
58
59public class OplinkRoadmPowerConfig extends AbstractHandlerBehaviour
yjimmyycfcb0532016-07-11 16:03:48 -070060 implements PowerConfig<Object> {
61
yjimmyy646aa022016-07-05 12:09:50 -070062 protected final Logger log = LoggerFactory.getLogger(getClass());
63
yjimmyycfcb0532016-07-11 16:03:48 -070064 // Component type
65 private enum Type {
66 NONE,
67 PORT,
68 CHANNEL
69 }
70
71 // Get the type if component is valid
72 private Type getType(Object component) {
73 if (component == null || component instanceof Direction) {
74 return Type.PORT;
75 } else if (component instanceof OchSignal) {
76 return Type.CHANNEL;
77 } else {
78 return Type.NONE;
79 }
80 }
81
yjimmyy646aa022016-07-05 12:09:50 -070082 private OpenFlowSwitch getOpenFlowDevice() {
83 final OpenFlowController controller = this.handler().get(OpenFlowController.class);
84 final Dpid dpid = Dpid.dpid(this.data().deviceId().uri());
85 OpenFlowSwitch sw = controller.getSwitch(dpid);
86 if (sw == null || !sw.isConnected()) {
87 return null;
88 } else {
89 return sw;
90 }
91 }
92
yjimmyycfcb0532016-07-11 16:03:48 -070093 // Find matching flow on device
94 private FlowEntry findFlow(PortNumber portNum, OchSignal och) {
95 FlowRuleService service = this.handler().get(FlowRuleService.class);
96 Iterable<FlowEntry> flowEntries = service.getFlowEntries(this.data().deviceId());
97
98 // Return first matching flow
99 for (FlowEntry entry : flowEntries) {
100 TrafficSelector selector = entry.selector();
101 OchSignalCriterion entrySigid =
102 (OchSignalCriterion) selector.getCriterion(Criterion.Type.OCH_SIGID);
103 if (entrySigid != null && och.equals(entrySigid.lambda())) {
104 PortCriterion entryPort =
105 (PortCriterion) selector.getCriterion(Criterion.Type.IN_PORT);
106 if (entryPort != null && portNum.equals(entryPort.port())) {
107 return entry;
108 }
109 }
110 }
111 log.warn("No matching flow found");
112 return null;
yjimmyy646aa022016-07-05 12:09:50 -0700113 }
114
115 @Override
yjimmyycfcb0532016-07-11 16:03:48 -0700116 public Optional<Long> getTargetPower(PortNumber portNum, Object component) {
yjimmyy646aa022016-07-05 12:09:50 -0700117 Long returnVal = null;
118 // Check if switch is connected, otherwise do not return value in store,
119 // which is obsolete.
120 if (getOpenFlowDevice() != null) {
yjimmyycfcb0532016-07-11 16:03:48 -0700121 switch (getType(component)) {
122 case PORT:
123 // Will be implemented in the future.
124 break;
125 case CHANNEL:
126 returnVal = getChannelAttenuation(portNum, (OchSignal) component);
127 break;
128 default:
129 break;
yjimmyy646aa022016-07-05 12:09:50 -0700130 }
131 }
132 return Optional.ofNullable(returnVal);
133 }
134
135 @Override
yjimmyycfcb0532016-07-11 16:03:48 -0700136 public Optional<Long> currentPower(PortNumber portNum, Object component) {
137 Long returnVal = null;
138 // Check if switch is connected, otherwise do not return value in store,
139 // which is obsolete.
140 if (getOpenFlowDevice() != null) {
141 switch (getType(component)) {
142 case PORT:
143 returnVal = getCurrentPortPower(portNum);
144 break;
145 case CHANNEL:
146 returnVal = getCurrentChannelPower(portNum, (OchSignal) component);
147 break;
148 default:
149 break;
150 }
151 }
152 return Optional.ofNullable(returnVal);
153 }
154
155 @Override
156 public void setTargetPower(PortNumber portNum, Object component, long power) {
157 if (getOpenFlowDevice() != null) {
158 switch (getType(component)) {
159 case PORT:
160 setTargetPortPower(portNum, power);
161 break;
162 case CHANNEL:
163 setChannelAttenuation(portNum, (OchSignal) component, power);
164 break;
165 default:
166 break;
167 }
yjimmyy646aa022016-07-05 12:09:50 -0700168 } else {
169 log.warn("OpenFlow handshaker driver not found or device is not connected");
170 }
171 }
yjimmyycfcb0532016-07-11 16:03:48 -0700172
173 private Long getChannelAttenuation(PortNumber portNum, OchSignal och) {
174 FlowEntry flowEntry = findFlow(portNum, och);
175 if (flowEntry != null) {
176 List<Instruction> instructions = flowEntry.treatment().allInstructions();
177 for (Instruction ins : instructions) {
178 if (ins.type() == Instruction.Type.EXTENSION) {
179 ExtensionTreatment ext = ((Instructions.ExtensionInstructionWrapper) ins).extensionInstruction();
180 if (ext.type() == ExtensionTreatmentType.ExtensionTreatmentTypes.OPLINK_ATTENUATION.type()) {
181 return (long) ((OplinkAttenuation) ext).getAttenuation();
182 }
183 }
184 }
185 }
186 return null;
187 }
188
189 private Long getCurrentPortPower(PortNumber portNum) {
190 DeviceService deviceService = this.handler().get(DeviceService.class);
191 Port port = deviceService.getPort(this.data().deviceId(), portNum);
192 if (port != null) {
193 String currentPower = port.annotations().value(OpticalAnnotations.CURRENT_POWER);
194 if (currentPower != null) {
195 return Long.valueOf(currentPower);
196 }
197 }
198 return null;
199 }
200
201 private Long getCurrentChannelPower(PortNumber portNum, OchSignal och) {
202 FlowEntry flowEntry = findFlow(portNum, och);
203 if (flowEntry != null) {
204 // TODO put somewhere else if possible
205 // We put channel power in packets
206 return flowEntry.packets();
207 }
208 return null;
209 }
210
211 private void setTargetPortPower(PortNumber portNum, long power) {
212 OpenFlowSwitch device = getOpenFlowDevice();
213 device.sendMsg(device.factory().buildOplinkPortPowerSet()
214 .setXid(0)
215 .setPort((int) portNum.toLong())
216 .setPowerValue((int) power)
217 .build());
218 }
219
220 private void setChannelAttenuation(PortNumber portNum, OchSignal och, long power) {
221 FlowEntry flowEntry = findFlow(portNum, och);
222 if (flowEntry != null) {
223 List<Instruction> instructions = flowEntry.treatment().allInstructions();
224 for (Instruction ins : instructions) {
225 if (ins.type() == Instruction.Type.EXTENSION) {
226 ExtensionTreatment ext = ((Instructions.ExtensionInstructionWrapper) ins).extensionInstruction();
227 if (ext.type() == ExtensionTreatmentType.ExtensionTreatmentTypes.OPLINK_ATTENUATION.type()) {
228 ((OplinkAttenuation) ext).setAttenuation((int) power);
229 FlowRuleService service = this.handler().get(FlowRuleService.class);
230 service.applyFlowRules(flowEntry);
231 return;
232 }
233 }
234 }
235 addAttenuation(flowEntry, power);
236 } else {
237 log.warn("Target channel power not set");
238 }
239 }
240
241 // Replace flow with new flow containing Oplink attenuation extension instruction. Also resets
242 // metrics.
243 private void addAttenuation(FlowEntry flowEntry, long power) {
244 FlowRule.Builder flowBuilder = new DefaultFlowRule.Builder();
245 flowBuilder.withCookie(flowEntry.id().value());
246 flowBuilder.withPriority(flowEntry.priority());
247 flowBuilder.forDevice(flowEntry.deviceId());
248 flowBuilder.forTable(flowEntry.tableId());
249 if (flowEntry.isPermanent()) {
250 flowBuilder.makePermanent();
251 } else {
252 flowBuilder.makeTemporary(flowEntry.timeout());
253 }
254
255 flowBuilder.withSelector(flowEntry.selector());
256
257 // Copy original instructions and add attenuation instruction
258 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
259 flowEntry.treatment().allInstructions().forEach(ins -> treatmentBuilder.add(ins));
260 treatmentBuilder.add(Instructions.extension(new OplinkAttenuation((int) power), this.data().deviceId()));
261 flowBuilder.withTreatment(treatmentBuilder.build());
262
263 FlowRuleService service = this.handler().get(FlowRuleService.class);
264 service.applyFlowRules(flowBuilder.build());
265 }
yjimmyy646aa022016-07-05 12:09:50 -0700266}