blob: 0827d09bdcee9189f8cca997759cfd550a672c8c [file] [log] [blame]
gyewan.aneeb4cf52018-12-24 11:47:57 +09001/*
sdn5d65d112019-01-11 18:45:26 +09002 * Copyright 2019-present Open Networking Foundation
gyewan.aneeb4cf52018-12-24 11:47:57 +09003 *
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.cisco.rest;
18
19import com.fasterxml.jackson.core.JsonParseException;
20import com.fasterxml.jackson.core.JsonProcessingException;
21import com.fasterxml.jackson.databind.JsonMappingException;
22import com.fasterxml.jackson.databind.JsonNode;
23import com.fasterxml.jackson.databind.ObjectMapper;
24import com.fasterxml.jackson.databind.node.JsonNodeType;
25import com.google.common.collect.Lists;
26import org.onlab.packet.ChassisId;
27import org.onlab.packet.MacAddress;
28import org.onosproject.net.AnnotationKeys;
29import org.onosproject.net.DefaultAnnotations;
30import org.onosproject.net.Device;
31import org.onosproject.net.DeviceId;
32import org.onosproject.net.Port;
33import org.onosproject.net.PortNumber;
34import org.onosproject.net.device.DefaultDeviceDescription;
35import org.onosproject.net.device.DefaultPortDescription;
36import org.onosproject.net.device.DeviceDescription;
37import org.onosproject.net.device.DeviceDescriptionDiscovery;
38import org.onosproject.net.device.DeviceService;
39import org.onosproject.net.device.PortDescription;
40import org.onosproject.net.driver.AbstractHandlerBehaviour;
41import org.slf4j.Logger;
42
43import java.io.IOException;
44import java.util.ArrayList;
45import java.util.Iterator;
46import java.util.List;
47import java.util.Optional;
48import java.util.stream.StreamSupport;
49
50import static com.google.common.base.Preconditions.checkNotNull;
51import static org.slf4j.LoggerFactory.getLogger;
52
53/**
54 * Discovers the device, ports information from a Cisco Nexus 9K REST device.
55 */
56public class DeviceDescriptionDiscoveryCisco9kImpl extends AbstractHandlerBehaviour
57 implements DeviceDescriptionDiscovery {
58 private final Logger log = getLogger(getClass());
59
60 private static final String SHOW_INTERFACES_CMD = "show interface";
61 private static final String SHOW_VERSION_CMD = "show version";
62 private static final String SHOW_MODULE_CMD = "show module";
63
64 private static final String JSON_BODY = "body";
65 private static final String JSON_RESULT = "result";
66 private static final String JSON_INTERFACE = "interface";
67 private static final String JSON_ROW_INTERFACE = "ROW_interface";
68 private static final String JSON_ROW_MODULE = "ROW_modinfo";
69 private static final String JSON_ROW_MODULE_MAC = "ROW_modmacinfo";
70
71 private static final String MANUFACTURER = "manufacturer";
72 private static final String CHASSIS_ID = "chassis_id";
73 private static final String CISCO_SERIAL_BOARD = "proc_board_id";
74 private static final String KICKSTART_VER = "kickstart_ver_str";
75 private static final String INTERFACE_STATE = "state";
76 private static final String INTERFACE_ADMIN_STATE = "admin_state";
77 private static final String INTERFACE_ENABLED = "enabled";
78 private static final String INTERFACE_DISABLED = "disabled";
79 private static final String STATE_UP = "up";
80 private static final String MODULE_MODEL = "model";
81 private static final String MODULE_INTERFACE = "modinf";
82 private static final String MODULE_MAC = "modmac";
83 private static final String MODULE_SERIAL = "serialnum";
84
85 private static final String INTERFACE_ETHERNET = "Ethernet";
86 private static final String INTERFACE_PORTCHANNEL = "port-channel";
87 private static final String INTERFACE_BW = "eth_bw";
88 private static final String INTERFACE_MAC = "eth_bia_addr";
89 private static final String BREAKOUT = "breakout";
90 private static final String UNKNOWN = "unknown";
91
92 private static final String MODULE_ANNOTATION_FORMAT = "%s:%s:%s";
93 private static final String MODULE_BRACKET_FORMAT = "[%s]";
94
95 @Override
96 public DeviceDescription discoverDeviceDetails() {
97 DeviceId deviceId = handler().data().deviceId();
98
99 ArrayList<String> cmd = new ArrayList<>();
100 cmd.add(SHOW_VERSION_CMD);
101 cmd.add(SHOW_MODULE_CMD);
102
103 String response = NxApiRequest.postClis(handler(), cmd);
104
105 String mrf = UNKNOWN;
106 String hwVer = UNKNOWN;
107 String swVer = UNKNOWN;
108 String serialNum = UNKNOWN;
109 String module = UNKNOWN;
110
111 try {
112 ObjectMapper om = new ObjectMapper();
113 JsonNode json = om.readTree(response);
114
115 JsonNode body = json.at("/0/body");
116 if (!body.isMissingNode()) {
117 mrf = body.at("/" + MANUFACTURER).asText();
118 hwVer = body.at("/" + CHASSIS_ID).asText();
119 swVer = body.at("/" + KICKSTART_VER).asText();
120 serialNum = body.at("/" + CISCO_SERIAL_BOARD).asText();
121 }
122
123
124 JsonNode modInfo = json.at("/1/" + JSON_ROW_MODULE);
125 JsonNode modMacInfo = json.at("/1/" + JSON_ROW_MODULE_MAC);
126
127 if (!modInfo.isMissingNode()) {
128 List<String> modulesAnn = prepareModuleAnnotation(modInfo, modMacInfo);
129 module = String.format(MODULE_BRACKET_FORMAT, String.join(",", modulesAnn));
130 }
131 } catch (JsonParseException e) {
132 log.error("Failed to parse Json", e);
133 } catch (JsonMappingException e) {
134 log.error("Failed to map Json", e);
135 } catch (JsonProcessingException e) {
136 log.error("Failed to processing Json", e);
137 } catch (IOException e) {
138 log.error("Failed to retrieve Device Information", e);
139 }
140 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder();
141
142 DeviceService deviceService = checkNotNull(handler().get(DeviceService.class));
143 Device device = deviceService.getDevice(deviceId);
144 if (device != null) {
145 annotations.putAll(device.annotations());
146 }
147
148 return new DefaultDeviceDescription(deviceId.uri(), Device.Type.SWITCH,
149 mrf, hwVer, swVer, serialNum,
150 new ChassisId(), annotations.build());
151 }
152
153 @Override
154 public List<PortDescription> discoverPortDetails() {
155 List<PortDescription> ports = Lists.newArrayList();
156
157 try {
158 String response;
159 try {
160 response = NxApiRequest.postCli(handler(), SHOW_INTERFACES_CMD);
161 } catch (NullPointerException e) {
162 log.error("Failed to perform {} command on the device {}",
163 SHOW_INTERFACES_CMD, handler().data().deviceId());
164 return ports;
165 }
166
167 ObjectMapper om = new ObjectMapper();
168 JsonNode json = om.readTree(response);
169 JsonNode res = json.get(JSON_RESULT);
170 JsonNode interfaces = res.findValue(JSON_ROW_INTERFACE);
171 Iterator<JsonNode> iter = interfaces.elements();
172 Integer ifCount = 1;
173 while (iter.hasNext()) {
174 JsonNode ifs = iter.next();
175 String ifName = ifs.get(JSON_INTERFACE).asText();
176
177 if (isPortValid(ifName)) {
178 Port.Type portType = Port.Type.VIRTUAL;
179 long portSpeed = ifs.get(INTERFACE_BW).asLong() / 1000; //Mbps
180 String portMac = ifs.get(INTERFACE_MAC).asText();
181 MacAddress mac = MacAddress.valueOf(
182 portMac.replace(".", "").replaceAll("(.{2})", "$1:").trim().substring(0, 17));
183 boolean state = STATE_UP.equals(ifs.get(INTERFACE_STATE).asText());
184 String adminState = STATE_UP.equals(ifs.get(INTERFACE_ADMIN_STATE).asText())
185 ? INTERFACE_ENABLED : INTERFACE_DISABLED;
186
187 DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
188 .set(AnnotationKeys.PORT_NAME, ifName)
189 .set(AnnotationKeys.PORT_MAC, mac.toString())
190 .set(AnnotationKeys.ADMIN_STATE, adminState);
191
192 if (isValidPhysicalPort(ifName)) {
193 String interfaceNumber = ifName.replace(INTERFACE_ETHERNET, "");
194 String[] interfaceLocation = interfaceNumber.split("/");
195 portType = Port.Type.FIBER;
196
197 if (interfaceLocation.length == 3) {
198 String breakout = ifName.substring(0, ifName.lastIndexOf("/"));
199 annotations.set(BREAKOUT, breakout);
200 }
201 }
202 PortDescription desc = DefaultPortDescription.builder()
203 .withPortNumber(PortNumber.portNumber(ifCount))
204 .isEnabled(state)
205 .type(portType).portSpeed(portSpeed).annotations(annotations.build())
206 .build();
207 ports.add(desc);
208 ifCount++;
209 }
210 }
211 } catch (Exception e) {
212 log.error("Exception occurred because of ", e);
213 }
214
215 return ports;
216 }
217
218 private boolean isValidPhysicalPort(String portName) {
219 return portName.startsWith(INTERFACE_ETHERNET);
220 }
221
222 private boolean isValidVirtualPort(String portName) {
223 return portName.startsWith(INTERFACE_PORTCHANNEL);
224 }
225
226 private boolean isPortValid(String portName) {
227 return isValidPhysicalPort(portName) || isValidVirtualPort(portName);
228 }
229
230 private List<String> prepareModuleAnnotation(JsonNode modules, JsonNode macs) {
231 List<String> modulesInfo = new ArrayList<>();
232 if (modules.getNodeType() == JsonNodeType.ARRAY) {
233 modules.forEach(module -> modulesInfo.add(getModuleInfo(module, macs)));
234 } else if (modules.getNodeType() == JsonNodeType.OBJECT) {
235 modulesInfo.add(getModuleInfo(modules, macs));
236 }
237 return modulesInfo;
238 }
239
240 private String getModuleInfo(JsonNode module, JsonNode moduleMac) {
241 int moduleId = module.get(MODULE_INTERFACE).asInt();
242 String moduleModel = module.get(MODULE_MODEL).asText();
243 String moduleSerial = getModuleSerial(moduleId, moduleMac);
244 return String.format(MODULE_ANNOTATION_FORMAT, moduleId, moduleModel, moduleSerial);
245 }
246
247 private String getModuleSerial(int moduleId, JsonNode macs) {
248 if (macs.getNodeType() == JsonNodeType.ARRAY) {
249 Optional<JsonNode> serial = StreamSupport.stream(macs.spliterator(), false)
250 .filter(mac -> mac.get(MODULE_MAC).asInt() == moduleId)
251 .findAny();
252 if (serial.isPresent()) {
253 return serial.get().get(MODULE_SERIAL).asText();
254 }
255 } else if (macs.getNodeType() == JsonNodeType.OBJECT) {
256 if (macs.get(MODULE_MAC).asInt() == moduleId) {
257 return macs.get(MODULE_SERIAL).asText();
258 }
259 }
260 return UNKNOWN;
261 }
262
263}