1 .. _controller-dev-guide:
9 OpenDaylight Controller is Java-based, model-driven controller using
10 YANG as its modeling language for various aspects of the system and
11 applications and with its components serves as a base platform for other
12 OpenDaylight applications.
14 The OpenDaylight Controller relies on the following technologies:
16 - **OSGI** - This framework is the back-end of OpenDaylight as it
17 allows dynamically loading of bundles and packages JAR files, and
18 binding bundles together for exchanging information.
20 - **Karaf** - Application container built on top of OSGI, which
21 simplifies operational aspects of packaging and installing
24 - **YANG** - a data modeling language used to model configuration and
25 state data manipulated by the applications, remote procedure calls,
28 The OpenDaylight Controller provides following model-driven subsystems
29 as a foundation for Java applications:
31 - :ref:`config_subsystem` - an activation,
32 dependency-injection and configuration framework, which allows
33 two-phase commits of configuration and dependency-injection, and
34 allows for run-time rewiring.
36 - :ref:`MD-SAL <mdsal_dev_guide>` - messaging and data storage
37 functionality for data, notifications and RPCs modeled by application
38 developers. MD-SAL uses YANG as the modeling for both interface and
39 data definitions, and provides a messaging and data-centric runtime
40 for such services based on YANG modeling.
42 - **MD-SAL Clustering** - enables cluster support for core MD-SAL
43 functionality and provides location-transparent accesss to
46 The OpenDaylight Controller supports external access to applications and
47 data using following model-driven protocols:
49 - **NETCONF** - XML-based RPC protocol, which provides abilities for
50 client to invoke YANG-modeled RPCs, receive notifications and to
51 read, modify and manipulate YANG modeled data.
53 - **RESTCONF** - HTTP-based protocol, which provides REST-like APIs to
54 manipulate YANG modeled data and invoke YANG modeled RPCs, using XML
55 or JSON as payload format.
62 The Model-Driven Service Adaptation Layer (MD-SAL) is message-bus
63 inspired extensible middleware component that provides messaging and
64 data storage functionality based on data and interface models defined by
65 application developers (i.e. user-defined models).
69 - Defines a **common-layer, concepts, data model building blocks and
70 messaging patterns** and provides infrastructure / framework for
71 applications and inter-application communication.
73 - Provide common support for user-defined transport and payload
74 formats, including payload serialization and adaptation (e.g. binary,
77 The MD-SAL uses **YANG** as the modeling language for both interface and
78 data definitions, and provides a messaging and data-centric runtime for
79 such services based on YANG modeling.
81 | The MD-SAL provides two different API types (flavours):
83 - **MD-SAL Binding:** MD-SAL APIs which extensively uses APIs and
84 classes generated from YANG models, which provides compile-time
87 - **MD-SAL DOM:** (Document Object Model) APIs which uses DOM-like
88 representation of data, which makes them more powerful, but provides
89 less compile-time safety.
93 Model-driven nature of the MD-SAL and **DOM**-based APIs allows for
94 behind-the-scene API and payload type mediation and transformation
95 to facilitate seamless communication between applications - this
96 enables for other components and applications to provide connectors
97 / expose different set of APIs and derive most of its functionality
98 purely from models, which all existing code can benefit from without
99 modification. For example **RESTCONF Connector** is an application
100 built on top of MD-SAL and exposes YANG-modeled application APIs
101 transparently via HTTP and adds support for XML and JSON payload
107 Basic concepts are building blocks which are used by applications, and
108 from which MD-SAL uses to define messaging patterns and to provide
109 services and behavior based on developer-supplied YANG models.
112 All state-related data are modeled and represented as data tree,
113 with possibility to address any element / subtree
115 - **Operational Data Tree** - Reported state of the system,
116 published by the providers using MD-SAL. Represents a feedback
117 loop for applications to observe state of the network / system.
119 - **Configuration Data Tree** - Intended state of the system or
120 network, populated by consumers, which expresses their intention.
123 Unique identifier of node / subtree in data tree, which provides
124 unambiguous information, how to reference and retrieve node /
125 subtree from conceptual data trees.
128 Asynchronous transient event which may be consumed by subscribers
129 and they may act upon it
132 asynchronous request-reply message pair, when request is triggered
133 by consumer, send to the provider, which in future replies with
138 In MD-SAL terminology, the term *RPC* is used to define the
139 input and output for a procedure (function) that is to be
140 provided by a provider, and mediated by the MD-SAL, that means
141 it may not result in remote call.
146 MD-SAL provides several messaging patterns using broker derived from
147 basic concepts, which are intended to transfer YANG modeled data between
148 applications to provide data-centric integration between applications
149 instead of API-centric integration.
151 - **Unicast communication**
153 - **Remote Procedure Calls** - unicast between consumer and
154 provider, where consumer sends **request** message to provider,
155 which asynchronously responds with **reply** message
157 - **Publish / Subscribe**
159 - **Notifications** - multicast transient message which is published
160 by provider and is delivered to subscribers
162 - **Data Change Events** - multicast asynchronous event, which is
163 sent by data broker if there is change in conceptual data tree,
164 and is delivered to subscribers
166 - **Transactional access to Data Tree**
168 - Transactional **reads** from conceptual **data tree** - read-only
169 transactions with isolation from other running transactions.
171 - Transactional **modification** to conceptual **data tree** - write
172 transactions with isolation from other running transactions.
174 - **Transaction chaining**
176 MD-SAL Data Transactions
177 ------------------------
179 MD-SAL **Data Broker** provides transactional access to conceptual
180 **data trees** representing configuration and operational state.
184 **Data tree** usually represents state of the modeled data, usually
185 this is state of controller, applications and also external systems
188 **Transactions** provide :ref:`stable and isolated
189 view <transaction_isolation>` from other currently running
190 transactions. The state of running transaction and underlying data tree
191 is not affected by other concurrently running transactions.
194 Transaction provides only modification capabilities, but does not
195 provide read capabilities. Write-only transaction is allocated using
196 ``newWriteOnlyTransaction()``.
200 This allows less state tracking for write-only transactions and
201 allows MD-SAL Clustering to optimize internal representation of
202 transaction in cluster.
205 Transaction provides both read and write capabilities. It is
206 allocated using ``newReadWriteTransaction()``.
209 Transaction provides stable read-only view based on current data
210 tree. Read-only view is not affected by any subsequent write
211 transactions. Read-only transaction is allocated using
212 ``newReadOnlyTransaction()``.
216 If an application needs to observe changes itself in data tree,
217 it should use **data tree listeners** instead of read-only
218 transactions and polling data tree.
220 Transactions may be allocated using the **data broker** itself or using
221 **transaction chain**. In the case of **transaction chain**, the new
222 allocated transaction is not based on current state of data tree, but
223 rather on state introduced by previous transaction from the same chain,
224 even if the commit for previous transaction has not yet occurred (but
225 transaction was submitted).
227 Write-Only & Read-Write Transaction
228 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
230 Write-Only and Read-Write transactions provide modification capabilities
231 for the conceptual data trees.
233 1. application allocates new transactions using
234 ``newWriteOnlyTransaction()`` or ``newReadWriteTransaction()``.
236 2. application `modifies data tree <#_modification_of_data_tree>`__
237 using ``put``, ``merge`` and/or ``delete``.
239 3. application finishes transaction using
240 ``submit()``, which :ref:`seals transaction
241 and submits <submitting_transaction>` it to be processed.
243 4. application observes the result of the transaction commit using
244 either blocking or asynchronous calls.
246 The **initial state** of the write transaction is a **stable snapshot**
247 of the current data tree state captured when transaction was created and
248 it’s state and underlying data tree are not affected by other
249 concurrently running transactions.
251 Write transactions are **isolated** from other concurrent write
252 transactions. All :ref:`writes are local <transaction_local_state>`
253 to the transaction and represents only a **proposal of state change**
254 for data tree and **are not visible** to any other concurrently running
255 transactions (including read-only transactions).
257 The transaction :ref:`commit may fail <commit_failure_scenarios>` due
258 to failing verification of data or concurrent transaction modifying and
259 affected data in an incompatible way.
261 Modification of Data Tree
262 ^^^^^^^^^^^^^^^^^^^^^^^^^
264 Write-only and read-write transaction provides following methods to
270 <T> void put(LogicalDatastoreType store, InstanceIdentifier<T> path, T data);
272 Stores a piece of data at a specified path. This acts as an **add /
273 replace** operation, which is to say that whole subtree will be
274 replaced by the specified data.
279 <T> void merge(LogicalDatastoreType store, InstanceIdentifier<T> path, T data);
281 Merges a piece of data with the existing data at a specified path.
282 Any **pre-existing data** which are not explicitly overwritten
283 **will be preserved**. This means that if you store a container, its
284 child subtrees will be merged.
289 void delete(LogicalDatastoreType store, InstanceIdentifier<?> path);
291 Removes a whole subtree from a specified path.
293 .. _submitting_transaction:
295 Submitting transaction
296 ^^^^^^^^^^^^^^^^^^^^^^
298 Transaction is submitted to be processed and committed using following
303 CheckedFuture<Void,TransactionCommitFailedException> submit();
305 Applications publish the changes proposed in the transaction by calling
306 ``submit()`` on the transaction. This **seals the transaction**
307 (preventing any further writes using this transaction) and submits it to
308 be processed and applied to global conceptual data tree. The
309 ``submit()`` method does not block, but rather returns
310 ``ListenableFuture``, which will complete successfully once processing
311 of transaction is finished and changes are applied to data tree. If
312 **commit** of data failed, the future will fail with
313 ``TransactionFailedException``.
315 Application may listen on commit state asynchronously using
316 ``ListenableFuture``.
320 Futures.addCallback( writeTx.submit(), new FutureCallback<Void>() {
321 public void onSuccess( Void result ) {
322 LOG.debug("Transaction committed successfully.");
325 public void onFailure( Throwable t ) {
326 LOG.error("Commit failed.",e);
330 - Submits ``writeTx`` and registers application provided
331 ``FutureCallback`` on returned future.
333 - Invoked when future completed successfully - transaction ``writeTx``
334 was successfully committed to data tree.
336 - Invoked when future failed - commit of transaction ``writeTx``
337 failed. Supplied exception provides additional details and cause of
340 If application need to block till commit is finished it may use
341 ``checkedGet()`` to wait till commit is finished.
346 writeTx.submit().checkedGet();
347 } catch (TransactionCommitFailedException e) {
348 LOG.error("Commit failed.",e);
351 - Submits ``writeTx`` and blocks till commit of ``writeTx`` is
352 finished. If commit fails ``TransactionCommitFailedException`` will
355 - Catches ``TransactionCommitFailedException`` and logs it.
357 .. _transaction_local_state:
359 Transaction local state
360 ^^^^^^^^^^^^^^^^^^^^^^^
362 Read-Write transactions maintain transaction-local state, which renders
363 all modifications as if they happened, but this is only local to
366 Reads from the transaction returns data as if the previous modifications
367 in transaction already happened.
369 Let assume initial state of data tree for ``PATH`` is ``A``.
373 ReadWriteTransaction rwTx = broker.newReadWriteTransaction();
375 rwRx.read(OPERATIONAL,PATH).get();
376 rwRx.put(OPERATIONAL,PATH,B);
377 rwRx.read(OPERATIONAL,PATH).get();
378 rwRx.put(OPERATIONAL,PATH,C);
379 rwRx.read(OPERATIONAL,PATH).get();
381 - Allocates new ``ReadWriteTransaction``.
383 - Read from ``rwTx`` will return value ``A`` for ``PATH``.
385 - Writes value ``B`` to ``PATH`` using ``rwTx``.
387 - Read will return value ``B`` for ``PATH``, since previous write
388 occurred in same transaction.
390 - Writes value ``C`` to ``PATH`` using ``rwTx``.
392 - Read will return value ``C`` for ``PATH``, since previous write
393 occurred in same transaction.
395 .. _transaction_isolation:
397 Transaction isolation
398 ~~~~~~~~~~~~~~~~~~~~~
400 Running (not submitted) transactions are isolated from each other and
401 changes done in one transaction are not observable in other currently
404 Lets assume initial state of data tree for ``PATH`` is ``A``.
408 ReadOnlyTransaction txRead = broker.newReadOnlyTransaction();
409 ReadWriteTransaction txWrite = broker.newReadWriteTransaction();
411 txRead.read(OPERATIONAL,PATH).get();
412 txWrite.put(OPERATIONAL,PATH,B);
413 txWrite.read(OPERATIONAL,PATH).get();
414 txWrite.submit().get();
415 txRead.read(OPERATIONAL,PATH).get();
416 txAfterCommit = broker.newReadOnlyTransaction();
417 txAfterCommit.read(OPERATIONAL,PATH).get();
419 - Allocates read only transaction, which is based on data tree which
420 contains value ``A`` for ``PATH``.
422 - Allocates read write transaction, which is based on data tree which
423 contains value ``A`` for ``PATH``.
425 - Read from read-only transaction returns value ``A`` for ``PATH``.
427 - Data tree is updated using read-write transaction, ``PATH`` contains
428 ``B``. Change is not public and only local to transaction.
430 - Read from read-write transaction returns value ``B`` for ``PATH``.
432 - Submits changes in read-write transaction to be committed to data
433 tree. Once commit will finish, changes will be published and ``PATH``
434 will be updated for value ``B``. Previously allocated transactions
435 are not affected by this change.
437 - Read from previously allocated read-only transaction still returns
438 value ``A`` for ``PATH``, since it provides stable and isolated view.
440 - Allocates new read-only transaction, which is based on data tree,
441 which contains value ``B`` for ``PATH``.
443 - Read from new read-only transaction return value ``B`` for ``PATH``
444 since read-write transaction was committed.
448 Examples contain blocking calls on future only to illustrate that
449 action happened after other asynchronous action. The use of the
450 blocking call ``ListenableFuture#get()`` is discouraged for most
451 use-cases and you should use
452 ``Futures#addCallback(ListenableFuture, FutureCallback)`` to listen
453 asynchronously for result.
455 .. _commit_failure_scenarios:
457 Commit failure scenarios
458 ~~~~~~~~~~~~~~~~~~~~~~~~
460 A transaction commit may fail because of following reasons:
462 Optimistic Lock Failure
463 Another transaction finished earlier and **modified the same node in
464 a non-compatible way**. The commit (and the returned future) will
465 fail with an ``OptimisticLockFailedException``.
467 It is the responsibility of the caller to create a new transaction
468 and submit the same modification again in order to update data tree.
472 ``OptimisticLockFailedException`` usually exposes **multiple
473 writers** to the same data subtree, which may conflict on same
476 In most cases, retrying may result in a probability of success.
478 There are scenarios, albeit unusual, where any number of retries
479 will not succeed. Therefore it is strongly recommended to limit
480 the number of retries (2 or 3) to avoid an endless loop.
483 The data change introduced by this transaction **did not pass
484 validation** by commit handlers or data was incorrectly structured.
485 The returned future will fail with a
486 ``DataValidationFailedException``. User **should not retry** to
487 create new transaction with same data, since it probably will fail
490 Example conflict of two transactions
491 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
493 This example illustrates two concurrent transactions, which derived from
494 same initial state of data tree and proposes conflicting modifications.
498 WriteTransaction txA = broker.newWriteTransaction();
499 WriteTransaction txB = broker.newWriteTransaction();
501 txA.put(CONFIGURATION, PATH, A);
502 txB.put(CONFIGURATION, PATH, B);
504 CheckedFuture<?,?> futureA = txA.submit();
505 CheckedFuture<?,?> futureB = txB.submit();
507 - Updates ``PATH`` to value ``A`` using ``txA``
509 - Updates ``PATH`` to value ``B`` using ``txB``
511 - Seals & submits ``txA``. The commit will be processed asynchronously
512 and data tree will be updated to contain value ``A`` for ``PATH``.
513 The returned ‘ListenableFuture’ will complete successfully once state
514 is applied to data tree.
516 - Seals & submits ``txB``. Commit of ``txB`` will fail, because
517 previous transaction also modified path in a concurrent way. The
518 state introduced by ``txB`` will not be applied. The returned
519 ``ListenableFuture`` will fail with ``OptimisticLockFailedException``
520 exception, which indicates that concurrent transaction prevented the
521 submitted transaction from being applied.
523 Example asynchronous retry-loop
524 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
528 private void doWrite( final int tries ) {
529 WriteTransaction writeTx = dataBroker.newWriteOnlyTransaction();
531 MyDataObject data = ...;
532 InstanceIdentifier<MyDataObject> path = ...;
533 writeTx.put( LogicalDatastoreType.OPERATIONAL, path, data );
535 Futures.addCallback( writeTx.submit(), new FutureCallback<Void>() {
536 public void onSuccess( Void result ) {
540 public void onFailure( Throwable t ) {
541 if( t instanceof OptimisticLockFailedException && (( tries - 1 ) > 0)) {
542 doWrite( tries - 1 );
550 Concurrent change compatibility
551 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
553 There are several sets of changes which could be considered incompatible
554 between two transactions which are derived from same initial state.
555 Rules for conflict detection applies recursively for each subtree level.
557 Following table shows state changes and failures between two concurrent
558 transactions, which are based on same initial state, ``tx1`` is
559 submitted before ``tx2``.
561 INFO: Following tables stores numeric values and shows data using
562 ``toString()`` to simplify examples.
564 +--------------------+--------------------+--------------------+--------------------+
565 | Initial state | tx1 | tx2 | Observable Result |
566 +====================+====================+====================+====================+
567 | Empty | ``put(A,1)`` | ``put(A,2)`` | ``tx2`` will fail, |
568 | | | | value of ``A`` is |
570 +--------------------+--------------------+--------------------+--------------------+
571 | Empty | ``put(A,1)`` | ``merge(A,2)`` | value of ``A`` is |
573 +--------------------+--------------------+--------------------+--------------------+
574 | Empty | ``merge(A,1)`` | ``put(A,2)`` | ``tx2`` will fail, |
575 | | | | value of ``A`` is |
577 +--------------------+--------------------+--------------------+--------------------+
578 | Empty | ``merge(A,1)`` | ``merge(A,2)`` | ``A`` is ``2`` |
579 +--------------------+--------------------+--------------------+--------------------+
580 | A=0 | ``put(A,1)`` | ``put(A,2)`` | ``tx2`` will fail, |
581 | | | | ``A`` is ``1`` |
582 +--------------------+--------------------+--------------------+--------------------+
583 | A=0 | ``put(A,1)`` | ``merge(A,2)`` | ``A`` is ``2`` |
584 +--------------------+--------------------+--------------------+--------------------+
585 | A=0 | ``merge(A,1)`` | ``put(A,2)`` | ``tx2`` will fail, |
586 | | | | value of ``A`` is |
588 +--------------------+--------------------+--------------------+--------------------+
589 | A=0 | ``merge(A,1)`` | ``merge(A,2)`` | ``A`` is ``2`` |
590 +--------------------+--------------------+--------------------+--------------------+
591 | A=0 | ``delete(A)`` | ``put(A,2)`` | ``tx2`` will fail, |
592 | | | | ``A`` does not |
594 +--------------------+--------------------+--------------------+--------------------+
595 | A=0 | ``delete(A)`` | ``merge(A,2)`` | ``A`` is ``2`` |
596 +--------------------+--------------------+--------------------+--------------------+
598 Table: Concurrent change resolution for leaves and leaf-list items
600 +--------------------+--------------------+--------------------+--------------------+
601 | Initial state | ``tx1`` | ``tx2`` | Result |
602 +====================+====================+====================+====================+
603 | Empty | put(TOP,[]) | put(TOP,[]) | ``tx2`` will fail, |
604 | | | | state is TOP=[] |
605 +--------------------+--------------------+--------------------+--------------------+
606 | Empty | put(TOP,[]) | merge(TOP,[]) | TOP=[] |
607 +--------------------+--------------------+--------------------+--------------------+
608 | Empty | put(TOP,[FOO=1]) | put(TOP,[BAR=1]) | ``tx2`` will fail, |
610 | | | | TOP=[FOO=1] |
611 +--------------------+--------------------+--------------------+--------------------+
612 | Empty | put(TOP,[FOO=1]) | merge(TOP,[BAR=1]) | TOP=[FOO=1,BAR=1] |
613 +--------------------+--------------------+--------------------+--------------------+
614 | Empty | merge(TOP,[FOO=1]) | put(TOP,[BAR=1]) | ``tx2`` will fail, |
616 | | | | TOP=[FOO=1] |
617 +--------------------+--------------------+--------------------+--------------------+
618 | Empty | merge(TOP,[FOO=1]) | merge(TOP,[BAR=1]) | TOP=[FOO=1,BAR=1] |
619 +--------------------+--------------------+--------------------+--------------------+
620 | TOP=[] | put(TOP,[FOO=1]) | put(TOP,[BAR=1]) | ``tx2`` will fail, |
622 | | | | TOP=[FOO=1] |
623 +--------------------+--------------------+--------------------+--------------------+
624 | TOP=[] | put(TOP,[FOO=1]) | merge(TOP,[BAR=1]) | state is |
625 | | | | TOP=[FOO=1,BAR=1] |
626 +--------------------+--------------------+--------------------+--------------------+
627 | TOP=[] | merge(TOP,[FOO=1]) | put(TOP,[BAR=1]) | ``tx2`` will fail, |
629 | | | | TOP=[FOO=1] |
630 +--------------------+--------------------+--------------------+--------------------+
631 | TOP=[] | merge(TOP,[FOO=1]) | merge(TOP,[BAR=1]) | state is |
632 | | | | TOP=[FOO=1,BAR=1] |
633 +--------------------+--------------------+--------------------+--------------------+
634 | TOP=[] | delete(TOP) | put(TOP,[BAR=1]) | ``tx2`` will fail, |
635 | | | | state is empty |
637 +--------------------+--------------------+--------------------+--------------------+
638 | TOP=[] | delete(TOP) | merge(TOP,[BAR=1]) | state is |
639 | | | | TOP=[BAR=1] |
640 +--------------------+--------------------+--------------------+--------------------+
641 | TOP=[] | put(TOP/FOO,1) | put(TOP/BAR,1]) | state is |
642 | | | | TOP=[FOO=1,BAR=1] |
643 +--------------------+--------------------+--------------------+--------------------+
644 | TOP=[] | put(TOP/FOO,1) | merge(TOP/BAR,1) | state is |
645 | | | | TOP=[FOO=1,BAR=1] |
646 +--------------------+--------------------+--------------------+--------------------+
647 | TOP=[] | merge(TOP/FOO,1) | put(TOP/BAR,1) | state is |
648 | | | | TOP=[FOO=1,BAR=1] |
649 +--------------------+--------------------+--------------------+--------------------+
650 | TOP=[] | merge(TOP/FOO,1) | merge(TOP/BAR,1) | state is |
651 | | | | TOP=[FOO=1,BAR=1] |
652 +--------------------+--------------------+--------------------+--------------------+
653 | TOP=[] | delete(TOP) | put(TOP/BAR,1) | ``tx2`` will fail, |
654 | | | | state is empty |
656 +--------------------+--------------------+--------------------+--------------------+
657 | TOP=[] | delete(TOP) | merge(TOP/BAR,1] | ``tx2`` will fail, |
658 | | | | state is empty |
660 +--------------------+--------------------+--------------------+--------------------+
661 | TOP=[FOO=1] | put(TOP/FOO,2) | put(TOP/BAR,1) | state is |
662 | | | | TOP=[FOO=2,BAR=1] |
663 +--------------------+--------------------+--------------------+--------------------+
664 | TOP=[FOO=1] | put(TOP/FOO,2) | merge(TOP/BAR,1) | state is |
665 | | | | TOP=[FOO=2,BAR=1] |
666 +--------------------+--------------------+--------------------+--------------------+
667 | TOP=[FOO=1] | merge(TOP/FOO,2) | put(TOP/BAR,1) | state is |
668 | | | | TOP=[FOO=2,BAR=1] |
669 +--------------------+--------------------+--------------------+--------------------+
670 | TOP=[FOO=1] | merge(TOP/FOO,2) | merge(TOP/BAR,1) | state is |
671 | | | | TOP=[FOO=2,BAR=1] |
672 +--------------------+--------------------+--------------------+--------------------+
673 | TOP=[FOO=1] | delete(TOP/FOO) | put(TOP/BAR,1) | state is |
674 | | | | TOP=[BAR=1] |
675 +--------------------+--------------------+--------------------+--------------------+
676 | TOP=[FOO=1] | delete(TOP/FOO) | merge(TOP/BAR,1] | state is |
677 | | | | TOP=[BAR=1] |
678 +--------------------+--------------------+--------------------+--------------------+
680 Table: Concurrent change resolution for containers, lists, list items
685 The MD-SAL provides a way to deliver Remote Procedure Calls (RPCs) to a
686 particular implementation based on content in the input as it is modeled
687 in YANG. This part of the RPC input is referred to as a **context
690 The MD-SAL does not dictate the name of the leaf which is used for this
691 RPC routing, but provides necessary functionality for YANG model author
692 to define their **context reference** in their model of RPCs.
694 MD-SAL routing behavior is modeled using following terminology and its
695 application to YANG models:
698 Logical type of RPC routing. Context type is modeled as YANG
699 ``identity`` and is referenced in model to provide scoping
703 Conceptual location in data tree, which represents context in which
704 RPC could be executed. Context instance usually represent logical
705 point to which RPC execution is attached.
708 Field of RPC input payload which contains Instance Identifier
709 referencing **context instance** in which the RPC should be
712 Modeling a routed RPC
713 ~~~~~~~~~~~~~~~~~~~~~
715 In order to define routed RPCs, the YANG model author needs to declare
716 (or reuse) a **context type**, set of possible **context instances** and
717 finally RPCs which will contain **context reference** on which they will
720 Declaring a routing context type
721 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
725 identity node-context {
726 description "Identity used to mark node context";
729 This declares an identity named ``node-context``, which is used as
730 marker for node-based routing and is used in other places to reference
733 Declaring possible context instances
734 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
736 In order to define possible values of **context instances** for routed
737 RPCs, we need to model that set accordingly using ``context-instance``
738 extension from the ``yang-ext`` model.
742 import yang-ext { prefix ext; }
744 /** Base structure **/
748 ext:context-instance "node-context";
749 // other node-related fields would go here
753 The statement ``ext:context-instance "node-context";`` marks any element
754 of the ``list node`` as a possible valid **context instance** in
755 ``node-context`` based routing.
759 The existence of a **context instance** node in operational or
760 config data tree is not strongly tied to existence of RPC
763 For most routed RPC models, there is relationship between the data
764 present in operational data tree and RPC implementation
765 availability, but this is not enforced by MD-SAL. This provides some
766 flexibility for YANG model writers to better specify their routing
767 model and requirements for implementations. Details when RPC
768 implementations are available should be documented in YANG model.
770 If user invokes RPC with a **context instance** that has no
771 registered implementation, the RPC invocation will fail with the
772 exception ``DOMRpcImplementationNotAvailableException``.
774 Declaring a routed RPC
775 ^^^^^^^^^^^^^^^^^^^^^^
777 To declare RPC to be routed based on ``node-context`` we need to add
778 leaf of ``instance-identifier`` type (or type derived from
779 ``instance-identifier``) to the RPC and mark it as **context
782 This is achieved using YANG extension ``context-reference`` from
783 ``yang-ext`` model on leaf, which will be used for RPC routing.
787 rpc example-routed-rpc {
790 ext:context-reference "node-context";
791 type "instance-identifier";
793 // other input to the RPC would go here
797 The statement ``ext:context-reference "node-context"`` marks
798 ``leaf node`` as **context reference** of type ``node-context``. The
799 value of this leaf, will be used by the MD-SAL to select the particular
800 RPC implementation that registered itself as the implementation of the
801 RPC for particular **context instance**.
806 From a user perspective (e.g. invoking RPCs) there is no difference
807 between routed and non-routed RPCs. Routing information is just an
808 additional leaf in RPC which must be populated.
810 Implementing a routed RPC
811 ~~~~~~~~~~~~~~~~~~~~~~~~~
815 Registering implementations
816 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
818 Implementations of a routed RPC (e.g., southbound plugins) will specify
819 an instance-identifier for the **context reference** (in this case a
820 node) for which they want to provide an implementation during
821 registration. Consumers, e.g., those calling the RPC are required to
822 specify that instance-identifier (in this case the identifier of a node)
825 Simple code which showcases that for add-flow via Binding-Aware APIs
826 (`RoutedServiceTest.java <https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blob;f=opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/RoutedServiceTest.java;h=d49d6f0e25e271e43c8550feb5eef63d96301184;hb=HEAD>`__
832 62 public void onSessionInitiated(ProviderContext session) {
833 63 assertNotNull(session);
834 64 firstReg = session.addRoutedRpcImplementation(SalFlowService.class, salFlowService1);
837 Line 64: We are registering salFlowService1 as implementation of
842 107 NodeRef nodeOne = createNodeRef("foo:node:1");
844 110 * Provider 1 registers path of node 1
846 112 firstReg.registerPath(NodeContext.class, nodeOne);
848 Line 107: We are creating NodeRef (encapsulation of InstanceIdentifier)
851 Line 112: We register salFlowService1 as implementation for nodeOne.
853 The salFlowService1 will be executed only for RPCs which contains
854 Instance Identifier for foo:node:1.
859 In case there is is only a single provider of an RPC in the cluster
860 the RPC registration is propagated to other nodes via Gossip protocol
861 and the RPC calls from other nodes are correctly routed to the
862 provider. Since the registrations are not expected to change rapidly
863 there is a latency of about 1 second until the registration is reflected
867 OpenDaylight Controller MD-SAL: RESTCONF
868 ----------------------------------------
870 RESTCONF operations overview
871 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
873 | RESTCONF allows access to datastores in the controller.
874 | There are two datastores:
876 - Config: Contains data inserted via controller
878 - Operational: Contains other data
882 | Each request must start with the URI /restconf.
883 | RESTCONF listens on port 8080 for HTTP requests.
885 RESTCONF supports **OPTIONS**, **GET**, **PUT**, **POST**, and
886 **DELETE** operations. Request and response data can either be in the
887 XML or JSON format. XML structures according to yang are defined at:
888 `XML-YANG <http://tools.ietf.org/html/rfc6020>`__. JSON structures are
890 `JSON-YANG <http://tools.ietf.org/html/draft-lhotka-netmod-yang-json-02>`__.
891 Data in the request must have a correctly set **Content-Type** field in
892 the http header with the allowed value of the media type. The media type
893 of the requested data has to be set in the **Accept** field. Get the
894 media types for each resource by calling the OPTIONS operation. Most of
895 the paths of the pathsRestconf endpoints use `Instance
896 Identifier <https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL:Concepts#Instance_Identifier>`__.
897 ``<identifier>`` is used in the explanation of the operations.
901 - It must start with <moduleName>:<nodeName> where <moduleName> is a
902 name of the module and <nodeName> is the name of a node in the
903 module. It is sufficient to just use <nodeName> after
904 <moduleName>:<nodeName>. Each <nodeName> has to be separated by /.
906 - <nodeName> can represent a data node which is a list or container
907 yang built-in type. If the data node is a list, there must be defined
908 keys of the list behind the data node name for example,
909 <nodeName>/<valueOfKey1>/<valueOfKey2>.
911 - | The format <moduleName>:<nodeName> has to be used in this case as
913 | Module A has node A1. Module B augments node A1 by adding node X.
914 Module C augments node A1 by adding node X. For clarity, it has to
915 be known which node is X (for example: C:X). For more details about
916 encoding, see: `RESTCONF 02 - Encoding YANG Instance Identifiers in
918 URI. <http://tools.ietf.org/html/draft-bierman-netconf-restconf-02#section-5.3.1>`__
923 | A Node can be behind a mount point. In this case, the URI has to be in
924 format <identifier>/**yang-ext:mount**/<identifier>. The first
925 <identifier> is the path to a mount point and the second <identifier>
926 is the path to a node behind the mount point. A URI can end in a mount
927 point itself by using <identifier>/**yang-ext:mount**.
928 | More information on how to actually use mountpoints is available at:
930 Controller:Config:Examples:Netconf <https://wiki.opendaylight.org/view/OpenDaylight_Controller:Config:Examples:Netconf>`__.
938 - Returns the XML description of the resources with the required
939 request and response media types in Web Application Description
942 GET /restconf/config/<identifier>
943 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
945 - Returns a data node from the Config datastore.
947 - <identifier> points to a data node which must be retrieved.
949 GET /restconf/operational/<identifier>
950 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
952 - Returns the value of the data node from the Operational datastore.
954 - <identifier> points to a data node which must be retrieved.
956 PUT /restconf/config/<identifier>
957 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
959 - Updates or creates data in the Config datastore and returns the state
962 - <identifier> points to a data node which must be stored.
968 PUT http://<controllerIP>:8080/restconf/config/module1:foo/bar
969 Content-Type: applicaton/xml
974 | **Example with mount point:**
978 PUT http://<controllerIP>:8080/restconf/config/module1:foo1/foo2/yang-ext:mount/module2:foo/bar
979 Content-Type: applicaton/xml
984 POST /restconf/config
985 ^^^^^^^^^^^^^^^^^^^^^
987 - Creates the data if it does not exist
993 POST URL: http://localhost:8080/restconf/config/
994 content-type: application/yang.data+json
1000 "toaster:toasterManufacturer" : "General Electric",
1001 "toaster:toasterModelNumber" : "123",
1002 "toaster:toasterStatus" : "up"
1006 POST /restconf/config/<identifier>
1007 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1009 - Creates the data if it does not exist in the Config datastore, and
1010 returns the state about success.
1012 - <identifier> points to a data node where data must be stored.
1014 - The root element of data must have the namespace (data are in XML) or
1015 module name (data are in JSON.)
1021 POST http://<controllerIP>:8080/restconf/config/module1:foo
1022 Content-Type: applicaton/xml/
1023 <bar xmlns=“module1namespace”>
1027 **Example with mount point:**
1031 http://<controllerIP>:8080/restconf/config/module1:foo1/foo2/yang-ext:mount/module2:foo
1032 Content-Type: applicaton/xml
1033 <bar xmlns=“module2namespace”>
1037 POST /restconf/operations/<moduleName>:<rpcName>
1038 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1042 - <moduleName>:<rpcName> - <moduleName> is the name of the module and
1043 <rpcName> is the name of the RPC in this module.
1045 - The Root element of the data sent to RPC must have the name “input”.
1047 - The result can be the status code or the retrieved data having the
1048 root element “output”.
1054 POST http://<controllerIP>:8080/restconf/operations/module1:fooRpc
1055 Content-Type: applicaton/xml
1056 Accept: applicaton/xml
1061 The answer from the server could be:
1066 | **An example using a JSON payload:**
1070 POST http://localhost:8080/restconf/operations/toaster:make-toast
1071 Content-Type: application/yang.data+json
1075 "toaster:toasterDoneness" : "10",
1076 "toaster:toasterToastType":"wheat-bread"
1082 Even though this is a default for the toasterToastType value in the
1083 yang, you still need to define it.
1085 DELETE /restconf/config/<identifier>
1086 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1088 - Removes the data node in the Config datastore and returns the state
1091 - <identifier> points to a data node which must be removed.
1093 More information is available in the `RESTCONF
1094 RFC <http://tools.ietf.org/html/draft-bierman-netconf-restconf-02>`__.
1099 | RESTCONF uses these base classes:
1102 Represents the path in the data tree
1105 Used for invoking RPCs
1108 Offers manipulation with transactions and reading data from the
1112 Holds information about yang modules
1115 Returns MountInstance based on the InstanceIdentifier pointing to a
1119 Contains the SchemaContext behind the mount point
1122 Provides information about the schema node
1125 Possesses the same name as the schema node, and contains the value
1126 representing the data node value
1129 Can contain CompositeNode-s and SimpleNode-s
1134 Figure 1 shows the GET operation with URI restconf/config/M:N where M is
1135 the module name, and N is the node name.
1137 .. figure:: ./images/Get.png
1142 1. The requested URI is translated into the InstanceIdentifier which
1143 points to the data node. During this translation, the DataSchemaNode
1144 that conforms to the data node is obtained. If the data node is
1145 behind the mount point, the MountInstance is obtained as well.
1147 2. RESTCONF asks for the value of the data node from DataBrokerService
1148 based on InstanceIdentifier.
1150 3. DataBrokerService returns CompositeNode as data.
1152 4. StructuredDataToXmlProvider or StructuredDataToJsonProvider is called
1153 based on the **Accept** field from the http request. These two
1154 providers can transform CompositeNode regarding DataSchemaNode to an
1155 XML or JSON document.
1157 5. XML or JSON is returned as the answer on the request from the client.
1162 Figure 2 shows the PUT operation with the URI restconf/config/M:N where
1163 M is the module name, and N is the node name. Data is sent in the
1164 request either in the XML or JSON format.
1166 .. figure:: ./images/Put.png
1171 1. Input data is sent to JsonToCompositeNodeProvider or
1172 XmlToCompositeNodeProvider. The correct provider is selected based on
1173 the Content-Type field from the http request. These two providers can
1174 transform input data to CompositeNode. However, this CompositeNode
1175 does not contain enough information for transactions.
1177 2. The requested URI is translated into InstanceIdentifier which points
1178 to the data node. DataSchemaNode conforming to the data node is
1179 obtained during this translation. If the data node is behind the
1180 mount point, the MountInstance is obtained as well.
1182 3. CompositeNode can be normalized by adding additional information from
1185 4. RESTCONF begins the transaction, and puts CompositeNode with
1186 InstanceIdentifier into it. The response on the request from the
1187 client is the status code which depends on the result from the
1193 1. Create a new flow on the switch openflow:1 in table 2.
1200 URI: http://192.168.11.1:8080/restconf/config/opendaylight-inventory:nodes/node/openflow:1/table/2
1201 Content-Type: application/xml
1205 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1207 xmlns="urn:opendaylight:flow:inventory">
1208 <strict>false</strict>
1220 <table_id>2</table_id>
1222 <cookie_mask>10</cookie_mask>
1223 <out_port>10</out_port>
1224 <installHw>false</installHw>
1225 <out_group>2</out_group>
1232 <ipv4-destination>10.0.0.1/24</ipv4-destination>
1234 <hard-timeout>0</hard-timeout>
1236 <idle-timeout>0</idle-timeout>
1237 <flow-name>FooXf22</flow-name>
1238 <priority>2</priority>
1239 <barrier>false</barrier>
1246 Status: 204 No Content
1248 1. Change *strict* to *true* in the previous flow.
1255 URI: http://192.168.11.1:8080/restconf/config/opendaylight-inventory:nodes/node/openflow:1/table/2/flow/111
1256 Content-Type: application/xml
1260 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1262 xmlns="urn:opendaylight:flow:inventory">
1263 <strict>true</strict>
1275 <table_id>2</table_id>
1277 <cookie_mask>10</cookie_mask>
1278 <out_port>10</out_port>
1279 <installHw>false</installHw>
1280 <out_group>2</out_group>
1287 <ipv4-destination>10.0.0.1/24</ipv4-destination>
1289 <hard-timeout>0</hard-timeout>
1291 <idle-timeout>0</idle-timeout>
1292 <flow-name>FooXf22</flow-name>
1293 <priority>2</priority>
1294 <barrier>false</barrier>
1303 1. Show flow: check that *strict* is *true*.
1310 URI: http://192.168.11.1:8080/restconf/config/opendaylight-inventory:nodes/node/openflow:1/table/2/flow/111
1311 Accept: application/xml
1321 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1323 xmlns="urn:opendaylight:flow:inventory">
1324 <strict>true</strict>
1336 <table_id>2</table_id>
1338 <cookie_mask>10</cookie_mask>
1339 <out_port>10</out_port>
1340 <installHw>false</installHw>
1341 <out_group>2</out_group>
1348 <ipv4-destination>10.0.0.1/24</ipv4-destination>
1350 <hard-timeout>0</hard-timeout>
1352 <idle-timeout>0</idle-timeout>
1353 <flow-name>FooXf22</flow-name>
1354 <priority>2</priority>
1355 <barrier>false</barrier>
1358 1. Delete the flow created.
1365 URI: http://192.168.11.1:8080/restconf/config/opendaylight-inventory:nodes/node/openflow:1/table/2/flow/111
1373 .. _config_subsystem:
1381 The Controller configuration operation has three stages:
1383 - First, a Proposed configuration is created. Its target is to replace
1384 the old configuration.
1386 - Second, the Proposed configuration is validated, and then committed.
1387 If it passes validation successfully, the Proposed configuration
1388 state will be changed to Validated.
1390 - Finally, a Validated configuration can be Committed, and the affected
1391 modules can be reconfigured.
1393 In fact, each configuration operation is wrapped in a transaction. Once
1394 a transaction is created, it can be configured, that is to say, a user
1395 can abort the transaction during this stage. After the transaction
1396 configuration is done, it is committed to the validation stage. In this
1397 stage, the validation procedures are invoked. If one or more validations
1398 fail, the transaction can be reconfigured. Upon success, the second
1399 phase commit is invoked. If this commit is successful, the transaction
1400 enters the last stage, committed. After that, the desired modules are
1401 reconfigured. If the second phase commit fails, it means that the
1402 transaction is unhealthy - basically, a new configuration instance
1403 creation failed, and the application can be in an inconsistent state.
1405 .. figure:: ./images/configuration.jpg
1406 :alt: Configuration states
1408 Configuration states
1410 .. figure:: ./images/Transaction.jpg
1411 :alt: Transaction states
1418 To secure the consistency and safety of the new configuration and to
1419 avoid conflicts, the configuration validation process is necessary.
1420 Usually, validation checks the input parameters of a new configuration,
1421 and mostly verifies module-specific relationships. The validation
1422 procedure results in a decision on whether the proposed configuration is
1428 Since there can be dependencies between modules, a change in a module
1429 configuration can affect the state of other modules. Therefore, we need
1430 to verify whether dependencies on other modules can be resolved. The
1431 Dependency Resolver acts in a manner similar to dependency injectors.
1432 Basically, a dependency tree is built.
1437 This section describes configuration system APIs and SPIs.
1442 **Module** org.opendaylight.controller.config.spi. Module is the common
1443 interface for all modules: every module must implement it. The module is
1444 designated to hold configuration attributes, validate them, and create
1445 instances of service based on the attributes. This instance must
1446 implement the AutoCloseable interface, owing to resources clean up. If
1447 the module was created from an already running instance, it contains an
1448 old instance of the module. A module can implement multiple services. If
1449 the module depends on other modules, setters need to be annotated with
1454 1. The module needs to be configured, set with all required attributes.
1456 2. The module is then moved to the commit stage for validation. If the
1457 validation fails, the module attributes can be reconfigured.
1458 Otherwise, a new instance is either created, or an old instance is
1459 reconfigured. A module instance is identified by ModuleIdentifier,
1460 consisting of the factory name and instance name.
1462 | **ModuleFactory** org.opendaylight.controller.config.spi. The
1463 ModuleFactory interface must be implemented by each module factory.
1464 | A module factory can create a new module instance in two ways:
1466 - From an existing module instance
1468 - | An entirely new instance
1469 | ModuleFactory can also return default modules, useful for
1470 populating registry with already existing configurations. A module
1471 factory implementation must have a globally unique name.
1476 +--------------------------------------+--------------------------------------+
1477 | ConfigRegistry | Represents functionality provided by |
1478 | | a configuration transaction (create, |
1479 | | destroy module, validate, or abort |
1481 +--------------------------------------+--------------------------------------+
1482 | ConfigTransactionController | Represents functionality for |
1483 | | manipulating with configuration |
1484 | | transactions (begin, commit config). |
1485 +--------------------------------------+--------------------------------------+
1486 | RuntimeBeanRegistratorAwareConfiBean | The module implementing this |
1487 | | interface will receive |
1488 | | RuntimeBeanRegistrator before |
1489 | | getInstance is invoked. |
1490 +--------------------------------------+--------------------------------------+
1495 +--------------------------------------+--------------------------------------+
1496 | RuntimeBean | Common interface for all runtime |
1498 +--------------------------------------+--------------------------------------+
1499 | RootRuntimeBeanRegistrator | Represents functionality for root |
1500 | | runtime bean registration, which |
1501 | | subsequently allows hierarchical |
1503 +--------------------------------------+--------------------------------------+
1504 | HierarchicalRuntimeBeanRegistration | Represents functionality for runtime |
1505 | | bean registration and |
1506 | | unreregistration from hierarchy |
1507 +--------------------------------------+--------------------------------------+
1512 | JMX API is purposed as a transition between the Client API and the JMX
1515 +--------------------------------------+--------------------------------------+
1516 | ConfigTransactionControllerMXBean | Extends ConfigTransactionController, |
1517 | | executed by Jolokia clients on |
1518 | | configuration transaction. |
1519 +--------------------------------------+--------------------------------------+
1520 | ConfigRegistryMXBean | Represents entry point of |
1521 | | configuration management for |
1523 +--------------------------------------+--------------------------------------+
1524 | Object names | Object Name is the pattern used in |
1525 | | JMX to locate JMX beans. It consists |
1526 | | of domain and key properties (at |
1527 | | least one key-value pair). Domain is |
1529 | | "org.opendaylight.controller". The |
1530 | | only mandatory property is "type". |
1531 +--------------------------------------+--------------------------------------+
1536 | A few samples of successful and unsuccessful transaction scenarios
1539 **Successful commit scenario**
1541 1. The user creates a transaction calling creteTransaction() method on
1544 2. ConfigRegisty creates a transaction controller, and registers the
1545 transaction as a new bean.
1547 3. Runtime configurations are copied to the transaction. The user can
1548 create modules and set their attributes.
1550 4. The configuration transaction is to be committed.
1552 5. The validation process is performed.
1554 6. After successful validation, the second phase commit begins.
1556 7. Modules proposed to be destroyed are destroyed, and their service
1557 instances are closed.
1559 8. Runtime beans are set to registrator.
1561 9. The transaction controller invokes the method getInstance on each
1564 10. The transaction is committed, and resources are either closed or
1567 | **Validation failure scenario**
1568 | The transaction is the same as the previous case until the validation
1571 1. If validation fails, (that is to day, illegal input attributes values
1572 or dependency resolver failure), the validationException is thrown
1573 and exposed to the user.
1575 2. The user can decide to reconfigure the transaction and commit again,
1576 or abort the current transaction.
1578 3. On aborted transactions, TransactionController and JMXRegistrator are
1581 4. Unregistration event is sent to ConfigRegistry.
1583 Default module instances
1584 ^^^^^^^^^^^^^^^^^^^^^^^^
1586 The configuration subsystem provides a way for modules to create default
1587 instances. A default instance is an instance of a module, that is
1588 created at the module bundle start-up (module becomes visible for
1589 configuration subsystem, for example, its bundle is activated in the
1590 OSGi environment). By default, no default instances are produced.
1592 The default instance does not differ from instances created later in the
1593 module life-cycle. The only difference is that the configuration for the
1594 default instance cannot be provided by the configuration subsystem. The
1595 module has to acquire the configuration for these instances on its own.
1596 It can be acquired from, for example, environment variables. After the
1597 creation of a default instance, it acts as a regular instance and fully
1598 participates in the configuration subsystem (It can be reconfigured or
1599 deleted in following transactions.).