mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-04-29 20:04:11 +00:00
Merge pull request #3361 from opensourcerouting/yang-embed-models
yang: embed models into binaries
This commit is contained in:
commit
0c9503eb4e
@ -92,6 +92,12 @@ lib_libfrr_la_SOURCES = \
|
|||||||
lib/lua.c \
|
lib/lua.c \
|
||||||
# end
|
# end
|
||||||
|
|
||||||
|
nodist_lib_libfrr_la_SOURCES = \
|
||||||
|
yang/frr-interface.yang.c \
|
||||||
|
yang/frr-route-types.yang.c \
|
||||||
|
yang/frr-module-translator.yang.c \
|
||||||
|
# end
|
||||||
|
|
||||||
vtysh_scan += \
|
vtysh_scan += \
|
||||||
$(top_srcdir)/lib/distribute.c \
|
$(top_srcdir)/lib/distribute.c \
|
||||||
$(top_srcdir)/lib/filter.c \
|
$(top_srcdir)/lib/filter.c \
|
||||||
|
40
lib/yang.c
40
lib/yang.c
@ -32,6 +32,45 @@ DEFINE_MTYPE(LIB, YANG_DATA, "YANG data structure")
|
|||||||
/* libyang container. */
|
/* libyang container. */
|
||||||
struct ly_ctx *ly_native_ctx;
|
struct ly_ctx *ly_native_ctx;
|
||||||
|
|
||||||
|
static struct yang_module_embed *embeds, **embedupd = &embeds;
|
||||||
|
|
||||||
|
void yang_module_embed(struct yang_module_embed *embed)
|
||||||
|
{
|
||||||
|
embed->next = NULL;
|
||||||
|
*embedupd = embed;
|
||||||
|
embedupd = &embed->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *yang_module_imp_clb(const char *mod_name,
|
||||||
|
const char *mod_rev,
|
||||||
|
const char *submod_name,
|
||||||
|
const char *submod_rev,
|
||||||
|
void *user_data,
|
||||||
|
LYS_INFORMAT *format,
|
||||||
|
void (**free_module_data)
|
||||||
|
(void *, void*))
|
||||||
|
{
|
||||||
|
struct yang_module_embed *e;
|
||||||
|
|
||||||
|
if (submod_name || submod_rev)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (e = embeds; e; e = e->next) {
|
||||||
|
if (strcmp(e->mod_name, mod_name))
|
||||||
|
continue;
|
||||||
|
if (mod_rev && strcmp(e->mod_rev, mod_rev))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
*format = e->format;
|
||||||
|
return e->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
flog_warn(EC_LIB_YANG_MODULE_LOAD,
|
||||||
|
"YANG model \"%s@%s\" not embedded, trying external file",
|
||||||
|
mod_name, mod_rev ? mod_rev : "*");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Generate the yang_modules tree. */
|
/* Generate the yang_modules tree. */
|
||||||
static inline int yang_module_compare(const struct yang_module *a,
|
static inline int yang_module_compare(const struct yang_module *a,
|
||||||
const struct yang_module *b)
|
const struct yang_module *b)
|
||||||
@ -575,6 +614,7 @@ void yang_init(void)
|
|||||||
flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__);
|
flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
ly_ctx_set_module_imp_clb(ly_native_ctx, yang_module_imp_clb, NULL);
|
||||||
ly_ctx_set_searchdir(ly_native_ctx, YANG_MODELS_PATH);
|
ly_ctx_set_searchdir(ly_native_ctx, YANG_MODELS_PATH);
|
||||||
ly_ctx_set_priv_dup_clb(ly_native_ctx, ly_dup_cb);
|
ly_ctx_set_priv_dup_clb(ly_native_ctx, ly_dup_cb);
|
||||||
|
|
||||||
|
17
lib/yang.h
17
lib/yang.h
@ -44,6 +44,13 @@ DECLARE_MTYPE(YANG_DATA)
|
|||||||
/* Maximum string length of an YANG value. */
|
/* Maximum string length of an YANG value. */
|
||||||
#define YANG_VALUE_MAXLEN 1024
|
#define YANG_VALUE_MAXLEN 1024
|
||||||
|
|
||||||
|
struct yang_module_embed {
|
||||||
|
struct yang_module_embed *next;
|
||||||
|
const char *mod_name, *mod_rev;
|
||||||
|
const char *data;
|
||||||
|
LYS_INFORMAT format;
|
||||||
|
};
|
||||||
|
|
||||||
struct yang_module {
|
struct yang_module {
|
||||||
RB_ENTRY(yang_module) entry;
|
RB_ENTRY(yang_module) entry;
|
||||||
const char *name;
|
const char *name;
|
||||||
@ -132,6 +139,16 @@ extern struct yang_module *yang_module_load(const char *module_name);
|
|||||||
*/
|
*/
|
||||||
extern struct yang_module *yang_module_find(const char *module_name);
|
extern struct yang_module *yang_module_find(const char *module_name);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Register a YANG module embedded in the binary file. Should be called
|
||||||
|
* from a constructor function.
|
||||||
|
*
|
||||||
|
* embed
|
||||||
|
* YANG module embedding structure to register. (static global provided
|
||||||
|
* by caller.)
|
||||||
|
*/
|
||||||
|
extern void yang_module_embed(struct yang_module_embed *embed);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Iterate over all libyang schema nodes from the given YANG module.
|
* Iterate over all libyang schema nodes from the given YANG module.
|
||||||
*
|
*
|
||||||
|
@ -51,6 +51,9 @@ ripd_ripd_LDADD = ripd/librip.a lib/libfrr.la @LIBCAP@
|
|||||||
ripd_ripd_SOURCES = \
|
ripd_ripd_SOURCES = \
|
||||||
ripd/rip_main.c \
|
ripd/rip_main.c \
|
||||||
# end
|
# end
|
||||||
|
nodist_ripd_ripd_SOURCES = \
|
||||||
|
yang/frr-ripd.yang.c \
|
||||||
|
# end
|
||||||
|
|
||||||
ripd_ripd_snmp_la_SOURCES = ripd/rip_snmp.c
|
ripd_ripd_snmp_la_SOURCES = ripd/rip_snmp.c
|
||||||
ripd_ripd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99
|
ripd_ripd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99
|
||||||
|
2
yang/.gitignore
vendored
Normal file
2
yang/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
*.yang.c
|
||||||
|
*.yin
|
78
yang/embedmodel.py
Normal file
78
yang/embedmodel.py
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
#
|
||||||
|
# YANG module to C wrapper
|
||||||
|
# written 2018 by David Lamparter, placed in Public Domain.
|
||||||
|
|
||||||
|
import sys, string, re
|
||||||
|
|
||||||
|
inname = sys.argv[1]
|
||||||
|
outname = sys.argv[2]
|
||||||
|
|
||||||
|
# these are regexes to avoid a compile-time/host dependency on yang-tools
|
||||||
|
# or python-yang. Cross-compiling FRR is already somewhat involved, no need
|
||||||
|
# to make it even harder.
|
||||||
|
|
||||||
|
re_name = re.compile(r'\bmodule\s+([^\s]+)\s+\{')
|
||||||
|
re_rev = re.compile(r'\brevision\s+([\d-]+)\s+\{')
|
||||||
|
|
||||||
|
|
||||||
|
template = '''/* autogenerated by embedmodel.py. DO NOT EDIT */
|
||||||
|
|
||||||
|
#include <zebra.h>
|
||||||
|
#include "yang.h"
|
||||||
|
|
||||||
|
static const char model[] =
|
||||||
|
\t"%s";
|
||||||
|
|
||||||
|
static struct yang_module_embed embed = {
|
||||||
|
\t.mod_name = "%s",
|
||||||
|
\t.mod_rev = "%s",
|
||||||
|
\t.data = model,
|
||||||
|
\t.format = %s,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void embed_register(void) __attribute__((_CONSTRUCTOR(2000)));
|
||||||
|
static void embed_register(void)
|
||||||
|
{
|
||||||
|
\tyang_module_embed(&embed);
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
|
||||||
|
passchars = set(string.printable) - set('\\\'"%\r\n\t\x0b\x0c')
|
||||||
|
def escapech(char):
|
||||||
|
if char in passchars:
|
||||||
|
return char
|
||||||
|
if char == '\n':
|
||||||
|
return '\\n'
|
||||||
|
if char == '\t':
|
||||||
|
return '\\t'
|
||||||
|
if char in '"\\\'':
|
||||||
|
return '\\' + char
|
||||||
|
return '\\x%02x' % (ord(char))
|
||||||
|
def escape(line):
|
||||||
|
return ''.join([escapech(i) for i in line])
|
||||||
|
|
||||||
|
with open(inname, 'r') as fd:
|
||||||
|
data = fd.read()
|
||||||
|
|
||||||
|
# XML support isn't actively used currently, but it's here in case the need
|
||||||
|
# arises. It does avoid the regex'ing.
|
||||||
|
if '<?xml' in data:
|
||||||
|
from xml.etree import ElementTree
|
||||||
|
xml = ElementTree.fromstring(data)
|
||||||
|
name = xml.get('name')
|
||||||
|
rev = xml.find('{urn:ietf:params:xml:ns:yang:yin:1}revision').get('date')
|
||||||
|
fmt = 'LYS_YIN'
|
||||||
|
else:
|
||||||
|
name = re_name.search(data).group(1)
|
||||||
|
rev = re_rev.search(data).group(1)
|
||||||
|
fmt = 'LYS_YANG'
|
||||||
|
|
||||||
|
if name is None or rev is None:
|
||||||
|
raise ValueError('cannot determine YANG module name and revision')
|
||||||
|
|
||||||
|
lines = [escape(row) for row in data.split('\n')]
|
||||||
|
text = '\\n"\n\t"'.join(lines)
|
||||||
|
|
||||||
|
with open(outname, 'w') as fd:
|
||||||
|
fd.write(template % (text, escape(name), escape(rev), fmt))
|
@ -1,3 +1,24 @@
|
|||||||
|
SUFFIXES += .yang .yang.c .yin .yin.c
|
||||||
|
EXTRA_DIST += yang/embedmodel.py
|
||||||
|
|
||||||
|
.yang.yang.c:
|
||||||
|
$(AM_V_GEN)$(PYTHON) $(top_srcdir)/yang/embedmodel.py $^ $@
|
||||||
|
.yin.yin.c:
|
||||||
|
$(AM_V_GEN)$(PYTHON) $(top_srcdir)/yang/embedmodel.py $^ $@
|
||||||
|
|
||||||
|
# use .yang.c files like this:
|
||||||
|
#
|
||||||
|
# ripd_ripd_SOURCES = \
|
||||||
|
# ...
|
||||||
|
# nodist_ripd_ripd_SOURCES = \
|
||||||
|
# yang/frr-ripd.yang.c \
|
||||||
|
# # end
|
||||||
|
#
|
||||||
|
# Note that putting the .yang.c file into a static library.a will NOT work
|
||||||
|
# because the entire file is "optimized out" since it does not contain any
|
||||||
|
# global symbols :(. Just put it in the daemon. Dynamic libraries.so work
|
||||||
|
# without problems, as seen in libfrr.
|
||||||
|
|
||||||
dist_yangmodels_DATA += yang/frr-module-translator.yang
|
dist_yangmodels_DATA += yang/frr-module-translator.yang
|
||||||
dist_yangmodels_DATA += yang/frr-interface.yang
|
dist_yangmodels_DATA += yang/frr-interface.yang
|
||||||
dist_yangmodels_DATA += yang/frr-route-types.yang
|
dist_yangmodels_DATA += yang/frr-route-types.yang
|
||||||
|
Loading…
Reference in New Issue
Block a user