Inital commit
This commit is contained in:
parent
edc5e091bb
commit
d6e393ea58
145 changed files with 58117 additions and 0 deletions
51
CHANGELOG
Normal file
51
CHANGELOG
Normal 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
632
COPYING
Normal 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
112
Makefile.in
Normal 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
72
README
Normal 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
68
README.develop
Normal 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
31
README.doxygen
Normal 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
37
README.md
Normal 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
68
apps/Makefile.in
Normal 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
137
apps/backend/Makefile.in
Normal 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
|
||||||
|
|
||||||
1066
apps/backend/backend_client.c
Normal file
1066
apps/backend/backend_client.c
Normal file
File diff suppressed because it is too large
Load diff
64
apps/backend/backend_client.h
Normal file
64
apps/backend/backend_client.h
Normal 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_ */
|
||||||
684
apps/backend/backend_commit.c
Normal file
684
apps/backend/backend_commit.c
Normal 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 */
|
||||||
34
apps/backend/backend_commit.h
Normal file
34
apps/backend/backend_commit.h
Normal 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_ */
|
||||||
43
apps/backend/backend_handle.h
Normal file
43
apps/backend/backend_handle.h
Normal 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_ */
|
||||||
95
apps/backend/backend_lock.c
Normal file
95
apps/backend/backend_lock.c
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
37
apps/backend/backend_lock.h
Normal file
37
apps/backend/backend_lock.h
Normal 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
617
apps/backend/backend_main.c
Normal 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;
|
||||||
|
}
|
||||||
751
apps/backend/backend_plugin.c
Normal file
751
apps/backend/backend_plugin.c
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
72
apps/backend/backend_plugin.h
Normal file
72
apps/backend/backend_plugin.h
Normal 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_ */
|
||||||
262
apps/backend/backend_socket.c
Normal file
262
apps/backend/backend_socket.c
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
33
apps/backend/backend_socket.h
Normal file
33
apps/backend/backend_socket.h
Normal 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_ */
|
||||||
92
apps/backend/clicon_backend.h
Normal file
92
apps/backend/clicon_backend.h
Normal 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_ */
|
||||||
353
apps/backend/clicon_backend_handle.c
Normal file
353
apps/backend/clicon_backend_handle.c
Normal 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;
|
||||||
|
}
|
||||||
71
apps/backend/clicon_backend_handle.h
Normal file
71
apps/backend/clicon_backend_handle.h
Normal 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_ */
|
||||||
206
apps/backend/clicon_backend_transaction.c
Normal file
206
apps/backend/clicon_backend_transaction.c
Normal 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;
|
||||||
|
}
|
||||||
60
apps/backend/clicon_backend_transaction.h
Normal file
60
apps/backend/clicon_backend_transaction.h
Normal 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_ */
|
||||||
BIN
apps/backend/clicon_transaction_api.o
Normal file
BIN
apps/backend/clicon_transaction_api.o
Normal file
Binary file not shown.
134
apps/cli/Makefile.in
Normal file
134
apps/cli/Makefile.in
Normal 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
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
33
apps/cli/cli_common.h
Normal 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
689
apps/cli/cli_generate.c
Normal 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
32
apps/cli/cli_generate.h
Normal 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
295
apps/cli/cli_handle.c
Normal 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
58
apps/cli/cli_handle.h
Normal 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
407
apps/cli/cli_main.c
Normal 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
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
90
apps/cli/cli_plugin.h
Normal 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
59
apps/cli/clicon_cli.h
Normal 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
113
apps/cli/clicon_cli_api.h
Normal 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
99
apps/dbctrl/Makefile.in
Normal 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
241
apps/dbctrl/dbctrl_main.c
Normal 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
122
apps/netconf/Makefile.in
Normal 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
|
||||||
|
|
||||||
73
apps/netconf/clicon_netconf.h
Normal file
73
apps/netconf/clicon_netconf.h
Normal 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_ */
|
||||||
633
apps/netconf/netconf_filter.c
Normal file
633
apps/netconf/netconf_filter.c
Normal 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 */
|
||||||
36
apps/netconf/netconf_filter.h
Normal file
36
apps/netconf/netconf_filter.h
Normal 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_ */
|
||||||
118
apps/netconf/netconf_hello.c
Normal file
118
apps/netconf/netconf_hello.c
Normal 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;
|
||||||
|
}
|
||||||
34
apps/netconf/netconf_hello.h
Normal file
34
apps/netconf/netconf_hello.h
Normal 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
261
apps/netconf/netconf_lib.c
Normal 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;
|
||||||
|
}
|
||||||
75
apps/netconf/netconf_lib.h
Normal file
75
apps/netconf/netconf_lib.h
Normal 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
425
apps/netconf/netconf_main.c
Normal 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;
|
||||||
|
}
|
||||||
277
apps/netconf/netconf_plugin.c
Normal file
277
apps/netconf/netconf_plugin.c
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
57
apps/netconf/netconf_plugin.h
Normal file
57
apps/netconf/netconf_plugin.h
Normal 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
1258
apps/netconf/netconf_rpc.c
Normal file
File diff suppressed because it is too large
Load diff
48
apps/netconf/netconf_rpc.h
Normal file
48
apps/netconf/netconf_rpc.h
Normal 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
5482
autom4te.cache/output.0
Normal file
File diff suppressed because it is too large
Load diff
77
autom4te.cache/requests
Normal file
77
autom4te.cache/requests
Normal 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
452
autom4te.cache/traces.0
Normal 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
124
clicon.conf.cpp.cpp
Normal 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
44
clicon.mk.cpp
Normal 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
1550
config.guess
vendored
Normal file
File diff suppressed because it is too large
Load diff
1786
config.sub
vendored
Normal file
1786
config.sub
vendored
Normal file
File diff suppressed because it is too large
Load diff
173
configure.ac
Normal file
173
configure.ac
Normal 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
2303
doc/Doxyfile
Normal file
File diff suppressed because it is too large
Load diff
2303
doc/Doxyfile.graphs
Normal file
2303
doc/Doxyfile.graphs
Normal file
File diff suppressed because it is too large
Load diff
69
doc/Makefile.in
Normal file
69
doc/Makefile.in
Normal 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
49
etc/Makefile.in
Normal 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
14
etc/README
Normal 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
13
etc/cliconrc.in
Normal 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
114
example/Makefile.in
Normal 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
27
example/README
Normal 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>]]>]]>
|
||||||
457
example/ietf-inet-types@2013-07-15.yang
Normal file
457
example/ietf-inet-types@2013-07-15.yang
Normal 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)";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
698
example/ietf-interfaces@2014-05-08.yang
Normal file
698
example/ietf-interfaces@2014-05-08.yang
Normal 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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
701
example/ietf-ip@2014-06-16.yang
Normal file
701
example/ietf-ip@2014-06-16.yang
Normal 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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
232
example/ietf-ipv4-unicast-routing@2014-10-26.yang
Normal file
232
example/ietf-ipv4-unicast-routing@2014-10-26.yang
Normal 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.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
636
example/ietf-ipv6-unicast-routing@2014-10-26.yang
Normal file
636
example/ietf-ipv6-unicast-routing@2014-10-26.yang
Normal 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.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
1112
example/ietf-routing@2014-10-26.yang
Normal file
1112
example/ietf-routing@2014-10-26.yang
Normal file
File diff suppressed because it is too large
Load diff
481
example/ietf-yang-types@2013-07-15.yang
Normal file
481
example/ietf-yang-types@2013-07-15.yang
Normal 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.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
27
example/routing.conf.local
Normal file
27
example/routing.conf.local
Normal 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
78
example/routing_backend.c
Normal 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
57
example/routing_cli.c
Normal 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
45
example/routing_cli.cli
Normal 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
62
example/routing_netconf.c
Normal 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
49
include/Makefile.in
Normal 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
122
include/clicon_config.h.in
Normal 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
33
include/clicon_custom.h
Normal 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
250
install-sh
Executable 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
73
lib/Makefile.in
Normal 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
44
lib/clicon/Makefile.in
Normal 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
78
lib/clicon/clicon.h.in
Normal 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
166
lib/clicon/clicon_chunk.h
Normal 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
80
lib/clicon/clicon_err.h
Normal 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
46
lib/clicon/clicon_event.h
Normal 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
36
lib/clicon/clicon_file.h
Normal 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_ */
|
||||||
61
lib/clicon/clicon_handle.h
Normal file
61
lib/clicon/clicon_handle.h
Normal 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
70
lib/clicon/clicon_hash.h
Normal 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
57
lib/clicon/clicon_log.h
Normal 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
114
lib/clicon/clicon_options.h
Normal 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_ */
|
||||||
67
lib/clicon/clicon_plugin.h
Normal file
67
lib/clicon/clicon_plugin.h
Normal 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
33
lib/clicon/clicon_proc.h
Normal 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
Loading…
Add table
Add a link
Reference in a new issue