blob: 76f5f3b7ca6ebe449008c92d66271452cd1015a8 [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
Michele Santuarif5945372017-01-19 16:39:21 +010067 private static final String LLDP_LIST_NBR_INFO = "lldp-neighbors-information";
68 private static final String LLDP_NBR_INFO = "lldp-neighbor-information";
Michele Santuari21c14012016-11-14 13:31:33 +010069 private static final String SYS_INFO = "system-information";
70 private static final String HW_MODEL = "hardware-model";
71 private static final String OS_NAME = "os-name";
72 private static final String OS_VER = "os-version";
73 private static final String SER_NUM = "serial-number";
74 private static final String IF_INFO = "interface-information";
75 private static final String IF_PHY = "physical-interface";
76 private static final String IF_TYPE = "if-type";
77 private static final String SPEED = "speed";
78 private static final String ETH = "Ethernet";
79 private static final String MBPS = "mbps";
80 private static final String NAME = "name";
81 private static final String IF_LO_ENCAP = "logical-interface.encapsulation";
82 private static final String IF_LO_NAME = "logical-interface.name";
83 private static final String IF_LO_ADD =
84 "logical-interface.address-family.interface-address.ifa-local";
85 private static final String LO_INDEX = "local-index";
86 private static final String STATUS = "admin-status";
87 private static final String SNMP_INDEX = "snmp-index";
88 private static final String IF_LO_INDEX = "logical-interface.local-index";
89 private static final String IF_LO_STATUS =
90 "logical-interface.if-config-flags.iff-up";
91 private static final String LLDP_LO_PORT = "lldp-local-port-id";
92 private static final String LLDP_REM_CHASS = "lldp-remote-chassis-id";
93 private static final String LLDP_REM_PORT = "lldp-remote-port-id";
94 private static final String REGEX_ADD =
95 ".*Private base address\\s*([:,0-9,a-f,A-F]*).*";
96 private static final Pattern ADD_PATTERN =
97 Pattern.compile(REGEX_ADD, Pattern.DOTALL);
98
99 private static final String JUNIPER = "JUNIPER";
100 private static final String UNKNOWN = "UNKNOWN";
101 private static final long DEFAULT_PORT_SPEED = 1000;
102
103
104 private JuniperUtils() {
105 //not called, preventing any allocation
106 }
107
108 /**
109 * Helper method to build a XML schema given a request.
110 *
111 * @param request a tag element of the XML schema
112 * @return string containing the XML schema
113 */
114 public static String requestBuilder(String request) {
115 return RPC_TAG_NETCONF_BASE +
116 request + RPC_CLOSE_TAG;
117 }
118
119 /**
120 * Parses device configuration and returns the device description.
121 *
122 * @param deviceId the id of the device
123 * @param sysInfoCfg system configuration
124 * @param chassisText chassis string
125 * @return device description
126 */
127 public static DeviceDescription parseJuniperDescription(DeviceId deviceId,
128 HierarchicalConfiguration sysInfoCfg,
129 String chassisText) {
130 HierarchicalConfiguration info = sysInfoCfg.configurationAt(SYS_INFO);
131
132 String hw = info.getString(HW_MODEL) == null ? UNKNOWN : info.getString(HW_MODEL);
133 String sw = UNKNOWN;
134 if (info.getString(OS_NAME) != null || info.getString(OS_VER) != null) {
135 sw = info.getString(OS_NAME) + " " + info.getString(OS_VER);
136 }
137 String serial = info.getString(SER_NUM) == null ? UNKNOWN : info.getString(SER_NUM);
138
139 Matcher matcher = ADD_PATTERN.matcher(chassisText);
140 if (matcher.lookingAt()) {
141 String chassis = matcher.group(1);
142 MacAddress chassisMac = MacAddress.valueOf(chassis);
143 return new DefaultDeviceDescription(deviceId.uri(), ROUTER,
144 JUNIPER, hw, sw, serial,
145 new ChassisId(chassisMac.toLong()),
146 DefaultAnnotations.EMPTY);
147 }
148 return new DefaultDeviceDescription(deviceId.uri(), ROUTER,
149 JUNIPER, hw, sw, serial,
150 null, DefaultAnnotations.EMPTY);
151 }
152
153 /**
154 * Parses device ports configuration and returns a list of
155 * port description.
156 *
157 * @param cfg interface configuration
158 * @return list of interface descriptions of the device
159 */
160 public static List<PortDescription> parseJuniperPorts(HierarchicalConfiguration cfg) {
161 //This methods ignores some internal ports
162
163 List<PortDescription> portDescriptions = Lists.newArrayList();
164 List<HierarchicalConfiguration> subtrees =
165 cfg.configurationsAt(IF_INFO);
166 for (HierarchicalConfiguration interfInfo : subtrees) {
167 List<HierarchicalConfiguration> interfaceTree =
168 interfInfo.configurationsAt(IF_PHY);
169 for (HierarchicalConfiguration interf : interfaceTree) {
170 if (interf != null) {
171 if (interf.getString(IF_TYPE) != null &&
172 interf.getString(SPEED) != null) {
173 if (interf.getString(IF_TYPE).contains(ETH) &&
174 interf.getString(SPEED).contains(MBPS)) {
175 portDescriptions.add(parseDefaultPort(interf));
176 }
177 } else if (interf.getString(IF_LO_ENCAP) != null &&
178 !interf.getString(NAME).contains("pfe") &&
179 interf.getString(IF_LO_ENCAP).contains("ENET2")) {
180 portDescriptions.add(parseLogicalPort(interf));
181 } else if (interf.getString(NAME).contains("lo")) {
182 portDescriptions.add(parseLoopback(interf));
183 }
184 }
185 }
186 }
187 return portDescriptions;
188 }
189
190 private static PortDescription parseLoopback(HierarchicalConfiguration cfg) {
191 String name = cfg.getString(IF_LO_NAME).trim();
192 PortNumber portNumber = portNumber(name.replace("lo0.", ""));
193
194 Builder annotationsBuilder = DefaultAnnotations.builder()
195 .set(AnnotationKeys.PORT_NAME, name);
196 String ip = cfg.getString(IF_LO_ADD);
197 if (ip != null) {
198 annotationsBuilder.set("ip", ip);
199 }
200
201 return new DefaultPortDescription(portNumber,
202 true,
203 COPPER,
204 DEFAULT_PORT_SPEED,
205 annotationsBuilder.build());
206 }
207
208 private static DefaultPortDescription parseDefaultPort(HierarchicalConfiguration cfg) {
209 PortNumber portNumber = portNumber(cfg.getString(LO_INDEX));
Jon Halla3fcf672017-03-28 16:53:22 -0700210 boolean enabled = "up".equals(cfg.getString(STATUS));
Michele Santuari21c14012016-11-14 13:31:33 +0100211 int speed = parseInt(cfg.getString(SPEED).replaceAll(MBPS, ""));
212
213
214 Builder annotationsBuilder = DefaultAnnotations.builder()
215 .set(AnnotationKeys.PORT_NAME, cfg.getString(NAME).trim());
216 setIpIfPresent(cfg, annotationsBuilder);
217
218 return new DefaultPortDescription(portNumber,
219 enabled,
220 COPPER,
221 speed,
222 annotationsBuilder.build());
223 }
224
225 private static DefaultPortDescription parseLogicalPort(HierarchicalConfiguration cfg) {
226
227 String name = cfg.getString(NAME).trim();
228 String index = cfg.getString(SNMP_INDEX).trim();
229 Builder annotationsBuilder = DefaultAnnotations.builder()
230 .set(AnnotationKeys.PORT_NAME, name)
231 .set("index", index);
232 setIpIfPresent(cfg, annotationsBuilder);
233
Michele Santuarif5945372017-01-19 16:39:21 +0100234 PortNumber portNumber = PortNumber.portNumber(index);
Michele Santuari21c14012016-11-14 13:31:33 +0100235
236 boolean enabled = false;
237 if (cfg.getString(IF_LO_STATUS) != null) {
238 enabled = true;
239 }
240 //FIXME: port speed should be exposed
241 return new DefaultPortDescription(
242 portNumber,
243 enabled,
244 COPPER,
245 DEFAULT_PORT_SPEED,
246 annotationsBuilder.build());
247 }
248
Michele Santuari21c14012016-11-14 13:31:33 +0100249 private static void setIpIfPresent(HierarchicalConfiguration cfg,
250 Builder annotationsBuilder) {
251 String ip = cfg.getString(IF_LO_ADD);
252 if (ip != null) {
253 annotationsBuilder.set("ip", ip);
254 }
255 }
256
257 /**
258 * Create two LinkDescriptions corresponding to the bidirectional links.
259 *
260 * @param localDevId the identity of the local device
261 * @param localPort the port of the local device
262 * @param remoteDevId the identity of the remote device
263 * @param remotePort the port of the remote device
264 * @param descs the collection to which the link descriptions
265 * should be added
266 */
267 public static void createBiDirLinkDescription(DeviceId localDevId,
268 Port localPort,
269 DeviceId remoteDevId,
270 Port remotePort,
271 Set<LinkDescription> descs) {
272
273 ConnectPoint local = new ConnectPoint(localDevId, localPort.number());
274 ConnectPoint remote = new ConnectPoint(remoteDevId, remotePort.number());
275 DefaultAnnotations annotations = DefaultAnnotations.builder()
276 .set("layer", "IP")
277 .build();
278 descs.add(new DefaultLinkDescription(
279 local, remote, Link.Type.INDIRECT, false, annotations));
280 descs.add(new DefaultLinkDescription(
281 remote, local, Link.Type.INDIRECT, false, annotations));
282 }
283
284 /**
285 * Parses neighbours discovery information and returns a list of
286 * link abstractions.
287 *
288 * @param info interface configuration
289 * @return set of link abstractions
290 */
291 public static Set<LinkAbstraction> parseJuniperLldp(HierarchicalConfiguration info) {
292 Set<LinkAbstraction> neighbour = new HashSet<>();
293 List<HierarchicalConfiguration> subtrees =
Michele Santuarif5945372017-01-19 16:39:21 +0100294 info.configurationsAt(LLDP_LIST_NBR_INFO);
Michele Santuari21c14012016-11-14 13:31:33 +0100295 for (HierarchicalConfiguration neighborsInfo : subtrees) {
296 List<HierarchicalConfiguration> neighbors =
297 neighborsInfo.configurationsAt(LLDP_NBR_INFO);
298 for (HierarchicalConfiguration neighbor : neighbors) {
299 String localPortName = neighbor.getString(LLDP_LO_PORT);
300 MacAddress mac = MacAddress.valueOf(
301 neighbor.getString(LLDP_REM_CHASS));
302 int remotePortIndex =
303 neighbor.getInt(LLDP_REM_PORT);
304 LinkAbstraction link = new LinkAbstraction(
305 localPortName,
306 mac.toLong(),
307 remotePortIndex);
308 neighbour.add(link);
309 }
310 }
311 return neighbour;
312 }
313
314 /**
315 * Device representation of the adjacency at the IP Layer.
316 */
317 protected static final class LinkAbstraction {
318 protected String localPortName;
319 protected ChassisId remoteChassisId;
320 protected int remotePortIndex;
321
322 protected LinkAbstraction(String pName, long chassisId, int pIndex) {
323 this.localPortName = pName;
324 this.remoteChassisId = new ChassisId(chassisId);
325 this.remotePortIndex = pIndex;
326 }
327 }
328}