blob: 7d771cbc2ae153990218ee5f9f65b4481d75be18 [file] [log] [blame]
Michele Santuari21c14012016-11-14 13:31:33 +01001/*
2 * Copyright 2016-present Open Networking Laboratory
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.juniper;
18
19import com.google.common.collect.Lists;
20import org.apache.commons.configuration.HierarchicalConfiguration;
21import org.onlab.packet.ChassisId;
22import org.onlab.packet.MacAddress;
23import org.onosproject.net.AnnotationKeys;
24import org.onosproject.net.ConnectPoint;
25import org.onosproject.net.DefaultAnnotations;
26import org.onosproject.net.DeviceId;
27import org.onosproject.net.Link;
28import org.onosproject.net.Port;
29import org.onosproject.net.PortNumber;
30import org.onosproject.net.device.DefaultDeviceDescription;
31import org.onosproject.net.device.DefaultPortDescription;
32import org.onosproject.net.device.DeviceDescription;
33import org.onosproject.net.device.PortDescription;
34import org.onosproject.net.link.DefaultLinkDescription;
35import org.onosproject.net.link.LinkDescription;
36
37import java.util.HashSet;
38import java.util.List;
39import java.util.Set;
40import java.util.regex.Matcher;
41import java.util.regex.Pattern;
42
43import static java.lang.Integer.parseInt;
44import static org.onosproject.net.DefaultAnnotations.Builder;
45import static org.onosproject.net.Device.Type.ROUTER;
46import static org.onosproject.net.Port.Type.COPPER;
47import static org.onosproject.net.PortNumber.portNumber;
48
49/**
50 * Utility class for Netconf XML for Juniper.
51 * Tested with MX240 junos 14.2
52 */
53public final class JuniperUtils {
54
55 public static final String FAILED_CFG = "Failed to retrieve configuration.";
56
57 private static final String RPC_TAG_NETCONF_BASE = "<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">";
58 private static final String RPC_CLOSE_TAG = "</rpc>";
59
60 //requests
61 public static final String REQ_LLDP_NBR_INFO = "<get-lldp-neighbors-information/>";
62 public static final String REQ_SYS_INFO = "<get-system-information/>";
63 public static final String REQ_MAC_ADD_INFO = "<get-chassis-mac-addresses/>";
64 public static final String REQ_IF_INFO = "<get-interface-information/>";
65
66 //helper strings for parsing
67 private static final String LLDP_NBR_INFO = "lldp-neighbors-information";
68 private static final String SYS_INFO = "system-information";
69 private static final String HW_MODEL = "hardware-model";
70 private static final String OS_NAME = "os-name";
71 private static final String OS_VER = "os-version";
72 private static final String SER_NUM = "serial-number";
73 private static final String IF_INFO = "interface-information";
74 private static final String IF_PHY = "physical-interface";
75 private static final String IF_TYPE = "if-type";
76 private static final String SPEED = "speed";
77 private static final String ETH = "Ethernet";
78 private static final String MBPS = "mbps";
79 private static final String NAME = "name";
80 private static final String IF_LO_ENCAP = "logical-interface.encapsulation";
81 private static final String IF_LO_NAME = "logical-interface.name";
82 private static final String IF_LO_ADD =
83 "logical-interface.address-family.interface-address.ifa-local";
84 private static final String LO_INDEX = "local-index";
85 private static final String STATUS = "admin-status";
86 private static final String SNMP_INDEX = "snmp-index";
87 private static final String IF_LO_INDEX = "logical-interface.local-index";
88 private static final String IF_LO_STATUS =
89 "logical-interface.if-config-flags.iff-up";
90 private static final String LLDP_LO_PORT = "lldp-local-port-id";
91 private static final String LLDP_REM_CHASS = "lldp-remote-chassis-id";
92 private static final String LLDP_REM_PORT = "lldp-remote-port-id";
93 private static final String REGEX_ADD =
94 ".*Private base address\\s*([:,0-9,a-f,A-F]*).*";
95 private static final Pattern ADD_PATTERN =
96 Pattern.compile(REGEX_ADD, Pattern.DOTALL);
97
98 private static final String JUNIPER = "JUNIPER";
99 private static final String UNKNOWN = "UNKNOWN";
100 private static final long DEFAULT_PORT_SPEED = 1000;
101
102
103 private JuniperUtils() {
104 //not called, preventing any allocation
105 }
106
107 /**
108 * Helper method to build a XML schema given a request.
109 *
110 * @param request a tag element of the XML schema
111 * @return string containing the XML schema
112 */
113 public static String requestBuilder(String request) {
114 return RPC_TAG_NETCONF_BASE +
115 request + RPC_CLOSE_TAG;
116 }
117
118 /**
119 * Parses device configuration and returns the device description.
120 *
121 * @param deviceId the id of the device
122 * @param sysInfoCfg system configuration
123 * @param chassisText chassis string
124 * @return device description
125 */
126 public static DeviceDescription parseJuniperDescription(DeviceId deviceId,
127 HierarchicalConfiguration sysInfoCfg,
128 String chassisText) {
129 HierarchicalConfiguration info = sysInfoCfg.configurationAt(SYS_INFO);
130
131 String hw = info.getString(HW_MODEL) == null ? UNKNOWN : info.getString(HW_MODEL);
132 String sw = UNKNOWN;
133 if (info.getString(OS_NAME) != null || info.getString(OS_VER) != null) {
134 sw = info.getString(OS_NAME) + " " + info.getString(OS_VER);
135 }
136 String serial = info.getString(SER_NUM) == null ? UNKNOWN : info.getString(SER_NUM);
137
138 Matcher matcher = ADD_PATTERN.matcher(chassisText);
139 if (matcher.lookingAt()) {
140 String chassis = matcher.group(1);
141 MacAddress chassisMac = MacAddress.valueOf(chassis);
142 return new DefaultDeviceDescription(deviceId.uri(), ROUTER,
143 JUNIPER, hw, sw, serial,
144 new ChassisId(chassisMac.toLong()),
145 DefaultAnnotations.EMPTY);
146 }
147 return new DefaultDeviceDescription(deviceId.uri(), ROUTER,
148 JUNIPER, hw, sw, serial,
149 null, DefaultAnnotations.EMPTY);
150 }
151
152 /**
153 * Parses device ports configuration and returns a list of
154 * port description.
155 *
156 * @param cfg interface configuration
157 * @return list of interface descriptions of the device
158 */
159 public static List<PortDescription> parseJuniperPorts(HierarchicalConfiguration cfg) {
160 //This methods ignores some internal ports
161
162 List<PortDescription> portDescriptions = Lists.newArrayList();
163 List<HierarchicalConfiguration> subtrees =
164 cfg.configurationsAt(IF_INFO);
165 for (HierarchicalConfiguration interfInfo : subtrees) {
166 List<HierarchicalConfiguration> interfaceTree =
167 interfInfo.configurationsAt(IF_PHY);
168 for (HierarchicalConfiguration interf : interfaceTree) {
169 if (interf != null) {
170 if (interf.getString(IF_TYPE) != null &&
171 interf.getString(SPEED) != null) {
172 if (interf.getString(IF_TYPE).contains(ETH) &&
173 interf.getString(SPEED).contains(MBPS)) {
174 portDescriptions.add(parseDefaultPort(interf));
175 }
176 } else if (interf.getString(IF_LO_ENCAP) != null &&
177 !interf.getString(NAME).contains("pfe") &&
178 interf.getString(IF_LO_ENCAP).contains("ENET2")) {
179 portDescriptions.add(parseLogicalPort(interf));
180 } else if (interf.getString(NAME).contains("lo")) {
181 portDescriptions.add(parseLoopback(interf));
182 }
183 }
184 }
185 }
186 return portDescriptions;
187 }
188
189 private static PortDescription parseLoopback(HierarchicalConfiguration cfg) {
190 String name = cfg.getString(IF_LO_NAME).trim();
191 PortNumber portNumber = portNumber(name.replace("lo0.", ""));
192
193 Builder annotationsBuilder = DefaultAnnotations.builder()
194 .set(AnnotationKeys.PORT_NAME, name);
195 String ip = cfg.getString(IF_LO_ADD);
196 if (ip != null) {
197 annotationsBuilder.set("ip", ip);
198 }
199
200 return new DefaultPortDescription(portNumber,
201 true,
202 COPPER,
203 DEFAULT_PORT_SPEED,
204 annotationsBuilder.build());
205 }
206
207 private static DefaultPortDescription parseDefaultPort(HierarchicalConfiguration cfg) {
208 PortNumber portNumber = portNumber(cfg.getString(LO_INDEX));
209 boolean enabled = cfg.getString(STATUS).equals("up");
210 int speed = parseInt(cfg.getString(SPEED).replaceAll(MBPS, ""));
211
212
213 Builder annotationsBuilder = DefaultAnnotations.builder()
214 .set(AnnotationKeys.PORT_NAME, cfg.getString(NAME).trim());
215 setIpIfPresent(cfg, annotationsBuilder);
216
217 return new DefaultPortDescription(portNumber,
218 enabled,
219 COPPER,
220 speed,
221 annotationsBuilder.build());
222 }
223
224 private static DefaultPortDescription parseLogicalPort(HierarchicalConfiguration cfg) {
225
226 String name = cfg.getString(NAME).trim();
227 String index = cfg.getString(SNMP_INDEX).trim();
228 Builder annotationsBuilder = DefaultAnnotations.builder()
229 .set(AnnotationKeys.PORT_NAME, name)
230 .set("index", index);
231 setIpIfPresent(cfg, annotationsBuilder);
232
233 PortNumber portNumber = portNumberFromName(cfg.getString(IF_LO_INDEX), name);
234
235 boolean enabled = false;
236 if (cfg.getString(IF_LO_STATUS) != null) {
237 enabled = true;
238 }
239 //FIXME: port speed should be exposed
240 return new DefaultPortDescription(
241 portNumber,
242 enabled,
243 COPPER,
244 DEFAULT_PORT_SPEED,
245 annotationsBuilder.build());
246 }
247
248 private static PortNumber portNumberFromName(String ifIndex, String name) {
249 PortNumber portNumber = portNumber(ifIndex);
250 if (name.contains("-")) {
251 String[] splitted = name.split("-");
252 String typeInt = "[" + splitted[0] + "]";
253 String number = splitted[1].replace("/", "");
254 number = "(" + number + ")";
255 portNumber = PortNumber.fromString(typeInt + number);
256 }
257 return portNumber;
258 }
259
260 private static void setIpIfPresent(HierarchicalConfiguration cfg,
261 Builder annotationsBuilder) {
262 String ip = cfg.getString(IF_LO_ADD);
263 if (ip != null) {
264 annotationsBuilder.set("ip", ip);
265 }
266 }
267
268 /**
269 * Create two LinkDescriptions corresponding to the bidirectional links.
270 *
271 * @param localDevId the identity of the local device
272 * @param localPort the port of the local device
273 * @param remoteDevId the identity of the remote device
274 * @param remotePort the port of the remote device
275 * @param descs the collection to which the link descriptions
276 * should be added
277 */
278 public static void createBiDirLinkDescription(DeviceId localDevId,
279 Port localPort,
280 DeviceId remoteDevId,
281 Port remotePort,
282 Set<LinkDescription> descs) {
283
284 ConnectPoint local = new ConnectPoint(localDevId, localPort.number());
285 ConnectPoint remote = new ConnectPoint(remoteDevId, remotePort.number());
286 DefaultAnnotations annotations = DefaultAnnotations.builder()
287 .set("layer", "IP")
288 .build();
289 descs.add(new DefaultLinkDescription(
290 local, remote, Link.Type.INDIRECT, false, annotations));
291 descs.add(new DefaultLinkDescription(
292 remote, local, Link.Type.INDIRECT, false, annotations));
293 }
294
295 /**
296 * Parses neighbours discovery information and returns a list of
297 * link abstractions.
298 *
299 * @param info interface configuration
300 * @return set of link abstractions
301 */
302 public static Set<LinkAbstraction> parseJuniperLldp(HierarchicalConfiguration info) {
303 Set<LinkAbstraction> neighbour = new HashSet<>();
304 List<HierarchicalConfiguration> subtrees =
305 info.configurationsAt(LLDP_NBR_INFO);
306 for (HierarchicalConfiguration neighborsInfo : subtrees) {
307 List<HierarchicalConfiguration> neighbors =
308 neighborsInfo.configurationsAt(LLDP_NBR_INFO);
309 for (HierarchicalConfiguration neighbor : neighbors) {
310 String localPortName = neighbor.getString(LLDP_LO_PORT);
311 MacAddress mac = MacAddress.valueOf(
312 neighbor.getString(LLDP_REM_CHASS));
313 int remotePortIndex =
314 neighbor.getInt(LLDP_REM_PORT);
315 LinkAbstraction link = new LinkAbstraction(
316 localPortName,
317 mac.toLong(),
318 remotePortIndex);
319 neighbour.add(link);
320 }
321 }
322 return neighbour;
323 }
324
325 /**
326 * Device representation of the adjacency at the IP Layer.
327 */
328 protected static final class LinkAbstraction {
329 protected String localPortName;
330 protected ChassisId remoteChassisId;
331 protected int remotePortIndex;
332
333 protected LinkAbstraction(String pName, long chassisId, int pIndex) {
334 this.localPortName = pName;
335 this.remoteChassisId = new ChassisId(chassisId);
336 this.remotePortIndex = pIndex;
337 }
338 }
339}