blob: 89ec2e3591a1c518e6aa51c6a27fc0921fa8bc95 [file] [log] [blame]
Michele Santuari21c14012016-11-14 13:31:33 +01001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Michele Santuari21c14012016-11-14 13:31:33 +01003 *
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
Michele Santuari21c14012016-11-14 13:31:33 +010019import org.apache.commons.configuration.HierarchicalConfiguration;
Michele Santuarice256492017-06-23 14:44:01 +020020import org.apache.commons.lang.StringUtils;
Michele Santuari21c14012016-11-14 13:31:33 +010021import org.onlab.packet.ChassisId;
Michele Santuarice256492017-06-23 14:44:01 +020022import org.onlab.packet.Ip4Address;
23import org.onlab.packet.Ip4Prefix;
Michele Santuari21c14012016-11-14 13:31:33 +010024import org.onlab.packet.MacAddress;
25import org.onosproject.net.AnnotationKeys;
26import org.onosproject.net.ConnectPoint;
27import org.onosproject.net.DefaultAnnotations;
Yuta HIGUCHIebff1b52017-04-21 20:41:42 -070028import org.onosproject.net.DefaultAnnotations.Builder;
Michele Santuari21c14012016-11-14 13:31:33 +010029import org.onosproject.net.DeviceId;
30import org.onosproject.net.Link;
31import org.onosproject.net.Port;
32import org.onosproject.net.PortNumber;
Yuta HIGUCHIebff1b52017-04-21 20:41:42 -070033import org.onosproject.net.Port.Type;
Michele Santuari21c14012016-11-14 13:31:33 +010034import org.onosproject.net.device.DefaultDeviceDescription;
35import org.onosproject.net.device.DefaultPortDescription;
36import org.onosproject.net.device.DeviceDescription;
37import org.onosproject.net.device.PortDescription;
38import org.onosproject.net.link.DefaultLinkDescription;
39import org.onosproject.net.link.LinkDescription;
Yuta HIGUCHI0184a7b2017-03-31 13:13:58 -070040import org.slf4j.Logger;
Michele Santuari21c14012016-11-14 13:31:33 +010041
Yuta HIGUCHIebff1b52017-04-21 20:41:42 -070042import com.google.common.base.Strings;
43
44import java.util.ArrayList;
Michele Santuarice256492017-06-23 14:44:01 +020045import java.util.Collection;
Michele Santuari21c14012016-11-14 13:31:33 +010046import java.util.HashSet;
47import java.util.List;
Michele Santuarice256492017-06-23 14:44:01 +020048import java.util.Optional;
Michele Santuari21c14012016-11-14 13:31:33 +010049import java.util.Set;
50import java.util.regex.Matcher;
51import java.util.regex.Pattern;
52
Michele Santuarice256492017-06-23 14:44:01 +020053import static org.onosproject.drivers.juniper.StaticRoute.DEFAULT_METRIC_STATIC_ROUTE;
54import static org.onosproject.drivers.juniper.StaticRoute.toFlowRulePriority;
Michele Santuari21c14012016-11-14 13:31:33 +010055import static org.onosproject.net.Device.Type.ROUTER;
Michele Santuari21c14012016-11-14 13:31:33 +010056import static org.onosproject.net.PortNumber.portNumber;
Yuta HIGUCHI0184a7b2017-03-31 13:13:58 -070057import static org.slf4j.LoggerFactory.getLogger;
Michele Santuari21c14012016-11-14 13:31:33 +010058
Yuta HIGUCHIebff1b52017-04-21 20:41:42 -070059// Ref: Junos YANG:
60// https://github.com/Juniper/yang
Michele Santuarice256492017-06-23 14:44:01 +020061
Michele Santuari21c14012016-11-14 13:31:33 +010062/**
63 * Utility class for Netconf XML for Juniper.
64 * Tested with MX240 junos 14.2
65 */
66public final class JuniperUtils {
67
Yuta HIGUCHI0184a7b2017-03-31 13:13:58 -070068 private static final Logger log = getLogger(JuniperUtils.class);
69
Michele Santuari21c14012016-11-14 13:31:33 +010070 public static final String FAILED_CFG = "Failed to retrieve configuration.";
71
72 private static final String RPC_TAG_NETCONF_BASE = "<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">";
73 private static final String RPC_CLOSE_TAG = "</rpc>";
74
75 //requests
76 public static final String REQ_LLDP_NBR_INFO = "<get-lldp-neighbors-information/>";
77 public static final String REQ_SYS_INFO = "<get-system-information/>";
78 public static final String REQ_MAC_ADD_INFO = "<get-chassis-mac-addresses/>";
79 public static final String REQ_IF_INFO = "<get-interface-information/>";
80
81 //helper strings for parsing
Michele Santuarif5945372017-01-19 16:39:21 +010082 private static final String LLDP_LIST_NBR_INFO = "lldp-neighbors-information";
83 private static final String LLDP_NBR_INFO = "lldp-neighbor-information";
Michele Santuari21c14012016-11-14 13:31:33 +010084 private static final String SYS_INFO = "system-information";
85 private static final String HW_MODEL = "hardware-model";
86 private static final String OS_NAME = "os-name";
87 private static final String OS_VER = "os-version";
88 private static final String SER_NUM = "serial-number";
89 private static final String IF_INFO = "interface-information";
90 private static final String IF_PHY = "physical-interface";
Yuta HIGUCHIebff1b52017-04-21 20:41:42 -070091
Michele Santuari21c14012016-11-14 13:31:33 +010092 private static final String IF_TYPE = "if-type";
93 private static final String SPEED = "speed";
Michele Santuari21c14012016-11-14 13:31:33 +010094 private static final String NAME = "name";
Yuta HIGUCHIebff1b52017-04-21 20:41:42 -070095
96 // seems to be unique index within device
Michele Santuari21c14012016-11-14 13:31:33 +010097 private static final String SNMP_INDEX = "snmp-index";
Yuta HIGUCHIebff1b52017-04-21 20:41:42 -070098
Michele Santuari21c14012016-11-14 13:31:33 +010099 private static final String LLDP_LO_PORT = "lldp-local-port-id";
100 private static final String LLDP_REM_CHASS = "lldp-remote-chassis-id";
101 private static final String LLDP_REM_PORT = "lldp-remote-port-id";
102 private static final String REGEX_ADD =
103 ".*Private base address\\s*([:,0-9,a-f,A-F]*).*";
104 private static final Pattern ADD_PATTERN =
105 Pattern.compile(REGEX_ADD, Pattern.DOTALL);
106
Michele Santuarice256492017-06-23 14:44:01 +0200107 public static final String PROTOCOL_NAME = "protocol-name";
108
Michele Santuari21c14012016-11-14 13:31:33 +0100109 private static final String JUNIPER = "JUNIPER";
110 private static final String UNKNOWN = "UNKNOWN";
Yuta HIGUCHIebff1b52017-04-21 20:41:42 -0700111
112 /**
113 * Annotation key for interface type.
114 */
115 static final String AK_IF_TYPE = "ifType";
116
117 /**
118 * Annotation key for Logical link-layer encapsulation.
119 */
120 static final String AK_ENCAPSULATION = "encapsulation";
121
122 /**
123 * Annotation key for interface description.
124 */
125 static final String AK_DESCRIPTION = "description";
126
127 /**
128 * Annotation key for interface admin status. "up"/"down"
129 */
130 static final String AK_ADMIN_STATUS = "adminStatus";
131
132 /**
133 * Annotation key for interface operational status. "up"/"down"
134 */
135 static final String AK_OPER_STATUS = "operStatus";
136
137 /**
138 * Annotation key for logical-interfaces parent physical interface name.
139 */
140 static final String AK_PHYSICAL_PORT_NAME = "physicalPortName";
141
142
143 private static final String NUMERIC_SPEED_REGEXP = "(\\d+)([GM])bps";
144
145 /**
146 * {@value #NUMERIC_SPEED_REGEXP} as {@link Pattern}.
147 * Case insensitive
148 */
149 private static final Pattern SPEED_PATTERN =
150 Pattern.compile(NUMERIC_SPEED_REGEXP, Pattern.CASE_INSENSITIVE);
151
152 /**
153 * Default port speed {@value} Mbps.
154 */
Michele Santuari21c14012016-11-14 13:31:33 +0100155 private static final long DEFAULT_PORT_SPEED = 1000;
156
157
158 private JuniperUtils() {
159 //not called, preventing any allocation
160 }
161
162 /**
163 * Helper method to build a XML schema given a request.
164 *
165 * @param request a tag element of the XML schema
166 * @return string containing the XML schema
167 */
168 public static String requestBuilder(String request) {
169 return RPC_TAG_NETCONF_BASE +
170 request + RPC_CLOSE_TAG;
171 }
172
173 /**
Michele Santuarice256492017-06-23 14:44:01 +0200174 * Helper method to commit a config.
175 *
176 * @return string contains the result of the commit
177 */
178 public static String commitBuilder() {
179 return RPC_TAG_NETCONF_BASE +
180 "<commit/>" + RPC_CLOSE_TAG;
181 }
182
183 /**
184 * Helper method to build the schema for returning to a previously
185 * committed configuration.
186 *
187 * @param versionToReturn Configuration to return to. The range of values is from 0 through 49.
188 * The most recently saved configuration is number 0,
189 * and the oldest saved configuration is number 49.
190 * @return string containing the XML schema
191 */
192 public static String rollbackBuilder(int versionToReturn) {
193 return RPC_TAG_NETCONF_BASE +
194 "<get-rollback-information>" +
195 "<rollback>" + versionToReturn + "</rollback>" +
196 "</get-rollback-information>" +
197 RPC_CLOSE_TAG;
198 }
199
200
201 /**
202 * Helper method to build an XML schema to configure a static route
203 * given a {@link StaticRoute}.
204 *
205 * @param staticRoute the static route to be configured
206 * @return string contains the result of the configuration
207 */
208 public static String routeAddBuilder(StaticRoute staticRoute) {
209 StringBuilder rpc = new StringBuilder("<configuration>\n");
210 rpc.append("<routing-options>\n");
211 rpc.append("<static>\n");
212 rpc.append("<route>\n");
213 rpc.append("<destination>" + staticRoute.ipv4Dst().toString() + "</destination>\n");
214 rpc.append("<next-hop>" + staticRoute.nextHop() + "</next-hop>\n");
215
216 if (staticRoute.getMetric() != DEFAULT_METRIC_STATIC_ROUTE) {
217 rpc.append("<metric>" + staticRoute.getMetric() + "</metric>");
218 }
219
220 rpc.append("</route>\n");
221 rpc.append("</static>\n");
222 rpc.append("</routing-options>\n");
223 rpc.append("</configuration>\n");
224
225 return rpc.toString();
226 }
227
228 /**
229 * Helper method to build a XML schema to delete a static route
230 * given a {@link StaticRoute}.
231 * @param staticRoute the static route to be deleted
232 * @return string contains the result of the configuratio
233 */
234 public static String routeDeleteBuilder(StaticRoute staticRoute) {
235 return "<configuration>\n" +
236 "<routing-options>\n" +
237 "<static>\n" +
238 "<route operation=\"delete\">\n" +
239 "<name>" + staticRoute.ipv4Dst().toString() + "</name>\n" +
240 "</route>\n" +
241 "</static>\n" +
242 "</routing-options>\n" +
243 "</configuration>\n";
244 }
245
246
247 /**
Michele Santuari21c14012016-11-14 13:31:33 +0100248 * Parses device configuration and returns the device description.
249 *
250 * @param deviceId the id of the device
251 * @param sysInfoCfg system configuration
252 * @param chassisText chassis string
253 * @return device description
254 */
255 public static DeviceDescription parseJuniperDescription(DeviceId deviceId,
256 HierarchicalConfiguration sysInfoCfg,
257 String chassisText) {
258 HierarchicalConfiguration info = sysInfoCfg.configurationAt(SYS_INFO);
259
260 String hw = info.getString(HW_MODEL) == null ? UNKNOWN : info.getString(HW_MODEL);
261 String sw = UNKNOWN;
262 if (info.getString(OS_NAME) != null || info.getString(OS_VER) != null) {
263 sw = info.getString(OS_NAME) + " " + info.getString(OS_VER);
264 }
265 String serial = info.getString(SER_NUM) == null ? UNKNOWN : info.getString(SER_NUM);
266
267 Matcher matcher = ADD_PATTERN.matcher(chassisText);
268 if (matcher.lookingAt()) {
269 String chassis = matcher.group(1);
270 MacAddress chassisMac = MacAddress.valueOf(chassis);
271 return new DefaultDeviceDescription(deviceId.uri(), ROUTER,
272 JUNIPER, hw, sw, serial,
273 new ChassisId(chassisMac.toLong()),
274 DefaultAnnotations.EMPTY);
275 }
276 return new DefaultDeviceDescription(deviceId.uri(), ROUTER,
277 JUNIPER, hw, sw, serial,
278 null, DefaultAnnotations.EMPTY);
279 }
280
281 /**
282 * Parses device ports configuration and returns a list of
283 * port description.
284 *
285 * @param cfg interface configuration
286 * @return list of interface descriptions of the device
287 */
288 public static List<PortDescription> parseJuniperPorts(HierarchicalConfiguration cfg) {
289 //This methods ignores some internal ports
290
Yuta HIGUCHIebff1b52017-04-21 20:41:42 -0700291 List<PortDescription> portDescriptions = new ArrayList<>();
Michele Santuari21c14012016-11-14 13:31:33 +0100292 List<HierarchicalConfiguration> subtrees =
293 cfg.configurationsAt(IF_INFO);
294 for (HierarchicalConfiguration interfInfo : subtrees) {
295 List<HierarchicalConfiguration> interfaceTree =
296 interfInfo.configurationsAt(IF_PHY);
Yuta HIGUCHIebff1b52017-04-21 20:41:42 -0700297 for (HierarchicalConfiguration phyIntf : interfaceTree) {
298 if (phyIntf == null) {
299 continue;
Michele Santuari21c14012016-11-14 13:31:33 +0100300 }
Yuta HIGUCHIebff1b52017-04-21 20:41:42 -0700301 // parse physical Interface
302 parsePhysicalInterface(portDescriptions, phyIntf);
Michele Santuari21c14012016-11-14 13:31:33 +0100303 }
304 }
305 return portDescriptions;
306 }
307
Yuta HIGUCHIebff1b52017-04-21 20:41:42 -0700308 /**
309 * Parses {@literal physical-interface} tree.
310 *
311 * @param portDescriptions list to populate Ports found parsing configuration
312 * @param phyIntf physical-interface
313 */
314 private static void parsePhysicalInterface(List<PortDescription> portDescriptions,
315 HierarchicalConfiguration phyIntf) {
316 Builder annotations = DefaultAnnotations.builder();
317 PortNumber portNumber = portNumber(phyIntf.getString(SNMP_INDEX));
318 String phyPortName = phyIntf.getString(NAME);
319 if (portNumber == null) {
320 log.debug("Skipping physical-interface {}, no PortNumer",
321 phyPortName);
322 log.trace(" {}", phyIntf);
323 return;
Michele Santuari21c14012016-11-14 13:31:33 +0100324 }
325
Yuta HIGUCHIebff1b52017-04-21 20:41:42 -0700326 setIfNonNull(annotations,
327 AnnotationKeys.PORT_NAME,
328 phyPortName);
Michele Santuari21c14012016-11-14 13:31:33 +0100329
Yuta HIGUCHIebff1b52017-04-21 20:41:42 -0700330 setIfNonNull(annotations,
331 AnnotationKeys.PORT_MAC,
332 phyIntf.getString("current-physical-address"));
Michele Santuari21c14012016-11-14 13:31:33 +0100333
Yuta HIGUCHIebff1b52017-04-21 20:41:42 -0700334 setIfNonNull(annotations,
335 AK_IF_TYPE,
336 phyIntf.getString(IF_TYPE));
Michele Santuari21c14012016-11-14 13:31:33 +0100337
Yuta HIGUCHIebff1b52017-04-21 20:41:42 -0700338 setIfNonNull(annotations,
339 AK_DESCRIPTION,
340 phyIntf.getString("description"));
Michele Santuari21c14012016-11-14 13:31:33 +0100341
Michele Santuari0b832652017-06-05 16:59:11 +0200342 boolean opUp = phyIntf.getString("oper-status", "down").equals("up");
343 annotations.set(AK_OPER_STATUS, toUpDown(opUp));
Michele Santuari21c14012016-11-14 13:31:33 +0100344
Michele Santuari0b832652017-06-05 16:59:11 +0200345 boolean admUp = phyIntf.getString("admin-status", "down").equals("up");
346 annotations.set(AK_ADMIN_STATUS, toUpDown(admUp));
Michele Santuari21c14012016-11-14 13:31:33 +0100347
Yuta HIGUCHIebff1b52017-04-21 20:41:42 -0700348 long portSpeed = toMbps(phyIntf.getString(SPEED));
Michele Santuari21c14012016-11-14 13:31:33 +0100349
Yuta HIGUCHIebff1b52017-04-21 20:41:42 -0700350 portDescriptions.add(new DefaultPortDescription(portNumber,
351 admUp & opUp,
352 Type.COPPER,
353 portSpeed,
354 annotations.build()));
Michele Santuari21c14012016-11-14 13:31:33 +0100355
Yuta HIGUCHIebff1b52017-04-21 20:41:42 -0700356 // parse each logical Interface
357 for (HierarchicalConfiguration logIntf : phyIntf.configurationsAt("logical-interface")) {
358 if (logIntf == null) {
359 continue;
360 }
361 PortNumber lPortNumber = safePortNumber(logIntf.getString(SNMP_INDEX));
362 if (lPortNumber == null) {
363 log.debug("Skipping logical-interface {} under {}, no PortNumer",
364 logIntf.getString(NAME), phyPortName);
365 log.trace(" {}", logIntf);
366 continue;
367 }
368
369 Builder lannotations = DefaultAnnotations.builder();
370 setIfNonNull(lannotations,
371 AnnotationKeys.PORT_NAME,
372 logIntf.getString(NAME));
373 setIfNonNull(lannotations,
374 AK_PHYSICAL_PORT_NAME,
375 phyPortName);
376
377 String afName = logIntf.getString("address-family.address-family-name");
378 String address = logIntf.getString("address-family.interface-address.ifa-local");
379 if (afName != null && address != null) {
380 // e.g., inet : IPV4, inet6 : IPV6
381 setIfNonNull(lannotations, afName, address);
382 }
383
384 // preserving former behavior
385 setIfNonNull(lannotations,
386 "ip",
387 logIntf.getString("address-family.interface-address.ifa-local"));
388
389 setIfNonNull(lannotations,
390 AK_ENCAPSULATION, logIntf.getString("encapsulation"));
391
392 // TODO confirm if this is correct.
393 // Looking at sample data,
394 // it seemed all logical loop-back interfaces were down
395 boolean lEnabled = logIntf.getString("if-config-flags.iff-up") != null;
396
397 portDescriptions.add(new DefaultPortDescription(lPortNumber,
398 admUp & opUp & lEnabled,
399 Type.COPPER,
400 portSpeed,
401 lannotations.build()));
Michele Santuari21c14012016-11-14 13:31:33 +0100402 }
Michele Santuari21c14012016-11-14 13:31:33 +0100403 }
404
Yuta HIGUCHIebff1b52017-04-21 20:41:42 -0700405 /**
406 * Port status as "up"/"down".
407 *
408 * @param portStatus port status
409 * @return "up" if {@code portStats} is {@literal true}, "down" otherwise
410 */
411 static String toUpDown(boolean portStatus) {
412 return portStatus ? "up" : "down";
413 }
414
415 /**
416 * Translate interface {@literal speed} value as Mbps value.
417 *
418 * Note: {@literal Unlimited} and unrecognizable string will be treated as
419 * {@value #DEFAULT_PORT_SPEED} Mbps.
420 *
421 * @param speed in String
422 * @return Mbps
423 */
424 static long toMbps(String speed) {
425 String s = Strings.nullToEmpty(speed).trim().toLowerCase();
426 Matcher matcher = SPEED_PATTERN.matcher(s);
427 if (matcher.matches()) {
428 // numeric
429 int n = Integer.parseInt(matcher.group(1));
430 String unit = matcher.group(2);
431 if ("m".equalsIgnoreCase(unit)) {
432 // Mbps
433 return n;
434 } else {
435 // assume Gbps
436 return 1000 * n;
437 }
Michele Santuari21c14012016-11-14 13:31:33 +0100438 }
Yuta HIGUCHIebff1b52017-04-21 20:41:42 -0700439 log.trace("Treating unknown speed value {} as default", speed);
440 // Unlimited or unrecognizable
441 return DEFAULT_PORT_SPEED;
442 }
443
444 /**
445 * Sets annotation entry if {@literal value} was not {@literal null}.
446 *
447 * @param builder Annotation Builder
448 * @param key Annotation key
449 * @param value Annotation value (can be {@literal null})
450 */
451 static void setIfNonNull(Builder builder, String key, String value) {
452 if (value != null) {
453 builder.set(key, value.trim());
454 }
455 }
456
457 /**
458 * Creates PortNumber instance from String.
459 *
460 * Instead for throwing Exception, it will return null on format error.
461 *
462 * @param s port number as string
463 * @return PortNumber instance or null on error
464 */
465 static PortNumber safePortNumber(String s) {
466 try {
467 return portNumber(s);
468 } catch (RuntimeException e) {
469 log.trace("Failed parsing PortNumber {}", s, e);
470 }
471 return null;
Michele Santuari21c14012016-11-14 13:31:33 +0100472 }
473
474 /**
475 * Create two LinkDescriptions corresponding to the bidirectional links.
476 *
477 * @param localDevId the identity of the local device
478 * @param localPort the port of the local device
479 * @param remoteDevId the identity of the remote device
480 * @param remotePort the port of the remote device
481 * @param descs the collection to which the link descriptions
482 * should be added
483 */
484 public static void createBiDirLinkDescription(DeviceId localDevId,
485 Port localPort,
486 DeviceId remoteDevId,
487 Port remotePort,
488 Set<LinkDescription> descs) {
489
490 ConnectPoint local = new ConnectPoint(localDevId, localPort.number());
491 ConnectPoint remote = new ConnectPoint(remoteDevId, remotePort.number());
492 DefaultAnnotations annotations = DefaultAnnotations.builder()
493 .set("layer", "IP")
494 .build();
495 descs.add(new DefaultLinkDescription(
496 local, remote, Link.Type.INDIRECT, false, annotations));
497 descs.add(new DefaultLinkDescription(
498 remote, local, Link.Type.INDIRECT, false, annotations));
499 }
500
501 /**
502 * Parses neighbours discovery information and returns a list of
503 * link abstractions.
504 *
505 * @param info interface configuration
506 * @return set of link abstractions
507 */
508 public static Set<LinkAbstraction> parseJuniperLldp(HierarchicalConfiguration info) {
509 Set<LinkAbstraction> neighbour = new HashSet<>();
510 List<HierarchicalConfiguration> subtrees =
Michele Santuarif5945372017-01-19 16:39:21 +0100511 info.configurationsAt(LLDP_LIST_NBR_INFO);
Michele Santuari21c14012016-11-14 13:31:33 +0100512 for (HierarchicalConfiguration neighborsInfo : subtrees) {
513 List<HierarchicalConfiguration> neighbors =
514 neighborsInfo.configurationsAt(LLDP_NBR_INFO);
515 for (HierarchicalConfiguration neighbor : neighbors) {
516 String localPortName = neighbor.getString(LLDP_LO_PORT);
517 MacAddress mac = MacAddress.valueOf(
518 neighbor.getString(LLDP_REM_CHASS));
Michele Santuaria85bd3b2017-05-05 12:57:40 +0200519 long remotePortIndex =
Michele Santuari21c14012016-11-14 13:31:33 +0100520 neighbor.getInt(LLDP_REM_PORT);
521 LinkAbstraction link = new LinkAbstraction(
522 localPortName,
523 mac.toLong(),
524 remotePortIndex);
525 neighbour.add(link);
526 }
527 }
528 return neighbour;
529 }
530
531 /**
532 * Device representation of the adjacency at the IP Layer.
533 */
534 protected static final class LinkAbstraction {
535 protected String localPortName;
536 protected ChassisId remoteChassisId;
Michele Santuaria85bd3b2017-05-05 12:57:40 +0200537 protected long remotePortIndex;
Michele Santuari21c14012016-11-14 13:31:33 +0100538
Michele Santuaria85bd3b2017-05-05 12:57:40 +0200539 protected LinkAbstraction(String pName, long chassisId, long pIndex) {
Michele Santuari21c14012016-11-14 13:31:33 +0100540 this.localPortName = pName;
541 this.remoteChassisId = new ChassisId(chassisId);
542 this.remotePortIndex = pIndex;
543 }
544 }
Michele Santuarice256492017-06-23 14:44:01 +0200545
546 protected enum OperationType {
547 ADD,
548 REMOVE,
549 }
550
551 /**
552 * Parses {@literal route-information} tree.
553 * This implementation supports only static routes.
554 *
555 * @param cfg route-information
556 * @return a collection of static routes
557 */
558 public static Collection<StaticRoute> parseRoutingTable(HierarchicalConfiguration cfg) {
559
560 Collection<StaticRoute> staticRoutes = new HashSet<>();
561 HierarchicalConfiguration routeInfo =
562 cfg.configurationAt("route-information");
563 List<HierarchicalConfiguration> routeTables = routeInfo.configurationsAt("route-table");
564 for (HierarchicalConfiguration routeTable : routeTables) {
565 List<HierarchicalConfiguration> routes = routeTable.configurationsAt("rt");
566 for (HierarchicalConfiguration route : routes) {
567 if (route != null) {
568 HierarchicalConfiguration rtEntry = route.configurationAt("rt-entry");
569 if (rtEntry.getString(PROTOCOL_NAME) != null &&
570 rtEntry.getString(PROTOCOL_NAME).contains("Static")) {
571 parseStaticRoute(rtEntry,
572 route.getString("rt-destination"),
573 rtEntry.getString("metric"))
574 .ifPresent(x -> staticRoutes.add(x));
575
576 }
577 }
578 }
579 }
580 return staticRoutes;
581 }
582
583 /**
584 * Parse the {@literal rt-entry} for static routes.
585 *
586 * @param rtEntry rt-entry filtered by {@literal protocol-name} equals to Static
587 * @param destination rt-destination
588 * @return optional of static route
589 */
590 private static Optional<StaticRoute> parseStaticRoute(HierarchicalConfiguration rtEntry,
591 String destination, String metric) {
592
593 Ip4Prefix ipDst = Ip4Prefix.valueOf(destination);
594
595 HierarchicalConfiguration nextHop = rtEntry.configurationAt("nh");
596 String to = nextHop.getString("to");
597 if (StringUtils.isEmpty(to)) {
598 return Optional.empty();
599 }
600 Ip4Address nextHopIp = Ip4Address.valueOf(to);
601
602 if (metric == null) {
603 return Optional.of(new StaticRoute(ipDst, nextHopIp, false));
604 } else {
605 return Optional.of(new StaticRoute(ipDst, nextHopIp, false,
606 toFlowRulePriority(Integer.parseInt(metric))));
607 }
608 }
Michele Santuari21c14012016-11-14 13:31:33 +0100609}