diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/distribute.c | 155 | ||||
| -rw-r--r-- | lib/distribute.h | 36 | ||||
| -rw-r--r-- | lib/hook.c | 26 | ||||
| -rw-r--r-- | lib/hook.h | 28 | ||||
| -rw-r--r-- | lib/lib_errors.c | 26 | ||||
| -rw-r--r-- | lib/lib_errors.h | 5 | ||||
| -rw-r--r-- | lib/mlag.c | 41 | ||||
| -rw-r--r-- | lib/mlag.h | 32 | ||||
| -rw-r--r-- | lib/module.c | 26 | ||||
| -rw-r--r-- | lib/module.h | 26 | ||||
| -rw-r--r-- | lib/northbound.c | 39 | ||||
| -rw-r--r-- | lib/northbound_cli.c | 15 | ||||
| -rw-r--r-- | lib/northbound_cli.h | 2 | ||||
| -rw-r--r-- | lib/subdir.am | 2 | ||||
| -rw-r--r-- | lib/vrf.c | 2 | ||||
| -rw-r--r-- | lib/vty.h | 2 | ||||
| -rw-r--r-- | lib/workqueue.c | 29 | ||||
| -rw-r--r-- | lib/workqueue.h | 5 | ||||
| -rw-r--r-- | lib/yang.c | 4 | ||||
| -rw-r--r-- | lib/yang_wrappers.c | 8 | ||||
| -rw-r--r-- | lib/zclient.c | 13 | ||||
| -rw-r--r-- | lib/zclient.h | 7 | ||||
| -rw-r--r-- | lib/zebra.h | 52 |
23 files changed, 398 insertions, 183 deletions
diff --git a/lib/distribute.c b/lib/distribute.c index 9697916332..3a6b775bc8 100644 --- a/lib/distribute.c +++ b/lib/distribute.c @@ -27,16 +27,12 @@ #include "distribute.h" #include "memory.h" +DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_CTX, "Distribute ctx") DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE, "Distribute list") DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_IFNAME, "Dist-list ifname") DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_NAME, "Dist-list name") -/* Hash of distribute list. */ -struct hash *disthash; - -/* Hook functions. */ -void (*distribute_add_hook)(struct distribute *); -void (*distribute_delete_hook)(struct distribute *); +struct list *dist_ctx_list; static struct distribute *distribute_new(void) { @@ -62,7 +58,8 @@ static void distribute_free(struct distribute *dist) XFREE(MTYPE_DISTRIBUTE, dist); } -static void distribute_free_if_empty(struct distribute *dist) +static void distribute_free_if_empty(struct distribute_ctx *ctx, + struct distribute *dist) { int i; @@ -70,12 +67,13 @@ static void distribute_free_if_empty(struct distribute *dist) if (dist->list[i] != NULL || dist->prefix[i] != NULL) return; - hash_release(disthash, dist); + hash_release(ctx->disthash, dist); distribute_free(dist); } /* Lookup interface's distribute list. */ -struct distribute *distribute_lookup(const char *ifname) +struct distribute *distribute_lookup(struct distribute_ctx *ctx, + const char *ifname) { struct distribute key; struct distribute *dist; @@ -83,7 +81,7 @@ struct distribute *distribute_lookup(const char *ifname) /* temporary reference */ key.ifname = (ifname) ? XSTRDUP(MTYPE_DISTRIBUTE_IFNAME, ifname) : NULL; - dist = hash_lookup(disthash, &key); + dist = hash_lookup(ctx->disthash, &key); if (key.ifname) XFREE(MTYPE_DISTRIBUTE_IFNAME, key.ifname); @@ -91,14 +89,18 @@ struct distribute *distribute_lookup(const char *ifname) return dist; } -void distribute_list_add_hook(void (*func)(struct distribute *)) +void distribute_list_add_hook(struct distribute_ctx *ctx, + void (*func)(struct distribute_ctx *ctx, + struct distribute *)) { - distribute_add_hook = func; + ctx->distribute_add_hook = func; } -void distribute_list_delete_hook(void (*func)(struct distribute *)) +void distribute_list_delete_hook(struct distribute_ctx *ctx, + void (*func)(struct distribute_ctx *ctx, + struct distribute *)) { - distribute_delete_hook = func; + ctx->distribute_delete_hook = func; } static void *distribute_hash_alloc(struct distribute *arg) @@ -114,7 +116,8 @@ static void *distribute_hash_alloc(struct distribute *arg) } /* Make new distribute list and push into hash. */ -static struct distribute *distribute_get(const char *ifname) +static struct distribute *distribute_get(struct distribute_ctx *ctx, + const char *ifname) { struct distribute key; struct distribute *ret; @@ -122,7 +125,7 @@ static struct distribute *distribute_get(const char *ifname) /* temporary reference */ key.ifname = (ifname) ? XSTRDUP(MTYPE_DISTRIBUTE_IFNAME, ifname) : NULL; - ret = hash_get(disthash, &key, + ret = hash_get(ctx->disthash, &key, (void *(*)(void *))distribute_hash_alloc); if (key.ifname) @@ -152,29 +155,32 @@ static bool distribute_cmp(const struct distribute *dist1, } /* Set access-list name to the distribute list. */ -static void distribute_list_set(const char *ifname, enum distribute_type type, +static void distribute_list_set(struct distribute_ctx *ctx, + const char *ifname, enum distribute_type type, const char *alist_name) { struct distribute *dist; - dist = distribute_get(ifname); + dist = distribute_get(ctx, ifname); if (dist->list[type]) XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[type]); dist->list[type] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, alist_name); /* Apply this distribute-list to the interface. */ - (*distribute_add_hook)(dist); + (ctx->distribute_add_hook)(ctx, dist); } /* Unset distribute-list. If matched distribute-list exist then return 1. */ -static int distribute_list_unset(const char *ifname, enum distribute_type type, +static int distribute_list_unset(struct distribute_ctx *ctx, + const char *ifname, + enum distribute_type type, const char *alist_name) { struct distribute *dist; - dist = distribute_lookup(ifname); + dist = distribute_lookup(ctx, ifname); if (!dist) return 0; @@ -187,39 +193,41 @@ static int distribute_list_unset(const char *ifname, enum distribute_type type, dist->list[type] = NULL; /* Apply this distribute-list to the interface. */ - (*distribute_delete_hook)(dist); + (ctx->distribute_delete_hook)(ctx, dist); /* If all dist are NULL, then free distribute list. */ - distribute_free_if_empty(dist); + distribute_free_if_empty(ctx, dist); return 1; } /* Set access-list name to the distribute list. */ -static void distribute_list_prefix_set(const char *ifname, +static void distribute_list_prefix_set(struct distribute_ctx *ctx, + const char *ifname, enum distribute_type type, const char *plist_name) { struct distribute *dist; - dist = distribute_get(ifname); + dist = distribute_get(ctx, ifname); if (dist->prefix[type]) XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[type]); dist->prefix[type] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, plist_name); /* Apply this distribute-list to the interface. */ - (*distribute_add_hook)(dist); + (ctx->distribute_add_hook)(ctx, dist); } /* Unset distribute-list. If matched distribute-list exist then return 1. */ -static int distribute_list_prefix_unset(const char *ifname, +static int distribute_list_prefix_unset(struct distribute_ctx *ctx, + const char *ifname, enum distribute_type type, const char *plist_name) { struct distribute *dist; - dist = distribute_lookup(ifname); + dist = distribute_lookup(ctx, ifname); if (!dist) return 0; @@ -232,10 +240,10 @@ static int distribute_list_prefix_unset(const char *ifname, dist->prefix[type] = NULL; /* Apply this distribute-list to the interface. */ - (*distribute_delete_hook)(dist); + (ctx->distribute_delete_hook)(ctx, dist); /* If all dist are NULL, then free distribute list. */ - distribute_free_if_empty(dist); + distribute_free_if_empty(ctx, dist); return 1; } @@ -250,15 +258,17 @@ DEFUN (distribute_list, "Interface name\n") { int prefix = (argv[1]->type == WORD_TKN) ? 1 : 0; - /* Check of distribute list type. */ enum distribute_type type = argv[2 + prefix]->arg[0] == 'i' ? DISTRIBUTE_V4_IN : DISTRIBUTE_V4_OUT; /* Set appropriate function call */ - void (*distfn)(const char *, enum distribute_type, const char *) = + void (*distfn)(struct distribute_ctx *, const char *, + enum distribute_type, const char *) = prefix ? &distribute_list_prefix_set : &distribute_list_set; + struct distribute_ctx *ctx = + (struct distribute_ctx *)listnode_head(dist_ctx_list); /* if interface is present, get name */ const char *ifname = NULL; @@ -266,7 +276,7 @@ DEFUN (distribute_list, ifname = argv[argc - 1]->arg; /* Get interface name corresponding distribute list. */ - distfn(ifname, type, argv[1 + prefix]->arg); + distfn(ctx, ifname, type, argv[1 + prefix]->arg); return CMD_SUCCESS; } @@ -283,15 +293,16 @@ DEFUN (ipv6_distribute_list, "Interface name\n") { int prefix = (argv[2]->type == WORD_TKN) ? 1 : 0; - /* Check of distribute list type. */ enum distribute_type type = argv[3 + prefix]->arg[0] == 'i' ? DISTRIBUTE_V6_IN : DISTRIBUTE_V6_OUT; /* Set appropriate function call */ - void (*distfn)(const char *, enum distribute_type, const char *) = + void (*distfn)(struct distribute_ctx *, const char *, + enum distribute_type, const char *) = prefix ? &distribute_list_prefix_set : &distribute_list_set; + struct distribute_ctx *ctx = listnode_head(dist_ctx_list); /* if interface is present, get name */ const char *ifname = NULL; @@ -299,7 +310,7 @@ DEFUN (ipv6_distribute_list, ifname = argv[argc - 1]->arg; /* Get interface name corresponding distribute list. */ - distfn(ifname, type, argv[2 + prefix]->arg); + distfn(ctx, ifname, type, argv[2 + prefix]->arg); return CMD_SUCCESS; } @@ -316,7 +327,6 @@ DEFUN (no_distribute_list, "Interface name\n") { int prefix = (argv[2]->type == WORD_TKN) ? 1 : 0; - int idx_alname = 2 + prefix; int idx_disttype = idx_alname + 1; enum distribute_type type = @@ -324,16 +334,17 @@ DEFUN (no_distribute_list, DISTRIBUTE_V4_IN : DISTRIBUTE_V4_OUT; /* Set appropriate function call */ - int (*distfn)(const char *, enum distribute_type, - const char *) = + int (*distfn)(struct distribute_ctx *, const char *, + enum distribute_type, const char *) = prefix ? &distribute_list_prefix_unset : &distribute_list_unset; + struct distribute_ctx *ctx = listnode_head(dist_ctx_list); /* if interface is present, get name */ const char *ifname = NULL; if (argv[argc - 1]->type == VARIABLE_TKN) ifname = argv[argc - 1]->arg; /* Get interface name corresponding distribute list. */ - int ret = distfn(ifname, type, argv[2 + prefix]->arg); + int ret = distfn(ctx, ifname, type, argv[2 + prefix]->arg); if (!ret) { vty_out(vty, "distribute list doesn't exist\n"); @@ -355,16 +366,17 @@ DEFUN (no_ipv6_distribute_list, "Interface name\n") { int prefix = (argv[3]->type == WORD_TKN) ? 1 : 0; - int idx_alname = 3 + prefix; int idx_disttype = idx_alname + 1; enum distribute_type type = argv[idx_disttype]->arg[0] == 'i' ? DISTRIBUTE_V6_IN : DISTRIBUTE_V6_OUT; + struct distribute_ctx *ctx = listnode_head(dist_ctx_list); /* Set appropriate function call */ - int (*distfn)(const char *, enum distribute_type, const char *) = + int (*distfn)(struct distribute_ctx *, const char *, + enum distribute_type, const char *) = prefix ? &distribute_list_prefix_unset : &distribute_list_unset; /* if interface is present, get name */ @@ -373,7 +385,7 @@ DEFUN (no_ipv6_distribute_list, if (argv[argc - 1]->type == VARIABLE_TKN) ifname = argv[argc - 1]->arg; /* Get interface name corresponding distribute list. */ - int ret = distfn(ifname, type, argv[3 + prefix]->arg); + int ret = distfn(ctx, ifname, type, argv[3 + prefix]->arg); if (!ret) { vty_out(vty, "distribute list doesn't exist\n"); @@ -393,7 +405,7 @@ static int distribute_print(struct vty *vty, char *tab[], int is_prefix, return has_print; } -int config_show_distribute(struct vty *vty) +int config_show_distribute(struct vty *vty, struct distribute_ctx *dist_ctxt) { unsigned int i; int has_print = 0; @@ -401,7 +413,7 @@ int config_show_distribute(struct vty *vty) struct distribute *dist; /* Output filter configuration. */ - dist = distribute_lookup(NULL); + dist = distribute_lookup(dist_ctxt, NULL); vty_out(vty, " Outgoing update filter list for all interface is"); has_print = 0; if (dist) { @@ -419,8 +431,8 @@ int config_show_distribute(struct vty *vty) else vty_out(vty, " not set\n"); - for (i = 0; i < disthash->size; i++) - for (mp = disthash->index[i]; mp; mp = mp->next) { + for (i = 0; i < dist_ctxt->disthash->size; i++) + for (mp = dist_ctxt->disthash->index[i]; mp; mp = mp->next) { dist = mp->data; if (dist->ifname) { vty_out(vty, " %s filtered by", @@ -447,7 +459,7 @@ int config_show_distribute(struct vty *vty) /* Input filter configuration. */ - dist = distribute_lookup(NULL); + dist = distribute_lookup(dist_ctxt, NULL); vty_out(vty, " Incoming update filter list for all interface is"); has_print = 0; if (dist) { @@ -465,8 +477,8 @@ int config_show_distribute(struct vty *vty) else vty_out(vty, " not set\n"); - for (i = 0; i < disthash->size; i++) - for (mp = disthash->index[i]; mp; mp = mp->next) { + for (i = 0; i < dist_ctxt->disthash->size; i++) + for (mp = dist_ctxt->disthash->index[i]; mp; mp = mp->next) { dist = mp->data; if (dist->ifname) { vty_out(vty, " %s filtered by", @@ -494,7 +506,8 @@ int config_show_distribute(struct vty *vty) } /* Configuration write function. */ -int config_write_distribute(struct vty *vty) +int config_write_distribute(struct vty *vty, + struct distribute_ctx *dist_ctxt) { unsigned int i; int j; @@ -502,8 +515,8 @@ int config_write_distribute(struct vty *vty) struct hash_backet *mp; int write = 0; - for (i = 0; i < disthash->size; i++) - for (mp = disthash->index[i]; mp; mp = mp->next) { + for (i = 0; i < dist_ctxt->disthash->size; i++) + for (mp = dist_ctxt->disthash->index[i]; mp; mp = mp->next) { struct distribute *dist; dist = mp->data; @@ -543,19 +556,38 @@ int config_write_distribute(struct vty *vty) return write; } -/* Clear all distribute list. */ -void distribute_list_reset() +void distribute_list_delete(struct distribute_ctx **ctx) { - hash_clean(disthash, (void (*)(void *))distribute_free); + if ((*ctx)->disthash) { + hash_clean((*ctx)->disthash, (void (*)(void *))distribute_free); + } + if (!dist_ctx_list) + dist_ctx_list = list_new(); + listnode_delete(dist_ctx_list, *ctx); + if (list_isempty(dist_ctx_list)) + list_delete(&dist_ctx_list); + XFREE(MTYPE_DISTRIBUTE_CTX, (*ctx)); } -/* Initialize distribute list related hash. */ -void distribute_list_init(int node) +/* Initialize distribute list container */ +struct distribute_ctx *distribute_list_ctx_create(struct vrf *vrf) { - disthash = hash_create( + struct distribute_ctx *ctx; + + ctx = XCALLOC(MTYPE_DISTRIBUTE_CTX, sizeof(struct distribute_ctx)); + ctx->vrf = vrf; + ctx->disthash = hash_create( distribute_hash_make, (bool (*)(const void *, const void *))distribute_cmp, NULL); + if (!dist_ctx_list) + dist_ctx_list = list_new(); + listnode_add(dist_ctx_list, ctx); + return ctx; +} +/* Initialize distribute list vty commands */ +void distribute_list_init(int node) +{ /* vtysh command-extraction doesn't grok install_element(node, ) */ if (node == RIP_NODE) { install_element(RIP_NODE, &distribute_list_cmd); @@ -563,10 +595,7 @@ void distribute_list_init(int node) } else if (node == RIPNG_NODE) { install_element(RIPNG_NODE, &distribute_list_cmd); install_element(RIPNG_NODE, &no_distribute_list_cmd); - } - - /* install v6 */ - if (node == RIPNG_NODE) { + /* install v6 */ install_element(RIPNG_NODE, &ipv6_distribute_list_cmd); install_element(RIPNG_NODE, &no_ipv6_distribute_list_cmd); } diff --git a/lib/distribute.h b/lib/distribute.h index 35c5e0d6b6..44c699b38a 100644 --- a/lib/distribute.h +++ b/lib/distribute.h @@ -45,14 +45,36 @@ struct distribute { char *prefix[DISTRIBUTE_MAX]; }; +struct distribute_ctx { + /* Hash of distribute list. */ + struct hash *disthash; + + /* Hook functions. */ + void (*distribute_add_hook)(struct distribute_ctx *ctx, + struct distribute *dist); + void (*distribute_delete_hook)(struct distribute_ctx *ctx, + struct distribute *dist); + + /* vrf information */ + struct vrf *vrf; +}; + /* Prototypes for distribute-list. */ -extern void distribute_list_init(int); -extern void distribute_list_reset(void); -extern void distribute_list_add_hook(void (*)(struct distribute *)); -extern void distribute_list_delete_hook(void (*)(struct distribute *)); -extern struct distribute *distribute_lookup(const char *); -extern int config_write_distribute(struct vty *); -extern int config_show_distribute(struct vty *); +extern void distribute_list_init(int node); +extern struct distribute_ctx *distribute_list_ctx_create(struct vrf *vrf); +extern void distribute_list_delete(struct distribute_ctx **ctx); +extern void distribute_list_add_hook(struct distribute_ctx *ctx, + void (*)(struct distribute_ctx *ctx, + struct distribute *)); +extern void distribute_list_delete_hook(struct distribute_ctx *ctx, + void (*)(struct distribute_ctx *ctx, + struct distribute *)); +extern struct distribute *distribute_lookup(struct distribute_ctx *ctx, + const char *ifname); +extern int config_write_distribute(struct vty *vty, + struct distribute_ctx *ctx); +extern int config_show_distribute(struct vty *vty, + struct distribute_ctx *ctx); extern enum filter_type distribute_apply_in(struct interface *, struct prefix *); diff --git a/lib/hook.c b/lib/hook.c index 4fe305f282..870d158aac 100644 --- a/lib/hook.c +++ b/lib/hook.c @@ -1,23 +1,17 @@ /* * Copyright (c) 2016 David Lamparter, for NetDEF, Inc. * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifdef HAVE_CONFIG_H diff --git a/lib/hook.h b/lib/hook.h index ee496ab365..96fec97d7e 100644 --- a/lib/hook.h +++ b/lib/hook.h @@ -1,23 +1,17 @@ /* * Copyright (c) 2016 David Lamparter, for NetDEF, Inc. * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _FRR_HOOK_H diff --git a/lib/lib_errors.c b/lib/lib_errors.c index b1ed7d2f6b..7e428f135c 100644 --- a/lib/lib_errors.c +++ b/lib/lib_errors.c @@ -105,10 +105,16 @@ static struct log_ref ferr_lib_warn[] = { .suggestion = "Check if the installed FRR YANG modules are in sync with the FRR binaries", }, { - .code = EC_LIB_NB_CB_CONFIG, - .title = "A northbound configuration callback has failed", - .description = "The northbound subsystem has detected that a callback used to process a configuration change has returned an error", - .suggestion = "The log message should contain further details on the specific error that occurred; investigate the reported error.", + .code = EC_LIB_NB_CB_CONFIG_VALIDATE, + .title = "A northbound configuration callback has failed in the VALIDATE phase", + .description = "A callback used to process a configuration change has returned a validation error", + .suggestion = "The provided configuration is invalid. Fix any inconsistency and try again.", + }, + { + .code = EC_LIB_NB_CB_CONFIG_PREPARE, + .title = "A northbound configuration callback has failed in the PREPARE phase", + .description = "A callback used to process a configuration change has returned a resource allocation error", + .suggestion = "The system might be running out of resources. Check the log for more details.", }, { .code = EC_LIB_NB_CB_STATE, @@ -327,6 +333,18 @@ static struct log_ref ferr_lib_err[] = { .suggestion = "Open an Issue with all relevant log files and restart FRR" }, { + .code = EC_LIB_NB_CB_CONFIG_ABORT, + .title = "A northbound configuration callback has failed in the ABORT phase", + .description = "A callback used to process a configuration change has returned an error while trying to abort a change", + .suggestion = "Gather log data and open an Issue.", + }, + { + .code = EC_LIB_NB_CB_CONFIG_APPLY, + .title = "A northbound configuration callback has failed in the APPLY phase", + .description = "A callback used to process a configuration change has returned an error while applying the changes", + .suggestion = "Gather log data and open an Issue.", + }, + { .code = END_FERR, } }; diff --git a/lib/lib_errors.h b/lib/lib_errors.h index 5534edbd8d..86a83df46c 100644 --- a/lib/lib_errors.h +++ b/lib/lib_errors.h @@ -57,7 +57,10 @@ enum lib_log_refs { EC_LIB_NB_CB_MISSING, EC_LIB_NB_CB_INVALID_PRIO, EC_LIB_NB_CBS_VALIDATION, - EC_LIB_NB_CB_CONFIG, + EC_LIB_NB_CB_CONFIG_VALIDATE, + EC_LIB_NB_CB_CONFIG_PREPARE, + EC_LIB_NB_CB_CONFIG_ABORT, + EC_LIB_NB_CB_CONFIG_APPLY, EC_LIB_NB_CB_STATE, EC_LIB_NB_CB_RPC, EC_LIB_NB_CANDIDATE_INVALID, diff --git a/lib/mlag.c b/lib/mlag.c new file mode 100644 index 0000000000..acdc662924 --- /dev/null +++ b/lib/mlag.c @@ -0,0 +1,41 @@ +/* mlag generic code. + * Copyright (C) 2018 Cumulus Networks, Inc. + * Donald Sharp + * + * This file is part of FRR. + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with FRR; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ +#include <zebra.h> + +#include <mlag.h> + +char *mlag_role2str(enum mlag_role role, char *buf, size_t size) +{ + switch (role) { + case MLAG_ROLE_NONE: + snprintf(buf, size, "NONE"); + break; + case MLAG_ROLE_PRIMARY: + snprintf(buf, size, "PRIMARY"); + break; + case MLAG_ROLE_SECONDARY: + snprintf(buf, size, "SECONDARY"); + break; + } + + return buf; +} diff --git a/lib/mlag.h b/lib/mlag.h new file mode 100644 index 0000000000..73725ca3fd --- /dev/null +++ b/lib/mlag.h @@ -0,0 +1,32 @@ +/* mlag header. + * Copyright (C) 2018 Cumulus Networks, Inc. + * Donald Sharp + * + * This file is part of FRR. + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with FRR; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ +#ifndef __MLAG_H__ +#define __MLAG_H__ + +enum mlag_role { + MLAG_ROLE_NONE, + MLAG_ROLE_PRIMARY, + MLAG_ROLE_SECONDARY +}; + +extern char *mlag_role2str(enum mlag_role role, char *buf, size_t size); +#endif diff --git a/lib/module.c b/lib/module.c index 7d5671290b..6754b94579 100644 --- a/lib/module.c +++ b/lib/module.c @@ -1,23 +1,17 @@ /* * Copyright (c) 2015-16 David Lamparter, for NetDEF, Inc. * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "config.h" diff --git a/lib/module.h b/lib/module.h index e66e5cd650..68ed959270 100644 --- a/lib/module.h +++ b/lib/module.h @@ -1,23 +1,17 @@ /* * Copyright (c) 2015-16 David Lamparter, for NetDEF, Inc. * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _FRR_MODULE_H diff --git a/lib/northbound.c b/lib/northbound.c index 8b96dc4a6c..a7f9c8620e 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -719,6 +719,7 @@ static int nb_configuration_callback(const enum nb_event event, const struct lyd_node *dnode = change->cb.dnode; union nb_resource *resource; int ret = NB_ERR; + enum lib_log_refs ref; if (debug_northbound) { const char *value = "(none)"; @@ -751,12 +752,36 @@ static int nb_configuration_callback(const enum nb_event event, break; } - if (ret != NB_OK) - flog_warn( - EC_LIB_NB_CB_CONFIG, - "%s: error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]", - __func__, nb_err_name(ret), nb_event_name(event), - nb_operation_name(operation), xpath); + if (ret != NB_OK) { + switch (event) { + case NB_EV_VALIDATE: + ref = EC_LIB_NB_CB_CONFIG_VALIDATE; + break; + case NB_EV_PREPARE: + ref = EC_LIB_NB_CB_CONFIG_PREPARE; + break; + case NB_EV_ABORT: + ref = EC_LIB_NB_CB_CONFIG_ABORT; + break; + case NB_EV_APPLY: + ref = EC_LIB_NB_CB_CONFIG_APPLY; + break; + } + if (event == NB_EV_VALIDATE || event == NB_EV_PREPARE) + flog_warn( + ref, + "%s: error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]", + __func__, nb_err_name(ret), + nb_event_name(event), + nb_operation_name(operation), xpath); + else + flog_err( + ref, + "%s: error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]", + __func__, nb_err_name(ret), + nb_event_name(event), + nb_operation_name(operation), xpath); + } return ret; } @@ -1071,7 +1096,7 @@ static int nb_oper_data_iter_list(const struct nb_node *nb_node, /* Iterate over all list entries. */ do { struct yang_list_keys list_keys; - char xpath[XPATH_MAXLEN]; + char xpath[XPATH_MAXLEN * 2]; int ret; /* Obtain list entry. */ diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c index d685a4e7c2..2b024ace93 100644 --- a/lib/northbound_cli.c +++ b/lib/northbound_cli.c @@ -71,7 +71,7 @@ void nb_cli_enqueue_change(struct vty *vty, const char *xpath, } change = &vty->cfg_changes[vty->num_cfg_changes++]; - change->xpath = xpath; + strlcpy(change->xpath, xpath, sizeof(change->xpath)); change->operation = operation; change->value = value; } @@ -79,8 +79,7 @@ void nb_cli_enqueue_change(struct vty *vty, const char *xpath, int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, ...) { struct nb_config *candidate_transitory; - char xpath_base[XPATH_MAXLEN]; - va_list ap; + char xpath_base[XPATH_MAXLEN] = {}; bool error = false; int ret; @@ -94,9 +93,13 @@ int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, ...) candidate_transitory = nb_config_dup(vty->candidate_config); /* Parse the base XPath format string. */ - va_start(ap, xpath_base_fmt); - vsnprintf(xpath_base, sizeof(xpath_base), xpath_base_fmt, ap); - va_end(ap); + if (xpath_base_fmt) { + va_list ap; + + va_start(ap, xpath_base_fmt); + vsnprintf(xpath_base, sizeof(xpath_base), xpath_base_fmt, ap); + va_end(ap); + } /* Edit candidate configuration. */ for (size_t i = 0; i < vty->num_cfg_changes; i++) { diff --git a/lib/northbound_cli.h b/lib/northbound_cli.h index 362a4bc325..884f250941 100644 --- a/lib/northbound_cli.h +++ b/lib/northbound_cli.h @@ -60,7 +60,7 @@ extern void nb_cli_enqueue_change(struct vty *vty, const char *xpath, * * xpath_base_fmt * Prepend the given XPath (absolute or relative) to all enqueued - * configuration changes. + * configuration changes. This is an optional parameter. * * Returns: * CMD_SUCCESS on success, CMD_WARNING_CONFIG_FAILED otherwise. diff --git a/lib/subdir.am b/lib/subdir.am index 43b39100cb..ccbe13bca6 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -44,6 +44,7 @@ lib_libfrr_la_SOURCES = \ lib/md5.c \ lib/memory.c \ lib/memory_vty.c \ + lib/mlag.c \ lib/module.c \ lib/mpls.c \ lib/network.c \ @@ -134,6 +135,7 @@ pkginclude_HEADERS += \ lib/bitfield.h \ lib/buffer.h \ lib/checksum.h \ + lib/mlag.h \ lib/command.h \ lib/command_graph.h \ lib/command_match.h \ @@ -330,6 +330,8 @@ vrf_id_t vrf_name_to_id(const char *name) vrf_id_t vrf_id = VRF_DEFAULT; // Pending: need a way to return invalid // id/ routine not used. + if (!name) + return vrf_id; vrf = vrf_lookup_by_name(name); if (vrf) vrf_id = vrf->vrf_id; @@ -43,7 +43,7 @@ struct vty_error { }; struct vty_cfg_change { - const char *xpath; + char xpath[XPATH_MAXLEN]; enum nb_operation operation; const char *value; }; diff --git a/lib/workqueue.c b/lib/workqueue.c index c927d5d714..24ef24c774 100644 --- a/lib/workqueue.c +++ b/lib/workqueue.c @@ -91,9 +91,10 @@ struct work_queue *work_queue_new(struct thread_master *m, new->cycles.granularity = WORK_QUEUE_MIN_GRANULARITY; - /* Default values, can be overriden by caller */ + /* Default values, can be overridden by caller */ new->spec.hold = WORK_QUEUE_DEFAULT_HOLD; new->spec.yield = THREAD_YIELD_TIME_SLOT; + new->spec.retry = WORK_QUEUE_DEFAULT_RETRY; return new; } @@ -133,8 +134,17 @@ static int work_queue_schedule(struct work_queue *wq, unsigned int delay) if (CHECK_FLAG(wq->flags, WQ_UNPLUGGED) && (wq->thread == NULL) && !work_queue_empty(wq)) { wq->thread = NULL; - thread_add_timer_msec(wq->master, work_queue_run, wq, delay, - &wq->thread); + + /* Schedule timer if there's a delay, otherwise just schedule + * as an 'event' + */ + if (delay > 0) + thread_add_timer_msec(wq->master, work_queue_run, wq, + delay, &wq->thread); + else + thread_add_event(wq->master, work_queue_run, wq, 0, + &wq->thread); + /* set thread yield time, if needed */ if (wq->thread && wq->spec.yield != THREAD_YIELD_TIME_SLOT) thread_set_yield_time(wq->thread, wq->spec.yield); @@ -234,7 +244,7 @@ int work_queue_run(struct thread *thread) { struct work_queue *wq; struct work_queue_item *item, *titem; - wq_item_status ret; + wq_item_status ret = WQ_SUCCESS; unsigned int cycles = 0; char yielded = 0; @@ -376,9 +386,14 @@ stats: #endif /* Is the queue done yet? If it is, call the completion callback. */ - if (!work_queue_empty(wq)) - work_queue_schedule(wq, 0); - else if (wq->spec.completion_func) + if (!work_queue_empty(wq)) { + if (ret == WQ_RETRY_LATER || + ret == WQ_QUEUE_BLOCKED) + work_queue_schedule(wq, wq->spec.retry); + else + work_queue_schedule(wq, 0); + + } else if (wq->spec.completion_func) wq->spec.completion_func(wq); return 0; diff --git a/lib/workqueue.h b/lib/workqueue.h index fe1700f8de..7c84655063 100644 --- a/lib/workqueue.h +++ b/lib/workqueue.h @@ -30,6 +30,9 @@ DECLARE_MTYPE(WORK_QUEUE) /* Hold time for the initial schedule of a queue run, in millisec */ #define WORK_QUEUE_DEFAULT_HOLD 50 +/* Retry for queue that is 'blocked' or 'retry later' */ +#define WORK_QUEUE_DEFAULT_RETRY 0 + /* action value, for use by item processor and item error handlers */ typedef enum { WQ_SUCCESS = 0, @@ -90,6 +93,8 @@ struct work_queue { unsigned long yield; /* yield time in us for associated thread */ + + uint32_t retry; /* Optional retry timeout if queue is blocked */ } spec; /* remaining fields should be opaque to users */ diff --git a/lib/yang.c b/lib/yang.c index 462e693549..71b41c35d8 100644 --- a/lib/yang.c +++ b/lib/yang.c @@ -71,9 +71,11 @@ static const char *yang_module_imp_clb(const char *mod_name, return NULL; } -static const char * const frr_native_modules[] = { +static const char *const frr_native_modules[] = { "frr-interface", "frr-ripd", + "frr-ripngd", + "frr-isisd", }; /* Generate the yang_modules tree. */ diff --git a/lib/yang_wrappers.c b/lib/yang_wrappers.c index 96076d6468..6273dff3ce 100644 --- a/lib/yang_wrappers.c +++ b/lib/yang_wrappers.c @@ -171,6 +171,7 @@ int yang_str2enum(const char *xpath, const char *value) { const struct lys_node *snode; const struct lys_node_leaf *sleaf; + const struct lys_type *type; const struct lys_type_info_enums *enums; snode = ly_ctx_get_node(ly_native_ctx, NULL, xpath, 0); @@ -182,7 +183,12 @@ int yang_str2enum(const char *xpath, const char *value) } sleaf = (const struct lys_node_leaf *)snode; - enums = &sleaf->type.info.enums; + type = &sleaf->type; + enums = &type->info.enums; + while (enums->count == 0 && type->der) { + type = &type->der->type; + enums = &type->info.enums; + } for (unsigned int i = 0; i < enums->count; i++) { const struct lys_type_enum *enm = &enums->enm[i]; diff --git a/lib/zclient.c b/lib/zclient.c index beb3ca4f34..1c40750db0 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1770,19 +1770,19 @@ struct interface *zebra_interface_vrf_update_read(struct stream *s, vrf_id_t vrf_id, vrf_id_t *new_vrf_id) { - unsigned int ifindex; + char ifname[INTERFACE_NAMSIZ]; struct interface *ifp; vrf_id_t new_id; - /* Get interface index. */ - ifindex = stream_getl(s); + /* Read interface name. */ + stream_get(ifname, s, INTERFACE_NAMSIZ); /* Lookup interface. */ - ifp = if_lookup_by_index(ifindex, vrf_id); + ifp = if_lookup_by_name(ifname, vrf_id); if (ifp == NULL) { flog_err(EC_LIB_ZAPI_ENCODE, - "INTERFACE_VRF_UPDATE: Cannot find IF %u in VRF %d", - ifindex, vrf_id); + "INTERFACE_VRF_UPDATE: Cannot find IF %s in VRF %d", + ifname, vrf_id); return NULL; } @@ -2355,6 +2355,7 @@ static void zclient_capability_decode(int command, struct zclient *zclient, STREAM_GETC(s, mpls_enabled); cap.mpls_enabled = !!mpls_enabled; STREAM_GETL(s, cap.ecmp); + STREAM_GETC(s, cap.role); if (zclient->zebra_capabilities) (*zclient->zebra_capabilities)(&cap); diff --git a/lib/zclient.h b/lib/zclient.h index adb48b252a..831cccfb7e 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -36,6 +36,8 @@ /* For union pw_protocol_fields */ #include "pw.h" +#include "mlag.h" + /* For input/output buffer to zebra. */ #define ZEBRA_MAX_PACKET_SIZ 16384 @@ -58,6 +60,10 @@ #define ZEBRA_IPTABLES_FORWARD 0 #define ZEBRA_IPTABLES_DROP 1 +/* Zebra FEC register command flags. */ +#define ZEBRA_FEC_REGISTER_LABEL 0x1 +#define ZEBRA_FEC_REGISTER_LABEL_INDEX 0x2 + extern struct sockaddr_storage zclient_addr; extern socklen_t zclient_addr_len; @@ -167,6 +173,7 @@ struct redist_proto { struct zclient_capabilities { uint32_t ecmp; bool mpls_enabled; + enum mlag_role role; }; /* Structure for the zebra client. */ diff --git a/lib/zebra.h b/lib/zebra.h index 46721cc1ab..09115951e9 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -410,21 +410,47 @@ extern const char *zserv_command_string(unsigned int command); #define strmatch(a,b) (!strcmp((a), (b))) /* Zebra message flags */ + +/* + * Cause Zebra to consider this routes nexthops recursively + */ #define ZEBRA_FLAG_ALLOW_RECURSION 0x01 +/* + * This is a route that is read in on startup that was left around + * from a previous run of FRR + */ #define ZEBRA_FLAG_SELFROUTE 0x02 -#define ZEBRA_FLAG_IBGP 0x08 -#define ZEBRA_FLAG_SELECTED 0x10 -#define ZEBRA_FLAG_STATIC 0x40 -#define ZEBRA_FLAG_SCOPE_LINK 0x100 -#define ZEBRA_FLAG_FIB_OVERRIDE 0x200 -#define ZEBRA_FLAG_EVPN_ROUTE 0x400 -#define ZEBRA_FLAG_RR_USE_DISTANCE 0x800 -#define ZEBRA_FLAG_ONLINK 0x1000 -/* ZEBRA_FLAG_BLACKHOLE was 0x04 */ -/* ZEBRA_FLAG_REJECT was 0x80 */ - -/* Zebra FEC flags. */ -#define ZEBRA_FEC_REGISTER_LABEL_INDEX 0x1 +/* + * This flag is used to tell Zebra that the BGP route being passed + * down is a IBGP route + */ +#define ZEBRA_FLAG_IBGP 0x04 +/* + * This is a route that has been selected for FIB installation. + * This flag is set in zebra and can be passed up to routing daemons + */ +#define ZEBRA_FLAG_SELECTED 0x08 +/* + * This is a route that we are telling Zebra that this route *must* + * win and will be installed even over ZEBRA_FLAG_SELECTED + */ +#define ZEBRA_FLAG_FIB_OVERRIDE 0x10 +/* + * This flag tells Zebra that the route is a EVPN route and should + * be treated specially + */ +#define ZEBRA_FLAG_EVPN_ROUTE 0x20 +/* + * This flag tells Zebra that it should treat the distance passed + * down as an additional discriminator for route selection of the + * route entry. This mainly is used for backup static routes. + */ +#define ZEBRA_FLAG_RR_USE_DISTANCE 0x40 +/* + * This flag tells Zebra that the passed down route is ONLINK and the + * kernel install flag for it should be turned on + */ +#define ZEBRA_FLAG_ONLINK 0x80 #ifndef INADDR_LOOPBACK #define INADDR_LOOPBACK 0x7f000001 /* Internet address 127.0.0.1. */ |
