blob: f9d223668d00a07a517dadbaa5876921698bc738 [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;
21import gnmi.Gnmi;
22import gnmi.Gnmi.GetRequest;
23import gnmi.Gnmi.GetResponse;
24import org.onosproject.net.DefaultAnnotations;
25import org.onosproject.net.PortNumber;
26import org.onosproject.net.device.DefaultPortDescription;
27import org.onosproject.net.device.DeviceDescription;
28import org.onosproject.net.device.DeviceDescriptionDiscovery;
29import org.onosproject.net.device.PortDescription;
30import org.slf4j.Logger;
31import org.slf4j.LoggerFactory;
32
33import java.nio.charset.Charset;
34import java.util.Collections;
35import java.util.List;
36import java.util.Map;
37import java.util.concurrent.ExecutionException;
38import java.util.concurrent.TimeUnit;
39import java.util.concurrent.TimeoutException;
40
41import static gnmi.Gnmi.Path;
42import static gnmi.Gnmi.PathElem;
43import static gnmi.Gnmi.Update;
44
45/**
46 * Class that discovers the device description and ports of a device that
47 * supports the gNMI protocol and Openconfig models.
48 */
49public class OpenConfigGnmiDeviceDescriptionDiscovery
50 extends AbstractGnmiHandlerBehaviour
51 implements DeviceDescriptionDiscovery {
52
53 private static final int REQUEST_TIMEOUT_SECONDS = 5;
54
55 private static final Logger log = LoggerFactory
56 .getLogger(OpenConfigGnmiDeviceDescriptionDiscovery.class);
57
58 @Override
59 public DeviceDescription discoverDeviceDetails() {
60 return null;
61 }
62
63 @Override
64 public List<PortDescription> discoverPortDetails() {
65 if (!setupBehaviour()) {
66 return Collections.emptyList();
67 }
68 log.debug("Discovering port details on device {}", handler().data().deviceId());
69
70 GetResponse response;
71 try {
72 response = client.get(buildPortStateRequest())
73 .get(REQUEST_TIMEOUT_SECONDS, TimeUnit.SECONDS);
74 } catch (InterruptedException | ExecutionException | TimeoutException e) {
75 log.warn("Unable to discover ports from {}: {}", deviceId, e.getMessage());
76 log.debug("{}", e);
77 return Collections.emptyList();
78 }
79
80 Map<String, DefaultPortDescription.Builder> ports = Maps.newHashMap();
81 Map<String, DefaultAnnotations.Builder> annotations = Maps.newHashMap();
82
83 // Creates port descriptions with port name and port number
84 response.getNotificationList()
85 .stream()
86 .flatMap(notification -> notification.getUpdateList().stream())
87 .forEach(update -> {
88 // /interfaces/interface[name=ifName]/state/...
89 String ifName = update.getPath().getElem(1).getKeyMap().get("name");
90 if (!ports.containsKey(ifName)) {
91 ports.put(ifName, DefaultPortDescription.builder());
92 annotations.put(ifName, DefaultAnnotations.builder());
93 }
94
95
96 DefaultPortDescription.Builder builder = ports.get(ifName);
97 DefaultAnnotations.Builder annotationsBuilder = annotations.get(ifName);
98 parseInterfaceInfo(update, ifName, builder, annotationsBuilder);
99 });
100
101 List<PortDescription> portDescriptionList = Lists.newArrayList();
102 ports.forEach((key, value) -> {
103 DefaultAnnotations annotation = annotations.get(key).build();
104 portDescriptionList.add(value.annotations(annotation).build());
105 });
106 return portDescriptionList;
107 }
108
109 private GetRequest buildPortStateRequest() {
110 Path path = Path.newBuilder()
111 .addElem(PathElem.newBuilder().setName("interfaces").build())
112 .addElem(PathElem.newBuilder().setName("interface").putKey("name", "...").build())
113 .addElem(PathElem.newBuilder().setName("state").build())
114 .build();
115 return GetRequest.newBuilder()
116 .addPath(path)
117 .setType(GetRequest.DataType.ALL)
118 .setEncoding(Gnmi.Encoding.PROTO)
119 .build();
120 }
121
122 /**
123 * Parses the interface information.
124 *
125 * @param update the update received
126 */
127 private void parseInterfaceInfo(Update update,
128 String ifName,
129 DefaultPortDescription.Builder builder,
130 DefaultAnnotations.Builder annotationsBuilder) {
131
132
133 Path path = update.getPath();
134 List<PathElem> elems = path.getElemList();
135 Gnmi.TypedValue val = update.getVal();
136 if (elems.size() == 4) {
137 // /interfaces/interface/state/ifindex
138 // /interfaces/interface/state/oper-status
139 String pathElemName = elems.get(3).getName();
140 switch (pathElemName) {
141 case "ifindex": // port number
142 builder.withPortNumber(PortNumber.portNumber(val.getUintVal(), ifName));
143 break;
144 case "oper-status":
145 builder.isEnabled(parseOperStatus(val.getStringVal()));
146 break;
147 default:
148 String valueString = val.toByteString().toString(Charset.defaultCharset()).trim();
149 if (!valueString.isEmpty()) {
150 annotationsBuilder.set(pathElemName, valueString);
151 }
152 log.debug("Unknown path: {}", path);
153 break;
154 }
155 }
156 if (elems.size() == 5) {
157 // /interfaces/interface/ethernet/config/port-speed
158 String pathElemName = elems.get(4).getName();
159 switch (pathElemName) {
160 case "port-speed":
161 builder.portSpeed(parsePortSpeed(val.getStringVal()));
162 break;
163 default:
164 String valueString = val.toByteString().toString(Charset.defaultCharset()).trim();
165 if (!valueString.isEmpty()) {
166 annotationsBuilder.set(pathElemName, valueString);
167 }
168 log.debug("Unknown path: {}", path);
169 break;
170 }
171 }
172 }
173
174 private boolean parseOperStatus(String operStatus) {
175 switch (operStatus) {
176 case "UP":
177 return true;
178 case "DOWN":
179 default:
180 return false;
181 }
182 }
183
184 private long parsePortSpeed(String speed) {
185 log.debug("Speed from config {}", speed);
186 switch (speed) {
187 case "SPEED_10MB":
188 return 10;
189 case "SPEED_100MB":
190 return 100;
191 case "SPEED_1GB":
192 return 1000;
193 case "SPEED_10GB":
194 return 10000;
195 case "SPEED_25GB":
196 return 25000;
197 case "SPEED_40GB":
198 return 40000;
199 case "SPEED_50GB":
200 return 50000;
201 case "SPEED_100GB":
202 return 100000;
203 default:
204 return 1000;
205 }
206 }
207}