Inital commit

This commit is contained in:
Olof hagsand 2016-02-22 22:17:30 +01:00
parent edc5e091bb
commit d6e393ea58
145 changed files with 58117 additions and 0 deletions

51
CHANGELOG Normal file
View file

@ -0,0 +1,51 @@
# Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
#
# This file is part of CLICON.
#
# CLICON is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# CLICON is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with CLICON; see the file COPYING. If not, see
# <http://www.gnu.org/licenses/>.
- New option: CLICON_DB_XML with new xml-based database. This makes more efficient
implementation of yang-based applications.
- Changed yang type lookup to be lexically instead of dynamically scoped (as
they should) by using a cache (yang_type_cache).
- Added support for yang 'max' range keyword
- Added option: CLICON_YANG_MODULE_REVISION
- Cleaned up xml translation functions in clicon_xml_map.c
- Extended client/backend protocol with dumping a database config: CLICON_MSG_DBITEMS
- Removed -a (appdir) config options. Use only -f <config-file>.
- Added INET (IPv4) communication between client and backend. Not only UNIX. Experimental.
- Removed clicon_dbmatch.[ch]. Replaced with clicon_dbitems_match().
- Replaced internal clicon_proto_ messaging API with clicon_rpc_.
- Extended tree-based access functions: clicon_dbget_parent/children/descendents/xpath.
- clicon_dbctrl: Renamed brief option from -P to -b and made it work with -m
- Reference documentation using doxygen: make doc, make graphs
- When entering CLI commands, they appear in the same order in xml and reload.
- yang parse error using '+' in strings
- New example: clicon_yang for stateless yang experiments (no backend)
- Event subscription API: add/delete/each
- Long-term mem-leak in chunk-code
- xml parser did not support "<a></a>" only "</a>"
- fixed error in event-loop if timers are used: events before now caused hanging
R3.0.0 23 February 2015
=======================
This is a new major CLICON release.
The changes from previous versions are too numerous to document.
Major recent additions are:
- Added python API
- YANG modeling support
- Updated commit callback API
- Asynchronous notifications
- db2txt

632
COPYING Normal file
View file

@ -0,0 +1,632 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
Note the following clarification from the GNU FAQ concerning plugins
(CLIXON uses cli, netconf and backend plugins that comply to this):
If the program dynamically links plug-ins, and they make function
calls to each other and share data structures, we believe they form a
single program, which must be treated as an extension of both the main
program and the plug-ins. This means the plug-ins must be released
under the GPL or a GPL-compatible free software license, and that the
terms of the GPL must be followed when those plug-ins are distributed.

112
Makefile.in Normal file
View file

@ -0,0 +1,112 @@
#
# Makefile
#
#
# Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
#
# This file is part of CLICON.
#
# CLICON is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# CLICON is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with CLICON; see the file COPYING. If not, see
# <http://www.gnu.org/licenses/>.
#
prefix = @prefix@
exec_prefix = @exec_prefix@
# abs_top_builddir is by default the absolute path of the builddir.
includedir = @includedir@
datadir = @datarootdir@
localstatedir = @localstatedir@
sysconfdir = @sysconfdir@
VPATH = @srcdir@
srcdir = @srcdir@
libdir = @libdir@
top_srcdir = @top_srcdir@
CC = @CC@
CFLAGS = @CFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
#INSTALL = @INSTALL@
INCLUDES = -I. -I@srcdir@ @INCLUDES@
SHELL = /bin/sh
SUBDIRS = lib apps include doc etc
.PHONY: doc all clean depend $(SUBDIRS) install loc TAGS .config.status
all: $(SUBDIRS) clicon.conf.cpp clicon.mk
$(SUBDIRS):
(cd $@ && $(MAKE) $(MFLAGS) all)
depend:
for i in $(SUBDIRS) example; \
do (cd $$i && $(MAKE) $(MFLAGS) depend); done
# template clicon.conf file
clicon.conf.cpp: clicon.conf.cpp.cpp
$(CPP) -P -x assembler-with-cpp -Dprefix=$(prefix) -Dlocalstatedir=$(localstatedir) -Dsysconfdir=$(sysconfdir) -Ddatadir=$(datadir) -Dlibdir=$(libdir) $< > $@
clicon.mk: clicon.mk.cpp
$(CPP) -P -traditional-cpp -x assembler-with-cpp -Dprefix=$(prefix) -Dlocalstatedir=$(localstatedir) -Dsysconfdir=$(sysconfdir) -Ddatadir=$(datadir) -Dlibdir=$(libdir) $< > $@
install: clicon.conf.cpp clicon.mk
for i in $(SUBDIRS); \
do (cd $$i && $(MAKE) $(MFLAGS) $@); done; \
install -d -m 755 $(DESTDIR)$(datadir)/clicon
install -m 755 clicon.conf.cpp $(DESTDIR)$(datadir)/clicon
install -m 755 clicon.mk $(DESTDIR)$(datadir)/clicon
echo "Install for compilation by: make install-include"
install-include:
for i in $(SUBDIRS); \
do (cd $$i && $(MAKE) $(MFLAGS) $@); done; \
echo "To install example app: cd example; make; make install"
uninstall:
for i in $(SUBDIRS) example; \
do (cd $$i && $(MAKE) $(MFLAGS) $@); done;
rm -f $(datadir)/clicon/clicon.conf.cpp
rm -f $(datadir)/clicon/clicon.mk
# Overrides SUBDIRS above
#doc:
# cd $@; $(MAKE) $(MFLAGS) $@
config.status: configure
$(SHELL) config.status --recheck
configure: configure.ac
cd $(srcdir) && autoconf
clean:
for i in $(SUBDIRS) example; \
do (cd $$i && $(MAKE) $(MFLAGS) $@); done;
distclean:
rm -f Makefile TAGS config.status config.log *~ .depend
rm -rf Makefile autom4te.cache
rm -rf clicon.conf.cpp clicon.mk
for i in $(SUBDIRS) example; \
do (cd $$i && $(MAKE) $(MFLAGS) $@); done
# Lines of code
loc:
find . -name '*.[chyl]' -type f | xargs wc -l | tail -1 2> /dev/null
TAGS:
find $(srcdir) -name '*.[chyl]' -type f | grep -v \.tab\.[ch] | grep -v lex.*.c | grep -v .yy.c | etags -

72
README Normal file
View file

@ -0,0 +1,72 @@
This README contains information for developers:
1. How to document the code
2. How to work in git (branching)
3. How the meta-configure stuff works
1. How to document the code
+++++++++++++++++++++++++++
Create documentation:
cd doc
make doc
make graphs # callgraphs
/*! This is a small comment on one line
*
* This is a detailed description
* spanning several lines.
*
* Example usage:
* @code
* fn(a, &b);
* @endcode
*
* @param[in] src This is a description of the first parameter
* @param[in,out] dest This is a description of the second parameter
* @retval TRUE This is a description of the return value
* @retval FALSE This is a description of another return value
* @see See also this function
*/
2. How to work in git (branching)
+++++++++++++++++++++++++++++++++
Baically follows: http://nvie.com/posts/a-successful-git-branching-model/
only somewhat simplified:
Do commits in develop branch. When done, merge with master.
($ git checkout -b develop master # create develop)
$ git checkout develop
Switch to branch develop
$ git add ..
$ git commit ..
$ git push origin develop
Add/commit stuff here (and push)
Ready for tagging
-----------------
(This is somewhat simplified - no release branch)
$ ./bump-version.sh 3.6.0
Files modified successfully, version bumped to 3.6.0
$ git checkout master
Switch to master
$ git merge --no-ff develop
Merge made by recursive.
(Summary of changes)
$ git tag -a 3.6.0
3. How the meta-configure stuff works
+++++++++++++++++++++++++++++++++++++
configure.ac --.
| .------> autoconf* -----> configure
[aclocal.m4] --+---+
| `-----> [autoheader*] --> [config.h.in]
[acsite.m4] ---'
.-------------> [config.cache]
configure* ------------+-------------> config.log
|
[config.h.in] -. v .-> [config.h] -.
+--> config.status* -+ +--> make*
Makefile.in ---' `-> Makefile ---'

68
README.develop Normal file
View file

@ -0,0 +1,68 @@
This README contains information for developers:
1. How to document the code
2. How to work in git (branching)
3. How the meta-configure stuff works
1. How to document the code
+++++++++++++++++++++++++++
/*! This is a small comment on one line
*
* This is a detailed description
* spanning several lines.
*
* Example usage:
* @code
* fn(a, &b);
* @endcode
*
* @param[in] src This is a description of the first parameter
* @param[in,out] dest This is a description of the second parameter
* @retval TRUE This is a description of the return value
* @retval FALSE This is a description of another return value
* @see See also this function
*/
2. How to work in git (branching)
+++++++++++++++++++++++++++++++++
Baically follows: http://nvie.com/posts/a-successful-git-branching-model/
only somewhat simplified:
Do commits in develop branch. When done, merge with master.
$ git checkout develop
Switch to branch develop
$ git add ..
$ git commit ..
$ git push origin develop
Add/commit stuff here (and push)
Ready for tagging
-----------------
(This is somewhat simplified - no release branch)
$ ./bump-version.sh 3.6.0
Files modified successfully, version bumped to 3.6.0
$ git checkout master
Switch to master
$ git merge --no-ff develop
Merge made by recursive.
(Summary of changes)
$ git tag -a 3.6.0
3. How the meta-configure stuff works
+++++++++++++++++++++++++++++++++++++
configure.ac --.
| .------> autoconf* -----> configure
[aclocal.m4] --+---+
| `-----> [autoheader*] --> [config.h.in]
[acsite.m4] ---'
.-------------> [config.cache]
configure* ------------+-------------> config.log
|
[config.h.in] -. v .-> [config.h] -.
+--> config.status* -+ +--> make*
Makefile.in ---' `-> Makefile ---'

31
README.doxygen Normal file
View file

@ -0,0 +1,31 @@
/*! This is a small comment on one line
*
* This is a detailed description
* spanning several lines.
*
* Example usage:
* @code
* fn(a, &b);
* @endcode
*
* @param[in] src This is a description of the first parameter
* @param[in,out] dest This is a description of the second parameter
* @retval TRUE This is a description of the return value
* @retval FALSE This is a description of another return value
* @see anotherfn()
* @note This is just an example
*/
/*! This is a documentation of a typedef or struct
*
* This is a detailed description
* spanning several lines.
*
* Example usage:
* @code
* struct foo f;
* @endcode
*/
typedef foo{
int a; /**< This is the a field*/
};

37
README.md Normal file
View file

@ -0,0 +1,37 @@
CLIXON
======
CLIXON is an automatic configuration manager where you from a YANG
specification generate interactive CLI, NETCONF and embedded
databases with transaction support.
CLIXON is a fork of CLICON where legacy key specification has been
replaced completely by YANG. This means that legacy CLICON
applications such as CLICON/ROST does not run on CLIXON.
Presentations and tutorial is found on the [CLICON project
page](http://www.clicon.org)
A typical installation is as follows:
> configure # Configure clixon to platform
> make # Compile
> sudo make install # Install libs, binaries, and config-files
> sudo make install-include # Install include files (for compiling)
One example applications is provided, the IETF IP YANG datamodel with generated CLI and configuration interface. It all origins from work at
[KTH](http://www.csc.kth.se/~olofh/10G_OSR)
[CLIgen](http://www.cligen.se) is required for building CLIXON. If you need
to build and install CLIgen:
git clone https://github.com/olofhagsand/cligen.git
cd cligen; configure; make; make install
CLIXON is covered by GPLv3, and is also available with commercial license.
See COPYING for license, CHANGELOG for recent changes.

68
apps/Makefile.in Normal file
View file

@ -0,0 +1,68 @@
#
# Makefile
#
# Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
#
# This file is part of CLICON.
#
# CLICON is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# CLICON is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with CLICON; see the file COPYING. If not, see
# <http://www.gnu.org/licenses/>.
#
#
VPATH = @srcdir@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
CC = @CC@
CFLAGS = @CFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
SHELL = /bin/sh
SUBDIRS = cli backend dbctrl netconf
.PHONY: all clean depend install $(SUBDIRS)
all: $(SUBDIRS)
depend:
for i in $(SUBDIRS); \
do (cd $$i; $(MAKE) $(MFLAGS) $@); done
$(SUBDIRS):
(cd $@; $(MAKE) $(MFLAGS) all)
install-include:
for i in $(SUBDIRS); \
do (cd $$i ; $(MAKE) $(MFLAGS) $@); done;
install:
for i in $(SUBDIRS); \
do (cd $$i; $(MAKE) $(MFLAGS) $@); done
uninstall:
for i in $(SUBDIRS); \
do (cd $$i; $(MAKE) $(MFLAGS) $@); done
clean:
for i in $(SUBDIRS); \
do (cd $$i; $(MAKE) $(MFLAGS) $@); done
distclean: clean
rm -f Makefile *~ .depend
for i in $(SUBDIRS); \
do (cd $$i; $(MAKE) $(MFLAGS) $@); done
tags:
find $(srcdir) -name '*.[chyl]' -print | etags -

137
apps/backend/Makefile.in Normal file
View file

@ -0,0 +1,137 @@
#
# Makefile
#
# Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
#
# This file is part of CLICON.
#
# CLICON is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# CLICON is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with CLICON; see the file COPYING. If not, see
# <http://www.gnu.org/licenses/>.
#
#
VPATH = @srcdir@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
CC = @CC@
CFLAGS = @CFLAGS@
LDFLAGS = @LDFLAGS@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
libdir = @libdir@
sbindir = @sbindir@
libexecdir = @libexecdir@
localstatedir = @localstatedir@
sysconfdir = @sysconfdir@
includedir = @includedir@
SH_SUFFIX = @SH_SUFFIX@
CLICON_MAJOR = @CLICON_VERSION_MAJOR@
CLICON_MINOR = @CLICON_VERSION_MINOR@
# Use this clicon lib for linking
CLICON_LIB = libclicon.so.$(CLICON_MAJOR).$(CLICON_MINOR)
# Location of system plugins
CLICON_BACKEND_SYSDIR = $(libdir)/clicon/plugins/backend
# For dependency. A little strange that we rely on it being built in the src dir
# even though it may exist in $(libdir). But the new version may not have been installed yet.
LIBDEPS = $(top_srcdir)/lib/src/$(CLICON_LIB)
LIBS = -L$(top_srcdir)/lib/src @LIBS@ -l:$(CLICON_LIB) -lpthread
CPPFLAGS = @CPPFLAGS@ -fPIC
INCLUDES = -I. -I$(top_srcdir)/lib/src -I$(top_srcdir)/lib -I$(top_srcdir)/include -I$(top_srcdir) @INCLUDES@
# Not accessible from plugin
APPSRC = backend_main.c backend_socket.c backend_client.c \
backend_lock.c backend_commit.c backend_plugin.c
APPOBJ = $(APPSRC:.c=.o)
APPL = clicon_backend
#SHLIB = clicon_backend
MYNAME = clicon_backend
MYLIBLINK = lib$(MYNAME)$(SH_SUFFIX)
MYLIB = $(MYLIBLINK).$(CLICON_MAJOR).$(CLICON_MINOR)
MYLIBSO = $(MYLIBLINK).$(CLICON_MAJOR)
# Accessible from plugin
LIBSRC = clicon_backend_transaction.c clicon_backend_handle.c
LIBOBJ = $(LIBSRC:.c=.o)
all: $(MYLIB) $(APPL) test
clean:
rm -f *.core $(APPL) $(APPOBJ) $(LIBOBJ) $(MYLIB) $(MYLIBSO) $(MYLIBLINK)
distclean: clean
rm -f Makefile *~ .depend
# Put demon in bin
# Put other executables in libexec/
# Also create a libexec/ directory for writeable/temporary files.
# Put config file in etc/
install: install-lib $(APPL)
install -d $(DESTDIR)$(sbindir)
install $(APPL) $(DESTDIR)$(sbindir)
install-lib: $(MYLIB)
install -d $(DESTDIR)$(libdir)
install $(MYLIB) $(DESTDIR)$(libdir)
ln -sf $(MYLIB) $(DESTDIR)$(libdir)/$(MYLIBSO) # -l:libclicon_config.so.2
ln -sf $(MYLIBSO) $(DESTDIR)$(libdir)/$(MYLIBLINK) # -l:libclicon_config.so
install -d $(DESTDIR)$(libdir)/clicon/plugins/backend
uninstall:
rm -f $(sbindir)/$(APPL)
rm -f $(libdir)/$(MYLIB)
rm -f $(includedir)/clicon/*
install-include: clicon_backend.h clicon_backend_api.h
install -d $(DESTDIR)$(includedir)/clicon
install -m 644 $^ $(DESTDIR)$(includedir)/clicon
.SUFFIXES:
.SUFFIXES: .c .o
.c.o:
$(CC) $(INCLUDES) -D__PROGRAM__=\"$(APPL)\" -DCLICON_BACKEND_SYSDIR=\"$(CLICON_BACKEND_SYSDIR)\" $(CPPFLAGS) $(CFLAGS) -c $<
# Just link test programs
test.c :
echo "main(){}" > $@
test: test.c $(LIBOBJ)
$(CC) $(INCLUDES) $(LDFLAGS) $< $(LIBOBJ) -L. -l:$(MYLIB) $(LIBS) -o $@
$(APPL) : $(APPOBJ) $(MYLIBLINK) $(LIBDEPS)
$(CC) $(LDFLAGS) $(APPOBJ) $(OBJS) -L. -l:$(MYLIB) $(LIBS) -o $@
$(MYLIB): $(LIBOBJ)
$(CC) $(LDFLAGS) -shared -Wl,-soname,$(MYLIBSO) -o $@ -lc $(LIBOBJ) -Wl,-soname=$(MYLIBSO)
# link-name is needed for application linking, eg for clicon_cli and clicon_backend
$(MYLIBLINK) : $(MYLIB)
# ln -sf $(MYLIB) $(MYLIBSO)
# ln -sf $(MYLIB) $@
TAGS:
find . -name '*.[chyl]' -print | etags -
depend:
$(CC) $(DEPENDFLAGS) @DEFS@ $(INCLUDES) $(CFLAGS) -MM $(SRC) $(APPSRC) > .depend
#include .depend

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,64 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef _BACKEND_CLIENT_H_
#define _BACKEND_CLIENT_H_
/*
* Types
*/
/*
* Client entry.
* Keep state about every connected client.
*/
struct client_entry{
struct client_entry *ce_next; /* The clients linked list */
struct sockaddr ce_addr; /* The clients (UNIX domain) address */
int ce_s; /* stream socket to client */
int ce_nr; /* Client number (for dbg/tracing) */
int ce_stat_in; /* Nr of received msgs from client */
int ce_stat_out;/* Nr of sent msgs to client */
int ce_pid; /* Process id */
int ce_uid; /* User id of calling process */
clicon_handle ce_handle; /* clicon config handle (all clients have same?) */
struct client_subscription *ce_subscription; /* notification subscriptions */
};
/* Notification subscription info
* @see subscription in config_handle.c
*/
struct client_subscription{
struct client_subscription *su_next;
int su_s; /* stream socket */
enum format_enum su_format; /* format of notification stream */
char *su_stream;
char *su_filter;
};
/*
* Prototypes
*/
int backend_client_rm(clicon_handle h, struct client_entry *ce);
int config_snapshot(clicon_handle h, char *dbname, char *dir);
int from_client(int fd, void *arg);
#endif /* _BACKEND_CLIENT_H_ */

View file

@ -0,0 +1,684 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "clicon_config.h" /* generated by config & autoconf */
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <time.h>
#include <pwd.h>
#include <syslog.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <netinet/in.h>
/* cligen */
#include <cligen/cligen.h>
/* clicon */
#include <clicon/clicon.h>
#include "clicon_backend_transaction.h"
#include "backend_plugin.h"
#include "backend_handle.h"
#include "backend_commit.h"
#include "backend_client.h"
/*! Key values are checked for validity independent of user-defined callbacks
*
* Key values are checked as follows:
* 1. If no value and default value defined, add it.
* 2. If no value and mandatory flag set in spec, report error.
* 3. Validate value versus spec, and report error if no match. Currently only int ranges and
* string regexp checked.
* See also db_lv_set() where defaults are also filled in. The case here for defaults
* are if code comes via XML/NETCONF.
* @param yspec Yang spec
* @param td Transaction data
*/
static int
generic_validate(yang_spec *yspec,
transaction_data_t *td)
{
int retval = -1;
cxobj *x1;
cxobj *x2;
int i;
yang_stmt *ys;
/* changed entries */
for (i=0; i<td->td_clen; i++){
x1 = td->td_scvec[i]; /* source changed */
x2 = td->td_tcvec[i]; /* target changed */
ys = xml_spec(x1);
if (xml_yang_validate(x2, ys) < 0)
goto done;
}
/* deleted entries */
for (i=0; i<td->td_dlen; i++){
x1 = td->td_dvec[i];
ys = xml_spec(x1);
if (yang_mandatory(ys)){
clicon_err(OE_CFG, 0,"Removed mandatory variable: %s",
xml_name(x1));
goto done;
}
}
/* added entries */
for (i=0; i<td->td_alen; i++){
x2 = td->td_avec[i];
if (xml_yang_validate(x2, xml_spec(x2)) < 0)
goto done;
if (xml_apply(x2, CX_ELMNT,
(xml_applyfn_t*)xml_yang_validate, NULL) < 0)
goto done;
}
retval = 0;
done:
return retval;
}
/*! Do a diff between candidate and running, then start a commit transaction
*
* The code reverts changes if the commit fails. But if the revert
* fails, we just ignore the errors and proceed. Maybe we should
* do something more drastic?
* @param[in] h Clicon handle
* @param[in] running The current database. The original backend state
* @param[in] candidate: The candidate database. The wanted backend state
*/
int
candidate_commit(clicon_handle h,
char *candidate,
char *running)
{
int retval = -1;
// int i, j;
// int failed = 0;
struct stat sb;
void *firsterr = NULL;
yang_spec *yspec;
transaction_data_t *td = NULL;
if ((yspec = clicon_dbspec_yang(h)) == NULL){
clicon_err(OE_FATAL, 0, "No DB_SPEC");
goto done;
}
/* Sanity checks that databases exists. */
if (stat(running, &sb) < 0){
clicon_err(OE_DB, errno, "%s", running);
goto done;
}
if (stat(candidate, &sb) < 0){
clicon_err(OE_DB, errno, "%s", candidate);
goto done;
}
/* 1. Start transaction */
if ((td = transaction_new()) == NULL)
goto done;
/* 2. Parse xml trees */
if (xmldb_get(running, "/", yspec, &td->td_src) < 0)
goto done;
if (xmldb_get(candidate, "/", yspec, &td->td_target) < 0)
goto done;
/* 3. Compute differences */
if (xml_diff(yspec,
td->td_src,
td->td_target,
&td->td_dvec, /* removed: only in running */
&td->td_dlen,
&td->td_avec, /* added: only in candidate */
&td->td_alen,
&td->td_scvec, /* changed: original values */
&td->td_tcvec, /* changed: wanted values */
&td->td_clen) < 0)
goto done;
if (debug)
transaction_print(stderr, td);
/* 4. Call plugin transaction start callbacks */
if (plugin_transaction_begin(h, td) < 0)
goto done;
/* 5. Make generic validation on all new or changed data. */
if (generic_validate(yspec, td) < 0)
goto done;
/* 6. Call plugin transaction validate callbacks */
if (plugin_transaction_validate(h, td) < 0)
goto done;
/* 7. Call plugin transaction complete callbacks */
if (plugin_transaction_complete(h, td) < 0)
goto done;
/* 7. Call plugin transaction commit callbacks */
if (plugin_transaction_commit(h, td) < 0)
goto done;
/* 8. Copy running back to candidate in case end functions triggered
updates in running */
if (file_cp(running, candidate) < 0){
/* ignore errors or signal major setback ? */
clicon_err(OE_UNIX, errno, "file_cp(running, candidate)");
clicon_log(LOG_NOTICE, "Error in rollback, trying to continue");
goto done;
}
/* 9. Call plugin transaction end callbacks */
plugin_transaction_end(h, td);
#ifdef OBSOLETE
/* Find the differences between the two databases and store it in df vector. */
memset(&df, 0, sizeof(df));
if (db_diff(running, candidate,
__FUNCTION__,
clicon_dbspec_key(h),
&df
) < 0)
goto done;
if (debug){
struct dbdiff_ent *dfe;
for (i=0; i<df.df_nr; i++) {
dfe = &df.df_ents[i];
clicon_debug(1, "%s op:%d key:%s",
__FUNCTION__,
dfe->dfe_op,
cvec_name_get(dfe->dfe_vec1?dfe->dfe_vec1:dfe->dfe_vec2));
}
}
/* 1. Get commit processing to dbdiff vector: one entry per key that changed.
changes are registered as if they exist in the 1st(candidate) or
2nd(running) dbs.
*/
if (dbdep_commitvec(h, &df, &nvec, &ddvec) < 0)
goto done;
/* 2. Call transaction_begin hooks */
if (plugin_transaction_begin(h) < 0)
goto done;
/* call generic cv_validate() on all new or changed keys. */
if (generic_validate(yspec, NULL) < 0)
goto done;
/* user-defined validate callbacks registered in dbdep_validate */
// if (validate_db(h, nvec, ddvec, running, candidate) < 0)
// goto done;
/* Call plugin post-commit hooks */
if (plugin_transaction_complete(h) < 0)
goto done;
if (clicon_commit_order(h) == 0){
for (i=0; i < nvec; i++){ /* revert in opposite order */
dd = &ddvec[i];
dp = dd->dd_dep; /* op, callback, arg */
if ((dp->dp_type & TRANS_CB_COMMIT) == 0)
continue;
dfe = dd->dd_dbdiff; /* key1/key2/op */
op = dbdiff2commit_op(dfe->dfe_op);
if (plugin_commit_callback(h,
op, /* oper */
running, /* db1 */
candidate, /* db2 */
dd->dd_mkey1, /* key1 */
dd->dd_mkey2, /* key2 */
dd->dd_dbdiff->dfe_vec1, /* vec1 */
dd->dd_dbdiff->dfe_vec2, /* vec2 */
dp /* callback */
) < 0){
firsterr = clicon_err_save(); /* save this error */
failed++;
break;
}
}
if (!failed)
if (file_cp(candidate, running) < 0){ /* Commit here in case cp fails */
clicon_err(OE_UNIX, errno, "file_cp");
failed++;
}
/* Failed operation, start error handling: rollback in opposite order */
if (failed){
for (j=i-1; j>=0; j--){ /* revert in opposite order */
dd = &ddvec[j];
dp = dd->dd_dep; /* op, callback, arg */
if ((dp->dp_type & TRANS_CB_COMMIT) == 0)
continue;
dfe = dd->dd_dbdiff; /* key1/key2/op */
op = dbdiff2commit_op(dfe->dfe_op);
switch (op){ /* reverse operation */
case CO_ADD:
op = CO_DELETE;
break;
case CO_DELETE:
op = CO_ADD;
break;
default:
break;
}
if (plugin_commit_callback(h,
op, /* oper */
candidate, /* db1 */
running, /* db2 */
dd->dd_mkey2, /* key1 */
dd->dd_mkey1, /* key2 */
dd->dd_dbdiff->dfe_vec2, /* vec1 */
dd->dd_dbdiff->dfe_vec1, /* vec2 */
dp /* callback */
) < 0){
/* ignore errors or signal major setback ? */
clicon_log(LOG_NOTICE, "Error in rollback, trying to continue");
continue;
}
}
goto done;
} /* error handling */
}
else { /* commit_order == 1 or 2 */
/* Now follows commit rules in order.
* 4. For all keys that are not in candidate but in running, delete key
* in reverse prio order
*/
for (i = nvec-1; i >= 0; i--){
dd = &ddvec[i];
dp = dd->dd_dep; /* op, callback, arg */
if ((dp->dp_type & TRANS_CB_COMMIT) == 0)
continue;
dfe = dd->dd_dbdiff; /* key1/key2/op */
op = dbdiff2commit_op(dfe->dfe_op);
/* original mode 2 where CHANGE=DEL/ADD */
if (clicon_commit_order(h) == 2 && op == CO_CHANGE)
op = CO_DELETE;
if (op != CO_DELETE)
continue;
if (plugin_commit_callback(h,
op, /* oper */
running, /* db1 */
candidate, /* db2 */
dd->dd_mkey1, /* key1 */
dd->dd_mkey2, /* key2 */
dd->dd_dbdiff->dfe_vec1, /* vec1 */
dd->dd_dbdiff->dfe_vec2, /* vec2 */
dp /* callback */
) < 0){
firsterr = clicon_err_save(); /* save this error */
break;
}
}
/* 5. Failed deletion, add the key value back to running */
if (i >= 0){ /* failed */
for (j=i+1; j<nvec; j++){ /* revert in opposite order */
dd = &ddvec[j];
dp = dd->dd_dep; /* op, callback, arg */
if ((dp->dp_type & TRANS_CB_COMMIT) == 0)
continue;
dfe = dd->dd_dbdiff; /* key1/key2/op */
op = dbdiff2commit_op(dfe->dfe_op);
/* original mode 2 where CHANGE=DEL/ADD */
if (clicon_commit_order(h) == 2 && op == CO_CHANGE)
op = CO_DELETE;
if (op != CO_DELETE)
continue;
if (plugin_commit_callback(h,
op, /* oper */
candidate, /* db1 */
running, /* db2 */
dd->dd_mkey2, /* key1 */
dd->dd_mkey1, /* key2 */
dd->dd_dbdiff->dfe_vec2, /* vec1 */
dd->dd_dbdiff->dfe_vec1, /* vec2 */
dp /* callback */
) < 0){
/* ignore errors or signal major setback ? */
clicon_log(LOG_NOTICE, "Error in rollback, trying to continue");
continue;
}
}
goto done;
}
/*
* 6. For all added or changed keys
*/
for (i=0; i < nvec; i++){
dd = &ddvec[i];
dp = dd->dd_dep; /* op, callback, arg */
if ((dp->dp_type & TRANS_CB_COMMIT) == 0)
continue;
dfe = dd->dd_dbdiff; /* key1/key2/op */
op = dbdiff2commit_op(dfe->dfe_op);
if (op != CO_CHANGE && op != CO_ADD)
continue;
/* original mode 2 where CHANGE=DEL/ADD */
if (clicon_commit_order(h) == 2 && op == CO_CHANGE)
op = CO_ADD;
if (plugin_commit_callback(h,
op, /* oper */
running, /* db1 */
candidate, /* db2 */
dd->dd_mkey1, /* key1 */
dd->dd_mkey2, /* key2 */
dd->dd_dbdiff->dfe_vec1, /* vec1 */
dd->dd_dbdiff->dfe_vec2, /* vec2 */
dp /* callback */
) < 0){
firsterr = clicon_err_save(); /* save this error */
failed++;
break;
}
}
if (!failed) /* Commit here in case cp fails */
if (file_cp(candidate, running) < 0){
clicon_err(OE_UNIX, errno, "file_cp(candidate; running)");
failed++;
}
/* 10. Failed setting keys in running, first remove the keys set */
if (failed){ /* failed */
for (j=i-1; j>=0; j--){ /* revert in opposite order */
dd = &ddvec[j];
dp = dd->dd_dep; /* op, callback, arg */
if ((dp->dp_type & TRANS_CB_COMMIT) == 0)
continue;
dfe = dd->dd_dbdiff; /* key1/key2/op */
op = dbdiff2commit_op(dfe->dfe_op);
if (op != CO_CHANGE && op != CO_ADD)
continue;
/* original mode 2 where CHANGE=DEL/ADD */
if (clicon_commit_order(h) == 2 && op == CO_CHANGE)
op = CO_ADD;
if (op == CO_ADD) /* reverse op */
op = CO_DELETE;
if (plugin_commit_callback(h,
op, /* oper */
candidate, /* db1 */
running, /* db2 */
dd->dd_mkey2, /* key1 */
dd->dd_mkey1, /* key2 */
dd->dd_dbdiff->dfe_vec2, /* vec1 */
dd->dd_dbdiff->dfe_vec1, /* vec2 */
dp /* callback */
) < 0){
/* ignore errors or signal major setback ? */
clicon_log(LOG_NOTICE, "Error in rollback, trying to continue");
continue;
}
}
for (j=0; j < nvec; j++){ /* revert in opposite order */
dd = &ddvec[j];
dp = dd->dd_dep; /* op, callback, arg */
if ((dp->dp_type & TRANS_CB_COMMIT) == 0)
continue;
dfe = dd->dd_dbdiff; /* key1/key2/op */
op = dbdiff2commit_op(dfe->dfe_op);
/* original mode 2 where CHANGE=DEL/ADD */
if (clicon_commit_order(h) == 2 && op == CO_CHANGE)
op = CO_DELETE;
if (op != CO_DELETE)
continue;
op = CO_ADD;
if (plugin_commit_callback(h,
op, /* oper */
candidate, /* db1 */
running, /* db2 */
dd->dd_mkey2, /* key1 */
dd->dd_mkey1, /* key2 */
dd->dd_dbdiff->dfe_vec2, /* vec1 */
dd->dd_dbdiff->dfe_vec1, /* vec2 */
dp /* callback */
) < 0){
/* ignore errors or signal major setback ? */
clicon_log(LOG_NOTICE, "Error in rollback, trying to continue");
continue;
}
}
goto done;
}
} /* commit_order */
#endif /* OBSOLETE */
retval = 0;
done:
/* In case of failure, call plugin transaction termination callbacks */
if (retval < 0 && td)
plugin_transaction_abort(h, td);
if (td)
transaction_free(td);
if (firsterr)
clicon_err_restore(firsterr);
return retval;
}
/*! Do a diff between candidate and running, then start a validate transaction
*
* @param[in] h Clicon handle
* @param[in] running The current database. The original backend state
* @param[in] candidate: The candidate database. The wanted backend state
*/
int
candidate_validate(clicon_handle h,
char *candidate,
char *running)
{
int retval = -1;
struct stat sb;
yang_spec *yspec;
transaction_data_t *td = NULL;
if ((yspec = clicon_dbspec_yang(h)) == NULL){
clicon_err(OE_FATAL, 0, "No DB_SPEC");
goto done;
}
/* Sanity checks that databases exists. */
if (stat(running, &sb) < 0){
clicon_err(OE_DB, errno, "%s", running);
goto done;
}
if (stat(candidate, &sb) < 0){
clicon_err(OE_DB, errno, "%s", candidate);
goto done;
}
/* 1. Start transaction */
if ((td = transaction_new()) == NULL)
goto done;
/* 2. Parse xml trees */
if (xmldb_get(running, "/", yspec, &td->td_src) < 0)
goto done;
if (xmldb_get(candidate, "/", yspec, &td->td_target) < 0)
goto done;
/* 3. Compute differences */
if (xml_diff(yspec,
td->td_src,
td->td_target,
&td->td_dvec, /* removed: only in running */
&td->td_dlen,
&td->td_avec, /* added: only in candidate */
&td->td_alen,
&td->td_scvec, /* changed: original values */
&td->td_tcvec, /* changed: wanted values */
&td->td_clen) < 0)
goto done;
if (debug)
transaction_print(stderr, td);
/* 4. Call plugin start transaction callbacks */
if (plugin_transaction_begin(h, td) < 0)
goto done;
/* 5. Make generic validation on all new or changed data. */
if (generic_validate(yspec, td) < 0)
goto done;
/* 6. Call plugin validate transaction callbacks */
if (plugin_transaction_validate(h, td) < 0)
goto done;
/* 7. Call plugin complete transaction callbacks */
if (plugin_transaction_complete(h, td) < 0)
goto done;
retval = 0;
done:
/* In case of failure, call plugin transaction termination callbacks */
if (retval < 0 && td)
plugin_transaction_abort(h, td);
if (td)
transaction_free(td);
return retval;
}
/*! Handle an incoming commit message from a client.
* XXX: If commit succeeds and snapshot/startup fails, we have strange state:
* the commit has succeeded but an error message is returned.
*/
int
from_client_commit(clicon_handle h,
int s,
struct clicon_msg *msg,
const char *label)
{
int retval = -1;
char *candidate;
char *running;
uint32_t snapshot;
uint32_t startup;
char *snapshot_0;
char *archive_dir;
char *startup_config;
if (clicon_msg_commit_decode(msg, &candidate, &running,
&snapshot, &startup, label) < 0)
goto err;
if (candidate_commit(h, candidate, running) < 0){
clicon_debug(1, "Commit %s failed", candidate);
retval = 0; /* We ignore errors from commit, but maybe
we should fail on fatal errors? */
goto err;
}
clicon_debug(1, "Commit %s", candidate);
if (snapshot){
if ((archive_dir = clicon_archive_dir(h)) == NULL){
clicon_err(OE_PLUGIN, 0, "snapshot set and clicon_archive_dir not defined");
goto err;
}
if (config_snapshot(h, running, archive_dir) < 0)
goto err;
}
if (startup){
if ((archive_dir = clicon_archive_dir(h)) == NULL){
clicon_err(OE_PLUGIN, 0, "startup set but clicon_archive_dir not defined");
goto err;
}
if ((startup_config = clicon_startup_config(h)) == NULL){
clicon_err(OE_PLUGIN, 0, "startup set but startup_config not defined");
goto err;
}
snapshot_0 = chunk_sprintf(__FUNCTION__, "%s/0", archive_dir);
if (file_cp(snapshot_0, startup_config) < 0){
clicon_err(OE_PROTO, errno, "%s: Error when creating startup",
__FUNCTION__);
goto err;
}
}
retval = 0;
if (send_msg_ok(s) < 0)
goto done;
goto done;
err:
/* XXX: more elaborate errstring? */
if (send_msg_err(s, clicon_errno, clicon_suberrno, "%s", clicon_err_reason) < 0)
retval = -1;
done:
unchunk_group(__FUNCTION__);
return retval; /* may be zero if we ignoring errors from commit */
} /* from_client_commit */
/*
* Call backend plugin
*/
int
from_client_validate(clicon_handle h,
int s,
struct clicon_msg *msg,
const char *label)
{
char *dbname;
char *running_db;
int retval = -1;
if (clicon_msg_validate_decode(msg, &dbname, label) < 0){
send_msg_err(s, clicon_errno, clicon_suberrno,
clicon_err_reason);
goto err;
}
clicon_debug(1, "Validate %s", dbname);
if ((running_db = clicon_running_db(h)) == NULL){
clicon_err(OE_FATAL, 0, "running db not set");
goto err;
}
if (candidate_validate(h, dbname, running_db) < 0){
clicon_debug(1, "Validate %s failed", dbname);
retval = 0; /* We ignore errors from commit, but maybe
we should fail on fatal errors? */
goto err;
}
retval = 0;
if (send_msg_ok(s) < 0)
goto done;
goto done;
err:
/* XXX: more elaborate errstring? */
if (send_msg_err(s, clicon_errno, clicon_suberrno, "%s", clicon_err_reason) < 0)
retval = -1;
done:
unchunk_group(__FUNCTION__);
return retval;
} /* from_client_validate */

View file

@ -0,0 +1,34 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef _BACKEND_COMMIT_H_
#define _BACKEND_COMMIT_H_
/*
* Prototypes
*/
int from_client_validate(clicon_handle h, int s, struct clicon_msg *msg, const char *label);
int from_client_commit(clicon_handle h, int s, struct clicon_msg *msg, const char *label);
int candidate_commit(clicon_handle h, char *candidate, char *running);
#endif /* _BACKEND_COMMIT_H_ */

View file

@ -0,0 +1,43 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
*/
#ifndef _BACKEND_HANDLE_H_
#define _BACKEND_HANDLE_H_
/*
* Prototypes
* not exported.
*/
/* backend handles */
clicon_handle backend_handle_init(void);
int backend_handle_exit(clicon_handle h);
struct client_entry *backend_client_add(clicon_handle h, struct sockaddr *addr);
struct client_entry *backend_client_list(clicon_handle h);
int backend_client_delete(clicon_handle h, struct client_entry *ce);
#endif /* _BACKEND_HANDLE_H_ */

View file

@ -0,0 +1,95 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "clicon_config.h" /* generated by config & autoconf */
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <time.h>
#include <syslog.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <netinet/in.h>
/* cligen */
#include <cligen/cligen.h>
/* clicon */
#include <clicon/clicon.h>
#include "backend_lock.h"
/*
* Easy way out: store an integer for candidate db which contains
* the session-id of the client holding the lock.
* more general: any database
* we dont make any sanity check on who is locking.
*/
static int _db_locked = 0;
/*
* db_lock
*/
int
db_lock(clicon_handle h, int id)
{
_db_locked = id;
clicon_debug(1, "%s: lock db by %u", __FUNCTION__, id);
return 0;
}
/*
* db_unlock
*/
int
db_unlock(clicon_handle h)
{
if (!_db_locked )
return 0;
_db_locked = 0;
return 0;
}
/*
* db_islocked
* returns id of locker
*/
int
db_islocked(clicon_handle h)
{
return _db_locked;
}

View file

@ -0,0 +1,37 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
* Database logical lock functions.
* Only one lock (candidate_db)
* Not persistent (needs another db)
*/
#ifndef _BACKEND_LOCK_H_
#define _BACKEND_LOCK_H_
/*
* Prototypes
*/
int db_lock(clicon_handle h, int id);
int db_unlock(clicon_handle h);
int db_islocked(clicon_handle h);
#endif /* _BACKEND_LOCK_H_ */

617
apps/backend/backend_main.c Normal file
View file

@ -0,0 +1,617 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "clicon_config.h" /* generated by config & autoconf */
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <time.h>
#include <syslog.h>
#include <ifaddrs.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/types.h>
#include <grp.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/in.h>
/* cligen */
#include <cligen/cligen.h>
/* clicon */
#include <clicon/clicon.h>
#include "clicon_backend_handle.h"
#include "backend_socket.h"
#include "backend_client.h"
#include "backend_commit.h"
#include "backend_plugin.h"
#include "backend_handle.h"
/* Command line options to be passed to getopt(3) */
#define BACKEND_OPTS "hD:f:d:Fzu:P:1IRCc::rg:pt"
/* Cannot use h after this */
static int
config_terminate(clicon_handle h)
{
yang_spec *yspec;
char *pidfile = clicon_backend_pidfile(h);
char *sockpath = clicon_sock(h);
clicon_debug(1, "%s", __FUNCTION__);
if ((yspec = clicon_dbspec_yang(h)) != NULL)
yspec_free(yspec);
plugin_finish(h);
if (pidfile)
unlink(pidfile);
if (sockpath)
unlink(sockpath);
backend_handle_exit(h); /* Cannot use h after this */
clicon_log_register_callback(NULL, NULL);
clicon_debug(1, "%s done", __FUNCTION__);
if (debug)
chunk_check(stderr, NULL);
return 0;
}
/*
config_sig_term
Unlink pidfile and quit
*/
static void
config_sig_term(int arg)
{
static int i=0;
if (i++ == 0)
clicon_log(LOG_NOTICE, "%s: %s: pid: %u Signal %d",
__PROGRAM__, __FUNCTION__, getpid(), arg);
clicon_exit_set(); /* checked in event_loop() */
}
/*
* usage
*/
static void
usage(char *argv0, clicon_handle h)
{
char *plgdir = clicon_backend_dir(h);
char *confsock = clicon_sock(h);
char *confpid = clicon_backend_pidfile(h);
char *startup = clicon_startup_config(h);
char *group = clicon_sock_group(h);
fprintf(stderr, "usage:%s\n"
"where options are\n"
" -h\t\tHelp\n"
" -D <level>\tdebug\n"
" -f <file>\tCLICON config file (mandatory)\n"
" -d <dir>\tSpecify backend plugin directory (default: %s)\n"
" -z\t\tKill other config daemon and exit\n"
" -F\t\tforeground\n"
" -1\t\tonce (dont wait for events)\n"
" -u <path>\tconfig UNIX domain path / ip address (default: %s)\n"
" -P <file>\tPid filename (default: %s)\n"
" -I\t\tInitialize running state database\n"
" -R\t\tCall plugin_reset() in plugins to reset system state in running db (use with -I)\n"
" -C\t\tCall plugin_reset() in plugins to reset system state in candidate db (use with -I)\n"
" -c [<file>]\tLoad specified application config. Default is\n"
" \t\"CLICON_STARTUP_CONFIG\" = %s\n"
" -r\t\tReload running database\n"
" -p \t\tPrint database yang specification\n"
" -t \t\tPrint alternate spec translation (eg if YANG print KEY, if KEY print YANG)\n"
" -g <group>\tClient membership required to this group (default: %s)\n",
argv0,
plgdir ? plgdir : "none",
confsock ? confsock : "none",
confpid ? confpid : "none",
startup ? startup : "none",
group ? group : "none"
);
exit(0);
}
static int
rundb_init(clicon_handle h, char *running_db)
{
if (unlink(running_db) != 0 && errno != ENOENT) {
clicon_err(OE_UNIX, errno, "unlink");
return -1;
}
if (db_init(running_db) < 0)
return -1;
return 0;
}
/*! Initialize running-config from file application configuration
*
* @param[in] h clicon handle
* @param[in] app_config_file clicon application configuration file
* @param[in] running_db Name of running db
* @retval 0 OK
* @retval -1 Error. clicon_err set
*/
static int
rundb_main(clicon_handle h,
char *app_config_file,
char *running_db)
{
char *tmp = NULL;
int retval = -1;
int fd = -1;
yang_spec *yspec;
cxobj *xt = NULL;
cxobj *xn;
if ((tmp = clicon_tmpfile(__FUNCTION__)) == NULL)
goto done;
if (file_cp(running_db, tmp) < 0){
clicon_err(OE_UNIX, errno, "file copy");
goto done;
}
if ((fd = open(app_config_file, O_RDONLY)) < 0){
clicon_err(OE_UNIX, errno, "open(%s)", app_config_file);
goto done;
}
if (clicon_xml_parse_file(fd, &xt, "</clicon>") < 0)
goto done;
yspec = clicon_dbspec_yang(h);
if ((xn = xml_child_i(xt, 0)) != NULL)
if (xmldb_put(tmp, xn, yspec, OP_MERGE) < 0)
goto done;
if (candidate_commit(h, tmp, running_db) < 0)
goto done;
retval = 0;
done:
if (tmp)
unlink(tmp);
if (xt)
xml_free(xt);
if (fd != -1)
close(fd);
unchunk_group(__FUNCTION__);
return retval;
}
static int
candb_reset(clicon_handle h, char *running_db)
{
int retval = -1;
char *tmp = NULL;
if ((tmp = clicon_tmpfile(__FUNCTION__)) == NULL)
goto done;
if (file_cp(running_db, tmp) < 0){
clicon_err(OE_UNIX, errno, "file copy");
goto done;
}
/* Request plugins to reset system state, eg initiate running from system
* -R
*/
if (plugin_reset_state(h, tmp) < 0)
goto done;
if (candidate_commit(h, tmp, running_db) < 0)
goto done;
retval = 0;
done:
if (tmp)
unlink(tmp);
unchunk_group(__FUNCTION__);
return retval;
}
/*! Create backend server socket and register callback
*/
static int
server_socket(clicon_handle h)
{
int ss;
/* Open control socket */
if ((ss = config_socket_init(h)) < 0)
return -1;
/* ss is a server socket that the clients connect to. The callback
therefore accepts clients on ss */
if (event_reg_fd(ss, config_accept_client, h, "server socket") < 0) {
close(ss);
return -1;
}
return ss;
}
/*! Callback for CLICON log events
* If you make a subscription to CLICON stream, this function is called for every
* log event.
*/
static int
config_log_cb(int level, char *msg, void *arg)
{
size_t n;
char *ptr;
char *nptr;
char *newmsg = NULL;
int retval = -1;
/* backend_notify() will go through all clients and see if any has registered "CLICON",
and if so make a clicon_proto notify message to those clients. */
/* Sanitize '%' into "%%" to prevent segvfaults in vsnprintf later.
At this stage all formatting is already done */
n = 0;
for(ptr=msg; *ptr; ptr++)
if (*ptr == '%')
n++;
if ((newmsg = malloc(strlen(msg) + n + 1)) == NULL) {
clicon_err(OE_UNIX, errno, "malloc");
return -1;
}
for(ptr=msg, nptr=newmsg; *ptr; ptr++) {
*nptr++ = *ptr;
if (*ptr == '%')
*nptr++ = '%';
}
retval = backend_notify(arg, "CLICON", level, newmsg);
free(newmsg);
return retval;
}
int
main(int argc, char **argv)
{
char c;
int zap;
int foreground;
int once;
int init_rundb;
char *running_db;
char *candidate_db;
int reload_running;
int reset_state_running;
int reset_state_candidate;
char *app_config_file = NULL;
char *config_group;
char *argv0 = argv[0];
char *tmp;
struct stat st;
clicon_handle h;
int help = 0;
int printspec = 0;
int printalt = 0;
int pid;
char *pidfile;
char *sock;
int sockfamily;
/* In the startup, logs to stderr & syslog and debug flag set later */
clicon_log_init(__PROGRAM__, LOG_INFO, CLICON_LOG_STDERR|CLICON_LOG_SYSLOG);
/* Initiate CLICON handle */
if ((h = backend_handle_init()) == NULL)
return -1;
if (config_plugin_init(h) != 0)
return -1;
foreground = 0;
once = 0;
zap = 0;
init_rundb = 0;
reload_running = 0;
reset_state_running = 0;
reset_state_candidate = 0;
/*
* Command-line options for help, debug, and config-file
*/
opterr = 0;
optind = 1;
while ((c = getopt(argc, argv, BACKEND_OPTS)) != -1)
switch (c) {
case '?':
case 'h':
/* Defer the call to usage() to later. Reason is that for helpful
text messages, default dirs, etc, are not set until later.
But this measn that we need to check if 'help' is set before
exiting, and then call usage() before exit.
*/
help = 1;
break;
case 'D' : /* debug */
if (sscanf(optarg, "%d", &debug) != 1)
usage(argv[0], h);
break;
case 'f': /* config file */
if (!strlen(optarg))
usage(argv[0], h);
clicon_option_str_set(h, "CLICON_CONFIGFILE", optarg);
break;
}
/*
* Syslogs also to stderr, but later turn stderr off in daemon mode.
* error only to syslog. debug to syslog
*/
clicon_log_init(__PROGRAM__, debug?LOG_DEBUG:LOG_INFO, CLICON_LOG_STDERR|CLICON_LOG_SYSLOG);
clicon_debug_init(debug, NULL);
/* Find and read configfile */
if (clicon_options_main(h) < 0){
if (help)
usage(argv[0], h);
return -1;
}
/* Now run through the operational args */
opterr = 1;
optind = 1;
while ((c = getopt(argc, argv, BACKEND_OPTS)) != -1)
switch (c) {
case 'D' : /* debug */
case 'f': /* config file */
break; /* see above */
case 'd': /* Plugin directory */
if (!strlen(optarg))
usage(argv[0], h);
clicon_option_str_set(h, "CLICON_BACKEND_DIR", optarg);
break;
case 'F' : /* foreground */
foreground = 1;
break;
case '1' : /* Quit after reading database once - dont wait for events */
once = 1;
break;
case 'z': /* Zap other process */
zap++;
break;
case 'u': /* config unix domain path / ip address */
if (!strlen(optarg))
usage(argv[0], h);
clicon_option_str_set(h, "CLICON_SOCK", optarg);
break;
case 'P': /* pidfile */
clicon_option_str_set(h, "CLICON_BACKEND_PIDFILE", optarg);
break;
case 'I': /* Initiate running db */
init_rundb++;
break;
case 'R': /* Reset state directly into running */
reset_state_running++;
break;
case 'C': /* Reset state into candidate and then commit it */
reset_state_candidate++;
break;
case 'c': /* Load application config */
app_config_file = optarg ? optarg : clicon_startup_config(h);
if (app_config_file == NULL) {
fprintf(stderr, "Option \"CLICON_STARTUP_CONFIG\" not set\n");
return -1;
}
break;
case 'r': /* Reload running */
reload_running++;
break;
case 'g': /* config socket group */
clicon_option_str_set(h, "CLICON_SOCK_GROUP", optarg);
break;
case 'p' : /* Print spec */
printspec++;
break;
case 't' : /* Print alternative dbspec format (eg if YANG, print KEY) */
printalt++;
break;
default:
usage(argv[0], h);
break;
}
argc -= optind;
argv += optind;
/* Defer: Wait to the last minute to print help message */
if (help)
usage(argv[0], h);
/* Check pid-file, if zap kil the old daemon, else return here */
if ((pidfile = clicon_backend_pidfile(h)) == NULL){
clicon_err(OE_FATAL, 0, "pidfile not set");
goto done;
}
sockfamily = clicon_sock_family(h);
if ((sock = clicon_sock(h)) == NULL){
clicon_err(OE_FATAL, 0, "sock not set");
goto done;
}
if (pidfile_get(pidfile, &pid) < 0)
return -1;
if (zap){
if (pid && pidfile_zapold(pid) < 0)
return -1;
if (lstat(pidfile, &st) == 0)
unlink(pidfile);
if (sockfamily==AF_UNIX && lstat(sock, &st) == 0)
unlink(sock);
exit(0);
}
else
if (pid){
clicon_err(OE_DEMON, 0, "Daemon already running with pid %d\n(Try killing it with %s -z)",
pid, argv0);
return -1; /* goto done deletes pidfile */
}
/* After this point we can goto done on error
* Here there is either no old process or we have killed it,..
*/
if (lstat(pidfile, &st) == 0)
unlink(pidfile);
if (sockfamily==AF_UNIX && lstat(sock, &st) == 0)
unlink(sock);
/* Sanity check: config group exists */
if ((config_group = clicon_sock_group(h)) == NULL){
clicon_err(OE_FATAL, 0, "clicon_sock_group option not set");
return -1;
}
if (group_name2gid(config_group, NULL) < 0){
clicon_log(LOG_ERR, "'%s' does not seem to be a valid user group.\n"
"The config demon requires a valid group to create a server UNIX socket\n"
"Define a valid CLICON_SOCK_GROUP in %s or via the -g option\n"
"or create the group and add the user to it. On linux for example:"
" sudo groupadd %s\n"
" sudo usermod -a -G %s user\n",
config_group, clicon_configfile(h), config_group, config_group);
return -1;
}
/* Parse db spec file */
if (yang_spec_main(h, stdout, printspec) < 0)
goto done;
if ((running_db = clicon_running_db(h)) == NULL){
clicon_err(OE_FATAL, 0, "running db not set");
goto done;
}
if ((candidate_db = clicon_candidate_db(h)) == NULL){
clicon_err(OE_FATAL, 0, "candidate db not set");
goto done;
}
/* If running exists and reload_running set, make a copy to candidate */
if (reload_running){
if (stat(running_db, &st) && errno == ENOENT){
clicon_log(LOG_NOTICE, "%s: -r (reload running) option given but no running_db found, proceeding without", __PROGRAM__);
reload_running = 0; /* void it, so we dont commit candidate below */
}
else
if (file_cp(running_db, candidate_db) < 0){
clicon_err(OE_UNIX, errno, "FATAL: file_cp");
goto done;
}
}
/* Init running db
* -I
*/
if (init_rundb || (stat(running_db, &st) && errno == ENOENT))
if (rundb_init(h, running_db) < 0)
goto done;
/* Initialize plugins
(also calls plugin_init() and plugin_start(argc,argv) in each plugin */
if (plugin_initiate(h) != 0)
goto done;
if (reset_state_candidate){
if (candb_reset(h, running_db) < 0)
goto done;
}
else
if (reset_state_running){
if (plugin_reset_state(h, running_db) < 0)
goto done;
}
/* Call plugin_start */
tmp = *(argv-1);
*(argv-1) = argv0;
if (plugin_start_hooks(h, argc+1, argv-1) < 0)
goto done;
*(argv-1) = tmp;
if (reload_running){
if (candidate_commit(h, candidate_db, running_db) < 0)
goto done;
}
/* Have we specified a config file to load? eg
-c <file>
-r replace running (obsolete)
*/
if (app_config_file)
if (rundb_main(h, app_config_file, running_db) < 0)
goto done;
/* Initiate the shared candidate. Maybe we should not do this? */
if (file_cp(running_db, candidate_db) < 0){
clicon_err(OE_UNIX, errno, "FATAL: file_cp");
goto done;
}
/* XXX Hack for now. Change mode so that we all can write. Security issue*/
chmod(candidate_db, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
if (once)
goto done;
/* Daemonize and initiate logging. Note error is initiated here to make
demonized errors OK. Before this stage, errors are logged on stderr
also */
if (foreground==0){
clicon_log_init(__PROGRAM__, debug?LOG_DEBUG:LOG_INFO, CLICON_LOG_SYSLOG);
if (daemon(0, 0) < 0){
fprintf(stderr, "config: daemon");
exit(0);
}
}
/* Write pid-file */
if ((pid = pidfile_write(pidfile)) < 0)
goto done;
/* Register log notifications */
if (clicon_log_register_callback(config_log_cb, h) < 0)
goto done;
clicon_log(LOG_NOTICE, "%s: %u Started", __PROGRAM__, getpid());
if (set_signal(SIGTERM, config_sig_term, NULL) < 0){
clicon_err(OE_DEMON, errno, "Setting signal");
goto done;
}
if (set_signal(SIGINT, config_sig_term, NULL) < 0){
clicon_err(OE_DEMON, errno, "Setting signal");
goto done;
}
/* Initialize server socket */
if (server_socket(h) < 0)
goto done;
if (debug)
clicon_option_dump(h, debug);
if (event_loop() < 0)
goto done;
done:
clicon_log(LOG_NOTICE, "%s: %u Terminated", __PROGRAM__, getpid());
config_terminate(h); /* Cannot use h after this */
return 0;
}

View file

@ -0,0 +1,751 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
*/
#ifdef HAVE_CONFIG_H
#include "clicon_config.h" /* generated by config & autoconf */
#endif
#include <stdio.h>
#define __USE_GNU /* strverscmp */
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <dlfcn.h>
#include <dirent.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <netinet/in.h>
/* cligen */
#include <cligen/cligen.h>
/* clicon */
#include <clicon/clicon.h>
#include "clicon_backend_transaction.h"
#include "backend_plugin.h"
#include "backend_commit.h"
/*
* Types
*/
/* Following are specific to backend. For common see clicon_plugin.h
* @note the following should match the prototypes in clicon_backend.h
*/
#define PLUGIN_RESET "plugin_reset"
typedef int (plgreset_t)(clicon_handle h, char *dbname); /* Reset system status */
#define PLUGIN_TRANS_BEGIN "transaction_begin"
#define PLUGIN_TRANS_VALIDATE "transaction_validate"
#define PLUGIN_TRANS_COMPLETE "transaction_complete"
#define PLUGIN_TRANS_COMMIT "transaction_commit"
#define PLUGIN_TRANS_END "transaction_end"
#define PLUGIN_TRANS_ABORT "transaction_abort"
typedef int (trans_cb_t)(clicon_handle h, transaction_data td); /* Transaction cbs */
/* Backend (config) plugins */
struct plugin {
char p_name[PATH_MAX]; /* Plugin name */
void *p_handle; /* Dynamic object handle */
plginit_t *p_init; /* Init */
plgstart_t *p_start; /* Start */
plgexit_t *p_exit; /* Exit */
plgreset_t *p_reset; /* Reset state */
trans_cb_t *p_trans_begin; /* Transaction start */
trans_cb_t *p_trans_validate; /* Transaction validation */
trans_cb_t *p_trans_complete; /* Transaction validation complete */
trans_cb_t *p_trans_commit; /* Transaction commit */
trans_cb_t *p_trans_end; /* Transaction completed */
trans_cb_t *p_trans_abort; /* Transaction aborted */
};
/*
* Local variables
*/
static int nplugins = 0;
static struct plugin *plugins = NULL;
/*! Find a plugin by name and return the dlsym handl
* Used by libclicon code to find callback funcctions in plugins.
* @param[in] h Clicon handle
* @param[in] h Name of plugin
* @retval handle Plugin handle if found
* @retval NULL Not found
*/
static void *
config_find_plugin(clicon_handle h,
char *name)
{
int i;
struct plugin *p;
for (i = 0; i < nplugins; i++){
p = &plugins[i];
if (strcmp(p->p_name, name) == 0)
return p->p_handle;
}
return NULL;
}
/*! Initialize plugin code (not the plugins themselves)
* @param[in] h Clicon handle
* @retval 0 OK
* @retval -1 Error
*/
int
config_plugin_init(clicon_handle h)
{
find_plugin_t *fp = config_find_plugin;
clicon_hash_t *data = clicon_data(h);
/* Register CLICON_FIND_PLUGIN in data hash */
if (hash_add(data, "CLICON_FIND_PLUGIN", &fp, sizeof(fp)) == NULL) {
clicon_err(OE_UNIX, errno, "failed to register CLICON_FIND_PLUGIN");
return -1;
}
return 0;
}
/*! Unload a plugin
* @param[in] h Clicon handle
* @param[in] plg Plugin structure
* @retval 0 OK
* @retval -1 Error
*/
static int
plugin_unload(clicon_handle h,
struct plugin *plg)
{
char *error;
/* Call exit function is it exists */
if (plg->p_exit)
plg->p_exit(h);
dlerror(); /* Clear any existing error */
if (dlclose(plg->p_handle) != 0) {
error = (char*)dlerror();
clicon_err(OE_UNIX, 0, "dlclose: %s", error?error:"Unknown error");
return -1;
/* Just report */
}
else
clicon_debug(1, "Plugin '%s' unloaded.", plg->p_name);
return 0;
}
/*! Load a dynamic plugin and call its init-function
* @param[in] h Clicon handle
* @param[in] file The plugin (.so) to load
* @param[in] dlflags Arguments to dlopen(3)
* @param[in] label Chunk label
* @retval plugin Plugin struct
* @retval NULL Error
*/
static struct plugin *
plugin_load (clicon_handle h,
char *file,
int dlflags,
const char *label)
{
char *error;
void *handle;
char *name;
struct plugin *new;
plginit_t *initfun;
dlerror(); /* Clear any existing error */
if ((handle = dlopen (file, dlflags)) == NULL) {
error = (char*)dlerror();
clicon_err(OE_UNIX, 0, "dlopen: %s", error?error:"Unknown error");
return NULL;
}
initfun = dlsym(handle, PLUGIN_INIT);
if ((error = (char*)dlerror()) != NULL) {
clicon_err(OE_UNIX, 0, "dlsym: %s", error);
return NULL;
}
if (initfun(h) != 0) {
dlclose(handle);
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
clicon_err(OE_DB, 0, "Unknown error: %s: plugin_init does not make clicon_err call on error",
file);
return NULL;
}
if ((new = chunk(sizeof(*new), label)) == NULL) {
clicon_err(OE_UNIX, errno, "dhunk: %s", strerror(errno));
dlclose(handle);
return NULL;
}
memset(new, 0, sizeof(*new));
name = strrchr(file, '/') ? strrchr(file, '/')+1 : file;
clicon_debug(2, "Loading plugin '%s'.", name);
snprintf(new->p_name, sizeof(new->p_name), "%*s",
(int)strlen(name)-2, name);
new->p_handle = handle;
new->p_init = initfun;
if ((new->p_start = dlsym(handle, PLUGIN_START)) != NULL)
clicon_debug(2, "%s callback registered.", PLUGIN_START);
if ((new->p_exit = dlsym(handle, PLUGIN_EXIT)) != NULL)
clicon_debug(2, "%s callback registered.", PLUGIN_EXIT);
if ((new->p_reset = dlsym(handle, PLUGIN_RESET)) != NULL)
clicon_debug(2, "%s callback registered.", PLUGIN_RESET);
if ((new->p_trans_begin = dlsym(handle, PLUGIN_TRANS_BEGIN)) != NULL)
clicon_debug(2, "%s callback registered.", PLUGIN_TRANS_BEGIN);
if ((new->p_trans_validate = dlsym(handle, PLUGIN_TRANS_VALIDATE)) != NULL)
clicon_debug(2, "%s callback registered.", PLUGIN_TRANS_VALIDATE);
if ((new->p_trans_complete = dlsym(handle, PLUGIN_TRANS_COMPLETE)) != NULL)
clicon_debug(2, "%s callback registered.", PLUGIN_TRANS_COMPLETE);
if ((new->p_trans_commit = dlsym(handle, PLUGIN_TRANS_COMMIT)) != NULL)
clicon_debug(2, "%s callback registered.", PLUGIN_TRANS_COMMIT);
if ((new->p_trans_end = dlsym(handle, PLUGIN_TRANS_END)) != NULL)
clicon_debug(2, "%s callback registered.", PLUGIN_TRANS_END);
if ((new->p_trans_abort = dlsym(handle, PLUGIN_TRANS_ABORT)) != NULL)
clicon_debug(2, "%s callback registered.", PLUGIN_TRANS_ABORT);
clicon_debug(2, "Plugin '%s' loaded.\n", name);
return new;
}
/*! Request plugins to reset system state
* The system 'state' should be the same as the contents of running_db
* @param[in] h Clicon handle
* @param[in] dbname Name of database
* @retval 0 OK
* @retval -1 Error
*/
int
plugin_reset_state(clicon_handle h,
char *dbname)
{
int i;
struct plugin *p;
for (i = 0; i < nplugins; i++) {
p = &plugins[i];
if (p->p_reset) {
clicon_debug(1, "Calling plugin_reset() for %s\n",
p->p_name);
if (((p->p_reset)(h, dbname)) < 0) {
clicon_err(OE_FATAL, 0, "plugin_reset() failed for %s\n",
p->p_name);
return -1;
}
}
}
return 0;
}
/*! Call plugin_start in all plugins
* @param[in] h Clicon handle
* @param[in] argc Command-line arguments
* @param[in] argv Command-line arguments
* @retval 0 OK
* @retval -1 Error
*/
int
plugin_start_hooks(clicon_handle h,
int argc,
char **argv)
{
int i;
struct plugin *p;
for (i = 0; i < nplugins; i++) {
p = &plugins[i];
if (p->p_start) {
optind = 0;
if (((p->p_start)(h, argc, argv)) < 0) {
clicon_err(OE_FATAL, 0, "plugin_start() failed for %s\n",
p->p_name);
return -1;
}
}
}
return 0;
}
/*! Append plugin to list
* @param[in] p Plugin
* @retval 0 OK
* @retval -1 Error
*/
static int
plugin_append(struct plugin *p)
{
struct plugin *new;
if ((new = rechunk(plugins, (nplugins+1) * sizeof (*p), NULL)) == NULL) {
clicon_err(OE_UNIX, errno, "chunk");
return -1;
}
memset (&new[nplugins], 0, sizeof(new[nplugins]));
memcpy (&new[nplugins], p, sizeof(new[nplugins]));
plugins = new;
nplugins++;
return 0;
}
/*! Load backend plugins found in a directory
* The plugins must have the '.so' suffix
* @param[in] h Clicon handle
* @param[in] dir Backend plugin directory
* @retval 0 OK
* @retval -1 Error
*/
static int
config_plugin_load_dir(clicon_handle h,
const char *dir)
{
int retval = -1;
int i;
int np = 0;
int ndp;
struct stat st;
char *filename;
struct dirent *dp;
struct plugin *new;
struct plugin *p = NULL;
char *master;
char *master_plugin;
/* Format master plugin path */
if ((master_plugin = clicon_master_plugin(h)) == NULL){
clicon_err(OE_PLUGIN, 0, "clicon_master_plugin option not set");
goto quit;
}
master = chunk_sprintf(__FUNCTION__, "%s.so", master_plugin);
if (master == NULL) {
clicon_err(OE_PLUGIN, errno, "chunk_sprintf master plugin");
goto quit;
}
/* Allocate plugin group object */
/* Get plugin objects names from plugin directory */
if((ndp = clicon_file_dirent(dir, &dp, "(.so)$", S_IFREG, __FUNCTION__))<0)
goto quit;
/* reset num plugins */
np = 0;
/* Master plugin must be loaded first if it exists. */
filename = chunk_sprintf(__FUNCTION__, "%s/%s", dir, master);
if (filename == NULL) {
clicon_err(OE_UNIX, errno, "chunk");
goto quit;
}
if (stat(filename, &st) == 0) {
clicon_debug(1, "Loading master plugin '%.*s' ...",
(int)strlen(filename), filename);
new = plugin_load(h, filename, RTLD_NOW|RTLD_GLOBAL, __FUNCTION__);
if (new == NULL)
goto quit;
if (plugin_append(new) < 0)
goto quit;
}
/* Now load the rest */
for (i = 0; i < ndp; i++) {
if (strcmp(dp[i].d_name, master) == 0)
continue; /* Skip master now */
filename = chunk_sprintf(__FUNCTION__, "%s/%s", dir, dp[i].d_name);
clicon_debug(1, "Loading plugin '%.*s' ...", (int)strlen(filename), filename);
if (filename == NULL) {
clicon_err(OE_UNIX, errno, "chunk");
goto quit;
}
new = plugin_load (h, filename, RTLD_NOW, __FUNCTION__);
if (new == NULL)
goto quit;
if (plugin_append(new) < 0)
goto quit;
}
/* All good. */
retval = 0;
quit:
if (retval != 0) {
if (p) {
while (--np >= 0)
plugin_unload (h, &p[np]);
unchunk(p);
}
}
unchunk_group(__FUNCTION__);
return retval;
}
/*! Load a plugin group.
* @param[in] h Clicon handle
* @retval 0 OK
* @retval -1 Error
*/
int
plugin_initiate(clicon_handle h)
{
char *dir;
/* First load CLICON system plugins */
if (config_plugin_load_dir(h, CLICON_BACKEND_SYSDIR) < 0)
return -1;
/* Then load application plugins */
if ((dir = clicon_backend_dir(h)) == NULL){
clicon_err(OE_PLUGIN, 0, "backend_dir not defined");
return -1;
}
if (config_plugin_load_dir(h, dir) < 0)
return -1;
return 0;
}
/*! Unload and deallocate all backend plugins
* @param[in] h Clicon handle
* @retval 0 OK
* @retval -1 Error
*/
int
plugin_finish(clicon_handle h)
{
int i;
struct plugin *p;
for (i = 0; i < nplugins; i++) {
p = &plugins[i];
plugin_unload(h, p);
}
if (plugins)
unchunk(plugins);
nplugins = 0;
return 0;
}
/*! Call from frontend to function 'func' in plugin 'plugin'.
* Plugin function is supposed to populate 'retlen' and 'retarg' where
* 'retarg' is malloc:ed data if non-NULL.
* @param[in] h Clicon handle
* @param[in] req Clicon message containing information about the downcall
* @param[out] retlen Length of return value
* @param[out] ret Return value
* @retval 0 OK
* @retval -1 Error
*/
int
plugin_downcall(clicon_handle h,
struct clicon_msg_call_req *req,
uint16_t *retlen,
void **retarg)
{
int retval = -1;
int i;
downcall_cb funcp;
char name[PATH_MAX];
char *error;
struct plugin *p;
for (i = 0; i < nplugins; i++) {
p = &plugins[i];
strncpy(name, p->p_name, sizeof(name)-1);
if (!strcmp(name+strlen(name)-3, ".so"))
name[strlen(name)-3] = '\0';
/* If no plugin is given or the plugin-name matches */
if (req->cr_plugin == NULL || strlen(req->cr_plugin)==0 ||
strcmp(name, req->cr_plugin) == 0) {
funcp = dlsym(p->p_handle, req->cr_func);
if ((error = (char*)dlerror()) != NULL) {
clicon_err(OE_PROTO, ENOENT,
"Function does not exist: %s()", req->cr_func);
return -1;
}
retval = funcp(h, req->cr_op, req->cr_arglen, req->cr_arg, retlen, retarg);
goto done;
}
}
clicon_err(OE_PROTO, ENOENT,"%s: %s(): Plugin does not exist: %s",
__FUNCTION__, req->cr_func, req->cr_plugin);
return -1;
done:
return retval;
}
/*! Create and initialize transaction */
transaction_data_t *
transaction_new(void)
{
transaction_data_t *td;
static uint64_t id = 0; /* Global transaction id */
if ((td = malloc(sizeof(*td))) == NULL){
clicon_err(OE_CFG, errno, "malloc");
return NULL;
}
memset(td, 0, sizeof(*td));
td->td_id = id++;
return td;
}
/*! Free transaction structure */
int
transaction_free(transaction_data_t *td)
{
if (td->td_src)
xml_free(td->td_src);
if (td->td_target)
xml_free(td->td_target);
if (td->td_dvec)
free(td->td_dvec);
if (td->td_avec)
free(td->td_avec);
if (td->td_scvec)
free(td->td_scvec);
if (td->td_tcvec)
free(td->td_tcvec);
free(td);
return 0;
}
/* The plugin_transaction routines need access to struct plugin which is local to this file */
/*! Call transaction_begin() in all plugins before a validate/commit.
* @param[in] h Clicon handle
* @param[in] td Transaction data
* @retval 0 OK
* @retval -1 Error: one of the plugin callbacks returned error
*/
int
plugin_transaction_begin(clicon_handle h,
transaction_data_t *td)
{
int i;
int retval = 0;
struct plugin *p;
for (i = 0; i < nplugins; i++) {
p = &plugins[i];
if (p->p_trans_begin)
if ((retval = (p->p_trans_begin)(h, (transaction_data)td)) < 0){
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
clicon_log(LOG_NOTICE, "%s: Plugin '%s' %s callback does not make clicon_err call on error",
__FUNCTION__, p->p_name, PLUGIN_TRANS_BEGIN);
break;
}
}
return retval;
}
/*! Call transaction_validate callbacks in all backend plugins
* @param[in] h Clicon handle
* @param[in] td Transaction data
* @retval 0 OK. Validation succeeded in all plugins
* @retval -1 Error: one of the plugin callbacks returned validation fail
*/
int
plugin_transaction_validate(clicon_handle h,
transaction_data_t *td)
{
int retval = 0;
int i;
struct plugin *p;
for (i = 0; i < nplugins; i++){
p = &plugins[i];
if (p->p_trans_validate)
if ((retval = (p->p_trans_validate)(h, (transaction_data)td)) < 0){
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
clicon_log(LOG_NOTICE, "%s: Plugin '%s' %s callback does not make clicon_err call on error",
__FUNCTION__, p->p_name, PLUGIN_TRANS_VALIDATE);
break;
}
}
return retval;
}
/*! Call transaction_complete() in all plugins after validation (before commit)
* @param[in] h Clicon handle
* @param[in] td Transaction data
* @retval 0 OK
* @retval -1 Error: one of the plugin callbacks returned error
* @note Call plugins which have commit dependencies?
* @note Rename to transaction_complete?
*/
int
plugin_transaction_complete(clicon_handle h,
transaction_data_t *td)
{
int i;
int retval = 0;
struct plugin *p;
for (i = 0; i < nplugins; i++){
p = &plugins[i];
if (p->p_trans_complete)
if ((retval = (p->p_trans_complete)(h, (transaction_data)td)) < 0){
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
clicon_log(LOG_NOTICE, "%s: Plugin '%s' %s callback does not make clicon_err call on error",
__FUNCTION__, p->p_name, PLUGIN_TRANS_COMPLETE);
break;
}
}
return retval;
}
int
plugin_transaction_revert(clicon_handle h,
transaction_data_t *td,
int nr)
{
int retval = 0;
transaction_data_t tr; /* revert transaction */
int i;
struct plugin *p;
/* Create a new reversed transaction from the original where src and target
are swapped */
memcpy(&tr, td, sizeof(tr));
tr.td_src = td->td_target;
tr.td_target = td->td_src;
tr.td_dlen = td->td_alen;
tr.td_dvec = td->td_avec;
tr.td_alen = td->td_dlen;
tr.td_avec = td->td_dvec;
tr.td_scvec = td->td_tcvec;
tr.td_tcvec = td->td_scvec;
for (i = nr-1; i; i--){
p = &plugins[i];
if (p->p_trans_commit)
if ((p->p_trans_commit)(h, (transaction_data)&tr) < 0){
clicon_log(LOG_NOTICE, "Plugin '%s' %s revert callback failed",
p->p_name, PLUGIN_TRANS_COMMIT);
break;
}
}
return retval; /* ignore errors */
}
/*! Call transaction_commit callbacks in all backend plugins
* @param[in] h Clicon handle
* @param[in] td Transaction data
* @retval 0 OK
* @retval -1 Error: one of the plugin callbacks returned error
* If any of the commit callbacks fail by returning -1, a revert of the
* transaction is tried by calling the commit callbacsk with reverse arguments
* and in reverse order.
*/
int
plugin_transaction_commit(clicon_handle h,
transaction_data_t *td)
{
int retval = 0;
int i;
struct plugin *p;
for (i = 0; i < nplugins; i++){
p = &plugins[i];
if (p->p_trans_commit)
if ((retval = (p->p_trans_commit)(h, (transaction_data)td)) < 0){
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
clicon_log(LOG_NOTICE, "%s: Plugin '%s' %s callback does not make clicon_err call on error",
__FUNCTION__, p->p_name, PLUGIN_TRANS_COMMIT);
/* Make an effort to revert transaction */
plugin_transaction_revert(h, td, i);
break;
}
}
return retval;
}
/*! Call transaction_end() in all plugins after a successful commit.
* @param[in] h Clicon handle
* @param[in] td Transaction data
* @retval 0 OK
* @retval -1 Error
*/
int
plugin_transaction_end(clicon_handle h,
transaction_data_t *td)
{
int retval = 0;
int i;
struct plugin *p;
for (i = 0; i < nplugins; i++) {
p = &plugins[i];
if (p->p_trans_end)
if ((retval = (p->p_trans_end)(h, (transaction_data)td)) < 0){
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
clicon_log(LOG_NOTICE, "%s: Plugin '%s' %s callback does not make clicon_err call on error",
__FUNCTION__, p->p_name, PLUGIN_TRANS_END);
break;
}
}
return retval;
}
/*! Call transaction_abort() in all plugins after a failed validation/commit.
* @param[in] h Clicon handle
* @param[in] td Transaction data
* @retval 0 OK
* @retval -1 Error
*/
int
plugin_transaction_abort(clicon_handle h,
transaction_data_t *td)
{
int retval = 0;
int i;
struct plugin *p;
for (i = 0; i < nplugins; i++) {
p = &plugins[i];
if (p->p_trans_abort)
(p->p_trans_abort)(h, (transaction_data)td); /* dont abort on error */
}
return retval;
}

View file

@ -0,0 +1,72 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef _BACKEND_PLUGIN_H_
#define _BACKEND_PLUGIN_H_
/*
* Types
*/
/*! Transaction data
* Clicon internal, presented as void* to app's callback in the 'transaction_data'
* type in clicon_backend_api.h
* XXX: move to .c file?
*/
typedef struct {
uint64_t td_id; /* Transaction id */
void *td_arg; /* Callback argument */
cxobj *td_src; /* Source database xml tree */
cxobj *td_target; /* Target database xml tree */
cxobj **td_dvec; /* Delete xml vector */
size_t td_dlen; /* Delete xml vector length */
cxobj **td_avec; /* Add xml vector */
size_t td_alen; /* Add xml vector length */
cxobj **td_scvec; /* Source changed xml vector */
cxobj **td_tcvec; /* Target changed xml vector */
size_t td_clen; /* Changed xml vector length */
} transaction_data_t;
/*
* Prototypes
*/
int config_plugin_init(clicon_handle h);
int plugin_initiate(clicon_handle h);
int plugin_finish(clicon_handle h);
int plugin_reset_state(clicon_handle h, char *dbname);
int plugin_start_hooks(clicon_handle h, int argc, char **argv);
int plugin_downcall(clicon_handle h, struct clicon_msg_call_req *req,
uint16_t *retlen, void **retarg);
transaction_data_t * transaction_new(void);
int transaction_free(transaction_data_t *);
int plugin_transaction_begin(clicon_handle h, transaction_data_t *td);
int plugin_transaction_validate(clicon_handle h, transaction_data_t *td);
int plugin_transaction_complete(clicon_handle h, transaction_data_t *td);
int plugin_transaction_commit(clicon_handle h, transaction_data_t *td);
int plugin_transaction_end(clicon_handle h, transaction_data_t *td);
int plugin_transaction_abort(clicon_handle h, transaction_data_t *td);
#endif /* _BACKEND_PLUGIN_H_ */

View file

@ -0,0 +1,262 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "clicon_config.h" /* generated by config & autoconf */
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <time.h>
#include <syslog.h>
#include <grp.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/param.h>
#ifdef HAVE_SYS_UCRED_H
#include <sys/types.h>
#include <sys/ucred.h>
#endif
#define __USE_GNU
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cligen/cligen.h>
/* clicon */
#include <clicon/clicon.h>
#include "backend_socket.h"
#include "backend_client.h"
#include "backend_handle.h"
static int
config_socket_init_ipv4(clicon_handle h, char *dst)
{
int s;
struct sockaddr_in addr;
uint16_t port;
port = clicon_sock_port(h);
/* create inet socket */
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
clicon_err(OE_UNIX, errno, "socket");
return -1;
}
// setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*)&one, sizeof(one));
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
if (inet_pton(addr.sin_family, dst, &addr.sin_addr) != 1){
clicon_err(OE_UNIX, errno, "inet_pton: %s (Expected IPv4 address. Check settings of CLICON_SOCK_FAMILY and CLICON_SOCK)", dst);
goto err; /* Could check getaddrinfo */
}
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0){
clicon_err(OE_UNIX, errno, "%s: bind", __FUNCTION__);
goto err;
}
clicon_debug(1, "Listen on server socket at %s:%hu", dst, port);
if (listen(s, 5) < 0){
clicon_err(OE_UNIX, errno, "%s: listen", __FUNCTION__);
goto err;
}
return s;
err:
close(s);
return -1;
}
/*! Open a socket and bind it to a file descriptor
*
* The socket is accessed via CLICON_SOCK option, has 770 permissions
* and group according to CLICON_SOCK_GROUP option.
*/
static int
config_socket_init_unix(clicon_handle h, char *sock)
{
int s;
struct sockaddr_un addr;
mode_t old_mask;
char *config_group;
gid_t gid;
struct stat st;
if (lstat(sock, &st) == 0 && unlink(sock) < 0){
clicon_err(OE_UNIX, errno, "%s: unlink(%s)", __FUNCTION__, sock);
return -1;
}
/* then find configuration group (for clients) and find its groupid */
if ((config_group = clicon_sock_group(h)) == NULL){
clicon_err(OE_FATAL, 0, "clicon_sock_group option not set");
return -1;
}
if (group_name2gid(config_group, &gid) < 0)
return -1;
#if 0
if (gid == 0)
clicon_log(LOG_WARNING, "%s: No such group: %s\n", __FUNCTION__, config_group);
#endif
/* create unix socket */
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
clicon_err(OE_UNIX, errno, "%s: socket", __FUNCTION__);
return -1;
}
// setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*)&one, sizeof(one));
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, sock, sizeof(addr.sun_path)-1);
old_mask = umask(S_IRWXO | S_IXGRP | S_IXUSR);
if (bind(s, (struct sockaddr *)&addr, SUN_LEN(&addr)) < 0){
clicon_err(OE_UNIX, errno, "%s: bind", __FUNCTION__);
umask(old_mask);
goto err;
}
umask(old_mask);
/* change socket path file group */
if (lchown(sock, -1, gid) < 0){
clicon_err(OE_UNIX, errno, "%s: lchown(%s, %s)", __FUNCTION__,
sock, config_group);
goto err;
}
clicon_debug(1, "Listen on server socket at %s", addr.sun_path);
if (listen(s, 5) < 0){
clicon_err(OE_UNIX, errno, "%s: listen", __FUNCTION__);
goto err;
}
return s;
err:
close(s);
return -1;
}
int
config_socket_init(clicon_handle h)
{
char *sock;
if ((sock = clicon_sock(h)) == NULL){
clicon_err(OE_FATAL, 0, "CLICON_SOCK option not set");
return -1;
}
switch (clicon_sock_family(h)){
case AF_UNIX:
return config_socket_init_unix(h, sock);
break;
case AF_INET:
return config_socket_init_ipv4(h, sock);
break;
}
return 0;
}
/*
* config_accept_client
* XXX: credentials not properly implemented
*/
int
config_accept_client(int fd, void *arg)
{
int retval = -1;
clicon_handle h = (clicon_handle)arg;
int s;
struct sockaddr_un from;
socklen_t len;
struct client_entry *ce;
#ifdef DONT_WORK /* XXX HAVE_SYS_UCRED_H */
struct xucred credentials; /* FreeBSD. */
socklen_t clen;
#elif defined(SO_PEERCRED)
struct ucred credentials; /* Linux. */
socklen_t clen;
#endif
char *config_group;
struct group *gr;
char *mem;
int i;
clicon_debug(1, "%s", __FUNCTION__);
len = sizeof(from);
if ((s = accept(fd, (struct sockaddr*)&from, &len)) < 0){
clicon_err(OE_UNIX, errno, "%s: accept", __FUNCTION__);
goto done;
}
#if defined(SO_PEERCRED)
/* fill in the user data structure */
clen = sizeof(credentials);
if(getsockopt(s, SOL_SOCKET, SO_PEERCRED/* XXX finns ej i freebsd*/, &credentials, &clen)){
clicon_err(OE_UNIX, errno, "%s: getsockopt", __FUNCTION__);
goto done;
}
#endif
if ((ce = backend_client_add(h, (struct sockaddr*)&from)) == NULL)
goto done;
#if defined(SO_PEERCRED)
ce->ce_pid = credentials.pid;
ce->ce_uid = credentials.uid;
#endif
ce->ce_handle = h;
/* check credentials of caller (not properly implemented yet) */
if ((config_group = clicon_sock_group(h)) == NULL){
clicon_err(OE_FATAL, 0, "clicon_sock_group option not set");
goto done;
}
if ((gr = getgrnam(config_group)) != NULL){
i = 0; /* one of mem should correspond to ce->ce_uid */
while ((mem = gr->gr_mem[i++]) != NULL)
;
}
#if 0
{ /* XXX */
int ii;
struct client_entry *c;
for (c = ce_list, ii=0; c; c = c->ce_next, ii++);
clicon_debug(1, "Open client socket (nr:%d pid:%d [Total: %d])",
ce->ce_nr, ce->ce_pid, ii);
}
#endif
ce->ce_s = s;
/*
* Here we register callbacks for actual data socket
*/
if (event_reg_fd(s, from_client, (void*)ce, "client socket") < 0)
goto done;
retval = 0;
done:
return retval;
}

View file

@ -0,0 +1,33 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef _BACKEND_SOCKET_H_
#define _BACKEND_SOCKET_H_
/*
* Prototypes
*/
int config_socket_init(clicon_handle h);
int config_accept_client(int fd, void *arg);
#endif /* _BACKEND_SOCKET_H_ */

View file

@ -0,0 +1,92 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
* The exported interface to plugins. External apps (eg backend plugins) should
* only include this file.
* Internal code should not include this file
*/
#ifndef _CLICON_BACKEND_H_
#define _CLICON_BACKEND_H_
/*
* Use this constant to disable some prototypes that should not be visible outside the lib.
* This is an alternative to use separate internal include files.
*/
/* Common code (API and Backend daemon) */
#include <clicon/clicon_backend_handle.h>
#include <clicon/clicon_backend_transaction.h>
/*! Clicon Backend plugin callbacks: use these in your backend plugin code
*/
/*! Called when plugin loaded. Only mandadory callback. All others optional
* @see plginit_t
*/
int plugin_init(clicon_handle h);
/* Called when backend started with cmd-line arguments from daemon call.
* @see plgstart_t
*/
int plugin_start(clicon_handle h, int argc, char **argv);
/* Called just before plugin unloaded.
* @see plgexit_t
*/
int plugin_exit(clicon_handle h);
/*! Reset system state to original state. Eg at reboot before running thru config.
* @see plgreset_t
*/
int plugin_reset(clicon_handle h, char *dbname);
/*! Called before a commit/validate sequence begins. Eg setup state before commit
* @see trans_cb_t
*/
int transaction_begin(clicon_handle h, transaction_data td);
/*! Validate.
* @see trans_cb_t
*/
int transaction_validate(clicon_handle h, transaction_data td);
/* Called after a validation completed succesfully (but before commit).
* @see trans_cb_t
*/
int transaction_complete(clicon_handle h, transaction_data td);
/* Commit.
* @see trans_cb_t
*/
int transaction_commit(clicon_handle h, transaction_data td);
/* Called after a commit sequence completed succesfully.
* @see trans_cb_t
*/
int transaction_end(clicon_handle h, transaction_data td);
/* Called if commit or validate sequence fails. After eventual rollback.
* @see trans_cb_t
*/
int transaction_abort(clicon_handle h, transaction_data td);
#endif /* _CLICON_BACKEND_H_ */

View file

@ -0,0 +1,353 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "clicon_config.h" /* generated by config & autoconf */
#endif
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include <dirent.h>
#include <errno.h>
#include <unistd.h>
#include <assert.h>
#include <fnmatch.h>
#include <sys/types.h>
#include <sys/time.h>
#include <regex.h>
#include <netinet/in.h>
/* cligen */
#include <cligen/cligen.h>
/* clicon */
#include <clicon/clicon.h>
#include "clicon_backend_handle.h"
#include "backend_client.h"
#include "backend_handle.h"
/* header part is copied from struct clicon_handle in lib/src/clicon_handle.c */
#define CLICON_MAGIC 0x99aafabe
#define handle(h) (assert(clicon_handle_check(h)==0),(struct backend_handle *)(h))
/* Clicon_handle for backends.
* First part of this is header, same for clicon_handle and cli_handle.
* Access functions for common fields are found in clicon lib: clicon_options.[ch]
* This file should only contain access functions for the _specific_
* entries in the struct below.
*/
struct backend_handle {
int cb_magic; /* magic (HDR)*/
clicon_hash_t *cb_copt; /* clicon option list (HDR) */
clicon_hash_t *cb_data; /* internal clicon data (HDR) */
/* ------ end of common handle ------ */
struct client_entry *cb_ce_list; /* The client list */
int cb_ce_nr; /* Number of clients, just increment */
struct handle_subscription *cb_subscription; /* Event subscription list */
};
/*! Creates and returns a clicon config handle for other CLICON API calls
*/
clicon_handle
backend_handle_init(void)
{
return clicon_handle_init0(sizeof(struct backend_handle));
}
/*! Deallocates a backend handle, including all client structs
* @Note: handle 'h' cannot be used in calls after this
*/
int
backend_handle_exit(clicon_handle h)
{
struct client_entry *ce;
/* only delete client structs, not close sockets, etc, see backend_client_rm */
while ((ce = backend_client_list(h)) != NULL)
backend_client_delete(h, ce);
clicon_handle_exit(h); /* frees h and options */
return 0;
}
/*! Notify event and distribute to all registered clients
*
* @param[in] h Clicon handle
* @param[in] stream Name of event stream. CLICON is predefined as LOG stream
* @param[in] level Event level (not used yet)
* @param[in] event Actual message as text format
*
* Stream is a string used to qualify the event-stream. Distribute the
* event to all clients registered to this backend.
* XXX: event-log NYI.
* @see also subscription_add()
* @see also backend_notify_xml()
*/
int
backend_notify(clicon_handle h, char *stream, int level, char *event)
{
struct client_entry *ce;
struct client_subscription *su;
struct handle_subscription *hs;
int retval = -1;
/* First thru all clients(sessions), and all subscriptions and find matches */
for (ce = backend_client_list(h); ce; ce = ce->ce_next)
for (su = ce->ce_subscription; su; su = su->su_next)
if (strcmp(su->su_stream, stream) == 0){
if (fnmatch(su->su_filter, event, 0) == 0)
if (send_msg_notify(ce->ce_s, level, event) < 0)
goto done;
}
/* Then go thru all global (handle) subscriptions and find matches */
hs = NULL;
while ((hs = subscription_each(h, hs)) != NULL){
if (hs->hs_format != MSG_NOTIFY_TXT)
continue;
if (strcmp(hs->hs_stream, stream))
continue;
if (fnmatch(hs->hs_filter, event, 0) == 0)
if ((*hs->hs_fn)(h, event, hs->hs_arg) < 0)
goto done;
}
retval = 0;
done:
return retval;
}
/*! Notify event and distribute to all registered clients
*
* @param[in] h Clicon handle
* @param[in] stream Name of event stream. CLICON is predefined as LOG stream
* @param[in] level Event level (not used yet)
* @param[in] event Actual message as xml tree
*
* Stream is a string used to qualify the event-stream. Distribute the
* event to all clients registered to this backend.
* XXX: event-log NYI.
* @see also subscription_add()
* @see also backend_notify()
*/
int
backend_notify_xml(clicon_handle h, char *stream, int level, cxobj *x)
{
struct client_entry *ce;
struct client_subscription *su;
int retval = -1;
cbuf *cb = NULL;
struct handle_subscription *hs;
/* Now go thru all clients(sessions), and all subscriptions and find matches */
for (ce = backend_client_list(h); ce; ce = ce->ce_next)
for (su = ce->ce_subscription; su; su = su->su_next)
if (strcmp(su->su_stream, stream) == 0){
if (strlen(su->su_filter)==0 || xpath_first(x, su->su_filter) != NULL){
if (cb==NULL){
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_PLUGIN, errno, "cbuf_new");
goto done;
}
if (clicon_xml2cbuf(cb, x, 0, 0) < 0)
goto done;
}
if (send_msg_notify(ce->ce_s, level, cbuf_get(cb)) < 0)
goto done;
}
}
/* Then go thru all global (handle) subscriptions and find matches */
/* XXX: x contains name==dk-ore, but filter is
id==/[userid=d2d5e46c-c6f9-42f3-9a69-fb52fe60940d] */
hs = NULL;
while ((hs = subscription_each(h, hs)) != NULL){
if (hs->hs_format != MSG_NOTIFY_XML)
continue;
if (strcmp(hs->hs_stream, stream))
continue;
if (strlen(hs->hs_filter)==0 || xpath_first(x, hs->hs_filter) != NULL)
if ((*hs->hs_fn)(h, x, hs->hs_arg) < 0)
goto done;
}
retval = 0;
done:
if (cb)
cbuf_free(cb);
return retval;
}
struct client_entry *
backend_client_add(clicon_handle h, struct sockaddr *addr)
{
struct backend_handle *cb = handle(h);
struct client_entry *ce;
if ((ce = (struct client_entry *)malloc(sizeof(*ce))) == NULL){
clicon_err(OE_PLUGIN, errno, "malloc");
return NULL;
}
memset(ce, 0, sizeof(*ce));
ce->ce_nr = cb->cb_ce_nr++;
memcpy(&ce->ce_addr, addr, sizeof(*addr));
ce->ce_next = cb->cb_ce_list;
cb->cb_ce_list = ce;
return ce;
}
struct client_entry *
backend_client_list(clicon_handle h)
{
struct backend_handle *cb = handle(h);
return cb->cb_ce_list;
}
/*! Actually remove client from list
* See also backend_client_rm()
*/
int
backend_client_delete(clicon_handle h, struct client_entry *ce)
{
struct client_entry *c;
struct client_entry **ce_prev;
struct backend_handle *cb = handle(h);
ce_prev = &cb->cb_ce_list;
for (c = *ce_prev; c; c = c->ce_next){
if (c == ce){
*ce_prev = c->ce_next;
free(ce);
break;
}
ce_prev = &c->ce_next;
}
return 0;
}
/*! Add subscription given stream name, callback and argument
* @param[in] h Clicon handle
* @param[in] stream Name of event stream
* @param[in] format Expected format of event, eg text or xml
* @param[in] filter Filter to match event, depends on format, eg xpath for xml
* @param[in] fn Callback when event occurs
* @param[in] arg Argument to use with callback. Also handle when deleting
* Note that arg is not a real handle.
* @see subscription_delete
* @see subscription_each
*/
struct handle_subscription *
subscription_add(clicon_handle h,
char *stream,
enum format_enum format,
char *filter,
subscription_fn_t fn,
void *arg)
{
struct backend_handle *cb = handle(h);
struct handle_subscription *hs = NULL;
if ((hs = malloc(sizeof(*hs))) == NULL){
clicon_err(OE_PLUGIN, errno, "malloc");
goto done;
}
memset(hs, 0, sizeof(*hs));
hs->hs_stream = strdup(stream);
hs->hs_format = format;
hs->hs_filter = strdup(filter);
hs->hs_next = cb->cb_subscription;
hs->hs_fn = fn;
hs->hs_arg = arg;
cb->cb_subscription = hs;
done:
return hs;
}
/*! Delete subscription given stream name, callback and argument
* @param[in] h Clicon handle
* @param[in] stream Name of event stream
* @param[in] fn Callback when event occurs
* @param[in] arg Argument to use with callback and handle
* Note that arg is not a real handle.
* @see subscription_add
* @see subscription_each
*/
int
subscription_delete(clicon_handle h,
char *stream,
subscription_fn_t fn,
void *arg)
{
struct backend_handle *cb = handle(h);
struct handle_subscription *hs;
struct handle_subscription **hs_prev;
hs_prev = &cb->cb_subscription; /* this points to stack and is not real backpointer */
for (hs = *hs_prev; hs; hs = hs->hs_next){
/* XXX arg == hs->hs_arg */
if (strcmp(hs->hs_stream, stream)==0 && hs->hs_fn == fn){
*hs_prev = hs->hs_next;
free(hs->hs_stream);
if (hs->hs_filter)
free(hs->hs_filter);
if (hs->hs_arg)
free(hs->hs_arg);
free(hs);
break;
}
hs_prev = &hs->hs_next;
}
return 0;
}
/*! Iterator over subscriptions
*
* NOTE: Never manipulate the child-list during operation or using the
* same object recursively, the function uses an internal field to remember the
* index used. It works as long as the same object is not iterated concurrently.
*
* @param[in] h clicon handle
* @param[in] hprev iterator, initialize with NULL
* @code
* clicon_handle h;
* struct handle_subscription *hs = NULL;
* while ((hs = subscription_each(h, hs)) != NULL) {
* ...
* }
* @endcode
*/
struct handle_subscription *
subscription_each(clicon_handle h,
struct handle_subscription *hprev)
{
struct backend_handle *cb = handle(h);
struct handle_subscription *hs = NULL;
if (hprev)
hs = hprev->hs_next;
else
hs = cb->cb_subscription;
return hs;
}

View file

@ -0,0 +1,71 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
* Part of the external API to plugins. Applications should not include
* this file directly (only via clicon_backend.h).
* Internal code should include this
*/
#ifndef _CLICON_BACKEND_HANDLE_H_
#define _CLICON_BACKEND_HANDLE_H_
/*
* Types
*/
/*! Generic downcall registration.
* Enables any function to be called from (cli) frontend
* to backend. Like an RPC on application-level.
*/
typedef int (*downcall_cb)(clicon_handle h, uint16_t op, uint16_t len,
void *arg, uint16_t *retlen, void **retarg);
/*
* Log for netconf notify function (config_client.c)
*/
int backend_notify(clicon_handle h, char *stream, int level, char *txt);
int backend_notify_xml(clicon_handle h, char *stream, int level, cxobj *x);
/* subscription callback */
typedef int (*subscription_fn_t)(clicon_handle, void *filter, void *arg);
/* Notification subscription info
* @see client_subscription in config_client.h
*/
struct handle_subscription{
struct handle_subscription *hs_next;
enum format_enum hs_format; /* format (enum format_enum) XXX not needed? */
char *hs_stream; /* name of notify stream */
char *hs_filter; /* filter, if format=xml: xpath, if text: fnmatch */
subscription_fn_t hs_fn; /* Callback when event occurs */
void *hs_arg; /* Callback argument */
};
struct handle_subscription *subscription_add(clicon_handle h, char *stream,
enum format_enum format, char *filter,
subscription_fn_t fn, void *arg);
int subscription_delete(clicon_handle h, char *stream,
subscription_fn_t fn, void *arg);
struct handle_subscription *subscription_each(clicon_handle h,
struct handle_subscription *hprev);
#endif /* _CLICON_BACKEND_HANDLE_H_ */

View file

@ -0,0 +1,206 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*/
/*
* Note that the functions in this file are accessible from the plugins
*/
#ifdef HAVE_CONFIG_H
#include "clicon_config.h" /* generated by config & autoconf */
#endif
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include <dirent.h>
#include <errno.h>
#include <ctype.h>
#include <sys/types.h>
#include <regex.h>
#include <netinet/in.h>
/* cligen */
#include <cligen/cligen.h>
/* clicon */
#include <clicon/clicon.h>
#include "clicon_backend_transaction.h"
#include "backend_plugin.h"
/* Access functions for transaction-data handle in callbacks
* Expressed in a transition from an current -> wanted state.
* For example, adding a database symbol 'a' in candidate and commiting
* would give running in source and 'a' and candidate in 'target'.
*/
/*! Get transaction id
* @param[in] td transaction_data
* @retval id transaction id
*/
uint64_t
transaction_id(transaction_data td)
{
return ((transaction_data_t *)td)->td_id;
}
/*! Get plugin/application specific callbackargument
* @param[in] td transaction_data
* @retval arg callback argument
* @note NYI
*/
void *
transaction_arg(transaction_data td)
{
return ((transaction_data_t *)td)->td_arg;
}
/*! Get Source database xml tree
* @param[in] td transaction_data
* @retval src source xml tree containing original state
*/
cxobj *
transaction_src(transaction_data td)
{
return ((transaction_data_t *)td)->td_src;
}
/*! Get target database xml tree
* @param[in] td transaction_data
* @retval xml target xml tree containing wanted state
*/
cxobj *
transaction_target(transaction_data td)
{
return ((transaction_data_t *)td)->td_target;
}
/*! Get delete xml vector, ie vector of xml nodes that are deleted src->target
* @param[in] td transaction_data
* @retval vec Vector of xml nodes
*/
cxobj **
transaction_dvec(transaction_data td)
{
return ((transaction_data_t *)td)->td_dvec;
}
/*! Get length of delete xml vector
* @param[in] td transaction_data
* @retval len Length of vector of xml nodes
* @see transaction_dvec
*/
size_t
transaction_dlen(transaction_data td)
{
return ((transaction_data_t *)td)->td_dlen;
}
/*! Get add xml vector, ie vector of xml nodes that are added src->target
* @param[in] td transaction_data
* @retval vec Vector of xml nodes
*/
cxobj **
transaction_avec(transaction_data td)
{
return ((transaction_data_t *)td)->td_avec;
}
/*! Get length of add xml vector
* @param[in] td transaction_data
* @retval len Length of vector of xml nodes
* @see transaction_avec
*/
size_t
transaction_alen(transaction_data td)
{
return ((transaction_data_t *)td)->td_alen;
}
/*! Get source changed xml vector, ie vector of xml nodes that changed
* @param[in] td transaction_data
* @retval vec Vector of xml nodes
* These are only nodes of type LEAF.
* For each node in this vector which contains the original value, there
* is a node in tcvec with the changed value
* @see transaction_dcvec
*/
cxobj **
transaction_scvec(transaction_data td)
{
return ((transaction_data_t *)td)->td_scvec;
}
/*! Get target changed xml vector, ie vector of xml nodes that changed
* @param[in] td transaction_data
* @retval vec Vector of xml nodes
* These are only nodes of type LEAF.
* For each node in this vector which contains the original value, there
* is a node in tcvec with the changed value
* @see transaction_scvec
*/
cxobj **
transaction_tcvec(transaction_data td)
{
return ((transaction_data_t *)td)->td_dvec;
}
/*! Get length of changed xml vector
* @param[in] td transaction_data
* @retval len Length of vector of xml nodes
* This is the length of both the src change vector and the target change vector
*/
size_t
transaction_clen(transaction_data td)
{
return ((transaction_data_t *)td)->td_clen;
}
int
transaction_print(FILE *f,
transaction_data th)
{
cxobj *xn;
int i;
transaction_data_t *td;
td = (transaction_data_t *)th;
fprintf(f, "Transaction id: 0x%llx\n", td->td_id);
fprintf(f, "Removed\n=========\n");
for (i=0; i<td->td_dlen; i++){
xn = td->td_dvec[i];
clicon_xml2file(f, xn, 0, 1);
}
fprintf(f, "Added\n=========\n");
for (i=0; i<td->td_alen; i++){
xn = td->td_avec[i];
clicon_xml2file(f, xn, 0, 1);
}
fprintf(stderr, "Changed\n=========\n");
for (i=0; i<td->td_clen; i++){
xn = td->td_scvec[i];
clicon_xml2file(f, xn, 0, 1);
xn = td->td_tcvec[i];
clicon_xml2file(f, xn, 0, 1);
}
return 0;
}

View file

@ -0,0 +1,60 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
* Part of the external API to plugins. Applications should not include
* this file directly (only via clicon_backend.h).
* Internal code should include this
*/
#ifndef _CLICON_BACKEND_TRANSACTION_H_
#define _CLICON_BACKEND_TRANSACTION_H_
/*
* Types
*/
/*! Generic downcall registration.
* Enables any function to be called from (cli) frontend
* to backend. Like an RPC on application-level.
*/
typedef int (*downcall_cb)(clicon_handle h, uint16_t op, uint16_t len,
void *arg, uint16_t *retlen, void **retarg);
/* Transaction callback data accessors for client plugins
* (defined in config_dbdep.c)
* @see transaction_data_t internal structure
*/
typedef void *transaction_data;
uint64_t transaction_id(transaction_data td);
void *transaction_arg(transaction_data td);
cxobj *transaction_src(transaction_data td);
cxobj *transaction_target(transaction_data td);
cxobj **transaction_dvec(transaction_data td);
size_t transaction_dlen(transaction_data td);
cxobj **transaction_avec(transaction_data td);
size_t transaction_alen(transaction_data td);
cxobj **transaction_scvec(transaction_data td);
cxobj **transaction_tcvec(transaction_data td);
size_t transaction_clen(transaction_data td);
int transaction_print(FILE *f, transaction_data th);
#endif /* _CLICON_BACKEND_TRANSACTION_H_ */

Binary file not shown.

134
apps/cli/Makefile.in Normal file
View file

@ -0,0 +1,134 @@
#
# Makefile
#
# Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
#
# This file is part of CLICON.
#
# CLICON is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# CLICON is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with CLICON; see the file COPYING. If not, see
# <http://www.gnu.org/licenses/>.
#
#
VPATH = @srcdir@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
CC = @CC@
CFLAGS = @CFLAGS@
LDFLAGS = @LDFLAGS@
prefix = @prefix@
datarootdir = @datarootdir@
exec_prefix = @exec_prefix@
bindir = @bindir@
libdir = @libdir@
mandir = @mandir@
libexecdir = @libexecdir@
localstatedir = @localstatedir@
sysconfdir = @sysconfdir@
includedir = @includedir@
SH_SUFFIX = @SH_SUFFIX@
CLICON_MAJOR = @CLICON_VERSION_MAJOR@
CLICON_MINOR = @CLICON_VERSION_MINOR@
# Use this clicon lib for linking
CLICON_LIB = libclicon.so.$(CLICON_MAJOR).$(CLICON_MINOR)
# Location of system plugins
CLICON_CLI_SYSDIR = $(libdir)/clicon/plugins/cli
# For dependency. A little strange that we rely on it being built in the src dir
# even though it may exist in $(libdir). But the new version may not have been installed yet.
LIBDEPS = $(top_srcdir)/lib/src/$(CLICON_LIB)
LIBS = -L$(top_srcdir)/lib/src @LIBS@ -l:$(CLICON_LIB) -lpthread
CPPFLAGS = @CPPFLAGS@ -fPIC
INCLUDES = -I. -I$(top_srcdir)/lib -I$(top_srcdir)/include -I$(top_srcdir) @INCLUDES@
APPL = clicon_cli
SRC = cli_main.c
OBJS = $(SRC:.c=.o)
MYNAME = clicon_cli
MYLIBLINK = lib$(MYNAME)$(SH_SUFFIX)
MYLIB = $(MYLIBLINK).$(CLICON_MAJOR).$(CLICON_MINOR)
MYLIBSO = $(MYLIBLINK).$(CLICON_MAJOR)
LIBSRC = cli_plugin.c cli_common.c cli_handle.c cli_generate.c
LIBOBJS = $(LIBSRC:.c=.o)
all: $(MYLIB) $(APPL) test
clean:
rm -f $(OBJS) $(LIBOBJS) *.core $(APPL) $(MYLIB) $(MYLIBSO) $(MYLIBLINK)
distclean: clean
rm -f Makefile *~ .depend
# Put daemon in bin
# Put other executables in libexec/
# Also create a libexec/ directory for writeable/temporary files.
# Put config file in etc/
install: install-lib $(APPL)
install -d $(DESTDIR)$(bindir)
install $(APPL) $(DESTDIR)$(bindir)
install-lib: $(MYLIB)
install -d $(DESTDIR)$(libdir)
install $(MYLIB) $(DESTDIR)$(libdir)
ln -sf $(MYLIB) $(DESTDIR)$(libdir)/$(MYLIBSO) # -l:libclicon_cli.so.2
ln -sf $(MYLIBSO) $(DESTDIR)$(libdir)/$(MYLIBLINK) # -l:libclicon_cli.so
install -d $(DESTDIR)$(libdir)/clicon/plugins/cli
install-include: clicon_cli.h clicon_cli_api.h
install -d $(DESTDIR)$(includedir)/clicon
install -m 644 $^ $(DESTDIR)$(includedir)/clicon
uninstall:
rm -f $(bindir)/$(APPL)
rm -f $(libdir)/$(MYLIB)
rm -f $(includedir)/clicon/*
.SUFFIXES:
.SUFFIXES: .c .o
.c.o:
$(CC) $(INCLUDES) $(CPPFLAGS) -D__PROGRAM__=\"$(APPL)\" -DCLICON_CLI_SYSDIR=\"$(CLICON_CLI_SYSDIR)\" $(CFLAGS) -c $<
# Just link test programs
test.c :
echo "main(){}" > $@
test: test.c $(LIBOBJ)
$(CC) $(INCLUDES) $(LDFLAGS) $< $(LIBOBJ) -L. -l:$(MYLIB) $(LIBS) -o $@
$(APPL): $(OBJS) $(MYLIBLINK) $(LIBDEPS)
$(CC) $(LDFLAGS) $(OBJS) -L. -l:$(MYLIB) $(LIBS) -o $@
$(MYLIB) : $(LIBOBJS)
$(CC) -shared -Wl,-soname,$(MYLIBSO) -o $@ $(LIBOBJS) $(LIBS) -Wl,-soname=$(MYLIBSO)
# link-name is needed for application linking, eg for clicon_cli and clicon_config
$(MYLIBLINK) : $(MYLIB)
# ln -sf $(MYLIB) $(MYLIBSO)
# ln -sf $(MYLIB) $@
TAGS:
find . -name '*.[chyl]' -print | etags -
depend:
$(CC) $(DEPENDFLAGS) @DEFS@ $(INCLUDES) $(CFLAGS) -MM $(SRC) $(APPSRC) > .depend
#include .depend

1930
apps/cli/cli_common.c Normal file

File diff suppressed because it is too large Load diff

33
apps/cli/cli_common.h Normal file
View file

@ -0,0 +1,33 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
*/
#ifndef _CLI_COMMON_H_
#define _CLI_COMMON_H_
void cli_signal_block(clicon_handle h);
void cli_signal_unblock(clicon_handle h);
/* If you do not find a function here it may be in clicon_cli_api.h which is
the external API */
#endif /* _CLI_COMMON_H_ */

689
apps/cli/cli_generate.c Normal file
View file

@ -0,0 +1,689 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
* Translation between database specs
* dbspec_key yang_spec CLIgen parse_tree
* +-------------+ key2yang +-------------+ yang2cli +-------------+
* | keyspec | -------------> | | ------------> | cli |
* | A[].B !$a | yang2key | list{key A;}| | syntax |
* +-------------+ <------------ +-------------+ +-------------+
*/
#ifdef HAVE_CONFIG_H
#include "clicon_config.h" /* generated by config & autoconf */
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include <fcntl.h>
#include <sys/param.h>
/* cligen */
#include <cligen/cligen.h>
/* clicon */
#include <clicon/clicon.h>
#include "clicon_cli_api.h"
#include "cli_plugin.h"
#include "cli_generate.h"
/* This is the default callback function. But this is typically overwritten */
#define GENERATE_CALLBACK "cli_set"
/* variable expand function */
#define GENERATE_EXPAND_LVEC "expand_dbvar_auto"
#define GENERATE_EXPAND_XMLDB "expand_dbvar_dbxml"
/*=====================================================================
* YANG generate CLI
*=====================================================================*/
#if 0 /* examples/ntp */
ntp("Network Time Protocol"),cli_set("ntp");{
logging("Configure NTP message logging"),cli_set("ntp.logging");{
status (<status:bool>),cli_set("ntp.logging $status:bool");
}
server("Configure NTP Server") (<ipv4addr:ipv4addr>("IPv4 address of peer")),cli_set("ntp.server[] $!ipv4addr:ipv4addr");
}
#endif
#if 0 /* examples/datamodel */
WITH COMPLETION:
a (<x:number>|<x:number expand_dbvar_auto("candidate a[] $!x")>),cli_set("a[] $!x");{
b,cli_set("a[].b $!x");{
y (<y:string>|<y:string expand_dbvar_auto("candidate a[].b $!x $y")>),cli_set("a[].b $!x $y");
}
z (<z:string>|<z:string expand_dbvar_auto("candidate a[] $!x $z")>),cli_set("a[] $!x $z");
}
#endif
#ifndef HAVE_CLIGEN_MAX2STR /* XXX cligen 3.6 feature */
/*! Print max value of a CLIgen variable type as string
* @param[in] type CLIgen variable type
* @param[out] str Max value printed in this string
* @param[in] size Length of 'str'
* @retval len How many bytes printed
* @see cvtype_max2str_dup
* You can use str=NULL to get the expected length.
* The number of (potentially if str=NULL) written bytes is returned.
*/
static int
cvtype_max2str(enum cv_type type, char *str, size_t size)
{
int len = 0;
switch (type){
case CGV_INT8:
len = snprintf(str, size, "%" PRId8, INT8_MAX);
break;
case CGV_INT16:
len = snprintf(str, size, "%" PRId16, INT16_MAX);
break;
case CGV_INT32:
len = snprintf(str, size, "%" PRId32, INT32_MAX);
break;
case CGV_INT64:
len = snprintf(str, size, "%" PRId64, INT64_MAX);
break;
case CGV_UINT8:
len = snprintf(str, size, "%" PRIu8, UINT8_MAX);
break;
case CGV_UINT16:
len = snprintf(str, size, "%" PRIu16, UINT16_MAX);
break;
case CGV_UINT32:
len = snprintf(str, size, "%" PRIu32, UINT32_MAX);
break;
case CGV_UINT64:
len = snprintf(str, size, "%" PRIu64, UINT64_MAX);
break;
case CGV_DEC64:
len = snprintf(str, size, "%" PRId64 ".0", INT64_MAX);
break;
case CGV_BOOL:
len = snprintf(str, size, "true");
break;
default:
break;
}
return len;
}
/*! Print max value of a CLIgen variable type as string
*
* The string should be freed after use.
* @param[in] type CLIgen variable type
* @retval str Malloced string containing value. Should be freed after use.
* @see cvtype_max2str
*/
static char *
cvtype_max2str_dup(enum cv_type type)
{
int len;
char *str;
if ((len = cvtype_max2str(type, NULL, 0)) < 0)
return NULL;
if ((str = (char *)malloc (len+1)) == NULL)
return NULL;
memset (str, '\0', len+1);
if ((cvtype_max2str(type, str, len+1)) < 0){
free(str);
return NULL;
}
return str;
}
#endif /* HAVE_CLIGEN_MAX2STR */
/*! Create cligen variable expand entry with xmlkey format string as argument
* @param[in] h clicon handle
* @param[in] ys yang_stmt of the node at hand
* @param[in] cvtype Type of the cligen variable
* @param[in] cb0 The string where the result format string is inserted.
* @see expand_dbvar_dbxml This is where the expand string is used
*/
static int
cli_expand_var_generate(clicon_handle h,
yang_stmt *ys,
enum cv_type cvtype,
cbuf *cb0)
{
int retval = -1;
char *xkfmt = NULL;
if (yang2xmlkeyfmt(ys, &xkfmt) < 0)
goto done;
cprintf(cb0, "|<%s:%s %s(\"candidate %s\")>",
ys->ys_argument,
cv_type2str(cvtype),
GENERATE_EXPAND_XMLDB,
xkfmt);
retval = 0;
done:
if (xkfmt)
free(xkfmt);
return retval;
}
/*! Create callback with xmlkey format string as argument
* @param[in] h clicon handle
* @param[in] ys yang_stmt of the node at hand
* @param[in] cb0 The string where the result format string is inserted.
* @see cli_dbxml This is where the xmlkeyfmt string is used
*/
static int
cli_callback_generate(clicon_handle h,
yang_stmt *ys,
cbuf *cb0)
{
int retval = -1;
char *xkfmt = NULL;
if (yang2xmlkeyfmt(ys, &xkfmt) < 0)
goto done;
cprintf(cb0, ",%s(\"%s\")", GENERATE_CALLBACK, xkfmt);
retval = 0;
done:
if (xkfmt)
free(xkfmt);
return retval;
}
static int yang2cli_stmt(clicon_handle h, yang_stmt *ys,
cbuf *cb0,
enum genmodel_type gt,
int level);
/*
* Check for completion (of already existent values), ranges (eg range[min:max]) and
* patterns, (eg regexp:"[0.9]*").
*/
static int
yang2cli_var_sub(clicon_handle h,
yang_stmt *ys,
cbuf *cb0,
char *description,
enum cv_type cvtype,
yang_stmt *ytype, /* resolved type */
int options,
cg_var *mincv,
cg_var *maxcv,
char *pattern,
uint8_t fraction_digits
)
{
int retval = -1;
char *type;
char *r;
yang_stmt *yi = NULL;
int i = 0;
char *cvtypestr;
int completion;
/* enumeration already gives completion */
if (cvtype == CGV_VOID){
retval = 0;
goto done;
}
type = ytype?ytype->ys_argument:NULL;
if (type)
completion = clicon_cli_genmodel_completion(h) &&
strcmp(type, "enumeration") != 0 &&
strcmp(type, "bits") != 0;
else
completion = clicon_cli_genmodel_completion(h);
if (completion)
cprintf(cb0, "(");
cvtypestr = cv_type2str(cvtype);
cprintf(cb0, "<%s:%s", ys->ys_argument, cvtypestr);
#if 0
if (type && (strcmp(type, "identityref") == 0)){
yang_stmt *ybase;
if ((ybase = yang_find((yang_node*)ytype, Y_BASE, NULL)) != NULL){
cprintf(cb0, " choice:");
i = 0;
/* for every found identity derived from base-type , do: */
{
if (yi->ys_keyword != Y_ENUM && yi->ys_keyword != Y_BIT)
continue;
if (i)
cprintf(cb0, "|");
cprintf(cb0, "%s", yi->ys_argument);
i++;
}
}
}
#endif
if (type && (strcmp(type, "enumeration") == 0 || strcmp(type, "bits") == 0)){
cprintf(cb0, " choice:");
i = 0;
while ((yi = yn_each((yang_node*)ytype, yi)) != NULL){
if (yi->ys_keyword != Y_ENUM && yi->ys_keyword != Y_BIT)
continue;
if (i)
cprintf(cb0, "|");
cprintf(cb0, "%s", yi->ys_argument);
i++;
}
}
if (options & YANG_OPTIONS_FRACTION_DIGITS)
cprintf(cb0, " fraction-digits:%u", fraction_digits);
if (options & (YANG_OPTIONS_RANGE|YANG_OPTIONS_LENGTH)){
cprintf(cb0, " %s[", (options&YANG_OPTIONS_RANGE)?"range":"length");
if (mincv){
if ((r = cv2str_dup(mincv)) == NULL){
clicon_err(OE_UNIX, errno, "cv2str_dup");
goto done;
}
cprintf(cb0, "%s:", r);
free(r);
}
if (maxcv != NULL){
if ((r = cv2str_dup(maxcv)) == NULL){
clicon_err(OE_UNIX, errno, "cv2str_dup");
goto done;
}
}
else{ /* Cligen does not have 'max' keyword in range so need to find actual
max value of type if yang range expression is 0..max */
if ((r = cvtype_max2str_dup(cvtype)) == NULL){
clicon_err(OE_UNIX, errno, "cvtype_max2str");
goto done;
}
}
cprintf(cb0, "%s]", r);
free(r);
}
if (options & YANG_OPTIONS_PATTERN)
cprintf(cb0, " regexp:\"%s\"", pattern);
cprintf(cb0, ">");
if (description)
cprintf(cb0, "(\"%s\")", description);
if (completion){
if (cli_expand_var_generate(h, ys, cvtype, cb0) < 0)
goto done;
if (description)
cprintf(cb0, "(\"%s\")", description);
cprintf(cb0, ")");
}
retval = 0;
done:
return retval;
}
/*! Translate a yang leaf to cligen variable
* Make a type lookup and complete a cligen variable expression such as <a:string>.
* One complication is yang union, that needs a recursion since it consists of sub-types.
* eg type union{ type int32; type string } --> (<x:int32>| <x:string>)
*/
static int
yang2cli_var(clicon_handle h,
yang_stmt *ys,
cbuf *cb0,
char *description)
{
int retval = -1;
char *type; /* orig type */
yang_stmt *yrestype; /* resolved type */
char *restype; /* resolved type */
cg_var *mincv = NULL;
cg_var *maxcv = NULL;
char *pattern = NULL;
yang_stmt *yt = NULL;
yang_stmt *yrt;
uint8_t fraction_digits = 0;
enum cv_type cvtype;
int options = 0;
int i;
if (yang_type_get(ys, &type, &yrestype,
&options, &mincv, &maxcv, &pattern, &fraction_digits) < 0)
goto done;
restype = yrestype?yrestype->ys_argument:NULL;
if (clicon_type2cv(type, restype, &cvtype) < 0)
goto done;
/* Note restype can be NULL here for example with unresolved hardcoded uuid */
if (restype && strcmp(restype, "union") == 0){
/* Union: loop over resolved type's sub-types */
cprintf(cb0, "(");
yt = NULL;
i = 0;
while ((yt = yn_each((yang_node*)yrestype, yt)) != NULL){
if (yt->ys_keyword != Y_TYPE)
continue;
if (i++)
cprintf(cb0, "|");
if (yang_type_resolve(ys, yt, &yrt,
&options, &mincv, &maxcv, &pattern, &fraction_digits) < 0)
goto done;
restype = yrt?yrt->ys_argument:NULL;
if (clicon_type2cv(type, restype, &cvtype) < 0)
goto done;
if ((retval = yang2cli_var_sub(h, ys, cb0, description, cvtype, yrt,
options, mincv, maxcv, pattern, fraction_digits)) < 0)
goto done;
}
cprintf(cb0, ")");
}
else
if ((retval = yang2cli_var_sub(h, ys, cb0, description, cvtype, yrestype,
options, mincv, maxcv, pattern, fraction_digits)) < 0)
goto done;
retval = 0;
done:
return retval;
}
/*!
* @param[in] h Clicon handle
* @param[in] callback If set, include a "; cli_set()" callback, otherwise not.
*/
static int
yang2cli_leaf(clicon_handle h,
yang_stmt *ys,
cbuf *cbuf,
enum genmodel_type gt,
int level,
int callback)
{
yang_stmt *yd; /* description */
int retval = -1;
char *description = NULL;
/* description */
if ((yd = yang_find((yang_node*)ys, Y_DESCRIPTION, NULL)) != NULL)
description = yd->ys_argument;
cprintf(cbuf, "%*s", level*3, "");
if (gt == GT_VARS|| gt == GT_ALL){
cprintf(cbuf, "%s", ys->ys_argument);
if (yd != NULL)
cprintf(cbuf, "(\"%s\")", yd->ys_argument);
cprintf(cbuf, " ");
yang2cli_var(h, ys, cbuf, description);
}
else
yang2cli_var(h, ys, cbuf, description);
if (callback){
if (cli_callback_generate(h, ys, cbuf) < 0)
goto done;
cprintf(cbuf, ";\n");
}
retval = 0;
done:
return retval;
}
static int
yang2cli_container(clicon_handle h,
yang_stmt *ys,
cbuf *cbuf,
enum genmodel_type gt,
int level)
{
yang_stmt *yc;
yang_stmt *yd;
int i;
int retval = -1;
cprintf(cbuf, "%*s%s", level*3, "", ys->ys_argument);
if ((yd = yang_find((yang_node*)ys, Y_DESCRIPTION, NULL)) != NULL)
cprintf(cbuf, "(\"%s\")", yd->ys_argument);
if (cli_callback_generate(h, ys, cbuf) < 0)
goto done;
cprintf(cbuf, ";{\n");
for (i=0; i<ys->ys_len; i++)
if ((yc = ys->ys_stmt[i]) != NULL)
if (yang2cli_stmt(h, yc, cbuf, gt, level+1) < 0)
goto done;
cprintf(cbuf, "%*s}\n", level*3, "");
retval = 0;
done:
return retval;
}
static int
yang2cli_list(clicon_handle h,
yang_stmt *ys,
cbuf *cbuf,
enum genmodel_type gt,
int level)
{
yang_stmt *yc;
yang_stmt *yd;
yang_stmt *ykey;
yang_stmt *yleaf;
int i;
cg_var *cvi;
char *keyname;
cvec *cvk = NULL; /* vector of index keys */
int retval = -1;
cprintf(cbuf, "%*s%s", level*3, "", ys->ys_argument);
if ((yd = yang_find((yang_node*)ys, Y_DESCRIPTION, NULL)) != NULL)
cprintf(cbuf, "(\"%s\")", yd->ys_argument);
/* Loop over all key variables */
if ((ykey = yang_find((yang_node*)ys, Y_KEY, NULL)) == NULL){
clicon_err(OE_XML, 0, "List statement \"%s\" has no key", ys->ys_argument);
goto done;
}
/* The value is a list of keys: <key>[ <key>]* */
if ((cvk = yang_arg2cvec(ykey, " ")) == NULL)
goto done;
cvi = NULL;
/* Iterate over individual keys */
while ((cvi = cvec_each(cvk, cvi)) != NULL) {
keyname = cv_string_get(cvi);
if ((yleaf = yang_find((yang_node*)ys, Y_LEAF, keyname)) == NULL){
clicon_err(OE_XML, 0, "List statement \"%s\" has no key leaf \"%s\"",
ys->ys_argument, keyname);
goto done;
}
/* Print key variable now, and skip it in loop below
Note, only print callback on last statement
*/
if (yang2cli_leaf(h, yleaf, cbuf, gt==GT_VARS?GT_NONE:gt, level+1,
cvec_next(cvk, cvi)?0:1) < 0)
goto done;
}
cprintf(cbuf, "{\n");
for (i=0; i<ys->ys_len; i++)
if ((yc = ys->ys_stmt[i]) != NULL){
/* cvk is a cvec of strings containing variable names
yc is a leaf that may match one of the values of cvk.
*/
cvi = NULL;
while ((cvi = cvec_each(cvk, cvi)) != NULL) {
keyname = cv_string_get(cvi);
if (strcmp(keyname, yc->ys_argument) == 0)
break;
}
if (cvi != NULL)
continue;
if (yang2cli_stmt(h, yc, cbuf, gt, level+1) < 0)
goto done;
}
cprintf(cbuf, "%*s}\n", level*3, "");
retval = 0;
done:
if (cvk)
cvec_free(cvk);
return retval;
}
/*! Generate cli code for yang choice statement
Example:
choice interface-type {
container ethernet { ... }
container fddi { ... }
}
@Note Removes 'meta-syntax' from cli syntax. They are not shown when xml is
translated to cli. and therefore input-syntax != output syntax. Which is bad
*/
static int
yang2cli_choice(clicon_handle h,
yang_stmt *ys,
cbuf *cbuf,
enum genmodel_type gt,
int level)
{
int retval = -1;
yang_stmt *yc;
int i;
for (i=0; i<ys->ys_len; i++)
if ((yc = ys->ys_stmt[i]) != NULL){
switch (yc->ys_keyword){
case Y_CASE:
if (yang2cli_stmt(h, yc, cbuf, gt, level+2) < 0)
goto done;
break;
case Y_CONTAINER:
case Y_LEAF:
case Y_LEAF_LIST:
case Y_LIST:
default:
if (yang2cli_stmt(h, yc, cbuf, gt, level+1) < 0)
goto done;
break;
}
}
retval = 0;
done:
return retval;
}
/*! Translate yang-stmt to CLIgen syntax.
*/
static int
yang2cli_stmt(clicon_handle h,
yang_stmt *ys,
cbuf *cbuf,
enum genmodel_type gt,
int level /* indentation level for pretty-print */
)
{
yang_stmt *yc;
int retval = -1;
int i;
if (yang_config(ys)){
switch (ys->ys_keyword){
case Y_GROUPING:
case Y_RPC:
case Y_AUGMENT:
return 0;
break;
case Y_CONTAINER:
if (yang2cli_container(h, ys, cbuf, gt, level) < 0)
goto done;
break;
case Y_LIST:
if (yang2cli_list(h, ys, cbuf, gt, level) < 0)
goto done;
break;
case Y_CHOICE:
if (yang2cli_choice(h, ys, cbuf, gt, level) < 0)
goto done;
break;
case Y_LEAF_LIST:
case Y_LEAF:
if (yang2cli_leaf(h, ys, cbuf, gt, level, 1) < 0)
goto done;
break;
default:
for (i=0; i<ys->ys_len; i++)
if ((yc = ys->ys_stmt[i]) != NULL)
if (yang2cli_stmt(h, yc, cbuf, gt, level+1) < 0)
goto done;
break;
}
}
retval = 0;
done:
return retval;
}
/*! Translate from a yang specification into a CLIgen syntax.
*
* Print a CLIgen syntax to cbuf string, then parse it.
* @param gt - how to generate CLI:
* VARS: generate keywords for regular vars only not index
* ALL: generate keywords for all variables including index
*/
int
yang2cli(clicon_handle h,
yang_spec *yspec,
parse_tree *ptnew,
enum genmodel_type gt)
{
cbuf *cbuf;
int i;
int retval = -1;
yang_stmt *ymod = NULL;
cvec *globals; /* global variables from syntax */
if ((cbuf = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "%s: cbuf_new", __FUNCTION__);
goto done;
}
/* Traverse YANG specification: loop through statements */
for (i=0; i<yspec->yp_len; i++)
if ((ymod = yspec->yp_stmt[i]) != NULL){
if (yang2cli_stmt(h, ymod, cbuf, gt, 0) < 0)
goto done;
}
clicon_debug(1, "%s: buf\n%s\n", __FUNCTION__, cbuf_get(cbuf));
/* Parse the buffer using cligen parser. XXX why this?*/
if ((globals = cvec_new(0)) == NULL)
goto done;
/* load cli syntax */
if (cligen_parse_str(cli_cligen(h), cbuf_get(cbuf),
"yang2cli", ptnew, globals) < 0)
goto done;
cvec_free(globals);
/* handle=NULL for global namespace, this means expand callbacks must be in
CLICON namespace, not in a cli frontend plugin. */
if (cligen_expand_str2fn(*ptnew, expand_str2fn, NULL) < 0)
goto done;
retval = 0;
done:
cbuf_free(cbuf);
return retval;
}

32
apps/cli/cli_generate.h Normal file
View file

@ -0,0 +1,32 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef _CLI_GENERATE_H_
#define _CLI_GENERATE_H_
/*
* Prototypes
*/
int yang2cli(clicon_handle h, yang_spec *yspec, parse_tree *ptnew,
enum genmodel_type gt);
#endif /* _CLI_GENERATE_H_ */

295
apps/cli/cli_handle.c Normal file
View file

@ -0,0 +1,295 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
*/
#ifdef HAVE_CONFIG_H
#include "clicon_config.h" /* generated by config & autoconf */
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <syslog.h>
#include <errno.h>
#include <assert.h>
#include <dlfcn.h>
#include <dirent.h>
#include <grp.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <netinet/in.h>
/* cligen */
#include <cligen/cligen.h>
/* clicon */
#include <clicon/clicon.h>
#include "clicon_cli_api.h"
#include "cli_plugin.h"
#include "cli_handle.h"
#define CLICON_MAGIC 0x99aafabe
#define handle(h) (assert(clicon_handle_check(h)==0),(struct cli_handle *)(h))
#define cligen(h) (handle(h)->cl_cligen)
/*
* cli_handle
* first part of this is header, same for clicon_handle and config_handle.
* Access functions for common fields are found in clicon lib: clicon_options.[ch]
* This file should only contain access functions for the _specific_
* entries in the struct below.
*/
struct cli_handle {
int cl_magic; /* magic (HDR)*/
clicon_hash_t *cl_copt; /* clicon option list (HDR) */
clicon_hash_t *cl_data; /* internal clicon data (HDR) */
/* ------ end of common handle ------ */
cligen_handle cl_cligen; /* cligen handle */
int cl_send2backend; /* Send changes to configuration daemon */
enum candidate_db_type cl_candidate_type;
cli_syntax_t *cl_stx; /* syntax structure */
};
/*
* cli_handle_init
* returns a clicon handle for other CLICON API calls
*/
clicon_handle
cli_handle_init(void)
{
struct cli_handle *cl;
cligen_handle clih = NULL;
clicon_handle h = NULL;
if ((cl = (struct cli_handle *)clicon_handle_init0(sizeof(struct cli_handle))) == NULL)
return NULL;
if ((clih = cligen_init()) == NULL){
clicon_handle_exit((clicon_handle)cl);
goto done;
}
cligen_userhandle_set(clih, cl);
cl->cl_cligen = clih;
cl->cl_candidate_type = CANDIDATE_DB_SHARED;
h = (clicon_handle)cl;
done:
return h;
}
/*
* cli_handle_exit
* frees clicon handle
*/
int
cli_handle_exit(clicon_handle h)
{
cligen_handle ch = cligen(h);
clicon_handle_exit(h); /* frees h and options */
cligen_exit(ch);
return 0;
}
/*----------------------------------------------------------
* cli-specific handle access functions
*----------------------------------------------------------*/
/*! Send changes to configuration daemon or let client handle it itself. Default is 1 */
int
cli_set_send2backend(clicon_handle h, int send2backend)
{
struct cli_handle *cl = handle(h);
cl->cl_send2backend = send2backend;
return 0;
}
/*! Get status of whether to send changes to configuration daemon. */
int
cli_send2backend(clicon_handle h)
{
struct cli_handle *cl = handle(h);
return cl->cl_send2backend;
}
enum candidate_db_type
cli_candidate_type(clicon_handle h)
{
struct cli_handle *cl = handle(h);
return cl->cl_candidate_type;
}
int
cli_set_candidate_type(clicon_handle h, enum candidate_db_type type)
{
struct cli_handle *cl = handle(h);
cl->cl_candidate_type = type;
return 0;
}
/* Current syntax-group */
cli_syntax_t *
cli_syntax(clicon_handle h)
{
struct cli_handle *cl = handle(h);
return cl->cl_stx;
}
int
cli_syntax_set(clicon_handle h, cli_syntax_t *stx)
{
struct cli_handle *cl = handle(h);
cl->cl_stx = stx;
return 0;
}
/*----------------------------------------------------------
* cligen access functions
*----------------------------------------------------------*/
cligen_handle
cli_cligen(clicon_handle h)
{
return cligen(h);
}
/*
* cli_interactive and clicon_eval
*/
int
cli_exiting(clicon_handle h)
{
cligen_handle ch = cligen(h);
return cligen_exiting(ch);
}
/*
* cli_common.c: cli_quit
* cli_interactive()
*/
int
cli_set_exiting(clicon_handle h, int exiting)
{
cligen_handle ch = cligen(h);
return cligen_exiting_set(ch, exiting);
}
char
cli_comment(clicon_handle h)
{
cligen_handle ch = cligen(h);
return cligen_comment(ch);
}
char
cli_set_comment(clicon_handle h, char c)
{
cligen_handle ch = cligen(h);
return cligen_comment_set(ch, c);
}
char
cli_tree_add(clicon_handle h, char *tree, parse_tree pt)
{
cligen_handle ch = cligen(h);
return cligen_tree_add(ch, tree, pt);
}
char *
cli_tree_active(clicon_handle h)
{
cligen_handle ch = cligen(h);
return cligen_tree_active(ch);
}
int
cli_tree_active_set(clicon_handle h, char *treename)
{
cligen_handle ch = cligen(h);
return cligen_tree_active_set(ch, treename);
}
parse_tree *
cli_tree(clicon_handle h, char *name)
{
cligen_handle ch = cligen(h);
return cligen_tree(ch, name);
}
int
cli_parse_file(clicon_handle h,
FILE *f,
char *name, /* just for errs */
parse_tree *pt,
cvec *globals)
{
cligen_handle ch = cligen(h);
return cligen_parse_file(ch, f, name, pt, globals);
}
int
cli_susp_hook(clicon_handle h, cli_susphook_t *fn)
{
cligen_handle ch = cligen(h);
/* This assume first arg of fn can be treated as void* */
return cligen_susp_hook(ch, (cligen_susp_cb_t*)fn);
}
char *
cli_nomatch(clicon_handle h)
{
cligen_handle ch = cligen(h);
return cligen_nomatch(ch);
}
int
cli_prompt_set(clicon_handle h, char *prompt)
{
cligen_handle ch = cligen(h);
return cligen_prompt_set(ch, prompt);
}
int
cli_logsyntax_set(clicon_handle h, int status)
{
cligen_handle ch = cligen(h);
return cligen_logsyntax_set(ch, status);
}

58
apps/cli/cli_handle.h Normal file
View file

@ -0,0 +1,58 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
*/
#ifndef _CLI_HANDLE_H_
#define _CLI_HANDLE_H_
/*
* Prototypes
* Internal prototypes. For exported functions see clicon_cli_api.h
*/
char cli_tree_add(clicon_handle h, char *tree, parse_tree pt);
int cli_parse_file(clicon_handle h,
FILE *f,
char *name, /* just for errs */
parse_tree *pt,
cvec *globals);
char *cli_tree_active(clicon_handle h);
int cli_tree_active_set(clicon_handle h, char *treename);
parse_tree *cli_tree(clicon_handle h, char *name);
int cli_susp_hook(clicon_handle h, cli_susphook_t *fn);
char *cli_nomatch(clicon_handle h);
int cli_prompt_set(clicon_handle h, char *prompt);
int cli_logsyntax_set(clicon_handle h, int status);
/* Internal functions for handling cli groups */
cli_syntax_t *cli_syntax(clicon_handle h);
int cli_syntax_set(clicon_handle h, cli_syntax_t *stx);
#endif /* _CLI_HANDLE_H_ */

407
apps/cli/cli_main.c Normal file
View file

@ -0,0 +1,407 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
*/
#ifdef HAVE_CONFIG_H
#include "clicon_config.h" /* generated by config & autoconf */
#endif
#include <stdio.h>
#define __USE_GNU /* strverscmp */
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <dlfcn.h>
#include <dirent.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <assert.h>
/* cligen */
#include <cligen/cligen.h>
/* clicon */
#include <clicon/clicon.h>
#include "clicon_cli_api.h"
#include "cli_plugin.h"
#include "cli_generate.h"
#include "cli_common.h"
#include "cli_handle.h"
/* Command line options to be passed to getopt(3) */
#define CLI_OPTS "hD:f:F:1u:d:m:cP:qpGLl:"
static int
cli_terminate(clicon_handle h)
{
yang_spec *yspec;
if ((yspec = clicon_dbspec_yang(h)) != NULL)
yspec_free(yspec);
cli_plugin_finish(h);
exit_candidate_db(h);
cli_handle_exit(h);
return 0;
}
/*
* cli_sig_term
* Unlink pidfile and quit
*/
static void
cli_sig_term(int arg)
{
clicon_log(LOG_NOTICE, "%s: %u Terminated (killed by sig %d)",
__PROGRAM__, getpid(), arg);
exit(1);
}
/*
* Setup signal handlers
*/
static void
cli_signal_init (clicon_handle h)
{
cli_signal_block(h);
set_signal(SIGTERM, cli_sig_term, NULL);
}
static void
cli_interactive(clicon_handle h)
{
int res;
char *cmd;
char *new_mode;
int result;
/* Loop through all commands */
while(!cli_exiting(h)) {
// save_mode =
new_mode = cli_syntax_mode(h);
if ((cmd = clicon_cliread(h)) == NULL) {
cli_set_exiting(h, 1); /* EOF */
break;
}
if ((res = clicon_parse(h, cmd, &new_mode, &result)) < 0)
break;
}
}
static void
usage(char *argv0, clicon_handle h)
{
char *confsock = clicon_sock(h);
char *plgdir = clicon_cli_dir(h);
fprintf(stderr, "usage:%s [options] [commands]\n"
"where commands is a CLI command or options passed to the main plugin\n"
"where options are\n"
"\t-h \t\tHelp\n"
"\t-D <level> \tDebug\n"
"\t-f <file> \tConfig-file (mandatory)\n"
"\t-F <file> \tRead commands from file (default stdin)\n"
"\t-1\t\tDo not enter interactive mode\n"
"\t-u <sockpath>\tconfig UNIX domain path (default: %s)\n"
"\t-d <dir>\tSpecify plugin directory (default: %s)\n"
"\t-m <mode>\tSpecify plugin syntax mode\n"
"\t-c \t\tWrite to candidate db directly, not via config backend\n"
"\t-P <dbname> \tWrite to private database\n"
"\t-q \t\tQuiet mode, dont print greetings or prompt, terminate on ctrl-C\n"
"\t-p \t\tPrint database yang specification\n"
"\t-G \t\tPrint CLI syntax generated from dbspec (if CLICON_CLI_GENMODEL enabled)\n"
"\t-L \t\tDebug print dynamic CLI syntax including completions and expansions\n"
"\t-l <s|e|o> \tLog on (s)yslog, std(e)rr or std(o)ut (stderr is default)\n",
argv0,
confsock ? confsock : "none",
plgdir ? plgdir : "none"
);
exit(1);
}
/*
*/
int
main(int argc, char **argv)
{
char c;
enum candidate_db_type dbtype;
char private_db[MAXPATHLEN];
int once;
char *tmp;
char *argv0 = argv[0];
clicon_handle h;
int printspec = 0;
int printgen = 0;
int logclisyntax = 0;
int help = 0;
char *treename;
char *running_db;
int logdst = CLICON_LOG_STDERR;
/* Defaults */
/* In the startup, logs to stderr & debug flag set later */
clicon_log_init(__PROGRAM__, LOG_INFO, logdst);
/* Initiate CLICON handle */
if ((h = cli_handle_init()) == NULL)
goto done;
if (cli_plugin_init(h) != 0)
goto done;
dbtype = CANDIDATE_DB_SHARED;
once = 0;
private_db[0] = '\0';
cli_set_send2backend(h, 1); /* send changes to config daemon */
cli_set_comment(h, '#'); /* Default to handle #! clicon_cli scripts */
/*
* First-step command-line options for help, debug, config-file and log,
*/
optind = 1;
opterr = 0;
while ((c = getopt(argc, argv, CLI_OPTS)) != -1)
switch (c) {
case '?':
case 'h':
/* Defer the call to usage() to later. Reason is that for helpful
text messages, default dirs, etc, are not set until later.
But this means that we need to check if 'help' is set before
exiting, and then call usage() before exit.
*/
help = 1;
break;
case 'D' : /* debug */
if (sscanf(optarg, "%d", &debug) != 1)
usage(argv[0], h);
break;
case 'f': /* config file */
if (!strlen(optarg))
usage(argv[0], h);
clicon_option_str_set(h, "CLICON_CONFIGFILE", optarg);
break;
case 'l': /* Log destination: s|e|o */
switch (optarg[0]){
case 's':
logdst = CLICON_LOG_SYSLOG;
break;
case 'e':
logdst = CLICON_LOG_STDERR;
break;
case 'o':
logdst = CLICON_LOG_STDOUT;
break;
default:
usage(argv[0], h);
}
break;
}
/*
* Logs, error and debug to stderr or syslog, set debug level
*/
clicon_log_init(__PROGRAM__, debug?LOG_DEBUG:LOG_INFO, logdst);
clicon_debug_init(debug, NULL);
/* Find and read configfile */
if (clicon_options_main(h) < 0){
if (help)
usage(argv[0], h);
return -1;
}
/* Now rest of options */
opterr = 0;
optind = 1;
while ((c = getopt(argc, argv, CLI_OPTS)) != -1){
switch (c) {
case 'D' : /* debug */
case 'f': /* config file */
case 'l': /* Log destination */
break; /* see above */
case 'F': /* read commands from file */
if (freopen(optarg, "r", stdin) == NULL){
cli_output(stderr, "freopen: %s\n", strerror(errno));
return -1;
}
break;
case '1' : /* Quit after reading database once - dont wait for events */
once = 1;
break;
case 'u': /* config unix domain path/ ip host */
if (!strlen(optarg))
usage(argv[0], h);
clicon_option_str_set(h, "CLICON_SOCK", optarg);
break;
case 'd': /* Plugin directory: overrides configfile */
if (!strlen(optarg))
usage(argv[0], h);
clicon_option_str_set(h, "CLICON_CLI_DIR", optarg);
break;
case 'm': /* CLI syntax mode */
if (!strlen(optarg))
usage(argv[0], h);
clicon_option_str_set(h, "CLICON_CLI_MODE", optarg);
break;
case 'c' : /* No config daemon (used in bootstrapping and file load) */
cli_set_send2backend(h, 0);
break;
case 'P' : /* load to private database with given name */
dbtype = CANDIDATE_DB_PRIVATE;
clicon_option_str_set(h, "CLICON_CANDIDATE_DB", optarg); /* override default */
break;
case 'q' : /* Quiet mode */
clicon_option_str_set(h, "CLICON_QUIET", "on");
break;
case 'p' : /* Print spec */
printspec++;
break;
case 'G' : /* Print generated CLI syntax */
printgen++;
break;
case 'L' : /* Debug print dynamic CLI syntax */
logclisyntax++;
break;
default:
usage(argv[0], h);
break;
}
}
argc -= optind;
argv += optind;
/* Defer: Wait to the last minute to print help message */
if (help)
usage(argv[0], h);
/* Setup signal handlers */
cli_signal_init(h);
/* Backward compatible mode, do not include keys in cgv-arrays in callbacks.
Should be 0 but default is 1 since all legacy apps use 1
Test legacy before shifting default to 0
*/
cv_exclude_keys(clicon_cli_varonly(h));
/* Parse db specification as cli*/
if (yang_spec_main(h, stdout, printspec) < 0)
goto done;
/* Check plugin directory */
if (clicon_cli_dir(h) == NULL){
clicon_err(OE_PLUGIN, 0, "clicon_cli_dir not defined");
goto done;
}
/* Create tree generated from dataspec */
if (clicon_cli_genmodel(h)){
yang_spec *yspec; /* yang spec */
parse_tree pt = {0,}; /* cli parse tree */
if ((yspec = clicon_dbspec_yang(h)) == NULL){
clicon_err(OE_FATAL, 0, "No YANG DB_SPEC");
goto done;
}
/* Create cli command tree from dbspec */
if (yang2cli(h, yspec, &pt, clicon_cli_genmodel_type(h)) < 0)
goto done;
treename = chunk_sprintf(__FUNCTION__, "datamodel:%s", clicon_dbspec_name(h));
cli_tree_add(h, treename, pt);
if (printgen)
cligen_print(stdout, pt, 1);
}
/* Initialize cli syntax */
if (cli_syntax_load(h) < 0)
goto done;
/* Set syntax mode if specified from command-line or config-file. */
if (clicon_option_exists(h, "CLICON_CLI_MODE"))
if ((tmp = clicon_cli_mode(h)) != NULL)
if (cli_set_syntax_mode(h, tmp) == 0) {
fprintf(stderr, "FATAL: Failed to set syntax mode '%s'\n", tmp);
goto done;
}
if (!cli_syntax_mode(h)){
fprintf (stderr, "FATAL: No cli mode set (use -m or CLICON_CLI_MODE)\n");
goto done;
}
if (cli_tree(h, cli_syntax_mode(h)) == NULL){
fprintf (stderr, "FATAL: No such cli mode: %s\n", cli_syntax_mode(h));
goto done;
}
/* Initialize databases */
if ((running_db = clicon_running_db(h)) == NULL)
goto done;
if (strlen(private_db))
clicon_option_str_set(h, "CLICON_CANDIDATE_DB", private_db);
if (!cli_send2backend(h))
if (db_init(running_db) < 0){
fprintf (stderr, "FATAL: Could not init running_db. (Run as root?)\n");
goto done;
}
/* A client does not have access to the candidate (and running)
databases if both these conditions are true:
1. clicon_sock_family(h) == AF_INET[6]
2. cli_send2backend(h) == 1
*/
if (clicon_sock_family(h) == AF_UNIX || cli_send2backend(h)==0)
if (init_candidate_db(h, dbtype) < 0)
return -1;
if (logclisyntax)
cli_logsyntax_set(h, logclisyntax);
if (debug)
clicon_option_dump(h, debug);
/* Call start function in all plugins before we go interactive
Pass all args after the standard options to plugin_start
*/
tmp = *(argv-1);
*(argv-1) = argv0;
cli_plugin_start(h, argc+1, argv-1);
*(argv-1) = tmp;
/* Launch interfactive event loop, unless -1 */
if (once == 0)
cli_interactive(h);
done:
// Gets in your face if we log on stderr
clicon_log_init(__PROGRAM__, LOG_INFO, 0); /* Log on syslog no stderr */
clicon_log(LOG_NOTICE, "%s: %u Terminated\n", __PROGRAM__, getpid());
cli_terminate(h);
return 0;
}

1153
apps/cli/cli_plugin.c Normal file

File diff suppressed because it is too large Load diff

90
apps/cli/cli_plugin.h Normal file
View file

@ -0,0 +1,90 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef _CLI_PLUGIN_H_
#define _CLI_PLUGIN_H_
#include <stdio.h>
#include <inttypes.h>
#include <netinet/in.h>
/* clicon generic callback pointer */
typedef void (clicon_callback_t)(clicon_handle h);
/* clicon_set value callback */
typedef int (cli_valcb_t)(cvec *vars, cg_var *cgv, cg_var *arg);
/* specific to cli. For common see clicon_plugin.h */
/* Hook to get prompt format before each getline */
typedef char *(cli_prompthook_t)(clicon_handle, char *mode);
/* Ctrl-Z hook from getline() */
typedef int (cli_susphook_t)(clicon_handle, char *, int, int *);
/* CLIgen parse failure hook. Retry other mode? */
typedef char *(cli_parsehook_t)(clicon_handle, char *, char *);
typedef struct {
qelem_t csm_qelem; /* List header */
char csm_name[256]; /* Syntax mode name */
char csm_prompt[CLI_PROMPT_LEN]; /* Prompt for mode */
int csm_nsyntax; /* Num syntax specs registered by plugin */
parse_tree csm_pt; /* CLIgen parse tree */
} cli_syntaxmode_t;
/* A plugin list object */
struct cli_plugin {
qelem_t cp_qelem; /* List header */
char cp_name[256]; /* Plugin name */
void *cp_handle; /* Dynamic object handle */
};
/* Plugin group object */
typedef struct {
char stx_cnklbl[128]; /* Plugin group name */
int stx_nplugins; /* Number of plugins */
struct cli_plugin *stx_plugins; /* List of plugins */
int stx_nmodes; /* Number of syntax modes */
cli_syntaxmode_t *stx_active_mode; /* Current active syntax mode */
cli_syntaxmode_t *stx_modes; /* List of syntax modes */
cli_prompthook_t *stx_prompt_hook; /* Prompt hook */
cli_parsehook_t *stx_parse_hook; /* Parse mode hook */
cli_susphook_t *stx_susp_hook; /* Ctrl-Z hook from getline() */
} cli_syntax_t;
expand_cb *expand_str2fn(char *name, void *handle, char **error);
int cli_plugin_start(clicon_handle, int argc, char **argv);
int cli_plugin_init(clicon_handle h);
int clicon_eval(clicon_handle h, char *cmd, cg_obj *match_obj, cvec *vr);
int clicon_parse(clicon_handle h, char *cmd, char **mode, int *result);
char *clicon_cliread(clicon_handle h);
int cli_plugin_finish(clicon_handle h);
#endif /* _CLI_PLUGIN_H_ */

59
apps/cli/clicon_cli.h Normal file
View file

@ -0,0 +1,59 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef _CLICON_CLI_H_
#define _CLICON_CLI_H_
#include <sys/types.h>
#/* Common code (API and clicon_cli) */
include <clicon/clicon_cli_api.h>
/*! Clicon Cli plugin callbacks: use these in your cli plugin code
*/
/*! Called when plugin loaded. Only mandadory callback. All others optional
* @see plginit_t
*/
int plugin_init(clicon_handle h);
/* Called when backend started with cmd-line arguments from daemon call.
* @see plgstart_t
*/
int plugin_start(clicon_handle h, int argc, char **argv);
/* Called just before plugin unloaded.
* @see plgexit_t
*/
int plugin_exit(clicon_handle h);
/* Called before prompt is printed, return a customized prompt. */
char *plugin_prompt_hook(clicon_handle h, char *mode);
/* Called if a command is not matched w current mode. Return name of next syntax mode to check until NULL */
char *plugin_parse_hook(clicon_handle h, char *cmd, char *name);
/* Called if ^Z entered. Can modify cli command buffer and position */
int plugin_susp_hook(clicon_handle h, char *buf, int prompt_width, int *cursor_loc);
#endif /* _CLICON_CLI_H_ */

113
apps/cli/clicon_cli_api.h Normal file
View file

@ -0,0 +1,113 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
* Note, this is a CLICON API file, only exprorted function prototypes should appear here
*/
#ifndef _CLICON_CLI_API_H_
#define _CLICON_CLI_API_H_
/*
* Constants
*/
/* Max prompt length */
#define CLI_PROMPT_LEN 64
#define CLI_DEFAULT_PROMPT ">"
/*
* Types
*/
//typedef void *cli_handle; /* clicon cli handle, see struct cli_handle */
enum candidate_db_type{
CANDIDATE_DB_NONE, /* No candidate */
CANDIDATE_DB_PRIVATE, /* Create a private candidate_db */
CANDIDATE_DB_SHARED, /* Share the candidate with everyone else */
CANDIDATE_DB_CURRENT /* Dont create candidate, use current directly */
};
/*
* Function Declarations
*/
/* cli_plugin.c */
int cli_set_syntax_mode(clicon_handle h, const char *mode);
char *cli_syntax_mode(clicon_handle h);
int cli_syntax_load(clicon_handle h);
int cli_handler_err(FILE *fd);
int cli_set_prompt(clicon_handle h, const char *mode, const char *prompt);
char *cli_prompt(char *fmt);
int cli_exec(clicon_handle h, char *cmd, char **mode, int *result);
int cli_ptpush(clicon_handle h, char *mode, char *string, char *op);
int cli_ptpop(clicon_handle h, char *mode, char *op);
/* cli_handle.c */
char cli_set_comment(clicon_handle h, char c);
char cli_comment(clicon_handle h);
int cli_set_exiting(clicon_handle h, int exiting);
int cli_exiting(clicon_handle h);
int cli_set_send2backend(clicon_handle h, int send2backend);
int cli_send2backend(clicon_handle h);
clicon_handle cli_handle_init(void);
int cli_handle_exit(clicon_handle h);
cligen_handle cli_cligen(clicon_handle h);
enum candidate_db_type cli_candidate_type(clicon_handle h);
int cli_set_candidate_type(clicon_handle h, enum candidate_db_type type);
/* cli_common.c */
int init_candidate_db(clicon_handle h, enum candidate_db_type type);
int exit_candidate_db(clicon_handle h);
#define cli_output cligen_output
int cli_set (clicon_handle h, cvec *vars, cg_var *arg);
int cli_merge (clicon_handle h, cvec *vars, cg_var *arg);
int cli_del(clicon_handle h, cvec *vars, cg_var *argv);
int cli_debug(clicon_handle h, cvec *vars, cg_var *argv);
int cli_record(clicon_handle h, cvec *vars, cg_var *argv);
int isrecording(void);
int record_command(char *str);
int cli_set_mode(clicon_handle h, cvec *vars, cg_var *argv);
int cli_start_shell(clicon_handle h, cvec *vars, cg_var *argv);
int cli_quit(clicon_handle h, cvec *vars, cg_var *arg);
int cli_commit(clicon_handle h, cvec *vars, cg_var *arg);
int cli_validate(clicon_handle h, cvec *vars, cg_var *arg);
int expand_dbvar(void *h, char *name, cvec *vars, cg_var *arg,
int *nr, char ***commands, char ***helptexts);
int expand_dbvar_auto(void *h, char *name, cvec *vars, cg_var *arg,
int *nr, char ***commands, char ***helptexts);
int expand_db_variable(clicon_handle h, char *dbname, char *basekey, char *variable, int *nr, char ***commands);
int expand_db_symbol(clicon_handle h, char *symbol, int element, int *nr, char ***commands);
int expand_dir(char *dir, int *nr, char ***commands, mode_t flags, int detail);
int compare_dbs(clicon_handle h, cvec *vars, cg_var *arg);
int load_config_file(clicon_handle h, cvec *vars, cg_var *arg);
int save_config_file(clicon_handle h, cvec *vars, cg_var *arg);
int delete_all(clicon_handle h, cvec *vars, cg_var *arg);
int discard_changes(clicon_handle h, cvec *vars, cg_var *arg);
int show_conf_as_xml(clicon_handle h, cvec *vars, cg_var *arg);
int show_conf_as_netconf(clicon_handle h, cvec *vars, cg_var *arg);
int show_conf_as_json(clicon_handle h, cvec *vars, cg_var *arg);
int show_conf_as_text(clicon_handle h, cvec *vars, cg_var *arg);
int show_conf_as_cli(clicon_handle h, cvec *vars, cg_var *arg);
int show_conf_as_csv(clicon_handle h, cvec *vars, cg_var *arg);
int show_yang(clicon_handle h, cvec *vars, cg_var *arg);
int cli_notification_register(clicon_handle h, char *stream, enum format_enum format,
char *filter, int status,
int (*fn)(int, void*), void *arg);
#endif /* _CLICON_CLI_API_H_ */

99
apps/dbctrl/Makefile.in Normal file
View file

@ -0,0 +1,99 @@
#
# Makefile
#
#
# Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
#
# This file is part of CLICON.
#
# CLICON is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# CLICON is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with CLICON; see the file COPYING. If not, see
# <http://www.gnu.org/licenses/>.
#
VPATH = @srcdir@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
CC = @CC@
CFLAGS = @CFLAGS@
LDFLAGS = @LDFLAGS@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
libexecdir = @libexecdir@
localstatedir = @localstatedir@
sysconfdir = @sysconfdir@
SH_SUFFIX = @SH_SUFFIX@
CLICON_MAJOR = @CLICON_VERSION_MAJOR@
CLICON_MINOR = @CLICON_VERSION_MINOR@
# Use this clicon lib for linking
CLICON_LIB = libclicon.so.$(CLICON_MAJOR).$(CLICON_MINOR)
# For dependency
LIBDEPS = $(top_srcdir)/lib/src/$(CLICON_LIB)
LIBS = -L$(top_srcdir)/lib/src @LIBS@ -l:$(CLICON_LIB)
CPPFLAGS = @CPPFLAGS@
INCLUDES = -I. -I$(top_srcdir)/lib/src -I$(top_srcdir)/lib -I$(top_srcdir)/include -I$(top_srcdir) @INCLUDES@
SRC =
OBJS = $(SRC:.c=.o)
APPSRC = dbctrl_main.c
APPOBJ = $(APPSRC:.c=.o)
APPL = clicon_dbctrl
all: $(APPL)
clean:
rm -f $(OBJS) *.core $(APPL) $(APPOBJ)
distclean: clean
rm -f Makefile *~ .depend
# Put demon in bin
# Put other executables in libexec/
# Also create a libexec/ directory for writeable/temporary files.
# Put config file in etc/
install: $(APPL)
install -d $(DESTDIR)$(bindir)
install $(APPL) $(DESTDIR)$(bindir)
install-include:
uninstall:
rm -f $(bindir)/$(APPL)
.SUFFIXES:
.SUFFIXES: .c .o
.c.o:
$(CC) $(INCLUDES) -D__PROGRAM__=\"$(APPL)\" $(CPPFLAGS) $(CFLAGS) -c $<
$(APPL) : $(APPOBJ) $(OBJS) $(LIBDEPS)
$(CC) $(LDFLAGS) $(APPOBJ) $(OBJS) $(LIBS) -o $@
TAGS:
find . -name '*.[chyl]' -print | etags -
depend:
$(CC) $(DEPENDFLAGS) @DEFS@ $(INCLUDES) $(CFLAGS) -MM $(SRC) $(APPSRC) > .depend
#include .depend

241
apps/dbctrl/dbctrl_main.c Normal file
View file

@ -0,0 +1,241 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "clicon_config.h" /* generated by config & autoconf */
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <time.h>
#include <syslog.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/in.h>
/* cligen */
#include <cligen/cligen.h>
/* clicon */
#include <clicon/clicon.h>
/* Command line options to be passed to getopt(3) */
#define DBCTRL_OPTS "hDd:pbn:r:m:Zi"
/*! Write database contents to file, xml database variant
* @param[in] dbspec If set make a sanity check if key dont match (just)
*/
static int
dump_database(FILE *f,
char *dbname,
char *rxkey)
{
int retval = 0;
int npairs;
struct db_pair *pairs;
/* Default is match all */
if (rxkey == NULL)
rxkey = "^.*$";
/* Get all keys/values for vector */
if ((npairs = db_regexp(dbname, rxkey, __FUNCTION__, &pairs, 0)) < 0)
return -1;
for (npairs--; npairs >= 0; npairs--)
fprintf(f, "%s %s\n", pairs[npairs].dp_key,
pairs[npairs].dp_val?pairs[npairs].dp_val:"");
unchunk_group(__FUNCTION__);
return retval;
}
/*
* remove_entry
*/
static int
remove_entry(char *dbname, char *key)
{
return db_del(dbname, key);
}
/*
* usage
*/
static void
usage(char *argv0)
{
fprintf(stderr, "usage:%s\n"
"where options are\n"
"\t-h\t\tHelp\n"
"\t-D\t\tDebug\n"
"\t-d <dbname>\tDatabase name (default: running_db)\n"
"\t-p\t\tDump database on stdout\n"
"\t-b\t\tBrief output, just print keys. Combine with -p or -m\n"
"\t-n \"<key> <val>\" Add database entry\n"
"\t-r <key>\tRemove database entry\n"
"\t-m <regexp key>\tMatch regexp key in database\n"
"\t-Z\t\tDelete database\n"
"\t-i\t\tInit database\n",
argv0
);
exit(0);
}
int
main(int argc, char **argv)
{
char c;
int zapdb;
int initdb;
int dumpdb;
int addent;
int rment;
char *matchkey = NULL;
char *addstr;
char rmkey[MAXPATHLEN];
int brief;
char dbname[MAXPATHLEN] = {0,};
int use_syslog;
yang_spec *yspec;
clicon_handle h;
/* In the startup, logs to stderr & debug flag set later */
clicon_log_init(__PROGRAM__, LOG_INFO, CLICON_LOG_STDERR);
/* Defaults */
zapdb = 0;
initdb = 0;
dumpdb = 0;
addent = 0;
rment = 0;
brief = 0;
use_syslog = 0;
addstr = NULL;
memset(rmkey, '\0', sizeof(rmkey));
if ((h = clicon_handle_init()) == NULL)
goto done;
/* getopt in two steps, first find config-file before over-riding options. */
while ((c = getopt(argc, argv, DBCTRL_OPTS)) != -1)
switch (c) {
case '?' :
case 'h' : /* help */
usage(argv[0]);
break;
case 'D' : /* debug */
debug = 1;
break;
case 'S': /* Log on syslog */
use_syslog = 1;
break;
}
/*
* Logs, error and debug to stderr or syslog, set debug level
*/
clicon_log_init(__PROGRAM__, debug?LOG_DEBUG:LOG_INFO,
use_syslog?CLICON_LOG_SYSLOG:CLICON_LOG_STDERR);
clicon_debug_init(debug, NULL);
/* Now rest of options */
optind = 1;
while ((c = getopt(argc, argv, DBCTRL_OPTS)) != -1)
switch (c) {
case 'Z': /* Zap database */
zapdb++;
break;
case 'i': /* Init database */
initdb++;
break;
case 'p': /* Dump/print database */
dumpdb++;
break;
case 'b': /* Dump/print/match database brief (combone w -p or -m) */
brief++;
break;
case 'd': /* dbname */
if (!optarg || sscanf(optarg, "%s", dbname) != 1)
usage(argv[0]);
break;
case 'n': /* add database entry */
if (!optarg || !strlen(optarg) || (addstr = strdup(optarg)) == NULL)
usage(argv[0]);
/* XXX addign both key and value, for now only key */
addent++;
break;
case 'r':
if (!optarg || sscanf(optarg, "%s", rmkey) != 1)
usage(argv[0]);
rment++;
break;
case 'm':
if (!optarg || !strlen(optarg) || (matchkey = strdup(optarg)) == NULL)
usage(argv[0]);
dumpdb++;
break;
case 'D': /* Processed earlier, ignore now. */
case 'S':
break;
default:
usage(argv[0]);
break;
}
argc -= optind;
argv += optind;
if (*dbname == '\0'){
clicon_err(OE_FATAL, 0, "database not specified (with -d <db>): %s");
goto done;
}
yspec = clicon_dbspec_yang(h);
if (dumpdb){
if (dump_database(stdout, dbname, matchkey)) {
fprintf(stderr, "Match error\n");
goto done;
}
}
if (addent) /* add entry */
if (xmldb_put_xkey(dbname, addstr, NULL, yspec, OP_REPLACE) < 0)
goto done;
if (rment)
if (remove_entry(dbname, rmkey) < 0)
goto done;
if (zapdb) /* remove databases */
unlink(dbname);
if (initdb)
if (db_init(dbname) < 0)
goto done;
done:
return 0;
}

122
apps/netconf/Makefile.in Normal file
View file

@ -0,0 +1,122 @@
#
# Makefile
#
# Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
#
# This file is part of CLICON.
#
# CLICON is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# CLICON is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with CLICON; see the file COPYING. If not, see
# <http://www.gnu.org/licenses/>.
#
#
VPATH = @srcdir@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
CC = @CC@
CFLAGS = @CFLAGS@
LDFLAGS = @LDFLAGS@
prefix = @prefix@
datarootdir = @datarootdir@
exec_prefix = @exec_prefix@
bindir = @bindir@
libdir = @libdir@
mandir = @mandir@
libexecdir = @libexecdir@
localstatedir = @localstatedir@
sysconfdir = @sysconfdir@
includedir = @includedir@
SH_SUFFIX = @SH_SUFFIX@
CLICON_MAJOR = @CLICON_VERSION_MAJOR@
CLICON_MINOR = @CLICON_VERSION_MINOR@
# Use this clicon lib for linking
CLICON_LIB = libclicon.so.$(CLICON_MAJOR).$(CLICON_MINOR)
# For dependency
LIBDEPS = $(top_srcdir)/lib/src/$(CLICON_LIB)
LIBS = -L$(top_srcdir)/lib/src @LIBS@ -l:$(CLICON_LIB)
CPPFLAGS = @CPPFLAGS@ -fPIC
INCLUDES = -I. -I$(top_srcdir)/lib/src -I$(top_srcdir)/lib -I$(top_srcdir)/include -I$(top_srcdir) @INCLUDES@
APPL = clicon_netconf
SRC = netconf_main.c
OBJS = $(SRC:.c=.o)
MYNAME = clicon_netconf
MYLIBLINK = lib$(MYNAME)$(SH_SUFFIX)
MYLIB = $(MYLIBLINK).$(CLICON_MAJOR).$(CLICON_MINOR)
MYLIBSO = $(MYLIBLINK).$(CLICON_MAJOR)
LIBSRC = netconf_hello.c netconf_rpc.c netconf_filter.c netconf_lib.c netconf_plugin.c
LIBOBJS = $(LIBSRC:.c=.o)
all: $(MYLIB) $(APPL)
clean:
rm -f $(OBJS) $(LIBOBJS) *.core $(APPL) $(MYLIB) $(MYLIBSO) $(MYLIBLINK)
distclean: clean
rm -f Makefile *~ .depend
# Put demon in bin
# Put other executables in libexec/
# Also create a libexec/ directory for writeable/temporary files.
# Put config file in etc/
install: install-lib $(APPL)
install -d $(DESTDIR)$(bindir)
install $(APPL) $(DESTDIR)$(bindir)
install-lib: $(MYLIB)
install -d $(DESTDIR)$(libdir)
install $(MYLIB) $(DESTDIR)$(libdir)
ln -sf $(MYLIB) $(DESTDIR)$(libdir)/$(MYLIBSO) # -l:libclicon_netconf.so.2
ln -sf $(MYLIBSO) $(DESTDIR)$(libdir)/$(MYLIBLINK) # -l:libclicon_netconf.so
install-include: clicon_netconf.h
install -d $(DESTDIR)$(includedir)/clicon
install -m 644 $^ $(DESTDIR)$(includedir)/clicon
uninstall:
rm -f $(bindir)/$(APPL)
rm -f $(libdir)/$(MYLIB)
rm -f $(includedir)/clicon/*
.SUFFIXES:
.SUFFIXES: .c .o
.c.o:
$(CC) $(INCLUDES) $(CPPFLAGS) -D__PROGRAM__=\"$(APPL)\" $(CFLAGS) -c $<
$(APPL) : $(OBJS) $(MYLIBLINK) $(LIBDEPS)
$(CC) $(LDFLAGS) $(OBJS) -L. -l:$(MYLIB) $(LIBS) -o $@
$(MYLIB) : $(LIBOBJS)
$(CC) -shared -Wl,-soname,$(MYLIBSO) -o $@ $(LIBOBJS) $(LIBS) -Wl,-soname=$(MYLIBSO)
# link-name is needed for application linking, eg for clicon_cli and clicon_config
$(MYLIBLINK) : $(MYLIB)
# ln -sf $(MYLIB) $(MYLIBSO)
# ln -sf $(MYLIB) $@
TAGS:
find . -name '*.[chyl]' -print | etags -
depend:
$(CC) $(DEPENDFLAGS) @DEFS@ $(INCLUDES) $(CFLAGS) -MM $(SRC) $(APPSRC) > .depend
#include .depend

View file

@ -0,0 +1,73 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
* The exported interface to plugins. External apps (eg frontend netconf plugins)
* should only include this file (not the netconf_*.h)
*/
#ifndef _CLICON_NETCONF_H_
#define _CLICON_NETCONF_H_
/*
* Types
*/
typedef int (*netconf_cb_t)(
clicon_handle h,
cxobj *xorig, /* Original request. */
cxobj *xn, /* Sub-tree (under xorig) at child: <rpc><xn></rpc> */
cbuf *cb, /* Output xml stream. For reply */
cbuf *cb_err, /* Error xml stream. For error reply */
void *arg /* Argument given at netconf_register_callback() */
);
/*
* Prototypes
* (Duplicated. Also in netconf_*.h)
*/
int netconf_output(int s, cbuf *xf, char *msg);
int netconf_create_rpc_reply(cbuf *cb, /* msg buffer */
cxobj *xr, /* orig request */
char *body,
int ok);
int netconf_register_callback(clicon_handle h,
netconf_cb_t cb, /* Callback called */
void *arg, /* Arg to send to callback */
char *tag); /* Xml tag when callback is made */
int netconf_create_rpc_error(cbuf *xf, /* msg buffer */
cxobj *xr, /* orig request */
char *tag,
char *type,
char *severity,
char *message,
char *info);
void netconf_ok_set(int ok);
int netconf_ok_get(void);
int netconf_xpath(cxobj *xsearch,
cxobj *xfilter,
cbuf *xf, cbuf *xf_err,
cxobj *xt);
#endif /* _CLICON_NETCONF_H_ */

View file

@ -0,0 +1,633 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
* netconf match & selection: get and edit operations
*****************************************************************************/
#ifdef HAVE_CONFIG_H
#include "clicon_config.h" /* generated by config & autoconf */
#endif
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/param.h>
#include <assert.h>
/* cligen */
#include <cligen/cligen.h>
/* clicon */
#include <clicon/clicon.h>
#include "netconf_rpc.h"
#include "netconf_lib.h"
#include "netconf_filter.h"
/*
* xml_filter
* xf specifices a filter, and xn is an xml tree.
* Select the part of xn that matches xf and return it.
* Change xn destructively by removing the parts of the sub-tree that does
* not match.
* Match according to Section 6 of RFC 4741.
NO_FILTER, select all
EMPTY_FILTER, select nothing
ATTRIBUTE_MATCH, select if attribute match
SELECTION, select this node
CONTENT_MATCH, select all siblings with matching content
CONTAINMENT select
*/
/* return a string containing leafs value, NULL if no leaf or no value */
static char*
leafstring(cxobj *x)
{
cxobj *c;
if (xml_type(x) != CX_ELMNT)
return NULL;
if (xml_child_nr(x) != 1)
return NULL;
c = xml_child_i(x, 0);
if (xml_child_nr(c) != 0)
return NULL;
if (xml_type(c) != CX_BODY)
return NULL;
return xml_value(c);
}
/*! Internal recursive part where configuration xml tree is pruned frim filter
* assume parent has been selected and filter match (same name) as parent
* parent is pruned according to selection.
* @param[in] xfilter Filter xml
* @param[out] xconf Configuration xml
* @retval 0 OK
* @retval -1 Error
*/
static int
xml_filter2(cxobj *xfilter,
cxobj *xparent,
int *remove_me)
{
cxobj *s;
cxobj *sprev;
cxobj *f;
cxobj *attr;
char *an;
char *af;
char *fstr;
char *sstr;
int containments;
int remove_s;
*remove_me = 0;
assert(xfilter && xparent && strcmp(xml_name(xfilter), xml_name(xparent))==0);
/* 1. Check selection */
if (xml_child_nr(xfilter) == 0)
goto match;
/* Count containment/selection nodes in filter */
f = NULL;
containments = 0;
while ((f = xml_child_each(xfilter, f, CX_ELMNT)) != NULL) {
if (leafstring(f))
continue;
containments++;
}
/* 2. Check attribute match */
attr = NULL;
while ((attr = xml_child_each(xfilter, attr, CX_ATTR)) != NULL) {
af = xml_value(attr);
an = xml_find_value(xfilter, xml_name(attr));
if (af && an && strcmp(af, an)==0)
; // match
else
goto nomatch;
}
/* 3. Check content match */
f = NULL;
while ((f = xml_child_each(xfilter, f, CX_ELMNT)) != NULL) {
if ((fstr = leafstring(f)) == NULL)
continue;
if ((s = xml_find(xparent, xml_name(f))) == NULL)
goto nomatch;
if ((sstr = leafstring(s)) == NULL)
continue;
if (strcmp(fstr, sstr))
goto nomatch;
}
/* If filter has no further specifiers, accept */
if (!containments)
goto match;
/* Check recursively the rest of the siblings */
sprev = s = NULL;
while ((s = xml_child_each(xparent, s, CX_ELMNT)) != NULL) {
if ((f = xml_find(xfilter, xml_name(s))) == NULL){
xml_prune(xparent, s, 1);
s = sprev;
continue;
}
if (leafstring(f)){
sprev = s;
continue; // unsure?sk=lf
}
// XXX: s can be removed itself in the recursive call !
remove_s = 0;
if (xml_filter2(f, s, &remove_s) < 0)
return -1;
if (remove_s){
xml_prune(xparent, s, 1);
s = sprev;
}
sprev = s;
}
match:
return 0;
nomatch: /* prune this parent node (maybe only children?) */
*remove_me = 1;
return 0;
}
/*! Remove parts of configuration xml tree that does not match filter xml tree
* @param[in] xfilter Filter xml
* @param[out] xconf Configuration xml
* @retval 0 OK
* @retval -1 Error
* This is the top-level function, calls a recursive variant.
*/
int
xml_filter(cxobj *xfilter,
cxobj *xconfig)
{
int retval;
int remove_s;
/* Call recursive variant */
retval = xml_filter2(xfilter,
xconfig,
&remove_s);
return retval;
}
/*
* netconf_xpath
* @param[in] xsearch where you search for xpath, grouped by a single top node which
* is not significant and will not be returned in any result.
* @param[in] xfilter the xml sub-tree, eg:
* <filter type="xpath" select="/t:top/t:users/t:user[t:name='fred']"/>
* @param[out] cb Output xml stream. For reply
* @param[out] cb_err Error xml stream. For error reply
* @param[in] xorig Original tree
*
*/
int
netconf_xpath(cxobj *xsearch,
cxobj *xfilter,
cbuf *cb,
cbuf *cb_err,
cxobj *xorig)
{
cxobj *x;
int retval = -1;
char *selector;
cxobj **xv;
int xlen;
int i;
if ((selector = xml_find_value(xfilter, "select")) == NULL){
netconf_create_rpc_error(cb_err, xorig,
"operation-failed",
"application",
"error",
NULL,
"select");
goto done;
}
x = NULL;
clicon_errno = 0;
if ((xv = xpath_vec(xsearch, selector, &xlen)) != NULL) {
for (i=0; i<xlen; i++){
x = xv[i];
clicon_xml2cbuf(cb, x, 0, 1);
}
free(xv);
}
/* XXX: NULL means error sometimes */
if (clicon_errno){
netconf_create_rpc_error(cb_err, xorig,
"operation-failed",
"application",
"error",
clicon_err_reason,
"select");
goto done;
}
retval = 0;
done:
return retval;
}
#ifdef NOTUSED
/*
* in edit_config, we copy a tree to the config. But some wthings shouldbe
* cleaned:
* - operation attribute
*/
static int
netconf_clean(cxobj *xn)
{
cxobj *xa;
cxobj *x;
if ((xa = xml_find(xn, "operation")) != NULL &&
xml_type(xa) == CX_ATTR)
xml_prune(xn, xa, 1);
x = NULL;
while ((x = xml_child_each(xn, x, CX_ELMNT)) != NULL)
netconf_clean(x);
return 0;
}
/*
* get_operation
* get the value of the "operation" attribute and change op if given
*/
static int
get_operation(cxobj *xn,
enum operation_type *op,
cbuf *xf_err,
cxobj *xorig)
{
char *opstr;
if ((opstr = xml_find_value(xn, "operation")) != NULL){
if (strcmp("merge", opstr) == 0)
*op = OP_MERGE;
else
if (strcmp("replace", opstr) == 0)
*op = OP_REPLACE;
else
if (strcmp("create", opstr) == 0)
*op = OP_CREATE;
else
if (strcmp("delete", opstr) == 0)
*op = OP_DELETE;
else
if (strcmp("remove", opstr) == 0)
*op = OP_REMOVE;
else{
netconf_create_rpc_error(xf_err, xorig,
"bad-attribute",
"protocol",
"error",
NULL,
"<bad-attribute>operation</bad-attribute>");
return -1;
}
}
return 0;
}
/* forward */
static int
xml_edit(cxobj *filter,
cxobj *parent,
enum operation_type op,
cbuf *xf_err,
cxobj *xorig);
/*! Merge two XML trees according to RFC4741/Junos
* 1. in configuration(parent) but not in new(filter) -> remain in configuration
* 2. not in configuration but in new -> add to configuration
* 3. Both in configuration and new: Do 1.2.3 with children.
* A key is: the configuration data identified by the element
*/
static int
edit_selection(cxobj *filter,
cxobj *parent,
enum operation_type op,
cbuf *xf_err,
cxobj *xorig)
{
int retval = -1;
assert(filter && parent && strcmp(xml_name(filter), xml_name(parent))==0);
fprintf(stderr, "%s: %s\n", __FUNCTION__, xml_name(filter));
switch (op){
case OP_MERGE:
break;
case OP_REPLACE:
xml_prune(xml_parent(parent), parent, 1);
break;
case OP_CREATE:
netconf_create_rpc_error(xf_err, xorig,
NULL,
"protocol",
"error",
"statement creation failed",
"<bad-element></bad-element>");
goto done;
break;
case OP_DELETE:
fprintf(stderr, "%s: %s DELETE\n", __FUNCTION__, xml_name(filter));
if (xml_child_nr(parent) == 0){
fprintf(stderr, "%s: %s ERROR\n", __FUNCTION__, xml_name(filter));
netconf_create_rpc_error(xf_err, xorig,
NULL,
"protocol",
"error",
"statement not found",
"<bad-element></bad-element>");
goto done;
}
/* fall through */
case OP_REMOVE:
fprintf(stderr, "%s: %s REMOVE\n", __FUNCTION__, xml_name(filter));
xml_prune(xml_parent(parent), parent, 1);
break;
case OP_NONE:
break;
}
retval = 0;
netconf_ok_set(1); /* maybe cc_ok shouldnt be set if we continue? */
done:
return retval;
}
/*
* XXX: not called from external?
*/
static int
edit_match(cxobj *filter,
cxobj *parent,
enum operation_type op,
cbuf *xf_err,
cxobj *xorig,
int match
)
{
cxobj *f;
cxobj *s;
cxobj *copy;
int retval = -1;
clicon_debug(1, "%s: %s op:%d", __FUNCTION__, xml_name(filter), op);
if (match)
switch (op){
case OP_REPLACE:
case OP_CREATE:
s = NULL;
while ((s = xml_child_each(parent, s, -1)) != NULL){
xml_prune(parent, s, 1);
s = NULL;
}
if (xml_copy(filter, parent) < 0)
goto done;
netconf_clean(parent);
retval = 0;
netconf_ok_set(1);
goto done;
break;
case OP_DELETE:
case OP_REMOVE:
xml_prune(xml_parent(parent), parent, 1);
netconf_ok_set(1);
goto done;
break;
case OP_MERGE:
case OP_NONE:
break;
}
f = NULL;
while ((f = xml_child_each(filter, f, CX_ELMNT)) != NULL) {
s = xml_find(parent, xml_name(f));
switch (op){
case OP_MERGE:
/* things in filter:
not in conf should be added
in conf go down recursive
*/
if (s == NULL && match){
if ((copy = xml_new(xml_name(f), parent)) == NULL)
goto done;
if (xml_copy(f, copy) < 0)
goto done;
netconf_clean(copy);
}
else{
s = NULL;
while ((s = xml_child_each(parent, s, CX_ELMNT)) != NULL) {
if (strcmp(xml_name(f), xml_name(s)))
continue;
if ((retval = xml_edit(f, s, op, xf_err, xorig)) < 0)
goto done;
}
}
break;
case OP_REPLACE:
#if 1
/* things in filter
in conf: remove from conf and
add to conf
*/
// if (!match)
// break;
if (s != NULL)
xml_prune(parent, s, 1);
if ((copy = xml_new(xml_name(f), parent)) == NULL)
goto done;
if (xml_copy(f, copy) < 0)
goto done;
netconf_clean(copy);
#endif
break;
case OP_CREATE:
#if 0
/* things in filter
in conf: error
else add to conf
*/
if (!match)
break;
if (s != NULL){
netconf_create_rpc_error(xf_err, xorig,
NULL,
"protocol",
"error",
"statement creation failed",
"<bad-element></bad-element>");
goto done;
}
if ((copy = xml_new(xml_name(f), parent)) == NULL)
goto done;
if (xml_copy(f, copy) < 0)
goto done;
netconf_clean(copy);
#endif
break;
case OP_DELETE:
/* things in filter
if not in conf: error
else remove from conf
*/
#if 0
if (!match)
break;
if (s == NULL){
netconf_create_rpc_error(xf_err, xorig,
NULL,
"protocol",
"error",
"statement not found",
"<bad-element></bad-element>");
goto done;
}
#endif
/* fall through */
case OP_REMOVE:
/* things in filter
remove from conf
*/
#if 0
if (!match)
break;
xml_prune(parent, s, 1);
#endif
break;
case OP_NONE:
/* recursive descent */
s = NULL;
while ((s = xml_child_each(parent, s, CX_ELMNT)) != NULL) {
if (strcmp(xml_name(f), xml_name(s)))
continue;
if ((retval = xml_edit(f, s, op, xf_err, xorig)) < 0)
goto done;
}
break;
}
} /* while f */
retval = 0;
netconf_ok_set(1); /* maybe cc_ok shouldnt be set if we continue? */
done:
return retval;
}
/*
* xml_edit
* merge filter into parent
* XXX: not called from external?
*/
static int
xml_edit(cxobj *filter,
cxobj *parent,
enum operation_type op,
cbuf *xf_err,
cxobj *xorig)
{
cxobj *attr;
cxobj *f;
cxobj *s;
int retval = -1;
char *an, *af;
char *fstr, *sstr;
int keymatch = 0;
get_operation(filter, &op, xf_err, xorig);
/* 1. First try selection: filter is empty */
if (xml_child_nr(filter) == 0){ /* no elements? */
retval = edit_selection(filter, parent, op, xf_err, xorig);
goto done;
}
if (xml_child_nr(filter) == 1 && /* same as above */
xpath_first(filter, "/[@operation]")){
retval = edit_selection(filter, parent, op, xf_err, xorig);
goto done;
}
/* 2. Check attribute match */
attr = NULL;
while ((attr = xml_child_each(filter, attr, CX_ATTR)) != NULL) {
af = xml_value(attr);
an = xml_find_value(filter, xml_name(attr));
if (af && an && strcmp(af, an)==0)
; // match
else
goto nomatch;
}
/* 3. Check content match */
/*
* For content-match we do a somewhat strange thing, we find
* a match in first content-node and assume that is unique
* and then we remove/replace that
* For merge we just continue
*/
f = NULL;
while ((f = xml_child_each(filter, f, CX_ELMNT)) != NULL) {
if ((fstr = leafstring(f)) == NULL)
continue;
/* we found a filter leaf-match: no return we say it should match*/
if ((s = xml_find(parent, xml_name(f))) == NULL)
goto nomatch;
if ((sstr = leafstring(s)) == NULL)
goto nomatch;
if (strcmp(fstr, sstr))
goto nomatch;
keymatch++;
break; /* match */
}
if (debug && keymatch){
fprintf(stderr, "%s: match\n", __FUNCTION__);
fprintf(stderr, "%s: filter:\n", __FUNCTION__);
clicon_xml2file(stdout, filter, 0, 1);
fprintf(stderr, "%s: config:\n", __FUNCTION__);
clicon_xml2file(stdout, parent, 0, 1);
}
retval = edit_match(filter, parent, op, xf_err, xorig, keymatch);
/* match */
netconf_ok_set(1);
retval = 0;
done:
return retval;
nomatch:
return 0;
}
#endif /* NOTUSED */

View file

@ -0,0 +1,36 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
* netconf match & selection: get and edit operations
*****************************************************************************/
#ifndef _NETCONF_FILTER_H_
#define _NETCONF_FILTER_H_
/*
* Prototypes
*/
int xml_filter(cxobj *xf, cxobj *xn);
int netconf_xpath(cxobj *xsearch,
cxobj *xfilter,
cbuf *xf, cbuf *xf_err,
cxobj *xt);
#endif /* _NETCONF_FILTER_H_ */

View file

@ -0,0 +1,118 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
* Code for handling netconf hello messages
*****************************************************************************/
/*
Capabilities are advertised in messages sent by each peer during
session establishment. When the NETCONF session is opened, each peer
(both client and server) MUST send a <hello> element containing a
list of that peer's capabilities. Each peer MUST send at least the
base NETCONF capability, "urn:ietf:params:netconf:base:1.0".
<hello>
<capabilities>
<capability>URI</capability>
</capabilities>
</hello>
*/
#ifdef HAVE_CONFIG_H
#include "clicon_config.h" /* generated by config & autoconf */
#endif
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/param.h>
#include <assert.h>
/* cligen */
#include <cligen/cligen.h>
/* clicon */
#include <clicon/clicon.h>
#include "netconf_lib.h"
#include "netconf_hello.h"
static int
netconf_hello(cxobj *xn)
{
cxobj *x;
x = NULL;
while ((x = xpath_each(xn, "//capability", x)) != NULL) {
//fprintf(stderr, "cap: %s\n", xml_body(x));
}
return 0;
}
int
netconf_hello_dispatch(cxobj *xn)
{
cxobj *xp;
int retval = -1;
if ((xp = xpath_first(xn, "//hello")) != NULL)
retval = netconf_hello(xp);
return retval;
}
/*
* netconf_create_hello
* create capability string (once)
*/
int
netconf_create_hello(cbuf *xf, /* msg buffer */
int session_id)
{
int retval = 0;
add_preamble(xf);
cprintf(xf, "<hello>");
cprintf(xf, "<capabilities>");
cprintf(xf, "<capability>urn:ietf:params:xml:ns:netconf:base:1.0</capability>\n");
cprintf(xf, "<capability>urn:ietf:params:xml:ns:netconf:capability:candidate:1:0</capability>\n");
cprintf(xf, "<capability>urn:ietf:params:xml:ns:netconf:capability:validate:1.0</capability>\n");
cprintf(xf, "<capability>urn:ietf:params:netconf:capability:xpath:1.0</capability>\n");
cprintf(xf, "<capability>urn:ietf:params:netconf:capability:notification:1.0</capability>\n");
// cprintf(xf, "<capability>urn:rnr:rnrapi:1:0</capability>");
cprintf(xf, "</capabilities>");
cprintf(xf, "<session-id>%lu</session-id>", 42+session_id);
cprintf(xf, "</hello>");
add_postamble(xf);
return retval;
}

View file

@ -0,0 +1,34 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
* Code for handling netconf hello messages
*****************************************************************************/
#ifndef _NETCONF_HELLO_H_
#define _NETCONF_HELLO_H_
/*
* Prototypes
*/
int netconf_create_hello(cbuf *xf, int session_id);
int netconf_hello_dispatch(cxobj *xn);
#endif /* _NETCONF_HELLO_H_ */

261
apps/netconf/netconf_lib.c Normal file
View file

@ -0,0 +1,261 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
* netconf lib
*****************************************************************************/
#ifdef HAVE_CONFIG_H
#include "clicon_config.h" /* generated by config & autoconf */
#endif
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <syslog.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/param.h>
#include <assert.h>
/* cligen */
#include <cligen/cligen.h>
/* clicon */
#include <clicon/clicon.h>
#include "netconf_rpc.h"
#include "netconf_lib.h"
/*
* Exported variables
*/
enum transport_type transport = NETCONF_SSH;
int cc_closed = 0;
static int cc_ok = 0;
void
netconf_ok_set(int ok)
{
cc_ok = ok;
}
int
netconf_ok_get(void)
{
return cc_ok;
}
int
add_preamble(cbuf *xf)
{
if (transport == NETCONF_SOAP)
cprintf(xf, "\n<soapenv:Envelope\n xmlns:soapenv=\"http://www.w3.org/2003/05/soap-envelope\">\n"
"<soapenv:Body>");
return 0;
}
/*
* add_postamble
* add netconf xml postamble of message. That is, xml after the body of the message.
* for soap this is the envelope stuff, for ssh this is ]]>]]>
*/
int
add_postamble(cbuf *xf)
{
switch (transport){
case NETCONF_SSH:
cprintf(xf, "]]>]]>"); /* Add RFC4742 end-of-message marker */
break;
case NETCONF_SOAP:
cprintf(xf, "\n</soapenv:Body>" "</soapenv:Envelope>");
break;
}
return 0;
}
/*
* add_error_preamble
* compared to regular messages (see add_preamble), error message differ in some
* protocols (eg soap) by adding a longer and deeper header.
*/
int
add_error_preamble(cbuf *xf, char *reason)
{
switch (transport){
case NETCONF_SOAP:
cprintf(xf, "<soapenv:Envelope xmlns:soapenv=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:xml=\"http://www.w3.org/XML/1998/namespace\">"
"<soapenv:Body>"
"<soapenv:Fault>"
"<soapenv:Code>"
"<soapenv:Value>env:Receiver</soapenv:Value>"
"</soapenv:Code>"
"<soapenv:Reason>"
"<soapenv:Text xml:lang=\"en\">%s</soapenv:Text>"
"</soapenv:Reason>"
"<detail>", reason);
break;
default:
if (add_preamble(xf) < 0)
return -1;
break;
}
return 0;
}
/*
* add_error_postamble
* compared to regular messages (see add_postamble), error message differ in some
* protocols (eg soap) by adding a longer and deeper header.
*/
int
add_error_postamble(cbuf *xf)
{
switch (transport){
case NETCONF_SOAP:
cprintf(xf, "</detail>" "</soapenv:Fault>");
default: /* fall through */
if (add_postamble(xf) < 0)
return -1;
break;
}
return 0;
}
/*! Look for a text pattern in an input string, one char at a time
* @param[in] tag What to look for
* @param[in] ch New input character
* @param[in,out] state A state integer holding how far we have parsed.
* @retval 0 No, we havent detected end tag
* @retval 1 Yes, we have detected end tag!
* XXX: move to clicon_xml?
*/
int
detect_endtag(char *tag, char ch, int *state)
{
int retval = 0;
if (tag[*state] == ch){
(*state)++;
if (*state == strlen(tag)){
*state = 0;
retval = 1;
}
}
else
*state = 0;
return retval;
}
/*
* target_locked
* return 1 if locked, 0 if not.
* return clientid if locked.
*/
int
target_locked(enum target_type target, int *client)
{
return 0;
}
/*
* unlock_target
*/
int
unlock_target(enum target_type target)
{
return 0;
}
int
lock_target(enum target_type target)
{
return 0;
}
/*! Get "target" attribute, return actual database given candidate or running
* Caller must do error handling
* @retval dbname Actual database file name
*/
char *
netconf_get_target(clicon_handle h, cxobj *xn, char *path)
{
cxobj *x;
char *target = NULL;
char *running_db;
char *candidate_db;
if ((running_db = clicon_running_db(h)) == NULL)
goto done;
if ((candidate_db = clicon_candidate_db(h)) == NULL)
goto done;
if ((x = xpath_first(xn, path)) != NULL){
if (xpath_first(x, "candidate") != NULL)
target = candidate_db;
else
if (xpath_first(x, "running") != NULL)
target = running_db;
}
done:
return target;
}
/*! Send netconf message from cbuf on socket
* @param[in] s
* @param[in] cb Cligen buffer that contains the XML message
* @param[in] msg Only for debug
*/
int
netconf_output(int s, cbuf *xf, char *msg)
{
char *buf = cbuf_get(xf);
int len = cbuf_len(xf);
int retval = -1;
clicon_debug(1, "SEND %s", msg);
if (debug > 1){ /* XXX: below only works to stderr, clicon_debug may log to syslog */
cxobj *xt = NULL;
if (clicon_xml_parse_string(&buf, &xt) == 0){
clicon_xml2file(stderr, xml_child_i(xt, 0), 0, 0);
fprintf(stderr, "\n");
xml_free(xt);
}
}
if (write(s, buf, len) < 0){
if (errno == EPIPE)
;
else
clicon_log(LOG_ERR, "%s: write: %s", __FUNCTION__, strerror(errno));
goto done;
}
retval = 0;
done:
return retval;
}

View file

@ -0,0 +1,75 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
* Netconf lib
*****************************************************************************/
#ifndef _NETCONF_LIB_H_
#define _NETCONF_LIB_H_
/*
* Types
*/
enum target_type{ /* netconf */
RUNNING,
CANDIDATE
};
enum transport_type{
NETCONF_SSH, /* RFC 4742 */
NETCONF_SOAP, /* RFC 4743 */
};
enum test_option{ /* edit-config */
SET,
TEST_THEN_SET,
TEST_ONLY
};
enum error_option{ /* edit-config */
STOP_ON_ERROR,
CONTINUE_ON_ERROR
};
enum filter_option{ /* get-config/filter */
FILTER_SUBTREE,
FILTER_XPATH
};
/*
* Variables
*/
extern enum transport_type transport;
extern int cc_closed;
/*
* Prototypes
*/
void netconf_ok_set(int ok);
int netconf_ok_get(void);
int add_preamble(cbuf *xf);
int add_postamble(cbuf *xf);
int add_error_preamble(cbuf *xf, char *reason);
int detect_endtag(char *tag, char ch, int *state);
char *netconf_get_target(clicon_handle h, cxobj *xn, char *path);
int add_error_postamble(cbuf *xf);
int netconf_output(int s, cbuf *xf, char *msg);
#endif /* _NETCONF_LIB_H_ */

425
apps/netconf/netconf_main.c Normal file
View file

@ -0,0 +1,425 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "clicon_config.h" /* generated by config & autoconf */
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <time.h>
#include <syslog.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <netinet/in.h>
/* cligen */
#include <cligen/cligen.h>
/* clicon */
#include <clicon/clicon.h>
#include "clicon_netconf.h"
#include "netconf_lib.h"
#include "netconf_hello.h"
#include "netconf_plugin.h"
#include "netconf_rpc.h"
/* Command line options to be passed to getopt(3) */
#define NETCONF_OPTS "hDqf:d:S"
/*! Process incoming packet
* @param[in] h Clicon handle
* @param[in] xf Packet buffer
*/
static int
process_incoming_packet(clicon_handle h,
cbuf *xf)
{
char *str;
char *str0;
cxobj *xml_req = NULL; /* Request (in) */
int isrpc = 0; /* either hello or rpc */
cbuf *xf_out;
cbuf *xf_err;
cbuf *xf1;
clicon_debug(1, "RECV");
clicon_debug(2, "%s: RCV: \"%s\"", __FUNCTION__, cbuf_get(xf));
if ((str0 = strdup(cbuf_get(xf))) == NULL){
clicon_log(LOG_ERR, "%s: strdup: %s", __FUNCTION__, strerror(errno));
return -1;
}
str = str0;
/* Parse incoming XML message */
if (clicon_xml_parse_string(&str, &xml_req) < 0){
if ((xf = cbuf_new()) == NULL){
netconf_create_rpc_error(xf, NULL,
"operation-failed",
"rpc", "error",
NULL,
NULL);
netconf_output(1, xf, "rpc-error");
cbuf_free(xf);
}
else
clicon_log(LOG_ERR, "%s: cbuf_new", __FUNCTION__);
free(str0);
goto done;
}
free(str0);
if (xpath_first(xml_req, "//rpc") != NULL){
isrpc++;
}
else
if (xpath_first(xml_req, "//hello") != NULL)
;
else{
clicon_log(LOG_WARNING, "Invalid netconf msg: neither rpc or hello: dropp\
ed");
goto done;
}
/* Initialize response buffers */
if ((xf_out = cbuf_new()) == NULL){
clicon_log(LOG_ERR, "%s: cbuf_new", __FUNCTION__);
goto done;
}
/* Create error buf */
if ((xf_err = cbuf_new()) == NULL){
clicon_log(LOG_ERR, "%s: cbuf_new", __FUNCTION__);
goto done;
}
netconf_ok_set(0);
if (isrpc){
if (netconf_rpc_dispatch(h,
xml_req,
xpath_first(xml_req, "//rpc"),
xf_out, xf_err) < 0){
assert(cbuf_len(xf_err));
clicon_debug(1, "%s", cbuf_get(xf_err));
if (isrpc){
if (netconf_output(1, xf_err, "rpc-error") < 0)
goto done;
}
}
else{
if ((xf1 = cbuf_new()) != NULL){
if (netconf_create_rpc_reply(xf1, xml_req, cbuf_get(xf_out), netconf_ok_get()) < 0){
cbuf_free(xf_out);
cbuf_free(xf_err);
cbuf_free(xf1);
goto done;
}
if (netconf_output(1, xf1, "rpc-reply") < 0){
cbuf_reset(xf1);
netconf_create_rpc_error(xf1, xml_req, "operation-failed",
"protocol", "error",
NULL, cbuf_get(xf_err));
netconf_output(1, xf1, "rpc-error");
cbuf_free(xf_out);
cbuf_free(xf_err);
cbuf_free(xf1);
goto done;
}
cbuf_free(xf1);
}
}
}
else{
netconf_hello_dispatch(xml_req); /* XXX: return-value */
}
cbuf_free(xf_out);
cbuf_free(xf_err);
done:
if (xml_req)
xml_free(xml_req);
return 0;
}
/*! Get netconf message: detect end-of-msg
* @param[in] s Socket where input arrived. read from this.
* @param[in] arg Clicon handle.
*/
static int
netconf_input_cb(int s,
void *arg)
{
clicon_handle h = arg;
unsigned char buf[BUFSIZ];
int i;
int len;
static cbuf *xf; /* XXX: should use ce state? */
int xml_state = 0;
int retval = -1;
if (xf == NULL)
if ((xf = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "%s: cbuf_new", __FUNCTION__);
return retval;
}
memset(buf, 0, sizeof(buf));
if ((len = read(s, buf, sizeof(buf))) < 0){
if (errno == ECONNRESET)
len = 0; /* emulate EOF */
else{
clicon_log(LOG_ERR, "%s: read: %s", __FUNCTION__, strerror(errno));
goto done;
}
} /* read */
if (len == 0){ /* EOF */
cc_closed++;
close(s);
retval = 0;
goto done;
}
for (i=0; i<len; i++){
if (buf[i] == 0)
continue; /* Skip NULL chars (eg from terminals) */
cprintf(xf, "%c", buf[i]);
if (detect_endtag("]]>]]>",
buf[i],
&xml_state)) {
/* OK, we have an xml string from a client */
if (process_incoming_packet(h, xf) < 0){
goto done;
}
if (cc_closed)
break;
cbuf_reset(xf);
}
}
retval = 0;
done:
// cbuf_free(xf);
if (cc_closed)
retval = -1;
return retval;
}
/*
* send_hello
* args: s file descriptor to write on (eg 1 - stdout)
*/
static int
send_hello(int s)
{
cbuf *xf;
int retval = -1;
if ((xf = cbuf_new()) == NULL){
clicon_log(LOG_ERR, "%s: cbuf_new", __FUNCTION__);
goto done;
}
if (netconf_create_hello(xf, getpid()) < 0)
goto done;
if (netconf_output(s, xf, "hello") < 0)
goto done;
retval = 0;
done:
if (xf)
cbuf_free(xf);
return retval;
}
/* from init_candidate_db() and clicon_rpc_copy() */
static int
init_candidate_db(clicon_handle h, char *running_db, char *candidate_db)
{
struct stat sb;
int retval = -1;
/* init shared candidate */
if (lstat(candidate_db, &sb) < 0){
if (clicon_rpc_copy(h, running_db, candidate_db) < 0)
goto done;
}
retval = 0;
done:
unchunk_group(__FUNCTION__);
return retval;
}
static int
terminate(clicon_handle h)
{
yang_spec *yspec;
if ((yspec = clicon_dbspec_yang(h)) != NULL)
yspec_free(yspec);
clicon_handle_exit(h);
return 0;
}
/*
* usage
*/
static void
usage(char *argv0, clicon_handle h)
{
char *netconfdir = clicon_netconf_dir(h);
fprintf(stderr, "usage:%s\n"
"where options are\n"
"\t-h\t\tHelp\n"
"\t-D\t\tDebug\n"
"\t-q\t\tQuiet: dont send hello prompt\n"
"\t-f <file>\tConfiguration file (mandatory)\n"
"\t-d <dir>\tSpecify netconf plugin directory dir (default: %s)\n"
"\t-S\t\tLog on syslog\n",
argv0,
netconfdir
);
exit(0);
}
int
main(int argc, char **argv)
{
char c;
char *tmp;
char *argv0 = argv[0];
int quiet = 0;
clicon_handle h;
int use_syslog;
char *running_db;
char *candidate_db;
/* Defaults */
use_syslog = 0;
/* In the startup, logs to stderr & debug flag set later */
clicon_log_init(__PROGRAM__, LOG_INFO, CLICON_LOG_STDERR);
/* Create handle */
if ((h = clicon_handle_init()) == NULL)
return -1;
while ((c = getopt(argc, argv, NETCONF_OPTS)) != -1)
switch (c) {
case 'h' : /* help */
usage(argv[0], h);
break;
case 'D' : /* debug */
debug = 1;
break;
case 'f': /* override config file */
if (!strlen(optarg))
usage(argv[0], h);
clicon_option_str_set(h, "CLICON_CONFIGFILE", optarg);
break;
case 'S': /* Log on syslog */
use_syslog = 1;
break;
}
/*
* Logs, error and debug to stderr or syslog, set debug level
*/
clicon_log_init(__PROGRAM__, debug?LOG_DEBUG:LOG_INFO,
use_syslog?CLICON_LOG_SYSLOG:CLICON_LOG_STDERR);
clicon_debug_init(debug, NULL);
/* Find and read configfile */
if (clicon_options_main(h) < 0)
return -1;
/* Now rest of options */
optind = 1;
opterr = 0;
while ((c = getopt(argc, argv, NETCONF_OPTS)) != -1)
switch (c) {
case 'h' : /* help */
case 'D' : /* debug */
case 'f': /* config file */
case 'S': /* Log on syslog */
break; /* see above */
case 'q': /* quiet: dont write hello */
quiet++;
break;
case 'd': /* Plugin directory */
if (!strlen(optarg))
usage(argv[0], h);
clicon_option_str_set(h, "CLICON_NETCONF_DIR", optarg);
break;
default:
usage(argv[0], h);
break;
}
argc -= optind;
argv += optind;
/* Parse db spec file */
if (yang_spec_main(h, stdout, 0) < 0)
goto done;
/* Initialize plugins group */
if (netconf_plugin_load(h) < 0)
return -1;
if ((running_db = clicon_running_db(h)) == NULL){
clicon_err(OE_FATAL, 0, "running db not set");
goto done;
}
if ((candidate_db = clicon_candidate_db(h)) == NULL){
clicon_err(OE_FATAL, 0, "candidate db not set");
goto done;
}
if (init_candidate_db(h, running_db, candidate_db) < 0)
return -1;
/* Call start function is all plugins before we go interactive */
tmp = *(argv-1);
*(argv-1) = argv0;
netconf_plugin_start(h, argc+1, argv-1);
*(argv-1) = tmp;
if (!quiet)
send_hello(1);
if (event_reg_fd(0, netconf_input_cb, h, "netconf socket") < 0)
goto done;
if (debug)
clicon_option_dump(h, debug);
if (event_loop() < 0)
goto done;
done:
netconf_plugin_unload(h);
terminate(h);
clicon_log_init(__PROGRAM__, LOG_INFO, 0); /* Log on syslog no stderr */
clicon_log(LOG_NOTICE, "%s: %u Terminated\n", __PROGRAM__, getpid());
return 0;
}

View file

@ -0,0 +1,277 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
* handling netconf plugins
*/
#ifdef HAVE_CONFIG_H
#include "clicon_config.h" /* generated by config & autoconf */
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <syslog.h>
#include <errno.h>
#include <assert.h>
#include <dlfcn.h>
#include <dirent.h>
#include <grp.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <netinet/in.h>
/* cligen */
#include <cligen/cligen.h>
/* clicon */
#include <clicon/clicon.h>
/* clicon netconf*/
#include "clicon_netconf.h"
#include "netconf_lib.h"
#include "netconf_plugin.h"
/*
* Unload a plugin
*/
static int
plugin_unload(clicon_handle h, void *handle)
{
int retval = 0;
char *error;
plgexit_t *exitfn;
/* Call exit function is it exists */
exitfn = dlsym(handle, PLUGIN_EXIT);
if (dlerror() == NULL)
exitfn(h);
dlerror(); /* Clear any existing error */
if (dlclose(handle) != 0) {
error = (char*)dlerror();
clicon_err(OE_PLUGIN, errno, "dlclose: %s\n", error ? error : "Unknown error");
/* Just report */
}
return retval;
}
/*
* Load a dynamic plugin object and call it's init-function
* Note 'file' may be destructively modified
*/
static plghndl_t
plugin_load (clicon_handle h, char *file, int dlflags, const char *cnklbl)
{
char *error;
void *handle = NULL;
plginit_t *initfn;
dlerror(); /* Clear any existing error */
if ((handle = dlopen (file, dlflags)) == NULL) {
error = (char*)dlerror();
clicon_err(OE_PLUGIN, errno, "dlopen: %s\n", error ? error : "Unknown error");
goto quit;
}
/* call plugin_init() if defined */
if ((initfn = dlsym(handle, PLUGIN_INIT)) != NULL) {
if (initfn(h) != 0) {
clicon_err(OE_PLUGIN, errno, "Failed to initiate %s\n", strrchr(file,'/')?strchr(file, '/'):file);
goto quit;
}
}
quit:
return handle;
}
static int nplugins = 0;
static plghndl_t *plugins = NULL;
static netconf_reg_t *deps = NULL;
/*
* netconf_plugin_load
* Load allplugins you can find in CLICON_NETCONF_DIR
*/
int
netconf_plugin_load(clicon_handle h)
{
int retval = -1;
char *dir;
int ndp;
struct dirent *dp;
int i;
char *filename;
plghndl_t *handle;
if ((dir = clicon_netconf_dir(h)) == NULL){
clicon_err(OE_PLUGIN, 0, "clicon_netconf_dir not defined");
goto quit;
}
/* Get plugin objects names from plugin directory */
if((ndp = clicon_file_dirent(dir, &dp, "(.so)$", S_IFREG, __FUNCTION__))<0)
goto quit;
/* Load all plugins */
for (i = 0; i < ndp; i++) {
filename = chunk_sprintf(__FUNCTION__, "%s/%s", dir, dp[i].d_name);
clicon_debug(1, "DEBUG: Loading plugin '%.*s' ...",
(int)strlen(filename), filename);
if (filename == NULL) {
clicon_err(OE_UNIX, errno, "chunk");
goto quit;
}
if ((handle = plugin_load (h, filename, RTLD_NOW, __FUNCTION__)) == NULL)
goto quit;
if ((plugins = rechunk(plugins, (nplugins+1) * sizeof (*plugins), NULL)) == NULL) {
clicon_err(OE_UNIX, errno, "chunk");
goto quit;
}
plugins[nplugins++] = handle;
unchunk (filename);
}
retval = 0;
quit:
unchunk_group(__FUNCTION__);
return retval;
}
int
netconf_plugin_unload(clicon_handle h)
{
int i;
netconf_reg_t *nr;
while((nr = deps) != NULL) {
DELQ(nr, deps, netconf_reg_t *);
if (nr->nr_tag)
free(nr->nr_tag);
free(nr);
}
for (i = 0; i < nplugins; i++)
plugin_unload(h, plugins[i]);
if (plugins)
unchunk(plugins);
nplugins = 0;
return 0;
}
/*
* Call plugin_start in all plugins
*/
int
netconf_plugin_start(clicon_handle h, int argc, char **argv)
{
int i;
plgstart_t *startfn;
for (i = 0; i < nplugins; i++) {
/* Call exit function is it exists */
if ((startfn = dlsym(plugins[i], PLUGIN_START)) == NULL)
break;
optind = 0;
if (startfn(h, argc, argv) < 0) {
clicon_debug(1, "plugin_start() failed\n");
return -1;
}
}
return 0;
}
/*
* netconf_register_callback
* Called from plugin to register a callback for a specific netconf XML tag.
*/
int
netconf_register_callback(clicon_handle h,
netconf_cb_t cb, /* Callback called */
void *arg, /* Arg to send to callback */
char *tag) /* Xml tag when callback is made */
{
netconf_reg_t *nr;
if ((nr = malloc(sizeof(netconf_reg_t))) == NULL) {
clicon_err(OE_DB, errno, "malloc: %s", strerror(errno));
goto catch;
}
memset (nr, 0, sizeof (*nr));
nr->nr_callback = cb;
nr->nr_arg = arg;
nr->nr_tag = strdup(tag); /* strdup */
INSQ(nr, deps);
return 0;
catch:
if (nr){
if (nr->nr_tag)
free(nr->nr_tag);
free(nr);
}
return -1;
}
/*! See if there is any callback registered for this tag
*
* @param xn Sub-tree (under xorig) at child of rpc: <rpc><xn></rpc>.
* @param xf Output xml stream. For reply
* @param xf_err Error xml stream. For error reply
* @param xorig Original request.
*
* @retval -1 Error
* @retval 0 OK, not found handler.
* @retval 1 OK, handler called
*/
int
netconf_plugin_callbacks(clicon_handle h,
cxobj *xn,
cbuf *xf,
cbuf *xf_err,
cxobj *xorig)
{
netconf_reg_t *nr;
int retval;
if (deps == NULL)
return 0;
nr = deps;
do {
if (strcmp(nr->nr_tag, xml_name(xn)) == 0){
if ((retval = nr->nr_callback(h,
xorig,
xn,
xf,
xf_err,
nr->nr_arg)) < 0)
return -1;
else
return 1; /* handled */
}
nr = NEXTQ(netconf_reg_t *, nr);
} while (nr != deps);
return 0;
}

View file

@ -0,0 +1,57 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
* handling netconf plugins
*****************************************************************************/
#ifndef _NETCONF_PLUGIN_H_
#define _NETCONF_PLUGIN_H_
/*
* Types
*/
/* Database dependency description */
struct netconf_reg {
qelem_t nr_qelem; /* List header */
netconf_cb_t nr_callback; /* Validation/Commit Callback */
void *nr_arg; /* Application specific argument to cb */
char *nr_tag; /* Xml tag when matched, callback called */
};
typedef struct netconf_reg netconf_reg_t;
/*
* Prototypes
*/
int netconf_plugin_load(clicon_handle h);
int netconf_plugin_start(clicon_handle h, int argc, char **argv);
int netconf_plugin_unload(clicon_handle h);
int netconf_plugin_callbacks(clicon_handle h,
// dbspec_key *dbspec,
cxobj *xn,
cbuf *xf,
cbuf *xf_err,
cxobj *xt);
#endif /* _NETCONF_PLUGIN_H_ */

1258
apps/netconf/netconf_rpc.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,48 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
* Code for handling netconf rpc messages
*****************************************************************************/
#ifndef _NETCONF_RPC_H_
#define _NETCONF_RPC_H_
/*
* Prototypes
*/
int
netconf_rpc_dispatch(clicon_handle h,
cxobj *xorig,
cxobj *xn,
cbuf *xf,
cbuf *xf_err);
int netconf_create_rpc_reply(cbuf *xf, /* msg buffer */
cxobj *xr, /* orig request */
char *body, int ok);
int netconf_create_rpc_error(cbuf *xf, /* msg buffer */
cxobj *xr, /* orig request */
char *tag,
char *type,
char *severity,
char *message,
char *info);
#endif /* _NETCONF_RPC_H_ */

5482
autom4te.cache/output.0 Normal file

File diff suppressed because it is too large Load diff

77
autom4te.cache/requests Normal file
View file

@ -0,0 +1,77 @@
# This file was generated by Autom4te Thu Apr 10 10:06:43 UTC 2014.
# It contains the lists of macros which have been traced.
# It can be safely removed.
@request = (
bless( [
'0',
1,
[
'/usr/share/autoconf'
],
[
'/usr/share/autoconf/autoconf/autoconf.m4f',
'configure.ac'
],
{
'AC_REQUIRE_AUX_FILE' => 1,
'AC_DEFINE_TRACE_LITERAL' => 1,
'AC_SUBST_TRACE' => 1,
'AC_CONFIG_FILES' => 1,
'AC_SUBST' => 1,
'LT_INIT' => 1,
'AC_FC_PP_SRCEXT' => 1,
'_LT_AC_TAGCONFIG' => 1,
'm4_sinclude' => 1,
'AC_FC_FREEFORM' => 1,
'sinclude' => 1,
'AM_PATH_GUILE' => 1,
'AC_CONFIG_LIBOBJ_DIR' => 1,
'AC_INIT' => 1,
'_AM_COND_ENDIF' => 1,
'AM_PROG_CXX_C_O' => 1,
'm4_pattern_allow' => 1,
'AM_SILENT_RULES' => 1,
'm4_include' => 1,
'_m4_warn' => 1,
'AC_CONFIG_LINKS' => 1,
'AM_AUTOMAKE_VERSION' => 1,
'AM_NLS' => 1,
'AC_FC_SRCEXT' => 1,
'AM_CONDITIONAL' => 1,
'_AM_SUBST_NOTMAKE' => 1,
'_AM_COND_ELSE' => 1,
'AC_CONFIG_AUX_DIR' => 1,
'AC_CONFIG_HEADERS' => 1,
'AM_GNU_GETTEXT' => 1,
'AM_INIT_AUTOMAKE' => 1,
'include' => 1,
'LT_CONFIG_LTDL_DIR' => 1,
'_AM_COND_IF' => 1,
'AM_PROG_F77_C_O' => 1,
'AC_CANONICAL_SYSTEM' => 1,
'AC_CONFIG_SUBDIRS' => 1,
'AC_LIBSOURCE' => 1,
'AM_PROG_MOC' => 1,
'AC_FC_PP_DEFINE' => 1,
'_AM_MAKEFILE_INCLUDE' => 1,
'AM_ENABLE_MULTILIB' => 1,
'AC_PROG_LIBTOOL' => 1,
'AM_PROG_FC_C_O' => 1,
'AM_XGETTEXT_OPTION' => 1,
'AM_GNU_GETTEXT_INTL_SUBDIR' => 1,
'AM_POT_TOOLS' => 1,
'AM_MAINTAINER_MODE' => 1,
'AC_CANONICAL_HOST' => 1,
'AM_PROG_AR' => 1,
'AM_MAKEFILE_INCLUDE' => 1,
'AC_CANONICAL_TARGET' => 1,
'AM_PROG_CC_C_O' => 1,
'LT_SUPPORTED_TAG' => 1,
'm4_pattern_forbid' => 1,
'AH_OUTPUT' => 1,
'AC_CANONICAL_BUILD' => 1
}
], 'Autom4te::Request' )
);

452
autom4te.cache/traces.0 Normal file
View file

@ -0,0 +1,452 @@
m4trace:configure.ac:26: -1- AC_INIT([lib/clicon/clicon.h.in])
m4trace:configure.ac:26: -1- m4_pattern_forbid([^_?A[CHUM]_])
m4trace:configure.ac:26: -1- m4_pattern_forbid([_AC_])
m4trace:configure.ac:26: -1- m4_pattern_forbid([^LIBOBJS$], [do not use LIBOBJS directly, use AC_LIBOBJ (see section `AC_LIBOBJ vs LIBOBJS'])
m4trace:configure.ac:26: -1- m4_pattern_allow([^AS_FLAGS$])
m4trace:configure.ac:26: -1- m4_pattern_forbid([^_?m4_])
m4trace:configure.ac:26: -1- m4_pattern_forbid([^dnl$])
m4trace:configure.ac:26: -1- m4_pattern_forbid([^_?AS_])
m4trace:configure.ac:26: -1- AC_SUBST([SHELL])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([SHELL])
m4trace:configure.ac:26: -1- m4_pattern_allow([^SHELL$])
m4trace:configure.ac:26: -1- AC_SUBST([PATH_SEPARATOR])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([PATH_SEPARATOR])
m4trace:configure.ac:26: -1- m4_pattern_allow([^PATH_SEPARATOR$])
m4trace:configure.ac:26: -1- AC_SUBST([PACKAGE_NAME], [m4_ifdef([AC_PACKAGE_NAME], ['AC_PACKAGE_NAME'])])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([PACKAGE_NAME])
m4trace:configure.ac:26: -1- m4_pattern_allow([^PACKAGE_NAME$])
m4trace:configure.ac:26: -1- AC_SUBST([PACKAGE_TARNAME], [m4_ifdef([AC_PACKAGE_TARNAME], ['AC_PACKAGE_TARNAME'])])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([PACKAGE_TARNAME])
m4trace:configure.ac:26: -1- m4_pattern_allow([^PACKAGE_TARNAME$])
m4trace:configure.ac:26: -1- AC_SUBST([PACKAGE_VERSION], [m4_ifdef([AC_PACKAGE_VERSION], ['AC_PACKAGE_VERSION'])])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([PACKAGE_VERSION])
m4trace:configure.ac:26: -1- m4_pattern_allow([^PACKAGE_VERSION$])
m4trace:configure.ac:26: -1- AC_SUBST([PACKAGE_STRING], [m4_ifdef([AC_PACKAGE_STRING], ['AC_PACKAGE_STRING'])])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([PACKAGE_STRING])
m4trace:configure.ac:26: -1- m4_pattern_allow([^PACKAGE_STRING$])
m4trace:configure.ac:26: -1- AC_SUBST([PACKAGE_BUGREPORT], [m4_ifdef([AC_PACKAGE_BUGREPORT], ['AC_PACKAGE_BUGREPORT'])])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([PACKAGE_BUGREPORT])
m4trace:configure.ac:26: -1- m4_pattern_allow([^PACKAGE_BUGREPORT$])
m4trace:configure.ac:26: -1- AC_SUBST([PACKAGE_URL], [m4_ifdef([AC_PACKAGE_URL], ['AC_PACKAGE_URL'])])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([PACKAGE_URL])
m4trace:configure.ac:26: -1- m4_pattern_allow([^PACKAGE_URL$])
m4trace:configure.ac:26: -1- AC_SUBST([exec_prefix], [NONE])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([exec_prefix])
m4trace:configure.ac:26: -1- m4_pattern_allow([^exec_prefix$])
m4trace:configure.ac:26: -1- AC_SUBST([prefix], [NONE])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([prefix])
m4trace:configure.ac:26: -1- m4_pattern_allow([^prefix$])
m4trace:configure.ac:26: -1- AC_SUBST([program_transform_name], [s,x,x,])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([program_transform_name])
m4trace:configure.ac:26: -1- m4_pattern_allow([^program_transform_name$])
m4trace:configure.ac:26: -1- AC_SUBST([bindir], ['${exec_prefix}/bin'])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([bindir])
m4trace:configure.ac:26: -1- m4_pattern_allow([^bindir$])
m4trace:configure.ac:26: -1- AC_SUBST([sbindir], ['${exec_prefix}/sbin'])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([sbindir])
m4trace:configure.ac:26: -1- m4_pattern_allow([^sbindir$])
m4trace:configure.ac:26: -1- AC_SUBST([libexecdir], ['${exec_prefix}/libexec'])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([libexecdir])
m4trace:configure.ac:26: -1- m4_pattern_allow([^libexecdir$])
m4trace:configure.ac:26: -1- AC_SUBST([datarootdir], ['${prefix}/share'])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([datarootdir])
m4trace:configure.ac:26: -1- m4_pattern_allow([^datarootdir$])
m4trace:configure.ac:26: -1- AC_SUBST([datadir], ['${datarootdir}'])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([datadir])
m4trace:configure.ac:26: -1- m4_pattern_allow([^datadir$])
m4trace:configure.ac:26: -1- AC_SUBST([sysconfdir], ['${prefix}/etc'])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([sysconfdir])
m4trace:configure.ac:26: -1- m4_pattern_allow([^sysconfdir$])
m4trace:configure.ac:26: -1- AC_SUBST([sharedstatedir], ['${prefix}/com'])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([sharedstatedir])
m4trace:configure.ac:26: -1- m4_pattern_allow([^sharedstatedir$])
m4trace:configure.ac:26: -1- AC_SUBST([localstatedir], ['${prefix}/var'])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([localstatedir])
m4trace:configure.ac:26: -1- m4_pattern_allow([^localstatedir$])
m4trace:configure.ac:26: -1- AC_SUBST([includedir], ['${prefix}/include'])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([includedir])
m4trace:configure.ac:26: -1- m4_pattern_allow([^includedir$])
m4trace:configure.ac:26: -1- AC_SUBST([oldincludedir], ['/usr/include'])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([oldincludedir])
m4trace:configure.ac:26: -1- m4_pattern_allow([^oldincludedir$])
m4trace:configure.ac:26: -1- AC_SUBST([docdir], [m4_ifset([AC_PACKAGE_TARNAME],
['${datarootdir}/doc/${PACKAGE_TARNAME}'],
['${datarootdir}/doc/${PACKAGE}'])])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([docdir])
m4trace:configure.ac:26: -1- m4_pattern_allow([^docdir$])
m4trace:configure.ac:26: -1- AC_SUBST([infodir], ['${datarootdir}/info'])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([infodir])
m4trace:configure.ac:26: -1- m4_pattern_allow([^infodir$])
m4trace:configure.ac:26: -1- AC_SUBST([htmldir], ['${docdir}'])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([htmldir])
m4trace:configure.ac:26: -1- m4_pattern_allow([^htmldir$])
m4trace:configure.ac:26: -1- AC_SUBST([dvidir], ['${docdir}'])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([dvidir])
m4trace:configure.ac:26: -1- m4_pattern_allow([^dvidir$])
m4trace:configure.ac:26: -1- AC_SUBST([pdfdir], ['${docdir}'])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([pdfdir])
m4trace:configure.ac:26: -1- m4_pattern_allow([^pdfdir$])
m4trace:configure.ac:26: -1- AC_SUBST([psdir], ['${docdir}'])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([psdir])
m4trace:configure.ac:26: -1- m4_pattern_allow([^psdir$])
m4trace:configure.ac:26: -1- AC_SUBST([libdir], ['${exec_prefix}/lib'])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([libdir])
m4trace:configure.ac:26: -1- m4_pattern_allow([^libdir$])
m4trace:configure.ac:26: -1- AC_SUBST([localedir], ['${datarootdir}/locale'])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([localedir])
m4trace:configure.ac:26: -1- m4_pattern_allow([^localedir$])
m4trace:configure.ac:26: -1- AC_SUBST([mandir], ['${datarootdir}/man'])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([mandir])
m4trace:configure.ac:26: -1- m4_pattern_allow([^mandir$])
m4trace:configure.ac:26: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_NAME])
m4trace:configure.ac:26: -1- m4_pattern_allow([^PACKAGE_NAME$])
m4trace:configure.ac:26: -1- AH_OUTPUT([PACKAGE_NAME], [/* Define to the full name of this package. */
@%:@undef PACKAGE_NAME])
m4trace:configure.ac:26: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_TARNAME])
m4trace:configure.ac:26: -1- m4_pattern_allow([^PACKAGE_TARNAME$])
m4trace:configure.ac:26: -1- AH_OUTPUT([PACKAGE_TARNAME], [/* Define to the one symbol short name of this package. */
@%:@undef PACKAGE_TARNAME])
m4trace:configure.ac:26: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_VERSION])
m4trace:configure.ac:26: -1- m4_pattern_allow([^PACKAGE_VERSION$])
m4trace:configure.ac:26: -1- AH_OUTPUT([PACKAGE_VERSION], [/* Define to the version of this package. */
@%:@undef PACKAGE_VERSION])
m4trace:configure.ac:26: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_STRING])
m4trace:configure.ac:26: -1- m4_pattern_allow([^PACKAGE_STRING$])
m4trace:configure.ac:26: -1- AH_OUTPUT([PACKAGE_STRING], [/* Define to the full name and version of this package. */
@%:@undef PACKAGE_STRING])
m4trace:configure.ac:26: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_BUGREPORT])
m4trace:configure.ac:26: -1- m4_pattern_allow([^PACKAGE_BUGREPORT$])
m4trace:configure.ac:26: -1- AH_OUTPUT([PACKAGE_BUGREPORT], [/* Define to the address where bug reports for this package should be sent. */
@%:@undef PACKAGE_BUGREPORT])
m4trace:configure.ac:26: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_URL])
m4trace:configure.ac:26: -1- m4_pattern_allow([^PACKAGE_URL$])
m4trace:configure.ac:26: -1- AH_OUTPUT([PACKAGE_URL], [/* Define to the home page for this package. */
@%:@undef PACKAGE_URL])
m4trace:configure.ac:26: -1- AC_SUBST([DEFS])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([DEFS])
m4trace:configure.ac:26: -1- m4_pattern_allow([^DEFS$])
m4trace:configure.ac:26: -1- AC_SUBST([ECHO_C])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([ECHO_C])
m4trace:configure.ac:26: -1- m4_pattern_allow([^ECHO_C$])
m4trace:configure.ac:26: -1- AC_SUBST([ECHO_N])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([ECHO_N])
m4trace:configure.ac:26: -1- m4_pattern_allow([^ECHO_N$])
m4trace:configure.ac:26: -1- AC_SUBST([ECHO_T])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([ECHO_T])
m4trace:configure.ac:26: -1- m4_pattern_allow([^ECHO_T$])
m4trace:configure.ac:26: -1- AC_SUBST([LIBS])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([LIBS])
m4trace:configure.ac:26: -1- m4_pattern_allow([^LIBS$])
m4trace:configure.ac:26: -1- AC_SUBST([build_alias])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([build_alias])
m4trace:configure.ac:26: -1- m4_pattern_allow([^build_alias$])
m4trace:configure.ac:26: -1- AC_SUBST([host_alias])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([host_alias])
m4trace:configure.ac:26: -1- m4_pattern_allow([^host_alias$])
m4trace:configure.ac:26: -1- AC_SUBST([target_alias])
m4trace:configure.ac:26: -1- AC_SUBST_TRACE([target_alias])
m4trace:configure.ac:26: -1- m4_pattern_allow([^target_alias$])
m4trace:configure.ac:38: -1- AC_CONFIG_HEADERS([include/clicon_config.h lib/clicon/clicon.h])
m4trace:configure.ac:40: -1- AC_DEFINE_TRACE_LITERAL([CLICON_VERSION_STRING])
m4trace:configure.ac:40: -1- m4_pattern_allow([^CLICON_VERSION_STRING$])
m4trace:configure.ac:41: -1- AC_DEFINE_TRACE_LITERAL([CLICON_VERSION_MAJOR])
m4trace:configure.ac:41: -1- m4_pattern_allow([^CLICON_VERSION_MAJOR$])
m4trace:configure.ac:42: -1- AC_DEFINE_TRACE_LITERAL([CLICON_VERSION_MINOR])
m4trace:configure.ac:42: -1- m4_pattern_allow([^CLICON_VERSION_MINOR$])
m4trace:configure.ac:43: -1- AC_DEFINE_TRACE_LITERAL([CLICON_VERSION_PATCH])
m4trace:configure.ac:43: -1- m4_pattern_allow([^CLICON_VERSION_PATCH$])
m4trace:configure.ac:46: -1- AC_SUBST([CLICON_VERSION])
m4trace:configure.ac:46: -1- AC_SUBST_TRACE([CLICON_VERSION])
m4trace:configure.ac:46: -1- m4_pattern_allow([^CLICON_VERSION$])
m4trace:configure.ac:47: -1- AC_SUBST([CLICON_VERSION_STRING])
m4trace:configure.ac:47: -1- AC_SUBST_TRACE([CLICON_VERSION_STRING])
m4trace:configure.ac:47: -1- m4_pattern_allow([^CLICON_VERSION_STRING$])
m4trace:configure.ac:48: -1- AC_SUBST([CLICON_VERSION_MAJOR])
m4trace:configure.ac:48: -1- AC_SUBST_TRACE([CLICON_VERSION_MAJOR])
m4trace:configure.ac:48: -1- m4_pattern_allow([^CLICON_VERSION_MAJOR$])
m4trace:configure.ac:49: -1- AC_SUBST([CLICON_VERSION_MINOR])
m4trace:configure.ac:49: -1- AC_SUBST_TRACE([CLICON_VERSION_MINOR])
m4trace:configure.ac:49: -1- m4_pattern_allow([^CLICON_VERSION_MINOR$])
m4trace:configure.ac:50: -1- AC_SUBST([CLIGEN_VERSION])
m4trace:configure.ac:50: -1- AC_SUBST_TRACE([CLIGEN_VERSION])
m4trace:configure.ac:50: -1- m4_pattern_allow([^CLIGEN_VERSION$])
m4trace:configure.ac:55: -1- AC_CANONICAL_TARGET
m4trace:configure.ac:55: -1- AC_CANONICAL_HOST
m4trace:configure.ac:55: -1- AC_CANONICAL_BUILD
m4trace:configure.ac:55: -1- AC_REQUIRE_AUX_FILE([config.sub])
m4trace:configure.ac:55: -1- AC_REQUIRE_AUX_FILE([config.guess])
m4trace:configure.ac:55: -1- AC_SUBST([build], [$ac_cv_build])
m4trace:configure.ac:55: -1- AC_SUBST_TRACE([build])
m4trace:configure.ac:55: -1- m4_pattern_allow([^build$])
m4trace:configure.ac:55: -1- AC_SUBST([build_cpu], [$[1]])
m4trace:configure.ac:55: -1- AC_SUBST_TRACE([build_cpu])
m4trace:configure.ac:55: -1- m4_pattern_allow([^build_cpu$])
m4trace:configure.ac:55: -1- AC_SUBST([build_vendor], [$[2]])
m4trace:configure.ac:55: -1- AC_SUBST_TRACE([build_vendor])
m4trace:configure.ac:55: -1- m4_pattern_allow([^build_vendor$])
m4trace:configure.ac:55: -1- AC_SUBST([build_os])
m4trace:configure.ac:55: -1- AC_SUBST_TRACE([build_os])
m4trace:configure.ac:55: -1- m4_pattern_allow([^build_os$])
m4trace:configure.ac:55: -1- AC_SUBST([host], [$ac_cv_host])
m4trace:configure.ac:55: -1- AC_SUBST_TRACE([host])
m4trace:configure.ac:55: -1- m4_pattern_allow([^host$])
m4trace:configure.ac:55: -1- AC_SUBST([host_cpu], [$[1]])
m4trace:configure.ac:55: -1- AC_SUBST_TRACE([host_cpu])
m4trace:configure.ac:55: -1- m4_pattern_allow([^host_cpu$])
m4trace:configure.ac:55: -1- AC_SUBST([host_vendor], [$[2]])
m4trace:configure.ac:55: -1- AC_SUBST_TRACE([host_vendor])
m4trace:configure.ac:55: -1- m4_pattern_allow([^host_vendor$])
m4trace:configure.ac:55: -1- AC_SUBST([host_os])
m4trace:configure.ac:55: -1- AC_SUBST_TRACE([host_os])
m4trace:configure.ac:55: -1- m4_pattern_allow([^host_os$])
m4trace:configure.ac:55: -1- AC_SUBST([target], [$ac_cv_target])
m4trace:configure.ac:55: -1- AC_SUBST_TRACE([target])
m4trace:configure.ac:55: -1- m4_pattern_allow([^target$])
m4trace:configure.ac:55: -1- AC_SUBST([target_cpu], [$[1]])
m4trace:configure.ac:55: -1- AC_SUBST_TRACE([target_cpu])
m4trace:configure.ac:55: -1- m4_pattern_allow([^target_cpu$])
m4trace:configure.ac:55: -1- AC_SUBST([target_vendor], [$[2]])
m4trace:configure.ac:55: -1- AC_SUBST_TRACE([target_vendor])
m4trace:configure.ac:55: -1- m4_pattern_allow([^target_vendor$])
m4trace:configure.ac:55: -1- AC_SUBST([target_os])
m4trace:configure.ac:55: -1- AC_SUBST_TRACE([target_os])
m4trace:configure.ac:55: -1- m4_pattern_allow([^target_os$])
m4trace:configure.ac:56: -1- AC_SUBST([CC])
m4trace:configure.ac:56: -1- AC_SUBST_TRACE([CC])
m4trace:configure.ac:56: -1- m4_pattern_allow([^CC$])
m4trace:configure.ac:57: -1- AC_SUBST([CFLAGS])
m4trace:configure.ac:57: -1- AC_SUBST_TRACE([CFLAGS])
m4trace:configure.ac:57: -1- m4_pattern_allow([^CFLAGS$])
m4trace:configure.ac:58: -1- AC_SUBST([LDFLAGS])
m4trace:configure.ac:58: -1- AC_SUBST_TRACE([LDFLAGS])
m4trace:configure.ac:58: -1- m4_pattern_allow([^LDFLAGS$])
m4trace:configure.ac:59: -1- AC_SUBST([INCLUDES])
m4trace:configure.ac:59: -1- AC_SUBST_TRACE([INCLUDES])
m4trace:configure.ac:59: -1- m4_pattern_allow([^INCLUDES$])
m4trace:configure.ac:60: -1- AC_SUBST([CPPFLAGS])
m4trace:configure.ac:60: -1- AC_SUBST_TRACE([CPPFLAGS])
m4trace:configure.ac:60: -1- m4_pattern_allow([^CPPFLAGS$])
m4trace:configure.ac:61: -1- AC_SUBST([LIBS])
m4trace:configure.ac:61: -1- AC_SUBST_TRACE([LIBS])
m4trace:configure.ac:61: -1- m4_pattern_allow([^LIBS$])
m4trace:configure.ac:62: -1- AC_SUBST([OBJ_SUFFIX])
m4trace:configure.ac:62: -1- AC_SUBST_TRACE([OBJ_SUFFIX])
m4trace:configure.ac:62: -1- m4_pattern_allow([^OBJ_SUFFIX$])
m4trace:configure.ac:63: -1- AC_SUBST([AR_SUFFIX])
m4trace:configure.ac:63: -1- AC_SUBST_TRACE([AR_SUFFIX])
m4trace:configure.ac:63: -1- m4_pattern_allow([^AR_SUFFIX$])
m4trace:configure.ac:64: -1- AC_SUBST([SH_SUFFIX])
m4trace:configure.ac:64: -1- AC_SUBST_TRACE([SH_SUFFIX])
m4trace:configure.ac:64: -1- m4_pattern_allow([^SH_SUFFIX$])
m4trace:configure.ac:65: -1- AC_SUBST([EXE_SUFFIX])
m4trace:configure.ac:65: -1- AC_SUBST_TRACE([EXE_SUFFIX])
m4trace:configure.ac:65: -1- m4_pattern_allow([^EXE_SUFFIX$])
m4trace:configure.ac:66: -1- AC_SUBST([AR])
m4trace:configure.ac:66: -1- AC_SUBST_TRACE([AR])
m4trace:configure.ac:66: -1- m4_pattern_allow([^AR$])
m4trace:configure.ac:67: -1- AC_SUBST([RANLIB])
m4trace:configure.ac:67: -1- AC_SUBST_TRACE([RANLIB])
m4trace:configure.ac:67: -1- m4_pattern_allow([^RANLIB$])
m4trace:configure.ac:68: -1- AC_SUBST([CLICON__LIBDIR])
m4trace:configure.ac:68: -1- AC_SUBST_TRACE([CLICON__LIBDIR])
m4trace:configure.ac:68: -1- m4_pattern_allow([^CLICON__LIBDIR$])
m4trace:configure.ac:74: -1- AC_SUBST([CC])
m4trace:configure.ac:74: -1- AC_SUBST_TRACE([CC])
m4trace:configure.ac:74: -1- m4_pattern_allow([^CC$])
m4trace:configure.ac:74: -1- AC_SUBST([CFLAGS])
m4trace:configure.ac:74: -1- AC_SUBST_TRACE([CFLAGS])
m4trace:configure.ac:74: -1- m4_pattern_allow([^CFLAGS$])
m4trace:configure.ac:74: -1- AC_SUBST([LDFLAGS])
m4trace:configure.ac:74: -1- AC_SUBST_TRACE([LDFLAGS])
m4trace:configure.ac:74: -1- m4_pattern_allow([^LDFLAGS$])
m4trace:configure.ac:74: -1- AC_SUBST([LIBS])
m4trace:configure.ac:74: -1- AC_SUBST_TRACE([LIBS])
m4trace:configure.ac:74: -1- m4_pattern_allow([^LIBS$])
m4trace:configure.ac:74: -1- AC_SUBST([CPPFLAGS])
m4trace:configure.ac:74: -1- AC_SUBST_TRACE([CPPFLAGS])
m4trace:configure.ac:74: -1- m4_pattern_allow([^CPPFLAGS$])
m4trace:configure.ac:74: -1- AC_SUBST([CC])
m4trace:configure.ac:74: -1- AC_SUBST_TRACE([CC])
m4trace:configure.ac:74: -1- m4_pattern_allow([^CC$])
m4trace:configure.ac:74: -1- AC_SUBST([CC])
m4trace:configure.ac:74: -1- AC_SUBST_TRACE([CC])
m4trace:configure.ac:74: -1- m4_pattern_allow([^CC$])
m4trace:configure.ac:74: -1- AC_SUBST([CC])
m4trace:configure.ac:74: -1- AC_SUBST_TRACE([CC])
m4trace:configure.ac:74: -1- m4_pattern_allow([^CC$])
m4trace:configure.ac:74: -1- AC_SUBST([CC])
m4trace:configure.ac:74: -1- AC_SUBST_TRACE([CC])
m4trace:configure.ac:74: -1- m4_pattern_allow([^CC$])
m4trace:configure.ac:74: -1- AC_SUBST([ac_ct_CC])
m4trace:configure.ac:74: -1- AC_SUBST_TRACE([ac_ct_CC])
m4trace:configure.ac:74: -1- m4_pattern_allow([^ac_ct_CC$])
m4trace:configure.ac:74: -1- AC_SUBST([EXEEXT], [$ac_cv_exeext])
m4trace:configure.ac:74: -1- AC_SUBST_TRACE([EXEEXT])
m4trace:configure.ac:74: -1- m4_pattern_allow([^EXEEXT$])
m4trace:configure.ac:74: -1- AC_SUBST([OBJEXT], [$ac_cv_objext])
m4trace:configure.ac:74: -1- AC_SUBST_TRACE([OBJEXT])
m4trace:configure.ac:74: -1- m4_pattern_allow([^OBJEXT$])
m4trace:configure.ac:75: -1- AC_SUBST([CPP])
m4trace:configure.ac:75: -1- AC_SUBST_TRACE([CPP])
m4trace:configure.ac:75: -1- m4_pattern_allow([^CPP$])
m4trace:configure.ac:75: -1- AC_SUBST([CPPFLAGS])
m4trace:configure.ac:75: -1- AC_SUBST_TRACE([CPPFLAGS])
m4trace:configure.ac:75: -1- m4_pattern_allow([^CPPFLAGS$])
m4trace:configure.ac:75: -1- AC_SUBST([CPP])
m4trace:configure.ac:75: -1- AC_SUBST_TRACE([CPP])
m4trace:configure.ac:75: -1- m4_pattern_allow([^CPP$])
m4trace:configure.ac:86: -1- AC_SUBST([YACC])
m4trace:configure.ac:86: -1- AC_SUBST_TRACE([YACC])
m4trace:configure.ac:86: -1- m4_pattern_allow([^YACC$])
m4trace:configure.ac:86: -1- AC_SUBST([YACC])
m4trace:configure.ac:86: -1- AC_SUBST_TRACE([YACC])
m4trace:configure.ac:86: -1- m4_pattern_allow([^YACC$])
m4trace:configure.ac:86: -1- AC_SUBST([YFLAGS])
m4trace:configure.ac:86: -1- AC_SUBST_TRACE([YFLAGS])
m4trace:configure.ac:86: -1- m4_pattern_allow([^YFLAGS$])
m4trace:configure.ac:87: -1- AC_SUBST([LEX])
m4trace:configure.ac:87: -1- AC_SUBST_TRACE([LEX])
m4trace:configure.ac:87: -1- m4_pattern_allow([^LEX$])
m4trace:configure.ac:87: -1- AC_SUBST([LEX_OUTPUT_ROOT], [$ac_cv_prog_lex_root])
m4trace:configure.ac:87: -1- AC_SUBST_TRACE([LEX_OUTPUT_ROOT])
m4trace:configure.ac:87: -1- m4_pattern_allow([^LEX_OUTPUT_ROOT$])
m4trace:configure.ac:87: -1- AC_SUBST([LEXLIB])
m4trace:configure.ac:87: -1- AC_SUBST_TRACE([LEXLIB])
m4trace:configure.ac:87: -1- m4_pattern_allow([^LEXLIB$])
m4trace:configure.ac:87: -1- AC_DEFINE_TRACE_LITERAL([YYTEXT_POINTER])
m4trace:configure.ac:87: -1- m4_pattern_allow([^YYTEXT_POINTER$])
m4trace:configure.ac:87: -1- AH_OUTPUT([YYTEXT_POINTER], [/* Define to 1 if `lex\' declares `yytext\' as a `char *\' by default, not a
`char@<:@@:>@\'. */
@%:@undef YYTEXT_POINTER])
m4trace:configure.ac:104: -1- AH_OUTPUT([HAVE_LIBM], [/* Define to 1 if you have the `m\' library (-lm). */
@%:@undef HAVE_LIBM])
m4trace:configure.ac:104: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LIBM])
m4trace:configure.ac:104: -1- m4_pattern_allow([^HAVE_LIBM$])
m4trace:configure.ac:112: -1- AH_OUTPUT([HAVE_CLIGEN_CLIGEN_H], [/* Define to 1 if you have the <cligen/cligen.h> header file. */
@%:@undef HAVE_CLIGEN_CLIGEN_H])
m4trace:configure.ac:112: -1- AC_SUBST([GREP])
m4trace:configure.ac:112: -1- AC_SUBST_TRACE([GREP])
m4trace:configure.ac:112: -1- m4_pattern_allow([^GREP$])
m4trace:configure.ac:112: -1- AC_SUBST([EGREP])
m4trace:configure.ac:112: -1- AC_SUBST_TRACE([EGREP])
m4trace:configure.ac:112: -1- m4_pattern_allow([^EGREP$])
m4trace:configure.ac:112: -1- AC_DEFINE_TRACE_LITERAL([STDC_HEADERS])
m4trace:configure.ac:112: -1- m4_pattern_allow([^STDC_HEADERS$])
m4trace:configure.ac:112: -1- AH_OUTPUT([STDC_HEADERS], [/* Define to 1 if you have the ANSI C header files. */
@%:@undef STDC_HEADERS])
m4trace:configure.ac:112: -1- AH_OUTPUT([HAVE_SYS_TYPES_H], [/* Define to 1 if you have the <sys/types.h> header file. */
@%:@undef HAVE_SYS_TYPES_H])
m4trace:configure.ac:112: -1- AH_OUTPUT([HAVE_SYS_STAT_H], [/* Define to 1 if you have the <sys/stat.h> header file. */
@%:@undef HAVE_SYS_STAT_H])
m4trace:configure.ac:112: -1- AH_OUTPUT([HAVE_STDLIB_H], [/* Define to 1 if you have the <stdlib.h> header file. */
@%:@undef HAVE_STDLIB_H])
m4trace:configure.ac:112: -1- AH_OUTPUT([HAVE_STRING_H], [/* Define to 1 if you have the <string.h> header file. */
@%:@undef HAVE_STRING_H])
m4trace:configure.ac:112: -1- AH_OUTPUT([HAVE_MEMORY_H], [/* Define to 1 if you have the <memory.h> header file. */
@%:@undef HAVE_MEMORY_H])
m4trace:configure.ac:112: -1- AH_OUTPUT([HAVE_STRINGS_H], [/* Define to 1 if you have the <strings.h> header file. */
@%:@undef HAVE_STRINGS_H])
m4trace:configure.ac:112: -1- AH_OUTPUT([HAVE_INTTYPES_H], [/* Define to 1 if you have the <inttypes.h> header file. */
@%:@undef HAVE_INTTYPES_H])
m4trace:configure.ac:112: -1- AH_OUTPUT([HAVE_STDINT_H], [/* Define to 1 if you have the <stdint.h> header file. */
@%:@undef HAVE_STDINT_H])
m4trace:configure.ac:112: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the <unistd.h> header file. */
@%:@undef HAVE_UNISTD_H])
m4trace:configure.ac:112: -1- AC_DEFINE_TRACE_LITERAL([HAVE_CLIGEN_CLIGEN_H])
m4trace:configure.ac:112: -1- m4_pattern_allow([^HAVE_CLIGEN_CLIGEN_H$])
m4trace:configure.ac:118: -1- AH_OUTPUT([HAVE_DEPOT_H], [/* Define to 1 if you have the <depot.h> header file. */
@%:@undef HAVE_DEPOT_H])
m4trace:configure.ac:118: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DEPOT_H])
m4trace:configure.ac:118: -1- m4_pattern_allow([^HAVE_DEPOT_H$])
m4trace:configure.ac:118: -1- AH_OUTPUT([HAVE_QDBM_DEPOT_H], [/* Define to 1 if you have the <qdbm/depot.h> header file. */
@%:@undef HAVE_QDBM_DEPOT_H])
m4trace:configure.ac:118: -1- AC_DEFINE_TRACE_LITERAL([HAVE_QDBM_DEPOT_H])
m4trace:configure.ac:118: -1- m4_pattern_allow([^HAVE_QDBM_DEPOT_H$])
m4trace:configure.ac:119: -1- AH_OUTPUT([HAVE_LIBQDBM], [/* Define to 1 if you have the `qdbm\' library (-lqdbm). */
@%:@undef HAVE_LIBQDBM])
m4trace:configure.ac:119: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LIBQDBM])
m4trace:configure.ac:119: -1- m4_pattern_allow([^HAVE_LIBQDBM$])
m4trace:configure.ac:121: -1- AH_OUTPUT([HAVE_LIBCRYPT], [/* Define to 1 if you have the `crypt\' library (-lcrypt). */
@%:@undef HAVE_LIBCRYPT])
m4trace:configure.ac:121: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LIBCRYPT])
m4trace:configure.ac:121: -1- m4_pattern_allow([^HAVE_LIBCRYPT$])
m4trace:configure.ac:122: -1- AH_OUTPUT([HAVE_CRYPT_H], [/* Define to 1 if you have the <crypt.h> header file. */
@%:@undef HAVE_CRYPT_H])
m4trace:configure.ac:122: -1- AC_DEFINE_TRACE_LITERAL([HAVE_CRYPT_H])
m4trace:configure.ac:122: -1- m4_pattern_allow([^HAVE_CRYPT_H$])
m4trace:configure.ac:125: -1- AH_OUTPUT([HAVE_SYS_UCRED_H], [/* Define to 1 if you have the <sys/ucred.h> header file. */
@%:@undef HAVE_SYS_UCRED_H])
m4trace:configure.ac:125: -1- AC_DEFINE_TRACE_LITERAL([HAVE_SYS_UCRED_H])
m4trace:configure.ac:125: -1- m4_pattern_allow([^HAVE_SYS_UCRED_H$])
m4trace:configure.ac:130: -1- AH_OUTPUT([HAVE_LINUX_IF_VLAN_H], [/* Define to 1 if you have the <linux/if_vlan.h> header file. */
@%:@undef HAVE_LINUX_IF_VLAN_H])
m4trace:configure.ac:130: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LINUX_IF_VLAN_H])
m4trace:configure.ac:130: -1- m4_pattern_allow([^HAVE_LINUX_IF_VLAN_H$])
m4trace:configure.ac:132: -1- AH_OUTPUT([HAVE_LIBSOCKET], [/* Define to 1 if you have the `socket\' library (-lsocket). */
@%:@undef HAVE_LIBSOCKET])
m4trace:configure.ac:132: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LIBSOCKET])
m4trace:configure.ac:132: -1- m4_pattern_allow([^HAVE_LIBSOCKET$])
m4trace:configure.ac:133: -1- AH_OUTPUT([HAVE_LIBNSL], [/* Define to 1 if you have the `nsl\' library (-lnsl). */
@%:@undef HAVE_LIBNSL])
m4trace:configure.ac:133: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LIBNSL])
m4trace:configure.ac:133: -1- m4_pattern_allow([^HAVE_LIBNSL$])
m4trace:configure.ac:134: -1- AH_OUTPUT([HAVE_LIBDL], [/* Define to 1 if you have the `dl\' library (-ldl). */
@%:@undef HAVE_LIBDL])
m4trace:configure.ac:134: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LIBDL])
m4trace:configure.ac:134: -1- m4_pattern_allow([^HAVE_LIBDL$])
m4trace:configure.ac:136: -1- AH_OUTPUT([HAVE_INET_ATON], [/* Define to 1 if you have the `inet_aton\' function. */
@%:@undef HAVE_INET_ATON])
m4trace:configure.ac:136: -1- AH_OUTPUT([HAVE_SIGACTION], [/* Define to 1 if you have the `sigaction\' function. */
@%:@undef HAVE_SIGACTION])
m4trace:configure.ac:136: -1- AH_OUTPUT([HAVE_SIGVEC], [/* Define to 1 if you have the `sigvec\' function. */
@%:@undef HAVE_SIGVEC])
m4trace:configure.ac:136: -1- AH_OUTPUT([HAVE_STRLCPY], [/* Define to 1 if you have the `strlcpy\' function. */
@%:@undef HAVE_STRLCPY])
m4trace:configure.ac:136: -1- AH_OUTPUT([HAVE_STRSEP], [/* Define to 1 if you have the `strsep\' function. */
@%:@undef HAVE_STRSEP])
m4trace:configure.ac:136: -1- AH_OUTPUT([HAVE_STRNDUP], [/* Define to 1 if you have the `strndup\' function. */
@%:@undef HAVE_STRNDUP])
m4trace:configure.ac:136: -1- AH_OUTPUT([HAVE_ALPHASORT], [/* Define to 1 if you have the `alphasort\' function. */
@%:@undef HAVE_ALPHASORT])
m4trace:configure.ac:136: -1- AH_OUTPUT([HAVE_VERSIONSORT], [/* Define to 1 if you have the `versionsort\' function. */
@%:@undef HAVE_VERSIONSORT])
m4trace:configure.ac:136: -1- AH_OUTPUT([HAVE_STRVERSCMP], [/* Define to 1 if you have the `strverscmp\' function. */
@%:@undef HAVE_STRVERSCMP])
m4trace:configure.ac:149: -1- AH_OUTPUT([DB_KEYCONTENT], [/* Check if extra keys inserted for database lists containing content. Eg
A.n.foo = 3 means A.3 @S|@!a=foo exists */
@%:@undef DB_KEYCONTENT])
m4trace:configure.ac:153: -1- AC_DEFINE_TRACE_LITERAL([DB_KEYCONTENT])
m4trace:configure.ac:153: -1- m4_pattern_allow([^DB_KEYCONTENT$])
m4trace:configure.ac:156: -1- AH_OUTPUT([zzzz1], [#include <clicon_custom.h>])
m4trace:configure.ac:158: -1- AC_CONFIG_FILES([Makefile
lib/Makefile
lib/src/Makefile
lib/clicon/Makefile
apps/Makefile
apps/cli/Makefile
apps/backend/Makefile
apps/netconf/Makefile
apps/dbctrl/Makefile
include/Makefile
etc/Makefile
etc/cliconrc
example/Makefile
doc/Makefile
])
m4trace:configure.ac:158: -1- _m4_warn([obsolete], [AC_OUTPUT should be used without arguments.
You should run autoupdate.], [])
m4trace:configure.ac:158: -1- AC_SUBST([LIB@&t@OBJS], [$ac_libobjs])
m4trace:configure.ac:158: -1- AC_SUBST_TRACE([LIB@&t@OBJS])
m4trace:configure.ac:158: -1- m4_pattern_allow([^LIB@&t@OBJS$])
m4trace:configure.ac:158: -1- AC_SUBST([LTLIBOBJS], [$ac_ltlibobjs])
m4trace:configure.ac:158: -1- AC_SUBST_TRACE([LTLIBOBJS])
m4trace:configure.ac:158: -1- m4_pattern_allow([^LTLIBOBJS$])
m4trace:configure.ac:158: -1- AC_SUBST_TRACE([top_builddir])
m4trace:configure.ac:158: -1- AC_SUBST_TRACE([top_build_prefix])
m4trace:configure.ac:158: -1- AC_SUBST_TRACE([srcdir])
m4trace:configure.ac:158: -1- AC_SUBST_TRACE([abs_srcdir])
m4trace:configure.ac:158: -1- AC_SUBST_TRACE([top_srcdir])
m4trace:configure.ac:158: -1- AC_SUBST_TRACE([abs_top_srcdir])
m4trace:configure.ac:158: -1- AC_SUBST_TRACE([builddir])
m4trace:configure.ac:158: -1- AC_SUBST_TRACE([abs_builddir])
m4trace:configure.ac:158: -1- AC_SUBST_TRACE([abs_top_builddir])

124
clicon.conf.cpp.cpp Normal file
View file

@ -0,0 +1,124 @@
# Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
#
# This file is part of CLICON.
#
# CLICON is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# CLICON is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with CLICON; see the file COPYING. If not, see
# <http://www.gnu.org/licenses/>.
#
# CLICON options - Default values
# The origin of this file is run a _first_ time through a pre-processor at
# clicon make install time causing autoconf constants (such as "prefix" and
# "localstatedir") to be replaced with their installed values.
# It should be run a _second_ time as a part of installation of the application,
# in case clicon.mk is included in the application include file, and
# "$(APPNAME).conf" rule is accessed.
#
# See clicon_tutorial for more documentation
# Location of configuration-file for default values (this file)
CLICON_CONFIGFILE sysconfdir/APPNAME.conf
# Database (yang) specification file.
CLICON_DBSPEC_FILE prefix/share/APPNAME/datamodel.spec
# Location of YANG module and submodule files. Only if CLICON_DBSPEC_TYPE is YANG
CLICON_YANG_DIR prefix/share/APPNAME/yang
# Option used to construct initial yang file:
# <module>[@<revision>]
# This option is only relevant if CLICON_DBSPEC_TYPE is YANG
# CLICON_YANG_MODULE_MAIN clicon
# Option used to construct initial yang file:
# <module>[@<revision>]
# This option is only relevant if CLICON_DBSPEC_TYPE is YANG
CLICON_YANG_MODULE_REVISION
# Candidate qdbm database
CLICON_CANDIDATE_DB localstatedir/APPNAME/candidate_db
# Running qdbm database
CLICON_RUNNING_DB localstatedir/APPNAME/running_db
# Location of backend .so plugins
CLICON_BACKEND_DIR libdir/APPNAME/backend
# Location of netconf (frontend) .so plugins
CLICON_NETCONF_DIR libdir/APPNAME/netconf
# Location of cli frontend .so plugins
CLICON_CLI_DIR libdir/APPNAME/cli
# Location of frontend .cli cligen spec files
CLICON_CLISPEC_DIR libdir/APPNAME/clispec
# Directory where to save configuration commit history (in XML). Snapshots
# are saved chronologically
CLICON_ARCHIVE_DIR localstatedir/APPNAME/archive
# XXX Name of startup configuration file (in XML)
CLICON_STARTUP_CONFIG localstatedir/APPNAME/startup-config
# Address family for communicating with clicon_backend (UNIX|IPv4|IPv6)
CLICON_SOCK_FAMILY UNIX
# If family above is AF_UNIX: Unix socket for communicating with clicon_backend
# If family above is AF_INET: IPv4 address
CLICON_SOCK localstatedir/APPNAME/APPNAME.sock
# Inet socket port for communicating with clicon_backend (only IPv4|IPv6)
CLICON_SOCK_PORT 4535
# Process-id file
CLICON_BACKEND_PIDFILE localstatedir/APPNAME/APPNAME.pidfile
# Group membership to access clicon_config unix socket
# CLICON_SOCK_GROUP clicon
# Set if all configuration changes are committed directly, commit command unnecessary
# CLICON_AUTOCOMMIT 0
# Clicon backend callback order. There are two dimensions: operation (del/add/change)
# and priority
# 0: all callbacks in (rising) priority order
# 1: first delete operations in declining prio order; then add/change in prio order
# 2: like (1) but CHANGE is replaced by (DEL;ADD)
# XXX OBSOLETE?
# CLICON_COMMIT_ORDER 0
# Name of master plugin (both frontend and backend). Master plugin has special
# callbacks for frontends. See clicon user manual for more info.
# CLICON_MASTER_PLUGIN master
# Startup CLI mode. This should match the CLICON_MODE in your startup clispec file
# CLICON_CLI_MODE base
# Generate code for CLI completion of existing db symbols. Add name="myspec" in
# datamodel spec and reference as @myspec.
# CLICON_CLI_GENMODEL 1
# Generate code for CLI completion of existing db symbols
# CLICON_CLI_GENMODEL_COMPLETION 0
# How to generate and show CLI syntax: VARS|ALL
# CLICON_CLI_GENMODEL_TYPE VARS
# Comment character in CLI
# CLICON_CLI_COMMENT #
# Dont include keys in cvec in cli vars callbacks, ie a & k in 'a <b> k <c>' ignored
# CLICON_CLI_VARONLY 1

44
clicon.mk.cpp Normal file
View file

@ -0,0 +1,44 @@
# Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
#
# This file is part of CLICON.
#
# CLICON is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# CLICON is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with CLICON; see the file COPYING. If not, see
# <http://www.gnu.org/licenses/>.
#
# Include this file in your application Makefile using eg:
# -include $(datarootdir)/clicon/clicon.mk
# then you can use the DIRS below in your install rules.
# You also get rules for the application configure file.
# NOTE: APPNAME must be defined in the local Makefile
clicon_DBSPECDIR=prefix/share/$(APPNAME)
clicon_SYSCONFDIR=sysconfdir
clicon_LOCALSTATEDIR=localstatedir/$(APPNAME)
clicon_LIBDIR=libdir/$(APPNAME)
clicon_DATADIR=datadir/clicon
# Rules for the clicon application configuration file.
# The clicon applications should be started with this fileas its -f argument.
# Typically installed in sysconfdir
# Example: APPNAME=myapp --> clicon_cli -f /usr/local/etc/myapp.conf
# The two variants are if there is a .conf.local file or not
.PHONY: $(APPNAME).conf
ifneq (,$(wildcard ${APPNAME}.conf.local))
${APPNAME}.conf: ${clicon_DATADIR}/clicon.conf.cpp ${APPNAME}.conf.local
$(CPP) -P -x assembler-with-cpp -DAPPNAME=$(APPNAME) $< > $@
cat ${APPNAME}.conf.local >> $@
else
${APPNAME}.conf: ${clicon_DATADIR}/clicon.conf.cpp
$(CPP) -P -x assembler-with-cpp -DAPPNAME=$(APPNAME) $< > $@
endif

1550
config.guess vendored Normal file

File diff suppressed because it is too large Load diff

1786
config.sub vendored Normal file

File diff suppressed because it is too large Load diff

5482
configure vendored Executable file

File diff suppressed because it is too large Load diff

173
configure.ac Normal file
View file

@ -0,0 +1,173 @@
# To rebuild the `configure' script from this, execute the command
# autoconf
# in the directory containing this script.
#
#
# Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
#
# This file is part of CLICON.
#
# CLICON is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# CLICON is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with CLICON; see the file COPYING. If not, see
# <http://www.gnu.org/licenses/>.
#
#
AC_INIT(lib/clicon/clicon.h.in)
# Default CFLAGS unless set by environment.
: ${CFLAGS="-O2"}
CLICON_VERSION_MAJOR="3"
CLICON_VERSION_MINOR="2"
CLICON_VERSION_PATCH="0"
CLICON_VERSION="\"${CLICON_VERSION_MAJOR}.${CLICON_VERSION_MINOR}.${CLICON_VERSION_PATCH}\""
# Fix to specific version (eg 3.5) or head (3)
CLIGEN_VERSION="3.5"
AC_CONFIG_HEADERS([include/clicon_config.h lib/clicon/clicon.h])
AC_DEFINE_UNQUOTED(CLICON_VERSION_STRING, $CLICON_VERSION)
AC_DEFINE_UNQUOTED(CLICON_VERSION_MAJOR, $CLICON_VERSION_MAJOR)
AC_DEFINE_UNQUOTED(CLICON_VERSION_MINOR, $CLICON_VERSION_MINOR)
AC_DEFINE_UNQUOTED(CLICON_VERSION_PATCH, $CLICON_VERSION_PATCH)
# clicon versions spread to Makefile's (.so files) and variable in build.c
AC_SUBST(CLICON_VERSION)
AC_SUBST(CLICON_VERSION_STRING)
AC_SUBST(CLICON_VERSION_MAJOR)
AC_SUBST(CLICON_VERSION_MINOR)
AC_SUBST(CLIGEN_VERSION) # Bind to specific CLIgen version
AC_MSG_RESULT(CLICON version is ${CLICON_VERSION}_PRE1)
AC_CANONICAL_TARGET
AC_SUBST(CC)
AC_SUBST(CFLAGS)
AC_SUBST(LDFLAGS)
AC_SUBST(INCLUDES)
AC_SUBST(CPPFLAGS)
AC_SUBST(LIBS)
AC_SUBST(OBJ_SUFFIX)
AC_SUBST(AR_SUFFIX)
AC_SUBST(SH_SUFFIX)
AC_SUBST(EXE_SUFFIX)
AC_SUBST(AR)
AC_SUBST(RANLIB)
AC_SUBST(CLICON__LIBDIR) # Clicon application director. Eg /hello.
# Some stuff installed in /usr/local/. Such as qdbm
LIBS="-L /usr/local/lib"
#
AC_PROG_CC()
AC_PROG_CPP
CPPFLAGS="-DHAVE_CONFIG_H ${CPPFLAGS}"
AC_MSG_RESULT(compiler is $CC)
CFLAGS="${CFLAGS} -Wall"
AC_MSG_RESULT(CPPFLAGS is $CPPFLAGS)
AC_MSG_RESULT(CFLAGS is $CFLAGS)
AC_PROG_YACC
AC_PROG_LEX
if test "$LEX" = ":"; then
AC_MSG_ERROR(CLICON does not find lex or flex.)
fi
if test "$YACC" != "bison -y"; then
AC_MSG_ERROR(CLICON does not find bison. There are several problems with yacc and byacc. Please install bison.)
fi
if test "$prefix" = "NONE"; then
CPPFLAGS="-I${ac_default_prefix}/include ${CPPFLAGS}"
LDFLAGS="-L${ac_default_prefix}/lib ${LDFLAGS}"
else
CPPFLAGS="-I${prefix}/include ${CPPFLAGS}"
LDFLAGS="-L${prefix}/lib ${LDFLAGS}"
fi
LDFLAGS=""
AC_CHECK_LIB(m, main)
EXE_SUFFIX=""
OBJ_SUFFIX=".o"
AR_SUFFIX=".a"
SH_SUFFIX=".so"
AR="ar"
# This is for cligen
AC_CHECK_HEADERS(cligen/cligen.h,, AC_MSG_ERROR(cligen missing. Try: git clone https://github.com/olofhagsand/cligen.git))
AC_CHECK_LIB(:libcligen.so.${CLIGEN_VERSION}, cligen_init,, AC_MSG_ERROR([CLIgen${CLIGEN_VERSION} missing. Try: git clone https://github.com/olofhagsand/cligen.git]))
# This is for qdbm.
# Problem: depot.h may be in qdbm/depot.h.
AC_CHECK_HEADERS(depot.h,,[AC_CHECK_HEADERS(qdbm/depot.h,,AC_MSG_ERROR(libqdbm-dev required))])
AC_CHECK_LIB(qdbm, dpopen,, AC_MSG_ERROR(libqdbm-dev required))
AC_CHECK_LIB(crypt, crypt)
AC_CHECK_HEADERS(crypt.h)
# user credentials for unix sockets
AC_CHECK_HEADERS([sys/ucred.h],[],[],
[[# include <sys/param.h>]]
)
# This is for Linux vlan code
AC_CHECK_HEADERS(linux/if_vlan.h)
AC_CHECK_LIB(socket, socket)
AC_CHECK_LIB(nsl, xdr_char)
AC_CHECK_LIB(dl, dlopen)
AC_CHECK_FUNCS(inet_aton sigaction sigvec strlcpy strsep strndup alphasort versionsort strverscmp)
# Check if extra keys inserted for database lists containing content. Eg A.n.foo = 3
# means A.3 $!a=foo exists
AC_ARG_ENABLE(keycontent, [ --disable-keycontent Disable reverse lookup content keys],[
if test "$enableval" = no; then
ac_enable_keycontent=no
else
ac_enable_keycontent=yes
fi
],[ ac_enable_keycontent=yes])
AH_TEMPLATE([DB_KEYCONTENT],
[ Check if extra keys inserted for database lists containing content.
Eg A.n.foo = 3 means A.3 $!a=foo exists])
if test "$ac_enable_keycontent" = "yes"; then
AC_DEFINE(DB_KEYCONTENT)
fi
AH_BOTTOM([#include <clicon_custom.h>])
AC_OUTPUT(Makefile
lib/Makefile
lib/src/Makefile
lib/clicon/Makefile
apps/Makefile
apps/cli/Makefile
apps/backend/Makefile
apps/netconf/Makefile
apps/dbctrl/Makefile
include/Makefile
etc/Makefile
etc/cliconrc
example/Makefile
doc/Makefile
)

2303
doc/Doxyfile Normal file

File diff suppressed because it is too large Load diff

2303
doc/Doxyfile.graphs Normal file

File diff suppressed because it is too large Load diff

69
doc/Makefile.in Normal file
View file

@ -0,0 +1,69 @@
#
# CVS Version: $Id: Makefile.in,v 1.23 2013/09/11 18:35:14 olof Exp $
#
#
# This file is part of CLICON.
#
# CLICON is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# CLICON is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with CLICON; see the file COPYING. If not, see
# <http://www.gnu.org/licenses/>.
#
#
# This makefile contains conditionals that dont work with bsd make
prefix = @prefix@
datarootdir = @datarootdir@
docdir = @docdir@
pdflatex = @PDFLATEX@
SUBDIRS =
.PHONY: clean all $(SUBDIRS)
all: $(SUBDIRS)
echo "Build doxygen docs: make doc"
echo "Build doxygen doc and graphs: make graphs"
# Regular doxygen documentation
doc:
doxygen Doxyfile # generates html dir
echo "Build doxygen graphs: make graphs"
# doxygen documentation with callgraphs
graphs:
doxygen Doxyfile.graphs # generates html dir + call graphs (takes time)
$(SUBDIRS):
(cd $@; $(MAKE) $(MFLAGS) all)
distclean: clean
rm -rf html
rm -f Makefile *~ .depend
for i in $(SUBDIRS); \
do (cd $$i; $(MAKE) $(MFLAGS) $@); done
clean:
for i in $(SUBDIRS); \
do (cd $$i; $(MAKE) $(MFLAGS) $@); done;
install:
for i in $(SUBDIRS); \
do (cd $$i; $(MAKE) $(MFLAGS) $@); done;
install-include:
uninstall:
for i in $(SUBDIRS); \
do (cd $$i; $(MAKE) $(MFLAGS) $@); done;

49
etc/Makefile.in Normal file
View file

@ -0,0 +1,49 @@
#
# Makefile
#
# Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
#
# This file is part of CLICON.
#
# CLICON is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# CLICON is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with CLICON; see the file COPYING. If not, see
# <http://www.gnu.org/licenses/>.
#
#
VPATH = @srcdir@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
prefix = @prefix@
bindir = @bindir@
localstatedir = @localstatedir@
sysconfdir = @sysconfdir@
INSTALL = @INSTALL@
all:
@echo " "
clean:
distclean: clean
rm -f Makefile *~ .depend cliconrc
install: cliconrc
install -m 755 -d $(DESTDIR)$(sysconfdir)
install -m 755 cliconrc $(DESTDIR)$(sysconfdir)
install-include:
uninstall:
depend:

14
etc/README Normal file
View file

@ -0,0 +1,14 @@
This directory contains etc files. cliconrc is a script file that can be used to
setup a shell environment if clicon is installed in a non-standard place.
It sets up path and dynamic library links.
Example:
> tar xzf clicon.tgz
> cd clicon
> ./configure --prefix=/hello
> make
> make install
> make install-include
> cd
> source /hello/etc/cliconrc
> clicon_config
> clicon_cli

13
etc/cliconrc.in Normal file
View file

@ -0,0 +1,13 @@
# local variables may be needed below
prefix=@prefix@
exec_prefix=@exec_prefix@
# Path to binaries
export PATH=$PATH:@bindir@
# Path to config daemon
export PATH=$PATH:@sbindir@
# Path to dynamic libraries
export LD_LIBRARY_PATH=@libdir@:$LD_LIBRARY_PATH

114
example/Makefile.in Normal file
View file

@ -0,0 +1,114 @@
#
# Makefile
#
# Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
#
# This file is part of CLICON.
#
# CLICON is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# CLICON is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with CLICON; see the file COPYING. If not, see
# <http://www.gnu.org/licenses/>.
#
#
VPATH = @srcdir@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
prefix = @prefix@
bindir = @bindir@
includedir = @includedir@
datarootdir = @datarootdir@
APPNAME = routing
CC = @CC@
CFLAGS = @CFLAGS@ -rdynamic -fPIC
INCLUDES = -I$(includedir) @INCLUDES@
BE_PLUGIN = $(APPNAME)_backend.so
CLI_PLUGIN = $(APPNAME)_cli.so
NETCONF_PLUGIN = $(APPNAME)_netconf.so
PLUGINS = $(BE_PLUGIN) $(CLI_PLUGIN) $(NETCONF_PLUGIN)
all: $(PLUGINS) $(APPNAME).conf
# Note: clicon.mk has a rule for:
# $(APPNAME.conf)
-include $(DESTDIR)$(datarootdir)/clicon/clicon.mk
CLISPECS = routing_cli.cli
YANGSPECS = $(APPNAME).yang
YANGSPECS += ietf-yang-types@2013-07-15.yang
YANGSPECS += ietf-inet-types@2013-07-15.yang
YANGSPECS += ietf-interfaces@2014-05-08.yang
YANGSPECS += ietf-ip@2014-06-16.yang
YANGSPECS += ietf-routing@2014-10-26.yang
YANGSPECS += ietf-ipv4-unicast-routing@2014-10-26.yang
YANGSPECS += ietf-ipv6-unicast-routing@2014-10-26.yang
# Backend plugin
BE_SRC = routing_backend.c
BE_OBJ = $(BE_SRC:%.c=%.o)
$(BE_PLUGIN): $(BE_OBJ)
$(CC) -shared -o $@ -lc $<
# CLI frontend plugin
CLI_SRC = routing_cli.c
CLI_OBJ = $(CLI_SRC:%.c=%.o)
$(CLI_PLUGIN): $(CLI_OBJ)
$(CC) -shared -o $@ -lc $^
# NETCONF frontend plugin
NETCONF_SRC = routing_netconf.c
NETCONF_OBJ = $(NETCONF_SRC:%.c=%.o)
$(NETCONF_PLUGIN): $(NETCONF_OBJ)
$(CC) -shared -o $@ -lc $^
SRC = $(BE_SRC) $(CLI_SRC) $(NETCONF_SRC)
OBJS = $(BE_OBJ) $(CLI_OBJ) $(NETCONF_OBJ)
clean:
rm -f $(PLUGINS) $(OBJS) $(APPNAME).conf
distclean: clean
rm -f Makefile *~ .depend
install: $(YANGSPECS) $(CLISPECS) $(BE_PLUGIN) $(CLI_PLUGIN) $(NETCONF_PLUGIN) $(APPNAME).conf
install -d $(DESTDIR)$(clicon_SYSCONFDIR)
install $(APPNAME).conf $(DESTDIR)$(clicon_SYSCONFDIR)
install -d $(DESTDIR)$(clicon_DBSPECDIR)/yang
install $(YANGSPECS) $(DESTDIR)$(clicon_DBSPECDIR)/yang
install -d $(DESTDIR)$(clicon_LIBDIR)/cli
install $(CLI_PLUGIN) $(DESTDIR)$(clicon_LIBDIR)/cli;
install -d $(DESTDIR)$(clicon_LIBDIR)/backend
install $(BE_PLUGIN) $(DESTDIR)$(clicon_LIBDIR)/backend;
install -d $(DESTDIR)$(clicon_LIBDIR)/netconf
install $(NETCONF_PLUGIN) $(DESTDIR)$(clicon_LIBDIR)/netconf;
install -d $(DESTDIR)$(clicon_LIBDIR)/clispec
install $(CLISPECS) $(DESTDIR)$(clicon_LIBDIR)/clispec;
install -d $(DESTDIR)$(clicon_LOCALSTATEDIR)
uninstall:
rm -rf $(DESTDIR)$(clicon_SYSCONFDIR)/$(APPNAME).conf
rm -rf $(DESTDIR)$(clicon_DBSPECDIR)
rm -rf $(DESTDIR)$(clicon_LOCALSTATEDIR)
rm -rf $(DESTDIR)$(clicon_LIBDIR)
install-include:
depend:
$(CC) $(DEPENDFLAGS) $(INCLUDES) $(CFLAGS) -MM $(SRC) > .depend
#include .depend

27
example/README Normal file
View file

@ -0,0 +1,27 @@
Examples using netconf
<rpc><edit-config><target><candidate/></target><config>
<interfaces>
<interface>
<name>eth1</name>
<enabled>true</enabled>
<ipv4>
<address>
<ip>9.2.3.4</ip>
<prefix-length>24</prefix-length>
</address>
</ipv4>
</interface>
</interfaces>
</config></edit-config></rpc>]]>]]>
* no filter + no config
<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>
* filter subnet + no config:
<rpc><get-config><source><candidate/></source><filter/></get-config></rpc>]]>]]>
* filter xpath + no select:
<rpc><get-config><source><candidate/></source><filter type="xpath"/></get-config></rpc>]]>]]>
* filter subnet + config:
<rpc><get-config><source><candidate/></source><filter type="subtree"><configuration><interfaces><interface><ipv4/></interface></interfaces></configuration></filter></get-config></rpc>]]>]]>
* filter xpath + select:
<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface/ipv4"/></get-config></rpc>]]>]]>

View file

@ -0,0 +1,457 @@
module ietf-inet-types {
namespace "urn:ietf:params:xml:ns:yang:ietf-inet-types";
prefix "inet";
organization
"IETF NETMOD (NETCONF Data Modeling Language) Working Group";
contact
"WG Web: <http://tools.ietf.org/wg/netmod/>
WG List: <mailto:netmod@ietf.org>
WG Chair: David Kessens
<mailto:david.kessens@nsn.com>
WG Chair: Juergen Schoenwaelder
<mailto:j.schoenwaelder@jacobs-university.de>
Editor: Juergen Schoenwaelder
<mailto:j.schoenwaelder@jacobs-university.de>";
description
"This module contains a collection of generally useful derived
YANG data types for Internet addresses and related things.
Copyright (c) 2013 IETF Trust and the persons identified as
authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject
to the license terms contained in, the Simplified BSD License
set forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(http://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC 6991; see
the RFC itself for full legal notices.";
revision 2013-07-15 {
description
"This revision adds the following new data types:
- ip-address-no-zone
- ipv4-address-no-zone
- ipv6-address-no-zone";
reference
"RFC 6991: Common YANG Data Types";
}
revision 2010-09-24 {
description
"Initial revision.";
reference
"RFC 6021: Common YANG Data Types";
}
/*** collection of types related to protocol fields ***/
typedef ip-version {
type enumeration {
enum unknown {
value "0";
description
"An unknown or unspecified version of the Internet
protocol.";
}
enum ipv4 {
value "1";
description
"The IPv4 protocol as defined in RFC 791.";
}
enum ipv6 {
value "2";
description
"The IPv6 protocol as defined in RFC 2460.";
}
}
description
"This value represents the version of the IP protocol.
In the value set and its semantics, this type is equivalent
to the InetVersion textual convention of the SMIv2.";
reference
"RFC 791: Internet Protocol
RFC 2460: Internet Protocol, Version 6 (IPv6) Specification
RFC 4001: Textual Conventions for Internet Network Addresses";
}
typedef dscp {
type uint8 {
range "0..63";
}
description
"The dscp type represents a Differentiated Services Code Point
that may be used for marking packets in a traffic stream.
In the value set and its semantics, this type is equivalent
to the Dscp textual convention of the SMIv2.";
reference
"RFC 3289: Management Information Base for the Differentiated
Services Architecture
RFC 2474: Definition of the Differentiated Services Field
(DS Field) in the IPv4 and IPv6 Headers
RFC 2780: IANA Allocation Guidelines For Values In
the Internet Protocol and Related Headers";
}
typedef ipv6-flow-label {
type uint32 {
range "0..1048575";
}
description
"The ipv6-flow-label type represents the flow identifier or Flow
Label in an IPv6 packet header that may be used to
discriminate traffic flows.
In the value set and its semantics, this type is equivalent
to the IPv6FlowLabel textual convention of the SMIv2.";
reference
"RFC 3595: Textual Conventions for IPv6 Flow Label
RFC 2460: Internet Protocol, Version 6 (IPv6) Specification";
}
typedef port-number {
type uint16 {
range "0..65535";
}
description
"The port-number type represents a 16-bit port number of an
Internet transport-layer protocol such as UDP, TCP, DCCP, or
SCTP. Port numbers are assigned by IANA. A current list of
all assignments is available from <http://www.iana.org/>.
Note that the port number value zero is reserved by IANA. In
situations where the value zero does not make sense, it can
be excluded by subtyping the port-number type.
In the value set and its semantics, this type is equivalent
to the InetPortNumber textual convention of the SMIv2.";
reference
"RFC 768: User Datagram Protocol
RFC 793: Transmission Control Protocol
RFC 4960: Stream Control Transmission Protocol
RFC 4340: Datagram Congestion Control Protocol (DCCP)
RFC 4001: Textual Conventions for Internet Network Addresses";
}
/*** collection of types related to autonomous systems ***/
typedef as-number {
type uint32;
description
"The as-number type represents autonomous system numbers
which identify an Autonomous System (AS). An AS is a set
of routers under a single technical administration, using
an interior gateway protocol and common metrics to route
packets within the AS, and using an exterior gateway
protocol to route packets to other ASes. IANA maintains
the AS number space and has delegated large parts to the
regional registries.
Autonomous system numbers were originally limited to 16
bits. BGP extensions have enlarged the autonomous system
number space to 32 bits. This type therefore uses an uint32
base type without a range restriction in order to support
a larger autonomous system number space.
In the value set and its semantics, this type is equivalent
to the InetAutonomousSystemNumber textual convention of
the SMIv2.";
reference
"RFC 1930: Guidelines for creation, selection, and registration
of an Autonomous System (AS)
RFC 4271: A Border Gateway Protocol 4 (BGP-4)
RFC 4001: Textual Conventions for Internet Network Addresses
RFC 6793: BGP Support for Four-Octet Autonomous System (AS)
Number Space";
}
/*** collection of types related to IP addresses and hostnames ***/
typedef ip-address {
type union {
type inet:ipv4-address;
type inet:ipv6-address;
}
description
"The ip-address type represents an IP address and is IP
version neutral. The format of the textual representation
implies the IP version. This type supports scoped addresses
by allowing zone identifiers in the address format.";
reference
"RFC 4007: IPv6 Scoped Address Architecture";
}
typedef ipv4-address {
type string {
pattern
'(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+ '(%[\p{N}\p{L}]+)?';
}
description
"The ipv4-address type represents an IPv4 address in
dotted-quad notation. The IPv4 address may include a zone
index, separated by a % sign.
The zone index is used to disambiguate identical address
values. For link-local addresses, the zone index will
typically be the interface index number or the name of an
interface. If the zone index is not present, the default
zone of the device will be used.
The canonical format for the zone index is the numerical
format";
}
typedef ipv6-address {
type string {
pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+ '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+ '(%[\p{N}\p{L}]+)?';
pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+ '(%.+)?';
}
description
"The ipv6-address type represents an IPv6 address in full,
mixed, shortened, and shortened-mixed notation. The IPv6
address may include a zone index, separated by a % sign.
The zone index is used to disambiguate identical address
values. For link-local addresses, the zone index will
typically be the interface index number or the name of an
interface. If the zone index is not present, the default
zone of the device will be used.
The canonical format of IPv6 addresses uses the textual
representation defined in Section 4 of RFC 5952. The
canonical format for the zone index is the numerical
format as described in Section 11.2 of RFC 4007.";
reference
"RFC 4291: IP Version 6 Addressing Architecture
RFC 4007: IPv6 Scoped Address Architecture
RFC 5952: A Recommendation for IPv6 Address Text
Representation";
}
typedef ip-address-no-zone {
type union {
type inet:ipv4-address-no-zone;
type inet:ipv6-address-no-zone;
}
description
"The ip-address-no-zone type represents an IP address and is
IP version neutral. The format of the textual representation
implies the IP version. This type does not support scoped
addresses since it does not allow zone identifiers in the
address format.";
reference
"RFC 4007: IPv6 Scoped Address Architecture";
}
typedef ipv4-address-no-zone {
type inet:ipv4-address {
pattern '[0-9\.]*';
}
description
"An IPv4 address without a zone index. This type, derived from
ipv4-address, may be used in situations where the zone is
known from the context and hence no zone index is needed.";
}
typedef ipv6-address-no-zone {
type inet:ipv6-address {
pattern '[0-9a-fA-F:\.]*';
}
description
"An IPv6 address without a zone index. This type, derived from
ipv6-address, may be used in situations where the zone is
known from the context and hence no zone index is needed.";
reference
"RFC 4291: IP Version 6 Addressing Architecture
RFC 4007: IPv6 Scoped Address Architecture
RFC 5952: A Recommendation for IPv6 Address Text
Representation";
}
typedef ip-prefix {
type union {
type inet:ipv4-prefix;
type inet:ipv6-prefix;
}
description
"The ip-prefix type represents an IP prefix and is IP
version neutral. The format of the textual representations
implies the IP version.";
}
typedef ipv4-prefix {
type string {
pattern
'(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+ '/(([0-9])|([1-2][0-9])|(3[0-2]))';
}
description
"The ipv4-prefix type represents an IPv4 address prefix.
The prefix length is given by the number following the
slash character and must be less than or equal to 32.
A prefix length value of n corresponds to an IP address
mask that has n contiguous 1-bits from the most
significant bit (MSB) and all other bits set to 0.
The canonical format of an IPv4 prefix has all bits of
the IPv4 address set to zero that are not part of the
IPv4 prefix.";
}
typedef ipv6-prefix {
type string {
pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+ '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+ '(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8])))';
pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+ '(/.+)';
}
description
"The ipv6-prefix type represents an IPv6 address prefix.
The prefix length is given by the number following the
slash character and must be less than or equal to 128.
A prefix length value of n corresponds to an IP address
mask that has n contiguous 1-bits from the most
significant bit (MSB) and all other bits set to 0.
The IPv6 address should have all bits that do not belong
to the prefix set to zero.
The canonical format of an IPv6 prefix has all bits of
the IPv6 address set to zero that are not part of the
IPv6 prefix. Furthermore, the IPv6 address is represented
as defined in Section 4 of RFC 5952.";
reference
"RFC 5952: A Recommendation for IPv6 Address Text
Representation";
}
/*** collection of domain name and URI types ***/
typedef domain-name {
type string {
pattern
'((([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.)*'
+ '([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.?)'
+ '|\.';
length "1..253";
}
description
"The domain-name type represents a DNS domain name. The
name SHOULD be fully qualified whenever possible.
Internet domain names are only loosely specified. Section
3.5 of RFC 1034 recommends a syntax (modified in Section
2.1 of RFC 1123). The pattern above is intended to allow
for current practice in domain name use, and some possible
future expansion. It is designed to hold various types of
domain names, including names used for A or AAAA records
(host names) and other records, such as SRV records. Note
that Internet host names have a stricter syntax (described
in RFC 952) than the DNS recommendations in RFCs 1034 and
1123, and that systems that want to store host names in
schema nodes using the domain-name type are recommended to
adhere to this stricter standard to ensure interoperability.
The encoding of DNS names in the DNS protocol is limited
to 255 characters. Since the encoding consists of labels
prefixed by a length bytes and there is a trailing NULL
byte, only 253 characters can appear in the textual dotted
notation.
The description clause of schema nodes using the domain-name
type MUST describe when and how these names are resolved to
IP addresses. Note that the resolution of a domain-name value
may require to query multiple DNS records (e.g., A for IPv4
and AAAA for IPv6). The order of the resolution process and
which DNS record takes precedence can either be defined
explicitly or may depend on the configuration of the
resolver.
Domain-name values use the US-ASCII encoding. Their canonical
format uses lowercase US-ASCII characters. Internationalized
domain names MUST be A-labels as per RFC 5890.";
reference
"RFC 952: DoD Internet Host Table Specification
RFC 1034: Domain Names - Concepts and Facilities
RFC 1123: Requirements for Internet Hosts -- Application
and Support
RFC 2782: A DNS RR for specifying the location of services
(DNS SRV)
RFC 5890: Internationalized Domain Names in Applications
(IDNA): Definitions and Document Framework";
}
typedef host {
type union {
type inet:ip-address;
type inet:domain-name;
}
description
"The host type represents either an IP address or a DNS
domain name.";
}
typedef uri {
type string;
description
"The uri type represents a Uniform Resource Identifier
(URI) as defined by STD 66.
Objects using the uri type MUST be in US-ASCII encoding,
and MUST be normalized as described by RFC 3986 Sections
6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary
percent-encoding is removed, and all case-insensitive
characters are set to lowercase except for hexadecimal
digits, which are normalized to uppercase as described in
Section 6.2.2.1.
The purpose of this normalization is to help provide
unique URIs. Note that this normalization is not
sufficient to provide uniqueness. Two URIs that are
textually distinct after this normalization may still be
equivalent.
Objects using the uri type may restrict the schemes that
they permit. For example, 'data:' and 'urn:' schemes
might not be appropriate.
A zero-length URI is not a valid URI. This can be used to
express 'URI absent' where required.
In the value set and its semantics, this type is equivalent
to the Uri SMIv2 textual convention defined in RFC 5017.";
reference
"RFC 3986: Uniform Resource Identifier (URI): Generic Syntax
RFC 3305: Report from the Joint W3C/IETF URI Planning Interest
Group: Uniform Resource Identifiers (URIs), URLs,
and Uniform Resource Names (URNs): Clarifications
and Recommendations
RFC 5017: MIB Textual Conventions for Uniform Resource
Identifiers (URIs)";
}
}

View file

@ -0,0 +1,698 @@
module ietf-interfaces {
namespace "urn:ietf:params:xml:ns:yang:ietf-interfaces";
prefix if;
import ietf-yang-types {
prefix yang;
}
organization
"IETF NETMOD (NETCONF Data Modeling Language) Working Group";
contact
"WG Web: <http://tools.ietf.org/wg/netmod/>
WG List: <mailto:netmod@ietf.org>
WG Chair: Thomas Nadeau
<mailto:tnadeau@lucidvision.com>
WG Chair: Juergen Schoenwaelder
<mailto:j.schoenwaelder@jacobs-university.de>
Editor: Martin Bjorklund
<mailto:mbj@tail-f.com>";
description
"This module contains a collection of YANG definitions for
managing network interfaces.
Copyright (c) 2014 IETF Trust and the persons identified as
authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject
to the license terms contained in, the Simplified BSD License
set forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(http://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC 7223; see
the RFC itself for full legal notices.";
revision 2014-05-08 {
description
"Initial revision.";
reference
"RFC 7223: A YANG Data Model for Interface Management";
}
/*
* Typedefs
*/
typedef interface-ref {
type leafref {
path "/if:interfaces/if:interface/if:name";
}
description
"This type is used by data models that need to reference
configured interfaces.";
}
typedef interface-state-ref {
type leafref {
path "/if:interfaces-state/if:interface/if:name";
}
description
"This type is used by data models that need to reference
the operationally present interfaces.";
}
/*
* Identities
*/
identity interface-type {
description
"Base identity from which specific interface types are
derived.";
}
/*
* Features
*/
feature arbitrary-names {
description
"This feature indicates that the device allows user-controlled
interfaces to be named arbitrarily.";
}
feature pre-provisioning {
description
"This feature indicates that the device supports
pre-provisioning of interface configuration, i.e., it is
possible to configure an interface whose physical interface
hardware is not present on the device.";
}
feature if-mib {
description
"This feature indicates that the device implements
the IF-MIB.";
reference
"RFC 2863: The Interfaces Group MIB";
}
/*
* Configuration data nodes
*/
container interfaces {
description
"Interface configuration parameters.";
list interface {
key "name";
description
"The list of configured interfaces on the device.
The operational state of an interface is available in the
/interfaces-state/interface list. If the configuration of a
system-controlled interface cannot be used by the system
(e.g., the interface hardware present does not match the
interface type), then the configuration is not applied to
the system-controlled interface shown in the
/interfaces-state/interface list. If the configuration
of a user-controlled interface cannot be used by the system,
the configured interface is not instantiated in the
/interfaces-state/interface list.";
leaf name {
type string;
description
"The name of the interface.
A device MAY restrict the allowed values for this leaf,
possibly depending on the type of the interface.
For system-controlled interfaces, this leaf is the
device-specific name of the interface. The 'config false'
list /interfaces-state/interface contains the currently
existing interfaces on the device.
If a client tries to create configuration for a
system-controlled interface that is not present in the
/interfaces-state/interface list, the server MAY reject
the request if the implementation does not support
pre-provisioning of interfaces or if the name refers to
an interface that can never exist in the system. A
NETCONF server MUST reply with an rpc-error with the
error-tag 'invalid-value' in this case.
If the device supports pre-provisioning of interface
configuration, the 'pre-provisioning' feature is
advertised.
If the device allows arbitrarily named user-controlled
interfaces, the 'arbitrary-names' feature is advertised.
When a configured user-controlled interface is created by
the system, it is instantiated with the same name in the
/interface-state/interface list.";
}
leaf description {
type string;
description
"A textual description of the interface.
A server implementation MAY map this leaf to the ifAlias
MIB object. Such an implementation needs to use some
mechanism to handle the differences in size and characters
allowed between this leaf and ifAlias. The definition of
such a mechanism is outside the scope of this document.
Since ifAlias is defined to be stored in non-volatile
storage, the MIB implementation MUST map ifAlias to the
value of 'description' in the persistently stored
datastore.
Specifically, if the device supports ':startup', when
ifAlias is read the device MUST return the value of
'description' in the 'startup' datastore, and when it is
written, it MUST be written to the 'running' and 'startup'
datastores. Note that it is up to the implementation to
decide whether to modify this single leaf in 'startup' or
perform an implicit copy-config from 'running' to
'startup'.
If the device does not support ':startup', ifAlias MUST
be mapped to the 'description' leaf in the 'running'
datastore.";
reference
"RFC 2863: The Interfaces Group MIB - ifAlias";
}
leaf type {
type identityref {
base interface-type;
}
mandatory true;
description
"The type of the interface.
When an interface entry is created, a server MAY
initialize the type leaf with a valid value, e.g., if it
is possible to derive the type from the name of the
interface.
If a client tries to set the type of an interface to a
value that can never be used by the system, e.g., if the
type is not supported or if the type does not match the
name of the interface, the server MUST reject the request.
A NETCONF server MUST reply with an rpc-error with the
error-tag 'invalid-value' in this case.";
reference
"RFC 2863: The Interfaces Group MIB - ifType";
}
leaf enabled {
type boolean;
default "true";
description
"This leaf contains the configured, desired state of the
interface.
Systems that implement the IF-MIB use the value of this
leaf in the 'running' datastore to set
IF-MIB.ifAdminStatus to 'up' or 'down' after an ifEntry
has been initialized, as described in RFC 2863.
Changes in this leaf in the 'running' datastore are
reflected in ifAdminStatus, but if ifAdminStatus is
changed over SNMP, this leaf is not affected.";
reference
"RFC 2863: The Interfaces Group MIB - ifAdminStatus";
}
leaf link-up-down-trap-enable {
if-feature if-mib;
type enumeration {
enum enabled {
value 1;
}
enum disabled {
value 2;
}
}
description
"Controls whether linkUp/linkDown SNMP notifications
should be generated for this interface.
If this node is not configured, the value 'enabled' is
operationally used by the server for interfaces that do
not operate on top of any other interface (i.e., there are
no 'lower-layer-if' entries), and 'disabled' otherwise.";
reference
"RFC 2863: The Interfaces Group MIB -
ifLinkUpDownTrapEnable";
}
}
}
/*
* Operational state data nodes
*/
container interfaces-state {
config false;
description
"Data nodes for the operational state of interfaces.";
list interface {
key "name";
description
"The list of interfaces on the device.
System-controlled interfaces created by the system are
always present in this list, whether they are configured or
not.";
leaf name {
type string;
description
"The name of the interface.
A server implementation MAY map this leaf to the ifName
MIB object. Such an implementation needs to use some
mechanism to handle the differences in size and characters
allowed between this leaf and ifName. The definition of
such a mechanism is outside the scope of this document.";
reference
"RFC 2863: The Interfaces Group MIB - ifName";
}
leaf type {
type identityref {
base interface-type;
}
mandatory true;
description
"The type of the interface.";
reference
"RFC 2863: The Interfaces Group MIB - ifType";
}
leaf admin-status {
if-feature if-mib;
type enumeration {
enum up {
value 1;
description
"Ready to pass packets.";
}
enum down {
value 2;
description
"Not ready to pass packets and not in some test mode.";
}
enum testing {
value 3;
description
"In some test mode.";
}
}
mandatory true;
description
"The desired state of the interface.
This leaf has the same read semantics as ifAdminStatus.";
reference
"RFC 2863: The Interfaces Group MIB - ifAdminStatus";
}
leaf oper-status {
type enumeration {
enum up {
value 1;
description
"Ready to pass packets.";
}
enum down {
value 2;
description
"The interface does not pass any packets.";
}
enum testing {
value 3;
description
"In some test mode. No operational packets can
be passed.";
}
enum unknown {
value 4;
description
"Status cannot be determined for some reason.";
}
enum dormant {
value 5;
description
"Waiting for some external event.";
}
enum not-present {
value 6;
description
"Some component (typically hardware) is missing.";
}
enum lower-layer-down {
value 7;
description
"Down due to state of lower-layer interface(s).";
}
}
mandatory true;
description
"The current operational state of the interface.
This leaf has the same semantics as ifOperStatus.";
reference
"RFC 2863: The Interfaces Group MIB - ifOperStatus";
}
leaf last-change {
type yang:date-and-time;
description
"The time the interface entered its current operational
state. If the current state was entered prior to the
last re-initialization of the local network management
subsystem, then this node is not present.";
reference
"RFC 2863: The Interfaces Group MIB - ifLastChange";
}
leaf if-index {
if-feature if-mib;
type int32 {
range "1..2147483647";
}
mandatory true;
description
"The ifIndex value for the ifEntry represented by this
interface.";
reference
"RFC 2863: The Interfaces Group MIB - ifIndex";
}
leaf phys-address {
type yang:phys-address;
description
"The interface's address at its protocol sub-layer. For
example, for an 802.x interface, this object normally
contains a Media Access Control (MAC) address. The
interface's media-specific modules must define the bit
and byte ordering and the format of the value of this
object. For interfaces that do not have such an address
(e.g., a serial line), this node is not present.";
reference
"RFC 2863: The Interfaces Group MIB - ifPhysAddress";
}
leaf-list higher-layer-if {
type interface-state-ref;
description
"A list of references to interfaces layered on top of this
interface.";
reference
"RFC 2863: The Interfaces Group MIB - ifStackTable";
}
leaf-list lower-layer-if {
type interface-state-ref;
description
"A list of references to interfaces layered underneath this
interface.";
reference
"RFC 2863: The Interfaces Group MIB - ifStackTable";
}
leaf speed {
type yang:gauge64;
units "bits/second";
description
"An estimate of the interface's current bandwidth in bits
per second. For interfaces that do not vary in
bandwidth or for those where no accurate estimation can
be made, this node should contain the nominal bandwidth.
For interfaces that have no concept of bandwidth, this
node is not present.";
reference
"RFC 2863: The Interfaces Group MIB -
ifSpeed, ifHighSpeed";
}
container statistics {
description
"A collection of interface-related statistics objects.";
leaf discontinuity-time {
type yang:date-and-time;
mandatory true;
description
"The time on the most recent occasion at which any one or
more of this interface's counters suffered a
discontinuity. If no such discontinuities have occurred
since the last re-initialization of the local management
subsystem, then this node contains the time the local
management subsystem re-initialized itself.";
}
leaf in-octets {
type yang:counter64;
description
"The total number of octets received on the interface,
including framing characters.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB - ifHCInOctets";
}
leaf in-unicast-pkts {
type yang:counter64;
description
"The number of packets, delivered by this sub-layer to a
higher (sub-)layer, that were not addressed to a
multicast or broadcast address at this sub-layer.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB - ifHCInUcastPkts";
}
leaf in-broadcast-pkts {
type yang:counter64;
description
"The number of packets, delivered by this sub-layer to a
higher (sub-)layer, that were addressed to a broadcast
address at this sub-layer.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB -
ifHCInBroadcastPkts";
}
leaf in-multicast-pkts {
type yang:counter64;
description
"The number of packets, delivered by this sub-layer to a
higher (sub-)layer, that were addressed to a multicast
address at this sub-layer. For a MAC-layer protocol,
this includes both Group and Functional addresses.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB -
ifHCInMulticastPkts";
}
leaf in-discards {
type yang:counter32;
description
"The number of inbound packets that were chosen to be
discarded even though no errors had been detected to
prevent their being deliverable to a higher-layer
protocol. One possible reason for discarding such a
packet could be to free up buffer space.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB - ifInDiscards";
}
leaf in-errors {
type yang:counter32;
description
"For packet-oriented interfaces, the number of inbound
packets that contained errors preventing them from being
deliverable to a higher-layer protocol. For character-
oriented or fixed-length interfaces, the number of
inbound transmission units that contained errors
preventing them from being deliverable to a higher-layer
protocol.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB - ifInErrors";
}
leaf in-unknown-protos {
type yang:counter32;
description
"For packet-oriented interfaces, the number of packets
received via the interface that were discarded because
of an unknown or unsupported protocol. For
character-oriented or fixed-length interfaces that
support protocol multiplexing, the number of
transmission units received via the interface that were
discarded because of an unknown or unsupported protocol.
For any interface that does not support protocol
multiplexing, this counter is not present.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB - ifInUnknownProtos";
}
leaf out-octets {
type yang:counter64;
description
"The total number of octets transmitted out of the
interface, including framing characters.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB - ifHCOutOctets";
}
leaf out-unicast-pkts {
type yang:counter64;
description
"The total number of packets that higher-level protocols
requested be transmitted, and that were not addressed
to a multicast or broadcast address at this sub-layer,
including those that were discarded or not sent.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB - ifHCOutUcastPkts";
}
leaf out-broadcast-pkts {
type yang:counter64;
description
"The total number of packets that higher-level protocols
requested be transmitted, and that were addressed to a
broadcast address at this sub-layer, including those
that were discarded or not sent.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB -
ifHCOutBroadcastPkts";
}
leaf out-multicast-pkts {
type yang:counter64;
description
"The total number of packets that higher-level protocols
requested be transmitted, and that were addressed to a
multicast address at this sub-layer, including those
that were discarded or not sent. For a MAC-layer
protocol, this includes both Group and Functional
addresses.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB -
ifHCOutMulticastPkts";
}
leaf out-discards {
type yang:counter32;
description
"The number of outbound packets that were chosen to be
discarded even though no errors had been detected to
prevent their being transmitted. One possible reason
for discarding such a packet could be to free up buffer
space.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB - ifOutDiscards";
}
leaf out-errors {
type yang:counter32;
description
"For packet-oriented interfaces, the number of outbound
packets that could not be transmitted because of errors.
For character-oriented or fixed-length interfaces, the
number of outbound transmission units that could not be
transmitted because of errors.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB - ifOutErrors";
}
}
}
}
}

View file

@ -0,0 +1,701 @@
module ietf-ip {
namespace "urn:ietf:params:xml:ns:yang:ietf-ip";
prefix ip;
import ietf-interfaces {
prefix if;
}
import ietf-inet-types {
prefix inet;
}
import ietf-yang-types {
prefix yang;
}
organization
"IETF NETMOD (NETCONF Data Modeling Language) Working Group";
contact
"WG Web: <http://tools.ietf.org/wg/netmod/>
WG List: <mailto:netmod@ietf.org>
WG Chair: Thomas Nadeau
<mailto:tnadeau@lucidvision.com>
WG Chair: Juergen Schoenwaelder
<mailto:j.schoenwaelder@jacobs-university.de>
Editor: Martin Bjorklund
<mailto:mbj@tail-f.com>";
description
"This module contains a collection of YANG definitions for
configuring IP implementations.
Copyright (c) 2014 IETF Trust and the persons identified as
authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject
to the license terms contained in, the Simplified BSD License
set forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(http://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC 7277; see
the RFC itself for full legal notices.";
revision 2014-06-16 {
description
"Initial revision.";
reference
"RFC 7277: A YANG Data Model for IP Management";
}
/*
* Features
*/
feature ipv4-non-contiguous-netmasks {
description
"Indicates support for configuring non-contiguous
subnet masks.";
}
feature ipv6-privacy-autoconf {
description
"Indicates support for Privacy Extensions for Stateless Address
Autoconfiguration in IPv6.";
reference
"RFC 4941: Privacy Extensions for Stateless Address
Autoconfiguration in IPv6";
}
/*
* Typedefs
*/
typedef ip-address-origin {
type enumeration {
enum other {
description
"None of the following.";
}
enum static {
description
"Indicates that the address has been statically
configured - for example, using NETCONF or a Command Line
Interface.";
}
enum dhcp {
description
"Indicates an address that has been assigned to this
system by a DHCP server.";
}
enum link-layer {
description
"Indicates an address created by IPv6 stateless
autoconfiguration that embeds a link-layer address in its
interface identifier.";
}
enum random {
description
"Indicates an address chosen by the system at
random, e.g., an IPv4 address within 169.254/16, an
RFC 4941 temporary address, or an RFC 7217 semantically
opaque address.";
reference
"RFC 4941: Privacy Extensions for Stateless Address
Autoconfiguration in IPv6
RFC 7217: A Method for Generating Semantically Opaque
Interface Identifiers with IPv6 Stateless
Address Autoconfiguration (SLAAC)";
}
}
description
"The origin of an address.";
}
typedef neighbor-origin {
type enumeration {
enum other {
description
"None of the following.";
}
enum static {
description
"Indicates that the mapping has been statically
configured - for example, using NETCONF or a Command Line
Interface.";
}
enum dynamic {
description
"Indicates that the mapping has been dynamically resolved
using, e.g., IPv4 ARP or the IPv6 Neighbor Discovery
protocol.";
}
}
description
"The origin of a neighbor entry.";
}
/*
* Configuration data nodes
*/
augment "/if:interfaces/if:interface" {
description
"Parameters for configuring IP on interfaces.
If an interface is not capable of running IP, the server
must not allow the client to configure these parameters.";
container ipv4 {
presence
"Enables IPv4 unless the 'enabled' leaf
(which defaults to 'true') is set to 'false'";
description
"Parameters for the IPv4 address family.";
leaf enabled {
type boolean;
default true;
description
"Controls whether IPv4 is enabled or disabled on this
interface. When IPv4 is enabled, this interface is
connected to an IPv4 stack, and the interface can send
and receive IPv4 packets.";
}
leaf forwarding {
type boolean;
default false;
description
"Controls IPv4 packet forwarding of datagrams received by,
but not addressed to, this interface. IPv4 routers
forward datagrams. IPv4 hosts do not (except those
source-routed via the host).";
}
leaf mtu {
type uint16 {
range "68..max";
}
units octets;
description
"The size, in octets, of the largest IPv4 packet that the
interface will send and receive.
The server may restrict the allowed values for this leaf,
depending on the interface's type.
If this leaf is not configured, the operationally used MTU
depends on the interface's type.";
reference
"RFC 791: Internet Protocol";
}
list address {
key "ip";
description
"The list of configured IPv4 addresses on the interface.";
leaf ip {
type inet:ipv4-address-no-zone;
description
"The IPv4 address on the interface.";
}
choice subnet {
mandatory true;
description
"The subnet can be specified as a prefix-length, or,
if the server supports non-contiguous netmasks, as
a netmask.";
leaf prefix-length {
type uint8 {
range "0..32";
}
description
"The length of the subnet prefix.";
}
leaf netmask {
if-feature ipv4-non-contiguous-netmasks;
type yang:dotted-quad;
description
"The subnet specified as a netmask.";
}
}
}
list neighbor {
key "ip";
description
"A list of mappings from IPv4 addresses to
link-layer addresses.
Entries in this list are used as static entries in the
ARP Cache.";
reference
"RFC 826: An Ethernet Address Resolution Protocol";
leaf ip {
type inet:ipv4-address-no-zone;
description
"The IPv4 address of the neighbor node.";
}
leaf link-layer-address {
type yang:phys-address;
mandatory true;
description
"The link-layer address of the neighbor node.";
}
}
}
container ipv6 {
presence
"Enables IPv6 unless the 'enabled' leaf
(which defaults to 'true') is set to 'false'";
description
"Parameters for the IPv6 address family.";
leaf enabled {
type boolean;
default true;
description
"Controls whether IPv6 is enabled or disabled on this
interface. When IPv6 is enabled, this interface is
connected to an IPv6 stack, and the interface can send
and receive IPv6 packets.";
}
leaf forwarding {
type boolean;
default false;
description
"Controls IPv6 packet forwarding of datagrams received by,
but not addressed to, this interface. IPv6 routers
forward datagrams. IPv6 hosts do not (except those
source-routed via the host).";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6)
Section 6.2.1, IsRouter";
}
leaf mtu {
type uint32 {
range "1280..max";
}
units octets;
description
"The size, in octets, of the largest IPv6 packet that the
interface will send and receive.
The server may restrict the allowed values for this leaf,
depending on the interface's type.
If this leaf is not configured, the operationally used MTU
depends on the interface's type.";
reference
"RFC 2460: Internet Protocol, Version 6 (IPv6) Specification
Section 5";
}
list address {
key "ip";
description
"The list of configured IPv6 addresses on the interface.";
leaf ip {
type inet:ipv6-address-no-zone;
description
"The IPv6 address on the interface.";
}
leaf prefix-length {
type uint8 {
range "0..128";
}
mandatory true;
description
"The length of the subnet prefix.";
}
}
list neighbor {
key "ip";
description
"A list of mappings from IPv6 addresses to
link-layer addresses.
Entries in this list are used as static entries in the
Neighbor Cache.";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6)";
leaf ip {
type inet:ipv6-address-no-zone;
description
"The IPv6 address of the neighbor node.";
}
leaf link-layer-address {
type yang:phys-address;
mandatory true;
description
"The link-layer address of the neighbor node.";
}
}
leaf dup-addr-detect-transmits {
type uint32;
default 1;
description
"The number of consecutive Neighbor Solicitation messages
sent while performing Duplicate Address Detection on a
tentative address. A value of zero indicates that
Duplicate Address Detection is not performed on
tentative addresses. A value of one indicates a single
transmission with no follow-up retransmissions.";
reference
"RFC 4862: IPv6 Stateless Address Autoconfiguration";
}
container autoconf {
description
"Parameters to control the autoconfiguration of IPv6
addresses, as described in RFC 4862.";
reference
"RFC 4862: IPv6 Stateless Address Autoconfiguration";
leaf create-global-addresses {
type boolean;
default true;
description
"If enabled, the host creates global addresses as
described in RFC 4862.";
reference
"RFC 4862: IPv6 Stateless Address Autoconfiguration
Section 5.5";
}
leaf create-temporary-addresses {
if-feature ipv6-privacy-autoconf;
type boolean;
default false;
description
"If enabled, the host creates temporary addresses as
described in RFC 4941.";
reference
"RFC 4941: Privacy Extensions for Stateless Address
Autoconfiguration in IPv6";
}
leaf temporary-valid-lifetime {
if-feature ipv6-privacy-autoconf;
type uint32;
units "seconds";
default 604800;
description
"The time period during which the temporary address
is valid.";
reference
"RFC 4941: Privacy Extensions for Stateless Address
Autoconfiguration in IPv6
- TEMP_VALID_LIFETIME";
}
leaf temporary-preferred-lifetime {
if-feature ipv6-privacy-autoconf;
type uint32;
units "seconds";
default 86400;
description
"The time period during which the temporary address is
preferred.";
reference
"RFC 4941: Privacy Extensions for Stateless Address
Autoconfiguration in IPv6
- TEMP_PREFERRED_LIFETIME";
}
}
}
}
/*
* Operational state data nodes
*/
augment "/if:interfaces-state/if:interface" {
description
"Data nodes for the operational state of IP on interfaces.";
container ipv4 {
presence "Present if IPv4 is enabled on this interface";
config false;
description
"Interface-specific parameters for the IPv4 address family.";
leaf forwarding {
type boolean;
description
"Indicates whether IPv4 packet forwarding is enabled or
disabled on this interface.";
}
leaf mtu {
type uint16 {
range "68..max";
}
units octets;
description
"The size, in octets, of the largest IPv4 packet that the
interface will send and receive.";
reference
"RFC 791: Internet Protocol";
}
list address {
key "ip";
description
"The list of IPv4 addresses on the interface.";
leaf ip {
type inet:ipv4-address-no-zone;
description
"The IPv4 address on the interface.";
}
choice subnet {
description
"The subnet can be specified as a prefix-length, or,
if the server supports non-contiguous netmasks, as
a netmask.";
leaf prefix-length {
type uint8 {
range "0..32";
}
description
"The length of the subnet prefix.";
}
leaf netmask {
if-feature ipv4-non-contiguous-netmasks;
type yang:dotted-quad;
description
"The subnet specified as a netmask.";
}
}
leaf origin {
type ip-address-origin;
description
"The origin of this address.";
}
}
list neighbor {
key "ip";
description
"A list of mappings from IPv4 addresses to
link-layer addresses.
This list represents the ARP Cache.";
reference
"RFC 826: An Ethernet Address Resolution Protocol";
leaf ip {
type inet:ipv4-address-no-zone;
description
"The IPv4 address of the neighbor node.";
}
leaf link-layer-address {
type yang:phys-address;
description
"The link-layer address of the neighbor node.";
}
leaf origin {
type neighbor-origin;
description
"The origin of this neighbor entry.";
}
}
}
container ipv6 {
presence "Present if IPv6 is enabled on this interface";
config false;
description
"Parameters for the IPv6 address family.";
leaf forwarding {
type boolean;
default false;
description
"Indicates whether IPv6 packet forwarding is enabled or
disabled on this interface.";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6)
Section 6.2.1, IsRouter";
}
leaf mtu {
type uint32 {
range "1280..max";
}
units octets;
description
"The size, in octets, of the largest IPv6 packet that the
interface will send and receive.";
reference
"RFC 2460: Internet Protocol, Version 6 (IPv6) Specification
Section 5";
}
list address {
key "ip";
description
"The list of IPv6 addresses on the interface.";
leaf ip {
type inet:ipv6-address-no-zone;
description
"The IPv6 address on the interface.";
}
leaf prefix-length {
type uint8 {
range "0..128";
}
mandatory true;
description
"The length of the subnet prefix.";
}
leaf origin {
type ip-address-origin;
description
"The origin of this address.";
}
leaf status {
type enumeration {
enum preferred {
description
"This is a valid address that can appear as the
destination or source address of a packet.";
}
enum deprecated {
description
"This is a valid but deprecated address that should
no longer be used as a source address in new
communications, but packets addressed to such an
address are processed as expected.";
}
enum invalid {
description
"This isn't a valid address, and it shouldn't appear
as the destination or source address of a packet.";
}
enum inaccessible {
description
"The address is not accessible because the interface
to which this address is assigned is not
operational.";
}
enum unknown {
description
"The status cannot be determined for some reason.";
}
enum tentative {
description
"The uniqueness of the address on the link is being
verified. Addresses in this state should not be
used for general communication and should only be
used to determine the uniqueness of the address.";
}
enum duplicate {
description
"The address has been determined to be non-unique on
the link and so must not be used.";
}
enum optimistic {
description
"The address is available for use, subject to
restrictions, while its uniqueness on a link is
being verified.";
}
}
description
"The status of an address. Most of the states correspond
to states from the IPv6 Stateless Address
Autoconfiguration protocol.";
reference
"RFC 4293: Management Information Base for the
Internet Protocol (IP)
- IpAddressStatusTC
RFC 4862: IPv6 Stateless Address Autoconfiguration";
}
}
list neighbor {
key "ip";
description
"A list of mappings from IPv6 addresses to
link-layer addresses.
This list represents the Neighbor Cache.";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6)";
leaf ip {
type inet:ipv6-address-no-zone;
description
"The IPv6 address of the neighbor node.";
}
leaf link-layer-address {
type yang:phys-address;
description
"The link-layer address of the neighbor node.";
}
leaf origin {
type neighbor-origin;
description
"The origin of this neighbor entry.";
}
leaf is-router {
type empty;
description
"Indicates that the neighbor node acts as a router.";
}
leaf state {
type enumeration {
enum incomplete {
description
"Address resolution is in progress, and the link-layer
address of the neighbor has not yet been
determined.";
}
enum reachable {
description
"Roughly speaking, the neighbor is known to have been
reachable recently (within tens of seconds ago).";
}
enum stale {
description
"The neighbor is no longer known to be reachable, but
until traffic is sent to the neighbor no attempt
should be made to verify its reachability.";
}
enum delay {
description
"The neighbor is no longer known to be reachable, and
traffic has recently been sent to the neighbor.
Rather than probe the neighbor immediately, however,
delay sending probes for a short while in order to
give upper-layer protocols a chance to provide
reachability confirmation.";
}
enum probe {
description
"The neighbor is no longer known to be reachable, and
unicast Neighbor Solicitation probes are being sent
to verify reachability.";
}
}
description
"The Neighbor Unreachability Detection state of this
entry.";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6)
Section 7.3.2";
}
}
}
}
}

View file

@ -0,0 +1,232 @@
module ietf-ipv4-unicast-routing {
namespace "urn:ietf:params:xml:ns:yang:ietf-ipv4-unicast-routing";
prefix "v4ur";
import ietf-routing {
prefix "rt";
revision-date "2014-10-26";
}
import ietf-inet-types {
prefix "inet";
revision-date "2013-07-15";
}
organization
"IETF NETMOD (NETCONF Data Modeling Language) Working Group";
contact
"WG Web: <http://tools.ietf.org/wg/netmod/>
WG List: <mailto:netmod@ietf.org>
WG Chair: Thomas Nadeau
<mailto:tnadeau@lucidvision.com>
WG Chair: Juergen Schoenwaelder
<mailto:j.schoenwaelder@jacobs-university.de>
Editor: Ladislav Lhotka
<mailto:lhotka@nic.cz>";
description
"This YANG module augments the 'ietf-routing' module with basic
configuration and operational state data for IPv4 unicast
routing.
Copyright (c) 2014 IETF Trust and the persons identified as
authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject to
the license terms contained in, the Simplified BSD License set
forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(http://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC XXXX; see the
RFC itself for full legal notices.";
revision 2014-10-26 {
description
"Initial revision.";
reference
"RFC XXXX: A YANG Data Model for Routing Management";
}
/* Identities */
identity ipv4-unicast {
base rt:ipv4;
description
"This identity represents the IPv4 unicast address family.";
}
/* Operational state data */
augment "/rt:routing-state/rt:ribs/rt:rib/rt:routes/rt:route" {
when "../../rt:address-family = 'v4ur:ipv4-unicast'" {
description
"This augment is valid only for IPv4 unicast.";
}
description
"This leaf augments an IPv4 unicast route.";
leaf destination-prefix {
type inet:ipv4-prefix;
description
"IPv4 destination prefix.";
}
}
augment "/rt:routing-state/rt:ribs/rt:rib/rt:routes/rt:route/"
+ "rt:next-hop/rt:next-hop-options/rt:simple-next-hop" {
when "../../../rt:address-family = 'v4ur:ipv4-unicast'" {
description
"This augment is valid only for IPv4 unicast.";
}
description
"This leaf augments the 'simple-next-hop' case of IPv4 unicast
routes.";
leaf next-hop-address {
type inet:ipv4-address;
description
"IPv4 address of the next-hop.";
}
}
augment "/rt:routing-state/rt:next-hop-lists/rt:next-hop-list/"
+ "rt:next-hop/rt:next-hop-options/rt:simple-next-hop" {
when "../rt:address-family = 'v4ur:ipv4-unicast'" {
description
"This augment is valid only for IPv4 unicast.";
}
description
"This leaf augments next-hop list with IPv4 next-hop address.
routes.";
leaf next-hop-address {
type inet:ipv4-address;
description
"IPv4 address of the next-hop.";
}
}
/* Configuration data */
augment "/rt:routing/rt:routing-instance/rt:routing-protocols/"
+ "rt:routing-protocol/rt:static-routes" {
description
"This augment defines the configuration of the 'static'
pseudo-protocol with data specific to IPv4 unicast.";
container ipv4 {
description
"Configuration of a 'static' pseudo-protocol instance
consists of a list of routes.";
list route {
key "destination-prefix";
ordered-by "user";
description
"A user-ordered list of static routes.";
leaf destination-prefix {
type inet:ipv4-prefix;
mandatory "true";
description
"IPv4 destination prefix.";
}
leaf description {
type string;
description
"Textual description of the route.";
}
container next-hop {
description
"Configuration of next-hop.";
grouping next-hop-content {
description
"Next-hop content for IPv4 unicast static routes.";
uses rt:next-hop-content {
augment "next-hop-options" {
description
"Add next-hop address case.";
leaf next-hop-address {
type inet:ipv4-address;
description
"IPv4 address of the next-hop.";
}
}
}
}
choice simple-or-list {
description
"Options for next-hops.";
list multipath-entry {
if-feature rt:multipath-routes;
key "name";
description
"List of alternative next-hops.";
leaf name {
type string;
description
"A unique identifier of the next-hop entry.";
}
uses next-hop-content;
uses rt:next-hop-classifiers;
}
case simple-next-hop {
uses next-hop-content;
}
}
}
}
}
}
/* RPC methods */
augment "/rt:fib-route/rt:input/rt:destination-address" {
when "rt:address-family='v4ur:ipv4-unicast'" {
description
"This augment is valid only for IPv4 unicast.";
}
description
"This leaf augments the 'rt:destination-address' parameter of
the 'rt:fib-route' operation.";
leaf address {
type inet:ipv4-address;
description
"IPv4 destination address.";
}
}
augment "/rt:fib-route/rt:output/rt:route" {
when "rt:address-family='v4ur:ipv4-unicast'" {
description
"This augment is valid only for IPv4 unicast.";
}
description
"This leaf augments the reply to the 'rt:fib-route'
operation.";
leaf destination-prefix {
type inet:ipv4-prefix;
description
"IPv4 destination prefix.";
}
}
augment "/rt:fib-route/rt:output/rt:route/rt:next-hop/"
+ "rt:next-hop-options/rt:simple-next-hop" {
when "../rt:address-family='v4ur:ipv4-unicast'" {
description
"This augment is valid only for IPv4 unicast.";
}
description
"This leaf augments the 'simple-next-hop' case in the reply to
the 'rt:fib-route' operation.";
leaf next-hop-address {
type inet:ipv4-address;
description
"IPv4 address of the next-hop.";
}
}
}

View file

@ -0,0 +1,636 @@
module ietf-ipv6-unicast-routing {
namespace "urn:ietf:params:xml:ns:yang:ietf-ipv6-unicast-routing";
prefix "v6ur";
import ietf-routing {
prefix "rt";
revision-date "2014-10-26";
}
import ietf-inet-types {
prefix "inet";
revision-date "2013-07-15";
}
import ietf-interfaces {
prefix "if";
revision-date "2013-07-15";
}
import ietf-ip {
prefix "ip";
revision-date "2014-06-16";
}
organization
"IETF NETMOD (NETCONF Data Modeling Language) Working Group";
contact
"WG Web: <http://tools.ietf.org/wg/netmod/>
WG List: <mailto:netmod@ietf.org>
WG Chair: Thomas Nadeau
<mailto:tnadeau@lucidvision.com>
WG Chair: Juergen Schoenwaelder
<mailto:j.schoenwaelder@jacobs-university.de>
Editor: Ladislav Lhotka
<mailto:lhotka@nic.cz>";
description
"This YANG module augments the 'ietf-routing' module with basic
configuration and operational state data for IPv6 unicast
routing.
Copyright (c) 2014 IETF Trust and the persons identified as
authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject to
the license terms contained in, the Simplified BSD License set
forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(http://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC XXXX; see the
RFC itself for full legal notices.";
revision 2014-10-26 {
description
"Initial revision.";
reference
"RFC XXXX: A YANG Data Model for Routing Management";
}
/* Identities */
identity ipv6-unicast {
base rt:ipv6;
description
"This identity represents the IPv6 unicast address family.";
}
/* Operational state data */
augment "/rt:routing-state/rt:routing-instance/rt:interfaces/"
+ "rt:interface" {
description
"IPv6-specific parameters of router interfaces.";
container ipv6-router-advertisements {
description
"Parameters of IPv6 Router Advertisements.";
leaf send-advertisements {
type boolean;
description
"A flag indicating whether or not the router sends periodic
Router Advertisements and responds to Router
Solicitations.";
}
leaf max-rtr-adv-interval {
type uint16 {
range "4..1800";
}
units "seconds";
description
"The maximum time allowed between sending unsolicited
multicast Router Advertisements from the interface.";
}
leaf min-rtr-adv-interval {
type uint16 {
range "3..1350";
}
units "seconds";
description
"The minimum time allowed between sending unsolicited
multicast Router Advertisements from the interface.";
}
leaf managed-flag {
type boolean;
description
"The value that is placed in the 'Managed address
configuration' flag field in the Router Advertisement.";
}
leaf other-config-flag {
type boolean;
description
"The value that is placed in the 'Other configuration' flag
field in the Router Advertisement.";
}
leaf link-mtu {
type uint32;
description
"The value that is placed in MTU options sent by the
router. A value of zero indicates that no MTU options are
sent.";
}
leaf reachable-time {
type uint32 {
range "0..3600000";
}
units "milliseconds";
description
"The value that is placed in the Reachable Time field in
the Router Advertisement messages sent by the router. A
value of zero means unspecified (by this router).";
}
leaf retrans-timer {
type uint32;
units "milliseconds";
description
"The value that is placed in the Retrans Timer field in the
Router Advertisement messages sent by the router. A value
of zero means unspecified (by this router).";
}
leaf cur-hop-limit {
type uint8;
description
"The value that is placed in the Cur Hop Limit field in the
Router Advertisement messages sent by the router. A value
of zero means unspecified (by this router).";
}
leaf default-lifetime {
type uint16 {
range "0..9000";
}
units "seconds";
description
"The value that is placed in the Router Lifetime field of
Router Advertisements sent from the interface, in seconds.
A value of zero indicates that the router is not to be
used as a default router.";
}
container prefix-list {
description
"A list of prefixes that are placed in Prefix Information
options in Router Advertisement messages sent from the
interface.
By default, these are all prefixes that the router
advertises via routing protocols as being on-link for the
interface from which the advertisement is sent.";
list prefix {
key "prefix-spec";
description
"Advertised prefix entry and its parameters.";
leaf prefix-spec {
type inet:ipv6-prefix;
description
"IPv6 address prefix.";
}
leaf valid-lifetime {
type uint32;
units "seconds";
description
"The value that is placed in the Valid Lifetime in the
Prefix Information option. The designated value of all
1's (0xffffffff) represents infinity.";
}
leaf on-link-flag {
type boolean;
description
"The value that is placed in the on-link flag ('L-bit')
field in the Prefix Information option.";
}
leaf preferred-lifetime {
type uint32;
units "seconds";
description
"The value that is placed in the Preferred Lifetime in
the Prefix Information option, in seconds. The
designated value of all 1's (0xffffffff) represents
infinity.";
}
leaf autonomous-flag {
type boolean;
description
"The value that is placed in the Autonomous Flag field
in the Prefix Information option.";
}
}
}
}
}
augment "/rt:routing-state/rt:ribs/rt:rib/rt:routes/rt:route" {
when "../../rt:address-family = 'v6ur:ipv6-unicast'" {
description
"This augment is valid only for IPv6 unicast.";
}
description
"This leaf augments an IPv6 unicast route.";
leaf destination-prefix {
type inet:ipv6-prefix;
description
"IPv6 destination prefix.";
}
}
augment "/rt:routing-state/rt:ribs/rt:rib/rt:routes/rt:route/"
+ "rt:next-hop/rt:next-hop-options/rt:simple-next-hop" {
when "../../../rt:address-family = 'v6ur:ipv6-unicast'" {
description
"This augment is valid only for IPv6 unicast.";
}
description
"This leaf augments the 'simple-next-hop' case of IPv6 unicast
routes.";
leaf next-hop {
type inet:ipv6-address;
description
"IPv6 address of the next-hop.";
}
}
augment "/rt:routing-state/rt:next-hop-lists/rt:next-hop-list/"
+ "rt:next-hop/rt:next-hop-options/rt:simple-next-hop" {
when "../rt:address-family = 'v6ur:ipv6-unicast'" {
description
"This augment is valid only for IPv6 unicast.";
}
description
"This leaf augments next-hop list with IPv6 next-hop address.
routes.";
leaf next-hop-address {
type inet:ipv6-address;
description
"IPv6 address of the next-hop.";
}
}
/* Configuration data */
augment
"/rt:routing/rt:routing-instance/rt:interfaces/rt:interface" {
when "/if:interfaces/if:interface[if:name=current()/rt:name]/"
+ "ip:ipv6/ip:enabled='true'" {
description
"This augment is only valid for router interfaces with
enabled IPv6.";
}
description
"Configuration of IPv6-specific parameters of router
interfaces.";
container ipv6-router-advertisements {
description
"Configuration of IPv6 Router Advertisements.";
leaf send-advertisements {
type boolean;
default "false";
description
"A flag indicating whether or not the router sends periodic
Router Advertisements and responds to Router
Solicitations.";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6) -
AdvSendAdvertisements.";
}
leaf max-rtr-adv-interval {
type uint16 {
range "4..1800";
}
units "seconds";
default "600";
description
"The maximum time allowed between sending unsolicited
multicast Router Advertisements from the interface.";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6) -
MaxRtrAdvInterval.";
}
leaf min-rtr-adv-interval {
type uint16 {
range "3..1350";
}
units "seconds";
must ". <= 0.75 * ../max-rtr-adv-interval" {
description
"The value MUST NOT be greater than 75 % of
'max-rtr-adv-interval'.";
}
description
"The minimum time allowed between sending unsolicited
multicast Router Advertisements from the interface.
The default value to be used operationally if this leaf is
not configured is determined as follows:
- if max-rtr-adv-interval >= 9 seconds, the default value
is 0.33 * max-rtr-adv-interval;
- otherwise it is 0.75 * max-rtr-adv-interval.";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6) -
MinRtrAdvInterval.";
}
leaf managed-flag {
type boolean;
default "false";
description
"The value to be placed in the 'Managed address
configuration' flag field in the Router Advertisement.";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6) -
AdvManagedFlag.";
}
leaf other-config-flag {
type boolean;
default "false";
description
"The value to be placed in the 'Other configuration' flag
field in the Router Advertisement.";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6) -
AdvOtherConfigFlag.";
}
leaf link-mtu {
type uint32;
default "0";
description
"The value to be placed in MTU options sent by the router.
A value of zero indicates that no MTU options are sent.";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6) -
AdvLinkMTU.";
}
leaf reachable-time {
type uint32 {
range "0..3600000";
}
units "milliseconds";
default "0";
description
"The value to be placed in the Reachable Time field in the
Router Advertisement messages sent by the router. A value
of zero means unspecified (by this router).";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6) -
AdvReachableTime.";
}
leaf retrans-timer {
type uint32;
units "milliseconds";
default "0";
description
"The value to be placed in the Retrans Timer field in the
Router Advertisement messages sent by the router. A value
of zero means unspecified (by this router).";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6) -
AdvRetransTimer.";
}
leaf cur-hop-limit {
type uint8;
description
"The value to be placed in the Cur Hop Limit field in the
Router Advertisement messages sent by the router. A value
of zero means unspecified (by this router).
If this parameter is not configured, the device SHOULD use
the value specified in IANA Assigned Numbers that was in
effect at the time of implementation.";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6) -
AdvCurHopLimit.
IANA: IP Parameters,
http://www.iana.org/assignments/ip-parameters";
}
leaf default-lifetime {
type uint16 {
range "0..9000";
}
units "seconds";
description
"The value to be placed in the Router Lifetime field of
Router Advertisements sent from the interface, in seconds.
It MUST be either zero or between max-rtr-adv-interval and
9000 seconds. A value of zero indicates that the router is
not to be used as a default router. These limits may be
overridden by specific documents that describe how IPv6
operates over different link layers.
If this parameter is not configured, the device SHOULD use
a value of 3 * max-rtr-adv-interval.";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6) -
AdvDefaultLifeTime.";
}
container prefix-list {
description
"Configuration of prefixes to be placed in Prefix
Information options in Router Advertisement messages sent
from the interface.
Prefixes that are advertised by default but do not have
their entries in the child 'prefix' list are advertised
with the default values of all parameters.
The link-local prefix SHOULD NOT be included in the list
of advertised prefixes.";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6) -
AdvPrefixList.";
list prefix {
key "prefix-spec";
description
"Configuration of an advertised prefix entry.";
leaf prefix-spec {
type inet:ipv6-prefix;
description
"IPv6 address prefix.";
}
choice control-adv-prefixes {
default "advertise";
description
"The prefix either may be explicitly removed from the
set of advertised prefixes, or parameters with which
it is advertised may be specified (default case).";
leaf no-advertise {
type empty;
description
"The prefix will not be advertised.
This can be used for removing the prefix from the
default set of advertised prefixes.";
}
case advertise {
leaf valid-lifetime {
type uint32;
units "seconds";
default "2592000";
description
"The value to be placed in the Valid Lifetime in
the Prefix Information option. The designated
value of all 1's (0xffffffff) represents
infinity.";
reference
"RFC 4861: Neighbor Discovery for IP version 6
(IPv6) - AdvValidLifetime.";
}
leaf on-link-flag {
type boolean;
default "true";
description
"The value to be placed in the on-link flag
('L-bit') field in the Prefix Information
option.";
reference
"RFC 4861: Neighbor Discovery for IP version 6
(IPv6) - AdvOnLinkFlag.";
}
leaf preferred-lifetime {
type uint32;
units "seconds";
must ". <= ../valid-lifetime" {
description
"This value MUST NOT be greater than
valid-lifetime.";
}
default "604800";
description
"The value to be placed in the Preferred Lifetime
in the Prefix Information option. The designated
value of all 1's (0xffffffff) represents
infinity.";
reference
"RFC 4861: Neighbor Discovery for IP version 6
(IPv6) - AdvPreferredLifetime.";
}
leaf autonomous-flag {
type boolean;
default "true";
description
"The value to be placed in the Autonomous Flag
field in the Prefix Information option.";
reference
"RFC 4861: Neighbor Discovery for IP version 6
(IPv6) - AdvAutonomousFlag.";
}
}
}
}
}
}
}
augment "/rt:routing/rt:routing-instance/rt:routing-protocols/"
+ "rt:routing-protocol/rt:static-routes" {
description
"This augment defines the configuration of the 'static'
pseudo-protocol with data specific to IPv6 unicast.";
container ipv6 {
description
"Configuration of a 'static' pseudo-protocol instance
consists of a list of routes.";
list route {
key "destination-prefix";
ordered-by "user";
description
"A user-ordered list of static routes.";
leaf destination-prefix {
type inet:ipv6-prefix;
mandatory "true";
description
"IPv6 destination prefix.";
}
leaf description {
type string;
description
"Textual description of the route.";
}
container next-hop {
description
"Configuration of next-hop.";
grouping next-hop-content {
description
"Next-hop content for IPv6 unicast static routes.";
uses rt:next-hop-content {
augment "next-hop-options" {
description
"Add next-hop address case.";
leaf next-hop-address {
type inet:ipv6-address;
description
"IPv6 address of the next-hop.";
}
}
}
}
choice simple-or-list {
description
"Options for next-hops.";
list multipath-entry {
if-feature rt:multipath-routes;
key "name";
description
"List of alternative next-hops.";
leaf name {
type string;
description
"A unique identifier of the next-hop entry.";
}
uses next-hop-content;
uses rt:next-hop-classifiers;
}
case simple-next-hop {
uses next-hop-content;
}
}
}
}
}
}
/* RPC methods */
augment "/rt:fib-route/rt:input/rt:destination-address" {
when "rt:address-family='v6ur:ipv6-unicast'" {
description
"This augment is valid only for IPv6 unicast.";
}
description
"This leaf augments the 'rt:destination-address' parameter of
the 'rt:fib-route' operation.";
leaf address {
type inet:ipv6-address;
description
"IPv6 destination address.";
}
}
augment "/rt:fib-route/rt:output/rt:route" {
when "rt:address-family='v6ur:ipv6-unicast'" {
description
"This augment is valid only for IPv6 unicast.";
}
description
"This leaf augments the reply to the 'rt:fib-route'
operation.";
leaf destination-prefix {
type inet:ipv6-prefix;
description
"IPv6 destination prefix.";
}
}
augment "/rt:fib-route/rt:output/rt:route/rt:next-hop/"
+ "rt:next-hop-options/rt:simple-next-hop" {
when "../rt:address-family='v4ur:ipv6-unicast'" {
description
"This augment is valid only for IPv6 unicast.";
}
description
"This leaf augments the 'simple-next-hop' case in the reply to
the 'rt:fib-route' operation.";
leaf next-hop-address {
type inet:ipv6-address;
description
"IPv6 address of the next-hop.";
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,481 @@
module ietf-yang-types {
namespace "urn:ietf:params:xml:ns:yang:ietf-yang-types";
prefix "yang";
organization
"IETF NETMOD (NETCONF Data Modeling Language) Working Group";
contact
"WG Web: <http://tools.ietf.org/wg/netmod/>
WG List: <mailto:netmod@ietf.org>
WG Chair: David Kessens
<mailto:david.kessens@nsn.com>
WG Chair: Juergen Schoenwaelder
<mailto:j.schoenwaelder@jacobs-university.de>
Editor: Juergen Schoenwaelder
<mailto:j.schoenwaelder@jacobs-university.de>";
description
"This module contains a collection of generally useful derived
YANG data types.
Copyright (c) 2013 IETF Trust and the persons identified as
authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject
to the license terms contained in, the Simplified BSD License
set forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(http://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC 6991; see
the RFC itself for full legal notices.";
revision 2013-07-15 {
description
"This revision adds the following new data types:
- yang-identifier
- hex-string
- uuid
- dotted-quad";
reference
"RFC 6991: Common YANG Data Types";
}
revision 2010-09-24 {
description
"Initial revision.";
reference
"RFC 6021: Common YANG Data Types";
}
/*** collection of counter and gauge types ***/
typedef counter32 {
type uint32;
description
"The counter32 type represents a non-negative integer
that monotonically increases until it reaches a
maximum value of 2^32-1 (4294967295 decimal), when it
wraps around and starts increasing again from zero.
Counters have no defined 'initial' value, and thus, a
single value of a counter has (in general) no information
content. Discontinuities in the monotonically increasing
value normally occur at re-initialization of the
management system, and at other times as specified in the
description of a schema node using this type. If such
other times can occur, for example, the creation of
a schema node of type counter32 at times other than
re-initialization, then a corresponding schema node
should be defined, with an appropriate type, to indicate
the last discontinuity.
The counter32 type should not be used for configuration
schema nodes. A default statement SHOULD NOT be used in
combination with the type counter32.
In the value set and its semantics, this type is equivalent
to the Counter32 type of the SMIv2.";
reference
"RFC 2578: Structure of Management Information Version 2
(SMIv2)";
}
typedef zero-based-counter32 {
type yang:counter32;
default "0";
description
"The zero-based-counter32 type represents a counter32
that has the defined 'initial' value zero.
A schema node of this type will be set to zero (0) on creation
and will thereafter increase monotonically until it reaches
a maximum value of 2^32-1 (4294967295 decimal), when it
wraps around and starts increasing again from zero.
Provided that an application discovers a new schema node
of this type within the minimum time to wrap, it can use the
'initial' value as a delta. It is important for a management
station to be aware of this minimum time and the actual time
between polls, and to discard data if the actual time is too
long or there is no defined minimum time.
In the value set and its semantics, this type is equivalent
to the ZeroBasedCounter32 textual convention of the SMIv2.";
reference
"RFC 4502: Remote Network Monitoring Management Information
Base Version 2";
}
typedef counter64 {
type uint64;
description
"The counter64 type represents a non-negative integer
that monotonically increases until it reaches a
maximum value of 2^64-1 (18446744073709551615 decimal),
when it wraps around and starts increasing again from zero.
Counters have no defined 'initial' value, and thus, a
single value of a counter has (in general) no information
content. Discontinuities in the monotonically increasing
value normally occur at re-initialization of the
management system, and at other times as specified in the
description of a schema node using this type. If such
other times can occur, for example, the creation of
a schema node of type counter64 at times other than
re-initialization, then a corresponding schema node
should be defined, with an appropriate type, to indicate
the last discontinuity.
The counter64 type should not be used for configuration
schema nodes. A default statement SHOULD NOT be used in
combination with the type counter64.
In the value set and its semantics, this type is equivalent
to the Counter64 type of the SMIv2.";
reference
"RFC 2578: Structure of Management Information Version 2
(SMIv2)";
}
typedef zero-based-counter64 {
type yang:counter64;
default "0";
description
"The zero-based-counter64 type represents a counter64 that
has the defined 'initial' value zero.
A schema node of this type will be set to zero (0) on creation
and will thereafter increase monotonically until it reaches
a maximum value of 2^64-1 (18446744073709551615 decimal),
when it wraps around and starts increasing again from zero.
Provided that an application discovers a new schema node
of this type within the minimum time to wrap, it can use the
'initial' value as a delta. It is important for a management
station to be aware of this minimum time and the actual time
between polls, and to discard data if the actual time is too
long or there is no defined minimum time.
In the value set and its semantics, this type is equivalent
to the ZeroBasedCounter64 textual convention of the SMIv2.";
reference
"RFC 2856: Textual Conventions for Additional High Capacity
Data Types";
}
typedef gauge32 {
type uint32;
description
"The gauge32 type represents a non-negative integer, which
may increase or decrease, but shall never exceed a maximum
value, nor fall below a minimum value. The maximum value
cannot be greater than 2^32-1 (4294967295 decimal), and
the minimum value cannot be smaller than 0. The value of
a gauge32 has its maximum value whenever the information
being modeled is greater than or equal to its maximum
value, and has its minimum value whenever the information
being modeled is smaller than or equal to its minimum value.
If the information being modeled subsequently decreases
below (increases above) the maximum (minimum) value, the
gauge32 also decreases (increases).
In the value set and its semantics, this type is equivalent
to the Gauge32 type of the SMIv2.";
reference
"RFC 2578: Structure of Management Information Version 2
(SMIv2)";
}
typedef gauge64 {
type uint64;
description
"The gauge64 type represents a non-negative integer, which
may increase or decrease, but shall never exceed a maximum
value, nor fall below a minimum value. The maximum value
cannot be greater than 2^64-1 (18446744073709551615), and
the minimum value cannot be smaller than 0. The value of
a gauge64 has its maximum value whenever the information
being modeled is greater than or equal to its maximum
value, and has its minimum value whenever the information
being modeled is smaller than or equal to its minimum value.
If the information being modeled subsequently decreases
below (increases above) the maximum (minimum) value, the
gauge64 also decreases (increases).
In the value set and its semantics, this type is equivalent
to the CounterBasedGauge64 SMIv2 textual convention defined
in RFC 2856";
reference
"RFC 2856: Textual Conventions for Additional High Capacity
Data Types";
}
/*** collection of identifier-related types ***/
typedef object-identifier {
type string {
pattern '(([0-1](\.[1-3]?[0-9]))|(2\.(0|([1-9]\d*))))'
+ '(\.(0|([1-9]\d*)))*';
}
description
"The object-identifier type represents administratively
assigned names in a registration-hierarchical-name tree.
Values of this type are denoted as a sequence of numerical
non-negative sub-identifier values. Each sub-identifier
value MUST NOT exceed 2^32-1 (4294967295). Sub-identifiers
are separated by single dots and without any intermediate
whitespace.
The ASN.1 standard restricts the value space of the first
sub-identifier to 0, 1, or 2. Furthermore, the value space
of the second sub-identifier is restricted to the range
0 to 39 if the first sub-identifier is 0 or 1. Finally,
the ASN.1 standard requires that an object identifier
has always at least two sub-identifiers. The pattern
captures these restrictions.
Although the number of sub-identifiers is not limited,
module designers should realize that there may be
implementations that stick with the SMIv2 limit of 128
sub-identifiers.
This type is a superset of the SMIv2 OBJECT IDENTIFIER type
since it is not restricted to 128 sub-identifiers. Hence,
this type SHOULD NOT be used to represent the SMIv2 OBJECT
IDENTIFIER type; the object-identifier-128 type SHOULD be
used instead.";
reference
"ISO9834-1: Information technology -- Open Systems
Interconnection -- Procedures for the operation of OSI
Registration Authorities: General procedures and top
arcs of the ASN.1 Object Identifier tree";
}
typedef object-identifier-128 {
type object-identifier {
pattern '\d*(\.\d*){1,127}';
}
description
"This type represents object-identifiers restricted to 128
sub-identifiers.
In the value set and its semantics, this type is equivalent
to the OBJECT IDENTIFIER type of the SMIv2.";
reference
"RFC 2578: Structure of Management Information Version 2
(SMIv2)";
}
typedef yang-identifier {
type string {
length "1..max";
pattern '[a-zA-Z_][a-zA-Z0-9\-_.]*';
pattern '.|..|[^xX].*|.[^mM].*|..[^lL].*';
}
description
"A YANG identifier string as defined by the 'identifier'
rule in Section 12 of RFC 6020. An identifier must
start with an alphabetic character or an underscore
followed by an arbitrary sequence of alphabetic or
numeric characters, underscores, hyphens, or dots.
A YANG identifier MUST NOT start with any possible
combination of the lowercase or uppercase character
sequence 'xml'.";
reference
"RFC 6020: YANG - A Data Modeling Language for the Network
Configuration Protocol (NETCONF)";
}
/*** collection of types related to date and time***/
typedef date-and-time {
type string {
pattern '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?'
+ '(Z|[\+\-]\d{2}:\d{2})';
}
description
"The date-and-time type is a profile of the ISO 8601
standard for representation of dates and times using the
Gregorian calendar. The profile is defined by the
date-time production in Section 5.6 of RFC 3339.
The date-and-time type is compatible with the dateTime XML
schema type with the following notable exceptions:
(a) The date-and-time type does not allow negative years.
(b) The date-and-time time-offset -00:00 indicates an unknown
time zone (see RFC 3339) while -00:00 and +00:00 and Z
all represent the same time zone in dateTime.
(c) The canonical format (see below) of data-and-time values
differs from the canonical format used by the dateTime XML
schema type, which requires all times to be in UTC using
the time-offset 'Z'.
This type is not equivalent to the DateAndTime textual
convention of the SMIv2 since RFC 3339 uses a different
separator between full-date and full-time and provides
higher resolution of time-secfrac.
The canonical format for date-and-time values with a known time
zone uses a numeric time zone offset that is calculated using
the device's configured known offset to UTC time. A change of
the device's offset to UTC time will cause date-and-time values
to change accordingly. Such changes might happen periodically
in case a server follows automatically daylight saving time
(DST) time zone offset changes. The canonical format for
date-and-time values with an unknown time zone (usually
referring to the notion of local time) uses the time-offset
-00:00.";
reference
"RFC 3339: Date and Time on the Internet: Timestamps
RFC 2579: Textual Conventions for SMIv2
XSD-TYPES: XML Schema Part 2: Datatypes Second Edition";
}
typedef timeticks {
type uint32;
description
"The timeticks type represents a non-negative integer that
represents the time, modulo 2^32 (4294967296 decimal), in
hundredths of a second between two epochs. When a schema
node is defined that uses this type, the description of
the schema node identifies both of the reference epochs.
In the value set and its semantics, this type is equivalent
to the TimeTicks type of the SMIv2.";
reference
"RFC 2578: Structure of Management Information Version 2
(SMIv2)";
}
typedef timestamp {
type yang:timeticks;
description
"The timestamp type represents the value of an associated
timeticks schema node at which a specific occurrence
happened. The specific occurrence must be defined in the
description of any schema node defined using this type. When
the specific occurrence occurred prior to the last time the
associated timeticks attribute was zero, then the timestamp
value is zero. Note that this requires all timestamp values
to be reset to zero when the value of the associated timeticks
attribute reaches 497+ days and wraps around to zero.
The associated timeticks schema node must be specified
in the description of any schema node using this type.
In the value set and its semantics, this type is equivalent
to the TimeStamp textual convention of the SMIv2.";
reference
"RFC 2579: Textual Conventions for SMIv2";
}
/*** collection of generic address types ***/
typedef phys-address {
type string {
pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?';
}
description
"Represents media- or physical-level addresses represented
as a sequence octets, each octet represented by two hexadecimal
numbers. Octets are separated by colons. The canonical
representation uses lowercase characters.
In the value set and its semantics, this type is equivalent
to the PhysAddress textual convention of the SMIv2.";
reference
"RFC 2579: Textual Conventions for SMIv2";
}
typedef mac-address {
type string {
pattern '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}';
}
description
"The mac-address type represents an IEEE 802 MAC address.
The canonical representation uses lowercase characters.
In the value set and its semantics, this type is equivalent
to the MacAddress textual convention of the SMIv2.";
reference
"IEEE 802: IEEE Standard for Local and Metropolitan Area
Networks: Overview and Architecture
RFC 2579: Textual Conventions for SMIv2";
}
/*** collection of XML-specific types ***/
typedef xpath1.0 {
type string;
description
"This type represents an XPATH 1.0 expression.
When a schema node is defined that uses this type, the
description of the schema node MUST specify the XPath
context in which the XPath expression is evaluated.";
reference
"XPATH: XML Path Language (XPath) Version 1.0";
}
/*** collection of string types ***/
typedef hex-string {
type string {
pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?';
}
description
"A hexadecimal string with octets represented as hex digits
separated by colons. The canonical representation uses
lowercase characters.";
}
typedef uuid {
type string {
pattern '[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-'
+ '[0-9a-fA-F]{4}-[0-9a-fA-F]{12}';
}
description
"A Universally Unique IDentifier in the string representation
defined in RFC 4122. The canonical representation uses
lowercase characters.
The following is an example of a UUID in string representation:
f81d4fae-7dec-11d0-a765-00a0c91e6bf6
";
reference
"RFC 4122: A Universally Unique IDentifier (UUID) URN
Namespace";
}
typedef dotted-quad {
type string {
pattern
'(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])';
}
description
"An unsigned 32-bit number expressed in the dotted-quad
notation, i.e., four octets written as decimal numbers
and separated with the '.' (full stop) character.";
}
}

View file

@ -0,0 +1,27 @@
# Main YANG module first parsed by parser (in CLICON_YANG_DIR). eg clicon.yang.
# Save values as XML in database instead of lvec:s.
# This is optimized for yang specified applications
# But not compatible with key-based application (eg Rost)
CLICON_DB_XML 1
# Startup CLI mode. This should match the CLICON_MODE in your startup clispec file
CLICON_CLI_MODE routing
# Option used to construct initial yang file:
# <module>[@<revision>]
# This option is only relevant if CLICON_DBSPEC_TYPE is YANG
CLICON_YANG_MODULE_MAIN ietf-ip
# Option used to construct initial yang file:
# <module>[@<revision>]
# This option is only relevant if CLICON_DBSPEC_TYPE is YANG
CLICON_YANG_MODULE_REVISION 2014-06-16
# Generate code for CLI completion of existing db symbols
# CLICON_CLI_GENMODEL_COMPLETION 0
CLICON_CLI_GENMODEL_COMPLETION 1
# How to generate and show CLI syntax: VARS|ALL
# CLICON_CLI_GENMODEL_TYPE VARS
CLICON_CLI_GENMODEL_TYPE VARS

78
example/routing_backend.c Normal file
View file

@ -0,0 +1,78 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLIXON.
CLIXON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLIXON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLIXON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
* IETF yang routing example
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
/* clicon */
#include <cligen/cligen.h>
/* Clicon library functions. */
#include <clicon/clicon.h>
/* These include signatures for plugin and transaction callbacks. */
#include <clicon/clicon_backend.h>
/*
* Commit callback.
* We do nothing here but simply create the config based on the current
* db once everything is done as if will then contain the new config.
*/
int
transaction_commit(clicon_handle h,
transaction_data td)
{
fprintf(stderr, "%s\n", __FUNCTION__);
transaction_print(stderr, td);
return 0;
}
int
transaction_validate(clicon_handle h,
transaction_data td)
{
fprintf(stderr, "%s\n", __FUNCTION__);
transaction_print(stderr, td);
return 0;
}
/*
* Plugin initialization
*/
int
plugin_init(clicon_handle h)
{
int retval = -1;
retval = 0;
// done:
return retval;
}

57
example/routing_cli.c Normal file
View file

@ -0,0 +1,57 @@
/*
*
Copyright (C) 2009-2013 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
* hello clicon cli frontend
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <syslog.h>
#include <unistd.h>
#include <assert.h>
#include <math.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <fnmatch.h> /* matching strings */
#include <signal.h> /* matching strings */
/* clicon */
#include <cligen/cligen.h>
#include <clicon/clicon.h>
#include <clicon/clicon_cli.h>
/*
* Plugin initialization
*/
int
plugin_init(clicon_handle h)
{
struct timeval tv;
gettimeofday(&tv, NULL);
srandom(tv.tv_usec);
return 0;
}

45
example/routing_cli.cli Normal file
View file

@ -0,0 +1,45 @@
# $Id: datamodel_cli.cli,v 1.2 2013/09/19 15:02:38 olof Exp $
# Common CLI syntax for both server and PMNode operatio mode
CLICON_MODE="routing";
CLICON_PROMPT="%U@%H> ";
# Note, when switching to PT, change datamodel to only @datamodel
#set @datamodel:ietf-routing, cli_merge();
#set @datamodel:ietf-ipv4-unicast-routing, cli_merge();
set @datamodel:ietf-ip, cli_merge();
#delete("Delete a configuration item") @datamodel:ietf-ipv4-unicast-routing, cli_del();
delete("Delete a configuration item") @datamodel:ietf-ip, cli_del();
validate("Validate changes"), cli_validate();
commit("Commit the changes"), cli_commit((int)0); # snapshot
quit("Quit Hello"), cli_quit();
delete("Delete a configuration item") all("Delete whole candidate configuration"), delete_all("candidate");
no("Negate or remove") debug("Debugging parts of the system"), cli_debug((int)0);
debug("Debugging parts of the system"), cli_debug((int)1);{
level("Set debug level: 1..n") <level:int32>("Set debug level (0..n)"), cli_debug();
}
discard("Discard edits (rollback 0)"), discard_changes();
show("Show a particular state of the system"){
xpath("Show configuration") <xpath:string>("XPATH expression"), show_conf_xpath("candidate");
compare("Compare candidate and running databases"), compare_dbs((int32)0);{
xml("Show comparison in xml"), compare_dbs((int32)0);
text("Show comparison in text"), compare_dbs((int32)1);
}
configuration("Show configuration"), show_conf_as_text("candidate /");{
xml("Show configuration as XML"), show_conf_as_xml("candidate /");
netconf("Show configuration as netconf edit-config operation"), show_conf_as_netconf("candidate /");
text("Show configuration as text"), show_conf_as_text("candidate /");
cli("Show configuration as cli commands"), show_conf_as_cli("candidate /");
json("Show configuration as cli commands"), show_conf_as_json("candidate /");
}
}
save("Save candidate configuration to XML file") <filename:string>("Filename (local filename)"), save_config_file("candidate filename");
load("Load configuration from XML file") <filename:string>("Filename (local filename)"),load_config_file("filename replace");{
replace("Replace candidate with file contents"), load_config_file("filename replace");
merge("Merge file with existent candidate"), load_config_file("filename merge");
}

62
example/routing_netconf.c Normal file
View file

@ -0,0 +1,62 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLIXON.
CLIXON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLIXON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLIXON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <syslog.h>
#include <unistd.h>
#include <assert.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <cligen/cligen.h>
#include <clicon/clicon.h>
#include <clicon/clicon_netconf.h>
/*
* Plugin initialization
*/
int
plugin_init(clicon_handle h)
{
return 0;
}
/*
* Plugin start
* Called once everything has been initialized, right before
* the main event loop is entered.
*/
int
plugin_start(clicon_handle h, int argc, char **argv)
{
return 0;
}
int
plugin_exit(clicon_handle h)
{
return 0;
}

49
include/Makefile.in Normal file
View file

@ -0,0 +1,49 @@
#
# Makefile
#
# Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
#
# This file is part of CLICON.
#
# CLICON is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# CLICON is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with CLICON; see the file COPYING. If not, see
# <http://www.gnu.org/licenses/>.
#
#
VPATH = @srcdir@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
prefix = @prefix@
bindir = @bindir@
localstatedir = @localstatedir@
sysconfdir = @sysconfdir@
INSTALL = @INSTALL@
all:
@echo " "
clean:
distclean: clean
rm -f clicon_config.h Makefile *~ .depend
install:
install-include:
uninstall:
depend:

122
include/clicon_config.h.in Normal file
View file

@ -0,0 +1,122 @@
/* include/clicon_config.h.in. Generated from configure.ac by autoheader. */
/* Check if extra keys inserted for database lists containing content. Eg
A.n.foo = 3 means A.3 $!a=foo exists */
#undef DB_KEYCONTENT
/* Define to 1 if you have the `alphasort' function. */
#undef HAVE_ALPHASORT
/* Define to 1 if you have the <cligen/cligen.h> header file. */
#undef HAVE_CLIGEN_CLIGEN_H
/* Define to 1 if you have the <crypt.h> header file. */
#undef HAVE_CRYPT_H
/* Define to 1 if you have the <depot.h> header file. */
#undef HAVE_DEPOT_H
/* Define to 1 if you have the `inet_aton' function. */
#undef HAVE_INET_ATON
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the `crypt' library (-lcrypt). */
#undef HAVE_LIBCRYPT
/* Define to 1 if you have the `dl' library (-ldl). */
#undef HAVE_LIBDL
/* Define to 1 if you have the `m' library (-lm). */
#undef HAVE_LIBM
/* Define to 1 if you have the `nsl' library (-lnsl). */
#undef HAVE_LIBNSL
/* Define to 1 if you have the `qdbm' library (-lqdbm). */
#undef HAVE_LIBQDBM
/* Define to 1 if you have the `socket' library (-lsocket). */
#undef HAVE_LIBSOCKET
/* Define to 1 if you have the <linux/if_vlan.h> header file. */
#undef HAVE_LINUX_IF_VLAN_H
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the <qdbm/depot.h> header file. */
#undef HAVE_QDBM_DEPOT_H
/* Define to 1 if you have the `sigaction' function. */
#undef HAVE_SIGACTION
/* Define to 1 if you have the `sigvec' function. */
#undef HAVE_SIGVEC
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the `strlcpy' function. */
#undef HAVE_STRLCPY
/* Define to 1 if you have the `strndup' function. */
#undef HAVE_STRNDUP
/* Define to 1 if you have the `strsep' function. */
#undef HAVE_STRSEP
/* Define to 1 if you have the `strverscmp' function. */
#undef HAVE_STRVERSCMP
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the <sys/ucred.h> header file. */
#undef HAVE_SYS_UCRED_H
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to 1 if you have the `versionsort' function. */
#undef HAVE_VERSIONSORT
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
`char[]'. */
#undef YYTEXT_POINTER
#include <clicon_custom.h>

33
include/clicon_custom.h Normal file
View file

@ -0,0 +1,33 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
Custom file as boilerplate appended by clicon_config.h
*/
#ifndef HAVE_STRNDUP
#define strndup(s, n) clicon_strndup(s, n)
#endif
#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
#define BSD
/* at least for openbsd 4.5 i cannot get a hdr file */
int strverscmp (__const char *__s1, __const char *__s2);
#endif

250
install-sh Executable file
View file

@ -0,0 +1,250 @@
#! /bin/sh
#
# install - install a program, script, or datafile
# This comes from X11R5 (mit/util/scripts/install.sh).
#
# Copyright 1991 by the Massachusetts Institute of Technology
#
# Permission to use, copy, modify, distribute, and sell this software and its
# documentation for any purpose is hereby granted without fee, provided that
# the above copyright notice appear in all copies and that both that
# copyright notice and this permission notice appear in supporting
# documentation, and that the name of M.I.T. not be used in advertising or
# publicity pertaining to distribution of the software without specific,
# written prior permission. M.I.T. makes no representations about the
# suitability of this software for any purpose. It is provided "as is"
# without express or implied warranty.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch. It can only install one file at a time, a restriction
# shared with many OS's install programs.
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
# put in absolute paths if you don't have them in your path; or use env. vars.
mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
transformbasename=""
transform_arg=""
instcmd="$mvprog"
chmodcmd="$chmodprog 0755"
chowncmd=""
chgrpcmd=""
stripcmd=""
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=""
dst=""
dir_arg=""
while [ x"$1" != x ]; do
case $1 in
-c) instcmd="$cpprog"
shift
continue;;
-d) dir_arg=true
shift
continue;;
-m) chmodcmd="$chmodprog $2"
shift
shift
continue;;
-o) chowncmd="$chownprog $2"
shift
shift
continue;;
-g) chgrpcmd="$chgrpprog $2"
shift
shift
continue;;
-s) stripcmd="$stripprog"
shift
continue;;
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
shift
continue;;
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
shift
continue;;
*) if [ x"$src" = x ]
then
src=$1
else
# this colon is to work around a 386BSD /bin/sh bug
:
dst=$1
fi
shift
continue;;
esac
done
if [ x"$src" = x ]
then
echo "install: no input file specified"
exit 1
else
true
fi
if [ x"$dir_arg" != x ]; then
dst=$src
src=""
if [ -d $dst ]; then
instcmd=:
else
instcmd=mkdir
fi
else
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if [ -f $src -o -d $src ]
then
true
else
echo "install: $src does not exist"
exit 1
fi
if [ x"$dst" = x ]
then
echo "install: no destination specified"
exit 1
else
true
fi
# If destination is a directory, append the input filename; if your system
# does not like double slashes in filenames, you may need to add some logic
if [ -d $dst ]
then
dst="$dst"/`basename $src`
else
true
fi
fi
## this sed command emulates the dirname command
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
# Make sure that the destination directory exists.
# this part is taken from Noah Friedman's mkinstalldirs script
# Skip lots of stat calls in the usual case.
if [ ! -d "$dstdir" ]; then
defaultIFS='
'
IFS="${IFS-${defaultIFS}}"
oIFS="${IFS}"
# Some sh's can't handle IFS=/ for some reason.
IFS='%'
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
IFS="${oIFS}"
pathcomp=''
while [ $# -ne 0 ] ; do
pathcomp="${pathcomp}${1}"
shift
if [ ! -d "${pathcomp}" ] ;
then
$mkdirprog "${pathcomp}"
else
true
fi
pathcomp="${pathcomp}/"
done
fi
if [ x"$dir_arg" != x ]
then
$doit $instcmd $dst &&
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
else
# If we're going to rename the final executable, determine the name now.
if [ x"$transformarg" = x ]
then
dstfile=`basename $dst`
else
dstfile=`basename $dst $transformbasename |
sed $transformarg`$transformbasename
fi
# don't allow the sed command to completely eliminate the filename
if [ x"$dstfile" = x ]
then
dstfile=`basename $dst`
else
true
fi
# Make a temp file name in the proper directory.
dsttmp=$dstdir/#inst.$$#
# Move or copy the file name to the temp name
$doit $instcmd $src $dsttmp &&
trap "rm -f ${dsttmp}" 0 &&
# and set any options; do chmod last to preserve setuid bits
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $instcmd $src $dsttmp" command.
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
# Now rename the file to the real destination.
$doit $rmcmd -f $dstdir/$dstfile &&
$doit $mvcmd $dsttmp $dstdir/$dstfile
fi &&
exit 0

73
lib/Makefile.in Normal file
View file

@ -0,0 +1,73 @@
#
# Makefile
#
# Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
#
# This file is part of CLICON.
#
# CLICON is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# CLICON is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with CLICON; see the file COPYING. If not, see
# <http://www.gnu.org/licenses/>.
#
#
VPATH = @srcdir@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
CC = @CC@
CFLAGS = @CFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
SHELL = /bin/sh
SUBDIRS = src clicon
.PHONY: all clean depend $(SUBDIRS) install
all: $(SUBDIRS)
depend:
for i in $(SUBDIRS); \
do (cd $$i; $(MAKE) $(MFLAGS) depend); done
$(SUBDIRS):
(cd $@; $(MAKE) $(MFLAGS) all)
install:
for i in $(SUBDIRS); \
do (cd $$i; $(MAKE) $(MFLAGS) $@); done
install-include:
for i in $(SUBDIRS); \
do (cd $$i; $(MAKE) $(MFLAGS) $@); done; \
(cd clicon; $(MAKE) $(MFLAGS) $@)
uninstall:
for i in $(SUBDIRS); \
do (cd $$i; $(MAKE) $(MFLAGS) $@); done
config.status: configure
$(SHELL) config.status --recheck
clean:
for i in $(SUBDIRS); \
do (cd $$i; $(MAKE) $(MFLAGS) clean); done
distclean: clean
rm -f Makefile *~ .depend
for i in $(SUBDIRS); \
do (cd $$i; $(MAKE) $(MFLAGS) distclean); done; \
(cd clicon; $(MAKE) $(MFLAGS) $@)
tags:
find $(srcdir) -name '*.[chyl]' -print | etags -

44
lib/clicon/Makefile.in Normal file
View file

@ -0,0 +1,44 @@
#
# Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
#
# This file is part of CLICON.
#
# CLICON is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# CLICON is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with CLICON; see the file COPYING. If not, see
# <http://www.gnu.org/licenses/>.
#
prefix = @prefix@
includedir = @includedir@
.PHONY: install-include
all:
depend:
install:
install-include:
install -m 755 -d $(DESTDIR)$(includedir)/clicon
install -m 644 *.h $(DESTDIR)$(includedir)/clicon
uninstall:
rm -f $(includedir)/clicon
clean:
distclean:
rm -f Makefile clicon.h

78
lib/clicon/clicon.h.in Normal file
View file

@ -0,0 +1,78 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
* Meta-include file that includes all sub-files in control-lib
* Note: this include files is for external purposes. Do not include this
* file in clicon lib-routines.
*/
/* This include file requires the following include file dependencies */
#include <stdio.h>
#include <stdint.h>
#include <dirent.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
/*
* CLICON version macros
*/
#undef CLICON_VERSION_STRING
#undef CLICON_VERSION_MAJOR
#undef CLICON_VERSION_MINOR
#undef CLICON_VERSION_PATCH
/*
* Use this constant to disable some prototypes that should not be visible outside the lib.
* This is an alternative to use separate internal include files.
*/
#define LIBCLICON_API 1
#include <clicon/clicon_sig.h>
#include <clicon/clicon_log.h>
#include <clicon/clicon_err.h>
#include <clicon/clicon_queue.h>
#include <clicon/clicon_hash.h>
#include <clicon/clicon_handle.h>
#include <clicon/clicon_qdb.h>
#include <clicon/clicon_yang.h>
#include <clicon/clicon_yang_type.h>
#include <clicon/clicon_chunk.h>
#include <clicon/clicon_event.h>
#include <clicon/clicon_string.h>
#include <clicon/clicon_file.h>
#include <clicon/clicon_xml.h>
#include <clicon/clicon_proto.h>
#include <clicon/clicon_proto_encode.h>
#include <clicon/clicon_proto_client.h>
#include <clicon/clicon_proc.h>
#include <clicon/clicon_options.h>
#include <clicon/clicon_xml_map.h>
#include <clicon/clicon_xml_db.h>
#include <clicon/clicon_xsl.h>
#include <clicon/clicon_plugin.h>
#include <clicon/clicon_plugin.h>
/*
* Global variables generated by Makefile
*/
extern const char CLICON_BUILDSTR[];
extern const char CLICON_VERSION[];

166
lib/clicon/clicon_chunk.h Normal file
View file

@ -0,0 +1,166 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
* Copyright (C) 2002 Benny Holmgren, All rights reserved
*/
#ifndef _CLICON_CHUNK_H_
#define _CLICON_CHUNK_H_
/*
* Compile with chunk diagnostics. XXX Should be in Makefile.in ??
*/
#define CHUNK_DIAG
/*
* Base number of bits to shift getting the size of a chunk_head.
*/
#define CHUNK_BASE 6
/*
* Number of predefined chunk sizes. I.e. the number of chunk heads in the
* chunk_heads vector.
*/
#define CHUNK_HEADS (32 - CHUNK_BASE)
#ifdef CHUNK_DIAG
/*
* Chunk diagnostics
*/
typedef struct _chunk_diag_t {
const char *cd_file; /* File which requested chunk */
int cd_line; /* Line in requesting file */
} chunk_diag_t;
#endif /* CHUNK_DIAG */
/*
* The block header.
*/
struct _chunk_head_t;
typedef struct _chunk_head_t chunk_head_t;
typedef struct _chunk_block_t {
qelem_t cb_qelem; /* Circular queue of blocks */
chunk_head_t *cb_head; /* The chunk head I belong to */
void *cb_blk; /* Allocated memory block */
uint16_t cb_ref; /* Number of used chunks of block */
} chunk_block_t;
/*
* The chunk header.
*/
struct _chunk_grpent_t;
typedef struct _chunk_grpent_t chunk_grpent_t;
typedef struct _chunk_t {
qelem_t c_qelem; /* Circular queue of chunks */
chunk_block_t *c_blk; /* The block I belong to */
#ifdef CHUNK_DIAG
chunk_diag_t c_diag; /* The diagnostics structure */
#endif /* CHUNK_DIAG */
chunk_grpent_t *c_grpent;
} chunk_t;
/*
* The head of a chunk size. Each predefined size has it's own head keeping
* track of all blocks and chunks for the size.
*/
struct _chunk_head_t {
size_t ch_size; /* Chunk size */
int ch_nchkperblk; /* Number pf chunks per block */
size_t ch_blksz; /* Size of a block */
int ch_nblks; /* Number of allocated blocks */
chunk_block_t *ch_blks; /* Circular list of blocks */
chunk_t *ch_cnks; /* Circular list of chunks in use */
size_t ch_nfree; /* Number of free chunks */
chunk_t *ch_free; /* Circular list of free chunks */
};
/*
* The chunk group structure.
*/
typedef struct _chunk_group_t {
qelem_t cg_qelem; /* List of chunk groups */
char *cg_name; /* Name of group */
chunk_grpent_t *cg_ent; /* List of chunks in the group */
} chunk_group_t;
/*
* The chunk group entry structure.
*/
struct _chunk_grpent_t {
qelem_t ce_qelem; /* Circular list of entries */
chunk_group_t *ce_grp; /* The group I belong to */
chunk_t *ce_cnk; /* Pointer to the chunk */
};
/*
* Public function declarations
*/
#ifdef CHUNK_DIAG
void *_chunk (size_t, const char *, const char *, int);
#define chunk(siz,label) _chunk((siz),(label),__FILE__,__LINE__)
void *_rechunk (void *, size_t, const char *, const char *, int);
#define rechunk(ptr,siz,label) _rechunk((ptr),(siz),(label),__FILE__,__LINE__)
void *_chunkdup (const void *, size_t, const char *, const char *, int);
#define chunkdup(ptr,siz,label) _chunkdup((ptr),(siz),(label),__FILE__,__LINE__)
char *_chunk_strncat (const char *, const char *, size_t, const char *, const char *, int);
#define chunk_strncat(str,new,n,label) _chunk_strncat((str),(new),(n),(label),__FILE__,__LINE__)
char *_chunk_sprintf (const char *, const char *, int, const char *, ...);
#define chunk_sprintf(label,fmt,...) _chunk_sprintf((label),__FILE__,__LINE__,(fmt),__VA_ARGS__)
#else /* CHUNK_DIAG */
void *chunk (size_t, const char *);
void *rechunk (void *, size_t, const char *);
void *chunkdup (void *, size_t, const char *);
char *chunk_strncat (const char *, const char *, size_t, const char *);
char *chunk_sprintf (const char *, char *, ...);
#endif /* CHUNK_DIAG */
void unchunk (void *);
void unchunk_group (const char *);
void chunk_check (FILE *, const char *);
size_t chunksize (void *);
#endif /* _CLICON_CHUNK_H_ */

80
lib/clicon/clicon_err.h Normal file
View file

@ -0,0 +1,80 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
* Errors may be syslogged using LOG_ERR, and printed to stderr, as controlled by
* clicon_log_init
* global error variables are set:
* clicon_errno, clicon_suberrno, clicon_err_reason.
*/
#ifndef _CLICON_ERR_H_
#define _CLICON_ERR_H_
/*
* Constants
*/
#define ERR_STRLEN 256
/*
* Types
* Add error here, but must also add an entry in EV variable.
*/
enum clicon_err{
/* 0 means error not set) */
OE_DB = 1, /* database registries */
OE_DEMON, /* demons: pidfiles, etc */
OE_EVENTS, /* events, filedescriptors, timeouts */
OE_CFG, /* config commit / quagga */
OE_PROTO, /* config/client communication */
OE_REGEX, /* Regexp error */
OE_UNIX, /* unix/linux syscall error */
OE_SYSLOG, /* syslog error */
OE_ROUTING, /* routing daemon error (eg quagga) */
OE_XML, /* xml parsing etc */
OE_PLUGIN, /* plugin loading, etc */
OE_YANG , /* Yang error */
OE_FATAL, /* Fatal error */
OE_UNDEF,
};
/*
* Variables
* XXX: should not be global
*/
extern int clicon_errno; /* CLICON errors (see clicon_err) */
extern int clicon_suberrno; /* Eg orig errno */
extern char clicon_err_reason[ERR_STRLEN];
/*
* Macros
*/
#define clicon_err(e,s,_fmt, args...) clicon_err_fn(__FUNCTION__, __LINE__, (e), (s), _fmt , ##args)
/*
* Prototypes
*/
int clicon_err_reset(void);
int clicon_err_fn(const char *fn, const int line, int level, int err, char *format, ...);
char *clicon_strerror(int err);
void *clicon_err_save(void);
int clicon_err_restore(void *handle);
#endif /* _CLICON_ERR_H_ */

46
lib/clicon/clicon_event.h Normal file
View file

@ -0,0 +1,46 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
* Event handling and loop
*/
#ifndef _CLICON_EVENT_H_
#define _CLICON_EVENT_H_
/*
* Prototypes
*/
int clicon_exit_set(void);
int clicon_exit_get(void);
int event_reg_fd(int fd, int (*fn)(int, void*), void *arg, char *str);
int event_unreg_fd(int s, int (*fn)(int, void*));
int event_reg_timeout(struct timeval t, int (*fn)(int, void*),
void *arg, char *str);
int event_unreg_timeout(int (*fn)(int, void*), void *arg);
int event_loop(void);
#endif /* _CLICON_EVENT_H_ */

36
lib/clicon/clicon_file.h Normal file
View file

@ -0,0 +1,36 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef _CLICON_FILE_H_
#define _CLICON_FILE_H_
char **clicon_realpath(const char *cwd, char *path, const char *label);
int clicon_file_dirent(const char *dir, struct dirent **ent,
const char *regexp, mode_t type, const char *label);
char *clicon_tmpfile(const char *label);
int file_cp(char *src, char *target);
#endif /* _CLICON_FILE_H_ */

View file

@ -0,0 +1,61 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef _CLICON_HANDLE_H_
#define _CLICON_HANDLE_H_
/*
* Types
*/
/* Common handle used in most clicon calls that you get from clicon_init().
Note that its contents is different dependending on if invoked from a
cli/backend/netconf or other plugin. But this is hidden under-the-hood.
*/
#if 1 /* SANITY CHECK */
typedef struct {float a;} *clicon_handle;
#else
typedef void *clicon_handle;
#endif
/*
* Prototypes
*/
/* Basic CLICON init functions returning a handle for API access. */
clicon_handle clicon_handle_init(void);
/* Internal call to allocate a CLICON handle. */
clicon_handle clicon_handle_init0(int size);
/* Deallocate handle */
int clicon_handle_exit(clicon_handle h);
/* Check struct magic number for sanity checks */
int clicon_handle_check(clicon_handle h);
/* Return clicon options (hash-array) given a handle.*/
clicon_hash_t *clicon_options(clicon_handle h);
/* Return internal clicon data (hash-array) given a handle.*/
clicon_hash_t *clicon_data(clicon_handle h);
#endif /* _CLICON_HANDLE_H_ */

70
lib/clicon/clicon_hash.h Normal file
View file

@ -0,0 +1,70 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef _CLICON_HASH_H_
#define _CLICON_HASH_H_
struct clicon_hash {
qelem_t h_qelem;
char *h_key;
size_t h_vlen;
void *h_val;
};
typedef struct clicon_hash *clicon_hash_t;
clicon_hash_t *hash_init (void);
void hash_free (clicon_hash_t *);
clicon_hash_t hash_lookup (clicon_hash_t *head, const char *key);
void *hash_value (clicon_hash_t *head, const char *key, size_t *vlen);
clicon_hash_t hash_add (clicon_hash_t *head, const char *key, void *val, size_t vlen);
int hash_del (clicon_hash_t *head, const char *key);
void hash_dump(clicon_hash_t *head, FILE *f);
char **hash_keys(clicon_hash_t *hash, size_t *nkeys);
/*
* Macros to iterate over hash contents.
* XXX A bit crude. Just as easy for app to loop through the keys itself.
*
* Example:
* char *k;
* clicon_hash_t *h = hash_init();
*
* hash_add(h, "colour", "red", 6);
* hash_add(h, "name", "rudolf" 7);
* hash_add(h, "species", "reindeer" 9);
*
* hash_each(h, k) {
* printf ("%s = %s\n", k, (char *)hash_value(h, k, NULL));
* } hash_each_end();
*/
#define hash_each(__hash__, __key__) \
{ \
int __i__; \
size_t __n__; \
char **__k__ = hash_keys((__hash__),&__n__); \
if (__k__) { \
for(__i__ = 0; __i__ < __n__ && ((__key__) = __k__[__i__]); __i__++)
#define hash_each_end(__hash__) if (__k__) free(__k__); } }
#endif /* _CLICON_HASH_H_ */

57
lib/clicon/clicon_log.h Normal file
View file

@ -0,0 +1,57 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
* Regular logging and debugging. Syslog using levels.
*/
#ifndef _CLICON_LOG_H_
#define _CLICON_LOG_H_
/*
* Constants
*/
#define CLICON_LOG_SYSLOG 1 /* print logs on syslog */
#define CLICON_LOG_STDERR 2 /* print logs on stderr */
#define CLICON_LOG_STDOUT 4 /* print logs on stdout */
/*
* Types
*/
typedef int (clicon_log_notify_t)(int level, char *msg, void *arg);
/*
* Variables
*/
extern int debug;
/*
* Prototypes
*/
int clicon_log_init(char *ident, int upto, int flags);
int clicon_log_str(int level, char *msg);
int clicon_log(int level, char *format, ...);
clicon_log_notify_t *clicon_log_register_callback(clicon_log_notify_t *cb, void *arg);
int clicon_debug_init(int dbglevel, FILE *f);
int clicon_debug(int dbglevel, char *format, ...);
char *mon2name(int md);
#endif /* _CLICON_LOG_H_ */

114
lib/clicon/clicon_options.h Normal file
View file

@ -0,0 +1,114 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
* Configuration file and Options.
*/
#ifndef _CLICON_OPTIONS_H_
#define _CLICON_OPTIONS_H_
/*
* Constants
*/
/* default group membership to access config unix socket */
#define CLICON_SOCK_GROUP "clicon"
/* Default name of master plugin */
#define CLICON_MASTER_PLUGIN "master"
/*
* Types
*/
/*
* enum gensyntx
* Controls how keywords a generated in CLI syntax / prints from obhect model
* Example syntax a.b[] $!x $y:
* NONE: a b <x> <y>;
* VARS: a b <x> y <y>;
* ALL: a b x <x> y <y>;
*/
enum genmodel_type{
GT_ERR =-1, /* Error */
GT_NONE=0, /* No extra keywords */
GT_VARS, /* Keywords on non-index variables */
GT_ALL, /* Keywords on all variables */
};
/*
* Prototypes
*/
/* Initialize options: set defaults, read config-file, etc */
int clicon_options_main(clicon_handle h);
void clicon_option_dump(clicon_handle h, int dblevel);
int clicon_option_exists(clicon_handle h, const char *name);
/* Get a single option via handle */
char *clicon_option_str(clicon_handle h, const char *name);
int clicon_option_int(clicon_handle h, const char *name);
/* Set a single option via handle */
int clicon_option_str_set(clicon_handle h, const char *name, char *val);
int clicon_option_int_set(clicon_handle h, const char *name, int val);
/* Delete a single option via handle */
int clicon_option_del(clicon_handle h, const char *name);
char *clicon_configfile(clicon_handle h);
char *clicon_yang_dir(clicon_handle h);
char *clicon_yang_module_main(clicon_handle h);
char *clicon_yang_module_revision(clicon_handle h);
char *clicon_running_db(clicon_handle h);
char *clicon_candidate_db(clicon_handle h);
char *clicon_backend_dir(clicon_handle h);
char *clicon_cli_dir(clicon_handle h);
char *clicon_clispec_dir(clicon_handle h);
char *clicon_netconf_dir(clicon_handle h);
char *clicon_archive_dir(clicon_handle h);
char *clicon_startup_config(clicon_handle h);
int clicon_sock_family(clicon_handle h);
char *clicon_sock(clicon_handle h);
int clicon_sock_port(clicon_handle h);
char *clicon_backend_pidfile(clicon_handle h);
char *clicon_sock_group(clicon_handle h);
char *clicon_master_plugin(clicon_handle h);
char *clicon_cli_mode(clicon_handle h);
int clicon_cli_genmodel(clicon_handle h);
int clicon_cli_varonly(clicon_handle h);
int clicon_cli_varonly_set(clicon_handle h, int val);
int clicon_cli_genmodel_completion(clicon_handle h);
char *clicon_quiet_mode(clicon_handle h);
enum genmodel_type clicon_cli_genmodel_type(clicon_handle h);
int clicon_autocommit(clicon_handle h);
int clicon_autocommit_set(clicon_handle h, int val);
int clicon_commit_order(clicon_handle h);
yang_spec * clicon_dbspec_yang(clicon_handle h);
int clicon_dbspec_yang_set(clicon_handle h, struct yang_spec *ys);
char *clicon_dbspec_name(clicon_handle h);
int clicon_dbspec_name_set(clicon_handle h, char *name);
#endif /* _CLICON_OPTIONS_H_ */

View file

@ -0,0 +1,67 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*/
/*
* Internal prototypes, not accessed by plugin client code
*/
#ifndef _CLICON_PLUGIN_H_
#define _CLICON_PLUGIN_H_
/*
* Types
*/
/* The dynamicically loadable plugin object handle */
typedef void *plghndl_t;
/* Find plugin by name callback. XXX Should be clicon internal */
typedef void *(find_plugin_t)(clicon_handle, char *);
/*
* Prototypes
*/
/* Common plugin function names, function types and signatures.
* This set of plugins is extended in
* Cli see cli_plugin.c
* Backend see config_plugin.c
*/
/*! Called when plugin loaded. Only mandadory callback. All others optional
* @see plginit_t
*/
#define PLUGIN_INIT "plugin_init"
typedef int (plginit_t)(clicon_handle); /* Plugin Init */
/* Called when backend started with cmd-line arguments from daemon call.
* @see plgstart_t
*/
#define PLUGIN_START "plugin_start"
typedef int (plgstart_t)(clicon_handle, int, char **); /* Plugin start */
/* Called just before plugin unloaded.
* @see plgexit_t
*/
#define PLUGIN_EXIT "plugin_exit"
typedef int (plgexit_t)(clicon_handle); /* Plugin exit */
/* Find a function in global namespace or a plugin. XXX clicon internal */
void *clicon_find_func(clicon_handle h, char *plugin, char *func);
#endif /* _CLICON_PLUGIN_H_ */

33
lib/clicon/clicon_proc.h Normal file
View file

@ -0,0 +1,33 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLICON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef _CLICON_PROC_H_
#define _CLICON_PROC_H_
/*
* Prototypes
*/
int clicon_proc_run (char *, void (outcb)(char *), int doerr);
int clicon_proc_daemon (char *);
int group_name2gid(char *name, gid_t *gid);
#endif /* _CLICON_PROC_H_ */

Some files were not shown because too many files have changed in this diff Show more