mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-04-28 21:20:48 +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 \
|
||||
# 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 += \
|
||||
$(top_srcdir)/lib/distribute.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. */
|
||||
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. */
|
||||
static inline int yang_module_compare(const struct yang_module *a,
|
||||
const struct yang_module *b)
|
||||
@ -575,6 +614,7 @@ void yang_init(void)
|
||||
flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__);
|
||||
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_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. */
|
||||
#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 {
|
||||
RB_ENTRY(yang_module) entry;
|
||||
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);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
|
@ -51,6 +51,9 @@ ripd_ripd_LDADD = ripd/librip.a lib/libfrr.la @LIBCAP@
|
||||
ripd_ripd_SOURCES = \
|
||||
ripd/rip_main.c \
|
||||
# end
|
||||
nodist_ripd_ripd_SOURCES = \
|
||||
yang/frr-ripd.yang.c \
|
||||
# end
|
||||
|
||||
ripd_ripd_snmp_la_SOURCES = ripd/rip_snmp.c
|
||||
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-interface.yang
|
||||
dist_yangmodels_DATA += yang/frr-route-types.yang
|
||||
|
Loading…
Reference in New Issue
Block a user