diff --git a/lib/subdir.am b/lib/subdir.am index c144c2c2e1..43b39100cb 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -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 \ diff --git a/lib/yang.c b/lib/yang.c index bb5d38e2e6..a7a50a46b0 100644 --- a/lib/yang.c +++ b/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); diff --git a/lib/yang.h b/lib/yang.h index cd5597ff8c..b0348e320b 100644 --- a/lib/yang.h +++ b/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. * diff --git a/ripd/subdir.am b/ripd/subdir.am index 480fa1e47f..ed74047cce 100644 --- a/ripd/subdir.am +++ b/ripd/subdir.am @@ -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 diff --git a/yang/.gitignore b/yang/.gitignore new file mode 100644 index 0000000000..f43a1c30a1 --- /dev/null +++ b/yang/.gitignore @@ -0,0 +1,2 @@ +*.yang.c +*.yin diff --git a/yang/embedmodel.py b/yang/embedmodel.py new file mode 100644 index 0000000000..52671f99a8 --- /dev/null +++ b/yang/embedmodel.py @@ -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 +#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 '