blob: e56f2f32e74648a726cee8ecce32fb973dea893c [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
Yi Tseng27851e32018-11-01 18:30:04 -070033import java.util.Collections;
34import java.util.List;
35import java.util.Map;
Yi Tseng27851e32018-11-01 18:30:04 -070036
37import static gnmi.Gnmi.Path;
38import static gnmi.Gnmi.PathElem;
39import static gnmi.Gnmi.Update;
40
41/**
42 * Class that discovers the device description and ports of a device that
43 * supports the gNMI protocol and Openconfig models.
44 */
45public class OpenConfigGnmiDeviceDescriptionDiscovery
46 extends AbstractGnmiHandlerBehaviour
47 implements DeviceDescriptionDiscovery {
48
Yi Tseng27851e32018-11-01 18:30:04 -070049 private static final Logger log = LoggerFactory
50 .getLogger(OpenConfigGnmiDeviceDescriptionDiscovery.class);
51
Yi Tseng59d5f3e2018-11-27 23:09:41 -080052 private static final String LAST_CHANGE = "last-change";
53
Yi Tseng27851e32018-11-01 18:30:04 -070054 @Override
55 public DeviceDescription discoverDeviceDetails() {
56 return null;
57 }
58
59 @Override
60 public List<PortDescription> discoverPortDetails() {
61 if (!setupBehaviour()) {
62 return Collections.emptyList();
63 }
64 log.debug("Discovering port details on device {}", handler().data().deviceId());
65
Yi Tsengd7716482018-10-31 15:34:30 -070066 final GetResponse response = getFutureWithDeadline(
67 client.get(buildPortStateRequest()),
68 "getting port details", GetResponse.getDefaultInstance());
Yi Tseng27851e32018-11-01 18:30:04 -070069
Yi Tsengd7716482018-10-31 15:34:30 -070070 final Map<String, DefaultPortDescription.Builder> ports = Maps.newHashMap();
71 final Map<String, DefaultAnnotations.Builder> annotations = Maps.newHashMap();
Yi Tseng27851e32018-11-01 18:30:04 -070072
73 // Creates port descriptions with port name and port number
74 response.getNotificationList()
Yi Tseng59d5f3e2018-11-27 23:09:41 -080075 .forEach(notification -> {
76 long timestamp = notification.getTimestamp();
77 notification.getUpdateList().forEach(update -> {
78 // /interfaces/interface[name=ifName]/state/...
79 final String ifName = update.getPath().getElem(1)
80 .getKeyMap().get("name");
81 if (!ports.containsKey(ifName)) {
82 ports.put(ifName, DefaultPortDescription.builder());
83 annotations.put(ifName, DefaultAnnotations.builder());
84 }
85 final DefaultPortDescription.Builder builder = ports.get(ifName);
86 final DefaultAnnotations.Builder annotationsBuilder = annotations.get(ifName);
87 parseInterfaceInfo(update, ifName, builder, annotationsBuilder, timestamp);
88 });
Yi Tseng27851e32018-11-01 18:30:04 -070089 });
90
Yi Tsengd7716482018-10-31 15:34:30 -070091 final List<PortDescription> portDescriptionList = Lists.newArrayList();
Yi Tseng27851e32018-11-01 18:30:04 -070092 ports.forEach((key, value) -> {
93 DefaultAnnotations annotation = annotations.get(key).build();
94 portDescriptionList.add(value.annotations(annotation).build());
95 });
96 return portDescriptionList;
97 }
98
99 private GetRequest buildPortStateRequest() {
100 Path path = Path.newBuilder()
101 .addElem(PathElem.newBuilder().setName("interfaces").build())
102 .addElem(PathElem.newBuilder().setName("interface").putKey("name", "...").build())
103 .addElem(PathElem.newBuilder().setName("state").build())
104 .build();
105 return GetRequest.newBuilder()
106 .addPath(path)
107 .setType(GetRequest.DataType.ALL)
108 .setEncoding(Gnmi.Encoding.PROTO)
109 .build();
110 }
111
112 /**
113 * Parses the interface information.
114 *
Yi Tsengd7716482018-10-31 15:34:30 -0700115 * @param update the update received
Yi Tseng27851e32018-11-01 18:30:04 -0700116 */
117 private void parseInterfaceInfo(Update update,
118 String ifName,
119 DefaultPortDescription.Builder builder,
Yi Tseng59d5f3e2018-11-27 23:09:41 -0800120 DefaultAnnotations.Builder annotationsBuilder,
121 long timestamp) {
Yi Tseng27851e32018-11-01 18:30:04 -0700122
123
Yi Tsengd7716482018-10-31 15:34:30 -0700124 final Path path = update.getPath();
125 final List<PathElem> elems = path.getElemList();
126 final Gnmi.TypedValue val = update.getVal();
Yi Tseng27851e32018-11-01 18:30:04 -0700127 if (elems.size() == 4) {
128 // /interfaces/interface/state/ifindex
129 // /interfaces/interface/state/oper-status
Yi Tsengd7716482018-10-31 15:34:30 -0700130 final String pathElemName = elems.get(3).getName();
Yi Tseng27851e32018-11-01 18:30:04 -0700131 switch (pathElemName) {
132 case "ifindex": // port number
133 builder.withPortNumber(PortNumber.portNumber(val.getUintVal(), ifName));
Yi Tsengd7716482018-10-31 15:34:30 -0700134 return;
Yi Tseng27851e32018-11-01 18:30:04 -0700135 case "oper-status":
136 builder.isEnabled(parseOperStatus(val.getStringVal()));
Yi Tseng59d5f3e2018-11-27 23:09:41 -0800137 annotationsBuilder.set(LAST_CHANGE, String.valueOf(timestamp));
Yi Tsengd7716482018-10-31 15:34:30 -0700138 return;
Yi Tseng27851e32018-11-01 18:30:04 -0700139 default:
Yi Tseng27851e32018-11-01 18:30:04 -0700140 break;
141 }
Yi Tsengd7716482018-10-31 15:34:30 -0700142 } else if (elems.size() == 5) {
Yi Tseng27851e32018-11-01 18:30:04 -0700143 // /interfaces/interface/ethernet/config/port-speed
Yi Tsengd7716482018-10-31 15:34:30 -0700144 final String pathElemName = elems.get(4).getName();
145 if (pathElemName.equals("port-speed")) {
146 builder.portSpeed(parsePortSpeed(val.getStringVal()));
147 return;
Yi Tseng27851e32018-11-01 18:30:04 -0700148 }
149 }
Yi Tsengd7716482018-10-31 15:34:30 -0700150 log.debug("Unknown path when parsing interface info: {}", path);
Yi Tseng27851e32018-11-01 18:30:04 -0700151 }
152
153 private boolean parseOperStatus(String operStatus) {
154 switch (operStatus) {
155 case "UP":
156 return true;
157 case "DOWN":
158 default:
159 return false;
160 }
161 }
162
163 private long parsePortSpeed(String speed) {
164 log.debug("Speed from config {}", speed);
165 switch (speed) {
166 case "SPEED_10MB":
167 return 10;
168 case "SPEED_100MB":
169 return 100;
170 case "SPEED_1GB":
171 return 1000;
172 case "SPEED_10GB":
173 return 10000;
174 case "SPEED_25GB":
175 return 25000;
176 case "SPEED_40GB":
177 return 40000;
178 case "SPEED_50GB":
179 return 50000;
180 case "SPEED_100GB":
181 return 100000;
182 default:
Yi Tsengd7716482018-10-31 15:34:30 -0700183 log.warn("Unrecognized port speed string '{}'", speed);
Yi Tseng27851e32018-11-01 18:30:04 -0700184 return 1000;
185 }
186 }
187}