blob: ee55715ae495c47918326b5bcb45867a27bb938a [file] [log] [blame]
Michael Enrico584eebd2021-07-22 08:04:13 +00001/*
2 * Copyright 2017 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
17package org.onosproject.drivers.polatis.netconf;
18
19import org.apache.commons.configuration.HierarchicalConfiguration;
20import org.onlab.util.Frequency;
21import org.onlab.util.Spectrum;
22
23import org.slf4j.Logger;
24import static org.slf4j.LoggerFactory.getLogger;
25
26import com.google.common.collect.ImmutableList;
27import org.onosproject.net.PortNumber;
28import org.onosproject.net.device.PortDescription;
29import org.onosproject.net.AnnotationKeys;
30import org.onosproject.net.DefaultAnnotations;
31import org.onosproject.net.flow.DefaultFlowEntry;
32import org.onosproject.net.flow.FlowEntry;
33import org.onosproject.net.flow.FlowRule;
34import org.onosproject.net.driver.HandlerBehaviour;
35import org.onosproject.netconf.NetconfException;
36
37import static org.onosproject.net.optical.device.OmsPortHelper.omsPortDescription;
38import static org.onosproject.drivers.polatis.netconf.PolatisNetconfUtility.configsAt;
39import static org.onosproject.drivers.polatis.netconf.PolatisNetconfUtility.netconfGet;
40import static org.onosproject.drivers.polatis.netconf.PolatisNetconfUtility.xmlOpen;
41import static org.onosproject.drivers.polatis.netconf.PolatisNetconfUtility.xml;
42import static org.onosproject.drivers.polatis.netconf.PolatisNetconfUtility.xmlClose;
43import static org.onosproject.drivers.polatis.netconf.PolatisNetconfUtility.xmlEmpty;
44import static org.onosproject.drivers.polatis.netconf.PolatisNetconfUtility.opticalRevision;
45import static org.onosproject.drivers.polatis.netconf.PolatisNetconfUtility.KEY_PAIR;
46import static org.onosproject.drivers.polatis.netconf.PolatisNetconfUtility.KEY_PAIRS;
47import static org.onosproject.drivers.polatis.netconf.PolatisNetconfUtility.KEY_PORT;
48import static org.onosproject.drivers.polatis.netconf.PolatisNetconfUtility.KEY_PORTID;
49import static org.onosproject.drivers.polatis.netconf.PolatisNetconfUtility.KEY_PORTPEER;
50import static org.onosproject.drivers.polatis.netconf.PolatisNetconfUtility.KEY_PORTDIR;
51import static org.onosproject.drivers.polatis.netconf.PolatisNetconfUtility.KEY_PORTCONFIG;
52import static org.onosproject.drivers.polatis.netconf.PolatisNetconfUtility.KEY_PRODINF;
53import static org.onosproject.drivers.polatis.netconf.PolatisNetconfUtility.KEY_CONNS;
54import static org.onosproject.drivers.polatis.netconf.PolatisNetconfUtility.KEY_PORTSETSTATE;
55import static org.onosproject.drivers.polatis.netconf.PolatisNetconfUtility.KEY_PORTCONFIG_XMLNS;
56import static org.onosproject.drivers.polatis.netconf.PolatisNetconfUtility.KEY_PRODINF_XMLNS;
57import static org.onosproject.drivers.polatis.netconf.PolatisNetconfUtility.KEY_CONNS_XMLNS;
58import static org.onosproject.drivers.polatis.netconf.PolatisNetconfUtility.KEY_PORTSETSTATE_XMLNS;
59import static org.onosproject.drivers.polatis.netconf.PolatisNetconfUtility.KEY_DATA_PORTCONFIG;
60import static org.onosproject.drivers.polatis.netconf.PolatisNetconfUtility.KEY_DATA_CONNS;
61
62import java.util.List;
63import java.util.ArrayList;
64import java.util.Collection;
65import java.util.Date;
66import java.text.SimpleDateFormat;
67import java.text.ParseException;
68
69
70/**
71 * Polatis common utilities.
72 */
73public final class PolatisUtility {
74
75 public static final String DEFAULT_MANUFACTURER = "Polatis";
76 public static final String DEFAULT_DESCRIPTION_DATA = "Unknown";
77 public static final String KEY_MANUFACTURER = "manufacturer";
78 public static final String KEY_HWVERSION = "model-name";
79 public static final String KEY_SWVERSION = "software-version";
80 public static final String KEY_SERIALNUMBER = "serial-number";
81 public static final String KEY_INPUTPORTS = "inputPorts";
82 public static final String KEY_OUTPUTPORTS = "outputPorts";
83 public static final String KEY_PORTSTATUS = "status";
84 public static final String KEY_ENABLE = "ENABLE";
85 public static final String KEY_DISABLE = "DISABLE";
86 public static final String KEY_INGRESS = "ingress";
87 public static final String KEY_EGRESS = "egress";
88 public static final String VALUE_TRUE = "true";
89 public static final String VALUE_FALSE = "false";
90 public static final String VALUE_INPUT = "INPUT";
91 public static final String VALUE_OUTPUT = "OUTPUT";
92 public static final String VALUE_UNKNOWN = "UNKNOWN";
93 public static final String VALUE_CC = "CC";
94 public static final String KEY_RPCENABLE = "port-enab";
95 public static final String KEY_RPCDISABLE = "port-disab";
96 public static final String PORT_ENABLED = "ENABLED";
97 public static final String PORT_DISABLED = "DISABLED";
98 public static final String KEY_PORTLABEL = "label";
99 public static final String KEY_PEERPORT = "peer-port";
100 public static final String KEY_LINKBIDIR = "bidirectional";
101 public static final String KEY_LINKALLOWED = "allowed";
102 public static final String KEY_SRC = "ingress";
103 public static final String KEY_DST = "egress";
104 public static final String PAIR_COMPAT_REVISION = "2017-08-04";
105
106 public static final int POLATIS_NUM_OF_WAVELENGTHS = 39;
107
108 private static final Logger log = getLogger(PolatisDeviceDescription.class);
109
110 private PolatisUtility() {
111 }
112
113 /**
114 * Returns XML subtree filter term for NETCONF get[-config] RPC for retrieving product info from a Polatis switch.
115 *
116 * @return Filter term as string
117 */
118 public static String getProdInfoFilter() {
119 return new StringBuilder(xmlOpen(KEY_PRODINF_XMLNS))
120 .append(xmlClose(KEY_PRODINF))
121 .toString();
122 }
123
124 /**
125 * Returns XML subtree filter term for NETCONF get[-config] RPC for retrieving cross-connections on a
126 * Polatis switch.
127 *
128 * @return Filter term as string
129 */
130 public static String getConnectionsFilter() {
131 return new StringBuilder(xmlOpen(KEY_CONNS_XMLNS))
132 .append(xmlClose(KEY_CONNS))
133 .toString();
134 }
135
136 /**
137 * Returns XML subtree filter term for NETCONF get[-config] RPC for retrieving config and state data for all ports
138 * on a Polatis switch.
139 *
140 * @return Filter term as string
141 */
142 public static String getPortsFilter() {
143 return new StringBuilder(xmlOpen(KEY_PORTCONFIG_XMLNS))
144 .append(xmlOpen(KEY_PORT))
145 .append(xmlEmpty(KEY_PORTID))
146 .append(xmlEmpty(KEY_PORTSTATUS))
147 .append(xmlEmpty(KEY_PORTLABEL))
148 .append(xmlEmpty(KEY_PEERPORT))
149 .append(xmlClose(KEY_PORT))
150 .append(xmlClose(KEY_PORTCONFIG))
151 .toString();
152 }
153
154 /**
155 * Returns XML subtree filter term for NETCONF get[-config] RPC for retrieving config and state data for a specific
156 * port on a Polatis switch.
157 *
158 * @param portNum Port number as PortNumber object
159 * @return Filter term as string
160 */
161 public static String getPortFilter(PortNumber portNum) {
162 return new StringBuilder(xmlOpen(KEY_PORTCONFIG_XMLNS))
163 .append(xmlOpen(KEY_PORT))
164 .append(xml(KEY_PORTID, portNum.toString()))
165 .append(xmlEmpty(KEY_PORTSTATUS))
166 .append(xmlEmpty(KEY_PORTLABEL))
167 .append(xmlEmpty(KEY_PEERPORT))
168 .append(xmlClose(KEY_PORT))
169 .append(xmlClose(KEY_PORTCONFIG))
170 .toString();
171 }
172
173 /**
174 * Returns XML subtree filter term for NETCONF get RPC for retrieving state data (only) for a specific port on a
175 * Polatis switch.
176 *
177 * @param portNum Port number as PortNumber object
178 * @return Filter term as string
179 */
180 public static String getPortStatusFilter(PortNumber portNum) {
181 return new StringBuilder(xmlOpen(KEY_PORTCONFIG_XMLNS))
182 .append(xmlOpen(KEY_PORT))
183 .append(xml(KEY_PORTID, portNum.toString()))
184 .append(xmlEmpty(KEY_PORTSTATUS))
185 .append(xmlClose(KEY_PORT))
186 .append(xmlClose(KEY_PORTCONFIG))
187 .toString();
188 }
189
190 /**
191 * Returns XML body for NETCONF RPC for setting the admin status of a specific port on a Polatis switch.
192 *
193 * @param action Action (enable/disable) to be performed on port as string
194 * @param portNum Port number as PortNumber object
195 * @return RPC body (XML) as string
196 */
197 public static String getRpcSetPortStateBody(String action, PortNumber portNum) {
198 return new StringBuilder(xmlOpen(KEY_PORTSETSTATE_XMLNS))
199 .append(xmlOpen(action.equals(KEY_ENABLE) ? KEY_RPCENABLE : KEY_RPCDISABLE))
200 .append(portNum.toString())
201 .append(xmlClose(action.equals(KEY_ENABLE) ? KEY_RPCENABLE : KEY_RPCDISABLE))
202 .append(xmlClose(KEY_PORTSETSTATE))
203 .toString();
204 }
205
206 /**
207 * Returns a list of PortDescriptions from parsing the content of the reply to a get[-config] call to a
208 * Polatis switch.
209 *
210 * @param content XML to be parsed as string
211 * @param numInputPorts Number of input ports
212 * @param numOutputPorts Number of output ports
213 * @return List of ports as PortDescription objects
214 */
215 public static List<PortDescription> parsePorts(String content, int numInputPorts, int numOutputPorts) {
216 List<HierarchicalConfiguration> subtrees = configsAt(content, KEY_DATA_PORTCONFIG);
217 List<PortDescription> portDescriptions = new ArrayList<PortDescription>();
218 for (HierarchicalConfiguration portConfig : subtrees) {
219 PortDescription parsedPort = parsePort(portConfig, numInputPorts, numOutputPorts == 0 ? true : false);
220 portDescriptions.add(parsedPort);
221 }
222 return portDescriptions;
223 }
224
225 /**
226 * Returns a single PortDescription from parsing a HierarchicalConfiguration object containing a Polatis switch
227 * port config.
228 *
229 * @param cfg Single port as HierarchicalConfiguration object
230 * @param numInputPorts Number of input ports
231 * @param isConfigurable Switch is CC
232 * @return Single port as PortDescription object
233 */
234 public static PortDescription parsePort(HierarchicalConfiguration cfg, int numInputPorts, boolean isConfigurable) {
235 PortNumber portNumber = PortNumber.portNumber(cfg.getLong(KEY_PORTID));
236 String portType = VALUE_UNKNOWN;
237 if (isConfigurable) {
238 portType = VALUE_CC;
239 } else {
240 portType = portNumber.toLong() > numInputPorts ? VALUE_OUTPUT : VALUE_INPUT;
241 }
242 String peerPort = cfg.getString(KEY_PEERPORT);
243 DefaultAnnotations annotations = DefaultAnnotations.builder()
244 .set(AnnotationKeys.PORT_NAME, cfg.getString(KEY_PORTLABEL))
245 .set(KEY_PORTPEER, cfg.getString(KEY_PEERPORT))
246 .set(KEY_PORTDIR, portType)
247 .build();
248 return omsPortDescription(portNumber,
249 cfg.getString(KEY_PORTSTATUS).equals(PORT_ENABLED),
250 Spectrum.U_BAND_MIN, Spectrum.O_BAND_MAX,
251 Frequency.ofGHz(6_25), annotations);
252 }
253
254 /**
255 * Returns flow entries representing current cross-connections on a Polatis optical switch.
256 *
257 * @param behaviour HandlerBehaviour object associated with device being queried
258 * @return Cross-connections as a collection of FlowEntry objects
259 */
260 public static Collection<FlowEntry> parseConnections(HandlerBehaviour behaviour) {
261 log.debug("Fetch connections...");
262 String reply = netconfGet(behaviour.handler(), getConnectionsFilter());
263 final String keyPairMode = String.format("%s.%s", KEY_DATA_CONNS, parseKeyPairCompat(behaviour));
264 List<HierarchicalConfiguration> subtrees = configsAt(reply, keyPairMode);
265 ImmutableList.Builder<FlowEntry> connectionsBuilder = ImmutableList.builder();
266 for (HierarchicalConfiguration connection : subtrees) {
267 connectionsBuilder.add(new DefaultFlowEntry(parseConnection(connection, behaviour),
268 FlowEntry.FlowEntryState.ADDED));
269 }
270 return connectionsBuilder.build();
271 }
272
273 /**
274 * Returns single cross-connection as FlowRule object from parsing HierarchicalConfiguration object.
275 *
276 * @param cfg Single cross-connection as XML encoded in HierarchicalConfiguration object
277 * @param behaviour HandlerBehaviour object associated with device from which cross-connection has been retrieved
278 * @return Cross-connection as a FlowEntry object
279 */
280 public static FlowRule parseConnection(HierarchicalConfiguration cfg, HandlerBehaviour behaviour) {
281 return PolatisOpticalUtility.toFlowRule(behaviour,
282 PortNumber.portNumber(cfg.getInt(KEY_SRC)),
283 PortNumber.portNumber(cfg.getInt(KEY_DST)));
284 }
285
286 /**
287 * Returns string containing the correct name of the YANG list node containing the cross-connections on a specific
288 * Polatis optical switch.
289 * <p>
290 * This handles the backwards incompatible change ('pairs' to 'pair') introduced in the Polatis optical-switch
291 * YANG module in revision 2017-08-04
292 *
293 * @param behaviour HandlerBehaviour object associated with the ONOS device representing a particular Polatis
294 * optical switch
295 * @return Correct YANG list node name as string
296 */
297 public static String parseKeyPairCompat(HandlerBehaviour behaviour) {
298 String rev = opticalRevision(behaviour.handler());
299 if (rev == null) {
300 throw new IllegalStateException(new NetconfException("Failed to obtain the revision."));
301 }
302 String keyPairCompat;
303 try {
304 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
305 Date date = sdf.parse(PAIR_COMPAT_REVISION);
306
307 if (date.compareTo(sdf.parse(rev)) > 0) {
308 keyPairCompat = KEY_PAIRS;
309 } else {
310 keyPairCompat = KEY_PAIR;
311 }
312 } catch (ParseException e) {
313 throw new IllegalArgumentException(new NetconfException(String.format("Incorrect date format: %s", rev)));
314 }
315 return keyPairCompat;
316 }
317}