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.tuple.ImmutablePair;
33 * Describe a generic network element attachment points,
34 * attached to one Node, the NodeConnector is formed by the pair
35 * (NodeConnectorType, NodeConnectorID) because each SDN technology can
36 * identify an attachment point on the Node in different way.
40 @XmlAccessorType(XmlAccessType.NONE)
41 public class NodeConnector implements Serializable {
42 private static final long serialVersionUID = 1L;
43 public static final Short SPECIALNODECONNECTORID = (short) 0;
46 * Enumerate the different types of NodeConnectors supported by the class
49 public static class NodeConnectorIDType {
51 ConcurrentHashMap<String, ImmutablePair<Class<? extends Object>, String>> compatibleType =
52 new ConcurrentHashMap<String, ImmutablePair<Class<? extends Object>, String>>();
54 * Represents the OFPP_CONTROLLER reserved port to forward a
55 * packet to the controller, this is to send data packets
56 * to the controller from the data plane triggering
59 public static String CONTROLLER = "CTRL";
61 * Represents the OFPP_ALL reserved OF port
62 * to forward to ALL the ports in the system ,
63 * should be used for flooding like mechanism to
64 * be used cautiously to avoid excessive flooding.
66 public static String ALL = "ALL";
68 * Represents the OFPP_LOCAL reserved OF port
69 * to access the local networking stack of the node
70 * of which the packet is destined. Typically used for
71 * inband OF communications channel.
73 public static String SWSTACK = "SW";
75 * Describes OFPP_Normal reserved port destination that invokes
76 * the traditional native L2/L3 HW normal forwarding functionality
77 * if supported on the forwarding element.
79 public static String HWPATH = "HW";
80 public static String OPENFLOW = "OF";
81 public static String PCEP = "PE";
82 public static String ONEPK = "PK";
83 public static String OPENFLOW2PCEP = "O2E";
84 public static String PCEP2OPENFLOW = "E2O";
85 public static String OPENFLOW2ONEPK = "O2K";
86 public static String ONEPK2OPENFLOW = "K2O";
87 public static String PCEP2ONEPK = "E2K";
88 public static String ONEPK2PCEP = "K2E";
89 public static String PRODUCTION = "PR";
91 // Initialize the map with some well known, even though all of
92 // them could be siting outside of here, but it's convenient
93 // for Unit Testing coverage
95 compatibleType.put(CONTROLLER,
96 new ImmutablePair(Short.class, null));
97 compatibleType.put(ALL,
98 new ImmutablePair(Short.class, null));
99 compatibleType.put(SWSTACK,
100 new ImmutablePair(Short.class, null));
101 compatibleType.put(HWPATH,
102 new ImmutablePair(Short.class, null));
103 compatibleType.put(OPENFLOW,
104 new ImmutablePair(Short.class,
105 Node.NodeIDType.OPENFLOW));
106 compatibleType.put(PCEP,
107 new ImmutablePair(Integer.class,
108 Node.NodeIDType.PCEP));
109 compatibleType.put(ONEPK,
110 new ImmutablePair(String.class,
111 Node.NodeIDType.ONEPK));
112 compatibleType.put(OPENFLOW2PCEP,
113 new ImmutablePair(Short.class,
114 Node.NodeIDType.OPENFLOW));
115 compatibleType.put(OPENFLOW2ONEPK,
116 new ImmutablePair(Short.class,
117 Node.NodeIDType.OPENFLOW));
118 compatibleType.put(PCEP2OPENFLOW,
119 new ImmutablePair(Integer.class,
120 Node.NodeIDType.PCEP));
121 compatibleType.put(PCEP2ONEPK,
122 new ImmutablePair(Integer.class,
123 Node.NodeIDType.PCEP));
124 compatibleType.put(ONEPK2OPENFLOW,
125 new ImmutablePair(String.class,
126 Node.NodeIDType.ONEPK));
127 compatibleType.put(ONEPK2PCEP,
128 new ImmutablePair(String.class,
129 Node.NodeIDType.ONEPK));
130 compatibleType.put(PRODUCTION,
131 new ImmutablePair(String.class,
132 Node.NodeIDType.PRODUCTION));
136 * Return the type of the class expected for the
137 * NodeConnectorID, it's used for validity check in the constructor
139 * @param type, the type of the NodeConnector for which we
140 * want to retrieve the compatible class to be used as ID.
142 * @return The Class which is supposed to instantiate the ID
143 * for the NodeConnectorID
145 public static Class<?> getClassType(String type) {
146 if (compatibleType.get(type) == null) {
149 return compatibleType.get(type).getLeft();
153 * Return the NodeIDType compatible with this NodeConnector,
154 * in fact you cannot attach for example a PCEP NodeConnector
155 * to an OpenFlow Node.
157 * @param type, the type of the NodeConnector for which we
158 * want to retrieve the compatible class to be used as ID.
160 * @return The ID of the compatible Node
162 public static String getCompatibleNode(String type) {
163 if (compatibleType.get(type) == null) {
166 return compatibleType.get(type).getRight();
170 * Register a new ID for which Node can be created
172 * @param type, the new type being registered
173 * @param compatibleID, the type of class to be accepted as ID
174 * @param compatibleNode, the type of Node with which this
175 * NodeConnector is compatible
177 * @return true if registered, false otherwise
179 public static boolean registerIDType(String type,
180 Class<? extends Object> compatibleID,
181 String compatibleNode) {
182 if (compatibleType.get(type) != null) {
185 compatibleType.put(type, new ImmutablePair(compatibleID,
192 * UNRegister a new ID for which Node can be created
194 * @param type, the type being UN-registered
197 public static void unRegisterIDType(String type) {
198 compatibleType.remove(type);
202 // Elements that constitute the NodeConnector
203 private Object nodeConnectorID;
204 private String nodeConnectorType;
205 @XmlElement(name = "node")
206 private Node nodeConnectorNode;
208 // Helper field for JAXB
209 private String nodeConnectorIDString;
212 * Private constructor used for JAXB mapping
214 private NodeConnector() {
215 this.nodeConnectorIDString = null;
216 this.nodeConnectorID = null;
217 this.nodeConnectorType = null;
218 this.nodeConnectorNode = null;
222 * Create a NodeConnector from the component element. The
223 * constructor make sure the NodeConnector type is congruent with
224 * the Node used and also the NodeConnector ID is of type expected
226 * @param nodeConnectorType Type of the NodeConnector
227 * @param id ID portion of the NodeConnector
228 * @param node Node to which the NodeConnector is attached too
231 public NodeConnector(String nodeConnectorType, Object id,
232 Node node) throws ConstructionException {
233 // In case of compatible type being null then assume that this
234 // port can be attached on any node.
235 String compatibleNode =
236 NodeConnectorIDType.getCompatibleNode(nodeConnectorType);
237 if (NodeConnectorIDType.getClassType(nodeConnectorType) != null &&
238 NodeConnectorIDType.getClassType(nodeConnectorType).isInstance(id) &&
239 (compatibleNode == null ||
240 node.getType().equals(compatibleNode))) {
241 this.nodeConnectorType = nodeConnectorType;
242 this.nodeConnectorID = id;
243 this.nodeConnectorNode = node;
245 throw new ConstructionException("Type of incoming object:"
246 + id.getClass() + " not compatible with expected type:"
247 + NodeConnectorIDType.getClassType(nodeConnectorType)
248 + " or Node type incompatible:" + node.getType());
253 * Copy constructor for NodeConnector
255 * @param src NodeConnector to copy from
258 public NodeConnector(NodeConnector src) throws ConstructionException {
260 this.nodeConnectorType = src.getType();
261 // Here we can reference the object because that is
262 // supposed to be an immutable identifier as well like a
263 // UUID/Integer and so on, hence no need to create a copy
265 this.nodeConnectorID = src.getID();
266 this.nodeConnectorNode = new Node(src.getNode());
269 new ConstructionException("Null incoming object to copy from");
274 * getter method for NodeConnector
277 * @return the NodeConnectorType of this object
279 @XmlAttribute(name = "type")
280 public String getType() {
281 return this.nodeConnectorType;
285 * fill the current object from the string parameters passed, will
286 * be only used by JAXB
288 * @param typeStr string representing the type of the Node
289 * @param IDStr String representation of the ID
291 private void fillmeFromString(String typeStr, String IDStr) {
292 if (typeStr == null) {
300 this.nodeConnectorType = typeStr;
301 if (typeStr.equals(NodeConnectorIDType.OPENFLOW) ||
302 typeStr.equals(NodeConnectorIDType.OPENFLOW2ONEPK) ||
303 typeStr.equals(NodeConnectorIDType.OPENFLOW2PCEP)) {
305 Short ID = Short.parseShort(IDStr);
306 this.nodeConnectorID = ID;
307 } catch (Exception ex) {
310 } else if (typeStr.equals(NodeConnectorIDType.ONEPK) ||
311 typeStr.equals(NodeConnectorIDType.ONEPK2OPENFLOW) ||
312 typeStr.equals(NodeConnectorIDType.ONEPK2PCEP) ||
313 typeStr.equals(NodeConnectorIDType.PRODUCTION)) {
315 this.nodeConnectorID = IDStr;
316 } catch (Exception ex) {
319 } else if (typeStr.equals(NodeConnectorIDType.PCEP) ||
320 typeStr.equals(NodeConnectorIDType.PCEP2ONEPK) ||
321 typeStr.equals(NodeConnectorIDType.PCEP2OPENFLOW)) {
323 Integer ID = Integer.parseInt(IDStr);
324 this.nodeConnectorID = ID;
325 } catch (Exception ex) {
329 // Lookup via OSGi service registry
334 * Private setter for nodeConnectorType to be called by JAXB not by anyone
335 * else, NodeConnector is immutable
337 * @param type of node to be set
339 private void setType(String type) {
340 this.nodeConnectorType = type;
341 if (this.nodeConnectorIDString != null) {
342 this.fillmeFromString(type, this.nodeConnectorIDString);
347 * getter method for NodeConnector
350 * @return the NodeConnector ID of this object
352 public Object getID() {
353 return this.nodeConnectorID;
357 * getter method for NodeConnector ID in string format.
360 * @return the NodeConnector ID of this object in String format
362 @XmlAttribute(name = "id")
363 public String getNodeConnectorIDString() {
364 return this.nodeConnectorID.toString();
368 * private setter to be used by JAXB
370 * @param nodeConnectorIDString String representation for NodeConnectorID
372 private void setNodeConnectorIDString(String IDStr) {
373 this.nodeConnectorIDString = IDStr;
374 if (this.nodeConnectorType != null) {
375 this.fillmeFromString(this.nodeConnectorType, IDStr);
380 * getter method for NodeConnector
383 * @return the Node of this object
385 public Node getNode() {
386 return this.nodeConnectorNode;
390 public int hashCode() {
391 final int prime = 31;
393 result = prime * result
394 + ((nodeConnectorID == null) ? 0 : nodeConnectorID.hashCode());
397 + ((nodeConnectorNode == null) ? 0 : nodeConnectorNode
401 + ((nodeConnectorType == null) ? 0 : nodeConnectorType
407 public boolean equals(Object obj) {
412 if (getClass() != obj.getClass())
414 NodeConnector other = (NodeConnector) obj;
415 if (nodeConnectorID == null) {
416 if (other.nodeConnectorID != null)
418 } else if (!nodeConnectorID.equals(other.nodeConnectorID))
420 if (nodeConnectorNode == null) {
421 if (other.nodeConnectorNode != null)
423 } else if (!nodeConnectorNode.equals(other.nodeConnectorNode))
425 if (nodeConnectorType == null) {
426 if (other.nodeConnectorType != null)
428 } else if (!nodeConnectorType.equals(other.nodeConnectorType))
434 public String toString() {
435 return this.getNodeConnectorIdAsString() + "@" + this.nodeConnectorNode;
439 * A String representation of the NodeConnector without
442 * @return A String representation of the NodeConnector without
445 public String getNodeConnectorIdAsString() {
446 if (this.nodeConnectorType
447 .equals(NodeConnectorIDType.CONTROLLER) ||
448 this.nodeConnectorType
449 .equals(NodeConnectorIDType.ALL) ||
450 this.nodeConnectorType
451 .equals(NodeConnectorIDType.SWSTACK) ||
452 this.nodeConnectorType
453 .equals(NodeConnectorIDType.HWPATH)) {
454 return this.nodeConnectorType.toString();
456 return this.nodeConnectorType.toString() + "|"
457 + this.nodeConnectorID.toString();
462 * return a NodeConnector from a string
464 * @param str String to be parsed in a NodeConnector
466 * @return the NodeConnector if parse is successful, null otherwise
468 public static NodeConnector fromString(String str) {
472 String parts[] = str.split("\\@");
473 if (parts.length != 2) {
476 // Now get the Node from the Node portion
477 Node n = Node.fromString(parts[1]);
481 return fromStringNoNode(parts[0], n);
485 * return a NodeConnector from a string not containing explicitly
486 * the Node portion which has to be supplied as parameter
488 * @param str String to be parsed in a NodeConnector
489 * @param n Node to which the NodeConnector is attached
491 * @return the NodeConnector if parse is successful, null otherwise
493 public static NodeConnector fromStringNoNode(String str, Node n) {
497 String nodeConnectorParts[] = str.split("\\|");
498 if (nodeConnectorParts.length != 2) {
499 // Try to guess from a String formatted as a short because
500 // for long time openflow has been prime citizen so lets
501 // keep this legacy for now
502 String numStr = str.toUpperCase();
504 Short ofPortID = null;
505 // Try as an decimal/hex number
507 ofPortID = Short.decode(numStr);
508 } catch (Exception ex) {
512 // Lets try the special ports we know about
513 if (ofPortID == null) {
515 if (str.equalsIgnoreCase(NodeConnectorIDType.CONTROLLER
517 return new NodeConnector(
518 NodeConnectorIDType.CONTROLLER,
519 SPECIALNODECONNECTORID, n);
521 if (str.equalsIgnoreCase(NodeConnectorIDType.HWPATH
523 return new NodeConnector(NodeConnectorIDType.HWPATH,
524 SPECIALNODECONNECTORID, n);
526 if (str.equalsIgnoreCase(NodeConnectorIDType.SWSTACK
528 return new NodeConnector(NodeConnectorIDType.SWSTACK,
529 SPECIALNODECONNECTORID, n);
532 .equalsIgnoreCase(NodeConnectorIDType.ALL
534 return new NodeConnector(NodeConnectorIDType.ALL,
535 SPECIALNODECONNECTORID, n);
537 } catch (ConstructionException ex) {
543 // Lets return the cooked up NodeID
545 return new NodeConnector(NodeConnectorIDType.OPENFLOW,
547 } catch (ConstructionException ex) {
552 String typeStr = nodeConnectorParts[0];
553 String IDStr = nodeConnectorParts[1];
554 return fromStringNoNode(typeStr, IDStr, n);
558 * return a NodeConnector from a pair (type, ID) in string format
559 * not containing explicitly the Node portion which has to be
560 * supplied as parameter
562 * @param typeStr type String to be parsed in a NodeConnector
563 * @param IDStr ID String portion to be parsed in a NodeConnector
564 * @param n Node to which the NodeConnector is attached
566 * @return the NodeConnector if parse is successful, null otherwise
568 public static NodeConnector fromStringNoNode(String typeStr, String IDStr,
570 if (typeStr == null) {
577 if (typeStr.equals(NodeConnectorIDType.OPENFLOW) ||
578 typeStr.equals(NodeConnectorIDType.OPENFLOW2ONEPK) ||
579 typeStr.equals(NodeConnectorIDType.OPENFLOW2PCEP)) {
581 Short ID = Short.parseShort(IDStr);
582 return new NodeConnector(typeStr, ID, n);
583 } catch (Exception ex) {
586 } else if (typeStr.equals(NodeConnectorIDType.ONEPK) ||
587 typeStr.equals(NodeConnectorIDType.ONEPK2OPENFLOW) ||
588 typeStr.equals(NodeConnectorIDType.ONEPK2PCEP) ||
589 typeStr.equals(NodeConnectorIDType.PRODUCTION)) {
591 return new NodeConnector(typeStr, IDStr, n);
592 } catch (Exception ex) {
595 } else if (typeStr.equals(NodeConnectorIDType.PCEP) ||
596 typeStr.equals(NodeConnectorIDType.PCEP2ONEPK) ||
597 typeStr.equals(NodeConnectorIDType.PCEP2OPENFLOW)) {
599 Integer ID = Integer.parseInt(IDStr);
600 return new NodeConnector(typeStr, ID, n);
601 } catch (Exception ex) {
605 // Lookup via OSGi service registry