blob: bdc0e916d65e2962fa10af4ef12596f99b33d25e [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() {
HelloONOS4baf78a2019-02-14 18:47:19 +0900108
DongRyeol Cha53a270b2018-06-04 17:09:40 +0900109 Map<String, MacAddress> macAddressMap = getMacAddressesByInterface();
Daniel Park531fb482016-07-02 14:21:31 +0900110 List<PortDescription> ports = Lists.newArrayList();
HelloONOS4baf78a2019-02-14 18:47:19 +0900111 DeviceId deviceId = checkNotNull(handler().data().deviceId());
DongRyeol Cha53a270b2018-06-04 17:09:40 +0900112
113 try {
DongRyeol Cha06041fa2018-06-07 10:23:32 +0900114 Optional<JsonNode> result = AristaUtils.retrieveCommandResult(handler(), SHOW_INTERFACES_STATUS);
DongRyeol Cha53a270b2018-06-04 17:09:40 +0900115
116 if (!result.isPresent()) {
HelloONOS4baf78a2019-02-14 18:47:19 +0900117 log.warn("{} Device unable to get interfaces status information.", deviceId);
DongRyeol Cha53a270b2018-06-04 17:09:40 +0900118 return ports;
119 }
120
DongRyeol Cha06041fa2018-06-07 10:23:32 +0900121 JsonNode jsonNode = result.get().findValue(INTERFACE_STATUSES);
DongRyeol Cha53a270b2018-06-04 17:09:40 +0900122 jsonNode.fieldNames().forEachRemaining(name -> {
123 JsonNode interfaceNode = jsonNode.get(name);
124
125 Long bandwidth = interfaceNode.path(BANDWIDTH).asLong() / MBPS;
126
127 String macAddress = macAddressMap.containsKey(name) ? macAddressMap.get(name).toString() : "";
128
129 SparseAnnotations annotations = DefaultAnnotations.builder()
130 .set(AnnotationKeys.BANDWIDTH, bandwidth.toString())
131 .set(AnnotationKeys.NAME, name)
132 .set(AnnotationKeys.PORT_NAME, name)
133 .set(AnnotationKeys.PORT_MAC, macAddress)
134 .set(LINK_STATUS, interfaceNode.path(LINK_STATUS).asText())
135 .set(LINE_PROTOCOL_STATUS, interfaceNode.path(LINE_PROTOCOL_STATUS).asText())
136 .set(INTERFACE_TYPE, interfaceNode.path(INTERFACE_TYPE).asText())
137 .build();
138
139 int portNumber;
140
141 try {
142 portNumber = getPortNumber(name);
143 } catch (Exception e) {
144 log.debug("Interface does not have port number: {}", name);
145 return;
146 }
147
148 PortDescription portDescription = DefaultPortDescription.builder()
149 .withPortNumber(PortNumber.portNumber(portNumber))
150 .isEnabled(true)
151 .type(Port.Type.FIBER)
152 .portSpeed(bandwidth)
153 .annotations(annotations)
154 .build();
155 ports.add(portDescription);
156
157 });
158
159 } catch (Exception e) {
160 log.error("Exception occurred because of {}, trace: {}", e, e.getStackTrace());
161 }
162 return ports;
163 }
164
165 private int getPortNumber(String interfaceName) {
166 if (interfaceName.startsWith(ETHERNET)) {
167 return Integer.valueOf(interfaceName.substring(ETHERNET.length()).replace('/', '0'));
168 } else {
169 return Integer.valueOf(interfaceName.substring(MANAGEMENT.length())).intValue()
170 + WEIGHTING_FACTOR_MANAGEMENT_INTERFACE;
171 }
172 }
173
174 private Map<String, MacAddress> getMacAddressesByInterface() {
HelloONOS4baf78a2019-02-14 18:47:19 +0900175
176 DeviceId deviceId = checkNotNull(handler().data().deviceId());
DongRyeol Cha53a270b2018-06-04 17:09:40 +0900177 Map<String, MacAddress> macAddressMap = new HashMap();
178
179 try {
DongRyeol Cha06041fa2018-06-07 10:23:32 +0900180 Optional<JsonNode> result = AristaUtils.retrieveCommandResult(handler(), SHOW_INTERFACES);
DongRyeol Cha53a270b2018-06-04 17:09:40 +0900181
182 if (!result.isPresent()) {
HelloONOS4baf78a2019-02-14 18:47:19 +0900183 log.warn("{} Device unable to get interface information.", deviceId);
DongRyeol Cha53a270b2018-06-04 17:09:40 +0900184 return macAddressMap;
185 }
186
DongRyeol Cha06041fa2018-06-07 10:23:32 +0900187 JsonNode jsonNode = result.get().findValue(INTERFACES);
DongRyeol Cha53a270b2018-06-04 17:09:40 +0900188
189 jsonNode.fieldNames().forEachRemaining(name -> {
190 JsonNode interfaceNode = jsonNode.get(name);
191 JsonNode macAddressNode = interfaceNode.get(BURNED_IN_ADDRESS);
192
193 if (macAddressNode == null) {
194 log.debug("Interface does not have {}: {}", BURNED_IN_ADDRESS, name);
195 return;
196 }
197
198 String macAddress = macAddressNode.asText("");
199
200 if (macAddress.isEmpty()) {
201 macAddressNode = interfaceNode.get(PHYSICAL_ADDRESS);
202
203 if (macAddressNode == null) {
204 log.debug("Interface does not have {}: {}", PHYSICAL_ADDRESS, name);
205 return;
206 }
207
208 macAddress = macAddressNode.asText("");
209
210 if (macAddress.isEmpty()) {
211 log.debug("Interface does not have any mac address: {}", name);
212 return;
213 }
214 }
215
216 try {
217 macAddressMap.put(name, MacAddress.valueOf(macAddress));
218 } catch (IllegalArgumentException e) {
219 log.error("Cannot parse macAddress: {}", macAddress);
220 }
221 });
222 } catch (Exception e) {
223 log.error("Exception occurred because of {}, trace: {}", e, e.getStackTrace());
224 }
225
226 return macAddressMap;
227 }
Daniel Park531fb482016-07-02 14:21:31 +0900228}
229