Commit c0970023 authored by Francis Dupont's avatar Francis Dupont

[5-netconf-config] Added netconf syntax

parent 17272324
......@@ -57,6 +57,8 @@ nobase_dist_doc_DATA += examples/kea6/simple.json
nobase_dist_doc_DATA += examples/kea6/softwire46.json
nobase_dist_doc_DATA += examples/kea6/stateless.json
nobase_dist_doc_DATA += examples/kea6/with-ddns.json
nobase_dist_doc_DATA += examples/netconf/comments.json
nobase_dist_doc_DATA += examples/netconf/simple.json
devel:
mkdir -p html
......
// This is a example of a configuration for Netconf.
// It uses embedded (i.e., which will be included in configuration objects
// and not stripped by at lexical analysis) comments.
{
"Netconf":
{
// Global scope
"comment": "The Netconf Agent",
// In servers
"managed-servers":
{
"dhcp4":
{
"comment": "the model is mandatory",
"model": "kea-dhcp4-server",
// In control socket.
"control-socket":
{
"comment": "using unix/local socket",
"type": "unix",
"name": "/path/to/the/unix/socket-v4"
}
}
}
},
"Logging":
{
// In loggers
"loggers": [
{
"comment": "A logger",
"name": "kea-ctrl-agent"
}
]
}
}
// This is a simple example of a configuration for Netconf.
// This server provides YANG interface for all Kea servers and agent.
{
"Netconf":
{
// This map specifies how each server is managed:
// the YANG model to use and the control channel.
// Currently three control channel types are supported:
// "stdout" which output the configuration on the standard output,
// "unix" which uses the local control channel supported by
// "dhcp4" and "dhcp6" servers ("d2" support is not yet merged),
// and "http" which uses the Control agent "ca" to manage itself or
// to forward commands to "dhcp4" or "dhcp6" (same comment about "d2".
"managed-servers":
{
// This is how Netconf can communicate with the DHCPv4 server.
"dhcp4":
{
"comment": "DHCP4 server",
"model": "kea-dhcp4-server",
"control-socket":
{
"type": "unix",
"name": "/path/to/the/unix/socket-v4"
}
},
// DHCPv6 parameters.
"dhcp6":
{
"model": "kea-dhcp6-server",
"control-socket":
{
"type": "unix",
"name": "/path/to/the/unix/socket-v6"
}
},
// Currently the DHCP-DDNS (nicknamed D2) server does not support
// command channel yet.
"d2":
{
"model": "kea-dhcp-ddns",
"control-socket":
{
"type": "stdout",
"user-context": { "in-use": false }
}
},
// Of course the Control Agent (nicknamed CA) supports HTTP.
"ca":
{
"model": "kea-ctrl-agent",
"control-socket":
{
"type": "http",
"host": "127.0.0.1",
"port": 8000
}
}
},
// Netconf is able to load hook libraries that augment its operation.
// The primary functionality is the ability to add new commands.
"hooks-libraries": [
// Hook libraries list may contain more than one library.
{
// The only necessary parameter is the library filename.
"library": "/opt/local/netconf-commands.so",
// Some libraries may support parameters. Make sure you
// type this section carefully, as the CA does not validate
// it (because the format is library specific).
"parameters": {
"param1": "foo"
}
}
]
},
// Similar to other Kea components, Netconf also uses logging.
"Logging":
{
"loggers": [
{
"name": "kea-netconf",
"output_options": [
{
"output": "/var/log/kea-netconf.log",
// Several additional parameters are possible in addition
// to the typical output. Flush determines whether logger
// flushes output to a file. Maxsize determines maximum
// filesize before the file is being rotated. maxver
// specifies the maximum number of rotated files being
// kept.
"flush": true,
"maxsize": 204800,
"maxver": 4
}
],
"severity": "INFO",
"debuglevel": 0
}
]
}
}
SUBDIRS = . tests
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
......@@ -17,7 +16,7 @@ CLEANFILES = *.gcno *.gcda netconf_messages.h netconf_messages.cc s-messages
man_MANS = kea-netconf.8
DISTCLEANFILES = $(man_MANS)
EXTRA_DIST = $(man_MANS) kea-netconf.xml
#EXTRA_DIST += netconf.dox netconf_hooks.dox netconfo6.dox
#EXTRA_DIST += netconf.dox netconf_hooks.dox
#EXTRA_DIST += netconf_parser.yy
if GENERATE_DOCS
......@@ -47,18 +46,38 @@ BUILT_SOURCES = netconf_messages.h netconf_messages.cc
noinst_LTLIBRARIES = libnetconf.la
libnetconf_la_SOURCES = netconf_log.cc netconf_log.h
libnetconf_la_SOURCES += parser_context.cc parser_context.h
libnetconf_la_SOURCES += parser_context_decl.h netconf_lexer.ll
libnetconf_la_SOURCES += netconf_parser.cc netconf_parser.h
libnetconf_la_SOURCES += location.hh position.hh stack.hh
nodist_libnetconf_la_SOURCES = netconf_messages.h netconf_messages.cc
EXTRA_DIST += netconf_messages.mes
EXTRA_DIST += netconf_lexer.ll
EXTRA_DIST += netconf_parser.yy
sbin_PROGRAMS = kea-netconf
kea_netconf_SOURCES = main.cc
kea_netconf_LDADD = libnetconf.la
kea_netconf_LDADD += $(top_builddir)/src/lib/http/libkea-http.la
kea_netconf_LDADD += $(top_builddir)/src/lib/process/libkea-process.la
kea_netconf_LDADD += $(top_builddir)/src/lib/cfgrpt/libcfgrpt.la
kea_netconf_LDADD += $(top_builddir)/src/lib/yang/libkea-yang.la
kea_netconf_LDADD += $(top_builddir)/src/lib/stats/libkea-stats.la
kea_netconf_LDADD += $(top_builddir)/src/lib/config/libkea-cfgclient.la
kea_netconf_LDADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la
kea_netconf_LDADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la
kea_netconf_LDADD += $(top_builddir)/src/lib/cc/libkea-cc.la
kea_netconf_LDADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
kea_netconf_LDADD += $(top_builddir)/src/lib/dns/libkea-dns++.la
kea_netconf_LDADD += $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la
kea_netconf_LDADD += $(top_builddir)/src/lib/log/libkea-log.la
kea_netconf_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
kea_netconf_LDADD += $(top_builddir)/src/lib/util/threads/libkea-threads.la
kea_netconf_LDADD += $(top_builddir)/src/lib/util/libkea-util.la
kea_netconf_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
kea_netconf_LDADD += $(LOG4CPLUS_LIBS) $(CRYPTO_LIBS) $(BOOST_LIBS) $(SYSREPO_LIBS)
......@@ -67,7 +86,7 @@ kea_netconfdir = $(pkgdatadir)
if GENERATE_PARSER
#parser: netconf_lexer.cc location.hh position.hh stack.hh netconf_parser.cc netconf_parser.h
parser: netconf_lexer.cc location.hh position.hh stack.hh netconf_parser.cc netconf_parser.h
# @echo "Flex/bison files regenerated"
# --- Flex/Bison stuff below --------------------------------------------------
......@@ -79,11 +98,11 @@ if GENERATE_PARSER
# Call flex with -s to check that the default rule can be suppressed
# Call bison with -W to get warnings like unmarked empty rules
# Note C++11 deprecated register still used by flex < 2.6.0
#location.hh position.hh stack.hh netconf_parser.cc netconf_parser.h: netconf_parser.yy
# $(YACC) --defines=netconf_parser.h --report=all --report-file=netconf_parser.report -o netconf_parser.cc netconf_parser.yy
location.hh position.hh stack.hh netconf_parser.cc netconf_parser.h: netconf_parser.yy
$(YACC) --defines=netconf_parser.h --report=all --report-file=netconf_parser.report -o netconf_parser.cc netconf_parser.yy
#netconf_lexer.cc: netconf_lexer.ll
# $(LEX) --prefix netconf_ -o netconf_lexer.cc netconf_lexer.ll
netconf_lexer.cc: netconf_lexer.ll
$(LEX) --prefix netconf_ -o netconf_lexer.cc netconf_lexer.ll
else
......
/* Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/. */
%{ /* -*- C++ -*- */
/* Generated files do not make clang static analyser so happy */
#ifndef __clang_analyzer__
#include <cerrno>
#include <climits>
#include <cstdlib>
#include <string>
#include <netconf/parser_context.h>
#include <asiolink/io_address.h>
#include <boost/lexical_cast.hpp>
#include <exceptions/exceptions.h>
#include <cc/dhcp_config_error.h>
/* Please avoid C++ style comments (// ... eol) as they break flex 2.6.2 */
/* Work around an incompatibility in flex (at least versions
2.5.31 through 2.5.33): it generates code that does
not conform to C89. See Debian bug 333231
<http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=333231>. */
# undef yywrap
# define yywrap() 1
namespace {
bool start_token_flag = false;
isc::netconf::ParserContext::ParserType start_token_value;
unsigned int comment_start_line = 0;
using namespace isc;
using isc::netconf::NetconfParser;
};
/* To avoid the call to exit... oops! */
#define YY_FATAL_ERROR(msg) isc::netconf::ParserContext::fatal(msg)
%}
/* noyywrap disables automatic rewinding for the next file to parse. Since we
always parse only a single string, there's no need to do any wraps. And
using yywrap requires linking with -lfl, which provides the default yywrap
implementation that always returns 1 anyway. */
%option noyywrap
/* nounput simplifies the lexer, by removing support for putting a character
back into the input stream. We never use such capability anyway. */
%option nounput
/* batch means that we'll never use the generated lexer interactively. */
%option batch
/* avoid to get static global variables to remain with C++. */
/* in last resort %option reentrant */
/* Enables debug mode. To see the debug messages, one needs to also set
yy_flex_debug to 1, then the debug messages will be printed on stderr. */
%option debug
/* I have no idea what this option does, except it was specified in the bison
examples and Postgres folks added it to remove gcc 4.3 warnings. Let's
be on the safe side and keep it. */
%option noinput
%x COMMENT
%x DIR_ENTER DIR_INCLUDE DIR_EXIT
/* These are not token expressions yet, just convenience expressions that
can be used during actual token definitions. Note some can match
incorrect inputs (e.g., IP addresses) which must be checked. */
int \-?[0-9]+
blank [ \t\r]
UnicodeEscapeSequence u[0-9A-Fa-f]{4}
JSONEscapeCharacter ["\\/bfnrt]
JSONEscapeSequence {JSONEscapeCharacter}|{UnicodeEscapeSequence}
JSONStandardCharacter [^\x00-\x1f"\\]
JSONStringCharacter {JSONStandardCharacter}|\\{JSONEscapeSequence}
JSONString \"{JSONStringCharacter}*\"
/* for errors */
BadUnicodeEscapeSequence u[0-9A-Fa-f]{0,3}[^0-9A-Fa-f]
BadJSONEscapeSequence [^"\\/bfnrtu]|{BadUnicodeEscapeSequence}
ControlCharacter [\x00-\x1f]
ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
%{
/* This code run each time a pattern is matched. It updates the location
by moving it ahead by yyleng bytes. yyleng specifies the length of the
currently matched token. */
#define YY_USER_ACTION driver.loc_.columns(yyleng);
%}
%%
%{
/* This part of the code is copied over to the verbatim to the top
of the generated yylex function. Explanation:
http://www.gnu.org/software/bison/manual/html_node/Multiple-start_002dsymbols.html */
/* Code run each time yylex is called. */
driver.loc_.step();
/* We currently have 3 points of entries defined:
START_JSON - which expects any valid JSON
START_NETCONF - which expects full configuration (with outer map and Control-netconf
object in it.
START_SUB_NETCONF - which expects only content of the Control-netconf, this is
primarily useful for testing. */
if (start_token_flag) {
start_token_flag = false;
switch (start_token_value) {
case ParserContext::PARSER_JSON:
default:
return NetconfParser::make_START_JSON(driver.loc_);
case ParserContext::PARSER_NETCONF:
return NetconfParser::make_START_NETCONF(driver.loc_);
case ParserContext::PARSER_SUB_NETCONF:
return NetconfParser::make_START_SUB_NETCONF(driver.loc_);
}
}
%}
#.* ;
"//"(.*) ;
"/*" {
BEGIN(COMMENT);
comment_start_line = driver.loc_.end.line;;
}
<COMMENT>"*/" BEGIN(INITIAL);
<COMMENT>. ;
<COMMENT><<EOF>> {
isc_throw(ParseError, "Comment not closed. (/* in line " << comment_start_line);
}
"<?" BEGIN(DIR_ENTER);
<DIR_ENTER>"include" BEGIN(DIR_INCLUDE);
<DIR_INCLUDE>\"([^\"\n])+\" {
/* Include directive. */
/* Extract the filename. */
std::string tmp(yytext+1);
tmp.resize(tmp.size() - 1);
driver.includeFile(tmp);
}
<DIR_ENTER,DIR_INCLUDE,DIR_EXIT><<EOF>> {
isc_throw(ParseError, "Directive not closed.");
}
<DIR_EXIT>"?>" BEGIN(INITIAL);
<*>{blank}+ {
/* Ok, we found a with space. Let's ignore it and update loc variable. */
driver.loc_.step();
}
<*>[\n]+ {
/* Newline found. Let's update the location and continue. */
driver.loc_.lines(yyleng);
driver.loc_.step();
}
\"Netconf\" {
switch(driver.ctx_) {
case ParserContext::CONFIG:
return NetconfParser::make_NETCONF(driver.loc_);
default:
return NetconfParser::make_STRING("Netconf", driver.loc_);
}
}
\"user-context\" {
switch(driver.ctx_) {
case ParserContext::NETCONF:
case ParserContext::SERVER:
case ParserContext::CONTROL_SOCKET:
case ParserContext::LOGGERS:
return NetconfParser::make_USER_CONTEXT(driver.loc_);
default:
return NetconfParser::make_STRING("user-context", driver.loc_);
}
}
\"comment\" {
switch(driver.ctx_) {
case ParserContext::NETCONF:
case ParserContext::SERVER:
case ParserContext::CONTROL_SOCKET:
case ParserContext::LOGGERS:
return NetconfParser::make_COMMENT(driver.loc_);
default:
return NetconfParser::make_STRING("comment", driver.loc_);
}
}
\"managed-servers\" {
switch(driver.ctx_) {
case ParserContext::NETCONF:
return NetconfParser::make_MANAGED_SERVERS(driver.loc_);
default:
return NetconfParser::make_STRING("managed-servers", driver.loc_);
}
}
\"dhcp4\" {
switch(driver.ctx_) {
case ParserContext::MANAGED_SERVERS:
return NetconfParser::make_DHCP4_SERVER(driver.loc_);
default:
return NetconfParser::make_STRING("dhcp4", driver.loc_);
}
}
\"dhcp6\" {
switch(driver.ctx_) {
case ParserContext::MANAGED_SERVERS:
return NetconfParser::make_DHCP6_SERVER(driver.loc_);
default:
return NetconfParser::make_STRING("dhcp6", driver.loc_);
}
}
\"d2\" {
switch(driver.ctx_) {
case ParserContext::MANAGED_SERVERS:
return NetconfParser::make_D2_SERVER(driver.loc_);
default:
return NetconfParser::make_STRING("d2", driver.loc_);
}
}
\"ca\" {
switch(driver.ctx_) {
case ParserContext::MANAGED_SERVERS:
return NetconfParser::make_CA_SERVER(driver.loc_);
default:
return NetconfParser::make_STRING("ca", driver.loc_);
}
}
\"model\" {
switch(driver.ctx_) {
case ParserContext::SERVER:
return NetconfParser::make_MODEL(driver.loc_);
default:
return NetconfParser::make_STRING("model", driver.loc_);
}
}
\"control-socket\" {
switch(driver.ctx_) {
case ParserContext::SERVER:
return NetconfParser::make_CONTROL_SOCKET(driver.loc_);
default:
return NetconfParser::make_STRING("control-socket", driver.loc_);
}
}
\"unix\" {
switch(driver.ctx_) {
case ParserContext::SOCKET_TYPE:
return NetconfParser::make_UNIX(driver.loc_);
default:
return NetconfParser::make_STRING("unix", driver.loc_);
}
}
\"http\" {
switch(driver.ctx_) {
case ParserContext::SOCKET_TYPE:
return NetconfParser::make_HTTP(driver.loc_);
default:
return NetconfParser::make_STRING("http", driver.loc_);
}
}
\"stdout\" {
switch(driver.ctx_) {
case ParserContext::SOCKET_TYPE:
return NetconfParser::make_STDOUT(driver.loc_);
default:
return NetconfParser::make_STRING("stdout", driver.loc_);
}
}
\"name\" {
switch(driver.ctx_) {
case ParserContext::CONTROL_SOCKET:
case ParserContext::LOGGERS:
return NetconfParser::make_NAME(driver.loc_);
default:
return NetconfParser::make_STRING("name", driver.loc_);
}
}
\"type\" {
switch(driver.ctx_) {
case ParserContext::CONTROL_SOCKET:
return NetconfParser::make_TYPE(driver.loc_);
default:
return NetconfParser::make_STRING("type", driver.loc_);
}
}
\"host\" {
switch(driver.ctx_) {
case ParserContext::CONTROL_SOCKET:
return NetconfParser::make_HOST(driver.loc_);
default:
return NetconfParser::make_STRING("host", driver.loc_);
}
}
\"port\" {
switch(driver.ctx_) {
case ParserContext::CONTROL_SOCKET:
return NetconfParser::make_PORT(driver.loc_);
default:
return NetconfParser::make_STRING("port", driver.loc_);
}
}
\"hooks-libraries\" {
switch(driver.ctx_) {
case ParserContext::NETCONF:
return NetconfParser::make_HOOKS_LIBRARIES(driver.loc_);
default:
return NetconfParser::make_STRING("hooks-libraries", driver.loc_);
}
}
\"library\" {
switch(driver.ctx_) {
case ParserContext::HOOKS_LIBRARIES:
return NetconfParser::make_LIBRARY(driver.loc_);
default:
return NetconfParser::make_STRING("library", driver.loc_);
}
}
\"parameters\" {
switch(driver.ctx_) {
case ParserContext::HOOKS_LIBRARIES:
return NetconfParser::make_PARAMETERS(driver.loc_);
default:
return NetconfParser::make_STRING("parameters", driver.loc_);
}
}
\"Logging\" {
switch(driver.ctx_) {
case ParserContext::CONFIG:
return NetconfParser::make_LOGGING(driver.loc_);
default:
return NetconfParser::make_STRING("Logging", driver.loc_);
}
}
\"loggers\" {
switch(driver.ctx_) {
case ParserContext::LOGGING:
return NetconfParser::make_LOGGERS(driver.loc_);
default:
return NetconfParser::make_STRING("loggers", driver.loc_);
}
}
\"output_options\" {
switch(driver.ctx_) {
case ParserContext::LOGGERS:
return NetconfParser::make_OUTPUT_OPTIONS(driver.loc_);
default:
return NetconfParser::make_STRING("output_options", driver.loc_);
}
}
\"output\" {
switch(driver.ctx_) {
case ParserContext::OUTPUT_OPTIONS:
return NetconfParser::make_OUTPUT(driver.loc_);
default:
return NetconfParser::make_STRING("output", driver.loc_);
}
}
\"flush\" {
switch(driver.ctx_) {
case ParserContext::OUTPUT_OPTIONS:
return NetconfParser::make_FLUSH(driver.loc_);
default:
return NetconfParser::make_STRING("flush", driver.loc_);
}
}