1 == NetIDE Developer Guide ==
4 The NetIDE Network Engine enables portability and cooperation inside a single
5 network by using a client/server multi-controller SDN architecture. Separate
6 "Client SDN Controllers" host the various SDN Applications with their access
7 to the actual physical network abstracted and coordinated through a single
8 "Server SDN Controller", in this instance OpenDaylight. This allows
9 applications written for Ryu/Floodlight/Pyretic to execute on OpenDaylight
10 managed infrastructure.
12 The "Network Engine" is modular by design:
14 * An OpenDaylight plugin, "shim", sends/receives messages to/from subscribed SDN
15 Client Controllers. This consumes the ODL OpenFlow Plugin
16 * An initial suite of SDN Client Controller "Backends": Floodlight, Ryu, Pyretic.
17 Further controllers may be added over time as the engine is extensible.
19 The Network Engine provides a compatibility layer capable of translating calls of
20 the network applications running on top of the client controllers, into calls for
21 the server controller framework. The communication between the client and the
22 server layers is achieved through the NetIDE intermediate protocol,
23 which is an application-layer protocol on top of TCP that transmits the network
24 control/management messages from the client to the server controller and vice-versa.
25 Between client and server controller sits the Core Layer which also "speaks" the
26 intermediate protocol. The core layer implements three main functions:
28 ... interfacing with the client backends and server shim, controlling the lifecycle
29 of controllers as well as modules in them,
30 ... orchestrating the execution of individual modules (in one client controller)
31 or complete applications (possibly spread across multiple client controllers),
32 ... interfacing with the tools.
34 .NetIDE Network Engine Architecture
35 image::netide/arch-engine.jpg[width=500]
37 === NetIDE Intermediate Protocol ===
39 The Intermediate Protocol serves several needs, it has to:
41 ... carry control messages between core and shim/backend, e.g., to start up/take
42 down a particular module, providing unique identifiers for modules,
43 ... carry event and action messages between shim, core, and backend, properly
44 demultiplexing such messages to the right module based on identifiers,
45 ... encapsulate messages specific to a particular SBI protocol version (e.g.,
46 OpenFlow 1.X, NETCONF, etc.) towards the client controllers with proper information
47 to recognize these messages as such.
49 The NetIDE packages can be added as dependencies in Maven projects by putting the
50 following code in the _pom.xml_ file.
53 <groupId>org.opendaylight.netide</groupId>
54 <artifactId>api</artifactId>
55 <version>${NETIDE_VERSION}</version>
58 The current stable version for NetIDE is `0.1.0-Beryllium`.
62 ==== Protocol specification
64 Messages of the NetIDE protocol contain two basic elements: the NetIDE header and
65 the data (or payload). The NetIDE header, described below, is placed
66 before the payload and serves as the communication and control link between the
67 different components of the Network Engine. The payload can contain management
68 messages, used by the components of the Network Engine to exchange relevant
69 information, or control/configuration messages (such as OpenFlow, NETCONF, etc.)
70 crossing the Network Engine generated by either network application modules or by
73 The NetIDE header is defined as follows:
76 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
77 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
78 | netide_ver | type | length |
79 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
81 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
83 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
87 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
89 where each tick mark represents one bit position. Alternatively, in a C-style coding
90 format, the NetIDE header can be represented with the following structure:
92 struct netide_header {
101 * +netide_ver+ is the version of the NetIDE protocol (the current version is v1.2, which
102 is identified with value 0x03).
103 * +length+ is the total length of the payload in bytes.
104 * +type+ contains a code that indicates the type of the message according with the
108 NETIDE_HELLO = 0x01 ,
109 NETIDE_ERROR = 0x02 ,
111 MODULE_ANNOUNCEMENT = 0x04 ,
112 MODULE_ACKNOWLEDGE = 0x05 ,
113 NETIDE_HEARTBEAT = 0x06 ,
114 NETIDE_OPENFLOW = 0x11 ,
115 NETIDE_NETCONF = 0x12 ,
119 * +datapath_id+ is a 64-bit field that uniquely identifies the network elements.
120 * +module_id+ is a 32-bits field that uniquely identifies Backends and application modules running
121 on top of each client controller. The composition mechanism in the core layer leverages
122 on this field to implement the correct execution flow of these modules.
123 * +xid+ is the transaction identifier associated to the each message. Replies must use the same
124 value to facilitate the pairing.
127 ==== Module announcement
129 The first operation performed by a Backend is registering itself and the modules that
130 it is running to the Core. This is done by using the +MODULE_ANNOUNCEMENT+ and
131 +MODULE_ACKNOWLEDGE+ message types. As a result of this process, each Backend and
132 application module can be recognized by the Core through an identifier (the +module_id+)
133 placed in the NetIDE header. First, a Backend registers itself by using the following
134 schema: backend-<platform name>-<pid>.
136 For example,odule a Ryu Backend will register by using the following name in the message
137 backend-ryu-12345 where 12345 is the process ID of the registering instance of the
138 Ryu platform. The format of the message is the following:
140 struct NetIDE_message {
142 type = MODULE_ANNOUNCEMENT
143 length = len(" backend -< platform_name >-<pid >")
147 data = " backend -< platform_name >-<pid >"
150 The answer generated by the Core will include a +module_id+ number and the Backend name in
151 the payload (the same indicated in the +MODULE_ANNOUNCEMENT+ message):
153 struct NetIDE_message {
155 type = MODULE_ACKNOWLEDGE
156 length = len(" backend -< platform_name >-<pid >")
158 module_id = MODULE_ID
160 data = " backend -< platform_name >-<pid >"
163 Once a Backend has successfully registered itself, it can start registering its modules with the same
164 procedure described above by indicating the name of the module in the data (e.g. data="Firewall").
165 From this point on, the Backend will insert its own +module_id+ in the header of the messages it generates
166 (e.g. heartbeat, hello messages, OpenFlow echo messages from the client controllers, etc.).
167 Otherwise, it will encapsulate the control/configuration messages (e.g. FlowMod, PacketOut,
168 FeatureRequest, NETCONF request, etc.) generated by network application modules with the specific
174 The heartbeat mechanism has been introduced after the adoption of the ZeroMQ messaging queuing
175 library to transmit the NetIDE messages. Unfortunately, the ZeroMQ library does not offer any
176 mechanism to find out about disrupted connections (and also completely unresponsive peers).
177 This limitation of the ZeroMQ library can be an issue for the Core's composition mechanism and for
178 the tools connected to the Network Engine, as they cannot understand when an client controller
179 disconnects or crashes. As a consequence, Backends must periodically send (let's say every 5
180 seconds) a "heartbeat" message to the Core. If the Core does not receive at least one "heartbeat"
181 message from the Backend within a certain timeframe, the Core considers it disconnected, removes
182 all the related data from its memory structures and informs the relevant tools. The format of the
183 message is the following:
185 struct NetIDE_message {
187 type = NETIDE_HEARTBEAT
190 module_id = backend -id
197 Upon a successful connection with the Core, the client controller must immediately send a hello
198 message with the list of the control and/or management protocols needed by the applications
199 deployed on top of it.
201 struct NetIDE_message {
202 struct netide_header header ;
206 The header contains the following values:
209 * +type=NETIDE_HELLO+
210 * +length=2*NR_PROTOCOLS+
211 * +data+ contains one 2-byte word (in big endian order) for each protocol, with the first
212 byte containing the code of the protocol according to the above enum, while the second byte in-
213 dictates the version of the protocol (e.g. according to the ONF specification, 0x01 for OpenFlow
214 v1.0, 0x02 for OpenFlow v1.1, etc.). NETCONF version is marked with 0x01 that refers to the
215 specification in the RFC6241, while OpFlex version is marked with 0x00 since this protocol is
216 still in work-in-progress stage.
218 The Core relays hello messages to the server controller which responds with another hello message
219 containing the following:
222 * +type=NETIDE_HELLO+
223 * +length=2*NR_PROTOCOLS+
225 If at least one of the protocols requested by the client is supported. In particular, +data+ contains the
226 codes of the protocols that match the client's request (2-bytes words, big endian order). If the hand-
227 shake fails because none of the requested protocols is supported by the server controller, the header
228 of the answer is as follows:
231 * +type=NETIDE_ERROR+
232 * +length=2*NR_PROTOCOLS+
233 * +data+ contains the codes of all the protocols supported by the server
234 controller (2-bytes words, big endian order). In this case, the TCP session is terminated by the
235 server controller just after the answer is received by the client.