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 \
/* 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)
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);
/* 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;
*/
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.
*
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
--- /dev/null
+#!/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))
+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