blob: 34ad6134f28d23fd6e60c0f38e8ad5061dac4411 [file] [log] [blame]
MaoLuc201ae42017-02-06 17:57:01 -08001/*
2 * Copyright 2016-present 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 */
16package org.onosproject.driver.optical.handshaker;
17
18import com.google.common.collect.ImmutableList;
19import com.google.common.collect.ImmutableSet;
20
21import java.io.IOException;
22import java.util.ArrayList;
23import java.util.Collections;
24import java.util.List;
25import java.util.Set;
26import java.util.concurrent.atomic.AtomicBoolean;
27
28import org.onosproject.net.Device;
29import org.onosproject.net.device.PortDescription;
30import org.onosproject.openflow.controller.OpenFlowOpticalSwitch;
31import org.onosproject.openflow.controller.PortDescPropertyType;
32import org.onosproject.openflow.controller.driver.AbstractOpenFlowSwitch;
33import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeAlreadyStarted;
34import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeCompleted;
35import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeNotStarted;
36import org.projectfloodlight.openflow.protocol.OFCircuitPortStatus;
37import org.projectfloodlight.openflow.protocol.OFCircuitPortsReply;
38import org.projectfloodlight.openflow.protocol.OFCircuitPortsRequest;
39import org.projectfloodlight.openflow.protocol.OFExpPortAdjacencyReply;
40import org.projectfloodlight.openflow.protocol.OFMessage;
41import org.projectfloodlight.openflow.protocol.OFObject;
42import org.projectfloodlight.openflow.protocol.OFPortDesc;
43import org.projectfloodlight.openflow.protocol.OFPortOptical;
44import org.projectfloodlight.openflow.protocol.OFStatsReply;
45import org.projectfloodlight.openflow.protocol.OFStatsRequest;
46import org.projectfloodlight.openflow.protocol.OFStatsType;
47import org.projectfloodlight.openflow.protocol.OFType;
48import org.projectfloodlight.openflow.protocol.OFOplinkPortPowerReply;
49
50import static org.onosproject.net.Device.Type;
51
52/**
53 * Oplink open flow EDFA handshaker - for Open Flow 1.3.
54 * Driver for Oplink EDFA openflow device.
55 * Driver implements custom handshaker and supports Optical Port based on OpenFlow OTN extension.
56 */
57public class OplinkEdfaHandshaker extends AbstractOpenFlowSwitch implements OpenFlowOpticalSwitch {
58
59 private final AtomicBoolean driverHandshakeComplete = new AtomicBoolean(false);
60 private List<OFPortOptical> opticalPorts = new ArrayList<>();
61 private OplinkHandshakerUtil oplinkUtil = new OplinkHandshakerUtil(this);
62
63 @Override
64 public List<? extends OFObject> getPortsOf(PortDescPropertyType type) {
65 // Expected type is OPTICAL_TRANSPORT
66 if (type == PortDescPropertyType.OPTICAL_TRANSPORT) {
67 return ImmutableList.copyOf(opticalPorts);
68 }
69 // Any other type, return empty
70 log.warn("Unexpected port description property type: {}", type);
71 return ImmutableList.of();
72 }
73
74 /**
75 * Returns a list of standard (Ethernet) ports.
76 *
77 * @return List of ports
78 */
79 @Override
80 public List<OFPortDesc> getPorts() {
81 return ImmutableList.of();
82 }
83
84 @Override
85 public Set<PortDescPropertyType> getPortTypes() {
86 return ImmutableSet.of(PortDescPropertyType.OPTICAL_TRANSPORT);
87 }
88
89 @Override
90 public Boolean supportNxRole() {
91 return false;
92 }
93
94 @Override
95 public void startDriverHandshake() {
96 log.info("Starting driver handshake for sw {}", getStringId());
97 if (startDriverHandshakeCalled) {
98 throw new SwitchDriverSubHandshakeAlreadyStarted();
99 }
100 startDriverHandshakeCalled = true;
101 try {
102 sendHandshakeOFExperimenterPortDescRequest();
103 } catch (IOException e) {
104 log.error("OPLK EDFA exception while sending experimenter port desc:", e);
105 }
106 }
107
108 @Override
109 public boolean isDriverHandshakeComplete() {
110 return driverHandshakeComplete.get();
111 }
112
113 @Override
114 public void processDriverHandshakeMessage(OFMessage m) {
115
116 if (!startDriverHandshakeCalled) {
117 throw new SwitchDriverSubHandshakeNotStarted();
118 }
119
120 if (driverHandshakeComplete.get()) {
121 throw new SwitchDriverSubHandshakeCompleted(m);
122 }
123
124 switch (m.getType()) {
125 case BARRIER_REPLY:
126 log.debug("OPLK EDFA Received barrier response");
127 break;
128 case ERROR:
129 log.error("Switch {} Error {}", getStringId(), m);
130 break;
131 case PORT_STATUS:
132 processOFPortStatus((OFCircuitPortStatus) m);
133 break;
134 case STATS_REPLY:
135 OFStatsReply stats = (OFStatsReply) m;
136 if (stats.getStatsType() == OFStatsType.EXPERIMENTER) {
137 log.debug("OPLK EDFA : Received multipart (port desc) reply message {}", m);
138 //OTN Optical extension 1.0 port-desc
139 createOpticalPortList((OFCircuitPortsReply) m);
140 driverHandshakeComplete.set(true);
141 }
142 break;
143 default:
144 log.warn("Received message {} during switch-driver " +
145 "subhandshake from switch {} ... " +
146 "Ignoring message", m, getStringId());
147 }
148 }
149
150 @Override
151 public Device.Type deviceType() {
152 return Type.OPTICAL_AMPLIFIER;
153 }
154
155 @Override
156 public final void sendMsg(OFMessage m) {
157 List<OFMessage> messages = new ArrayList<>();
158 messages.add(m);
159
160 if (m.getType() == OFType.STATS_REQUEST) {
161 OFStatsRequest sr = (OFStatsRequest) m;
162 log.debug("OPLK EDFA rebuilding stats request type {}", sr.getStatsType());
163 switch (sr.getStatsType()) {
164 case PORT:
165 // add Oplink experiment message to get the port's current power
166 messages.add(oplinkUtil.buildPortPowerRequest());
167 // add experiment message to get adjacent ports
168 messages.add(oplinkUtil.buildPortAdjacencyRequest());
169 break;
170 default:
171 break;
172 }
173 } else {
174 log.debug("OPLK EDFA sends msg:{}, as is", m.getType());
175 }
176
177 super.sendMsg(messages);
178 }
179
180 @Override
181 public List<PortDescription> processExpPortStats(OFMessage msg) {
182 if (msg instanceof OFOplinkPortPowerReply) {
183 return oplinkUtil.buildPortPowerDescriptions(((OFOplinkPortPowerReply) msg).getEntries());
184 } else if (msg instanceof OFExpPortAdjacencyReply) {
185 return oplinkUtil.buildPortAdjacencyDescriptions(((OFExpPortAdjacencyReply) msg).getEntries());
186 }
187 return Collections.emptyList();
188 }
189
190 private void processOFPortStatus(OFCircuitPortStatus ps) {
191 log.debug("OPLK EDFA ..OF Port Status :", ps);
192 }
193
194 private void sendHandshakeOFExperimenterPortDescRequest() throws IOException {
195 // Send multipart message for port description for optical switches
196 OFCircuitPortsRequest circuitPortsRequest = oplinkUtil.buildCircuitPortsRequest();
197 log.debug("OPLK EDFA : Sending experimented port description message {}", circuitPortsRequest);
198 sendHandshakeMessage(circuitPortsRequest);
199 }
200
201 /**
202 * Builds list of OFPortOptical ports based on the multi-part circuit ports reply.
203 * Ensure the optical transport port's signal type is configured correctly.
204 *
205 * @param wPorts OF reply with circuit ports
206 */
207 private void createOpticalPortList(OFCircuitPortsReply wPorts) {
208 opticalPorts.addAll(wPorts.getEntries());
209 }
210}