diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Makefile.am | 14 | ||||
-rw-r--r-- | lib/checksum.c | 53 | ||||
-rw-r--r-- | lib/command.c | 340 | ||||
-rw-r--r-- | lib/command.h | 4 | ||||
-rw-r--r-- | lib/if.c | 2 | ||||
-rw-r--r-- | lib/if.h | 7 | ||||
-rw-r--r-- | lib/log.c | 83 | ||||
-rw-r--r-- | lib/log.h | 2 | ||||
-rw-r--r-- | lib/md5.c | 73 | ||||
-rw-r--r-- | lib/md5.h | 3 | ||||
-rw-r--r-- | lib/memory.c | 15 | ||||
-rw-r--r-- | lib/memtypes.c | 18 | ||||
-rw-r--r-- | lib/paths.c | 65 | ||||
-rw-r--r-- | lib/paths.h | 34 | ||||
-rw-r--r-- | lib/prefix.c | 54 | ||||
-rw-r--r-- | lib/prefix.h | 2 | ||||
-rw-r--r-- | lib/route_types.awk | 187 | ||||
-rwxr-xr-x | lib/route_types.pl | 199 | ||||
-rw-r--r-- | lib/route_types.txt | 19 | ||||
-rw-r--r-- | lib/sockunion.c | 34 | ||||
-rw-r--r-- | lib/sockunion.h | 2 | ||||
-rw-r--r-- | lib/stream.c | 26 | ||||
-rw-r--r-- | lib/stream.h | 4 | ||||
-rw-r--r-- | lib/thread.c | 274 | ||||
-rw-r--r-- | lib/thread.h | 13 | ||||
-rw-r--r-- | lib/vty.c | 31 | ||||
-rw-r--r-- | lib/workqueue.c | 17 | ||||
-rw-r--r-- | lib/zclient.c | 36 | ||||
-rw-r--r-- | lib/zclient.h | 12 | ||||
-rw-r--r-- | lib/zebra.h | 66 |
30 files changed, 1054 insertions, 635 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am index 315e919b..1b4134dc 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,7 +1,7 @@ ## Process this file with automake to produce Makefile.in. INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib @SNMP_INCLUDES@ -DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DPATH_CONFIG=\"$(sysconfdir)\" lib_LTLIBRARIES = libzebra.la libzebra_la_LDFLAGS = -version-info 0:0:0 @@ -12,13 +12,13 @@ libzebra_la_SOURCES = \ sockunion.c prefix.c thread.c if.c memory.c buffer.c table.c hash.c \ filter.c routemap.c distribute.c stream.c str.c log.c plist.c \ zclient.c sockopt.c smux.c md5.c if_rmap.c keychain.c privs.c \ - sigevent.c pqueue.c jhash.c memtypes.c workqueue.c + sigevent.c pqueue.c jhash.c memtypes.c workqueue.c paths.c BUILT_SOURCES = memtypes.h route_types.h libzebra_la_DEPENDENCIES = @LIB_REGEX@ -libzebra_la_LIBADD = @LIB_REGEX@ +libzebra_la_LIBADD = @LIB_REGEX@ @LIBCAP@ pkginclude_HEADERS = \ buffer.h checksum.h command.h filter.h getopt.h hash.h \ @@ -27,12 +27,12 @@ pkginclude_HEADERS = \ str.h stream.h table.h thread.h vector.h version.h vty.h zebra.h \ plist.h zclient.h sockopt.h smux.h md5.h if_rmap.h keychain.h \ privs.h sigevent.h pqueue.h jhash.h zassert.h memtypes.h \ - workqueue.h route_types.h + workqueue.h route_types.h paths.h -EXTRA_DIST = regex.c regex-gnu.h memtypes.awk route_types.awk route_types.txt +EXTRA_DIST = regex.c regex-gnu.h memtypes.awk route_types.pl route_types.txt memtypes.h: $(srcdir)/memtypes.c $(srcdir)/memtypes.awk ($(GAWK) -f $(srcdir)/memtypes.awk $(srcdir)/memtypes.c > $@) -route_types.h: $(srcdir)/route_types.txt $(srcdir)/route_types.awk - ($(GAWK) -f $(srcdir)/route_types.awk $(srcdir)/route_types.txt > $@) +route_types.h: $(srcdir)/route_types.txt $(srcdir)/route_types.pl + @PERL@ $(srcdir)/route_types.pl < $(srcdir)/route_types.txt > $@ diff --git a/lib/checksum.c b/lib/checksum.c index 3ddde815..af4f2550 100644 --- a/lib/checksum.c +++ b/lib/checksum.c @@ -14,27 +14,20 @@ in_cksum(void *parg, int nbytes) { u_short *ptr = parg; register long sum; /* assumes long == 32 bits */ - u_short oddbyte; register u_short answer; /* assumes u_short == 16 bits */ - + register int count; /* * Our algorithm is simple, using a 32-bit accumulator (sum), * we add sequential 16-bit words to it, and at the end, fold back * all the carry bits from the top 16 bits into the lower 16 bits. */ - sum = 0; - while (nbytes > 1) { - sum += *ptr++; - nbytes -= 2; - } - - /* mop up an odd byte, if necessary */ - if (nbytes == 1) { - oddbyte = 0; /* make sure top half is zero */ - *((u_char *) &oddbyte) = *(u_char *)ptr; /* one byte only */ - sum += oddbyte; - } + count = nbytes >> 1; /* div by 2 */ + for(ptr--; count; --count) + sum += *++ptr; + + if (nbytes & 1) /* Odd */ + sum += *(u_char *)(++ptr); /* one byte only */ /* * Add back carry outs from top 16 bits to low 16 bits. @@ -56,11 +49,8 @@ fletcher_checksum(u_char * buffer, const size_t len, const uint16_t offset) { u_int8_t *p; int x, y, c0, c1; - u_int16_t checksum; u_int16_t *csum; size_t partial_len, i, left = len; - - checksum = 0; assert (offset < len); @@ -68,47 +58,42 @@ fletcher_checksum(u_char * buffer, const size_t len, const uint16_t offset) * Zero the csum in the packet. */ csum = (u_int16_t *) (buffer + offset); - *(csum) = 0; + *csum = 0; - p = buffer; + p = buffer - 1; c0 = 0; c1 = 0; while (left != 0) { partial_len = MIN(left, MODX); + left -= partial_len; - for (i = 0; i < partial_len; i++) + do { - c0 = c0 + *(p++); + c0 = c0 + *(++p); c1 += c0; - } + } while (--partial_len); c0 = c0 % 255; c1 = c1 % 255; - - left -= partial_len; } - + /* The cast is important, to ensure the mod is taken as a signed value. */ x = (int)((len - offset - 1) * c0 - c1) % 255; if (x <= 0) x += 255; y = 510 - c0 - x; - if (y > 255) + if (y > 255) y -= 255; - + /* * Now we write this to the packet. * We could skip this step too, since the checksum returned would * be stored into the checksum field by the caller. + * Checksum is always big endian. */ - buffer[offset] = x; - buffer[offset + 1] = y; - - /* Take care of the endian issue */ - checksum = htons((x << 8) | (y & 0xFF)); - - return checksum; + *csum = htons((x << 8) | (y & 0xFF)); + return *csum; } diff --git a/lib/command.c b/lib/command.c index 478125f2..19fc192a 100644 --- a/lib/command.c +++ b/lib/command.c @@ -32,6 +32,7 @@ Boston, MA 02111-1307, USA. */ #include "vty.h" #include "command.h" #include "workqueue.h" +#include <stdbool.h> /* Command vector which includes some level of command lists. Normally each daemon maintains each own cmdvec. */ @@ -84,9 +85,9 @@ static struct cmd_node config_node = /* Default motd string. */ static const char *default_motd = "\r\n\ -Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ").\r\n\ -" QUAGGA_COPYRIGHT "\r\n\ -\r\n"; +This is " QUAGGA_PROGNAME " " QUAGGA_VERSION "\r\n\r\n\ +You're using the dn42 branch. Send bug reports to equinox@diac24.net\r\n\ +The 1.1.0 version number is for package management purposes only.\r\n"; static const struct facility_map { @@ -686,7 +687,8 @@ cmd_filter_by_symbol (char *command, char *symbol) /* Completion match types. */ enum match_type { - no_match, + no_match = 0, + any_match, extend_match, ipv4_prefix_match, ipv4_match, @@ -695,7 +697,7 @@ enum match_type range_match, vararg_match, partly_match, - exact_match + exact_match, }; static enum match_type @@ -1132,12 +1134,100 @@ cmd_range_match (const char *range, const char *str) return 1; } -/* Make completion match and return match type flag. */ +/* helper to retrieve the 'real' argument string from an optional argument */ +static char * +cmd_deopt (const char *str) +{ + /* we've got "[blah]". We want to strip off the []s and redo the + * match check for "blah" + */ + size_t len = strlen (str); + char *tmp; + + if (len < 3) + return NULL; + + /* tmp will hold a string of len-2 chars, so 'len' size is fine */ + tmp = XMALLOC(MTYPE_TMP, len); + + memcpy (tmp, (str + 1), len - 2); + tmp[len - 2] = '\0'; + + return tmp; +} + +static enum match_type +cmd_match (const char *str, const char *command, + enum match_type min, bool recur) +{ + + if (recur && CMD_OPTION(str)) + { + enum match_type ret; + char *tmp = cmd_deopt (str); + + /* this would be a bug in a command, however handle it gracefully + * as it we only discover it if a user tries to run it + */ + if (tmp == NULL) + return no_match; + + ret = cmd_match (tmp, command, min, false); + + XFREE (MTYPE_TMP, tmp); + + return ret; + } + else if (CMD_VARARG (str)) + return vararg_match; + else if (CMD_RANGE (str)) + { + if (cmd_range_match (str, command)) + return range_match; + } +#ifdef HAVE_IPV6 + else if (CMD_IPV6 (str)) + { + if (cmd_ipv6_match (command) >= min) + return ipv6_match; + } + else if (CMD_IPV6_PREFIX (str)) + { + if (cmd_ipv6_prefix_match (command) >= min) + return ipv6_prefix_match; + } +#endif /* HAVE_IPV6 */ + else if (CMD_IPV4 (str)) + { + if (cmd_ipv4_match (command) >= min) + return ipv4_match; + } + else if (CMD_IPV4_PREFIX (str)) + { + if (cmd_ipv4_prefix_match (command) >= min) + return ipv4_prefix_match; + } + else if (CMD_VARIABLE (str)) + return extend_match; + else if (strncmp (command, str, strlen (command)) == 0) + { + if (strcmp (command, str) == 0) + return exact_match; + else if (partly_match >= min) + return partly_match; + } + + return no_match; +} + +/* Filter vector at the specified index and by the given command string, to + * the desired matching level (thus allowing part matches), and return match + * type flag. + */ static enum match_type -cmd_filter_by_completion (char *command, vector v, unsigned int index) +cmd_filter (char *command, vector v, unsigned int index, enum match_type level) { unsigned int i; - const char *str; struct cmd_element *cmd_element; enum match_type match_type; vector descvec; @@ -1160,112 +1250,42 @@ cmd_filter_by_completion (char *command, vector v, unsigned int index) for (j = 0; j < vector_active (descvec); j++) if ((desc = vector_slot (descvec, j))) - { - str = desc->cmd; - - if (CMD_VARARG (str)) - { - if (match_type < vararg_match) - match_type = vararg_match; - matched++; - } - else if (CMD_RANGE (str)) - { - if (cmd_range_match (str, command)) - { - if (match_type < range_match) - match_type = range_match; + { + enum match_type ret; - matched++; - } - } -#ifdef HAVE_IPV6 - else if (CMD_IPV6 (str)) - { - if (cmd_ipv6_match (command)) - { - if (match_type < ipv6_match) - match_type = ipv6_match; - - matched++; - } - } - else if (CMD_IPV6_PREFIX (str)) - { - if (cmd_ipv6_prefix_match (command)) - { - if (match_type < ipv6_prefix_match) - match_type = ipv6_prefix_match; - - matched++; - } - } -#endif /* HAVE_IPV6 */ - else if (CMD_IPV4 (str)) - { - if (cmd_ipv4_match (command)) - { - if (match_type < ipv4_match) - match_type = ipv4_match; + ret = cmd_match (desc->cmd, command, level, true); + + if (ret != no_match) + matched++; - matched++; - } - } - else if (CMD_IPV4_PREFIX (str)) - { - if (cmd_ipv4_prefix_match (command)) - { - if (match_type < ipv4_prefix_match) - match_type = ipv4_prefix_match; - matched++; - } - } - else - /* Check is this point's argument optional ? */ - if (CMD_OPTION (str) || CMD_VARIABLE (str)) - { - if (match_type < extend_match) - match_type = extend_match; - matched++; - } - else if (strncmp (command, str, strlen (command)) == 0) - { - if (strcmp (command, str) == 0) - match_type = exact_match; - else - { - if (match_type < partly_match) - match_type = partly_match; - } - matched++; - } + if (match_type < ret) + match_type = ret; } if (!matched) vector_slot (v, i) = NULL; } } - return match_type; -} -/* Filter vector by command character with index. */ -static enum match_type -cmd_filter_by_string (char *command, vector v, unsigned int index) -{ - unsigned int i; - const char *str; - struct cmd_element *cmd_element; - enum match_type match_type; - vector descvec; - struct desc *desc; - - match_type = no_match; + if (match_type == no_match) + return no_match; - /* If command and cmd_element string does not match set NULL to vector */ + /* 2nd pass: We now know the 'strongest' match type for the index, so we + * go again and filter out commands whose argument (at this index) is + * 'weaker'. E.g., if we have 2 commands: + * + * foo bar <1-255> + * foo bar BLAH + * + * and the command string is 'foo bar 10', then we will get here with with + * 'range_match' being the strongest match. However, if 'BLAH' came + * earlier, it won't have been filtered out (as a CMD_VARIABLE allows "10"). + * + * If we don't do a 2nd pass and filter it out, the higher-layers will + * consider this to be ambiguous. + */ for (i = 0; i < vector_active (v); i++) if ((cmd_element = vector_slot (v, i)) != NULL) { - /* If given index is bigger than max string vector of command, - set NULL */ if (index >= vector_active (cmd_element->strvec)) vector_slot (v, i) = NULL; else @@ -1277,81 +1297,19 @@ cmd_filter_by_string (char *command, vector v, unsigned int index) for (j = 0; j < vector_active (descvec); j++) if ((desc = vector_slot (descvec, j))) - { - str = desc->cmd; + { + enum match_type ret; - if (CMD_VARARG (str)) - { - if (match_type < vararg_match) - match_type = vararg_match; - matched++; - } - else if (CMD_RANGE (str)) - { - if (cmd_range_match (str, command)) - { - if (match_type < range_match) - match_type = range_match; - matched++; - } - } -#ifdef HAVE_IPV6 - else if (CMD_IPV6 (str)) - { - if (cmd_ipv6_match (command) == exact_match) - { - if (match_type < ipv6_match) - match_type = ipv6_match; - matched++; - } - } - else if (CMD_IPV6_PREFIX (str)) - { - if (cmd_ipv6_prefix_match (command) == exact_match) - { - if (match_type < ipv6_prefix_match) - match_type = ipv6_prefix_match; - matched++; - } - } -#endif /* HAVE_IPV6 */ - else if (CMD_IPV4 (str)) - { - if (cmd_ipv4_match (command) == exact_match) - { - if (match_type < ipv4_match) - match_type = ipv4_match; - matched++; - } - } - else if (CMD_IPV4_PREFIX (str)) - { - if (cmd_ipv4_prefix_match (command) == exact_match) - { - if (match_type < ipv4_prefix_match) - match_type = ipv4_prefix_match; - matched++; - } - } - else if (CMD_OPTION (str) || CMD_VARIABLE (str)) - { - if (match_type < extend_match) - match_type = extend_match; - matched++; - } - else - { - if (strcmp (command, str) == 0) - { - match_type = exact_match; - matched++; - } - } + ret = cmd_match (desc->cmd, command, any_match, true); + + if (ret >= match_type) + matched++; } if (!matched) vector_slot (v, i) = NULL; } } + return match_type; } @@ -1361,7 +1319,6 @@ is_cmd_ambiguous (char *command, vector v, int index, enum match_type type) { unsigned int i; unsigned int j; - const char *str = NULL; struct cmd_element *cmd_element; const char *matched = NULL; vector descvec; @@ -1378,18 +1335,21 @@ is_cmd_ambiguous (char *command, vector v, int index, enum match_type type) if ((desc = vector_slot (descvec, j))) { enum match_type ret; - - str = desc->cmd; + char *str = desc->cmd; + if (CMD_OPTION(str)) + if ((str = cmd_deopt (str)) == NULL) + continue; + switch (type) { case exact_match: - if (!(CMD_OPTION (str) || CMD_VARIABLE (str)) + if (!(CMD_VARIABLE (str)) && strcmp (command, str) == 0) match++; break; case partly_match: - if (!(CMD_OPTION (str) || CMD_VARIABLE (str)) + if (!(CMD_VARIABLE (str)) && strncmp (command, str, strlen (command)) == 0) { if (matched && strcmp (matched, str) != 0) @@ -1438,13 +1398,16 @@ is_cmd_ambiguous (char *command, vector v, int index, enum match_type type) } break; case extend_match: - if (CMD_OPTION (str) || CMD_VARIABLE (str)) + if (CMD_VARIABLE (str)) match++; break; case no_match: default: break; } + + if (CMD_OPTION(desc->cmd)) + XFREE (MTYPE_TMP, str); } if (!match) vector_slot (v, i) = NULL; @@ -1614,7 +1577,7 @@ cmd_describe_command_real (vector vline, struct vty *vty, int *status) for (i = 0; i < index; i++) if ((command = vector_slot (vline, i))) { - match = cmd_filter_by_completion (command, cmd_vector, i); + match = cmd_filter (command, cmd_vector, i, any_match); if (match == vararg_match) { @@ -1663,7 +1626,7 @@ cmd_describe_command_real (vector vline, struct vty *vty, int *status) /* Make sure that cmd_vector is filtered based on current word */ command = vector_slot (vline, index); if (command) - match = cmd_filter_by_completion (command, cmd_vector, index); + match = cmd_filter (command, cmd_vector, index, any_match); /* Make description vector. */ for (i = 0; i < vector_active (cmd_vector); i++) @@ -1817,7 +1780,7 @@ cmd_complete_command_real (vector vline, struct vty *vty, int *status) int ret; /* First try completion match, if there is exactly match return 1 */ - match = cmd_filter_by_completion (command, cmd_vector, i); + match = cmd_filter (command, cmd_vector, i, any_match); /* If there is exact match then filter ambiguous match else check ambiguousness. */ @@ -2026,7 +1989,7 @@ cmd_execute_command_real (vector vline, struct vty *vty, { int ret; - match = cmd_filter_by_completion (command, cmd_vector, index); + match = cmd_filter (command, cmd_vector, index, any_match); if (match == vararg_match) break; @@ -2205,8 +2168,8 @@ cmd_execute_command_strict (vector vline, struct vty *vty, { int ret; - match = cmd_filter_by_string (vector_slot (vline, index), - cmd_vector, index); + match = cmd_filter (vector_slot (vline, index), cmd_vector, + index, exact_match); /* If command meets '.VARARG' then finish matching. */ if (match == vararg_match) @@ -2301,13 +2264,15 @@ cmd_execute_command_strict (vector vline, struct vty *vty, /* Configration make from file. */ int -config_from_file (struct vty *vty, FILE *fp) +config_from_file (struct vty *vty, FILE *fp, unsigned int *line_num) { int ret; + *line_num = 0; vector vline; while (fgets (vty->buf, VTY_BUFSIZ, fp)) { + ++(*line_num); vline = cmd_make_strvec (vty->buf); /* In case of comment line */ @@ -2408,6 +2373,7 @@ DEFUN (config_exit, case KEYCHAIN_NODE: case MASC_NODE: case RMAP_NODE: + case PIM_NODE: case VTY_NODE: vty->node = CONFIG_NODE; break; @@ -2464,6 +2430,7 @@ DEFUN (config_end, case KEYCHAIN_NODE: case KEYCHAIN_KEY_NODE: case MASC_NODE: + case PIM_NODE: case VTY_NODE: vty_config_unlock (vty); vty->node = ENABLE_NODE; @@ -3056,7 +3023,8 @@ DEFUN (config_logmsg, if ((level = level_match(argv[0])) == ZLOG_DISABLED) return CMD_ERR_NO_MATCH; - zlog(NULL, level, ((message = argv_concat(argv, argc, 1)) ? message : "")); + message = argv_concat(argv, argc, 1); + zlog(NULL, level, "%s", message ? message : ""); if (message) XFREE(MTYPE_TMP, message); return CMD_SUCCESS; @@ -3650,6 +3618,8 @@ cmd_init (int terminal) install_element (VIEW_NODE, &show_thread_cpu_cmd); install_element (ENABLE_NODE, &show_thread_cpu_cmd); install_element (RESTRICTED_NODE, &show_thread_cpu_cmd); + + install_element (ENABLE_NODE, &clear_thread_cpu_cmd); install_element (VIEW_NODE, &show_work_queues_cmd); install_element (ENABLE_NODE, &show_work_queues_cmd); } diff --git a/lib/command.h b/lib/command.h index 1275efee..a2f5eab8 100644 --- a/lib/command.h +++ b/lib/command.h @@ -1,6 +1,7 @@ /* * Zebra configuration command interface routine * Copyright (C) 1997, 98 Kunihiro Ishiguro + * Portions Copyright (c) 2008 Everton da Silva Marques <everton.marques@gmail.com> * * This file is part of GNU Zebra. * @@ -87,6 +88,7 @@ enum node_type OSPF_NODE, /* OSPF protocol mode */ OSPF6_NODE, /* OSPF protocol for IPv6 mode */ ISIS_NODE, /* ISIS protocol mode */ + PIM_NODE, /* PIM protocol mode */ MASC_NODE, /* MASC for multicast. */ IRDP_NODE, /* ICMP Router Discovery Protocol mode. */ IP_NODE, /* Static ip route node. */ @@ -341,7 +343,7 @@ extern void cmd_free_strvec (vector); extern vector cmd_describe_command (vector, struct vty *, int *status); extern char **cmd_complete_command (vector, struct vty *, int *status); extern const char *cmd_prompt (enum node_type); -extern int config_from_file (struct vty *, FILE *); +extern int config_from_file (struct vty *, FILE *, unsigned int *line_num); extern enum node_type node_parent (enum node_type); extern int cmd_execute_command (vector, struct vty *, struct cmd_element **, int); extern int cmd_execute_command_strict (vector, struct vty *, struct cmd_element **); @@ -664,7 +664,7 @@ connected_log (struct connected *connected, char *str) strncat (logbuf, inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), BUFSIZ - strlen(logbuf)); } - zlog (NULL, LOG_INFO, logbuf); + zlog (NULL, LOG_INFO, "%s", logbuf); } /* If two connected address has same prefix return 1. */ @@ -90,6 +90,7 @@ struct interface #define ZEBRA_INTERFACE_ACTIVE (1 << 0) #define ZEBRA_INTERFACE_SUB (1 << 1) #define ZEBRA_INTERFACE_LINKDETECTION (1 << 2) +#define ZEBRA_INTERFACE_UNNUMBERED (1 << 3) /* Interface flags. */ uint64_t flags; @@ -172,6 +173,12 @@ struct connected /* Label for Linux 2.2.X and upper. */ char *label; + + /* scope value, Linux only */ + unsigned scope; + + /* address preference, NetBSD >=4.0 with option IPSRCSEL, in_getifa(9) */ + int preference; }; /* Does the destination field contain a peer address? */ @@ -3,6 +3,7 @@ * * Logging of zebra * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro + * Portions Copyright (c) 2008 Everton da Silva Marques <everton.marques@gmail.com> * * This file is part of GNU Zebra. * @@ -22,6 +23,8 @@ * 02111-1307, USA. */ +#define QUAGGA_DEFINE_DESC_TABLE + #include <zebra.h> #include "log.h" @@ -50,6 +53,7 @@ const char *zlog_proto_names[] = "RIPNG", "OSPF6", "ISIS", + "PIM", "MASC", NULL, }; @@ -759,7 +763,7 @@ lookup (const struct message *mes, int key) { const struct message *pnt; - for (pnt = mes; pnt->key != 0; pnt++) + for (pnt = mes; pnt->str; pnt++) if (pnt->key == key) return pnt->str; @@ -815,29 +819,6 @@ safe_strerror(int errnum) return (s != NULL) ? s : "Unknown error"; } -struct zebra_desc_table -{ - unsigned int type; - const char *string; - char chr; -}; - -#define DESC_ENTRY(T,S,C) [(T)] = { (T), (S), (C) } -static const struct zebra_desc_table route_types[] = { - DESC_ENTRY (ZEBRA_ROUTE_SYSTEM, "system", 'X' ), - DESC_ENTRY (ZEBRA_ROUTE_KERNEL, "kernel", 'K' ), - DESC_ENTRY (ZEBRA_ROUTE_CONNECT, "connected", 'C' ), - DESC_ENTRY (ZEBRA_ROUTE_STATIC, "static", 'S' ), - DESC_ENTRY (ZEBRA_ROUTE_RIP, "rip", 'R' ), - DESC_ENTRY (ZEBRA_ROUTE_RIPNG, "ripng", 'R' ), - DESC_ENTRY (ZEBRA_ROUTE_OSPF, "ospf", 'O' ), - DESC_ENTRY (ZEBRA_ROUTE_OSPF6, "ospf6", 'O' ), - DESC_ENTRY (ZEBRA_ROUTE_ISIS, "isis", 'I' ), - DESC_ENTRY (ZEBRA_ROUTE_BGP, "bgp", 'B' ), - DESC_ENTRY (ZEBRA_ROUTE_HSLS, "hsls", 'H' ), -}; -#undef DESC_ENTRY - #define DESC_ENTRY(T) [(T)] = { (T), (#T), '\0' } static const struct zebra_desc_table command_types[] = { DESC_ENTRY (ZEBRA_INTERFACE_ADD), @@ -927,4 +908,58 @@ proto_name2num(const char *s) return route_types[i].type; return -1; } + #undef RTSIZE + +int +proto_redistnum(int afi, const char *s) +{ + if (! s) + return -1; + + if (afi == AFI_IP) + { + if (strncmp (s, "k", 1) == 0) + return ZEBRA_ROUTE_KERNEL; + else if (strncmp (s, "c", 1) == 0) + return ZEBRA_ROUTE_CONNECT; + else if (strncmp (s, "s", 1) == 0) + return ZEBRA_ROUTE_STATIC; + else if (strncmp (s, "r", 1) == 0) + return ZEBRA_ROUTE_RIP; + else if (strncmp (s, "os", 2) == 0) + return ZEBRA_ROUTE_OSPF; + else if (strncmp (s, "i", 1) == 0) + return ZEBRA_ROUTE_ISIS; + else if (strncmp (s, "bg", 2) == 0) + return ZEBRA_ROUTE_BGP; + else if (strncmp (s, "ol", 2) == 0) + return ZEBRA_ROUTE_OLSR; + else if (strncmp (s, "ba", 2) == 0) + return ZEBRA_ROUTE_BATMAN; + else if (strncmp (s, "d", 1) == 0) + return ZEBRA_ROUTE_DHCP; + } + if (afi == AFI_IP6) + { + if (strncmp (s, "k", 1) == 0) + return ZEBRA_ROUTE_KERNEL; + else if (strncmp (s, "c", 1) == 0) + return ZEBRA_ROUTE_CONNECT; + else if (strncmp (s, "s", 1) == 0) + return ZEBRA_ROUTE_STATIC; + else if (strncmp (s, "r", 1) == 0) + return ZEBRA_ROUTE_RIPNG; + else if (strncmp (s, "os", 2) == 0) + return ZEBRA_ROUTE_OSPF6; + else if (strncmp (s, "i", 1) == 0) + return ZEBRA_ROUTE_ISIS; + else if (strncmp (s, "bg", 2) == 0) + return ZEBRA_ROUTE_BGP; + else if (strncmp (s, "ol", 2) == 0) + return ZEBRA_ROUTE_OLSR; + else if (strncmp (s, "ba", 2) == 0) + return ZEBRA_ROUTE_BATMAN; + } + return -1; +} @@ -3,6 +3,7 @@ * * Zebra logging funcions. * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro + * Portions Copyright (c) 2008 Everton da Silva Marques <everton.marques@gmail.com> * * This file is part of GNU Zebra. * @@ -54,6 +55,7 @@ typedef enum ZLOG_RIPNG, ZLOG_OSPF6, ZLOG_ISIS, + ZLOG_PIM, ZLOG_MASC } zlog_proto_t; @@ -298,3 +298,76 @@ static void md5_calc(const uint8_t *b64, md5_ctxt * ctxt) ctxt->md5_stc += C; ctxt->md5_std += D; } + +/* From RFC 2104 */ +void +hmac_md5(text, text_len, key, key_len, digest) +unsigned char* text; /* pointer to data stream */ +int text_len; /* length of data stream */ +unsigned char* key; /* pointer to authentication key */ +int key_len; /* length of authentication key */ +caddr_t digest; /* caller digest to be filled in */ + +{ + MD5_CTX context; + unsigned char k_ipad[65]; /* inner padding - + * key XORd with ipad + */ + unsigned char k_opad[65]; /* outer padding - + * key XORd with opad + */ + unsigned char tk[16]; + int i; + /* if key is longer than 64 bytes reset it to key=MD5(key) */ + if (key_len > 64) { + + MD5_CTX tctx; + + MD5Init(&tctx); + MD5Update(&tctx, key, key_len); + MD5Final(tk, &tctx); + + key = tk; + key_len = 16; + } + + /* + * the HMAC_MD5 transform looks like: + * + * MD5(K XOR opad, MD5(K XOR ipad, text)) + * + * where K is an n byte key + * ipad is the byte 0x36 repeated 64 times + * opad is the byte 0x5c repeated 64 times + * and text is the data being protected + */ + + /* start out by storing key in pads */ + bzero( k_ipad, sizeof k_ipad); + bzero( k_opad, sizeof k_opad); + bcopy( key, k_ipad, key_len); + bcopy( key, k_opad, key_len); + + /* XOR key with ipad and opad values */ + for (i=0; i<64; i++) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + /* + * perform inner MD5 + */ + MD5Init(&context); /* init context for 1st + * pass */ + MD5Update(&context, k_ipad, 64); /* start with inner pad */ + MD5Update(&context, text, text_len); /* then text of datagram */ + MD5Final(digest, &context); /* finish up 1st pass */ + /* + * perform outer MD5 + */ + MD5Init(&context); /* init context for 2nd + * pass */ + MD5Update(&context, k_opad, 64); /* start with outer pad */ + MD5Update(&context, digest, 16); /* then results of 1st + * hash */ + MD5Final(digest, &context); /* finish up 2nd pass */ +} @@ -82,4 +82,7 @@ do { \ md5_result((x), (y)); \ } while (0) +/* From RFC 2104 */ +void hmac_md5(unsigned char* text, int text_len, unsigned char* key, int key_len, caddr_t digest); + #endif /* ! _LIBZEBRA_MD5_H_*/ diff --git a/lib/memory.c b/lib/memory.c index dc09d8a6..6291bf0d 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -1,6 +1,7 @@ /* * Memory management routine * Copyright (C) 1998 Kunihiro Ishiguro + * Portions Copyright (c) 2008 Everton da Silva Marques <everton.marques@gmail.com> * * This file is part of GNU Zebra. * @@ -482,6 +483,17 @@ DEFUN (show_memory_isis, return CMD_SUCCESS; } +DEFUN (show_memory_pim, + show_memory_pim_cmd, + "show memory pim", + SHOW_STR + "Memory statistics\n" + "PIM memory\n") +{ + show_memory_vty (vty, memory_list_pim); + return CMD_SUCCESS; +} + void memory_init (void) { @@ -504,6 +516,7 @@ memory_init (void) install_element (VIEW_NODE, &show_memory_ospf_cmd); install_element (VIEW_NODE, &show_memory_ospf6_cmd); install_element (VIEW_NODE, &show_memory_isis_cmd); + install_element (VIEW_NODE, &show_memory_pim_cmd); install_element (ENABLE_NODE, &show_memory_cmd); install_element (ENABLE_NODE, &show_memory_all_cmd); @@ -514,7 +527,7 @@ memory_init (void) install_element (ENABLE_NODE, &show_memory_bgp_cmd); install_element (ENABLE_NODE, &show_memory_ospf_cmd); install_element (ENABLE_NODE, &show_memory_ospf6_cmd); - install_element (ENABLE_NODE, &show_memory_isis_cmd); + install_element (ENABLE_NODE, &show_memory_pim_cmd); } /* Stats querying from users */ diff --git a/lib/memtypes.c b/lib/memtypes.c index 05d93225..fd99136c 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -1,4 +1,6 @@ /* + * Portions Copyright (c) 2008 Everton da Silva Marques <everton.marques@gmail.com> + * * Memory type definitions. This file is parsed by memtypes.awk to extract * MTYPE_ and memory_list_.. information in order to autogenerate * memtypes.h. @@ -244,6 +246,21 @@ struct memory_list memory_list_isis[] = { -1, NULL }, }; +struct memory_list memory_list_pim[] = +{ + { MTYPE_PIM_CHANNEL_OIL, "PIM SSM (S,G) channel OIL" }, + { MTYPE_PIM_INTERFACE, "PIM interface" }, + { MTYPE_PIM_IGMP_JOIN, "PIM interface IGMP static join" }, + { MTYPE_PIM_IGMP_SOCKET, "PIM interface IGMP socket" }, + { MTYPE_PIM_IGMP_GROUP, "PIM interface IGMP group" }, + { MTYPE_PIM_IGMP_GROUP_SOURCE, "PIM interface IGMP source" }, + { MTYPE_PIM_NEIGHBOR, "PIM interface neighbor" }, + { MTYPE_PIM_IFCHANNEL, "PIM interface (S,G) state" }, + { MTYPE_PIM_UPSTREAM, "PIM upstream (S,G) state" }, + { MTYPE_PIM_SSMPINGD, "PIM sspimgd socket" }, + { -1, NULL }, +}; + struct memory_list memory_list_vtysh[] = { { MTYPE_VTYSH_CONFIG, "Vtysh configuration", }, @@ -260,5 +277,6 @@ struct mlist mlists[] __attribute__ ((unused)) = { { memory_list_ospf6, "OSPF6" }, { memory_list_isis, "ISIS" }, { memory_list_bgp, "BGP" }, + { memory_list_pim, "PIM" }, { NULL, NULL}, }; diff --git a/lib/paths.c b/lib/paths.c new file mode 100644 index 00000000..5678b873 --- /dev/null +++ b/lib/paths.c @@ -0,0 +1,65 @@ +/* + * Path helper functions (for namespaces) + * Copyright (C) 2009 David Lamparter + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <zebra.h> +#include <log.h> +#include <paths.h> + +static char *namespace = ""; + +void path_set_namespace(const char *ns) +{ + size_t len; + + if (*namespace) + free(namespace); + if (!ns || !*ns) { + namespace = ""; + return; + } + + len = strlen(ns); + namespace = malloc(len + 2); + if (!namespace) { /* ugh... */ + namespace = ""; + return; + }; + namespace[0] = '/'; + memcpy(namespace + 1, ns, len + 1); +} + +const char *path_state(const char *filename) +{ + static char buf[MAXPATHLEN]; + snprintf(buf, sizeof(buf), "%s%s/%s", + PATH_STATE, namespace, filename); + return buf; +} + +const char *path_config(const char *filename) +{ + static char buf[MAXPATHLEN]; + snprintf(buf, sizeof(buf), "%s%s/%s", + PATH_CONFIG, namespace, filename); + return buf; +} + diff --git a/lib/paths.h b/lib/paths.h new file mode 100644 index 00000000..1f697855 --- /dev/null +++ b/lib/paths.h @@ -0,0 +1,34 @@ +/* + * Path helper functions (for namespaces) + * Copyright (C) 2009 David Lamparter + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_PATHS_H +#define _ZEBRA_PATHS_H + +extern void path_set_namespace(const char *ns); + +/* the following two functions return pointers to a _static_ buffer! + * if you need to keep a reference to the values, do a strdup + */ +extern const char *path_state(const char *filename); +extern const char *path_config(const char *filename); + +#endif /* _ZEBRA_PATHS_H */ diff --git a/lib/prefix.c b/lib/prefix.c index c85e6594..f5de4bde 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -180,6 +180,46 @@ prefix_cmp (const struct prefix *p1, const struct prefix *p2) return 0; } +/* + * Count the number of common bits in 2 prefixes. The prefix length is + * ignored for this function; the whole prefix is compared. If the prefix + * address families don't match, return -1; otherwise the return value is + * in range 0 ... maximum prefix length for the address family. + */ +int +prefix_common_bits (const struct prefix *p1, const struct prefix *p2) +{ + int pos, bit; + int length = 0; + u_char xor; + + /* Set both prefix's head pointer. */ + const u_char *pp1 = (const u_char *)&p1->u.prefix; + const u_char *pp2 = (const u_char *)&p2->u.prefix; + + if (p1->family == AF_INET) + length = IPV4_MAX_BYTELEN; +#ifdef HAVE_IPV6 + if (p1->family == AF_INET6) + length = IPV6_MAX_BYTELEN; +#endif + if (p1->family != p2->family || !length) + return -1; + + for (pos = 0; pos < length; pos++) + if (pp1[pos] != pp2[pos]) + break; + if (pos == length) + return pos * 8; + + xor = pp1[pos] ^ pp2[pos]; + for (bit = 0; bit < 8; bit++) + if (xor & (1 << (7 - bit))) + break; + + return pos * 8 + bit; +} + /* Return prefix family type string. */ const char * prefix_family_str (const struct prefix *p) @@ -569,6 +609,20 @@ sockunion2hostprefix (const union sockunion *su) return NULL; } +void +prefix2sockunion (const struct prefix *p, union sockunion *su) +{ + memset (su, 0, sizeof (*su)); + + su->sa.sa_family = p->family; + if (p->family == AF_INET) + su->sin.sin_addr = p->u.prefix4; +#ifdef HAVE_IPV6 + if (p->family == AF_INET6) + memcpy (&su->sin6.sin6_addr, &p->u.prefix6, sizeof (struct in6_addr)); +#endif /* HAVE_IPV6 */ +} + int prefix_blen (const struct prefix *p) { diff --git a/lib/prefix.h b/lib/prefix.h index a7598b7e..f6259dee 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -156,12 +156,14 @@ extern int prefix2str (const struct prefix *, char *, int); extern int prefix_match (const struct prefix *, const struct prefix *); extern int prefix_same (const struct prefix *, const struct prefix *); extern int prefix_cmp (const struct prefix *, const struct prefix *); +extern int prefix_common_bits (const struct prefix *, const struct prefix *); extern void prefix_copy (struct prefix *dest, const struct prefix *src); extern void apply_mask (struct prefix *); extern struct prefix *sockunion2prefix (const union sockunion *dest, const union sockunion *mask); extern struct prefix *sockunion2hostprefix (const union sockunion *); +extern void prefix2sockunion (const struct prefix *, union sockunion *); extern struct prefix_ipv4 *prefix_ipv4_new (void); extern void prefix_ipv4_free (struct prefix_ipv4 *); diff --git a/lib/route_types.awk b/lib/route_types.awk deleted file mode 100644 index eb3d382a..00000000 --- a/lib/route_types.awk +++ /dev/null @@ -1,187 +0,0 @@ -# $Id$ -# -# Scan a file of route-type definitions (see eg route_types.txt) and -# generate a corresponding header file with: -# -# - enum of Zserv route-types -# - redistribute strings for the various Quagga daemons -# -# See route_types.txt for the format. -# -# - -BEGIN { - FS="[,]"; - - # globals - exitret = 0; - tcount = 0; - - # formats for output - ## the define format - redist_def_fmt = "#define QUAGGA_REDIST_STR_%s \\\n"; - ## DEFUN/vty route-type argument - redist_str_fmt = "\"(%s)\"\n"; - redist_help_def_fmt = "#define QUAGGA_REDIST_HELP_STR_%s"; - redist_help_str_fmt = " \\\n \"%s\\n\""; - - # header - header = "/* Auto-generated from route_types.txt by " ARGV[0] ". */\n"; - header = header "/* Do not edit! */\n"; - header = header "\n#ifndef _QUAGGA_ROUTE_TYPES_H\n"; - header = header "#define _QUAGGA_ROUTE_TYPES_H\n"; - footer = "#endif /* _QUAGGA_ROUTE_TYPES_H */\n"; - printf ("%s\n", header); -} - -# Chomp comment lines -($0 ~ /^#/) { - next; -} - -# get rid of the commas, leading/trailling whitespace and -# quotes -{ - for (i = 1; i <= NF; i++) { - #print "before:" $i; - $i = gensub(/^[[:blank:]]*(.*)[,]*.*/, "\\1", "g",$i); - $i = gensub(/^["](.*)["]$/, "\\1", "g", $i); - #print "after :" $i; - } -} - -# 7 field format: -# type cname daemon C 4 6 short help -(NF >= 7) { - #print "7", $1, $0; - - if ($1 in types) { - print "error: attempt to redefine", $1; - exitret = 1; - exit exitret; - } - - typesbynum[tcount] = $1; - types[$1,"num"] = tcount++; - types[$1,"cname"] = $2; - types[$1,"daemon"] = $3; - types[$1,"C"] = $4; - types[$1,"4"] = strtonum($5); - types[$1,"6"] = strtonum($6); - types[$1,"shelp"] = $7; - - #print "num :", types[$1,"num"] - #print "cname :", types[$1,"cname"] - #print "daemon:", types[$1,"daemon"]; - #print "char :", types[$1,"C"]; -}; - -# 2 field: type "long description" -(NF == 2) { - #print "2", $1, $2; - - if (!(($1 SUBSEP "num") in types)) { - print "error: type", $1, "must be defined before help str"; - exitret = 2; - exit exitret; - } - - types[$1,"lhelp"] = $2; -} - -END { - if (exitret) - exit exitret; - - # The enums - # not yet... - #printf("enum\n{\n"); - #for (i = 0; i < tcount; i++) { - # type = typesbynum[i]; - # if (type != "" && types[type,"num"] == i) - # printf (" %s,\n", type); - #} - #printf (" ZEBRA_ROUTE_MAX,\n};\n\n"); - - # the redistribute defines - for (i = 0; i < tcount; i++) { - type = typesbynum[i]; - - # must be a type, and must cross-check against recorded type - if (type == "" || types[type,"num"] != i) - continue; - - # ignore route types that can't be redistributed - if (!(types[type,"4"] || types[type,"6"])) - continue; - - # must have a daemon name - if (!((type SUBSEP "daemon") in types)) - continue; - if (!(daemon = types[type,"daemon"])) - continue; - - # might have done this daemon already? - if (daemon in seen_daemons) - continue; - - cname = types[type,"cname"]; - all = all "|" cname; - rstr = ""; - hstr = ""; - - # add it to the others - for (j = 0; j < tcount; j++) { - # ignore self - if (i == j) - continue; - - type2 = typesbynum[j]; - - # type2 must be valid, and self-check. - if (type2 == "" || types[type2,"num"] != j) - continue; - - # ignore different route types for the same daemon - # (eg system/kernel/connected) - if (types[type2,"daemon"] == daemon) - continue; - - if ((types[type2,"4"] && types[type,"4"]) \ - || (types[type2,"6"] && types[type,"6"])) { - - if (rstr == "") - rstr = types[type2,"cname"]; - else - rstr = rstr "|" types[type2,"cname"]; - - if ((type2 SUBSEP "lhelp") in types) - hstr2 = types[type2,"lhelp"]; - else if ((type2 SUBSEP "shelp") in types) - hstr2 = types[type2,"shelp"]; - else - hstr2 = types[type2,"cname"]; - - hstr = hstr sprintf(redist_help_str_fmt, hstr2); - } - } - - # dont double-process daemons. - seen_daemons[daemon] = 1; - - printf("/* %s */\n", daemon); - printf(redist_def_fmt, toupper(daemon)); - printf(redist_str_fmt, rstr); - printf(redist_help_def_fmt, toupper(daemon)); - printf("%s", hstr); - printf("\n\n"); - } - - #printf("#define QUAGGA_REDIST_STR_ALL %s\n",all); - -# for (i = 0; i < lcount; i++) { -# if (mlists[i] != "") -# printf (mlistformat "\n", mlists[i]); -# } - printf (footer); -} diff --git a/lib/route_types.pl b/lib/route_types.pl new file mode 100755 index 00000000..e1595afc --- /dev/null +++ b/lib/route_types.pl @@ -0,0 +1,199 @@ +#!/usr/bin/perl +## +## Scan a file of route-type definitions (see eg route_types.txt) and +## generate a corresponding header file with: +## +## - enum of Zserv route-types +## - redistribute strings for the various Quagga daemons +## +## See route_types.txt for the format. +## +## +## Copyright (C) 2009 David Lamparter. +## This file is part of GNU Zebra. +## +## GNU Zebra is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## GNU Zebra is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with GNU Zebra; see the file COPYING. If not, write to the Free +## Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +## 02111-1307, USA. +## + +use strict; + +# input processing +# +my @protos; +my %protodetail; + +my %daemons; + +while (<STDIN>) { + # skip comments and empty lines + next if (/^\s*(#|$)/); + + # strip whitespace + chomp; + $_ =~ s/^\s*//; + $_ =~ s/\s*$//; + + # match help strings + if (/^(ZEBRA_ROUTE_[^\s]+)\s*,\s*"(.*)"$/) { + $protodetail{$1}->{'longhelp'} = $2; + next; + } + + $_ =~ s/\s*,\s*/,/g; + + # else: 7-field line + my @f = split(/,/, $_); + unless (@f == 7) { + die "invalid input on route_types line $.\n"; + } + + my $proto = $f[0]; + $f[3] = $1 if ($f[3] =~ /^'(.*)'$/); + $f[6] = $1 if ($f[6] =~ /^"(.*)"$/); + + $protodetail{$proto} = { + "number" => scalar @protos, + "type" => $f[0], + "cname" => $f[1], + "daemon" => $f[2], + "char" => $f[3], + "ipv4" => int($f[4]), + "ipv6" => int($f[5]), + "shorthelp" => $f[6], + }; + push @protos, $proto; + $daemons{$f[2]} = { + "ipv4" => int($f[4]), + "ipv6" => int($f[5]) + } unless ($f[2] eq "NULL"); +} + +# output +printf <<EOF, $ARGV[0]; +/* Auto-generated from route_types.txt by %s. */ +/* Do not edit! */ + +#ifndef _QUAGGA_ROUTE_TYPES_H +#define _QUAGGA_ROUTE_TYPES_H + +/* Zebra route's types. */ +EOF + +push @protos, "ZEBRA_ROUTE_MAX"; +my (@protosv4, @protosv6) = ((), ()); +for (my $c = 0; $c < @protos; $c++) { + my $p = $protos[$c]; + printf "#define %-32s %d\n", $p, $c; + push @protosv4, $p if ($protodetail{$p}->{"ipv4"}); + push @protosv6, $p if ($protodetail{$p}->{"ipv6"}); +} +pop @protos; + +sub codelist { + my (@protos) = @_; + my (@lines) = (); + my $str = " \"Codes: "; + for my $p (@protos) { + my $s = sprintf("%s - %s, ", + $protodetail{$p}->{"char"}, + $protodetail{$p}->{"shorthelp"}); + if (length($str . $s) > 70) { + $str =~ s/ $//; + push @lines, $str . "%s\" \\\n"; + $str = " \" "; + } + $str .= $s; + } + $str =~ s/ $//; + push @lines, $str . "%s\" \\\n"; + push @lines, " \" > - selected route, * - FIB route%s%s\", \\\n"; + my @nl = (); + for (my $c = 0; $c < @lines + 1; $c++) { + push @nl, "VTY_NEWLINE" + } + return join("", @lines) ." ". join(", ", @nl); +} + +print "\n"; +printf "#define SHOW_ROUTE_V4_HEADER \\\n%s\n", codelist(@protosv4); +printf "#define SHOW_ROUTE_V6_HEADER \\\n%s\n", codelist(@protosv6); +print "\n"; + +sub collect { + my ($daemon, $ipv4, $ipv6) = @_; + my (@names, @help) = ((), ()); + for my $p (@protos) { + next if ($protodetail{$p}->{"daemon"} eq $daemon && $daemon ne "zebra"); + next unless (($ipv4 && $protodetail{$p}->{"ipv4"}) + || ($ipv6 && $protodetail{$p}->{"ipv6"})); + push @names, $protodetail{$p}->{"cname"}; + push @help, " \"".$protodetail{$p}->{"longhelp"}."\\n\""; + } + return ("\"(" . join("|", @names) . ")\"", join(" \\\n", @help)); +} + +for my $daemon (sort keys %daemons) { + next unless ($daemons{$daemon}->{"ipv4"} || $daemons{$daemon}->{"ipv6"}); + printf "/* %s */\n", $daemon; + if ($daemons{$daemon}->{"ipv4"} && $daemons{$daemon}->{"ipv6"}) { + my ($names, $help) = collect($daemon, 1, 1); + printf "#define QUAGGA_REDIST_STR_%s \\\n %s\n", uc $daemon, $names; + printf "#define QUAGGA_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help; + ($names, $help) = collect($daemon, 1, 0); + printf "#define QUAGGA_IP_REDIST_STR_%s \\\n %s\n", uc $daemon, $names; + printf "#define QUAGGA_IP_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help; + ($names, $help) = collect($daemon, 0, 1); + printf "#define QUAGGA_IP6_REDIST_STR_%s \\\n %s\n", uc $daemon, $names; + printf "#define QUAGGA_IP6_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help; + } else { + my ($names, $help) = collect($daemon, + $daemons{$daemon}->{"ipv4"}, $daemons{$daemon}->{"ipv6"}); + printf "#define QUAGGA_REDIST_STR_%s \\\n %s\n", uc $daemon, $names; + printf "#define QUAGGA_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help; + } + print "\n"; +} + +print <<EOF; + +#ifdef QUAGGA_DEFINE_DESC_TABLE + +struct zebra_desc_table +{ + unsigned int type; + const char *string; + char chr; +}; + +#define DESC_ENTRY(T,S,C) [(T)] = { (T), (S), (C) } +static const struct zebra_desc_table route_types[] = { +EOF + +for (my $c = 0; $c < @protos; $c++) { + my $p = $protos[$c]; + printf " DESC_ENTRY\t(%s\t \"%s\",\t'%s' ),\n", + $p.",", $protodetail{$p}->{"cname"}, $protodetail{$p}->{"char"}; +} + +print <<EOF; +}; +#undef DESC_ENTRY + +#endif /* QUAGGA_DEFINE_DESC_TABLE */ + +#endif /* _QUAGGA_ROUTE_TYPES_H */ +EOF + diff --git a/lib/route_types.txt b/lib/route_types.txt index e99cacde..dfa34d74 100644 --- a/lib/route_types.txt +++ b/lib/route_types.txt @@ -42,13 +42,13 @@ ## type cname daemon C 4 6 short help ZEBRA_ROUTE_SYSTEM, system, NULL, 'X', 0, 0, "Reserved" -ZEBRA_ROUTE_KERNEL, kernel, zebra, 'K', 1, 1, NULL -ZEBRA_ROUTE_CONNECT, connected, zebra, 'C', 1, 1, NULL -ZEBRA_ROUTE_STATIC, static, zebra, 'S', 1, 1, NULL +ZEBRA_ROUTE_KERNEL, kernel, zebra, 'K', 1, 1, "kernel route" +ZEBRA_ROUTE_CONNECT, connected, zebra, 'C', 1, 1, "connected" +ZEBRA_ROUTE_STATIC, static, zebra, 'S', 1, 1, "static" ZEBRA_ROUTE_RIP, rip, ripd, 'R', 1, 0, "RIP" ZEBRA_ROUTE_RIPNG, ripng, ripngd, 'R', 0, 1, "RIPng" ZEBRA_ROUTE_OSPF, ospf, ospfd, 'O', 1, 0, "OSPF" -ZEBRA_ROUTE_OSPF6, ospf6, ospf6d, 'O', 0, 1, "OSPF" +ZEBRA_ROUTE_OSPF6, ospf6, ospf6d, 'O', 0, 1, "OSPFv6" ZEBRA_ROUTE_ISIS, isis, isisd, 'I', 1, 1, "IS-IS" ZEBRA_ROUTE_BGP, bgp, bgpd, 'B', 1, 1, "BGP" # HSLS and OLSR both are AFI independent (so: 1, 1), however @@ -56,8 +56,11 @@ ZEBRA_ROUTE_BGP, bgp, bgpd, 'B', 1, 1, "BGP" # This at least makes it trivial for users of these protocols # to 'switch on' redist support (direct numeric entry remaining # possible). -ZEBRA_ROUTE_HSLS, hsls, hslsd, 'H', 0, 0, "HSLS" -ZEBRA_ROUTE_OLSR, olsr, oslrd, 'o', 0, 0, "OLSR" +ZEBRA_ROUTE_HSLS, hsls, hslsd, 'h', 1, 1, "HSLS" +ZEBRA_ROUTE_OLSR, olsr, olsrd, 'o', 1, 1, "OLSR" +ZEBRA_ROUTE_BATMAN, batman, batman, 'b', 1, 1, "BATMAN" +ZEBRA_ROUTE_DHCP, dhcp, dhcpc, 'D', 1, 0, "DHCP" +ZEBRA_ROUTE_PIM, pim, pimd, 'P', 0, 0, "PIM-SSM" ## help strings ZEBRA_ROUTE_SYSTEM, "Reserved route type, for internal use only" @@ -72,3 +75,7 @@ ZEBRA_ROUTE_ISIS, "Intermediate System to Intermediate System (IS-IS)" ZEBRA_ROUTE_BGP, "Border Gateway Protocol (BGP)" ZEBRA_ROUTE_HSLS, "Hazy-Sighted Link State Protocol (HSLS)" ZEBRA_ROUTE_OLSR, "Optimised Link State Routing (OLSR)" +ZEBRA_ROUTE_BATMAN, "Better Approach To Mobile Ad-hoc Networking (BATMAN)" +ZEBRA_ROUTE_DHCP, "Dynamic Host Configuration Protocol (DHCP)" +ZEBRA_ROUTE_PIM, "Protocol Independent Multicast, Source Specific Mode (PIM-SSM)" + diff --git a/lib/sockunion.c b/lib/sockunion.c index 6a40f332..5de3bcfc 100644 --- a/lib/sockunion.c +++ b/lib/sockunion.c @@ -527,6 +527,40 @@ sockopt_ttl (int family, int sock, int ttl) return 0; } +int +sockopt_v6only (int family, int sock) +{ + int ret, on = 1; + +#ifdef HAVE_IPV6 +#ifdef IPV6_V6ONLY + if (family == AF_INET6) + { + ret = setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, + (void *) &on, sizeof (int)); + if (ret < 0) + { + zlog (NULL, LOG_WARNING, "can't set sockopt IPV6_V6ONLY " + "to socket %d", sock); + return -1; + } + return 0; + } +#endif /* IPV6_V6ONLY */ +#endif /* HAVE_IPV6 */ + return 0; +} + +int +sockopt_cork (int sock, int onoff) +{ +#ifdef TCP_CORK + return setsockopt (sock, IPPROTO_TCP, TCP_CORK, &onoff, sizeof(onoff)); +#else + return 0; +#endif +} + /* If same family and same prefix return 1. */ int sockunion_same (union sockunion *su1, union sockunion *su2) diff --git a/lib/sockunion.h b/lib/sockunion.h index 96b9a0d4..2e8ce2d0 100644 --- a/lib/sockunion.h +++ b/lib/sockunion.h @@ -99,9 +99,11 @@ extern int sockunion_accept (int sock, union sockunion *); extern int sockunion_stream_socket (union sockunion *); extern int sockopt_reuseaddr (int); extern int sockopt_reuseport (int); +extern int sockopt_v6only (int family, int sock); extern int sockunion_bind (int sock, union sockunion *, unsigned short, union sockunion *); extern int sockopt_ttl (int family, int sock, int ttl); +extern int sockopt_cork (int sock, int onoff); extern int sockunion_socket (union sockunion *su); extern const char *inet_sutop (union sockunion *su, char *str); extern enum connect_result sockunion_connect (int fd, union sockunion *su, diff --git a/lib/stream.c b/lib/stream.c index 983330ff..bff74d7b 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -711,32 +711,6 @@ stream_read (struct stream *s, int fd, size_t size) return nbytes; } -/* Read size from fd. */ -int -stream_read_unblock (struct stream *s, int fd, size_t size) -{ - int nbytes; - int val; - - STREAM_VERIFY_SANE(s); - - if (STREAM_WRITEABLE (s) < size) - { - STREAM_BOUND_WARN (s, "put"); - return 0; - } - - val = fcntl (fd, F_GETFL, 0); - fcntl (fd, F_SETFL, val|O_NONBLOCK); - nbytes = read (fd, s->data + s->endp, size); - fcntl (fd, F_SETFL, val); - - if (nbytes > 0) - s->endp += nbytes; - - return nbytes; -} - ssize_t stream_read_try(struct stream *s, int fd, size_t size) { diff --git a/lib/stream.h b/lib/stream.h index 3e4ba7b4..486a3f93 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -181,10 +181,6 @@ extern u_int32_t stream_get_ipv4 (struct stream *); Use stream_read_try instead. */ extern int stream_read (struct stream *, int, size_t); -/* Deprecated: all file descriptors should already be non-blocking. - Will be removed. Use stream_read_try instead. */ -extern int stream_read_unblock (struct stream *, int, size_t); - /* Read up to size bytes into the stream. Return code: >0: number of bytes read diff --git a/lib/thread.c b/lib/thread.c index e89af541..e083e8c7 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -20,8 +20,9 @@ */ /* #define DEBUG */ - +#include <errno.h> #include <zebra.h> +#include <sys/times.h> #include "thread.h" #include "memory.h" @@ -31,8 +32,7 @@ #include "sigevent.h" /* Recent absolute time of day */ -struct timeval recent_time; -static struct timeval last_recent_time; +static struct timeval recent_time; /* Relative time, since startup */ static struct timeval relative_time; static struct timeval relative_time_base; @@ -94,54 +94,98 @@ timeval_elapsed (struct timeval a, struct timeval b) } #ifndef HAVE_CLOCK_MONOTONIC +static unsigned long recent_clock_mark; /* Holds value of last call to times(2) */ +static unsigned long last_clock_mark; +static unsigned long clocks_per_sec, msec_scale, usec_scale; + +static unsigned long quagga_times(void) +{ +#if defined(GNU_LINUX) + unsigned long ret; + + errno = 0; + ret = times(NULL); /* Linux can handle NULL */ + /* Workaround broken syscall impl. + * A bugfix exists for the kernel, hopefully + * it will make it into 2.6.28 + */ + if (errno) + ret = (unsigned long) (-errno); + return ret; +#else + struct tms dummy; /* Only return value is used */ + + return times(&dummy); +#endif +} + static void quagga_gettimeofday_relative_adjust (void) { - struct timeval diff; - if (timeval_cmp (recent_time, last_recent_time) < 0) - { - relative_time.tv_sec++; - relative_time.tv_usec = 0; - } - else - { - diff = timeval_subtract (recent_time, last_recent_time); - relative_time.tv_sec += diff.tv_sec; - relative_time.tv_usec += diff.tv_usec; - relative_time = timeval_adjust (relative_time); - } - last_recent_time = recent_time; + unsigned long diff; + + diff = recent_clock_mark - last_clock_mark; + if (!diff) + return; + /* save mark for next calculation */ + last_clock_mark = recent_clock_mark; + + relative_time.tv_sec += diff / clocks_per_sec; /* convert to seconds */ + relative_time.tv_usec += (diff % clocks_per_sec) * usec_scale; /* convert to useconds */ + relative_time = timeval_adjust (relative_time); } #endif /* !HAVE_CLOCK_MONOTONIC */ +static int init_quagga_timers(void) +{ + int ret; + + ret = gettimeofday (&recent_time, NULL); + relative_time_base = recent_time; +#if !defined(HAVE_CLOCK_MONOTONIC) + clocks_per_sec = sysconf(_SC_CLK_TCK); + assert(clocks_per_sec != 0); + + /* Precondition: 1000 % clocks_per_sec == 0 */ + assert(1000 % clocks_per_sec == 0); + msec_scale = 1000 / clocks_per_sec; + + /* Precondition: TIMER_SECOND_MICRO % clocks_per_sec == 0 */ + assert(TIMER_SECOND_MICRO % clocks_per_sec == 0); + usec_scale = TIMER_SECOND_MICRO / clocks_per_sec; + recent_clock_mark = quagga_times(); + last_clock_mark = recent_clock_mark; +#endif + if (ret) + return ret; + timers_inited = 1; + return 0; +} + /* gettimeofday wrapper, to keep recent_time updated */ static int quagga_gettimeofday (struct timeval *tv) { int ret; - - assert (tv); - - if (!(ret = gettimeofday (&recent_time, NULL))) - { - /* init... */ - if (!timers_inited) - { - relative_time_base = last_recent_time = recent_time; - timers_inited = 1; - } - /* avoid copy if user passed recent_time pointer.. */ - if (tv != &recent_time) - *tv = recent_time; - return 0; - } - return ret; + + /* init... */ + if (!timers_inited) + ret = init_quagga_timers(); + else + ret = gettimeofday (&recent_time, NULL); + if (ret) + return ret; + + /* avoid copy if user passed recent_time pointer.. */ + if (tv != &recent_time) + *tv = recent_time; + return 0; } static int quagga_get_relative (struct timeval *tv) { - int ret; + int ret = 0; #ifdef HAVE_CLOCK_MONOTONIC { @@ -153,8 +197,12 @@ quagga_get_relative (struct timeval *tv) } } #else /* !HAVE_CLOCK_MONOTONIC */ - if (!(ret = quagga_gettimeofday (&recent_time))) - quagga_gettimeofday_relative_adjust(); + /* init... */ + if (!timers_inited) + ret = init_quagga_timers(); + + recent_clock_mark = quagga_times(); + quagga_gettimeofday_relative_adjust(); #endif /* HAVE_CLOCK_MONOTONIC */ if (tv) @@ -382,6 +430,89 @@ DEFUN(show_thread_cpu, cpu_record_print(vty, filter); return CMD_SUCCESS; } + +static void +cpu_record_hash_clear (struct hash_backet *bucket, + void *args) +{ + thread_type *filter = args; + struct cpu_thread_history *a = bucket->data; + + a = bucket->data; + if ( !(a->types & *filter) ) + return; + + hash_release (cpu_record, bucket->data); +} + +static void +cpu_record_clear (thread_type filter) +{ + thread_type *tmp = &filter; + hash_iterate (cpu_record, + (void (*) (struct hash_backet*,void*)) cpu_record_hash_clear, + tmp); +} + +DEFUN(clear_thread_cpu, + clear_thread_cpu_cmd, + "clear thread cpu [FILTER]", + "Clear stored data\n" + "Thread information\n" + "Thread CPU usage\n" + "Display filter (rwtexb)\n") +{ + int i = 0; + thread_type filter = (thread_type) -1U; + + if (argc > 0) + { + filter = 0; + while (argv[0][i] != '\0') + { + switch ( argv[0][i] ) + { + case 'r': + case 'R': + filter |= (1 << THREAD_READ); + break; + case 'w': + case 'W': + filter |= (1 << THREAD_WRITE); + break; + case 't': + case 'T': + filter |= (1 << THREAD_TIMER); + break; + case 'e': + case 'E': + filter |= (1 << THREAD_EVENT); + break; + case 'x': + case 'X': + filter |= (1 << THREAD_EXECUTE); + break; + case 'b': + case 'B': + filter |= (1 << THREAD_BACKGROUND); + break; + default: + break; + } + ++i; + } + if (filter == 0) + { + vty_out(vty, "Invalid filter \"%s\" specified," + " must contain at least one of 'RWTEXB'%s", + argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + } + + cpu_record_clear (filter); + return CMD_SUCCESS; +} /* List allocation and head/tail print out. */ static void @@ -903,6 +1034,24 @@ thread_timer_process (struct thread_list *list, struct timeval *timenow) return ready; } +/* process a list en masse, e.g. for event thread lists */ +static unsigned int +thread_process (struct thread_list *list) +{ + struct thread *thread; + unsigned int ready = 0; + + for (thread = list->head; thread; thread = thread->next) + { + thread_list_delete (list, thread); + thread->type = THREAD_READY; + thread_list_add (&thread->master->ready, thread); + ready++; + } + return ready; +} + + /* Fetch next ready thread. */ struct thread * thread_fetch (struct thread_master *m, struct thread *fetch) @@ -910,44 +1059,49 @@ thread_fetch (struct thread_master *m, struct thread *fetch) struct thread *thread; fd_set readfd; fd_set writefd; - fd_set exceptfd; - struct timeval timer_val; + struct timeval timer_val = { .tv_sec = 0, .tv_usec = 0 }; struct timeval timer_val_bg; - struct timeval *timer_wait; + struct timeval *timer_wait = &timer_val; struct timeval *timer_wait_bg; while (1) { int num = 0; - /* Signals are highest priority */ + /* Signals pre-empt everything */ quagga_sigevent_process (); - /* Normal event are the next highest priority. */ - if ((thread = thread_trim_head (&m->event)) != NULL) - return thread_run (m, thread, fetch); - - /* If there are any ready threads from previous scheduler runs, - * process top of them. + /* Drain the ready queue of already scheduled jobs, before scheduling + * more. */ if ((thread = thread_trim_head (&m->ready)) != NULL) return thread_run (m, thread, fetch); + /* To be fair to all kinds of threads, and avoid starvation, we + * need to be careful to consider all thread types for scheduling + * in each quanta. I.e. we should not return early from here on. + */ + + /* Normal event are the next highest priority. */ + thread_process (&m->event); + /* Structure copy. */ readfd = m->readfd; writefd = m->writefd; - exceptfd = m->exceptfd; /* Calculate select wait timer if nothing else to do */ - quagga_get_relative (NULL); - timer_wait = thread_timer_wait (&m->timer, &timer_val); - timer_wait_bg = thread_timer_wait (&m->background, &timer_val_bg); - - if (timer_wait_bg && - (!timer_wait || (timeval_cmp (*timer_wait, *timer_wait_bg) > 0))) - timer_wait = timer_wait_bg; + if (m->ready.count == 0) + { + quagga_get_relative (NULL); + timer_wait = thread_timer_wait (&m->timer, &timer_val); + timer_wait_bg = thread_timer_wait (&m->background, &timer_val_bg); + + if (timer_wait_bg && + (!timer_wait || (timeval_cmp (*timer_wait, *timer_wait_bg) > 0))) + timer_wait = timer_wait_bg; + } - num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait); + num = select (FD_SETSIZE, &readfd, &writefd, NULL, timer_wait); /* Signals should get quick treatment */ if (num < 0) @@ -1028,14 +1182,6 @@ thread_getrusage (RUSAGE_T *r) getrusage(RUSAGE_SELF, &(r->cpu)); #endif r->real = relative_time; - -#ifdef HAVE_CLOCK_MONOTONIC - /* quagga_get_relative() only updates recent_time if gettimeofday - * based, not when using CLOCK_MONOTONIC. As we export recent_time - * and guarantee to update it before threads are run... - */ - quagga_gettimeofday(&recent_time); -#endif /* HAVE_CLOCK_MONOTONIC */ } /* We check thread consumed time. If the system has getrusage, we'll diff --git a/lib/thread.h b/lib/thread.h index b52bc541..7de679c8 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -1,5 +1,6 @@ /* Thread management routine header. * Copyright (C) 1998 Kunihiro Ishiguro + * Portions Copyright (c) 2008 Everton da Silva Marques <everton.marques@gmail.com> * * This file is part of GNU Zebra. * @@ -53,7 +54,6 @@ struct thread_master struct thread_list background; fd_set readfd; fd_set writefd; - fd_set exceptfd; unsigned long alloc; }; @@ -137,6 +137,12 @@ enum quagga_clkid { thread = thread_add_timer (master, func, arg, time); \ } while (0) +#define THREAD_TIMER_MSEC_ON(master,thread,func,arg,time) \ + do { \ + if (! thread) \ + thread = thread_add_timer_msec (master, func, arg, time); \ + } while (0) + #define THREAD_OFF(thread) \ do { \ if (thread) \ @@ -197,6 +203,7 @@ extern int thread_should_yield (struct thread *); /* Internal libzebra exports */ extern void thread_getrusage (RUSAGE_T *); extern struct cmd_element show_thread_cpu_cmd; +extern struct cmd_element clear_thread_cpu_cmd; /* replacements for the system gettimeofday(), clock_gettime() and * time() functions, providing support for non-decrementing clock on @@ -209,10 +216,6 @@ extern time_t quagga_time (time_t *); extern unsigned long thread_consumed_time(RUSAGE_T *after, RUSAGE_T *before, unsigned long *cpu_time_elapsed); -/* Global variable containing a recent result from gettimeofday. This can - be used instead of calling gettimeofday if a recent value is sufficient. - This is guaranteed to be refreshed before a thread is called. */ -extern struct timeval recent_time; /* Similar to recent_time, but a monotonically increasing time value */ extern struct timeval recent_relative_time (void); #endif /* _ZEBRA_THREAD_H */ @@ -250,7 +250,7 @@ vty_hello (struct vty *vty) vty_out (vty, "MOTD file not found%s", VTY_NEWLINE); } else if (host.motd) - vty_out (vty, host.motd); + vty_out (vty, "%s", host.motd); } /* Put out prompt and wait input from user. */ @@ -712,6 +712,7 @@ vty_end_config (struct vty *vty) case KEYCHAIN_NODE: case KEYCHAIN_KEY_NODE: case MASC_NODE: + case PIM_NODE: case VTY_NODE: vty_config_unlock (vty); vty->node = ENABLE_NODE; @@ -1115,6 +1116,7 @@ vty_stop_input (struct vty *vty) case KEYCHAIN_NODE: case KEYCHAIN_KEY_NODE: case MASC_NODE: + case PIM_NODE: case VTY_NODE: vty_config_unlock (vty); vty->node = ENABLE_NODE; @@ -1816,6 +1818,7 @@ vty_serv_sock_addrinfo (const char *hostname, unsigned short port) if (sock < 0) continue; + sockopt_v6only (ainfo->ai_family, sock); sockopt_reuseaddr (sock); sockopt_reuseport (sock); @@ -1839,7 +1842,7 @@ vty_serv_sock_addrinfo (const char *hostname, unsigned short port) freeaddrinfo (ainfo_save); } -#endif /* HAVE_IPV6 && ! NRL */ +#else /* HAVE_IPV6 && ! NRL */ /* Make vty server socket. */ static void @@ -1905,6 +1908,7 @@ vty_serv_sock_family (const char* addr, unsigned short port, int family) /* Add vty server event. */ vty_event (VTY_SERV, accept_sock, NULL); } +#endif /* HAVE_IPV6 && ! NRL */ #ifdef VTYSH /* For sockaddr_un. */ @@ -2229,28 +2233,37 @@ vty_read_file (FILE *confp) { int ret; struct vty *vty; + unsigned int line_num = 15; vty = vty_new (); - vty->fd = 0; /* stdout */ - vty->type = VTY_TERM; + vty->fd = dup(STDERR_FILENO); /* vty_close() will close this */ + if (vty->fd < 0) + { + /* Fine, we couldn't make a new fd. vty_close doesn't close stdout. */ + vty->fd = STDOUT_FILENO; + } + vty->type = VTY_FILE; vty->node = CONFIG_NODE; /* Execute configuration file */ - ret = config_from_file (vty, confp); + ret = config_from_file (vty, confp, &line_num); + + /* Flush any previous errors before printing messages below */ + buffer_flush_all (vty->obuf, vty->fd); if ( !((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO)) ) { switch (ret) { case CMD_ERR_AMBIGUOUS: - fprintf (stderr, "Ambiguous command.\n"); + fprintf (stderr, "*** Error reading config: Ambiguous command.\n"); break; case CMD_ERR_NO_MATCH: - fprintf (stderr, "There is no such command.\n"); + fprintf (stderr, "*** Error reading config: There is no such command.\n"); break; } - fprintf (stderr, "Error occured during reading below line.\n%s\n", - vty->buf); + fprintf (stderr, "*** Error occured processing line %u, below:\n%s\n", + line_num, vty->buf); vty_close (vty); exit (1); } diff --git a/lib/workqueue.c b/lib/workqueue.c index 7c811edd..52b5f41c 100644 --- a/lib/workqueue.c +++ b/lib/workqueue.c @@ -341,7 +341,7 @@ work_queue_run (struct thread *thread) stats: -#define WQ_HYSTERIS_FACTOR 2 +#define WQ_HYSTERESIS_FACTOR 4 /* we yielded, check whether granularity should be reduced */ if (yielded && (cycles < wq->cycles.granularity)) @@ -349,17 +349,18 @@ stats: wq->cycles.granularity = ((cycles > 0) ? cycles : WORK_QUEUE_MIN_GRANULARITY); } - - if (cycles >= (wq->cycles.granularity)) + /* otherwise, should granularity increase? */ + else if (cycles >= (wq->cycles.granularity)) { if (cycles > wq->cycles.best) wq->cycles.best = cycles; - /* along with yielded check, provides hysteris for granularity */ - if (cycles > (wq->cycles.granularity * WQ_HYSTERIS_FACTOR * 2)) - wq->cycles.granularity *= WQ_HYSTERIS_FACTOR; /* quick ramp-up */ - else if (cycles > (wq->cycles.granularity * WQ_HYSTERIS_FACTOR)) - wq->cycles.granularity += WQ_HYSTERIS_FACTOR; + /* along with yielded check, provides hysteresis for granularity */ + if (cycles > (wq->cycles.granularity * WQ_HYSTERESIS_FACTOR + * WQ_HYSTERESIS_FACTOR)) + wq->cycles.granularity *= WQ_HYSTERESIS_FACTOR; /* quick ramp-up */ + else if (cycles > (wq->cycles.granularity * WQ_HYSTERESIS_FACTOR)) + wq->cycles.granularity += WQ_HYSTERESIS_FACTOR; } #undef WQ_HYSTERIS_FACTOR diff --git a/lib/zclient.c b/lib/zclient.c index d3d53227..8be9d040 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -32,6 +32,7 @@ #include "zclient.h" #include "memory.h" #include "table.h" +#include "paths.h" /* Zebra client events. */ enum event {ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT}; @@ -317,7 +318,7 @@ zclient_start (struct zclient *zclient) #ifdef HAVE_TCP_ZEBRA zclient->sock = zclient_socket (); #else - zclient->sock = zclient_socket_un (ZEBRA_SERV_PATH); + zclient->sock = zclient_socket_un (path_state (ZEBRA_SERV_NAME)); #endif /* HAVE_TCP_ZEBRA */ if (zclient->sock < 0) { @@ -404,10 +405,10 @@ zclient_connect (struct thread *t) * | IPv4 Nexthop address or Interface Index number | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * - * Alternatively, if the flags field has ZEBRA_FLAG_BLACKHOLE or - * ZEBRA_FLAG_REJECT is set then Nexthop count is set to 1, then _no_ + * Alternatively, if the route is a blackhole route (indicated to zapi + * by ZAPI_MESSAGE_BLACKHOLE), then Nexthop count is set to 1 and _no_ * nexthop information is provided, and the message describes a prefix - * to blackhole or reject route. + * to blackhole route. * * If ZAPI_MESSAGE_DISTANCE is set, the distance value is written as a 1 * byte value. @@ -423,8 +424,18 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p, { int i; int psize; + int blackhole = 0; struct stream *s; + /* blackhole routes are sent as containing a single nexthop + * of type blackhole. */ + if (CHECK_FLAG (api->message, ZAPI_MESSAGE_BLACKHOLE)) + { + blackhole = 1; + UNSET_FLAG (api->message, ZAPI_MESSAGE_BLACKHOLE); + SET_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP); + } + /* Reset stream. */ s = zclient->obuf; stream_reset (s); @@ -442,17 +453,14 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p, stream_write (s, (u_char *) & p->prefix, psize); /* Nexthop, ifindex, distance and metric information. */ - if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP)) + if (blackhole) { - if (CHECK_FLAG (api->flags, ZEBRA_FLAG_BLACKHOLE)) - { - stream_putc (s, 1); - stream_putc (s, ZEBRA_NEXTHOP_BLACKHOLE); - /* XXX assert(api->nexthop_num == 0); */ - /* XXX assert(api->ifindex_num == 0); */ - } - else - stream_putc (s, api->nexthop_num + api->ifindex_num); + stream_putc (s, 1); + stream_putc (s, ZEBRA_NEXTHOP_BLACKHOLE); + } + else if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP)) + { + stream_putc (s, api->nexthop_num + api->ifindex_num); for (i = 0; i < api->nexthop_num; i++) { diff --git a/lib/zclient.h b/lib/zclient.h index 21786ab8..7cce73f5 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -28,6 +28,9 @@ /* For input/output buffer to zebra. */ #define ZEBRA_MAX_PACKET_SIZ 4096 +/* Name of the zebra API socket */ +#define ZEBRA_SERV_NAME "zserv.api" + /* Zebra header size. */ #define ZEBRA_HEADER_SIZE 6 @@ -82,10 +85,11 @@ struct zclient }; /* Zebra API message flag. */ -#define ZAPI_MESSAGE_NEXTHOP 0x01 -#define ZAPI_MESSAGE_IFINDEX 0x02 -#define ZAPI_MESSAGE_DISTANCE 0x04 -#define ZAPI_MESSAGE_METRIC 0x08 +#define ZAPI_MESSAGE_NEXTHOP 0x01 +#define ZAPI_MESSAGE_IFINDEX 0x02 +#define ZAPI_MESSAGE_DISTANCE 0x04 +#define ZAPI_MESSAGE_METRIC 0x08 +#define ZAPI_MESSAGE_BLACKHOLE 0x10 /* only for zapi_ipv4_route */ /* Zserv protocol message header */ struct zserv_header diff --git a/lib/zebra.h b/lib/zebra.h index 2dc84514..63eb373a 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -1,5 +1,6 @@ /* Zebra common header. Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Kunihiro Ishiguro + Portions Copyright (c) 2008 Everton da Silva Marques <everton.marques@gmail.com> This file is part of GNU Zebra. @@ -421,7 +422,8 @@ struct in_pktinfo #define ZEBRA_ROUTER_ID_ADD 20 #define ZEBRA_ROUTER_ID_DELETE 21 #define ZEBRA_ROUTER_ID_UPDATE 22 -#define ZEBRA_MESSAGE_MAX 23 +#define ZEBRA_IPV4_NEXTHOP_LOOKUP_V2 23 +#define ZEBRA_MESSAGE_MAX 24 /* Marker value used in new Zserv, in the byte location corresponding * the command value in the old zserv header. To allow old and new @@ -429,19 +431,8 @@ struct in_pktinfo */ #define ZEBRA_HEADER_MARKER 255 -/* Zebra route's types. */ -#define ZEBRA_ROUTE_SYSTEM 0 -#define ZEBRA_ROUTE_KERNEL 1 -#define ZEBRA_ROUTE_CONNECT 2 -#define ZEBRA_ROUTE_STATIC 3 -#define ZEBRA_ROUTE_RIP 4 -#define ZEBRA_ROUTE_RIPNG 5 -#define ZEBRA_ROUTE_OSPF 6 -#define ZEBRA_ROUTE_OSPF6 7 -#define ZEBRA_ROUTE_ISIS 8 -#define ZEBRA_ROUTE_BGP 9 -#define ZEBRA_ROUTE_HSLS 10 -#define ZEBRA_ROUTE_MAX 11 +/* Zebra route's types are defined in route_types.h */ +#include "route_types.h" /* Note: whenever a new route-type or zserv-command is added the * corresponding {command,route}_types[] table in lib/log.c MUST be @@ -455,6 +446,10 @@ extern char zebra_route_char(unsigned int route_type); * e.g. ZEBRA_INTERFACE_ADD -> "ZEBRA_INTERFACE_ADD" */ /* Map a protocol name to its number. e.g. ZEBRA_ROUTE_BGP->9*/ extern int proto_name2num(const char *s); +/* Map redistribute X argument to protocol number. + * unlike proto_name2num, this accepts shorthands and takes + * an AFI value to restrict input */ +extern int proto_redistnum(int afi, const char *s); extern const char *zserv_command_string (unsigned int command); @@ -474,12 +469,12 @@ extern const char *zserv_command_string (unsigned int command); /* Zebra message flags */ #define ZEBRA_FLAG_INTERNAL 0x01 #define ZEBRA_FLAG_SELFROUTE 0x02 -#define ZEBRA_FLAG_BLACKHOLE 0x04 +/* 0x04 was: FLAG_BLACKHOLE */ #define ZEBRA_FLAG_IBGP 0x08 #define ZEBRA_FLAG_SELECTED 0x10 #define ZEBRA_FLAG_CHANGED 0x20 #define ZEBRA_FLAG_STATIC 0x40 -#define ZEBRA_FLAG_REJECT 0x80 +/* 0x80 was: FLAG_REJECT */ /* Zebra nexthop flags. */ #define ZEBRA_NEXTHOP_IFINDEX 1 @@ -538,43 +533,4 @@ typedef u_int8_t safi_t; typedef u_int16_t zebra_size_t; typedef u_int16_t zebra_command_t; -/* FIFO -- first in first out structure and macros. */ -struct fifo -{ - struct fifo *next; - struct fifo *prev; -}; - -#define FIFO_INIT(F) \ - do { \ - struct fifo *Xfifo = (struct fifo *)(F); \ - Xfifo->next = Xfifo->prev = Xfifo; \ - } while (0) - -#define FIFO_ADD(F,N) \ - do { \ - struct fifo *Xfifo = (struct fifo *)(F); \ - struct fifo *Xnode = (struct fifo *)(N); \ - Xnode->next = Xfifo; \ - Xnode->prev = Xfifo->prev; \ - Xfifo->prev = Xfifo->prev->next = Xnode; \ - } while (0) - -#define FIFO_DEL(N) \ - do { \ - struct fifo *Xnode = (struct fifo *)(N); \ - Xnode->prev->next = Xnode->next; \ - Xnode->next->prev = Xnode->prev; \ - } while (0) - -#define FIFO_HEAD(F) \ - ((((struct fifo *)(F))->next == (struct fifo *)(F)) \ - ? NULL : (F)->next) - -#define FIFO_EMPTY(F) \ - (((struct fifo *)(F))->next == (struct fifo *)(F)) - -#define FIFO_TOP(F) \ - (FIFO_EMPTY(F) ? NULL : ((struct fifo *)(F))->next) - #endif /* _ZEBRA_H */ |