blob: ce134adad97c2a6c29ade1c38544beae787fb338 [file] [log] [blame]
Yi Tseng27851e32018-11-01 18:30:04 -07001/*
2 * Copyright 2017-present 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.gnmi;
18
19import com.google.common.collect.Lists;
20import com.google.common.collect.Maps;
Carmelo Casconeab5d41e2019-03-06 18:02:34 -080021import com.google.common.util.concurrent.Futures;
Yi Tseng27851e32018-11-01 18:30:04 -070022import gnmi.Gnmi;
23import gnmi.Gnmi.GetRequest;
24import gnmi.Gnmi.GetResponse;
Carmelo Casconeab5d41e2019-03-06 18:02:34 -080025import org.onlab.packet.ChassisId;
26import org.onosproject.net.AnnotationKeys;
Yi Tseng27851e32018-11-01 18:30:04 -070027import org.onosproject.net.DefaultAnnotations;
Carmelo Casconeab5d41e2019-03-06 18:02:34 -080028import org.onosproject.net.Device;
Yi Tseng27851e32018-11-01 18:30:04 -070029import org.onosproject.net.PortNumber;
Carmelo Casconeab5d41e2019-03-06 18:02:34 -080030import org.onosproject.net.device.DefaultDeviceDescription;
Yi Tseng27851e32018-11-01 18:30:04 -070031import org.onosproject.net.device.DefaultPortDescription;
32import org.onosproject.net.device.DeviceDescription;
33import org.onosproject.net.device.DeviceDescriptionDiscovery;
34import org.onosproject.net.device.PortDescription;
35import org.slf4j.Logger;
36import org.slf4j.LoggerFactory;
37
Yi Tseng27851e32018-11-01 18:30:04 -070038import java.util.Collections;
39import java.util.List;
40import java.util.Map;
Yi Tseng27851e32018-11-01 18:30:04 -070041
42import static gnmi.Gnmi.Path;
43import static gnmi.Gnmi.PathElem;
44import static gnmi.Gnmi.Update;
45
46/**
47 * Class that discovers the device description and ports of a device that
48 * supports the gNMI protocol and Openconfig models.
49 */
50public class OpenConfigGnmiDeviceDescriptionDiscovery
51 extends AbstractGnmiHandlerBehaviour
52 implements DeviceDescriptionDiscovery {
53
Yi Tseng27851e32018-11-01 18:30:04 -070054 private static final Logger log = LoggerFactory
55 .getLogger(OpenConfigGnmiDeviceDescriptionDiscovery.class);
56
Carmelo Casconeab5d41e2019-03-06 18:02:34 -080057 private static final String LAST_CHANGE = "last-changed";
58
59 private static final String UNKNOWN = "unknown";
Yi Tseng59d5f3e2018-11-27 23:09:41 -080060
Yi Tseng27851e32018-11-01 18:30:04 -070061 @Override
62 public DeviceDescription discoverDeviceDetails() {
Carmelo Casconeab5d41e2019-03-06 18:02:34 -080063 return new DefaultDeviceDescription(
64 data().deviceId().uri(),
65 Device.Type.SWITCH,
66 data().driver().manufacturer(),
67 data().driver().hwVersion(),
68 data().driver().swVersion(),
69 UNKNOWN,
70 new ChassisId(),
71 true,
72 DefaultAnnotations.builder()
73 .set(AnnotationKeys.PROTOCOL, "gNMI")
74 .build());
Yi Tseng27851e32018-11-01 18:30:04 -070075 }
76
77 @Override
78 public List<PortDescription> discoverPortDetails() {
79 if (!setupBehaviour()) {
80 return Collections.emptyList();
81 }
82 log.debug("Discovering port details on device {}", handler().data().deviceId());
83
Carmelo Casconeab5d41e2019-03-06 18:02:34 -080084 final GetResponse response = Futures.getUnchecked(client.get(buildPortStateRequest()));
Yi Tseng27851e32018-11-01 18:30:04 -070085
Yi Tsengd7716482018-10-31 15:34:30 -070086 final Map<String, DefaultPortDescription.Builder> ports = Maps.newHashMap();
87 final Map<String, DefaultAnnotations.Builder> annotations = Maps.newHashMap();
Yi Tseng27851e32018-11-01 18:30:04 -070088
89 // Creates port descriptions with port name and port number
90 response.getNotificationList()
Yi Tseng59d5f3e2018-11-27 23:09:41 -080091 .forEach(notification -> {
92 long timestamp = notification.getTimestamp();
93 notification.getUpdateList().forEach(update -> {
94 // /interfaces/interface[name=ifName]/state/...
95 final String ifName = update.getPath().getElem(1)
96 .getKeyMap().get("name");
97 if (!ports.containsKey(ifName)) {
98 ports.put(ifName, DefaultPortDescription.builder());
99 annotations.put(ifName, DefaultAnnotations.builder());
100 }
101 final DefaultPortDescription.Builder builder = ports.get(ifName);
102 final DefaultAnnotations.Builder annotationsBuilder = annotations.get(ifName);
103 parseInterfaceInfo(update, ifName, builder, annotationsBuilder, timestamp);
104 });
Yi Tseng27851e32018-11-01 18:30:04 -0700105 });
106
Yi Tsengd7716482018-10-31 15:34:30 -0700107 final List<PortDescription> portDescriptionList = Lists.newArrayList();
Yi Tseng27851e32018-11-01 18:30:04 -0700108 ports.forEach((key, value) -> {
109 DefaultAnnotations annotation = annotations.get(key).build();
110 portDescriptionList.add(value.annotations(annotation).build());
111 });
112 return portDescriptionList;
113 }
114
115 private GetRequest buildPortStateRequest() {
116 Path path = Path.newBuilder()
117 .addElem(PathElem.newBuilder().setName("interfaces").build())
118 .addElem(PathElem.newBuilder().setName("interface").putKey("name", "...").build())
119 .addElem(PathElem.newBuilder().setName("state").build())
120 .build();
121 return GetRequest.newBuilder()
122 .addPath(path)
123 .setType(GetRequest.DataType.ALL)
124 .setEncoding(Gnmi.Encoding.PROTO)
125 .build();
126 }
127
128 /**
129 * Parses the interface information.
130 *
Yi Tsengd7716482018-10-31 15:34:30 -0700131 * @param update the update received
Yi Tseng27851e32018-11-01 18:30:04 -0700132 */
133 private void parseInterfaceInfo(Update update,
134 String ifName,
135 DefaultPortDescription.Builder builder,
Yi Tseng59d5f3e2018-11-27 23:09:41 -0800136 DefaultAnnotations.Builder annotationsBuilder,
137 long timestamp) {
Yi Tseng27851e32018-11-01 18:30:04 -0700138
139
Yi Tsengd7716482018-10-31 15:34:30 -0700140 final Path path = update.getPath();
141 final List<PathElem> elems = path.getElemList();
142 final Gnmi.TypedValue val = update.getVal();
Yi Tseng27851e32018-11-01 18:30:04 -0700143 if (elems.size() == 4) {
144 // /interfaces/interface/state/ifindex
145 // /interfaces/interface/state/oper-status
Yi Tsengd7716482018-10-31 15:34:30 -0700146 final String pathElemName = elems.get(3).getName();
Yi Tseng27851e32018-11-01 18:30:04 -0700147 switch (pathElemName) {
148 case "ifindex": // port number
149 builder.withPortNumber(PortNumber.portNumber(val.getUintVal(), ifName));
Yi Tsengd7716482018-10-31 15:34:30 -0700150 return;
Yi Tseng27851e32018-11-01 18:30:04 -0700151 case "oper-status":
152 builder.isEnabled(parseOperStatus(val.getStringVal()));
Yi Tseng59d5f3e2018-11-27 23:09:41 -0800153 annotationsBuilder.set(LAST_CHANGE, String.valueOf(timestamp));
Yi Tsengd7716482018-10-31 15:34:30 -0700154 return;
Yi Tseng27851e32018-11-01 18:30:04 -0700155 default:
Yi Tseng27851e32018-11-01 18:30:04 -0700156 break;
157 }
Yi Tsengd7716482018-10-31 15:34:30 -0700158 } else if (elems.size() == 5) {
Yi Tseng27851e32018-11-01 18:30:04 -0700159 // /interfaces/interface/ethernet/config/port-speed
Yi Tsengd7716482018-10-31 15:34:30 -0700160 final String pathElemName = elems.get(4).getName();
161 if (pathElemName.equals("port-speed")) {
162 builder.portSpeed(parsePortSpeed(val.getStringVal()));
163 return;
Yi Tseng27851e32018-11-01 18:30:04 -0700164 }
165 }
Yi Tsengd7716482018-10-31 15:34:30 -0700166 log.debug("Unknown path when parsing interface info: {}", path);
Yi Tseng27851e32018-11-01 18:30:04 -0700167 }
168
169 private boolean parseOperStatus(String operStatus) {
170 switch (operStatus) {
171 case "UP":
172 return true;
173 case "DOWN":
174 default:
175 return false;
176 }
177 }
178
179 private long parsePortSpeed(String speed) {
180 log.debug("Speed from config {}", speed);
181 switch (speed) {
182 case "SPEED_10MB":
183 return 10;
184 case "SPEED_100MB":
185 return 100;
186 case "SPEED_1GB":
187 return 1000;
188 case "SPEED_10GB":
189 return 10000;
190 case "SPEED_25GB":
191 return 25000;
192 case "SPEED_40GB":
193 return 40000;
194 case "SPEED_50GB":
195 return 50000;
196 case "SPEED_100GB":
197 return 100000;
198 default:
Yi Tsengd7716482018-10-31 15:34:30 -0700199 log.warn("Unrecognized port speed string '{}'", speed);
Yi Tseng27851e32018-11-01 18:30:04 -0700200 return 1000;
201 }
202 }
203}