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