3 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
5 * This program and the accompanying materials are made available under the
6 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
7 * and is available at http://www.eclipse.org/legal/epl-v10.html
11 * @file NodeConnector.java
13 * @brief Describe a generic network element attachment points,
14 * attached to one Node, the NodeConnector is formed by the pair
15 * (NodeConnectorType, NodeConnectorID) because each SDN technlogy can
16 * identify an attachment point on the Node in different way.
19 package org.opendaylight.controller.sal.core;
21 import java.io.Serializable;
22 import java.util.concurrent.ConcurrentHashMap;
24 import javax.xml.bind.annotation.XmlAccessType;
25 import javax.xml.bind.annotation.XmlAccessorType;
26 import javax.xml.bind.annotation.XmlAttribute;
27 import javax.xml.bind.annotation.XmlElement;
28 import javax.xml.bind.annotation.XmlRootElement;
30 import org.apache.commons.lang3.builder.EqualsBuilder;
31 import org.apache.commons.lang3.builder.HashCodeBuilder;
32 import org.apache.commons.lang3.tuple.ImmutablePair;
35 * Describe a generic network element attachment points,
36 * attached to one Node, the NodeConnector is formed by the pair
37 * (NodeConnectorType, NodeConnectorID) because each SDN technology can
38 * identify an attachment point on the Node in different way.
42 @XmlAccessorType(XmlAccessType.NONE)
43 public class NodeConnector implements Serializable {
44 private static final long serialVersionUID = 1L;
45 public static final Short SPECIALNODECONNECTORID = (short) 0;
48 * Enumerate the different types of NodeConnectors supported by the class
51 public static class NodeConnectorIDType {
53 ConcurrentHashMap<String, ImmutablePair<Class<? extends Object>, String>> compatibleType =
54 new ConcurrentHashMap<String, ImmutablePair<Class<? extends Object>, String>>();
56 * Represents the OFPP_CONTROLLER reserved port to forward a
57 * packet to the controller, this is to send data packets
58 * to the controller from the data plane triggering
61 public static String CONTROLLER = "CTRL";
63 * Represents the OFPP_ALL reserved OF port
64 * to forward to ALL the ports in the system ,
65 * should be used for flooding like mechanism to
66 * be used cautiously to avoid excessive flooding.
68 public static String ALL = "ALL";
70 * Represents the OFPP_LOCAL reserved OF port
71 * to access the local networking stack of the node
72 * of which the packet is destined. Typically used for
73 * inband OF communications channel.
75 public static String SWSTACK = "SW";
77 * Describes OFPP_Normal reserved port destination that invokes
78 * the traditional native L2/L3 HW normal forwarding functionality
79 * if supported on the forwarding element.
81 public static String HWPATH = "HW";
82 public static String OPENFLOW = "OF";
83 public static String PCEP = "PE";
84 public static String ONEPK = "PK";
85 public static String OPENFLOW2PCEP = "O2E";
86 public static String PCEP2OPENFLOW = "E2O";
87 public static String OPENFLOW2ONEPK = "O2K";
88 public static String ONEPK2OPENFLOW = "K2O";
89 public static String PCEP2ONEPK = "E2K";
90 public static String ONEPK2PCEP = "K2E";
91 public static String PRODUCTION = "PR";
93 // Initialize the map with some well known, even though all of
94 // them could be siting outside of here, but it's convenient
95 // for Unit Testing coverage
97 compatibleType.put(CONTROLLER,
98 new ImmutablePair(Short.class, null));
99 compatibleType.put(ALL,
100 new ImmutablePair(Short.class, null));
101 compatibleType.put(SWSTACK,
102 new ImmutablePair(Short.class, null));
103 compatibleType.put(HWPATH,
104 new ImmutablePair(Short.class, null));
105 compatibleType.put(OPENFLOW,
106 new ImmutablePair(Short.class,
107 Node.NodeIDType.OPENFLOW));
108 compatibleType.put(PCEP,
109 new ImmutablePair(Integer.class,
110 Node.NodeIDType.PCEP));
111 compatibleType.put(ONEPK,
112 new ImmutablePair(String.class,
113 Node.NodeIDType.ONEPK));
114 compatibleType.put(OPENFLOW2PCEP,
115 new ImmutablePair(Short.class,
116 Node.NodeIDType.OPENFLOW));
117 compatibleType.put(OPENFLOW2ONEPK,
118 new ImmutablePair(Short.class,
119 Node.NodeIDType.OPENFLOW));
120 compatibleType.put(PCEP2OPENFLOW,
121 new ImmutablePair(Integer.class,
122 Node.NodeIDType.PCEP));
123 compatibleType.put(PCEP2ONEPK,
124 new ImmutablePair(Integer.class,
125 Node.NodeIDType.PCEP));
126 compatibleType.put(ONEPK2OPENFLOW,
127 new ImmutablePair(String.class,
128 Node.NodeIDType.ONEPK));
129 compatibleType.put(ONEPK2PCEP,
130 new ImmutablePair(String.class,
131 Node.NodeIDType.ONEPK));
132 compatibleType.put(PRODUCTION,
133 new ImmutablePair(String.class,
134 Node.NodeIDType.PRODUCTION));
138 * Return the type of the class expected for the
139 * NodeConnectorID, it's used for validity check in the constructor
141 * @param type, the type of the NodeConnector for which we
142 * want to retrieve the compatible class to be used as ID.
144 * @return The Class which is supposed to instantiate the ID
145 * for the NodeConnectorID
147 public static Class<?> getClassType(String type) {
148 if (compatibleType.get(type) == null) {
151 return compatibleType.get(type).getLeft();
155 * Return the NodeIDType compatible with this NodeConnector,
156 * in fact you cannot attach for example a PCEP NodeConnector
157 * to an OpenFlow Node.
159 * @param type, the type of the NodeConnector for which we
160 * want to retrieve the compatible class to be used as ID.
162 * @return The ID of the compatible Node
164 public static String getCompatibleNode(String type) {
165 if (compatibleType.get(type) == null) {
168 return compatibleType.get(type).getRight();
172 * Register a new ID for which Node can be created
174 * @param type, the new type being registered
175 * @param compatibleID, the type of class to be accepted as ID
176 * @param compatibleNode, the type of Node with which this
177 * NodeConnector is compatible
179 * @return true if registered, false otherwise
181 public static boolean registerIDType(String type,
182 Class<? extends Object> compatibleID,
183 String compatibleNode) {
184 if (compatibleType.get(type) != null) {
187 compatibleType.put(type, new ImmutablePair(compatibleID,
194 * UNRegister a new ID for which Node can be created
196 * @param type, the type being UN-registered
199 public static void unRegisterIDType(String type) {
200 compatibleType.remove(type);
204 // Elements that constitute the NodeConnector
205 private Object nodeConnectorID;
206 private String nodeConnectorType;
207 @XmlElement(name = "node")
208 private Node nodeConnectorNode;
210 // Helper field for JAXB
211 private String nodeConnectorIDString;
214 * Private constructor used for JAXB mapping
216 private NodeConnector() {
217 this.nodeConnectorIDString = null;
218 this.nodeConnectorID = null;
219 this.nodeConnectorType = null;
220 this.nodeConnectorNode = null;
224 * Create a NodeConnector from the component element. The
225 * constructor make sure the NodeConnector type is congruent with
226 * the Node used and also the NodeConnector ID is of type expected
228 * @param nodeConnectorType Type of the NodeConnector
229 * @param id ID portion of the NodeConnector
230 * @param node Node to which the NodeConnector is attached too
233 public NodeConnector(String nodeConnectorType, Object id,
234 Node node) throws ConstructionException {
235 // In case of compatible type being null then assume that this
236 // port can be attached on any node.
237 String compatibleNode =
238 NodeConnectorIDType.getCompatibleNode(nodeConnectorType);
239 if (NodeConnectorIDType.getClassType(nodeConnectorType) != null &&
240 NodeConnectorIDType.getClassType(nodeConnectorType).isInstance(id) &&
241 (compatibleNode == null ||
242 node.getType().equals(compatibleNode))) {
243 this.nodeConnectorType = nodeConnectorType;
244 this.nodeConnectorID = id;
245 this.nodeConnectorNode = node;
247 throw new ConstructionException("Type of incoming object:"
248 + id.getClass() + " not compatible with expected type:"
249 + NodeConnectorIDType.getClassType(nodeConnectorType)
250 + " or Node type incompatible:" + node.getType());
255 * Copy constructor for NodeConnector
257 * @param src NodeConnector to copy from
260 public NodeConnector(NodeConnector src) throws ConstructionException {
262 this.nodeConnectorType = src.getType();
263 // Here we can reference the object because that is
264 // supposed to be an immutable identifier as well like a
265 // UUID/Integer and so on, hence no need to create a copy
267 this.nodeConnectorID = src.getID();
268 this.nodeConnectorNode = new Node(src.getNode());
271 new ConstructionException("Null incoming object to copy from");
276 * getter method for NodeConnector
279 * @return the NodeConnectorType of this object
281 @XmlAttribute(name = "type")
282 public String getType() {
283 return this.nodeConnectorType;
287 * fill the current object from the string parameters passed, will
288 * be only used by JAXB
290 * @param typeStr string representing the type of the Node
291 * @param IDStr String representation of the ID
293 private void fillmeFromString(String typeStr, String IDStr) {
294 if (typeStr == null) {
302 this.nodeConnectorType = typeStr;
303 if (typeStr.equals(NodeConnectorIDType.OPENFLOW) ||
304 typeStr.equals(NodeConnectorIDType.OPENFLOW2ONEPK) ||
305 typeStr.equals(NodeConnectorIDType.OPENFLOW2PCEP)) {
307 Short ID = Short.parseShort(IDStr);
308 this.nodeConnectorID = ID;
309 } catch (Exception ex) {
312 } else if (typeStr.equals(NodeConnectorIDType.ONEPK) ||
313 typeStr.equals(NodeConnectorIDType.ONEPK2OPENFLOW) ||
314 typeStr.equals(NodeConnectorIDType.ONEPK2PCEP) ||
315 typeStr.equals(NodeConnectorIDType.PRODUCTION)) {
317 this.nodeConnectorID = IDStr;
318 } catch (Exception ex) {
321 } else if (typeStr.equals(NodeConnectorIDType.PCEP) ||
322 typeStr.equals(NodeConnectorIDType.PCEP2ONEPK) ||
323 typeStr.equals(NodeConnectorIDType.PCEP2OPENFLOW)) {
325 Integer ID = Integer.parseInt(IDStr);
326 this.nodeConnectorID = ID;
327 } catch (Exception ex) {
331 // Lookup via OSGi service registry
336 * Private setter for nodeConnectorType to be called by JAXB not by anyone
337 * else, NodeConnector is immutable
339 * @param type of node to be set
341 private void setType(String type) {
342 this.nodeConnectorType = type;
343 if (this.nodeConnectorIDString != null) {
344 this.fillmeFromString(type, this.nodeConnectorIDString);
349 * getter method for NodeConnector
352 * @return the NodeConnector ID of this object
354 public Object getID() {
355 return this.nodeConnectorID;
359 * getter method for NodeConnector ID in string format.
362 * @return the NodeConnector ID of this object in String format
364 @XmlAttribute(name = "id")
365 public String getNodeConnectorIDString() {
366 return this.nodeConnectorID.toString();
370 * private setter to be used by JAXB
372 * @param nodeConnectorIDString String representation for NodeConnectorID
374 private void setNodeConnectorIDString(String IDStr) {
375 this.nodeConnectorIDString = IDStr;
376 if (this.nodeConnectorType != null) {
377 this.fillmeFromString(this.nodeConnectorType, IDStr);
382 * getter method for NodeConnector
385 * @return the Node of this object
387 public Node getNode() {
388 return this.nodeConnectorNode;
392 public int hashCode() {
393 return new HashCodeBuilder(63389, 4951)
394 .append(nodeConnectorType)
395 .append(nodeConnectorID)
396 .append(nodeConnectorNode)
401 public boolean equals(Object obj) {
402 if (obj == null) { return false; }
403 if (obj == this) { return true; }
404 if (obj.getClass() != getClass()) {
407 NodeConnector rhs = (NodeConnector)obj;
408 return new EqualsBuilder()
409 .append(this.getType(), rhs.getType())
410 .append(this.getID(), rhs.getID())
411 .append(this.getNode(), rhs.getNode())
416 public String toString() {
417 return this.getNodeConnectorIdAsString() + "@" + this.nodeConnectorNode;
421 * A String representation of the NodeConnector without
424 * @return A String representation of the NodeConnector without
427 public String getNodeConnectorIdAsString() {
428 if (this.nodeConnectorType
429 .equals(NodeConnectorIDType.CONTROLLER) ||
430 this.nodeConnectorType
431 .equals(NodeConnectorIDType.ALL) ||
432 this.nodeConnectorType
433 .equals(NodeConnectorIDType.SWSTACK) ||
434 this.nodeConnectorType
435 .equals(NodeConnectorIDType.HWPATH)) {
436 return this.nodeConnectorType.toString();
438 return this.nodeConnectorType.toString() + "|"
439 + this.nodeConnectorID.toString();
444 * return a NodeConnector from a string
446 * @param str String to be parsed in a NodeConnector
448 * @return the NodeConnector if parse is successful, null otherwise
450 public static NodeConnector fromString(String str) {
454 String parts[] = str.split("\\@");
455 if (parts.length != 2) {
458 // Now get the Node from the Node portion
459 Node n = Node.fromString(parts[1]);
463 return fromStringNoNode(parts[0], n);
467 * return a NodeConnector from a string not containing explicitly
468 * the Node portion which has to be supplied as parameter
470 * @param str String to be parsed in a NodeConnector
471 * @param n Node to which the NodeConnector is attached
473 * @return the NodeConnector if parse is successful, null otherwise
475 public static NodeConnector fromStringNoNode(String str, Node n) {
479 String nodeConnectorParts[] = str.split("\\|");
480 if (nodeConnectorParts.length != 2) {
481 // Try to guess from a String formatted as a short because
482 // for long time openflow has been prime citizen so lets
483 // keep this legacy for now
484 String numStr = str.toUpperCase();
486 Short ofPortID = null;
487 // Try as an decimal/hex number
489 ofPortID = Short.decode(numStr);
490 } catch (Exception ex) {
494 // Lets try the special ports we know about
495 if (ofPortID == null) {
497 if (str.equalsIgnoreCase(NodeConnectorIDType.CONTROLLER
499 return new NodeConnector(
500 NodeConnectorIDType.CONTROLLER,
501 SPECIALNODECONNECTORID, n);
503 if (str.equalsIgnoreCase(NodeConnectorIDType.HWPATH
505 return new NodeConnector(NodeConnectorIDType.HWPATH,
506 SPECIALNODECONNECTORID, n);
508 if (str.equalsIgnoreCase(NodeConnectorIDType.SWSTACK
510 return new NodeConnector(NodeConnectorIDType.SWSTACK,
511 SPECIALNODECONNECTORID, n);
514 .equalsIgnoreCase(NodeConnectorIDType.ALL
516 return new NodeConnector(NodeConnectorIDType.ALL,
517 SPECIALNODECONNECTORID, n);
519 } catch (ConstructionException ex) {
525 // Lets return the cooked up NodeID
527 return new NodeConnector(NodeConnectorIDType.OPENFLOW,
529 } catch (ConstructionException ex) {
534 String typeStr = nodeConnectorParts[0];
535 String IDStr = nodeConnectorParts[1];
536 return fromStringNoNode(typeStr, IDStr, n);
540 * return a NodeConnector from a pair (type, ID) in string format
541 * not containing explicitly the Node portion which has to be
542 * supplied as parameter
544 * @param typeStr type String to be parsed in a NodeConnector
545 * @param IDStr ID String portion to be parsed in a NodeConnector
546 * @param n Node to which the NodeConnector is attached
548 * @return the NodeConnector if parse is successful, null otherwise
550 public static NodeConnector fromStringNoNode(String typeStr, String IDStr,
552 if (typeStr == null) {
559 if (typeStr.equals(NodeConnectorIDType.OPENFLOW) ||
560 typeStr.equals(NodeConnectorIDType.OPENFLOW2ONEPK) ||
561 typeStr.equals(NodeConnectorIDType.OPENFLOW2PCEP)) {
563 Short ID = Short.parseShort(IDStr);
564 return new NodeConnector(typeStr, ID, n);
565 } catch (Exception ex) {
568 } else if (typeStr.equals(NodeConnectorIDType.ONEPK) ||
569 typeStr.equals(NodeConnectorIDType.ONEPK2OPENFLOW) ||
570 typeStr.equals(NodeConnectorIDType.ONEPK2PCEP) ||
571 typeStr.equals(NodeConnectorIDType.PRODUCTION)) {
573 return new NodeConnector(typeStr, IDStr, n);
574 } catch (Exception ex) {
577 } else if (typeStr.equals(NodeConnectorIDType.PCEP) ||
578 typeStr.equals(NodeConnectorIDType.PCEP2ONEPK) ||
579 typeStr.equals(NodeConnectorIDType.PCEP2OPENFLOW)) {
581 Integer ID = Integer.parseInt(IDStr);
582 return new NodeConnector(typeStr, ID, n);
583 } catch (Exception ex) {
587 // Lookup via OSGi service registry