blob: be2d6a03a3eda677cea0154e4147069fb0576cb0 [file] [log] [blame]
Daniel Park531fb482016-07-02 14:21:31 +09001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Daniel Park531fb482016-07-02 14:21:31 +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.arista;
18
Daniel Park531fb482016-07-02 14:21:31 +090019import com.fasterxml.jackson.databind.JsonNode;
Daniel Park531fb482016-07-02 14:21:31 +090020import com.google.common.collect.Lists;
DongRyeol Cha3df560b2018-06-05 12:50:58 +090021import org.onlab.packet.ChassisId;
DongRyeol Cha53a270b2018-06-04 17:09:40 +090022import org.onlab.packet.MacAddress;
Daniel Park531fb482016-07-02 14:21:31 +090023import org.onosproject.net.AnnotationKeys;
24import org.onosproject.net.DefaultAnnotations;
DongRyeol Cha3df560b2018-06-05 12:50:58 +090025import org.onosproject.net.Device;
Daniel Park531fb482016-07-02 14:21:31 +090026import org.onosproject.net.DeviceId;
27import org.onosproject.net.Port;
28import org.onosproject.net.PortNumber;
29import org.onosproject.net.SparseAnnotations;
DongRyeol Cha3df560b2018-06-05 12:50:58 +090030import org.onosproject.net.device.DefaultDeviceDescription;
Daniel Park531fb482016-07-02 14:21:31 +090031import org.onosproject.net.device.DefaultPortDescription;
32import org.onosproject.net.device.DeviceDescription;
33import org.onosproject.net.device.DeviceDescriptionDiscovery;
DongRyeol Cha3df560b2018-06-05 12:50:58 +090034import org.onosproject.net.device.DeviceService;
Daniel Park531fb482016-07-02 14:21:31 +090035import org.onosproject.net.device.PortDescription;
36import org.onosproject.net.driver.AbstractHandlerBehaviour;
Daniel Park531fb482016-07-02 14:21:31 +090037import org.slf4j.Logger;
38
DongRyeol Cha53a270b2018-06-04 17:09:40 +090039import java.util.HashMap;
Daniel Park531fb482016-07-02 14:21:31 +090040import java.util.List;
DongRyeol Cha53a270b2018-06-04 17:09:40 +090041import java.util.Map;
42import java.util.Optional;
Daniel Park531fb482016-07-02 14:21:31 +090043
44import static com.google.common.base.Preconditions.checkNotNull;
45import static org.slf4j.LoggerFactory.getLogger;
46
47/**
48 * Discovers the ports from Arista EOS device.
49 */
50public class DeviceDescriptionDiscoveryAristaImpl extends AbstractHandlerBehaviour
51 implements DeviceDescriptionDiscovery {
52
DongRyeol Cha3df560b2018-06-05 12:50:58 +090053 private static final String UNKNOWN = "unknown";
Daniel Park531fb482016-07-02 14:21:31 +090054 private static final String INTERFACE_STATUSES = "interfaceStatuses";
55 private static final String LINK_STATUS = "linkStatus";
56 private static final String LINE_PROTOCOL_STATUS = "lineProtocolStatus";
57 private static final String BANDWIDTH = "bandwidth";
58 private static final String ETHERNET = "Ethernet";
59 private static final String MANAGEMENT = "Management";
60 private static final String INTERFACE_TYPE = "interfaceType";
DongRyeol Cha53a270b2018-06-04 17:09:40 +090061 private static final String INTERFACES = "interfaces";
62 private static final String BURNED_IN_ADDRESS = "burnedInAddress";
63 private static final String PHYSICAL_ADDRESS = "physicalAddress";
DongRyeol Cha3df560b2018-06-05 12:50:58 +090064 private static final String MODEL_NAME = "modelName";
65 private static final String SW_VERSION = "version";
66 private static final String SERIAL_NUMBER = "serialNumber";
67 private static final String SYSTEM_MAC_ADDRESS = "systemMacAddress";
Eunjin Choi51244d32017-05-15 14:09:56 +090068 private static final int WEIGHTING_FACTOR_MANAGEMENT_INTERFACE = 10000;
DongRyeol Cha3df560b2018-06-05 12:50:58 +090069 private static final String MANUFACTURER = "Arista Networks";
Daniel Park531fb482016-07-02 14:21:31 +090070 private static final String SHOW_INTERFACES_STATUS = "show interfaces status";
DongRyeol Cha53a270b2018-06-04 17:09:40 +090071 private static final String SHOW_INTERFACES = "show interfaces";
DongRyeol Cha3df560b2018-06-05 12:50:58 +090072 private static final String SHOW_VERSION = "show version";
Daniel Park531fb482016-07-02 14:21:31 +090073 private static final long MBPS = 1000000;
74
75 private final Logger log = getLogger(getClass());
76
Daniel Park531fb482016-07-02 14:21:31 +090077 @Override
78 public DeviceDescription discoverDeviceDetails() {
DongRyeol Cha3df560b2018-06-05 12:50:58 +090079 try {
DongRyeol Cha06041fa2018-06-07 10:23:32 +090080 Optional<JsonNode> result = AristaUtils.retrieveCommandResult(handler(), SHOW_VERSION);
DongRyeol Cha3df560b2018-06-05 12:50:58 +090081
82 if (!result.isPresent()) {
83 return null;
84 }
85
DongRyeol Cha06041fa2018-06-07 10:23:32 +090086 JsonNode jsonNode = result.get().get(AristaUtils.RESULT_START_INDEX);
DongRyeol Cha3df560b2018-06-05 12:50:58 +090087 String hwVer = jsonNode.get(MODEL_NAME).asText(UNKNOWN);
88 String swVer = jsonNode.get(SW_VERSION).asText(UNKNOWN);
89 String serialNum = jsonNode.get(SERIAL_NUMBER).asText(UNKNOWN);
90 String systemMacAddress = jsonNode.get(SYSTEM_MAC_ADDRESS).asText("").replace(":", "");
DongRyeol Cha06041fa2018-06-07 10:23:32 +090091 DeviceId deviceId = checkNotNull(handler().data().deviceId());
DongRyeol Cha3df560b2018-06-05 12:50:58 +090092 DeviceService deviceService = checkNotNull(handler().get(DeviceService.class));
93 Device device = deviceService.getDevice(deviceId);
94 ChassisId chassisId = systemMacAddress.isEmpty() ? new ChassisId() : new ChassisId(systemMacAddress);
95
96 log.debug("systemMacAddress: {}", systemMacAddress);
97
98 return new DefaultDeviceDescription(deviceId.uri(), Device.Type.SWITCH,
99 MANUFACTURER, hwVer, swVer, serialNum, chassisId, (SparseAnnotations) device.annotations());
100 } catch (Exception e) {
101 log.error("Exception occurred because of {}, trace: {}", e, e.getStackTrace());
102 return null;
103 }
Daniel Park531fb482016-07-02 14:21:31 +0900104 }
105
106 @Override
107 public List<PortDescription> discoverPortDetails() {
DongRyeol Cha53a270b2018-06-04 17:09:40 +0900108 Map<String, MacAddress> macAddressMap = getMacAddressesByInterface();
Daniel Park531fb482016-07-02 14:21:31 +0900109 List<PortDescription> ports = Lists.newArrayList();
DongRyeol Cha53a270b2018-06-04 17:09:40 +0900110
111 try {
DongRyeol Cha06041fa2018-06-07 10:23:32 +0900112 Optional<JsonNode> result = AristaUtils.retrieveCommandResult(handler(), SHOW_INTERFACES_STATUS);
DongRyeol Cha53a270b2018-06-04 17:09:40 +0900113
114 if (!result.isPresent()) {
115 return ports;
116 }
117
DongRyeol Cha06041fa2018-06-07 10:23:32 +0900118 JsonNode jsonNode = result.get().findValue(INTERFACE_STATUSES);
DongRyeol Cha53a270b2018-06-04 17:09:40 +0900119
120 jsonNode.fieldNames().forEachRemaining(name -> {
121 JsonNode interfaceNode = jsonNode.get(name);
122
123 Long bandwidth = interfaceNode.path(BANDWIDTH).asLong() / MBPS;
124
125 String macAddress = macAddressMap.containsKey(name) ? macAddressMap.get(name).toString() : "";
126
127 SparseAnnotations annotations = DefaultAnnotations.builder()
128 .set(AnnotationKeys.BANDWIDTH, bandwidth.toString())
129 .set(AnnotationKeys.NAME, name)
130 .set(AnnotationKeys.PORT_NAME, name)
131 .set(AnnotationKeys.PORT_MAC, macAddress)
132 .set(LINK_STATUS, interfaceNode.path(LINK_STATUS).asText())
133 .set(LINE_PROTOCOL_STATUS, interfaceNode.path(LINE_PROTOCOL_STATUS).asText())
134 .set(INTERFACE_TYPE, interfaceNode.path(INTERFACE_TYPE).asText())
135 .build();
136
137 int portNumber;
138
139 try {
140 portNumber = getPortNumber(name);
141 } catch (Exception e) {
142 log.debug("Interface does not have port number: {}", name);
143 return;
144 }
145
146 PortDescription portDescription = DefaultPortDescription.builder()
147 .withPortNumber(PortNumber.portNumber(portNumber))
148 .isEnabled(true)
149 .type(Port.Type.FIBER)
150 .portSpeed(bandwidth)
151 .annotations(annotations)
152 .build();
153 ports.add(portDescription);
154
155 });
156
157 } catch (Exception e) {
158 log.error("Exception occurred because of {}, trace: {}", e, e.getStackTrace());
159 }
160 return ports;
161 }
162
163 private int getPortNumber(String interfaceName) {
164 if (interfaceName.startsWith(ETHERNET)) {
165 return Integer.valueOf(interfaceName.substring(ETHERNET.length()).replace('/', '0'));
166 } else {
167 return Integer.valueOf(interfaceName.substring(MANAGEMENT.length())).intValue()
168 + WEIGHTING_FACTOR_MANAGEMENT_INTERFACE;
169 }
170 }
171
172 private Map<String, MacAddress> getMacAddressesByInterface() {
173 Map<String, MacAddress> macAddressMap = new HashMap();
174
175 try {
DongRyeol Cha06041fa2018-06-07 10:23:32 +0900176 Optional<JsonNode> result = AristaUtils.retrieveCommandResult(handler(), SHOW_INTERFACES);
DongRyeol Cha53a270b2018-06-04 17:09:40 +0900177
178 if (!result.isPresent()) {
179 return macAddressMap;
180 }
181
DongRyeol Cha06041fa2018-06-07 10:23:32 +0900182 JsonNode jsonNode = result.get().findValue(INTERFACES);
DongRyeol Cha53a270b2018-06-04 17:09:40 +0900183
184 jsonNode.fieldNames().forEachRemaining(name -> {
185 JsonNode interfaceNode = jsonNode.get(name);
186 JsonNode macAddressNode = interfaceNode.get(BURNED_IN_ADDRESS);
187
188 if (macAddressNode == null) {
189 log.debug("Interface does not have {}: {}", BURNED_IN_ADDRESS, name);
190 return;
191 }
192
193 String macAddress = macAddressNode.asText("");
194
195 if (macAddress.isEmpty()) {
196 macAddressNode = interfaceNode.get(PHYSICAL_ADDRESS);
197
198 if (macAddressNode == null) {
199 log.debug("Interface does not have {}: {}", PHYSICAL_ADDRESS, name);
200 return;
201 }
202
203 macAddress = macAddressNode.asText("");
204
205 if (macAddress.isEmpty()) {
206 log.debug("Interface does not have any mac address: {}", name);
207 return;
208 }
209 }
210
211 try {
212 macAddressMap.put(name, MacAddress.valueOf(macAddress));
213 } catch (IllegalArgumentException e) {
214 log.error("Cannot parse macAddress: {}", macAddress);
215 }
216 });
217 } catch (Exception e) {
218 log.error("Exception occurred because of {}, trace: {}", e, e.getStackTrace());
219 }
220
221 return macAddressMap;
222 }
Daniel Park531fb482016-07-02 14:21:31 +0900223}
224