summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/agg_table.c2
-rw-r--r--lib/buffer.c6
-rw-r--r--lib/command.c35
-rw-r--r--lib/command.h12
-rw-r--r--lib/command_graph.h2
-rw-r--r--lib/command_lex.l2
-rw-r--r--lib/command_parse.y8
-rw-r--r--lib/defaults.c229
-rw-r--r--lib/defaults.h138
-rw-r--r--lib/filter.c14
-rw-r--r--lib/frr_pthread.c4
-rw-r--r--lib/frr_pthread.h4
-rw-r--r--lib/frrcu.c4
-rw-r--r--lib/frrcu.h2
-rw-r--r--lib/grammar_sandbox.c14
-rw-r--r--lib/grammar_sandbox_main.c4
-rw-r--r--lib/if.c29
-rw-r--r--lib/lib_vty.c (renamed from lib/memory_vty.c)79
-rw-r--r--lib/lib_vty.h (renamed from lib/memory_vty.h)8
-rw-r--r--lib/libfrr.c38
-rw-r--r--lib/libfrr.h2
-rw-r--r--lib/linklist.c23
-rw-r--r--lib/linklist.h24
-rw-r--r--lib/memory.h23
-rw-r--r--lib/mlag.c126
-rw-r--r--lib/mlag.h104
-rw-r--r--lib/netns_linux.c7
-rw-r--r--lib/netns_other.c2
-rw-r--r--lib/nexthop.c118
-rw-r--r--lib/nexthop.h19
-rw-r--r--lib/nexthop_group.c235
-rw-r--r--lib/nexthop_group.h15
-rw-r--r--lib/nexthop_group_private.h2
-rw-r--r--lib/northbound.c3
-rw-r--r--lib/northbound.h3
-rw-r--r--lib/northbound_cli.c13
-rw-r--r--lib/ns.h2
-rw-r--r--lib/plist.c2
-rw-r--r--lib/prefix.c492
-rw-r--r--lib/prefix.h7
-rw-r--r--lib/printfrr.h4
-rw-r--r--lib/qobj.c4
-rw-r--r--lib/qobj.h12
-rw-r--r--lib/resolver.c47
-rw-r--r--lib/resolver.h10
-rw-r--r--lib/routemap.c34
-rw-r--r--lib/routemap.h4
-rw-r--r--lib/skiplist.c2
-rw-r--r--lib/sockopt.c15
-rw-r--r--lib/sockopt.h1
-rw-r--r--lib/stream.c12
-rw-r--r--lib/stream.h13
-rw-r--r--lib/subdir.am7
-rw-r--r--lib/systemd.c6
-rw-r--r--lib/systemd.h1
-rw-r--r--lib/table.h2
-rw-r--r--lib/termtable.c4
-rw-r--r--lib/termtable.h4
-rw-r--r--lib/thread.c2
-rw-r--r--lib/vrf.c5
-rw-r--r--lib/vrf.h25
-rw-r--r--lib/vty.c2
-rw-r--r--lib/zclient.c389
-rw-r--r--lib/zclient.h54
64 files changed, 1623 insertions, 892 deletions
diff --git a/lib/agg_table.c b/lib/agg_table.c
index dad6a13d67..22b981e284 100644
--- a/lib/agg_table.c
+++ b/lib/agg_table.c
@@ -41,7 +41,7 @@ static void agg_node_destroy(route_table_delegate_t *delegate,
XFREE(MTYPE_TMP, anode);
}
-route_table_delegate_t agg_table_delegate = {
+static route_table_delegate_t agg_table_delegate = {
.create_node = agg_node_create,
.destroy_node = agg_node_destroy,
};
diff --git a/lib/buffer.c b/lib/buffer.c
index bb2cdb7e54..766b9791a5 100644
--- a/lib/buffer.c
+++ b/lib/buffer.c
@@ -114,12 +114,6 @@ char *buffer_getstr(struct buffer *b)
return s;
}
-/* Return 1 if buffer is empty. */
-int buffer_empty(struct buffer *b)
-{
- return (b->head == NULL);
-}
-
/* Clear and free all allocated data. */
void buffer_reset(struct buffer *b)
{
diff --git a/lib/command.c b/lib/command.c
index 59668e95fc..d2145d9f5a 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -74,7 +74,7 @@ const struct message tokennames[] = {
{0},
};
-const char *node_names[] = {
+const char *const node_names[] = {
"auth", // AUTH_NODE,
"view", // VIEW_NODE,
"auth enable", // AUTH_ENABLE_NODE,
@@ -370,7 +370,7 @@ const char *cmd_prompt(enum node_type node)
}
/* Install a command into a node. */
-void install_element(enum node_type ntype, struct cmd_element *cmd)
+void install_element(enum node_type ntype, const struct cmd_element *cmd)
{
struct cmd_node *cnode;
@@ -392,7 +392,7 @@ void install_element(enum node_type ntype, struct cmd_element *cmd)
exit(EXIT_FAILURE);
}
- if (hash_lookup(cnode->cmd_hash, cmd) != NULL) {
+ if (hash_lookup(cnode->cmd_hash, (void *)cmd) != NULL) {
fprintf(stderr,
"%s[%s]:\n"
"\tnode %d (%s) already has this command installed.\n"
@@ -401,7 +401,7 @@ void install_element(enum node_type ntype, struct cmd_element *cmd)
return;
}
- assert(hash_get(cnode->cmd_hash, cmd, hash_alloc_intern));
+ assert(hash_get(cnode->cmd_hash, (void *)cmd, hash_alloc_intern));
struct graph *graph = graph_new();
struct cmd_token *token =
@@ -413,13 +413,13 @@ void install_element(enum node_type ntype, struct cmd_element *cmd)
cmd_graph_merge(cnode->cmdgraph, graph, +1);
graph_delete_graph(graph);
- vector_set(cnode->cmd_vector, cmd);
+ vector_set(cnode->cmd_vector, (void *)cmd);
if (ntype == VIEW_NODE)
install_element(ENABLE_NODE, cmd);
}
-void uninstall_element(enum node_type ntype, struct cmd_element *cmd)
+void uninstall_element(enum node_type ntype, const struct cmd_element *cmd)
{
struct cmd_node *cnode;
@@ -441,7 +441,7 @@ void uninstall_element(enum node_type ntype, struct cmd_element *cmd)
exit(EXIT_FAILURE);
}
- if (hash_release(cnode->cmd_hash, cmd) == NULL) {
+ if (hash_release(cnode->cmd_hash, (void *)cmd) == NULL) {
fprintf(stderr,
"%s[%s]:\n"
"\tnode %d (%s) does not have this command installed.\n"
@@ -450,7 +450,7 @@ void uninstall_element(enum node_type ntype, struct cmd_element *cmd)
return;
}
- vector_unset_value(cnode->cmd_vector, cmd);
+ vector_unset_value(cnode->cmd_vector, (void *)cmd);
struct graph *graph = graph_new();
struct cmd_token *token =
@@ -1575,18 +1575,6 @@ DEFUN (show_version,
return CMD_SUCCESS;
}
-/* "Set" version ... ignore version tags */
-DEFUN (frr_version_defaults,
- frr_version_defaults_cmd,
- "frr <version|defaults> LINE...",
- "FRRouting global parameters\n"
- "version configuration was written by\n"
- "set of configuration defaults used\n"
- "version string\n")
-{
- return CMD_SUCCESS;
-}
-
/* Help display function for all node. */
DEFUN (config_help,
config_help_cmd,
@@ -1660,7 +1648,7 @@ int cmd_list_cmds(struct vty *vty, int do_permute)
permute(vector_slot(node->cmdgraph->nodes, 0), vty);
else {
/* loop over all commands at this node */
- struct cmd_element *element = NULL;
+ const struct cmd_element *element = NULL;
for (unsigned int i = 0; i < vector_active(node->cmd_vector);
i++)
if ((element = vector_slot(node->cmd_vector, i))
@@ -1721,8 +1709,10 @@ static int vty_write_config(struct vty *vty)
vty_out(vty, "!\n");
}
+ if (strcmp(frr_defaults_version(), FRR_VER_SHORT))
+ vty_out(vty, "! loaded from %s\n", frr_defaults_version());
vty_out(vty, "frr version %s\n", FRR_VER_SHORT);
- vty_out(vty, "frr defaults %s\n", DFLT_NAME);
+ vty_out(vty, "frr defaults %s\n", frr_defaults_profile());
vty_out(vty, "!\n");
for (i = 0; i < vector_active(cmdvec); i++)
@@ -2941,7 +2931,6 @@ void cmd_init(int terminal)
install_element(CONFIG_NODE, &no_hostname_cmd);
install_element(CONFIG_NODE, &domainname_cmd);
install_element(CONFIG_NODE, &no_domainname_cmd);
- install_element(CONFIG_NODE, &frr_version_defaults_cmd);
if (terminal > 0) {
install_element(CONFIG_NODE, &debug_memstats_cmd);
diff --git a/lib/command.h b/lib/command.h
index 73c15469e7..c8dd04604d 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -165,7 +165,7 @@ enum node_type {
extern vector cmdvec;
extern const struct message tokennames[];
-extern const char *node_names[];
+extern const char *const node_names[];
/* Node which has some commands and prompt string and configuration
function pointer . */
@@ -217,7 +217,7 @@ struct cmd_node {
/* helper defines for end-user DEFUN* macros */
#define DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attrs, dnum) \
- static struct cmd_element cmdname = { \
+ static const struct cmd_element cmdname = { \
.string = cmdstr, \
.func = funcname, \
.doc = helpstr, \
@@ -414,18 +414,18 @@ struct cmd_node {
/* Daemons lists */
#define DAEMONS_STR \
- "For the zebra daemon\nFor the rip daemon\nFor the ripng daemon\nFor the ospf daemon\nFor the ospfv6 daemon\nFor the bgp daemon\nFor the isis daemon\nFor the pbr daemon\nFor the fabricd daemon\nFor the pim daemon\nFor the static daemon\nFor the sharpd daemon\nFor the vrrpd daemon\n"
+ "For the zebra daemon\nFor the rip daemon\nFor the ripng daemon\nFor the ospf daemon\nFor the ospfv6 daemon\nFor the bgp daemon\nFor the isis daemon\nFor the pbr daemon\nFor the fabricd daemon\nFor the pim daemon\nFor the static daemon\nFor the sharpd daemon\nFor the vrrpd daemon\nFor the ldpd daemon\n"
#define DAEMONS_LIST \
- "<zebra|ripd|ripngd|ospfd|ospf6d|bgpd|isisd|pbrd|fabricd|pimd|staticd|sharpd|vrrpd>"
+ "<zebra|ripd|ripngd|ospfd|ospf6d|bgpd|isisd|pbrd|fabricd|pimd|staticd|sharpd|vrrpd|ldpd>"
/* Prototypes. */
extern void install_node(struct cmd_node *, int (*)(struct vty *));
extern void install_default(enum node_type);
-extern void install_element(enum node_type, struct cmd_element *);
+extern void install_element(enum node_type, const struct cmd_element *);
/* known issue with uninstall_element: changes to cmd_token->attr (i.e.
* deprecated/hidden) are not reversed. */
-extern void uninstall_element(enum node_type, struct cmd_element *);
+extern void uninstall_element(enum node_type, const struct cmd_element *);
/* Concatenates argv[shift] through argv[argc-1] into a single NUL-terminated
string with a space between each element (allocated using
diff --git a/lib/command_graph.h b/lib/command_graph.h
index 903d515834..1efe8b1803 100644
--- a/lib/command_graph.h
+++ b/lib/command_graph.h
@@ -116,7 +116,7 @@ extern struct cmd_token *cmd_token_dup(struct cmd_token *);
extern void cmd_token_del(struct cmd_token *);
extern void cmd_token_varname_set(struct cmd_token *token, const char *varname);
-extern void cmd_graph_parse(struct graph *graph, struct cmd_element *cmd);
+extern void cmd_graph_parse(struct graph *graph, const struct cmd_element *cmd);
extern void cmd_graph_names(struct graph *graph);
extern void cmd_graph_merge(struct graph *old, struct graph *n,
int direction);
diff --git a/lib/command_lex.l b/lib/command_lex.l
index f361db78e9..0556605d63 100644
--- a/lib/command_lex.l
+++ b/lib/command_lex.l
@@ -85,7 +85,7 @@ RANGE \({NUMBER}[ ]?\-[ ]?{NUMBER}\)
. {return yytext[0];}
%%
-YY_BUFFER_STATE buffer;
+static YY_BUFFER_STATE buffer;
void set_lexer_string (yyscan_t *scn, const char *string)
{
diff --git a/lib/command_parse.y b/lib/command_parse.y
index 062a4bb30c..5dc19d2c9b 100644
--- a/lib/command_parse.y
+++ b/lib/command_parse.y
@@ -84,7 +84,7 @@
struct parser_ctx {
yyscan_t scanner;
- struct cmd_element *el;
+ const struct cmd_element *el;
struct graph *graph;
struct graph_node *currnode;
@@ -379,7 +379,7 @@ selector: '[' selector_seq_seq ']' varname_token
DEFINE_MTYPE(LIB, LEX, "Lexer token (temporary)")
void
-cmd_graph_parse (struct graph *graph, struct cmd_element *cmd)
+cmd_graph_parse (struct graph *graph, const struct cmd_element *cmd)
{
struct parser_ctx ctx = { .graph = graph, .el = cmd };
@@ -485,11 +485,11 @@ terminate_graph (CMD_YYLTYPE *locp, struct parser_ctx *ctx,
{
// end of graph should look like this
// * -> finalnode -> END_TKN -> cmd_element
- struct cmd_element *element = ctx->el;
+ const struct cmd_element *element = ctx->el;
struct graph_node *end_token_node =
new_token_node (ctx, END_TKN, CMD_CR_TEXT, "");
struct graph_node *end_element_node =
- graph_new_node (ctx->graph, element, NULL);
+ graph_new_node (ctx->graph, (void *)element, NULL);
if (ctx->docstr && strlen (ctx->docstr) > 1) {
zlog_debug ("Excessive docstring while parsing '%s'", ctx->el->string);
diff --git a/lib/defaults.c b/lib/defaults.c
new file mode 100644
index 0000000000..71ccc73cc6
--- /dev/null
+++ b/lib/defaults.c
@@ -0,0 +1,229 @@
+/*
+ * FRR switchable defaults.
+ * Copyright (c) 2017-2019 David Lamparter, for NetDEF, Inc.
+ *
+ * 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.
+ */
+
+#include <zebra.h>
+
+#include "defaults.h"
+#include "version.h"
+
+static char df_version[128] = FRR_VER_SHORT, df_profile[128] = DFLT_NAME;
+static struct frr_default *dflt_first = NULL, **dflt_next = &dflt_first;
+
+/* these are global for all FRR daemons. they have to be, since we write an
+ * integrated config with the same value for all daemons.
+ */
+const char *frr_defaults_profiles[] = {
+ "traditional",
+ "datacenter",
+ NULL,
+};
+
+static int version_value(int ch)
+{
+ /* non-ASCII shouldn't happen */
+ if (ch < 0 || ch >= 128)
+ return 2;
+
+ /* ~foo sorts older than nothing */
+ if (ch == '~')
+ return 0;
+ if (ch == '\0')
+ return 1;
+ if (isalpha(ch))
+ return 0x100 + tolower(ch);
+
+ /* punctuation and digits (and everything else) */
+ return 0x200 + ch;
+}
+
+int frr_version_cmp(const char *aa, const char *bb)
+{
+ const char *apos = aa, *bpos = bb;
+
+ /* || is correct, we won't scan past the end of a string since that
+ * doesn't compare equal to anything else */
+ while (apos[0] || bpos[0]) {
+ if (isdigit((unsigned char)apos[0]) &&
+ isdigit((unsigned char)bpos[0])) {
+ unsigned long av, bv;
+ char *aend = NULL, *bend = NULL;
+
+ av = strtoul(apos, &aend, 10);
+ bv = strtoul(bpos, &bend, 10);
+ if (av < bv)
+ return -1;
+ if (av > bv)
+ return 1;
+
+ apos = aend;
+ bpos = bend;
+ continue;
+ }
+
+ int a = version_value(*apos++);
+ int b = version_value(*bpos++);
+
+ if (a < b)
+ return -1;
+ if (a > b)
+ return 1;
+ }
+ return 0;
+}
+
+static void frr_default_apply_one(struct frr_default *dflt, bool check);
+
+void frr_default_add(struct frr_default *dflt)
+{
+ dflt->next = NULL;
+ *dflt_next = dflt;
+ dflt_next = &dflt->next;
+
+ frr_default_apply_one(dflt, true);
+}
+
+static bool frr_match_version(const char *name, const char *vspec,
+ const char *version, bool check)
+{
+ int cmp;
+ static struct spec {
+ const char *str;
+ bool dir, eq;
+ } *s, specs[] = {
+ {"<=", -1, 1},
+ {">=", 1, 1},
+ {"==", 0, 1},
+ {"<", -1, 0},
+ {">", 1, 0},
+ {"=", 0, 1},
+ {NULL, 0, 0},
+ };
+
+ if (!vspec)
+ /* NULL = all versions */
+ return true;
+
+ for (s = specs; s->str; s++)
+ if (!strncmp(s->str, vspec, strlen(s->str)))
+ break;
+ if (!s->str) {
+ if (check)
+ fprintf(stderr, "invalid version specifier for %s: %s",
+ name, vspec);
+ /* invalid version spec, never matches */
+ return false;
+ }
+
+ vspec += strlen(s->str);
+ while (isspace((unsigned char)*vspec))
+ vspec++;
+
+ cmp = frr_version_cmp(version, vspec);
+ if (cmp == s->dir || (s->eq && cmp == 0))
+ return true;
+
+ return false;
+}
+
+static void frr_default_apply_one(struct frr_default *dflt, bool check)
+{
+ struct frr_default_entry *entry = dflt->entries;
+ struct frr_default_entry *dfltentry = NULL, *saveentry = NULL;
+
+ for (; entry->match_version || entry->match_profile; entry++) {
+ if (entry->match_profile
+ && strcmp(entry->match_profile, df_profile))
+ continue;
+
+ if (!dfltentry && frr_match_version(dflt->name,
+ entry->match_version, df_version, check))
+ dfltentry = entry;
+ if (!saveentry && frr_match_version(dflt->name,
+ entry->match_version, FRR_VER_SHORT, check))
+ saveentry = entry;
+
+ if (dfltentry && saveentry && !check)
+ break;
+ }
+ /* found default or arrived at last entry that has NULL,NULL spec */
+
+ if (!dfltentry)
+ dfltentry = entry;
+ if (!saveentry)
+ saveentry = entry;
+
+ if (dflt->dflt_bool)
+ *dflt->dflt_bool = dfltentry->val_bool;
+ if (dflt->dflt_str)
+ *dflt->dflt_str = dfltentry->val_str;
+ if (dflt->dflt_long)
+ *dflt->dflt_long = dfltentry->val_long;
+ if (dflt->dflt_ulong)
+ *dflt->dflt_ulong = dfltentry->val_ulong;
+ if (dflt->dflt_float)
+ *dflt->dflt_float = dfltentry->val_float;
+ if (dflt->save_bool)
+ *dflt->save_bool = saveentry->val_bool;
+ if (dflt->save_str)
+ *dflt->save_str = saveentry->val_str;
+ if (dflt->save_long)
+ *dflt->save_long = saveentry->val_long;
+ if (dflt->save_ulong)
+ *dflt->save_ulong = saveentry->val_ulong;
+ if (dflt->save_float)
+ *dflt->save_float = saveentry->val_float;
+}
+
+void frr_defaults_apply(void)
+{
+ struct frr_default *dflt;
+
+ for (dflt = dflt_first; dflt; dflt = dflt->next)
+ frr_default_apply_one(dflt, false);
+}
+
+bool frr_defaults_profile_valid(const char *profile)
+{
+ const char **p;
+
+ for (p = frr_defaults_profiles; *p; p++)
+ if (!strcmp(profile, *p))
+ return true;
+ return false;
+}
+
+const char *frr_defaults_version(void)
+{
+ return df_version;
+}
+
+const char *frr_defaults_profile(void)
+{
+ return df_profile;
+}
+
+void frr_defaults_version_set(const char *version)
+{
+ strlcpy(df_version, version, sizeof(df_version));
+ frr_defaults_apply();
+}
+
+void frr_defaults_profile_set(const char *profile)
+{
+ strlcpy(df_profile, profile, sizeof(df_profile));
+ frr_defaults_apply();
+}
diff --git a/lib/defaults.h b/lib/defaults.h
new file mode 100644
index 0000000000..7cdd18120e
--- /dev/null
+++ b/lib/defaults.h
@@ -0,0 +1,138 @@
+/*
+ * FRR switchable defaults.
+ * Copyright (C) 2017-2019 David Lamparter for NetDEF, Inc.
+ *
+ * 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_DEFAULTS_H
+#define _FRR_DEFAULTS_H
+
+#include <stdbool.h>
+
+#include "compiler.h"
+
+/* frr_default wraps information about a default that has different
+ * values depending on FRR version or default-set
+ *
+ * frr_default_entry describes one match rule and the resulting value;
+ * entries are evaluated in order and the first matching is used.
+ *
+ * If both match_version and match_profile are specified, they must both
+ * match. A NULL value matches everything.
+ */
+struct frr_default_entry {
+ /* syntax: "(<|<=|==|>=|>) [whitespace] version", e.g.
+ * ">= 6.1-dev" "<6.0"
+ */
+ const char *match_version;
+ /* exact profile string to compare against */
+ const char *match_profile;
+
+ /* value to use */
+ bool val_bool;
+ const char *val_str;
+ long val_long;
+ unsigned long val_ulong;
+ float val_float;
+};
+
+/* one struct frr_default exists for each malleable default value */
+struct frr_default {
+ struct frr_default *next;
+
+ /* for UI/debug use */
+ const char *name;
+
+ /* the following two sets of variables differ because the written
+ * config always targets the *current* FRR version
+ *
+ * e.g. if you load a config that has "frr version 5.0" on 6.0
+ * *dflt_long => set to the default value in 5.0
+ * *save_long => set to the default value in 6.0
+ * config save will write "frr version 6.0" with 6.0 defaults
+ */
+
+ /* variable holding the default value for reading/use */
+ bool *dflt_bool;
+ const char **dflt_str;
+ long *dflt_long;
+ unsigned long *dflt_ulong;
+ float *dflt_float;
+
+ /* variable to use when comparing for config save */
+ bool *save_bool;
+ const char **save_str;
+ long *save_long;
+ unsigned long *save_ulong;
+ float *save_float;
+
+ struct frr_default_entry entries[];
+};
+
+#define _FRR_CFG_DEFAULT(type, typname, varname, ...) \
+ static type DFLT_##varname; \
+ static type SAVE_##varname; \
+ static struct frr_default _dflt_##varname = { \
+ .name = #varname, \
+ .dflt_##typname = &DFLT_##varname, \
+ .save_##typname = &SAVE_##varname, \
+ .entries = { __VA_ARGS__ }, \
+ }; \
+ static void _dfltinit_##varname(void) \
+ __attribute__((_CONSTRUCTOR(1000))); \
+ static void _dfltinit_##varname(void) \
+ { \
+ frr_default_add(&_dflt_##varname); \
+ }
+
+/* use:
+ * FRR_CFG_DEFAULT_LONG(SHARP_BLUNTNESS,
+ * { .val_long = 2, .match_version = ">= 10.0" },
+ * { .val_long = 1, .match_profile = "datacenter" },
+ * { .val_long = 0 },
+ * )
+ *
+ * This will create DFLT_SHARP_BLUNTNESS and SAVE_SHARP_BLUNTNESS variables.
+ *
+ * Note: preprocessor defines cannot be used as variable names because they
+ * will be expanded and blow up with a compile error. Use an enum or add an
+ * extra _ at the beginning (e.g. _SHARP_BLUNTNESS => DFLT__SHARP_BLUNTNESS)
+ */
+#define FRR_CFG_DEFAULT_BOOL(varname, ...) \
+ _FRR_CFG_DEFAULT(bool, bool, varname, ## __VA_ARGS__)
+#define FRR_CFG_DEFAULT_LONG(varname, ...) \
+ _FRR_CFG_DEFAULT(long, long, varname, ## __VA_ARGS__)
+#define FRR_CFG_DEFAULT_ULONG(varname, ...) \
+ _FRR_CFG_DEFAULT(unsigned long, ulong, varname, ## __VA_ARGS__)
+#define FRR_CFG_DEFAULT_FLOAT(varname, ...) \
+ _FRR_CFG_DEFAULT(float, float, varname, ## __VA_ARGS__)
+#define FRR_CFG_DEFAULT_STR(varname, ...) \
+ _FRR_CFG_DEFAULT(const char *, str, varname, ## __VA_ARGS__)
+
+
+/* daemons don't need to call any of these, libfrr handles that */
+extern void frr_default_add(struct frr_default *dflt);
+extern void frr_defaults_version_set(const char *version);
+extern void frr_defaults_profile_set(const char *profile);
+extern const char *frr_defaults_version(void);
+extern const char *frr_defaults_profile(void);
+extern void frr_defaults_apply(void);
+
+extern const char *frr_defaults_profiles[];
+extern bool frr_defaults_profile_valid(const char *profile);
+
+/* like strcmp(), but with version ordering */
+extern int frr_version_cmp(const char *aa, const char *bb);
+
+#endif /* _FRR_DEFAULTS_H */
diff --git a/lib/filter.c b/lib/filter.c
index 8c210bd7ad..31e25d6001 100644
--- a/lib/filter.c
+++ b/lib/filter.c
@@ -2147,7 +2147,7 @@ DEFUN (no_access_list_any,
"Specify packets to forward\n"
"Prefix to match. e.g. 10.0.0.0/8\n")
{
- int idx_word = 1;
+ int idx_word = 2;
int idx = 0;
char *seq = NULL;
char *permit_deny = NULL;
@@ -2352,7 +2352,7 @@ DEFUN (no_ipv6_access_list_exact,
{
int idx = 0;
int exact = 0;
- int idx_word = 2;
+ int idx_word = 3;
char *seq = NULL;
char *permit_deny = NULL;
char *prefix = NULL;
@@ -2394,7 +2394,7 @@ DEFUN (no_ipv6_access_list_any,
"Specify packets to forward\n"
"Any prefixi to match\n")
{
- int idx_word = 2;
+ int idx_word = 3;
int idx = 0;
char *seq = NULL;
char *permit_deny = NULL;
@@ -2498,8 +2498,8 @@ DEFUN (no_ipv6_access_list_remark_comment,
return no_ipv6_access_list_remark(self, vty, argc, argv);
}
-void config_write_access_zebra(struct vty *, struct filter *);
-void config_write_access_cisco(struct vty *, struct filter *);
+static void config_write_access_zebra(struct vty *, struct filter *);
+static void config_write_access_cisco(struct vty *, struct filter *);
/* show access-list command. */
static int filter_show(struct vty *vty, const char *name, afi_t afi)
@@ -2685,7 +2685,7 @@ DEFUN (show_ipv6_access_list_name,
return filter_show(vty, argv[idx_word]->arg, AFI_IP6);
}
-void config_write_access_cisco(struct vty *vty, struct filter *mfilter)
+static void config_write_access_cisco(struct vty *vty, struct filter *mfilter)
{
struct filter_cisco *filter;
@@ -2724,7 +2724,7 @@ void config_write_access_cisco(struct vty *vty, struct filter *mfilter)
}
}
-void config_write_access_zebra(struct vty *vty, struct filter *mfilter)
+static void config_write_access_zebra(struct vty *vty, struct filter *mfilter)
{
struct filter_zebra *filter;
struct prefix *p;
diff --git a/lib/frr_pthread.c b/lib/frr_pthread.c
index 5c71fac10a..55f0b55ed6 100644
--- a/lib/frr_pthread.c
+++ b/lib/frr_pthread.c
@@ -39,7 +39,7 @@ static int fpt_halt(struct frr_pthread *fpt, void **res);
static void frr_pthread_destroy_nolock(struct frr_pthread *fpt);
/* default frr_pthread attributes */
-struct frr_pthread_attr frr_pthread_attr_default = {
+const struct frr_pthread_attr frr_pthread_attr_default = {
.start = fpt_run,
.stop = fpt_halt,
};
@@ -74,7 +74,7 @@ void frr_pthread_finish(void)
}
}
-struct frr_pthread *frr_pthread_new(struct frr_pthread_attr *attr,
+struct frr_pthread *frr_pthread_new(const struct frr_pthread_attr *attr,
const char *name, const char *os_name)
{
struct frr_pthread *fpt = NULL;
diff --git a/lib/frr_pthread.h b/lib/frr_pthread.h
index f70c8a0db4..89519abae0 100644
--- a/lib/frr_pthread.h
+++ b/lib/frr_pthread.h
@@ -99,7 +99,7 @@ struct frr_pthread {
char os_name[OS_THREAD_NAMELEN];
};
-extern struct frr_pthread_attr frr_pthread_attr_default;
+extern const struct frr_pthread_attr frr_pthread_attr_default;
/*
* Initializes this module.
@@ -133,7 +133,7 @@ void frr_pthread_finish(void);
* @param os_name - 16 characters (including '\0') thread name to set in os,
* @return the created frr_pthread upon success, or NULL upon failure
*/
-struct frr_pthread *frr_pthread_new(struct frr_pthread_attr *attr,
+struct frr_pthread *frr_pthread_new(const struct frr_pthread_attr *attr,
const char *name, const char *os_name);
/*
diff --git a/lib/frrcu.c b/lib/frrcu.c
index d65a4a98bf..7e6475b648 100644
--- a/lib/frrcu.c
+++ b/lib/frrcu.c
@@ -206,7 +206,7 @@ void rcu_thread_unprepare(struct rcu_thread *rt)
rcu_bump();
if (rt != &rcu_thread_main)
/* this free() happens after seqlock_release() below */
- rcu_free_internal(&_mt_RCU_THREAD, rt, rcu_head);
+ rcu_free_internal(MTYPE_RCU_THREAD, rt, rcu_head);
rcu_threads_del(&rcu_threads, rt);
seqlock_release(&rt->rcu);
@@ -269,7 +269,7 @@ static void rcu_bump(void)
* "last item is being deleted - start over" case, and then we may end
* up accessing old RCU queue items that are already free'd.
*/
- rcu_free_internal(&_mt_RCU_NEXT, rn, head_free);
+ rcu_free_internal(MTYPE_RCU_NEXT, rn, head_free);
/* Only allow the RCU sweeper to run after these 2 items are queued.
*
diff --git a/lib/frrcu.h b/lib/frrcu.h
index 8f789303cc..06d87c39f1 100644
--- a/lib/frrcu.h
+++ b/lib/frrcu.h
@@ -139,6 +139,8 @@ extern void rcu_enqueue(struct rcu_head *head, const struct rcu_action *action);
#define rcu_free(mtype, ptr, field) \
do { \
typeof(ptr) _ptr = (ptr); \
+ if (!_ptr) \
+ break; \
struct rcu_head *_rcu_head = &_ptr->field; \
static const struct rcu_action _rcu_action = { \
.type = RCUA_FREE, \
diff --git a/lib/grammar_sandbox.c b/lib/grammar_sandbox.c
index c6fd3c04ad..8ccdbfcbc1 100644
--- a/lib/grammar_sandbox.c
+++ b/lib/grammar_sandbox.c
@@ -28,7 +28,6 @@
#endif
#include "command.h"
-#include "memory_vty.h"
#include "graph.h"
#include "linklist.h"
#include "command_match.h"
@@ -39,9 +38,9 @@ DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command desc")
/** headers **/
void grammar_sandbox_init(void);
-void pretty_print_graph(struct vty *vty, struct graph_node *, int, int,
- struct graph_node **, size_t);
-void init_cmdgraph(struct vty *, struct graph **);
+static void pretty_print_graph(struct vty *vty, struct graph_node *, int, int,
+ struct graph_node **, size_t);
+static void init_cmdgraph(struct vty *, struct graph **);
/** shim interface commands **/
static struct graph *nodegraph = NULL, *nodegraph_free = NULL;
@@ -492,8 +491,9 @@ void grammar_sandbox_init(void)
* @param start the node to take as the root
* @param level indent level for recursive calls, always pass 0
*/
-void pretty_print_graph(struct vty *vty, struct graph_node *start, int level,
- int desc, struct graph_node **stack, size_t stackpos)
+static void pretty_print_graph(struct vty *vty, struct graph_node *start,
+ int level, int desc, struct graph_node **stack,
+ size_t stackpos)
{
// print this node
char tokennum[32];
@@ -551,7 +551,7 @@ void pretty_print_graph(struct vty *vty, struct graph_node *start, int level,
}
/** stuff that should go in command.c + command.h */
-void init_cmdgraph(struct vty *vty, struct graph **graph)
+static void init_cmdgraph(struct vty *vty, struct graph **graph)
{
// initialize graph, add start noe
*graph = graph_new();
diff --git a/lib/grammar_sandbox_main.c b/lib/grammar_sandbox_main.c
index 6d28a667b3..4bd8f5138a 100644
--- a/lib/grammar_sandbox_main.c
+++ b/lib/grammar_sandbox_main.c
@@ -28,7 +28,7 @@
#endif
#include "command.h"
-#include "memory_vty.h"
+#include "lib_vty.h"
static void vty_do_exit(int isexit)
{
@@ -57,7 +57,7 @@ int main(int argc, char **argv)
host.domainname = strdup("testdomainname");
vty_init(master, true);
- memory_init();
+ lib_cmd_init();
yang_init();
nb_init(master, NULL, 0);
diff --git a/lib/if.c b/lib/if.c
index 9d0f13ecbd..c91407084e 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -58,7 +58,7 @@ DEFINE_QOBJ_TYPE(interface)
DEFINE_HOOK(if_add, (struct interface * ifp), (ifp))
DEFINE_KOOH(if_del, (struct interface * ifp), (ifp))
-struct interface_master{
+static struct interface_master{
int (*create_hook)(struct interface *ifp);
int (*up_hook)(struct interface *ifp);
int (*down_hook)(struct interface *ifp);
@@ -262,7 +262,9 @@ void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id)
"/frr-interface:lib/interface[name='%s'][vrf='%s']/vrf",
ifp->name, old_vrf->name);
if (if_dnode) {
+ nb_running_unset_entry(if_dnode->parent);
yang_dnode_change_leaf(if_dnode, vrf->name);
+ nb_running_set_entry(if_dnode->parent, ifp);
running_config->version++;
}
}
@@ -1650,7 +1652,32 @@ static int lib_interface_description_destroy(enum nb_event event,
}
/* clang-format off */
+
+#if defined(__GNUC__) && ((__GNUC__ - 0) < 5) && !defined(__clang__)
+/* gcc versions before 5.x miscalculate the size for structs with variable
+ * length arrays (they just count it as size 0)
+ */
+struct frr_yang_module_info_size3 {
+ /* YANG module name. */
+ const char *name;
+
+ /* Northbound callbacks. */
+ const struct {
+ /* Data path of this YANG node. */
+ const char *xpath;
+
+ /* Callbacks implemented for this node. */
+ struct nb_callbacks cbs;
+
+ /* Priority - lower priorities are processed first. */
+ uint32_t priority;
+ } nodes[3];
+};
+
+const struct frr_yang_module_info_size3 frr_interface_info_size3 asm("frr_interface_info") = {
+#else
const struct frr_yang_module_info frr_interface_info = {
+#endif
.name = "frr-interface",
.nodes = {
{
diff --git a/lib/memory_vty.c b/lib/lib_vty.c
index 1adc0d7b74..787da08e28 100644
--- a/lib/memory_vty.c
+++ b/lib/lib_vty.c
@@ -1,5 +1,5 @@
/*
- * Memory and dynamic module VTY routine
+ * Assorted library VTY commands
*
* Copyright (C) 1998 Kunihiro Ishiguro
* Copyright (C) 2016-2017 David Lamparter for NetDEF, Inc.
@@ -35,7 +35,8 @@
#include "log.h"
#include "memory.h"
#include "module.h"
-#include "memory_vty.h"
+#include "defaults.h"
+#include "lib_vty.h"
/* Looking up memory status from vty interface. */
#include "vector.h"
@@ -120,11 +121,11 @@ static int qmem_walker(void *arg, struct memgroup *mg, struct memtype *mt)
}
-DEFUN (show_memory,
- show_memory_cmd,
- "show memory",
- "Show running system information\n"
- "Memory statistics\n")
+DEFUN_NOSH (show_memory,
+ show_memory_cmd,
+ "show memory",
+ "Show running system information\n"
+ "Memory statistics\n")
{
#ifdef HAVE_MALLINFO
show_memory_mallinfo(vty);
@@ -134,11 +135,11 @@ DEFUN (show_memory,
return CMD_SUCCESS;
}
-DEFUN (show_modules,
- show_modules_cmd,
- "show modules",
- "Show running system information\n"
- "Loaded modules\n")
+DEFUN_NOSH (show_modules,
+ show_modules_cmd,
+ "show modules",
+ "Show running system information\n"
+ "Loaded modules\n")
{
struct frrmod_runtime *plug = frrmod_list;
@@ -177,8 +178,60 @@ DEFUN (show_modules,
return CMD_SUCCESS;
}
-void memory_init(void)
+DEFUN (frr_defaults,
+ frr_defaults_cmd,
+ "frr defaults PROFILE...",
+ "FRRouting global parameters\n"
+ "set of configuration defaults used\n"
+ "profile string\n")
{
+ char *profile = argv_concat(argv, argc, 2);
+ int rv = CMD_SUCCESS;
+
+ if (!frr_defaults_profile_valid(profile)) {
+ vty_out(vty, "%% WARNING: profile %s is not known in this version\n",
+ profile);
+ rv = CMD_WARNING;
+ }
+ frr_defaults_profile_set(profile);
+ XFREE(MTYPE_TMP, profile);
+ return rv;
+}
+
+DEFUN (frr_version,
+ frr_version_cmd,
+ "frr version VERSION...",
+ "FRRouting global parameters\n"
+ "version configuration was written by\n"
+ "version string\n")
+{
+ char *version = argv_concat(argv, argc, 2);
+
+ frr_defaults_version_set(version);
+ XFREE(MTYPE_TMP, version);
+ return CMD_SUCCESS;
+}
+
+static void defaults_autocomplete(vector comps, struct cmd_token *token)
+{
+ const char **p;
+
+ for (p = frr_defaults_profiles; *p; p++)
+ vector_set(comps, XSTRDUP(MTYPE_COMPLETION, *p));
+}
+
+static const struct cmd_variable_handler default_var_handlers[] = {
+ {.tokenname = "PROFILE", .completions = defaults_autocomplete},
+ {.completions = NULL},
+};
+
+void lib_cmd_init(void)
+{
+ cmd_variable_handler_register(default_var_handlers);
+
+ install_element(CONFIG_NODE, &frr_defaults_cmd);
+ install_element(CONFIG_NODE, &frr_version_cmd);
+
install_element(VIEW_NODE, &show_memory_cmd);
install_element(VIEW_NODE, &show_modules_cmd);
}
diff --git a/lib/memory_vty.h b/lib/lib_vty.h
index 941255be1d..48e409ec52 100644
--- a/lib/memory_vty.h
+++ b/lib/lib_vty.h
@@ -18,8 +18,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef _ZEBRA_MEMORY_VTY_H
-#define _ZEBRA_MEMORY_VTY_H
+#ifndef _ZEBRA_LIB_VTY_H
+#define _ZEBRA_LIB_VTY_H
#include "memory.h"
@@ -27,7 +27,7 @@
extern "C" {
#endif
-extern void memory_init(void);
+extern void lib_cmd_init(void);
/* Human friendly string for given byte count */
#define MTYPE_MEMSTR_LEN 20
@@ -37,4 +37,4 @@ extern const char *mtype_memstr(char *, size_t, unsigned long);
}
#endif
-#endif /* _ZEBRA_MEMORY_VTY_H */
+#endif /* _ZEBRA_LIB_VTY_H */
diff --git a/lib/libfrr.c b/lib/libfrr.c
index 8ef32eaa8a..4fb43edff2 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -30,7 +30,7 @@
#include "vty.h"
#include "command.h"
#include "version.h"
-#include "memory_vty.h"
+#include "lib_vty.h"
#include "log_vty.h"
#include "zclient.h"
#include "log_int.h"
@@ -43,6 +43,7 @@
#include "debug.h"
#include "frrcu.h"
#include "frr_pthread.h"
+#include "defaults.h"
DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm))
DEFINE_KOOH(frr_early_fini, (), ())
@@ -104,6 +105,7 @@ static const struct option lo_always[] = {
{"version", no_argument, NULL, 'v'},
{"daemon", no_argument, NULL, 'd'},
{"module", no_argument, NULL, 'M'},
+ {"profile", required_argument, NULL, 'F'},
{"vty_socket", required_argument, NULL, OPTION_VTYSOCK},
{"moduledir", required_argument, NULL, OPTION_MODULEDIR},
{"log", required_argument, NULL, OPTION_LOG},
@@ -112,11 +114,12 @@ static const struct option lo_always[] = {
{"command-log-always", no_argument, NULL, OPTION_LOGGING},
{NULL}};
static const struct optspec os_always = {
- "hvdM:",
+ "hvdM:F:",
" -h, --help Display this help and exit\n"
" -v, --version Print program version\n"
" -d, --daemon Runs in daemon mode\n"
" -M, --module Load specified module\n"
+ " -F, --profile Use specified configuration profile\n"
" --vty_socket Override vty socket path\n"
" --moduledir Override modules directory\n"
" --log Set Logging to stdout, syslog, or file:<name>\n"
@@ -175,7 +178,6 @@ static const struct optspec os_user = {"u:g:",
" -g, --group Group to run as\n",
lo_user};
-
bool frr_zclient_addr(struct sockaddr_storage *sa, socklen_t *sa_len,
const char *path)
{
@@ -390,6 +392,32 @@ static int frr_opt(int opt)
*modnext = oc;
modnext = &oc->next;
break;
+ case 'F':
+ if (!frr_defaults_profile_valid(optarg)) {
+ const char **p;
+ FILE *ofd = stderr;
+
+ if (!strcmp(optarg, "help"))
+ ofd = stdout;
+ else
+ fprintf(stderr,
+ "The \"%s\" configuration profile is not valid for this FRR version.\n",
+ optarg);
+
+ fprintf(ofd, "Available profiles are:\n");
+ for (p = frr_defaults_profiles; *p; p++)
+ fprintf(ofd, "%s%s\n",
+ strcmp(*p, DFLT_NAME) ? " " : " * ",
+ *p);
+
+ if (ofd == stdout)
+ exit(0);
+ fprintf(ofd, "\n");
+ errors++;
+ break;
+ }
+ frr_defaults_profile_set(optarg);
+ break;
case 'i':
if (di->flags & FRR_NO_CFG_PID_DRY)
return 1;
@@ -608,6 +636,7 @@ struct thread_master *frr_init(void)
dir = di->module_path ? di->module_path : frr_moduledir;
srandom(time(NULL));
+ frr_defaults_apply();
if (di->instance) {
snprintf(frr_protonameinst, sizeof(frr_protonameinst), "%s[%u]",
@@ -679,7 +708,7 @@ struct thread_master *frr_init(void)
cmd_init(1);
vty_init(master, di->log_always);
- memory_init();
+ lib_cmd_init();
log_filter_cmd_init();
frr_pthread_init();
@@ -1077,7 +1106,6 @@ void frr_fini(void)
hook_call(frr_fini);
- /* memory_init -> nothing needed */
vty_terminate();
cmd_terminate();
nb_terminate();
diff --git a/lib/libfrr.h b/lib/libfrr.h
index e2b3db74a3..f964c9e2a1 100644
--- a/lib/libfrr.h
+++ b/lib/libfrr.h
@@ -98,7 +98,7 @@ struct frr_daemon_info {
struct zebra_privs_t *privs;
- const struct frr_yang_module_info **yang_modules;
+ const struct frr_yang_module_info *const *yang_modules;
size_t n_yang_modules;
bool log_always;
diff --git a/lib/linklist.c b/lib/linklist.c
index 0d1efdf3aa..272e153276 100644
--- a/lib/linklist.c
+++ b/lib/linklist.c
@@ -339,29 +339,6 @@ void list_delete_node(struct list *list, struct listnode *node)
listnode_free(node);
}
-void list_add_list(struct list *list, struct list *add)
-{
- struct listnode *n;
-
- for (n = listhead(add); n; n = listnextnode(n))
- listnode_add(list, n->data);
-}
-
-struct list *list_dup(struct list *list)
-{
- struct list *new = list_new();
- struct listnode *ln;
- void *data;
-
- new->cmp = list->cmp;
- new->del = list->del;
-
- for (ALL_LIST_ELEMENTS_RO(list, ln, data))
- listnode_add(new, data);
-
- return new;
-}
-
void list_sort(struct list *list, int (*cmp)(const void **, const void **))
{
struct listnode *ln, *nn;
diff --git a/lib/linklist.h b/lib/linklist.h
index ef914b965f..00cb9f8714 100644
--- a/lib/linklist.h
+++ b/lib/linklist.h
@@ -208,17 +208,6 @@ extern struct listnode *listnode_lookup(struct list *list, const void *data);
extern void *listnode_head(struct list *list);
/*
- * Duplicate a list.
- *
- * list
- * list to duplicate
- *
- * Returns:
- * copy of the list
- */
-extern struct list *list_dup(struct list *l);
-
-/*
* Sort a list in place.
*
* The sorting algorithm used is quicksort. Runtimes are equivalent to those of
@@ -296,19 +285,6 @@ extern void list_delete_all_node(struct list *list);
extern void list_delete_node(struct list *list, struct listnode *node);
/*
- * Append a list to an existing list.
- *
- * Runtime is O(N) where N = listcount(add).
- *
- * list
- * list to append to
- *
- * add
- * list to append
- */
-extern void list_add_list(struct list *list, struct list *add);
-
-/*
* Delete all nodes which satisfy a condition from a list.
* Deletes the node if cond function returns true for the node.
* If function ptr passed is NULL, it deletes all nodes
diff --git a/lib/memory.h b/lib/memory.h
index 8de5c4c2bf..44ea19b557 100644
--- a/lib/memory.h
+++ b/lib/memory.h
@@ -102,45 +102,42 @@ struct memgroup {
}
#define DECLARE_MTYPE(name) \
- extern struct memtype _mt_##name; \
- extern struct memtype *const MTYPE_##name; \
+ extern struct memtype MTYPE_##name[1]; \
/* end */
#define DEFINE_MTYPE_ATTR(group, mname, attr, desc) \
- attr struct memtype _mt_##mname \
- __attribute__((section(".data.mtypes"))) = { \
+ attr struct memtype MTYPE_##mname[1] \
+ __attribute__((section(".data.mtypes"))) = { { \
.name = desc, \
.next = NULL, \
.n_alloc = 0, \
.size = 0, \
.ref = NULL, \
- }; \
+ } }; \
static void _mtinit_##mname(void) __attribute__((_CONSTRUCTOR(1001))); \
static void _mtinit_##mname(void) \
{ \
if (_mg_##group.insert == NULL) \
_mg_##group.insert = &_mg_##group.types; \
- _mt_##mname.ref = _mg_##group.insert; \
- *_mg_##group.insert = &_mt_##mname; \
- _mg_##group.insert = &_mt_##mname.next; \
+ MTYPE_##mname->ref = _mg_##group.insert; \
+ *_mg_##group.insert = MTYPE_##mname; \
+ _mg_##group.insert = &MTYPE_##mname->next; \
} \
static void _mtfini_##mname(void) __attribute__((_DESTRUCTOR(1001))); \
static void _mtfini_##mname(void) \
{ \
- if (_mt_##mname.next) \
- _mt_##mname.next->ref = _mt_##mname.ref; \
- *_mt_##mname.ref = _mt_##mname.next; \
+ if (MTYPE_##mname->next) \
+ MTYPE_##mname->next->ref = MTYPE_##mname->ref; \
+ *MTYPE_##mname->ref = MTYPE_##mname->next; \
} \
/* end */
#define DEFINE_MTYPE(group, name, desc) \
DEFINE_MTYPE_ATTR(group, name, , desc) \
- struct memtype *const MTYPE_##name = &_mt_##name; \
/* end */
#define DEFINE_MTYPE_STATIC(group, name, desc) \
DEFINE_MTYPE_ATTR(group, name, static, desc) \
- static struct memtype *const MTYPE_##name = &_mt_##name; \
/* end */
DECLARE_MGROUP(LIB)
diff --git a/lib/mlag.c b/lib/mlag.c
index acdc662924..1daf290725 100644
--- a/lib/mlag.c
+++ b/lib/mlag.c
@@ -39,3 +39,129 @@ char *mlag_role2str(enum mlag_role role, char *buf, size_t size)
return buf;
}
+
+char *mlag_lib_msgid_to_str(enum mlag_msg_type msg_type, char *buf, size_t size)
+{
+ switch (msg_type) {
+ case MLAG_REGISTER:
+ snprintf(buf, size, "Register");
+ break;
+ case MLAG_DEREGISTER:
+ snprintf(buf, size, "De-Register");
+ break;
+ case MLAG_MROUTE_ADD:
+ snprintf(buf, size, "Mroute add");
+ break;
+ case MLAG_MROUTE_DEL:
+ snprintf(buf, size, "Mroute del");
+ break;
+ case MLAG_DUMP:
+ snprintf(buf, size, "Mlag Replay");
+ break;
+ case MLAG_MROUTE_ADD_BULK:
+ snprintf(buf, size, "Mroute Add Batch");
+ break;
+ case MLAG_MROUTE_DEL_BULK:
+ snprintf(buf, size, "Mroute Del Batch");
+ break;
+ case MLAG_STATUS_UPDATE:
+ snprintf(buf, size, "Mlag Status");
+ break;
+ case MLAG_VXLAN_UPDATE:
+ snprintf(buf, size, "Mlag vxlan update");
+ break;
+ case MLAG_PEER_FRR_STATUS:
+ snprintf(buf, size, "Mlag Peer FRR Status");
+ break;
+ default:
+ snprintf(buf, size, "Unknown %d", msg_type);
+ break;
+ }
+ return buf;
+}
+
+
+int mlag_lib_decode_mlag_hdr(struct stream *s, struct mlag_msg *msg)
+{
+ if (s == NULL || msg == NULL)
+ return -1;
+
+ STREAM_GETL(s, msg->msg_type);
+ STREAM_GETW(s, msg->data_len);
+ STREAM_GETW(s, msg->msg_cnt);
+ return 0;
+stream_failure:
+ return -1;
+}
+
+int mlag_lib_decode_mroute_add(struct stream *s, struct mlag_mroute_add *msg)
+{
+ if (s == NULL || msg == NULL)
+ return -1;
+
+ STREAM_GET(msg->vrf_name, s, VRF_NAMSIZ);
+ STREAM_GETL(s, msg->source_ip);
+ STREAM_GETL(s, msg->group_ip);
+ STREAM_GETL(s, msg->cost_to_rp);
+ STREAM_GETL(s, msg->owner_id);
+ STREAM_GETC(s, msg->am_i_dr);
+ STREAM_GETC(s, msg->am_i_dual_active);
+ STREAM_GETL(s, msg->vrf_id);
+ STREAM_GET(msg->intf_name, s, INTERFACE_NAMSIZ);
+ return 0;
+stream_failure:
+ return -1;
+}
+
+int mlag_lib_decode_mroute_del(struct stream *s, struct mlag_mroute_del *msg)
+{
+ if (s == NULL || msg == NULL)
+ return -1;
+
+ STREAM_GET(msg->vrf_name, s, VRF_NAMSIZ);
+ STREAM_GETL(s, msg->source_ip);
+ STREAM_GETL(s, msg->group_ip);
+ STREAM_GETL(s, msg->owner_id);
+ STREAM_GETL(s, msg->vrf_id);
+ STREAM_GET(msg->intf_name, s, INTERFACE_NAMSIZ);
+ return 0;
+stream_failure:
+ return -1;
+}
+
+int mlag_lib_decode_mlag_status(struct stream *s, struct mlag_status *msg)
+{
+ if (s == NULL || msg == NULL)
+ return -1;
+
+ STREAM_GET(msg->peerlink_rif, s, INTERFACE_NAMSIZ);
+ STREAM_GETL(s, msg->my_role);
+ STREAM_GETL(s, msg->peer_state);
+ return 0;
+stream_failure:
+ return -1;
+}
+
+int mlag_lib_decode_vxlan_update(struct stream *s, struct mlag_vxlan *msg)
+{
+ if (s == NULL || msg == NULL)
+ return -1;
+
+ STREAM_GETL(s, msg->anycast_ip);
+ STREAM_GETL(s, msg->local_ip);
+ return 0;
+
+stream_failure:
+ return -1;
+}
+
+int mlag_lib_decode_frr_status(struct stream *s, struct mlag_frr_status *msg)
+{
+ if (s == NULL || msg == NULL)
+ return -1;
+
+ STREAM_GETL(s, msg->frr_state);
+ return 0;
+stream_failure:
+ return -1;
+}
diff --git a/lib/mlag.h b/lib/mlag.h
index 2b904d44f4..c531fb5b68 100644
--- a/lib/mlag.h
+++ b/lib/mlag.h
@@ -26,14 +26,116 @@
extern "C" {
#endif
+#include "lib/if.h"
+#include "lib/vrf.h"
+#include "lib/stream.h"
+
+#define MLAG_MSG_NULL_PAYLOAD 0
+#define MLAG_MSG_NO_BATCH 1
+#define MLAG_BUF_LIMIT 2048
+
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);
+enum mlag_state {
+ MLAG_STATE_DOWN,
+ MLAG_STATE_RUNNING,
+};
+
+enum mlag_frr_state {
+ MLAG_FRR_STATE_NONE,
+ MLAG_FRR_STATE_DOWN,
+ MLAG_FRR_STATE_UP,
+};
+
+enum mlag_owner {
+ MLAG_OWNER_NONE,
+ MLAG_OWNER_INTERFACE,
+ MLAG_OWNER_VXLAN,
+};
+
+/*
+ * This message definition should match mlag.proto
+ * Because message registration is based on this
+ */
+enum mlag_msg_type {
+ MLAG_MSG_NONE = 0,
+ MLAG_REGISTER = 1,
+ MLAG_DEREGISTER = 2,
+ MLAG_STATUS_UPDATE = 3,
+ MLAG_MROUTE_ADD = 4,
+ MLAG_MROUTE_DEL = 5,
+ MLAG_DUMP = 6,
+ MLAG_MROUTE_ADD_BULK = 7,
+ MLAG_MROUTE_DEL_BULK = 8,
+ MLAG_PIM_CFG_DUMP = 10,
+ MLAG_VXLAN_UPDATE = 11,
+ MLAG_PEER_FRR_STATUS = 12,
+};
+
+struct mlag_frr_status {
+ enum mlag_frr_state frr_state;
+};
+struct mlag_status {
+ char peerlink_rif[INTERFACE_NAMSIZ];
+ enum mlag_role my_role;
+ enum mlag_state peer_state;
+};
+
+#define MLAG_ROLE_STRSIZE 16
+
+struct mlag_vxlan {
+ uint32_t anycast_ip;
+ uint32_t local_ip;
+};
+
+struct mlag_mroute_add {
+ char vrf_name[VRF_NAMSIZ];
+ uint32_t source_ip;
+ uint32_t group_ip;
+ uint32_t cost_to_rp;
+ enum mlag_owner owner_id;
+ bool am_i_dr;
+ bool am_i_dual_active;
+ vrf_id_t vrf_id;
+ char intf_name[INTERFACE_NAMSIZ];
+};
+
+struct mlag_mroute_del {
+ char vrf_name[VRF_NAMSIZ];
+ uint32_t source_ip;
+ uint32_t group_ip;
+ enum mlag_owner owner_id;
+ vrf_id_t vrf_id;
+ char intf_name[INTERFACE_NAMSIZ];
+};
+
+struct mlag_msg {
+ enum mlag_msg_type msg_type;
+ uint16_t data_len;
+ uint16_t msg_cnt;
+ uint8_t data[0];
+} __attribute__((packed));
+
+
+extern char *mlag_role2str(enum mlag_role role, char *buf, size_t size);
+extern char *mlag_lib_msgid_to_str(enum mlag_msg_type msg_type, char *buf,
+ size_t size);
+extern int mlag_lib_decode_mlag_hdr(struct stream *s, struct mlag_msg *msg);
+extern int mlag_lib_decode_mroute_add(struct stream *s,
+ struct mlag_mroute_add *msg);
+extern int mlag_lib_decode_mroute_del(struct stream *s,
+ struct mlag_mroute_del *msg);
+extern int mlag_lib_decode_mlag_status(struct stream *s,
+ struct mlag_status *msg);
+extern int mlag_lib_decode_vxlan_update(struct stream *s,
+ struct mlag_vxlan *msg);
+extern int mlag_lib_decode_frr_status(struct stream *s,
+ struct mlag_frr_status *msg);
#ifdef __cplusplus
}
#endif
diff --git a/lib/netns_linux.c b/lib/netns_linux.c
index 55c66fdc3d..d1a31ae35f 100644
--- a/lib/netns_linux.c
+++ b/lib/netns_linux.c
@@ -51,7 +51,7 @@ static struct ns *ns_lookup_name_internal(const char *name);
RB_GENERATE(ns_head, ns, entry, ns_compare)
-struct ns_head ns_tree = RB_INITIALIZER(&ns_tree);
+static struct ns_head ns_tree = RB_INITIALIZER(&ns_tree);
static struct ns *default_ns;
static int ns_current_ns_fd;
@@ -74,7 +74,8 @@ static inline int ns_map_compare(const struct ns_map_nsid *a,
RB_HEAD(ns_map_nsid_head, ns_map_nsid);
RB_PROTOTYPE(ns_map_nsid_head, ns_map_nsid, id_entry, ns_map_compare);
RB_GENERATE(ns_map_nsid_head, ns_map_nsid, id_entry, ns_map_compare);
-struct ns_map_nsid_head ns_map_nsid_list = RB_INITIALIZER(&ns_map_nsid_list);
+static struct ns_map_nsid_head ns_map_nsid_list =
+ RB_INITIALIZER(&ns_map_nsid_list);
static ns_id_t ns_id_external_numbering;
@@ -123,7 +124,7 @@ static int have_netns(void)
}
/* Holding NS hooks */
-struct ns_master {
+static struct ns_master {
int (*ns_new_hook)(struct ns *ns);
int (*ns_delete_hook)(struct ns *ns);
int (*ns_enable_hook)(struct ns *ns);
diff --git a/lib/netns_other.c b/lib/netns_other.c
index b0aae4f8df..740d2b621e 100644
--- a/lib/netns_other.c
+++ b/lib/netns_other.c
@@ -34,7 +34,7 @@ static inline int ns_compare(const struct ns *ns, const struct ns *ns2);
RB_GENERATE(ns_head, ns, entry, ns_compare)
-struct ns_head ns_tree = RB_INITIALIZER(&ns_tree);
+static struct ns_head ns_tree = RB_INITIALIZER(&ns_tree);
static inline int ns_compare(const struct ns *a, const struct ns *b)
{
diff --git a/lib/nexthop.c b/lib/nexthop.c
index 73c2de0cd8..d2ab70e209 100644
--- a/lib/nexthop.c
+++ b/lib/nexthop.c
@@ -33,6 +33,7 @@
#include "mpls.h"
#include "jhash.h"
#include "printfrr.h"
+#include "vrf.h"
DEFINE_MTYPE_STATIC(LIB, NEXTHOP, "Nexthop")
DEFINE_MTYPE_STATIC(LIB, NH_LABEL, "Nexthop label")
@@ -117,6 +118,12 @@ static int _nexthop_cmp_no_labels(const struct nexthop *next1,
if (next1->type > next2->type)
return 1;
+ if (next1->weight < next2->weight)
+ return -1;
+
+ if (next1->weight > next2->weight)
+ return 1;
+
switch (next1->type) {
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV6:
@@ -200,7 +207,7 @@ int nexthop_same_firsthop(struct nexthop *next1, struct nexthop *next2)
*/
const char *nexthop_type_to_str(enum nexthop_types_t nh_type)
{
- static const char *desc[] = {
+ static const char *const desc[] = {
"none", "Directly connected",
"IPv4 nexthop", "IPv4 nexthop with ifindex",
"IPv6 nexthop", "IPv6 nexthop with ifindex",
@@ -223,7 +230,23 @@ bool nexthop_labels_match(const struct nexthop *nh1, const struct nexthop *nh2)
struct nexthop *nexthop_new(void)
{
- return XCALLOC(MTYPE_NEXTHOP, sizeof(struct nexthop));
+ struct nexthop *nh;
+
+ nh = XCALLOC(MTYPE_NEXTHOP, sizeof(struct nexthop));
+
+ /*
+ * Default the weight to 1 here for all nexthops.
+ * The linux kernel does some weird stuff with adding +1 to
+ * all nexthop weights it gets over netlink.
+ * To handle this, just default everything to 1 right from
+ * from the beggining so we don't have to special case
+ * default weights in the linux netlink code.
+ *
+ * 1 should be a valid on all platforms anyway.
+ */
+ nh->weight = 1;
+
+ return nh;
}
/* Free nexthop. */
@@ -281,6 +304,93 @@ bool nexthop_same_no_labels(const struct nexthop *nh1,
return true;
}
+/*
+ * Allocate a new nexthop object and initialize it from various args.
+ */
+struct nexthop *nexthop_from_ifindex(ifindex_t ifindex, vrf_id_t vrf_id)
+{
+ struct nexthop *nexthop;
+
+ nexthop = nexthop_new();
+ nexthop->type = NEXTHOP_TYPE_IFINDEX;
+ nexthop->ifindex = ifindex;
+ nexthop->vrf_id = vrf_id;
+
+ return nexthop;
+}
+
+struct nexthop *nexthop_from_ipv4(const struct in_addr *ipv4,
+ const struct in_addr *src,
+ vrf_id_t vrf_id)
+{
+ struct nexthop *nexthop;
+
+ nexthop = nexthop_new();
+ nexthop->type = NEXTHOP_TYPE_IPV4;
+ nexthop->vrf_id = vrf_id;
+ nexthop->gate.ipv4 = *ipv4;
+ if (src)
+ nexthop->src.ipv4 = *src;
+
+ return nexthop;
+}
+
+struct nexthop *nexthop_from_ipv4_ifindex(const struct in_addr *ipv4,
+ const struct in_addr *src,
+ ifindex_t ifindex, vrf_id_t vrf_id)
+{
+ struct nexthop *nexthop;
+
+ nexthop = nexthop_new();
+ nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+ nexthop->vrf_id = vrf_id;
+ nexthop->gate.ipv4 = *ipv4;
+ if (src)
+ nexthop->src.ipv4 = *src;
+ nexthop->ifindex = ifindex;
+
+ return nexthop;
+}
+
+struct nexthop *nexthop_from_ipv6(const struct in6_addr *ipv6,
+ vrf_id_t vrf_id)
+{
+ struct nexthop *nexthop;
+
+ nexthop = nexthop_new();
+ nexthop->vrf_id = vrf_id;
+ nexthop->type = NEXTHOP_TYPE_IPV6;
+ nexthop->gate.ipv6 = *ipv6;
+
+ return nexthop;
+}
+
+struct nexthop *nexthop_from_ipv6_ifindex(const struct in6_addr *ipv6,
+ ifindex_t ifindex, vrf_id_t vrf_id)
+{
+ struct nexthop *nexthop;
+
+ nexthop = nexthop_new();
+ nexthop->vrf_id = vrf_id;
+ nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
+ nexthop->gate.ipv6 = *ipv6;
+ nexthop->ifindex = ifindex;
+
+ return nexthop;
+}
+
+struct nexthop *nexthop_from_blackhole(enum blackhole_type bh_type)
+{
+ struct nexthop *nexthop;
+
+ nexthop = nexthop_new();
+ nexthop->vrf_id = VRF_DEFAULT;
+ nexthop->type = NEXTHOP_TYPE_BLACKHOLE;
+ nexthop->bh_type = bh_type;
+
+ return nexthop;
+}
+
/* Update nexthop with label information. */
void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t type,
uint8_t num_labels, mpls_label_t *label)
@@ -288,6 +398,9 @@ void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t type,
struct mpls_label_stack *nh_label;
int i;
+ if (num_labels == 0)
+ return;
+
nexthop->nh_label_type = type;
nh_label = XCALLOC(MTYPE_NH_LABEL,
sizeof(struct mpls_label_stack)
@@ -459,6 +572,7 @@ void nexthop_copy(struct nexthop *copy, const struct nexthop *nexthop,
copy->ifindex = nexthop->ifindex;
copy->type = nexthop->type;
copy->flags = nexthop->flags;
+ copy->weight = nexthop->weight;
memcpy(&copy->gate, &nexthop->gate, sizeof(nexthop->gate));
memcpy(&copy->src, &nexthop->src, sizeof(nexthop->src));
memcpy(&copy->rmap_src, &nexthop->rmap_src, sizeof(nexthop->rmap_src));
diff --git a/lib/nexthop.h b/lib/nexthop.h
index fe029f1867..040b643a84 100644
--- a/lib/nexthop.h
+++ b/lib/nexthop.h
@@ -110,6 +110,9 @@ struct nexthop {
/* Label(s) associated with this nexthop. */
struct mpls_label_stack *nh_label;
+
+ /* Weight of the nexthop ( for unequal cost ECMP ) */
+ uint8_t weight;
};
struct nexthop *nexthop_new(void);
@@ -122,6 +125,22 @@ void nexthop_add_labels(struct nexthop *, enum lsp_types_t, uint8_t,
void nexthop_del_labels(struct nexthop *);
/*
+ * Allocate a new nexthop object and initialize it from various args.
+ */
+struct nexthop *nexthop_from_ifindex(ifindex_t ifindex, vrf_id_t vrf_id);
+struct nexthop *nexthop_from_ipv4(const struct in_addr *ipv4,
+ const struct in_addr *src,
+ vrf_id_t vrf_id);
+struct nexthop *nexthop_from_ipv4_ifindex(const struct in_addr *ipv4,
+ const struct in_addr *src,
+ ifindex_t ifindex, vrf_id_t vrf_id);
+struct nexthop *nexthop_from_ipv6(const struct in6_addr *ipv6,
+ vrf_id_t vrf_id);
+struct nexthop *nexthop_from_ipv6_ifindex(const struct in6_addr *ipv6,
+ ifindex_t ifindex, vrf_id_t vrf_id);
+struct nexthop *nexthop_from_blackhole(enum blackhole_type bh_type);
+
+/*
* Hash a nexthop. Suitable for use with hash tables.
*
* This function uses the following values when computing the hash:
diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c
index 9552f89568..0051cba625 100644
--- a/lib/nexthop_group.c
+++ b/lib/nexthop_group.c
@@ -34,6 +34,17 @@
DEFINE_MTYPE_STATIC(LIB, NEXTHOP_GROUP, "Nexthop Group")
+/*
+ * Internal struct used to hold nhg config strings
+ */
+struct nexthop_hold {
+ char *nhvrf_name;
+ union sockunion *addr;
+ char *intf;
+ char *labels;
+ uint32_t weight;
+};
+
struct nexthop_group_hooks {
void (*new)(const char *name);
void (*add_nexthop)(const struct nexthop_group_cmd *nhg,
@@ -233,25 +244,16 @@ void _nexthop_add(struct nexthop **target, struct nexthop *nexthop)
nexthop->prev = last;
}
-void _nexthop_group_add_sorted(struct nexthop_group *nhg,
- struct nexthop *nexthop)
+/* Add nexthop to sorted list of nexthops */
+static void _nexthop_add_sorted(struct nexthop **head,
+ struct nexthop *nexthop)
{
- struct nexthop *position, *prev, *tail;
-
- /* Try to just append to the end first
- * This trust it is already sorted
- */
-
- tail = nexthop_group_tail(nhg);
-
- if (tail && (nexthop_cmp(tail, nexthop) < 0)) {
- tail->next = nexthop;
- nexthop->prev = tail;
+ struct nexthop *position, *prev;
- return;
- }
+ /* Ensure this gets set */
+ nexthop->next = NULL;
- for (position = nhg->nexthop, prev = NULL; position;
+ for (position = *head, prev = NULL; position;
prev = position, position = position->next) {
if (nexthop_cmp(position, nexthop) > 0) {
nexthop->next = position;
@@ -260,7 +262,7 @@ void _nexthop_group_add_sorted(struct nexthop_group *nhg,
if (nexthop->prev)
nexthop->prev->next = nexthop;
else
- nhg->nexthop = nexthop;
+ *head = nexthop;
position->prev = nexthop;
return;
@@ -271,7 +273,27 @@ void _nexthop_group_add_sorted(struct nexthop_group *nhg,
if (prev)
prev->next = nexthop;
else
- nhg->nexthop = nexthop;
+ *head = nexthop;
+}
+
+void nexthop_group_add_sorted(struct nexthop_group *nhg,
+ struct nexthop *nexthop)
+{
+ struct nexthop *tail;
+
+ /* Try to just append to the end first;
+ * trust the list is already sorted
+ */
+ tail = nexthop_group_tail(nhg);
+
+ if (tail && (nexthop_cmp(tail, nexthop) < 0)) {
+ tail->next = nexthop;
+ nexthop->prev = tail;
+
+ return;
+ }
+
+ _nexthop_add_sorted(&nhg->nexthop, nexthop);
}
/* Delete nexthop from a nexthop list. */
@@ -298,6 +320,40 @@ void _nexthop_del(struct nexthop_group *nhg, struct nexthop *nh)
nh->next = NULL;
}
+/*
+ * Copy a list of nexthops in 'nh' to an nhg, enforcing canonical sort order
+ */
+void nexthop_group_copy_nh_sorted(struct nexthop_group *nhg,
+ const struct nexthop *nh)
+{
+ struct nexthop *nexthop, *tail;
+ const struct nexthop *nh1;
+
+ /* We'll try to append to the end of the new list;
+ * if the original list in nh is already sorted, this eliminates
+ * lots of comparison operations.
+ */
+ tail = nexthop_group_tail(nhg);
+
+ for (nh1 = nh; nh1; nh1 = nh1->next) {
+ nexthop = nexthop_dup(nh1, NULL);
+
+ if (tail && (nexthop_cmp(tail, nexthop) < 0)) {
+ tail->next = nexthop;
+ nexthop->prev = tail;
+
+ tail = nexthop;
+ continue;
+ }
+
+ _nexthop_add_sorted(&nhg->nexthop, nexthop);
+
+ if (tail == NULL)
+ tail = nexthop;
+ }
+}
+
+/* Copy a list of nexthops, no effort made to sort or order them. */
void copy_nexthops(struct nexthop **tnh, const struct nexthop *nh,
struct nexthop *rparent)
{
@@ -425,7 +481,11 @@ static int nhgl_cmp(struct nexthop_hold *nh1, struct nexthop_hold *nh2)
if (ret)
return ret;
- return nhgc_cmp_helper(nh1->nhvrf_name, nh2->nhvrf_name);
+ ret = nhgc_cmp_helper(nh1->nhvrf_name, nh2->nhvrf_name);
+ if (ret)
+ return ret;
+
+ return nhgc_cmp_helper(nh1->labels, nh2->labels);
}
static void nhgl_delete(struct nexthop_hold *nh)
@@ -437,6 +497,8 @@ static void nhgl_delete(struct nexthop_hold *nh)
if (nh->addr)
sockunion_free(nh->addr);
+ XFREE(MTYPE_TMP, nh->labels);
+
XFREE(MTYPE_TMP, nh);
}
@@ -510,7 +572,8 @@ DEFUN_NOSH(no_nexthop_group, no_nexthop_group_cmd, "no nexthop-group NHGNAME",
static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
const char *nhvrf_name,
const union sockunion *addr,
- const char *intf)
+ const char *intf, const char *labels,
+ const uint32_t weight)
{
struct nexthop_hold *nh;
@@ -522,6 +585,10 @@ static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
nh->intf = XSTRDUP(MTYPE_TMP, intf);
if (addr)
nh->addr = sockunion_dup(addr);
+ if (labels)
+ nh->labels = XSTRDUP(MTYPE_TMP, labels);
+
+ nh->weight = weight;
listnode_add_sort(nhgc->nhg_list, nh);
}
@@ -529,15 +596,18 @@ static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc,
const char *nhvrf_name,
const union sockunion *addr,
- const char *intf)
+ const char *intf, const char *labels,
+ const uint32_t weight)
{
struct nexthop_hold *nh;
struct listnode *node;
for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) {
- if (nhgc_cmp_helper(nhvrf_name, nh->nhvrf_name) == 0 &&
- nhgc_addr_cmp_helper(addr, nh->addr) == 0 &&
- nhgc_cmp_helper(intf, nh->intf) == 0)
+ if (nhgc_cmp_helper(nhvrf_name, nh->nhvrf_name) == 0
+ && nhgc_addr_cmp_helper(addr, nh->addr) == 0
+ && nhgc_cmp_helper(intf, nh->intf) == 0
+ && nhgc_cmp_helper(labels, nh->labels) == 0
+ && weight == nh->weight)
break;
}
@@ -551,10 +621,19 @@ static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc,
nhgl_delete(nh);
}
+/*
+ * Parse the config strings we support for a single nexthop. This gets used
+ * in a couple of different ways, and we distinguish between transient
+ * failures - such as a still-unprocessed interface - and fatal errors
+ * from label-string parsing.
+ */
static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
const union sockunion *addr,
- const char *intf, const char *name)
+ const char *intf, const char *name,
+ const char *labels, int *lbl_ret,
+ uint32_t weight)
{
+ int ret = 0;
struct vrf *vrf;
memset(nhop, 0, sizeof(*nhop));
@@ -592,16 +671,50 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
} else
nhop->type = NEXTHOP_TYPE_IFINDEX;
+ if (labels) {
+ uint8_t num = 0;
+ mpls_label_t larray[MPLS_MAX_LABELS];
+
+ ret = mpls_str2label(labels, &num, larray);
+
+ /* Return label parse result */
+ if (lbl_ret)
+ *lbl_ret = ret;
+
+ if (ret < 0)
+ return false;
+ else if (num > 0)
+ nexthop_add_labels(nhop, ZEBRA_LSP_NONE,
+ num, larray);
+ }
+
+ nhop->weight = weight;
+
return true;
}
+/*
+ * Wrapper to parse the strings in a 'nexthop_hold'
+ */
+static bool nexthop_group_parse_nhh(struct nexthop *nhop,
+ const struct nexthop_hold *nhh)
+{
+ return (nexthop_group_parse_nexthop(nhop, nhh->addr, nhh->intf,
+ nhh->nhvrf_name, nhh->labels, NULL,
+ nhh->weight));
+}
+
DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
"[no] nexthop\
<\
<A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
|INTERFACE$intf\
>\
- [nexthop-vrf NAME$vrf_name]",
+ [{ \
+ nexthop-vrf NAME$vrf_name \
+ |label WORD \
+ |weight (1-255) \
+ }]",
NO_STR
"Specify one of the nexthops in this ECMP group\n"
"v4 Address\n"
@@ -609,14 +722,20 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
"Interface to use\n"
"Interface to use\n"
"If the nexthop is in a different vrf tell us\n"
- "The nexthop-vrf Name\n")
+ "The nexthop-vrf Name\n"
+ "Specify label(s) for this nexthop\n"
+ "One or more labels in the range (16-1048575) separated by '/'\n"
+ "Weight to be used by the nexthop for purposes of ECMP\n"
+ "Weight value to be used\n")
{
VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);
struct nexthop nhop;
struct nexthop *nh;
+ int lbl_ret = 0;
bool legal;
- legal = nexthop_group_parse_nexthop(&nhop, addr, intf, vrf_name);
+ legal = nexthop_group_parse_nexthop(&nhop, addr, intf, vrf_name, label,
+ &lbl_ret, weight);
if (nhop.type == NEXTHOP_TYPE_IPV6
&& IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
@@ -625,10 +744,32 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
return CMD_WARNING_CONFIG_FAILED;
}
+ /* Handle label-string errors */
+ if (!legal && lbl_ret < 0) {
+ switch (lbl_ret) {
+ case -1:
+ vty_out(vty, "%% Malformed label(s)\n");
+ break;
+ case -2:
+ vty_out(vty,
+ "%% Cannot use reserved label(s) (%d-%d)\n",
+ MPLS_LABEL_RESERVED_MIN,
+ MPLS_LABEL_RESERVED_MAX);
+ break;
+ case -3:
+ vty_out(vty,
+ "%% Too many labels. Enter %d or fewer\n",
+ MPLS_MAX_LABELS);
+ break;
+ }
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
nh = nexthop_exists(&nhgc->nhg, &nhop);
if (no) {
- nexthop_group_unsave_nhop(nhgc, vrf_name, addr, intf);
+ nexthop_group_unsave_nhop(nhgc, vrf_name, addr, intf, label,
+ weight);
if (nh) {
_nexthop_del(&nhgc->nhg, nh);
@@ -646,7 +787,8 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
_nexthop_add(&nhgc->nhg.nexthop, nh);
}
- nexthop_group_save_nhop(nhgc, vrf_name, addr, intf);
+ nexthop_group_save_nhop(nhgc, vrf_name, addr, intf, label,
+ weight);
if (legal && nhg_hooks.add_nexthop)
nhg_hooks.add_nexthop(nhgc, nh);
@@ -655,7 +797,7 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
return CMD_SUCCESS;
}
-struct cmd_node nexthop_group_node = {
+static struct cmd_node nexthop_group_node = {
NH_GROUP_NODE,
"%s(config-nh-group)# ",
1
@@ -696,6 +838,19 @@ void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh)
vrf = vrf_lookup_by_id(nh->vrf_id);
vty_out(vty, " nexthop-vrf %s", vrf->name);
}
+
+ if (nh->nh_label && nh->nh_label->num_labels > 0) {
+ char buf[200];
+
+ mpls_label2str(nh->nh_label->num_labels,
+ nh->nh_label->label,
+ buf, sizeof(buf), 0);
+ vty_out(vty, " label %s", buf);
+ }
+
+ if (nh->weight)
+ vty_out(vty, " weight %u", nh->weight);
+
vty_out(vty, "\n");
}
@@ -715,6 +870,12 @@ static void nexthop_group_write_nexthop_internal(struct vty *vty,
if (nh->nhvrf_name)
vty_out(vty, " nexthop-vrf %s", nh->nhvrf_name);
+ if (nh->labels)
+ vty_out(vty, " label %s", nh->labels);
+
+ if (nh->weight)
+ vty_out(vty, " weight %u", nh->weight);
+
vty_out(vty, "\n");
}
@@ -751,9 +912,7 @@ void nexthop_group_enable_vrf(struct vrf *vrf)
struct nexthop nhop;
struct nexthop *nh;
- if (!nexthop_group_parse_nexthop(&nhop, nhh->addr,
- nhh->intf,
- nhh->nhvrf_name))
+ if (!nexthop_group_parse_nhh(&nhop, nhh))
continue;
nh = nexthop_exists(&nhgc->nhg, &nhop);
@@ -787,9 +946,7 @@ void nexthop_group_disable_vrf(struct vrf *vrf)
struct nexthop nhop;
struct nexthop *nh;
- if (!nexthop_group_parse_nexthop(&nhop, nhh->addr,
- nhh->intf,
- nhh->nhvrf_name))
+ if (!nexthop_group_parse_nhh(&nhop, nhh))
continue;
nh = nexthop_exists(&nhgc->nhg, &nhop);
@@ -824,9 +981,7 @@ void nexthop_group_interface_state_change(struct interface *ifp,
for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nhh)) {
struct nexthop nhop;
- if (!nexthop_group_parse_nexthop(
- &nhop, nhh->addr, nhh->intf,
- nhh->nhvrf_name))
+ if (!nexthop_group_parse_nhh(&nhop, nhh))
continue;
switch (nhop.type) {
diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h
index 391775c69c..73b020283a 100644
--- a/lib/nexthop_group.h
+++ b/lib/nexthop_group.h
@@ -44,12 +44,21 @@ void nexthop_group_delete(struct nexthop_group **nhg);
void nexthop_group_copy(struct nexthop_group *to,
struct nexthop_group *from);
+
+/*
+ * Copy a list of nexthops in 'nh' to an nhg, enforcing canonical sort order
+ */
+void nexthop_group_copy_nh_sorted(struct nexthop_group *nhg,
+ const struct nexthop *nh);
+
void copy_nexthops(struct nexthop **tnh, const struct nexthop *nh,
struct nexthop *rparent);
uint32_t nexthop_group_hash_no_recurse(const struct nexthop_group *nhg);
uint32_t nexthop_group_hash(const struct nexthop_group *nhg);
void nexthop_group_mark_duplicates(struct nexthop_group *nhg);
+void nexthop_group_add_sorted(struct nexthop_group *nhg,
+ struct nexthop *nexthop);
/* The following for loop allows to iterate over the nexthop
* structure of routes.
@@ -70,12 +79,6 @@ void nexthop_group_mark_duplicates(struct nexthop_group *nhg);
(nhop) = nexthop_next(nhop)
-struct nexthop_hold {
- char *nhvrf_name;
- union sockunion *addr;
- char *intf;
-};
-
struct nexthop_group_cmd {
RB_ENTRY(nexthop_group_cmd) nhgc_entry;
diff --git a/lib/nexthop_group_private.h b/lib/nexthop_group_private.h
index cdd0df0ab3..4abda624ae 100644
--- a/lib/nexthop_group_private.h
+++ b/lib/nexthop_group_private.h
@@ -35,8 +35,6 @@ extern "C" {
void _nexthop_add(struct nexthop **target, struct nexthop *nexthop);
void _nexthop_del(struct nexthop_group *nhg, struct nexthop *nexthop);
-void _nexthop_group_add_sorted(struct nexthop_group *nhg,
- struct nexthop *nexthop);
#ifdef __cplusplus
}
diff --git a/lib/northbound.c b/lib/northbound.c
index debd463624..206a88d980 100644
--- a/lib/northbound.c
+++ b/lib/northbound.c
@@ -1882,7 +1882,8 @@ static void nb_load_callbacks(const struct frr_yang_module_info *module)
}
void nb_init(struct thread_master *tm,
- const struct frr_yang_module_info *modules[], size_t nmodules)
+ const struct frr_yang_module_info *const modules[],
+ size_t nmodules)
{
unsigned int errors = 0;
diff --git a/lib/northbound.h b/lib/northbound.h
index f52fcc90cf..76a11e518c 100644
--- a/lib/northbound.h
+++ b/lib/northbound.h
@@ -1010,7 +1010,8 @@ extern const char *nb_client_name(enum nb_client client);
* nmodules
* Size of the modules array.
*/
-extern void nb_init(struct thread_master *tm, const struct frr_yang_module_info *modules[],
+extern void nb_init(struct thread_master *tm,
+ const struct frr_yang_module_info *const modules[],
size_t nmodules);
/*
diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c
index d3e788d5d3..17dc256281 100644
--- a/lib/northbound_cli.c
+++ b/lib/northbound_cli.c
@@ -21,6 +21,7 @@
#include "libfrr.h"
#include "version.h"
+#include "defaults.h"
#include "log.h"
#include "lib_errors.h"
#include "command.h"
@@ -432,12 +433,12 @@ void nb_cli_show_config_prepare(struct nb_config *config, bool with_defaults)
lyd_schema_sort(config->dnode, 1);
/*
- * When "with-defaults" is used, call lyd_validate() only to create
- * default child nodes, ignoring any possible validation error. This
- * doesn't need to be done when displaying the running configuration
- * since it's always fully validated.
+ * Call lyd_validate() only to create default child nodes, ignoring
+ * any possible validation error. This doesn't need to be done when
+ * displaying the running configuration since it's always fully
+ * validated.
*/
- if (with_defaults && config != running_config)
+ if (config != running_config)
(void)lyd_validate(&config->dnode,
LYD_OPT_CONFIG | LYD_OPT_WHENAUTODEL,
ly_native_ctx);
@@ -486,7 +487,7 @@ static void nb_cli_show_config_cmds(struct vty *vty, struct nb_config *config,
vty_out(vty, "Configuration:\n");
vty_out(vty, "!\n");
vty_out(vty, "frr version %s\n", FRR_VER_SHORT);
- vty_out(vty, "frr defaults %s\n", DFLT_NAME);
+ vty_out(vty, "frr defaults %s\n", frr_defaults_profile());
LY_TREE_FOR (config->dnode, root)
nb_cli_show_dnode_cmds(vty, root, with_defaults);
diff --git a/lib/ns.h b/lib/ns.h
index 1963b8a359..20e0a38e3b 100644
--- a/lib/ns.h
+++ b/lib/ns.h
@@ -71,8 +71,6 @@ struct ns {
RB_HEAD(ns_head, ns);
RB_PROTOTYPE(ns_head, ns, entry, ns_compare)
-extern struct ns_head ns_tree;
-
/*
* API for managing NETNS. eg from zebra daemon
* one want to manage the list of NETNS, etc...
diff --git a/lib/plist.c b/lib/plist.c
index 64571a05b7..a0976cd6bd 100644
--- a/lib/plist.c
+++ b/lib/plist.c
@@ -1891,6 +1891,8 @@ int prefix_bgp_orf_set(char *name, afi_t afi, struct orf_prefix *orfp,
if (!plist)
return CMD_WARNING_CONFIG_FAILED;
+ apply_mask(&orfp->p);
+
if (set) {
pentry = prefix_list_entry_make(
&orfp->p, (permit ? PREFIX_PERMIT : PREFIX_DENY),
diff --git a/lib/prefix.c b/lib/prefix.c
index e2bf3b949c..219f798dcc 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -37,394 +37,6 @@ DEFINE_MTYPE_STATIC(LIB, PREFIX_FLOWSPEC, "Prefix Flowspec")
static const uint8_t maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0,
0xf8, 0xfc, 0xfe, 0xff};
-static const struct in6_addr maskbytes6[] = {
- /* /0 */ {{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /1 */
- {{{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /2 */
- {{{0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /3 */
- {{{0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /4 */
- {{{0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /5 */
- {{{0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /6 */
- {{{0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /7 */
- {{{0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /8 */
- {{{0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /9 */
- {{{0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /10 */
- {{{0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /11 */
- {{{0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /12 */
- {{{0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /13 */
- {{{0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /14 */
- {{{0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /15 */
- {{{0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /16 */
- {{{0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /17 */
- {{{0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /18 */
- {{{0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /19 */
- {{{0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /20 */
- {{{0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /21 */
- {{{0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /22 */
- {{{0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /23 */
- {{{0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /24 */
- {{{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /25 */
- {{{0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /26 */
- {{{0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /27 */
- {{{0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /28 */
- {{{0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /29 */
- {{{0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /30 */
- {{{0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /31 */
- {{{0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /32 */
- {{{0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /33 */
- {{{0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /34 */
- {{{0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /35 */
- {{{0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /36 */
- {{{0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /37 */
- {{{0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /38 */
- {{{0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /39 */
- {{{0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /40 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /41 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /42 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /43 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /44 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /45 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /46 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /47 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /48 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /49 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /50 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /51 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /52 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /53 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /54 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /55 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /56 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /57 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /58 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /59 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /60 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /61 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /62 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /63 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /64 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /65 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /66 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /67 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /68 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /69 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /70 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /71 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /72 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /73 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /74 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /75 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /76 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /77 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /78 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /79 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /80 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /81 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /82 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /83 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /84 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /85 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /86 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /87 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /88 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00}}},
- /* /89 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x80, 0x00, 0x00, 0x00, 0x00}}},
- /* /90 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xc0, 0x00, 0x00, 0x00, 0x00}}},
- /* /91 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xe0, 0x00, 0x00, 0x00, 0x00}}},
- /* /92 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xf0, 0x00, 0x00, 0x00, 0x00}}},
- /* /93 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xf8, 0x00, 0x00, 0x00, 0x00}}},
- /* /94 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xfc, 0x00, 0x00, 0x00, 0x00}}},
- /* /95 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xfe, 0x00, 0x00, 0x00, 0x00}}},
- /* /96 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0x00, 0x00, 0x00, 0x00}}},
- /* /97 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0x80, 0x00, 0x00, 0x00}}},
- /* /98 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xc0, 0x00, 0x00, 0x00}}},
- /* /99 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xe0, 0x00, 0x00, 0x00}}},
- /* /100 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xf0, 0x00, 0x00, 0x00}}},
- /* /101 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xf8, 0x00, 0x00, 0x00}}},
- /* /102 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xfc, 0x00, 0x00, 0x00}}},
- /* /103 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xfe, 0x00, 0x00, 0x00}}},
- /* /104 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0x00, 0x00, 0x00}}},
- /* /105 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0x80, 0x00, 0x00}}},
- /* /106 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xc0, 0x00, 0x00}}},
- /* /107 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xe0, 0x00, 0x00}}},
- /* /108 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xf0, 0x00, 0x00}}},
- /* /109 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xf8, 0x00, 0x00}}},
- /* /110 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xfc, 0x00, 0x00}}},
- /* /111 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xfe, 0x00, 0x00}}},
- /* /112 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0x00, 0x00}}},
- /* /113 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0x80, 0x00}}},
- /* /114 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xc0, 0x00}}},
- /* /115 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xe0, 0x00}}},
- /* /116 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xf0, 0x00}}},
- /* /117 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xf8, 0x00}}},
- /* /118 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xfc, 0x00}}},
- /* /119 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xfe, 0x00}}},
- /* /120 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x00}}},
- /* /121 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x80}}},
- /* /122 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xc0}}},
- /* /123 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xe0}}},
- /* /124 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xf0}}},
- /* /125 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xf8}}},
- /* /126 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xfc}}},
- /* /127 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xfe}}},
- /* /128 */
- {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff}}}};
-
/* Number of bits in prefix type. */
#ifndef PNBBY
#define PNBBY 8
@@ -432,15 +44,6 @@ static const struct in6_addr maskbytes6[] = {
#define MASKBIT(offset) ((0xff << (PNBBY - (offset))) & 0xff)
-void prefix_hexdump(const struct prefix *p)
-{
- char buf[PREFIX_STRLEN];
-
- zlog_debug("prefix: %s",
- prefix2str(p, buf, sizeof(buf)));
- zlog_hexdump(p, sizeof(struct prefix));
-}
-
int is_zero_mac(const struct ethaddr *mac)
{
int i = 0;
@@ -461,11 +64,6 @@ unsigned int prefix_bit(const uint8_t *prefix, const uint16_t prefixlen)
return (prefix[offset] >> shift) & 1;
}
-unsigned int prefix6_bit(const struct in6_addr *prefix, const uint16_t prefixlen)
-{
- return prefix_bit((const uint8_t *)&prefix->s6_addr, prefixlen);
-}
-
int str2family(const char *string)
{
if (!strcmp("ipv4", string))
@@ -1121,31 +719,46 @@ int str2prefix_ipv6(const char *str, struct prefix_ipv6 *p)
* FIXME return uint8_t as ip_maskleni() does. */
int ip6_masklen(struct in6_addr netmask)
{
- int len = 0;
- unsigned char val;
- unsigned char *pnt;
-
- pnt = (unsigned char *)&netmask;
-
- while ((*pnt == 0xff) && len < IPV6_MAX_BITLEN) {
- len += 8;
- pnt++;
- }
-
- if (len < IPV6_MAX_BITLEN) {
- val = *pnt;
- while (val) {
- len++;
- val <<= 1;
- }
- }
- return len;
+ if (netmask.s6_addr32[0] != 0xffffffffU)
+ return __builtin_clz(~ntohl(netmask.s6_addr32[0]));
+ if (netmask.s6_addr32[1] != 0xffffffffU)
+ return __builtin_clz(~ntohl(netmask.s6_addr32[1])) + 32;
+ if (netmask.s6_addr32[2] != 0xffffffffU)
+ return __builtin_clz(~ntohl(netmask.s6_addr32[2])) + 64;
+ if (netmask.s6_addr32[3] != 0xffffffffU)
+ return __builtin_clz(~ntohl(netmask.s6_addr32[3])) + 96;
+ /* note __builtin_clz(0) is undefined */
+ return 128;
}
void masklen2ip6(const int masklen, struct in6_addr *netmask)
{
assert(masklen >= 0 && masklen <= IPV6_MAX_BITLEN);
- memcpy(netmask, maskbytes6 + masklen, sizeof(struct in6_addr));
+
+ if (masklen == 0) {
+ /* note << 32 is undefined */
+ memset(netmask, 0, sizeof(*netmask));
+ } else if (masklen <= 32) {
+ netmask->s6_addr32[0] = htonl(0xffffffffU << (32 - masklen));
+ netmask->s6_addr32[1] = 0;
+ netmask->s6_addr32[2] = 0;
+ netmask->s6_addr32[3] = 0;
+ } else if (masklen <= 64) {
+ netmask->s6_addr32[0] = 0xffffffffU;
+ netmask->s6_addr32[1] = htonl(0xffffffffU << (64 - masklen));
+ netmask->s6_addr32[2] = 0;
+ netmask->s6_addr32[3] = 0;
+ } else if (masklen <= 96) {
+ netmask->s6_addr32[0] = 0xffffffffU;
+ netmask->s6_addr32[1] = 0xffffffffU;
+ netmask->s6_addr32[2] = htonl(0xffffffffU << (96 - masklen));
+ netmask->s6_addr32[3] = 0;
+ } else {
+ netmask->s6_addr32[0] = 0xffffffffU;
+ netmask->s6_addr32[1] = 0xffffffffU;
+ netmask->s6_addr32[2] = 0xffffffffU;
+ netmask->s6_addr32[3] = htonl(0xffffffffU << (128 - masklen));
+ }
}
void apply_mask_ipv6(struct prefix_ipv6 *p)
@@ -1183,33 +796,6 @@ void apply_mask(struct prefix *p)
return;
}
-/* Utility function of convert between struct prefix <=> union sockunion.
- * FIXME This function isn't used anywhere. */
-struct prefix *sockunion2prefix(const union sockunion *dest,
- const union sockunion *mask)
-{
- if (dest->sa.sa_family == AF_INET) {
- struct prefix_ipv4 *p;
-
- p = prefix_ipv4_new();
- p->family = AF_INET;
- p->prefix = dest->sin.sin_addr;
- p->prefixlen = ip_masklen(mask->sin.sin_addr);
- return (struct prefix *)p;
- }
- if (dest->sa.sa_family == AF_INET6) {
- struct prefix_ipv6 *p;
-
- p = prefix_ipv6_new();
- p->family = AF_INET6;
- p->prefixlen = ip6_masklen(mask->sin6.sin6_addr);
- memcpy(&p->prefix, &dest->sin6.sin6_addr,
- sizeof(struct in6_addr));
- return (struct prefix *)p;
- }
- return NULL;
-}
-
/* Utility function of convert between struct prefix <=> union sockunion. */
struct prefix *sockunion2hostprefix(const union sockunion *su,
struct prefix *prefix)
@@ -1521,14 +1107,6 @@ void apply_classful_mask_ipv4(struct prefix_ipv4 *p)
}
}
-in_addr_t ipv4_network_addr(in_addr_t hostaddr, int masklen)
-{
- struct in_addr mask;
-
- masklen2ip(masklen, &mask);
- return hostaddr & mask.s_addr;
-}
-
in_addr_t ipv4_broadcast_addr(in_addr_t hostaddr, int masklen)
{
struct in_addr mask;
diff --git a/lib/prefix.h b/lib/prefix.h
index 7a93c766a3..667627ddfe 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -392,8 +392,6 @@ extern const char *afi2str(afi_t afi);
/* Check bit of the prefix. */
extern unsigned int prefix_bit(const uint8_t *prefix, const uint16_t prefixlen);
-extern unsigned int prefix6_bit(const struct in6_addr *prefix,
- const uint16_t prefixlen);
extern struct prefix *prefix_new(void);
extern void prefix_free(struct prefix **p);
@@ -430,8 +428,6 @@ extern void apply_mask(struct prefix *);
#define prefix_copy(a, b) ({ memset(a, 0, sizeof(*a)); prefix_copy(a, b); })
#endif
-extern struct prefix *sockunion2prefix(const union sockunion *dest,
- const union sockunion *mask);
extern struct prefix *sockunion2hostprefix(const union sockunion *,
struct prefix *p);
extern void prefix2sockunion(const struct prefix *, union sockunion *);
@@ -453,8 +449,6 @@ extern void apply_classful_mask_ipv4(struct prefix_ipv4 *);
extern uint8_t ip_masklen(struct in_addr);
extern void masklen2ip(const int, struct in_addr *);
-/* returns the network portion of the host address */
-extern in_addr_t ipv4_network_addr(in_addr_t hostaddr, int masklen);
/* given the address of a host on a network and the network mask length,
* calculate the broadcast address for that network;
* special treatment for /31: returns the address of the other host
@@ -484,7 +478,6 @@ extern unsigned prefix_hash_key(const void *pp);
extern int str_to_esi(const char *str, esi_t *esi);
extern char *esi_to_str(const esi_t *esi, char *buf, int size);
-extern void prefix_hexdump(const struct prefix *p);
extern void prefix_evpn_hexdump(const struct prefix_evpn *p);
static inline int ipv6_martian(struct in6_addr *addr)
diff --git a/lib/printfrr.h b/lib/printfrr.h
index 95dace7021..f9584bcacc 100644
--- a/lib/printfrr.h
+++ b/lib/printfrr.h
@@ -124,7 +124,7 @@ void printfrr_ext_reg(const struct printfrr_ext *);
#define printfrr_ext_autoreg_p(matchs, print_fn) \
static ssize_t print_fn(char *, size_t, const char *, int, \
const void *); \
- static struct printfrr_ext _printext_##print_fn = { \
+ static const struct printfrr_ext _printext_##print_fn = { \
.match = matchs, \
.print_ptr = print_fn, \
}; \
@@ -136,7 +136,7 @@ void printfrr_ext_reg(const struct printfrr_ext *);
#define printfrr_ext_autoreg_i(matchs, print_fn) \
static ssize_t print_fn(char *, size_t, const char *, int, uintmax_t); \
- static struct printfrr_ext _printext_##print_fn = { \
+ static const struct printfrr_ext _printext_##print_fn = { \
.match = matchs, \
.print_int = print_fn, \
}; \
diff --git a/lib/qobj.c b/lib/qobj.c
index 3e3860a96a..1e48b541dc 100644
--- a/lib/qobj.c
+++ b/lib/qobj.c
@@ -48,7 +48,7 @@ static pthread_rwlock_t nodes_lock;
static struct qobj_nodes_head nodes = { };
-void qobj_reg(struct qobj_node *node, struct qobj_nodetype *type)
+void qobj_reg(struct qobj_node *node, const struct qobj_nodetype *type)
{
node->type = type;
pthread_rwlock_wrlock(&nodes_lock);
@@ -76,7 +76,7 @@ struct qobj_node *qobj_get(uint64_t id)
return rv;
}
-void *qobj_get_typed(uint64_t id, struct qobj_nodetype *type)
+void *qobj_get_typed(uint64_t id, const struct qobj_nodetype *type)
{
struct qobj_node dummy = {.nid = id};
struct qobj_node *node;
diff --git a/lib/qobj.h b/lib/qobj.h
index 415eae02ef..400ae0151c 100644
--- a/lib/qobj.h
+++ b/lib/qobj.h
@@ -89,7 +89,7 @@ PREDECL_HASH(qobj_nodes)
struct qobj_node {
uint64_t nid;
struct qobj_nodes_item nodehash;
- struct qobj_nodetype *type;
+ const struct qobj_nodetype *type;
};
#define QOBJ_FIELDS struct qobj_node qobj_node;
@@ -111,20 +111,20 @@ struct qobj_node {
*
* in the long this may need another touch, e.g. built-in per-object locking.
*/
-void qobj_reg(struct qobj_node *node, struct qobj_nodetype *type);
+void qobj_reg(struct qobj_node *node, const struct qobj_nodetype *type);
void qobj_unreg(struct qobj_node *node);
struct qobj_node *qobj_get(uint64_t id);
-void *qobj_get_typed(uint64_t id, struct qobj_nodetype *type);
+void *qobj_get_typed(uint64_t id, const struct qobj_nodetype *type);
/* type declarations */
#define DECLARE_QOBJ_TYPE(structname) \
- extern struct qobj_nodetype qobj_t_##structname;
+ extern const struct qobj_nodetype qobj_t_##structname;
#define DEFINE_QOBJ_TYPE(structname) \
- struct qobj_nodetype qobj_t_##structname = { \
+ const struct qobj_nodetype qobj_t_##structname = { \
.node_member_offset = \
(ptrdiff_t)offsetof(struct structname, qobj_node)};
#define DEFINE_QOBJ_TYPE_INIT(structname, ...) \
- struct qobj_nodetype qobj_t_##structname = { \
+ const struct qobj_nodetype qobj_t_##structname = { \
.node_member_offset = \
(ptrdiff_t)offsetof(struct structname, qobj_node), \
__VA_ARGS__};
diff --git a/lib/resolver.c b/lib/resolver.c
index fb8aeed92f..1be47bd6e1 100644
--- a/lib/resolver.c
+++ b/lib/resolver.c
@@ -145,7 +145,8 @@ static void ares_address_cb(void *arg, int status, int timeouts,
{
struct resolver_query *query = (struct resolver_query *)arg;
union sockunion addr[16];
- void (*callback)(struct resolver_query *, int, union sockunion *);
+ void (*callback)(struct resolver_query *, const char *, int,
+ union sockunion *);
size_t i;
callback = query->callback;
@@ -153,9 +154,10 @@ static void ares_address_cb(void *arg, int status, int timeouts,
if (status != ARES_SUCCESS) {
if (resolver_debug)
- zlog_debug("[%p] Resolving failed", query);
+ zlog_debug("[%p] Resolving failed (%s)",
+ query, ares_strerror(status));
- callback(query, -1, NULL);
+ callback(query, ares_strerror(status), -1, NULL);
return;
}
@@ -177,14 +179,29 @@ static void ares_address_cb(void *arg, int status, int timeouts,
if (resolver_debug)
zlog_debug("[%p] Resolved with %d results", query, (int)i);
- callback(query, i, &addr[0]);
+ callback(query, NULL, i, &addr[0]);
+}
+
+static int resolver_cb_literal(struct thread *t)
+{
+ struct resolver_query *query = THREAD_ARG(t);
+ void (*callback)(struct resolver_query *, const char *, int,
+ union sockunion *);
+
+ callback = query->callback;
+ query->callback = NULL;
+
+ callback(query, ARES_SUCCESS, 1, &query->literal_addr);
+ return 0;
}
void resolver_resolve(struct resolver_query *query, int af,
const char *hostname,
- void (*callback)(struct resolver_query *, int,
- union sockunion *))
+ void (*callback)(struct resolver_query *, const char *,
+ int, union sockunion *))
{
+ int ret;
+
if (query->callback != NULL) {
flog_err(
EC_LIB_RESOLVER,
@@ -193,10 +210,26 @@ void resolver_resolve(struct resolver_query *query, int af,
return;
}
+ query->callback = callback;
+ query->literal_cb = NULL;
+
+ ret = str2sockunion(hostname, &query->literal_addr);
+ if (ret == 0) {
+ if (resolver_debug)
+ zlog_debug("[%p] Resolving '%s' (IP literal)",
+ query, hostname);
+
+ /* for consistency with proper name lookup, don't call the
+ * callback immediately; defer to thread loop
+ */
+ thread_add_timer_msec(state.master, resolver_cb_literal,
+ query, 0, &query->literal_cb);
+ return;
+ }
+
if (resolver_debug)
zlog_debug("[%p] Resolving '%s'", query, hostname);
- query->callback = callback;
ares_gethostbyname(state.channel, hostname, af, ares_address_cb, query);
resolver_update_timeouts(&state);
}
diff --git a/lib/resolver.h b/lib/resolver.h
index bc6326edaa..59bf0d0f55 100644
--- a/lib/resolver.h
+++ b/lib/resolver.h
@@ -14,12 +14,18 @@
#include "sockunion.h"
struct resolver_query {
- void (*callback)(struct resolver_query *, int n, union sockunion *);
+ void (*callback)(struct resolver_query *, const char *errstr, int n,
+ union sockunion *);
+
+ /* used to immediate provide the result if IP literal is passed in */
+ union sockunion literal_addr;
+ struct thread *literal_cb;
};
void resolver_init(struct thread_master *tm);
void resolver_resolve(struct resolver_query *query, int af,
const char *hostname, void (*cb)(struct resolver_query *,
- int, union sockunion *));
+ const char *, int,
+ union sockunion *));
#endif /* _FRR_RESOLVER_H */
diff --git a/lib/routemap.c b/lib/routemap.c
index 580d898448..14fec0283c 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -221,7 +221,7 @@ struct route_map_match_set_hooks {
const char *command, const char *arg);
};
-struct route_map_match_set_hooks rmap_match_set_hook;
+static struct route_map_match_set_hooks rmap_match_set_hook;
/* match interface */
void route_map_match_interface_hook(int (*func)(
@@ -598,7 +598,7 @@ int generic_set_delete(struct vty *vty, struct route_map_index *index,
/* Route map rule. This rule has both `match' rule and `set' rule. */
struct route_map_rule {
/* Rule type. */
- struct route_map_rule_cmd *cmd;
+ const struct route_map_rule_cmd *cmd;
/* For pretty printing. */
char *rule_str;
@@ -623,7 +623,7 @@ struct route_map_list {
/* Master list of route map. */
static struct route_map_list route_map_master = {NULL, NULL, NULL, NULL, NULL};
-struct hash *route_map_master_hash = NULL;
+static struct hash *route_map_master_hash = NULL;
static unsigned int route_map_hash_key_make(const void *p)
{
@@ -683,7 +683,7 @@ struct route_map_dep_data {
};
/* Hashes maintaining dependency between various sublists used by route maps */
-struct hash *route_map_dep_hash[ROUTE_MAP_DEP_MAX];
+static struct hash *route_map_dep_hash[ROUTE_MAP_DEP_MAX];
static unsigned int route_map_dep_hash_make_key(const void *p);
static void route_map_clear_all_references(char *rmap_name);
@@ -1228,22 +1228,22 @@ static struct route_map_rule *route_map_rule_new(void)
}
/* Install rule command to the match list. */
-void route_map_install_match(struct route_map_rule_cmd *cmd)
+void route_map_install_match(const struct route_map_rule_cmd *cmd)
{
- vector_set(route_match_vec, cmd);
+ vector_set(route_match_vec, (void *)cmd);
}
/* Install rule command to the set list. */
-void route_map_install_set(struct route_map_rule_cmd *cmd)
+void route_map_install_set(const struct route_map_rule_cmd *cmd)
{
- vector_set(route_set_vec, cmd);
+ vector_set(route_set_vec, (void *)cmd);
}
/* Lookup rule command from match list. */
-static struct route_map_rule_cmd *route_map_lookup_match(const char *name)
+static const struct route_map_rule_cmd *route_map_lookup_match(const char *name)
{
unsigned int i;
- struct route_map_rule_cmd *rule;
+ const struct route_map_rule_cmd *rule;
for (i = 0; i < vector_active(route_match_vec); i++)
if ((rule = vector_slot(route_match_vec, i)) != NULL)
@@ -1253,10 +1253,10 @@ static struct route_map_rule_cmd *route_map_lookup_match(const char *name)
}
/* Lookup rule command from set list. */
-static struct route_map_rule_cmd *route_map_lookup_set(const char *name)
+static const struct route_map_rule_cmd *route_map_lookup_set(const char *name)
{
unsigned int i;
- struct route_map_rule_cmd *rule;
+ const struct route_map_rule_cmd *rule;
for (i = 0; i < vector_active(route_set_vec); i++)
if ((rule = vector_slot(route_set_vec, i)) != NULL)
@@ -1324,7 +1324,7 @@ const char *route_map_get_match_arg(struct route_map_index *index,
const char *match_name)
{
struct route_map_rule *rule;
- struct route_map_rule_cmd *cmd;
+ const struct route_map_rule_cmd *cmd;
/* First lookup rule for add match statement. */
cmd = route_map_lookup_match(match_name);
@@ -1396,7 +1396,7 @@ enum rmap_compile_rets route_map_add_match(struct route_map_index *index,
{
struct route_map_rule *rule;
struct route_map_rule *next;
- struct route_map_rule_cmd *cmd;
+ const struct route_map_rule_cmd *cmd;
void *compile;
int8_t delete_rmap_event_type = 0;
const char *rule_key;
@@ -1482,7 +1482,7 @@ enum rmap_compile_rets route_map_delete_match(struct route_map_index *index,
route_map_event_t type)
{
struct route_map_rule *rule;
- struct route_map_rule_cmd *cmd;
+ const struct route_map_rule_cmd *cmd;
const char *rule_key;
cmd = route_map_lookup_match(match_name);
@@ -1523,7 +1523,7 @@ enum rmap_compile_rets route_map_add_set(struct route_map_index *index,
{
struct route_map_rule *rule;
struct route_map_rule *next;
- struct route_map_rule_cmd *cmd;
+ const struct route_map_rule_cmd *cmd;
void *compile;
cmd = route_map_lookup_set(set_name);
@@ -1574,7 +1574,7 @@ enum rmap_compile_rets route_map_delete_set(struct route_map_index *index,
const char *set_arg)
{
struct route_map_rule *rule;
- struct route_map_rule_cmd *cmd;
+ const struct route_map_rule_cmd *cmd;
cmd = route_map_lookup_set(set_name);
if (cmd == NULL)
diff --git a/lib/routemap.h b/lib/routemap.h
index e6eccd4b29..1ffd0525ae 100644
--- a/lib/routemap.h
+++ b/lib/routemap.h
@@ -246,7 +246,7 @@ route_map_delete_set(struct route_map_index *index,
const char *set_name, const char *set_arg);
/* Install rule command to the match list. */
-extern void route_map_install_match(struct route_map_rule_cmd *cmd);
+extern void route_map_install_match(const struct route_map_rule_cmd *cmd);
/*
* Install rule command to the set list.
@@ -257,7 +257,7 @@ extern void route_map_install_match(struct route_map_rule_cmd *cmd);
* in the apply command). See 'set metric' command
* as it is handled in ripd/ripngd and ospfd.
*/
-extern void route_map_install_set(struct route_map_rule_cmd *cmd);
+extern void route_map_install_set(const struct route_map_rule_cmd *cmd);
/* Lookup route map by name. */
extern struct route_map *route_map_lookup_by_name(const char *name);
diff --git a/lib/skiplist.c b/lib/skiplist.c
index dda442580a..6efa2c362d 100644
--- a/lib/skiplist.c
+++ b/lib/skiplist.c
@@ -608,7 +608,7 @@ void skiplist_test(struct vty *vty)
struct skiplist *l;
register int i, k;
void *keys[sampleSize];
- void *v;
+ void *v = NULL;
zlog_debug("%s: entry", __func__);
diff --git a/lib/sockopt.c b/lib/sockopt.c
index 7726d74ff7..3b12d16cbc 100644
--- a/lib/sockopt.c
+++ b/lib/sockopt.c
@@ -122,21 +122,6 @@ int setsockopt_ipv6_pktinfo(int sock, int val)
}
/* Set multicast hops val to the socket. */
-int setsockopt_ipv6_checksum(int sock, int val)
-{
- int ret;
-
-#ifdef GNU_LINUX
- ret = setsockopt(sock, IPPROTO_RAW, IPV6_CHECKSUM, &val, sizeof(val));
-#else
- ret = setsockopt(sock, IPPROTO_IPV6, IPV6_CHECKSUM, &val, sizeof(val));
-#endif /* GNU_LINUX */
- if (ret < 0)
- flog_err(EC_LIB_SOCKET, "can't setsockopt IPV6_CHECKSUM");
- return ret;
-}
-
-/* Set multicast hops val to the socket. */
int setsockopt_ipv6_multicast_hops(int sock, int val)
{
int ret;
diff --git a/lib/sockopt.h b/lib/sockopt.h
index f6b57b8e07..59d8a65964 100644
--- a/lib/sockopt.h
+++ b/lib/sockopt.h
@@ -33,7 +33,6 @@ extern int getsockopt_so_sendbuf(const int sock);
extern int getsockopt_so_recvbuf(const int sock);
extern int setsockopt_ipv6_pktinfo(int, int);
-extern int setsockopt_ipv6_checksum(int, int);
extern int setsockopt_ipv6_multicast_hops(int, int);
extern int setsockopt_ipv6_unicast_hops(int, int);
extern int setsockopt_ipv6_hoplimit(int, int);
diff --git a/lib/stream.c b/lib/stream.c
index 2e1a0193a2..dd4d5bd96d 100644
--- a/lib/stream.c
+++ b/lib/stream.c
@@ -812,7 +812,7 @@ int stream_put_ipv4(struct stream *s, uint32_t l)
}
/* Put long word to the stream. */
-int stream_put_in_addr(struct stream *s, struct in_addr *addr)
+int stream_put_in_addr(struct stream *s, const struct in_addr *addr)
{
STREAM_VERIFY_SANE(s);
@@ -828,7 +828,8 @@ int stream_put_in_addr(struct stream *s, struct in_addr *addr)
}
/* Put in_addr at location in the stream. */
-int stream_put_in_addr_at(struct stream *s, size_t putp, struct in_addr *addr)
+int stream_put_in_addr_at(struct stream *s, size_t putp,
+ const struct in_addr *addr)
{
STREAM_VERIFY_SANE(s);
@@ -842,7 +843,8 @@ int stream_put_in_addr_at(struct stream *s, size_t putp, struct in_addr *addr)
}
/* Put in6_addr at location in the stream. */
-int stream_put_in6_addr_at(struct stream *s, size_t putp, struct in6_addr *addr)
+int stream_put_in6_addr_at(struct stream *s, size_t putp,
+ const struct in6_addr *addr)
{
STREAM_VERIFY_SANE(s);
@@ -856,7 +858,7 @@ int stream_put_in6_addr_at(struct stream *s, size_t putp, struct in6_addr *addr)
}
/* Put prefix by nlri type format. */
-int stream_put_prefix_addpath(struct stream *s, struct prefix *p,
+int stream_put_prefix_addpath(struct stream *s, const struct prefix *p,
int addpath_encode, uint32_t addpath_tx_id)
{
size_t psize;
@@ -890,7 +892,7 @@ int stream_put_prefix_addpath(struct stream *s, struct prefix *p,
return psize;
}
-int stream_put_prefix(struct stream *s, struct prefix *p)
+int stream_put_prefix(struct stream *s, const struct prefix *p)
{
return stream_put_prefix_addpath(s, p, 0, 0);
}
diff --git a/lib/stream.h b/lib/stream.h
index 1144e43ef0..c0d25e0579 100644
--- a/lib/stream.h
+++ b/lib/stream.h
@@ -186,13 +186,16 @@ extern int stream_putl_at(struct stream *, size_t, uint32_t);
extern int stream_putq(struct stream *, uint64_t);
extern int stream_putq_at(struct stream *, size_t, uint64_t);
extern int stream_put_ipv4(struct stream *, uint32_t);
-extern int stream_put_in_addr(struct stream *, struct in_addr *);
-extern int stream_put_in_addr_at(struct stream *, size_t, struct in_addr *);
-extern int stream_put_in6_addr_at(struct stream *, size_t, struct in6_addr *);
-extern int stream_put_prefix_addpath(struct stream *, struct prefix *,
+extern int stream_put_in_addr(struct stream *s, const struct in_addr *addr);
+extern int stream_put_in_addr_at(struct stream *s, size_t putp,
+ const struct in_addr *addr);
+extern int stream_put_in6_addr_at(struct stream *s, size_t putp,
+ const struct in6_addr *addr);
+extern int stream_put_prefix_addpath(struct stream *s,
+ const struct prefix *p,
int addpath_encode,
uint32_t addpath_tx_id);
-extern int stream_put_prefix(struct stream *, struct prefix *);
+extern int stream_put_prefix(struct stream *s, const struct prefix *p);
extern int stream_put_labeled_prefix(struct stream *, struct prefix *,
mpls_label_t *, int addpath_encode,
uint32_t addpath_tx_id);
diff --git a/lib/subdir.am b/lib/subdir.am
index 23b1950384..cb6fa7a3b8 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -18,6 +18,7 @@ lib_libfrr_la_SOURCES = \
lib/command_parse.y \
lib/csv.c \
lib/debug.c \
+ lib/defaults.c \
lib/distribute.c \
lib/ferr.c \
lib/filter.c \
@@ -40,13 +41,13 @@ lib_libfrr_la_SOURCES = \
lib/json.c \
lib/keychain.c \
lib/lib_errors.c \
+ lib/lib_vty.c \
lib/libfrr.c \
lib/linklist.c \
lib/log.c \
lib/log_vty.c \
lib/md5.c \
lib/memory.c \
- lib/memory_vty.c \
lib/mlag.c \
lib/module.c \
lib/mpls.c \
@@ -114,6 +115,7 @@ vtysh_scan += \
$(top_srcdir)/lib/if.c \
$(top_srcdir)/lib/if_rmap.c \
$(top_srcdir)/lib/keychain.c \
+ $(top_srcdir)/lib/lib_vty.c \
$(top_srcdir)/lib/nexthop_group.c \
$(top_srcdir)/lib/plist.c \
$(top_srcdir)/lib/routemap.c \
@@ -156,6 +158,7 @@ pkginclude_HEADERS += \
lib/csv.h \
lib/db.h \
lib/debug.h \
+ lib/defaults.h \
lib/distribute.h \
lib/ferr.h \
lib/filter.h \
@@ -179,6 +182,7 @@ pkginclude_HEADERS += \
lib/json.h \
lib/keychain.h \
lib/lib_errors.h \
+ lib/lib_vty.h \
lib/libfrr.h \
lib/libospf.h \
lib/linklist.h \
@@ -186,7 +190,6 @@ pkginclude_HEADERS += \
lib/log_vty.h \
lib/md5.h \
lib/memory.h \
- lib/memory_vty.h \
lib/module.h \
lib/monotime.h \
lib/mpls.h \
diff --git a/lib/systemd.c b/lib/systemd.c
index 44db48d006..81b0400ab9 100644
--- a/lib/systemd.c
+++ b/lib/systemd.c
@@ -32,7 +32,7 @@
* Wrapper this silliness if we
* don't have systemd
*/
-void systemd_send_information(const char *info)
+static void systemd_send_information(const char *info)
{
#if defined HAVE_SYSTEMD
sd_notify(0, info);
@@ -93,8 +93,8 @@ void systemd_send_stopping(void)
/*
* How many seconds should we wait between watchdog sends
*/
-int wsecs = 0;
-struct thread_master *systemd_master = NULL;
+static int wsecs = 0;
+static struct thread_master *systemd_master = NULL;
static int systemd_send_watchdog(struct thread *t)
{
diff --git a/lib/systemd.h b/lib/systemd.h
index 1f730720ce..d9885c5d9c 100644
--- a/lib/systemd.h
+++ b/lib/systemd.h
@@ -32,7 +32,6 @@ extern "C" {
* To turn on systemd compilation, use --enable-systemd on
* configure run.
*/
-void systemd_send_information(const char *info);
void systemd_send_stopping(void);
/*
diff --git a/lib/table.h b/lib/table.h
index 7a69c1664f..7743d51681 100644
--- a/lib/table.h
+++ b/lib/table.h
@@ -45,7 +45,7 @@ struct route_table;
* Function vector that can be used by a client to customize the
* behavior of one or more route tables.
*/
-typedef struct route_table_delegate_t_ route_table_delegate_t;
+typedef const struct route_table_delegate_t_ route_table_delegate_t;
typedef struct route_node *(*route_table_create_node_func_t)(
route_table_delegate_t *, struct route_table *);
diff --git a/lib/termtable.c b/lib/termtable.c
index b59c1118f8..b22a1ad387 100644
--- a/lib/termtable.c
+++ b/lib/termtable.c
@@ -27,7 +27,7 @@
DEFINE_MTYPE_STATIC(LIB, TTABLE, "ASCII table")
/* clang-format off */
-struct ttable_style ttable_styles[] = {
+const struct ttable_style ttable_styles[] = {
{ // default ascii
.corner = '+',
.rownums_on = false,
@@ -99,7 +99,7 @@ void ttable_del(struct ttable *tt)
XFREE(MTYPE_TTABLE, tt);
}
-struct ttable *ttable_new(struct ttable_style *style)
+struct ttable *ttable_new(const struct ttable_style *style)
{
struct ttable *tt;
diff --git a/lib/termtable.h b/lib/termtable.h
index 4f7c595ce2..698cc73465 100644
--- a/lib/termtable.h
+++ b/lib/termtable.h
@@ -80,7 +80,7 @@ struct ttable {
#define TTSTYLE_ASCII 0
#define TTSTYLE_BLANK 1
-extern struct ttable_style ttable_styles[2];
+extern const struct ttable_style ttable_styles[2];
/**
* Creates a new table with the default style, which looks like this:
@@ -95,7 +95,7 @@ extern struct ttable_style ttable_styles[2];
*
* @return the created table
*/
-struct ttable *ttable_new(struct ttable_style *tts);
+struct ttable *ttable_new(const struct ttable_style *tts);
/**
* Deletes a table and releases all associated resources.
diff --git a/lib/thread.c b/lib/thread.c
index 649fe500cd..651d26dfb2 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -66,7 +66,7 @@ DECLARE_HEAP(thread_timer_list, struct thread, timeritem,
#define AWAKEN(m) \
do { \
- static unsigned char wakebyte = 0x01; \
+ const unsigned char wakebyte = 0x01; \
write(m->io_pipe[1], &wakebyte, 1); \
} while (0);
diff --git a/lib/vrf.c b/lib/vrf.c
index 2411cc3111..c3a94224ee 100644
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -67,7 +67,7 @@ static char vrf_default_name[VRF_NAMSIZ] = VRF_DEFAULT_NAME_INTERNAL;
static int debug_vrf = 0;
/* Holding VRF hooks */
-struct vrf_master {
+static struct vrf_master {
int (*vrf_new_hook)(struct vrf *);
int (*vrf_delete_hook)(struct vrf *);
int (*vrf_enable_hook)(struct vrf *);
@@ -555,7 +555,6 @@ void vrf_terminate(void)
}
}
-/* Create a socket for the VRF. */
int vrf_socket(int domain, int type, int protocol, vrf_id_t vrf_id,
const char *interfacename)
{
@@ -752,7 +751,7 @@ DEFUN (no_vrf,
}
-struct cmd_node vrf_node = {VRF_NODE, "%s(config-vrf)# ", 1};
+static struct cmd_node vrf_node = {VRF_NODE, "%s(config-vrf)# ", 1};
DEFUN_NOSH (vrf_netns,
vrf_netns_cmd,
diff --git a/lib/vrf.h b/lib/vrf.h
index ca253e58a3..1d87576f78 100644
--- a/lib/vrf.h
+++ b/lib/vrf.h
@@ -218,13 +218,36 @@ extern void vrf_terminate(void);
* or call network operations
*/
-/* Create a socket serving for the given VRF */
+/*
+ * Create a new socket associated with a VRF.
+ *
+ * This is a wrapper that ensures correct behavior when using namespace VRFs.
+ * In the namespace case, the socket is created within the namespace. In the
+ * non-namespace case, this is equivalent to socket().
+ *
+ * If name is provided, this is provided to vrf_bind() to bind the socket to
+ * the VRF. This is only relevant when using VRF-lite.
+ *
+ * Summary:
+ * - Namespace: pass vrf_id but not name
+ * - VRF-lite: pass vrf_id and name of VRF device to bind to
+ * - VRF-lite, no binding: pass vrf_id but not name, or just use socket()
+ */
extern int vrf_socket(int domain, int type, int protocol, vrf_id_t vrf_id,
const char *name);
extern int vrf_sockunion_socket(const union sockunion *su, vrf_id_t vrf_id,
const char *name);
+/*
+ * Binds a socket to a VRF device.
+ *
+ * If name is null, the socket is not bound, irrespective of any other
+ * arguments.
+ *
+ * name should be the name of the VRF device. vrf_id should be the
+ * corresponding vrf_id (the ifindex of the device).
+ */
extern int vrf_bind(vrf_id_t vrf_id, int fd, const char *name);
/* VRF ioctl operations */
diff --git a/lib/vty.c b/lib/vty.c
index c08e5e151a..40da8abcd7 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -89,7 +89,7 @@ static char *vty_ipv6_accesslist_name = NULL;
static vector Vvty_serv_thread;
/* Current directory. */
-char vty_cwd[MAXPATHLEN];
+static char vty_cwd[MAXPATHLEN];
/* Login password check. */
static int no_password_check = 0;
diff --git a/lib/zclient.c b/lib/zclient.c
index a135d18744..6982d287a2 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -802,6 +802,12 @@ static int zapi_nexthop_cmp_no_labels(const struct zapi_nexthop *next1,
if (next1->type > next2->type)
return 1;
+ if (next1->weight < next2->weight)
+ return -1;
+
+ if (next1->weight > next2->weight)
+ return 1;
+
switch (next1->type) {
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV6:
@@ -859,6 +865,82 @@ static void zapi_nexthop_group_sort(struct zapi_nexthop *nh_grp,
&zapi_nexthop_cmp);
}
+/*
+ * Encode a single zapi nexthop
+ */
+int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh,
+ uint32_t api_flags)
+{
+ int ret = 0;
+ int nh_flags = api_nh->flags;
+
+ stream_putl(s, api_nh->vrf_id);
+ stream_putc(s, api_nh->type);
+
+ /* If needed, set 'labelled nexthop' flag */
+ if (api_nh->label_num > 0) {
+ SET_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_LABEL);
+
+ /* Validate label count */
+ if (api_nh->label_num > MPLS_MAX_LABELS) {
+ ret = -1;
+ goto done;
+ }
+ }
+
+ if (api_nh->weight)
+ SET_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_WEIGHT);
+
+ /* Note that we're only encoding a single octet */
+ stream_putc(s, nh_flags);
+
+ switch (api_nh->type) {
+ case NEXTHOP_TYPE_BLACKHOLE:
+ stream_putc(s, api_nh->bh_type);
+ break;
+ case NEXTHOP_TYPE_IPV4:
+ stream_put_in_addr(s, &api_nh->gate.ipv4);
+ break;
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ stream_put_in_addr(s, &api_nh->gate.ipv4);
+ stream_putl(s, api_nh->ifindex);
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ stream_putl(s, api_nh->ifindex);
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ stream_write(s, (uint8_t *)&api_nh->gate.ipv6,
+ 16);
+ break;
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ stream_write(s, (uint8_t *)&api_nh->gate.ipv6,
+ 16);
+ stream_putl(s, api_nh->ifindex);
+ break;
+ }
+
+ /* We only encode labels if we have >0 - we use
+ * the per-nexthop flag above to signal that the count
+ * is present in the payload.
+ */
+ if (api_nh->label_num > 0) {
+ stream_putc(s, api_nh->label_num);
+ stream_put(s, &api_nh->labels[0],
+ api_nh->label_num * sizeof(mpls_label_t));
+ }
+
+ if (api_nh->weight)
+ stream_putl(s, api_nh->weight);
+
+ /* Router MAC for EVPN routes. */
+ if (CHECK_FLAG(api_flags, ZEBRA_FLAG_EVPN_ROUTE))
+ stream_put(s, &(api_nh->rmac),
+ sizeof(struct ethaddr));
+
+done:
+ return ret;
+}
+
int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
{
struct zapi_nexthop *api_nh;
@@ -921,59 +1003,22 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
for (i = 0; i < api->nexthop_num; i++) {
api_nh = &api->nexthops[i];
- stream_putl(s, api_nh->vrf_id);
- stream_putc(s, api_nh->type);
- stream_putc(s, api_nh->onlink);
- switch (api_nh->type) {
- case NEXTHOP_TYPE_BLACKHOLE:
- stream_putc(s, api_nh->bh_type);
- break;
- case NEXTHOP_TYPE_IPV4:
- stream_put_in_addr(s, &api_nh->gate.ipv4);
- break;
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- stream_put_in_addr(s, &api_nh->gate.ipv4);
- stream_putl(s, api_nh->ifindex);
- break;
- case NEXTHOP_TYPE_IFINDEX:
- stream_putl(s, api_nh->ifindex);
- break;
- case NEXTHOP_TYPE_IPV6:
- stream_write(s, (uint8_t *)&api_nh->gate.ipv6,
- 16);
- break;
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- stream_write(s, (uint8_t *)&api_nh->gate.ipv6,
- 16);
- stream_putl(s, api_nh->ifindex);
- break;
- }
-
/* MPLS labels for BGP-LU or Segment Routing */
- if (CHECK_FLAG(api->message, ZAPI_MESSAGE_LABEL)) {
- if (api_nh->label_num > MPLS_MAX_LABELS) {
- char buf[PREFIX2STR_BUFFER];
- prefix2str(&api->prefix, buf,
- sizeof(buf));
- flog_err(EC_LIB_ZAPI_ENCODE,
- "%s: prefix %s: can't encode "
- "%u labels (maximum is %u)",
- __func__, buf,
- api_nh->label_num,
- MPLS_MAX_LABELS);
- return -1;
- }
-
- stream_putc(s, api_nh->label_num);
- stream_put(s, &api_nh->labels[0],
- api_nh->label_num
- * sizeof(mpls_label_t));
+ if (api_nh->label_num > MPLS_MAX_LABELS) {
+ char buf[PREFIX2STR_BUFFER];
+
+ prefix2str(&api->prefix, buf, sizeof(buf));
+
+ flog_err(EC_LIB_ZAPI_ENCODE,
+ "%s: prefix %s: can't encode %u labels (maximum is %u)",
+ __func__, buf,
+ api_nh->label_num,
+ MPLS_MAX_LABELS);
+ return -1;
}
- /* Router MAC for EVPN routes. */
- if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE))
- stream_put(s, &(api_nh->rmac),
- sizeof(struct ethaddr));
+ if (zapi_nexthop_encode(s, api_nh, api->flags) != 0)
+ return -1;
}
}
@@ -995,6 +1040,76 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
return 0;
}
+/*
+ * Decode a single zapi nexthop object
+ */
+static int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh,
+ uint32_t api_flags)
+{
+ int ret = -1;
+
+ STREAM_GETL(s, api_nh->vrf_id);
+ STREAM_GETC(s, api_nh->type);
+
+ /* Note that we're only using a single octet of flags */
+ STREAM_GETC(s, api_nh->flags);
+
+ switch (api_nh->type) {
+ case NEXTHOP_TYPE_BLACKHOLE:
+ STREAM_GETC(s, api_nh->bh_type);
+ break;
+ case NEXTHOP_TYPE_IPV4:
+ STREAM_GET(&api_nh->gate.ipv4.s_addr, s,
+ IPV4_MAX_BYTELEN);
+ break;
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ STREAM_GET(&api_nh->gate.ipv4.s_addr, s,
+ IPV4_MAX_BYTELEN);
+ STREAM_GETL(s, api_nh->ifindex);
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ STREAM_GETL(s, api_nh->ifindex);
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ STREAM_GET(&api_nh->gate.ipv6, s, 16);
+ break;
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ STREAM_GET(&api_nh->gate.ipv6, s, 16);
+ STREAM_GETL(s, api_nh->ifindex);
+ break;
+ }
+
+ /* MPLS labels for BGP-LU or Segment Routing */
+ if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL)) {
+ STREAM_GETC(s, api_nh->label_num);
+ if (api_nh->label_num > MPLS_MAX_LABELS) {
+ flog_err(
+ EC_LIB_ZAPI_ENCODE,
+ "%s: invalid number of MPLS labels (%u)",
+ __func__, api_nh->label_num);
+ return -1;
+ }
+
+ STREAM_GET(&api_nh->labels[0], s,
+ api_nh->label_num * sizeof(mpls_label_t));
+ }
+
+ if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_WEIGHT))
+ STREAM_GETL(s, api_nh->weight);
+
+ /* Router MAC for EVPN routes. */
+ if (CHECK_FLAG(api_flags, ZEBRA_FLAG_EVPN_ROUTE))
+ STREAM_GET(&(api_nh->rmac), s,
+ sizeof(struct ethaddr));
+
+ /* Success */
+ ret = 0;
+
+stream_failure:
+
+ return ret;
+}
+
int zapi_route_decode(struct stream *s, struct zapi_route *api)
{
struct zapi_nexthop *api_nh;
@@ -1088,55 +1203,8 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api)
for (i = 0; i < api->nexthop_num; i++) {
api_nh = &api->nexthops[i];
- STREAM_GETL(s, api_nh->vrf_id);
- STREAM_GETC(s, api_nh->type);
- STREAM_GETC(s, api_nh->onlink);
- switch (api_nh->type) {
- case NEXTHOP_TYPE_BLACKHOLE:
- STREAM_GETC(s, api_nh->bh_type);
- break;
- case NEXTHOP_TYPE_IPV4:
- STREAM_GET(&api_nh->gate.ipv4.s_addr, s,
- IPV4_MAX_BYTELEN);
- break;
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- STREAM_GET(&api_nh->gate.ipv4.s_addr, s,
- IPV4_MAX_BYTELEN);
- STREAM_GETL(s, api_nh->ifindex);
- break;
- case NEXTHOP_TYPE_IFINDEX:
- STREAM_GETL(s, api_nh->ifindex);
- break;
- case NEXTHOP_TYPE_IPV6:
- STREAM_GET(&api_nh->gate.ipv6, s, 16);
- break;
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- STREAM_GET(&api_nh->gate.ipv6, s, 16);
- STREAM_GETL(s, api_nh->ifindex);
- break;
- }
-
- /* MPLS labels for BGP-LU or Segment Routing */
- if (CHECK_FLAG(api->message, ZAPI_MESSAGE_LABEL)) {
- STREAM_GETC(s, api_nh->label_num);
-
- if (api_nh->label_num > MPLS_MAX_LABELS) {
- flog_err(
- EC_LIB_ZAPI_ENCODE,
- "%s: invalid number of MPLS labels (%u)",
- __func__, api_nh->label_num);
- return -1;
- }
-
- STREAM_GET(&api_nh->labels[0], s,
- api_nh->label_num
- * sizeof(mpls_label_t));
- }
-
- /* Router MAC for EVPN routes. */
- if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE))
- stream_get(&(api_nh->rmac), s,
- sizeof(struct ethaddr));
+ if (zapi_nexthop_decode(s, api_nh, api->flags) != 0)
+ return -1;
}
}
@@ -1335,6 +1403,35 @@ struct nexthop *nexthop_from_zapi_nexthop(struct zapi_nexthop *znh)
return n;
}
+/*
+ * Convert nexthop to zapi nexthop
+ */
+int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh,
+ const struct nexthop *nh)
+{
+ int i;
+
+ memset(znh, 0, sizeof(*znh));
+
+ znh->type = nh->type;
+ znh->vrf_id = nh->vrf_id;
+ znh->ifindex = nh->ifindex;
+ znh->gate = nh->gate;
+
+ if (nh->nh_label && (nh->nh_label->num_labels > 0)) {
+ for (i = 0; i < nh->nh_label->num_labels; i++)
+ znh->labels[i] = nh->nh_label->label[i];
+
+ znh->label_num = i;
+ SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_LABEL);
+ }
+
+ return 0;
+}
+
+/*
+ * Decode the nexthop-tracking update message
+ */
bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr)
{
uint32_t i;
@@ -1361,38 +1458,8 @@ bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr)
STREAM_GETC(s, nhr->nexthop_num);
for (i = 0; i < nhr->nexthop_num; i++) {
- STREAM_GETL(s, nhr->nexthops[i].vrf_id);
- STREAM_GETC(s, nhr->nexthops[i].type);
- switch (nhr->nexthops[i].type) {
- case NEXTHOP_TYPE_IPV4:
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- STREAM_GET(&nhr->nexthops[i].gate.ipv4.s_addr, s,
- IPV4_MAX_BYTELEN);
- STREAM_GETL(s, nhr->nexthops[i].ifindex);
- break;
- case NEXTHOP_TYPE_IFINDEX:
- STREAM_GETL(s, nhr->nexthops[i].ifindex);
- break;
- case NEXTHOP_TYPE_IPV6:
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- STREAM_GET(&nhr->nexthops[i].gate.ipv6, s,
- IPV6_MAX_BYTELEN);
- STREAM_GETL(s, nhr->nexthops[i].ifindex);
- break;
- case NEXTHOP_TYPE_BLACKHOLE:
- break;
- }
- STREAM_GETC(s, nhr->nexthops[i].label_num);
- if (nhr->nexthops[i].label_num > MPLS_MAX_LABELS) {
- flog_err(EC_LIB_ZAPI_ENCODE,
- "%s: invalid number of MPLS labels (%u)",
- __func__, nhr->nexthops[i].label_num);
- return false;
- }
- if (nhr->nexthops[i].label_num)
- STREAM_GET(&nhr->nexthops[i].labels[0], s,
- nhr->nexthops[i].label_num
- * sizeof(mpls_label_t));
+ if (zapi_nexthop_decode(s, &(nhr->nexthops[i]), 0) != 0)
+ return -1;
}
return true;
@@ -2721,6 +2788,57 @@ stream_failure:
return;
}
+void zclient_send_mlag_register(struct zclient *client, uint32_t bit_map)
+{
+ struct stream *s;
+
+ s = client->obuf;
+ stream_reset(s);
+
+ zclient_create_header(s, ZEBRA_MLAG_CLIENT_REGISTER, VRF_DEFAULT);
+ stream_putl(s, bit_map);
+
+ stream_putw_at(s, 0, stream_get_endp(s));
+ zclient_send_message(client);
+}
+
+void zclient_send_mlag_deregister(struct zclient *client)
+{
+ zebra_message_send(client, ZEBRA_MLAG_CLIENT_UNREGISTER, VRF_DEFAULT);
+}
+
+void zclient_send_mlag_data(struct zclient *client, struct stream *client_s)
+{
+ struct stream *s;
+
+ s = client->obuf;
+ stream_reset(s);
+
+ zclient_create_header(s, ZEBRA_MLAG_FORWARD_MSG, VRF_DEFAULT);
+ stream_put(s, client_s->data, client_s->endp);
+
+ stream_putw_at(s, 0, stream_get_endp(s));
+ zclient_send_message(client);
+}
+
+static void zclient_mlag_process_up(ZAPI_CALLBACK_ARGS)
+{
+ if (zclient->mlag_process_up)
+ (*zclient->mlag_process_up)();
+}
+
+static void zclient_mlag_process_down(ZAPI_CALLBACK_ARGS)
+{
+ if (zclient->mlag_process_down)
+ (*zclient->mlag_process_down)();
+}
+
+static void zclient_mlag_handle_msg(ZAPI_CALLBACK_ARGS)
+{
+ if (zclient->mlag_handle_msg)
+ (*zclient->mlag_handle_msg)(zclient->ibuf, length);
+}
+
/* Zebra client message read function. */
static int zclient_read(struct thread *thread)
{
@@ -3015,6 +3133,15 @@ static int zclient_read(struct thread *thread)
(*zclient->vxlan_sg_del)(command, zclient, length,
vrf_id);
break;
+ case ZEBRA_MLAG_PROCESS_UP:
+ zclient_mlag_process_up(command, zclient, length, vrf_id);
+ break;
+ case ZEBRA_MLAG_PROCESS_DOWN:
+ zclient_mlag_process_down(command, zclient, length, vrf_id);
+ break;
+ case ZEBRA_MLAG_FORWARD_MSG:
+ zclient_mlag_handle_msg(command, zclient, length, vrf_id);
+ break;
default:
break;
}
diff --git a/lib/zclient.h b/lib/zclient.h
index 2131d4d47a..70304127a2 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -178,6 +178,11 @@ typedef enum {
ZEBRA_VXLAN_SG_ADD,
ZEBRA_VXLAN_SG_DEL,
ZEBRA_VXLAN_SG_REPLAY,
+ ZEBRA_MLAG_PROCESS_UP,
+ ZEBRA_MLAG_PROCESS_DOWN,
+ ZEBRA_MLAG_CLIENT_REGISTER,
+ ZEBRA_MLAG_CLIENT_UNREGISTER,
+ ZEBRA_MLAG_FORWARD_MSG,
} zebra_message_types_t;
struct redist_proto {
@@ -272,6 +277,9 @@ struct zclient {
int (*iptable_notify_owner)(ZAPI_CALLBACK_ARGS);
int (*vxlan_sg_add)(ZAPI_CALLBACK_ARGS);
int (*vxlan_sg_del)(ZAPI_CALLBACK_ARGS);
+ int (*mlag_process_up)(void);
+ int (*mlag_process_down)(void);
+ int (*mlag_handle_msg)(struct stream *msg, int len);
};
/* Zebra API message flag. */
@@ -281,7 +289,6 @@ struct zclient {
#define ZAPI_MESSAGE_TAG 0x08
#define ZAPI_MESSAGE_MTU 0x10
#define ZAPI_MESSAGE_SRCPFX 0x20
-#define ZAPI_MESSAGE_LABEL 0x40
/*
* This should only be used by a DAEMON that needs to communicate
* the table being used is not in the VRF. You must pass the
@@ -305,7 +312,7 @@ struct zapi_nexthop {
enum nexthop_types_t type;
vrf_id_t vrf_id;
ifindex_t ifindex;
- bool onlink;
+ uint8_t flags;
union {
union g_addr gate;
enum blackhole_type bh_type;
@@ -316,9 +323,18 @@ struct zapi_nexthop {
mpls_label_t labels[MPLS_MAX_LABELS];
struct ethaddr rmac;
+
+ uint32_t weight;
};
/*
+ * ZAPI nexthop flags values
+ */
+#define ZAPI_NEXTHOP_FLAG_ONLINK 0x01
+#define ZAPI_NEXTHOP_FLAG_LABEL 0x02
+#define ZAPI_NEXTHOP_FLAG_WEIGHT 0x04
+
+/*
* Some of these data structures do not map easily to
* a actual data structure size giving different compilers
* and systems. For those data structures we need
@@ -477,11 +493,35 @@ enum zapi_iptable_notify_owner {
ZAPI_IPTABLE_FAIL_REMOVE,
};
+static inline const char *
+zapi_rule_notify_owner2str(enum zapi_rule_notify_owner note)
+{
+ const char *ret = "UNKNOWN";
+
+ switch (note) {
+ case ZAPI_RULE_FAIL_INSTALL:
+ ret = "ZAPI_RULE_FAIL_INSTALL";
+ break;
+ case ZAPI_RULE_INSTALLED:
+ ret = "ZAPI_RULE_INSTALLED";
+ break;
+ case ZAPI_RULE_FAIL_REMOVE:
+ ret = "ZAPI_RULE_FAIL_REMOVE";
+ break;
+ case ZAPI_RULE_REMOVED:
+ ret = "ZAPI_RULE_REMOVED";
+ break;
+ }
+
+ return ret;
+}
+
/* Zebra MAC types */
#define ZEBRA_MACIP_TYPE_STICKY 0x01 /* Sticky MAC*/
#define ZEBRA_MACIP_TYPE_GW 0x02 /* gateway (SVI) mac*/
#define ZEBRA_MACIP_TYPE_ROUTER_FLAG 0x04 /* Router Flag - proxy NA */
#define ZEBRA_MACIP_TYPE_OVERRIDE_FLAG 0x08 /* Override Flag */
+#define ZEBRA_MACIP_TYPE_SVI_IP 0x10 /* SVI MAC-IP */
enum zebra_neigh_state { ZEBRA_NEIGH_INACTIVE = 0, ZEBRA_NEIGH_ACTIVE = 1 };
@@ -657,6 +697,8 @@ extern int zclient_route_send(uint8_t, struct zclient *, struct zapi_route *);
extern int zclient_send_rnh(struct zclient *zclient, int command,
struct prefix *p, bool exact_match,
vrf_id_t vrf_id);
+int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh,
+ uint32_t api_flags);
extern int zapi_route_encode(uint8_t, struct stream *, struct zapi_route *);
extern int zapi_route_decode(struct stream *, struct zapi_route *);
bool zapi_route_notify_decode(struct stream *s, struct prefix *p,
@@ -681,6 +723,8 @@ bool zapi_iptable_notify_decode(struct stream *s,
enum zapi_iptable_notify_owner *note);
extern struct nexthop *nexthop_from_zapi_nexthop(struct zapi_nexthop *znh);
+int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh,
+ const struct nexthop *nh);
extern bool zapi_nexthop_update_decode(struct stream *s,
struct zapi_route *nhr);
@@ -694,5 +738,11 @@ static inline void zapi_route_set_blackhole(struct zapi_route *api,
SET_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP);
};
+extern void zclient_send_mlag_register(struct zclient *client,
+ uint32_t bit_map);
+extern void zclient_send_mlag_deregister(struct zclient *client);
+
+extern void zclient_send_mlag_data(struct zclient *client,
+ struct stream *client_s);
#endif /* _ZEBRA_ZCLIENT_H */