diff --git a/Makefile.in b/Makefile.in index c4c6ac72..2d95f340 100644 --- a/Makefile.in +++ b/Makefile.in @@ -42,7 +42,7 @@ LIBS = @LIBS@ INCLUDES = -I. -I@srcdir@ @INCLUDES@ SHELL = /bin/sh -SUBDIRS = lib apps include doc etc +SUBDIRS = lib apps include etc .PHONY: doc all clean depend $(SUBDIRS) install loc TAGS .config.status @@ -52,7 +52,7 @@ $(SUBDIRS): (cd $@ && $(MAKE) $(MFLAGS) all) depend: - for i in $(SUBDIRS) example; \ + for i in $(SUBDIRS) doc example; \ do (cd $$i && $(MAKE) $(MFLAGS) depend); done # template clicon.conf file @@ -63,7 +63,7 @@ clicon.mk: clicon.mk.cpp $(CPP) -P -traditional-cpp -x assembler-with-cpp -Dprefix=$(prefix) -Dlocalstatedir=$(localstatedir) -Dsysconfdir=$(sysconfdir) -Ddatadir=$(datadir) -Dlibdir=$(libdir) $< > $@ install: clicon.conf.cpp clicon.mk - for i in $(SUBDIRS); \ + for i in $(SUBDIRS) doc; \ do (cd $$i && $(MAKE) $(MFLAGS) $@); done; \ install -d -m 755 $(DESTDIR)$(datadir)/clicon install -m 755 clicon.conf.cpp $(DESTDIR)$(datadir)/clicon @@ -71,19 +71,18 @@ install: clicon.conf.cpp clicon.mk echo "Install for compilation by: make install-include" install-include: - for i in $(SUBDIRS); \ + for i in $(SUBDIRS) doc; \ do (cd $$i && $(MAKE) $(MFLAGS) $@); done; \ echo "To install example app: cd example; make; make install" uninstall: - for i in $(SUBDIRS) example; \ + for i in $(SUBDIRS) doc example; \ do (cd $$i && $(MAKE) $(MFLAGS) $@); done; rm -f $(datadir)/clicon/clicon.conf.cpp rm -f $(datadir)/clicon/clicon.mk -# Overrides SUBDIRS above -#doc: -# cd $@; $(MAKE) $(MFLAGS) $@ +doc: + cd $@; $(MAKE) $(MFLAGS) $@ config.status: configure $(SHELL) config.status --recheck @@ -92,14 +91,14 @@ configure: configure.ac cd $(srcdir) && autoconf clean: - for i in $(SUBDIRS) example; \ + for i in $(SUBDIRS) doc example; \ do (cd $$i && $(MAKE) $(MFLAGS) $@); done; distclean: rm -f Makefile TAGS config.status config.log *~ .depend rm -rf Makefile autom4te.cache rm -rf clicon.conf.cpp clicon.mk - for i in $(SUBDIRS) example; \ + for i in $(SUBDIRS) doc example; \ do (cd $$i && $(MAKE) $(MFLAGS) $@); done # Lines of code diff --git a/apps/backend/backend_commit.c b/apps/backend/backend_commit.c index c7e3b8a9..b9afb96f 100644 --- a/apps/backend/backend_commit.c +++ b/apps/backend/backend_commit.c @@ -126,8 +126,8 @@ candidate_commit(clicon_handle h, char *running) { int retval = -1; - // int i, j; - // int failed = 0; + int i; + cxobj *xn; struct stat sb; void *firsterr = NULL; yang_spec *yspec; @@ -171,6 +171,25 @@ candidate_commit(clicon_handle h, goto done; if (debug) transaction_print(stderr, td); + /* Mark as changed in tree */ + for (i=0; itd_dlen; i++){ /* Also down */ + xn = td->td_dvec[i]; + xml_flag_set(xn, XML_FLAG_DEL); + xml_apply(xn, CX_ELMNT, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_DEL); + } + for (i=0; itd_alen; i++){ /* Also down */ + xn = td->td_avec[i]; + xml_flag_set(xn, XML_FLAG_ADD); + xml_apply(xn, CX_ELMNT, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_ADD); + } + for (i=0; itd_clen; i++){ /* Also up */ + xn = td->td_scvec[i]; + xml_flag(xn, XML_FLAG_CHANGE); + xml_apply_ancestor(xn, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_CHANGE); + xn = td->td_tcvec[i]; + xml_flag_set(xn, XML_FLAG_CHANGE); + xml_apply_ancestor(xn, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_CHANGE); + } /* 4. Call plugin transaction start callbacks */ if (plugin_transaction_begin(h, td) < 0) @@ -236,6 +255,8 @@ candidate_validate(clicon_handle h, struct stat sb; yang_spec *yspec; transaction_data_t *td = NULL; + int i; + cxobj *xn; if ((yspec = clicon_dbspec_yang(h)) == NULL){ clicon_err(OE_FATAL, 0, "No DB_SPEC"); @@ -276,6 +297,22 @@ candidate_validate(clicon_handle h, if (debug) transaction_print(stderr, td); + + /* Mark as changed in tree */ + for (i=0; itd_dlen; i++){ /* Also down */ + xn = td->td_dvec[i]; + xml_flag_set(xn, XML_FLAG_DEL); + } + for (i=0; itd_alen; i++){ /* Also down */ + xn = td->td_avec[i]; + xml_flag_set(xn, XML_FLAG_ADD); + } + for (i=0; itd_clen; i++){ /* Also up */ + xn = td->td_scvec[i]; + xml_flag_set(xn, XML_FLAG_CHANGE); + xn = td->td_tcvec[i]; + xml_flag(xn, XML_FLAG_CHANGE); + } /* 4. Call plugin start transaction callbacks */ if (plugin_transaction_begin(h, td) < 0) diff --git a/apps/cli/cli_common.c b/apps/cli/cli_common.c index fc72b346..a1715738 100644 --- a/apps/cli/cli_common.c +++ b/apps/cli/cli_common.c @@ -1492,7 +1492,7 @@ show_conf_xpath(clicon_handle h, cvec *cvv, cg_var *arg) cg_var *cv; cxobj *xt = NULL; cxobj **xv = NULL; - int xlen; + size_t xlen; int i; if (arg == NULL || (str = cv_string_get(arg)) == NULL){ @@ -1516,7 +1516,7 @@ show_conf_xpath(clicon_handle h, cvec *cvv, cg_var *arg) cv = cvec_find_var(cvv, "xpath"); xpath = cv_string_get(cv); yspec = clicon_dbspec_yang(h); - if (xmldb_get_xpath(dbname, xpath, yspec, &xt, &xv, &xlen) < 0) + if (xmldb_get_vec(dbname, xpath, yspec, &xt, &xv, &xlen) < 0) goto done; for (i=0; i -p -The name of the running or candidate databases are found in the -configuration file, eg /usr/local/var/routing/candidate_db +------------------------------------------ +Use clicon_dbctrl. The name of the running or candidate databases are found in the +configuration file. Example: - /interfaces/interface/eth0/ipv4 - /interfaces/interface/eth0/type bgp - /interfaces/interface/eth0 - /interfaces/interface/eth0/name eth0 -Each line corresponds to a database entry (node in an XML tree). If -the node is a leaf, the value appears as the second entry. + > clicon_dbctrl -d /usr/local/var/routing/candidate_db / -p + /interfaces/interface/eth0/ipv4 + /interfaces/interface/eth0/type bgp + /interfaces/interface/eth0 + /interfaces/interface/eth0/name eth0 +Each line corresponds to a database entry (node in an XML tree). +If the node is a leaf, the value appears as the second entry ('bgp' and 'eth0'). -Q: How do you write a commit rule in the example? -A: You write a commit function in routing_backend.c. +Q: How do you write a commit function? +-------------------------------------- +You write a commit function in routing_backend.c. Every time a commit is made, transaction_commit() is called in the backend. It has a 'transaction_data td' argument which is used to fetch information on added, deleted and changed entries. You access this information using access functions as defined in clicon_backend_transaction.h Q: How do you check what has changed on commit? -A: You use XPATHs on the XML trees in the transaction commit callback. +----------------------------------------------- +You use XPATHs on the XML trees in the transaction commit callback. Suppose you want to print all added interfaces: - cxobj *target = transaction_target(td); # wanted XML tree - # Get all added i/fs - cxobj **vec = xpath_vec_flag(target, "//interface", &len, XML_FLAG_ADD); - for (i=0; i("This is a variable"), mycallback("myarg"); -Then define a function in routing_cli.c +(2) Then define a function in routing_cli.c mycallback(clicon_handle h, cvec *cvv, cg_var *arg) where 'cvv' contains the value of the variable and 'arg' contains the function parameter 'myarg'. Q: What are cg_var and cvec used in CLI callbacks? -Those are 'CLIgen variables' and vector of CLOgen -variables. Documented in CLIgen documentation. Some examples on usage is found in the +-------------------------------------------------- +Those are 'CLIgen variables' and vector of CLIgen variables. +They are documented in CLIgen documentation. Some examples on usage is found in the routing_cli.c -Q: How do you write a validation rule? -Similar to a commit rule, but instead write the transaction_validate() function. -Check for consitencies in the XML trees and if they fail, make an clicon_err() call. +Q: How do you write a validation function? +------------------------------------------ +Similar to a commit function, but instead write the transaction_validate() function. +Check for inconsistencies in the XML trees and if they fail, make an clicon_err() call. clicon_err(OE_PLUGIN, 0, "Route %s lacks ipv4 addr", name); return -1; The validation or commit will then be aborted. diff --git a/doc/Makefile.in b/doc/Makefile.in index ae1da462..6aab438d 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -30,13 +30,13 @@ pdflatex = @PDFLATEX@ SUBDIRS = -.PHONY: clean all $(SUBDIRS) +.PHONY: clean all doc $(SUBDIRS) all: $(SUBDIRS) doc - echo "Build doxygen doc and graphs: make graphs" + echo "Build doxygen doc: make doc" # Regular doxygen documentation -doc: +doc: doxygen Doxyfile # generates html dir echo "Build doxygen graphs: make graphs" diff --git a/example/routing_backend.c b/example/routing_backend.c index f2d9552f..afd83a04 100644 --- a/example/routing_backend.c +++ b/example/routing_backend.c @@ -40,28 +40,36 @@ /* These include signatures for plugin and transaction callbacks. */ #include -/* - * Commit callback. - * We do nothing here but simply create the config based on the current - * db once everything is done as if will then contain the new config. +/*! This is called on validate (and commit). Check validity of candidate + */ +int +transaction_validate(clicon_handle h, + transaction_data td) +{ + if (debug) + transaction_print(stderr, td); + return 0; +} + +/*! This is called on commit. Identify modifications and adjust machine state */ int transaction_commit(clicon_handle h, transaction_data td) { - fprintf(stderr, "%s\n", __FUNCTION__); - transaction_print(stderr, td); + cxobj *target = transaction_target(td); /* wanted XML tree */ + cxobj **vec; + int i; + size_t len; + + /* Get all added i/fs */ + vec = xpath_vec_flag(target, "//interface", XML_FLAG_ADD, &len); + for (i=0; ixe_str, CX_ELMNT, &vec1, &vec1len) < 0) + if (recursive_find(xv, xe->xe_str, CX_ELMNT, flags, &vec1, &vec1len) < 0) goto done; } } @@ -490,8 +505,10 @@ xpath_find(struct xpath_element *xe, x = NULL; while ((x = xml_child_each(xv, x, -1)) != NULL) { if (fnmatch(xe->xe_str, xml_name(x), 0) == 0){ - if (cxvec_append(x, &vec1, &vec1len) < 0) - goto done; + clicon_debug(2, "%s %x %x", __FUNCTION__, flags, xml_flag(x, flags)); + if (flags==0x0 || xml_flag(x, flags)) + if (cxvec_append(x, &vec1, &vec1len) < 0) + goto done; } } } @@ -517,10 +534,10 @@ xpath_find(struct xpath_element *xe, } } if (xe->xe_predicate) - if (xpath_expr(xe->xe_predicate, &vec0, &vec0len) < 0) + if (xpath_expr(xe->xe_predicate, flags, &vec0, &vec0len) < 0) goto done; if (xpath_find(xe->xe_next, descendants, - vec0, vec0len, + vec0, vec0len, flags, vec2, vec2len) < 0) goto done; retval = 0; @@ -574,6 +591,7 @@ static int xpath_exec(char *xpath, cxobj **vec0, size_t vec0len, + uint16_t flags, cxobj ***vec2, size_t *vec2len) { @@ -587,7 +605,7 @@ xpath_exec(char *xpath, goto done; if (0) xpath_print(stderr, xplist); - if (xpath_find(xplist, 0, vec1, vec1len, vec2, vec2len) < 0) + if (xpath_find(xplist, 0, vec1, vec1len, flags, vec2, vec2len) < 0) goto done; if (xpath_free(xplist) < 0) goto done; @@ -607,6 +625,7 @@ xpath_exec(char *xpath, static int xpath_choice(cxobj *xtop, char *xpath0, + uint16_t flags, cxobj ***vec1, size_t *vec1len) { @@ -637,7 +656,7 @@ xpath_choice(cxobj *xtop, } xpath = s1; s1 = s2; - if (xpath_exec(xpath, vec0, vec0len, vec1, vec1len) < 0) + if (xpath_exec(xpath, vec0, vec0len, flags, vec1, vec1len) < 0) goto done; } retval = 0; @@ -667,13 +686,14 @@ xpath_choice(cxobj *xtop, * @see also xpath_vec. */ cxobj * -xpath_first(cxobj *cxtop, char *xpath) +xpath_first(cxobj *cxtop, + char *xpath) { cxobj **vec0 = NULL; size_t vec0len = 0; cxobj *xn = NULL; - if (xpath_choice(cxtop, xpath, &vec0, &vec0len) < 0) + if (xpath_choice(cxtop, xpath, 0, &vec0, &vec0len) < 0) goto done; if (vec0len) xn = vec0[0]; @@ -707,7 +727,9 @@ xpath_first(cxobj *cxtop, char *xpath) * NOTE: uses a static variable: consider replacing with xpath_vec() instead */ cxobj * -xpath_each(cxobj *cxtop, char *xpath, cxobj *xprev) +xpath_each(cxobj *cxtop, + char *xpath, + cxobj *xprev) { static cxobj **vec0 = NULL; /* XXX */ static size_t vec0len = 0; @@ -718,7 +740,7 @@ xpath_each(cxobj *cxtop, char *xpath, cxobj *xprev) if (vec0) // XXX free(vec0); // XXX vec0len = 0; - if (xpath_choice(cxtop, xpath, &vec0, &vec0len) < 0) + if (xpath_choice(cxtop, xpath, 0, &vec0, &vec0len) < 0) goto done; } if (vec0len){ @@ -765,14 +787,31 @@ xpath_each(cxobj *cxtop, char *xpath, cxobj *xprev) * @see also xpath_first, xpath_each. */ cxobj ** -xpath_vec(cxobj *cxtop, - char *xpath, - int *veclen) +xpath_vec(cxobj *cxtop, + char *xpath, + size_t *veclen) { cxobj **vec=NULL; *veclen = 0; - if (xpath_choice(cxtop, xpath, &vec, (size_t*)veclen) < 0) + if (xpath_choice(cxtop, xpath, 0, &vec, (size_t*)veclen) < 0) + return NULL; + return vec; +} + +/* A restricted xpath that returns a vector of matches (only nodes marked with flags) + * @param[in] flags Set of flags that return nodes must match (0 if all) + */ +cxobj ** +xpath_vec_flag(cxobj *cxtop, + char *xpath, + uint16_t flags, + size_t *veclen) +{ + cxobj **vec=NULL; + + *veclen = 0; + if (xpath_choice(cxtop, xpath, flags, &vec, (size_t*)veclen) < 0) return NULL; return vec; }