diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/command.c | 1 | ||||
| -rw-r--r-- | lib/command.h | 1 | ||||
| -rw-r--r-- | lib/filter.c | 212 | ||||
| -rw-r--r-- | lib/gitversion.pl | 2 | ||||
| -rw-r--r-- | lib/grammar_sandbox_main.c | 5 | ||||
| -rw-r--r-- | lib/hash.c | 5 | ||||
| -rw-r--r-- | lib/hash.h | 5 | ||||
| -rw-r--r-- | lib/libfrr.c | 413 | ||||
| -rw-r--r-- | lib/libfrr.h | 5 | ||||
| -rw-r--r-- | lib/log.c | 62 | ||||
| -rw-r--r-- | lib/log.h | 3 | ||||
| -rw-r--r-- | lib/prefix.c | 704 | ||||
| -rw-r--r-- | lib/prefix.h | 16 | ||||
| -rw-r--r-- | lib/privs.c | 17 | ||||
| -rw-r--r-- | lib/privs.h | 1 | ||||
| -rw-r--r-- | lib/subdir.am | 20 | ||||
| -rw-r--r-- | lib/vty.c | 140 | ||||
| -rw-r--r-- | lib/vty.h | 7 | ||||
| -rw-r--r-- | lib/zclient.c | 114 | ||||
| -rw-r--r-- | lib/zclient.h | 15 |
20 files changed, 1123 insertions, 625 deletions
diff --git a/lib/command.c b/lib/command.c index 09ffa6ce56..077a72398d 100644 --- a/lib/command.c +++ b/lib/command.c @@ -101,6 +101,7 @@ const char *node_names[] = { "ipv4 access list", // ACCESS_NODE, "ipv4 prefix list", // PREFIX_NODE, "ipv6 access list", // ACCESS_IPV6_NODE, + "MAC access list", // ACCESS_MAC_NODE, "ipv6 prefix list", // PREFIX_IPV6_NODE, "as list", // AS_LIST_NODE, "community list", // COMMUNITY_LIST_NODE, diff --git a/lib/command.h b/lib/command.h index d0c9f0eaf9..8f12e2aabd 100644 --- a/lib/command.h +++ b/lib/command.h @@ -123,6 +123,7 @@ enum node_type { ACCESS_NODE, /* Access list node. */ PREFIX_NODE, /* Prefix list node. */ ACCESS_IPV6_NODE, /* Access list node. */ + ACCESS_MAC_NODE, /* MAC access list node*/ PREFIX_IPV6_NODE, /* Prefix list node. */ AS_LIST_NODE, /* AS list node. */ COMMUNITY_LIST_NODE, /* Community list node. */ diff --git a/lib/filter.c b/lib/filter.c index 0262234c78..cb6f743c01 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -90,6 +90,14 @@ struct access_master { void (*delete_hook)(struct access_list *); }; +/* Static structure for mac access_list's master. */ +static struct access_master access_master_mac = { + {NULL, NULL}, + {NULL, NULL}, + NULL, + NULL, +}; + /* Static structure for IPv4 access_list's master. */ static struct access_master access_master_ipv4 = { {NULL, NULL}, @@ -112,6 +120,8 @@ static struct access_master *access_master_get(afi_t afi) return &access_master_ipv4; else if (afi == AFI_IP6) return &access_master_ipv6; + else if (afi == AFI_L2VPN) + return &access_master_mac; return NULL; } @@ -173,7 +183,7 @@ static int filter_match_cisco(struct filter *mfilter, struct prefix *p) /* If filter match to the prefix then return 1. */ static int filter_match_zebra(struct filter *mfilter, struct prefix *p) { - struct filter_zebra *filter; + struct filter_zebra *filter = NULL; filter = &mfilter->u.zfilter; @@ -365,9 +375,7 @@ static struct access_list *access_list_get(afi_t afi, const char *name) enum filter_type access_list_apply(struct access_list *access, void *object) { struct filter *filter; - struct prefix *p; - - p = (struct prefix *)object; + struct prefix *p = (struct prefix *)object; if (access == NULL) return FILTER_DENY; @@ -390,6 +398,7 @@ void access_list_add_hook(void (*func)(struct access_list *access)) { access_master_ipv4.add_hook = func; access_master_ipv6.add_hook = func; + access_master_mac.add_hook = func; } /* Delete hook function. */ @@ -397,6 +406,7 @@ void access_list_delete_hook(void (*func)(struct access_list *access)) { access_master_ipv4.delete_hook = func; access_master_ipv6.delete_hook = func; + access_master_mac.delete_hook = func; } /* Add new filter to the end of specified access_list. */ @@ -515,10 +525,10 @@ static struct filter *filter_lookup_zebra(struct access_list *access, filter = &mfilter->u.zfilter; if (filter->exact == new->exact - && mfilter->type - == mnew->type &&prefix_same(&filter->prefix, - &new->prefix)) - return mfilter; + && mfilter->type == mnew->type) { + if (prefix_same(&filter->prefix, &new->prefix)) + return mfilter; + } } return NULL; } @@ -1252,6 +1262,12 @@ static int filter_set_zebra(struct vty *vty, const char *name_str, "IPv6 address prefix/prefixlen is malformed\n"); return CMD_WARNING_CONFIG_FAILED; } + } else if (afi == AFI_L2VPN) { + ret = str2prefix_eth(prefix_str, (struct prefix_eth *)&p); + if (ret <= 0) { + vty_out(vty, "MAC address is malformed\n"); + return CMD_WARNING; + } } else return CMD_WARNING_CONFIG_FAILED; @@ -1274,7 +1290,6 @@ static int filter_set_zebra(struct vty *vty, const char *name_str, access_list_filter_add(access, mfilter); } else { struct filter *delete_filter; - delete_filter = filter_lookup_zebra(access, mfilter); if (delete_filter) access_list_filter_delete(access, delete_filter); @@ -1285,6 +1300,64 @@ static int filter_set_zebra(struct vty *vty, const char *name_str, return CMD_SUCCESS; } +DEFUN (mac_access_list, + mac_access_list_cmd, + "mac access-list WORD <deny|permit> MAC", + "Add a mac access-list\n" + "Add an access list entry\n" + "MAC zebra access-list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "MAC address to match. e.g. 00:01:00:01:00:01\n") +{ + return filter_set_zebra(vty, argv[2]->arg, argv[3]->arg, AFI_L2VPN, + argv[4]->arg, 0, 1); +} + +DEFUN (no_mac_access_list, + no_mac_access_list_cmd, + "no mac access-list WORD <deny|permit> MAC", + NO_STR + "Remove a mac access-list\n" + "Remove an access list entry\n" + "MAC zebra access-list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "MAC address to match. e.g. 00:01:00:01:00:01\n") +{ + return filter_set_zebra(vty, argv[3]->arg, argv[4]->arg, AFI_L2VPN, + argv[5]->arg, 0, 0); +} + +DEFUN (mac_access_list_any, + mac_access_list_any_cmd, + "mac access-list WORD <deny|permit> any", + "Add a mac access-list\n" + "Add an access list entry\n" + "MAC zebra access-list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "MAC address to match. e.g. 00:01:00:01:00:01\n") +{ + return filter_set_zebra(vty, argv[2]->arg, argv[3]->arg, AFI_L2VPN, + "00:00:00:00:00:00", 0, 1); +} + +DEFUN (no_mac_access_list_any, + no_mac_access_list_any_cmd, + "no mac access-list WORD <deny|permit> any", + NO_STR + "Remove a mac access-list\n" + "Remove an access list entry\n" + "MAC zebra access-list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "MAC address to match. e.g. 00:01:00:01:00:01\n") +{ + return filter_set_zebra(vty, argv[3]->arg, argv[4]->arg, AFI_L2VPN, + "00:00:00:00:00:00", 0, 0); +} + DEFUN (access_list_exact, access_list_exact_cmd, "access-list WORD <deny|permit> A.B.C.D/M [exact-match]", @@ -1666,12 +1739,15 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi) filter = &mfilter->u.cfilter; if (write) { - vty_out(vty, "%s IP%s access list %s\n", + vty_out(vty, "%s %s access list %s\n", mfilter->cisco ? (filter->extended ? "Extended" : "Standard") : "Zebra", - afi == AFI_IP6 ? "v6" : "", + (afi == AFI_IP) + ? ("IP") + : ((afi == AFI_IP6) ? ("IPv6 ") + : ("MAC ")), access->name); write = 0; } @@ -1710,12 +1786,15 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi) filter = &mfilter->u.cfilter; if (write) { - vty_out(vty, "%s IP%s access list %s\n", + vty_out(vty, "%s %s access list %s\n", mfilter->cisco ? (filter->extended ? "Extended" : "Standard") : "Zebra", - afi == AFI_IP6 ? "v6" : "", + (afi == AFI_IP) + ? ("IP") + : ((afi == AFI_IP6) ? ("IPv6 ") + : ("MAC ")), access->name); write = 0; } @@ -1746,6 +1825,28 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi) return CMD_SUCCESS; } +/* show MAC access list - this only has MAC filters for now*/ +DEFUN (show_mac_access_list, + show_mac_access_list_cmd, + "show mac access-list", + SHOW_STR + "mac access lists\n" + "List mac access lists\n") +{ + return filter_show(vty, NULL, AFI_L2VPN); +} + +DEFUN (show_mac_access_list_name, + show_mac_access_list_name_cmd, + "show mac access-list WORD", + SHOW_STR + "mac access lists\n" + "List mac access lists\n" + "mac address\n") +{ + return filter_show(vty, argv[3]->arg, AFI_L2VPN); +} + DEFUN (show_ip_access_list, show_ip_access_list_cmd, "show ip access-list", @@ -1844,10 +1945,17 @@ void config_write_access_zebra(struct vty *vty, struct filter *mfilter) if (p->prefixlen == 0 && !filter->exact) vty_out(vty, " any"); - else + else if (p->family == AF_INET6 || p->family == AF_INET) vty_out(vty, " %s/%d%s", inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ), p->prefixlen, filter->exact ? " exact-match" : ""); + else if (p->family == AF_ETHERNET) { + if (p->prefixlen == 0) + vty_out(vty, " any"); + else + vty_out(vty, " %s", prefix_mac2str(&(p->u.prefix_eth), + buf, sizeof(buf))); + } vty_out(vty, "\n"); } @@ -1866,15 +1974,19 @@ static int config_write_access(struct vty *vty, afi_t afi) for (access = master->num.head; access; access = access->next) { if (access->remark) { vty_out(vty, "%saccess-list %s remark %s\n", - afi == AFI_IP ? "" : "ipv6 ", access->name, - access->remark); + (afi == AFI_IP) ? ("") + : ((afi == AFI_IP6) ? ("ipv6 ") + : ("mac ")), + access->name, access->remark); write++; } for (mfilter = access->head; mfilter; mfilter = mfilter->next) { vty_out(vty, "%saccess-list %s %s", - afi == AFI_IP ? "" : "ipv6 ", access->name, - filter_type_str(mfilter)); + (afi == AFI_IP) ? ("") + : ((afi == AFI_IP6) ? ("ipv6 ") + : ("mac ")), + access->name, filter_type_str(mfilter)); if (mfilter->cisco) config_write_access_cisco(vty, mfilter); @@ -1888,15 +2000,19 @@ static int config_write_access(struct vty *vty, afi_t afi) for (access = master->str.head; access; access = access->next) { if (access->remark) { vty_out(vty, "%saccess-list %s remark %s\n", - afi == AFI_IP ? "" : "ipv6 ", access->name, - access->remark); + (afi == AFI_IP) ? ("") + : ((afi == AFI_IP6) ? ("ipv6 ") + : ("mac ")), + access->name, access->remark); write++; } for (mfilter = access->head; mfilter; mfilter = mfilter->next) { vty_out(vty, "%saccess-list %s %s", - afi == AFI_IP ? "" : "ipv6 ", access->name, - filter_type_str(mfilter)); + (afi == AFI_IP) ? ("") + : ((afi == AFI_IP6) ? ("ipv6 ") + : ("mac ")), + access->name, filter_type_str(mfilter)); if (mfilter->cisco) config_write_access_cisco(vty, mfilter); @@ -1909,6 +2025,56 @@ static int config_write_access(struct vty *vty, afi_t afi) return write; } +static struct cmd_node access_mac_node = { + ACCESS_MAC_NODE, "", /* Access list has no interface. */ + 1}; + +static int config_write_access_mac(struct vty *vty) +{ + return config_write_access(vty, AFI_L2VPN); +} + +static void access_list_reset_mac(void) +{ + struct access_list *access; + struct access_list *next; + struct access_master *master; + + master = access_master_get(AFI_L2VPN); + if (master == NULL) + return; + + for (access = master->num.head; access; access = next) { + next = access->next; + access_list_delete(access); + } + for (access = master->str.head; access; access = next) { + next = access->next; + access_list_delete(access); + } + + assert(master->num.head == NULL); + assert(master->num.tail == NULL); + + assert(master->str.head == NULL); + assert(master->str.tail == NULL); +} + +/* Install vty related command. */ +static void access_list_init_mac(void) +{ + install_node(&access_mac_node, config_write_access_mac); + + install_element(ENABLE_NODE, &show_mac_access_list_cmd); + install_element(ENABLE_NODE, &show_mac_access_list_name_cmd); + + /* Zebra access-list */ + install_element(CONFIG_NODE, &mac_access_list_cmd); + install_element(CONFIG_NODE, &no_mac_access_list_cmd); + install_element(CONFIG_NODE, &mac_access_list_any_cmd); + install_element(CONFIG_NODE, &no_mac_access_list_any_cmd); +} + /* Access-list node. */ static struct cmd_node access_node = {ACCESS_NODE, "", /* Access list has no interface. */ @@ -2050,10 +2216,12 @@ void access_list_init() { access_list_init_ipv4(); access_list_init_ipv6(); + access_list_init_mac(); } void access_list_reset() { access_list_reset_ipv4(); access_list_reset_ipv6(); + access_list_reset_mac(); } diff --git a/lib/gitversion.pl b/lib/gitversion.pl index 8ddd9ffa55..2718046d0b 100644 --- a/lib/gitversion.pl +++ b/lib/gitversion.pl @@ -4,7 +4,7 @@ use strict; my $dir = shift; chdir $dir || die "$dir: $!\n"; -my $gitdesc = `git describe --always --dirty || echo -- \"0-gUNKNOWN\"`; +my $gitdesc = `git describe --always --first-parent --tags --dirty --match 'frr-*' || echo -- \"0-gUNKNOWN\"`; chomp $gitdesc; my $gitsuffix = ($gitdesc =~ /([0-9a-fA-F]{7}(-dirty)?)$/) ? "-g$1" : "-gUNKNOWN"; diff --git a/lib/grammar_sandbox_main.c b/lib/grammar_sandbox_main.c index c236d2c7be..89b0993d1d 100644 --- a/lib/grammar_sandbox_main.c +++ b/lib/grammar_sandbox_main.c @@ -26,10 +26,11 @@ #include "command.h" #include "memory_vty.h" -static void vty_do_exit(void) +static void vty_do_exit(int isexit) { printf("\nend.\n"); - exit(0); + if (!isexit) + exit(0); } struct thread_master *master; diff --git a/lib/hash.c b/lib/hash.c index 801871f839..66341cf2f1 100644 --- a/lib/hash.c +++ b/lib/hash.c @@ -141,18 +141,15 @@ void *hash_get(struct hash *hash, void *data, void *(*alloc_func)(void *)) unsigned int key; unsigned int index; void *newdata; - unsigned int len; struct hash_backet *backet; key = (*hash->hash_key)(data); index = key & (hash->size - 1); - len = 0; for (backet = hash->index[index]; backet != NULL; backet = backet->next) { if (backet->key == key && (*hash->hash_cmp)(backet->data, data)) return backet->data; - ++len; } if (alloc_func) { @@ -160,7 +157,7 @@ void *hash_get(struct hash *hash, void *data, void *(*alloc_func)(void *)) if (newdata == NULL) return NULL; - if (len > HASH_THRESHOLD) { + if (HASH_THRESHOLD(hash->count + 1, hash->size)) { hash_expand(hash); index = key & (hash->size - 1); } diff --git a/lib/hash.h b/lib/hash.h index 236abbbd6a..b6fe27e257 100644 --- a/lib/hash.h +++ b/lib/hash.h @@ -28,8 +28,9 @@ DECLARE_MTYPE(HASH) DECLARE_MTYPE(HASH_BACKET) /* Default hash table size. */ -#define HASH_INITIAL_SIZE 256 /* initial number of backets. */ -#define HASH_THRESHOLD 10 /* expand when backet. */ +#define HASH_INITIAL_SIZE 256 +/* Expansion threshold */ +#define HASH_THRESHOLD(used, size) ((used) > (size)) #define HASHWALK_CONTINUE 0 #define HASHWALK_ABORT -1 diff --git a/lib/libfrr.c b/lib/libfrr.c index 022296b3fb..e5573da900 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -19,9 +19,14 @@ */ #include <zebra.h> +#include <sys/un.h> + +#include <sys/types.h> +#include <sys/wait.h> #include "libfrr.h" #include "getopt.h" +#include "privs.h" #include "vty.h" #include "command.h" #include "version.h" @@ -29,6 +34,7 @@ #include "zclient.h" #include "log_int.h" #include "module.h" +#include "network.h" DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm)) @@ -40,6 +46,7 @@ char frr_protoname[256] = "NONE"; char frr_protonameinst[256] = "NONE"; char config_default[256]; +char frr_zclientpath[256]; static char pidfile_default[256]; static char vtypath_default[256]; @@ -91,12 +98,15 @@ static const struct option lo_cfg_pid_dry[] = { {"pid_file", required_argument, NULL, 'i'}, {"config_file", required_argument, NULL, 'f'}, {"dryrun", no_argument, NULL, 'C'}, + {"terminal", no_argument, NULL, 't'}, {NULL}}; static const struct optspec os_cfg_pid_dry = { - "f:i:C", + "f:i:Ct", " -f, --config_file Set configuration file name\n" " -i, --pid_file Set process identifier file name\n" - " -C, --dryrun Check configuration for validity and exit\n", + " -C, --dryrun Check configuration for validity and exit\n" + " -t, --terminal Open terminal session on stdio\n" + " -d -t Daemonize after terminal session ends\n", lo_cfg_pid_dry}; @@ -127,6 +137,116 @@ static const struct optspec os_user = {"u:g:", lo_user}; +bool frr_zclient_addr(struct sockaddr_storage *sa, socklen_t *sa_len, + const char *path) +{ + memset(sa, 0, sizeof(*sa)); + + if (!path) + path = ZEBRA_SERV_PATH; + + if (!strncmp(path, ZAPI_TCP_PATHNAME, strlen(ZAPI_TCP_PATHNAME))) { + /* note: this functionality is disabled at bottom */ + int af; + int port = ZEBRA_PORT; + char *err = NULL; + struct sockaddr_in *sin = NULL; + struct sockaddr_in6 *sin6 = NULL; + + path += strlen(ZAPI_TCP_PATHNAME); + + switch (path[0]) { + case '4': + path++; + af = AF_INET; + break; + case '6': + path++; + /* fallthrough */ + default: + af = AF_INET6; + break; + } + + switch (path[0]) { + case '\0': + break; + case ':': + path++; + port = strtoul(path, &err, 10); + if (*err || !*path) + return false; + break; + default: + return false; + } + + sa->ss_family = af; + switch (af) { + case AF_INET: + sin = (struct sockaddr_in *)sa; + sin->sin_port = htons(port); + sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK); + *sa_len = sizeof(struct sockaddr_in); +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN + sin->sin_len = *sa_len; +#endif + break; + case AF_INET6: + sin6 = (struct sockaddr_in6 *)sa; + sin6->sin6_port = htons(port); + inet_pton(AF_INET6, "::1", &sin6->sin6_addr); + *sa_len = sizeof(struct sockaddr_in6); +#ifdef SIN6_LEN + sin6->sin6_len = *sa_len; +#endif + break; + } + +#if 1 + /* force-disable this path, because tcp-zebra is a + * SECURITY ISSUE. there are no checks at all against + * untrusted users on the local system connecting on TCP + * and injecting bogus routing data into the entire routing + * domain. + * + * The functionality is only left here because it may be + * useful during development, in order to be able to get + * tcpdump or wireshark watching ZAPI as TCP. If you want + * to do that, flip the #if 1 above to #if 0. */ + memset(sa, 0, sizeof(*sa)); + return false; +#endif + } else { + /* "sun" is a #define on solaris */ + struct sockaddr_un *suna = (struct sockaddr_un *)sa; + + suna->sun_family = AF_UNIX; + strlcpy(suna->sun_path, path, sizeof(suna->sun_path)); +#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN + *sa_len = suna->sun_len = SUN_LEN(suna); +#else + *sa_len = sizeof(suna->sun_family) + strlen(suna->sun_path); +#endif /* HAVE_STRUCT_SOCKADDR_UN_SUN_LEN */ +#if 0 + /* this is left here for future reference; Linux abstract + * socket namespace support can be enabled by replacing + * above #if 0 with #ifdef GNU_LINUX. + * + * THIS IS A SECURITY ISSUE, the abstract socket namespace + * does not have user/group permission control on sockets. + * we'd need to implement SCM_CREDENTIALS support first to + * check that only proper users can connect to abstract + * sockets. (same problem as tcp-zebra, except there is a + * fix with SCM_CREDENTIALS. tcp-zebra has no such fix.) + */ + if (suna->sun_path[0] == '@') + suna->sun_path[0] = '\0'; +#endif + } + return true; +} + static struct frr_daemon_info *di = NULL; void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv) @@ -156,6 +276,8 @@ void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv) strlcpy(frr_protoname, di->logname, sizeof(frr_protoname)); strlcpy(frr_protonameinst, di->logname, sizeof(frr_protonameinst)); + + strlcpy(frr_zclientpath, ZEBRA_SERV_PATH, sizeof(frr_zclientpath)); } void frr_opt_add(const char *optstr, const struct option *longopts, @@ -230,10 +352,15 @@ static int frr_opt(int opt) return 1; di->dryrun = 1; break; + case 't': + if (di->flags & FRR_NO_CFG_PID_DRY) + return 1; + di->terminal = 1; + break; case 'z': if (di->flags & FRR_NO_ZCLIENT) return 1; - zclient_serv_path_set(optarg); + strlcpy(frr_zclientpath, optarg, sizeof(frr_zclientpath)); break; case 'A': if (di->flags & FRR_NO_TCPVTY) @@ -320,6 +447,49 @@ int frr_getopt(int argc, char *const argv[], int *longindex) return opt; } +static void frr_mkdir(const char *path, bool strip) +{ + char buf[256]; + mode_t prev; + int ret; + struct zprivs_ids_t ids; + + if (strip) { + char *slash = strrchr(path, '/'); + size_t plen; + if (!slash) + return; + plen = slash - path; + if (plen > sizeof(buf) - 1) + return; + memcpy(buf, path, plen); + buf[plen] = '\0'; + path = buf; + } + + /* o+rx (..5) is needed for the frrvty group to work properly; + * without it, users in the frrvty group can't access the vty sockets. + */ + prev = umask(0022); + ret = mkdir(path, 0755); + umask(prev); + + if (ret != 0) { + /* if EEXIST, return without touching the permissions, + * so user-set custom permissions are left in place + */ + if (errno == EEXIST) + return; + + zlog_warn("failed to mkdir \"%s\": %s", path, strerror(errno)); + return; + } + + zprivs_get_ids(&ids); + if (chown(path, ids.uid_normal, ids.gid_normal)) + zlog_warn("failed to chown \"%s\": %s", path, strerror(errno)); +} + static struct thread_master *master; struct thread_master *frr_init(void) { @@ -335,12 +505,31 @@ struct thread_master *frr_init(void) snprintf(frr_protonameinst, sizeof(frr_protonameinst), "%s[%u]", di->logname, di->instance); + zprivs_preinit(di->privs); + openzlog(di->progname, di->logname, di->instance, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON); #if defined(HAVE_CUMULUS) zlog_set_level(ZLOG_DEST_SYSLOG, zlog_default->default_lvl); #endif + if (!frr_zclient_addr(&zclient_addr, &zclient_addr_len, + frr_zclientpath)) { + fprintf(stderr, "Invalid zserv socket path: %s\n", + frr_zclientpath); + exit(1); + } + + /* don't mkdir these as root... */ + if (!(di->flags & FRR_NO_PRIVSEP)) { + if (!di->pid_file || !di->vty_path) + frr_mkdir(frr_vtydir, false); + if (di->pid_file) + frr_mkdir(di->pid_file, true); + if (di->vty_path) + frr_mkdir(di->vty_path, true); + } + frrmod_init(di->module); while (modules) { modules = (oc = modules)->next; @@ -367,6 +556,134 @@ struct thread_master *frr_init(void) return master; } +static int rcvd_signal = 0; + +static void rcv_signal(int signum) +{ + rcvd_signal = signum; + /* poll() is interrupted by the signal; handled below */ +} + +static void frr_daemon_wait(int fd) +{ + struct pollfd pfd[1]; + int ret; + pid_t exitpid; + int exitstat; + sigset_t sigs, prevsigs; + + sigemptyset(&sigs); + sigaddset(&sigs, SIGTSTP); + sigaddset(&sigs, SIGQUIT); + sigaddset(&sigs, SIGINT); + sigprocmask(SIG_BLOCK, &sigs, &prevsigs); + + struct sigaction sa = { + .sa_handler = rcv_signal, .sa_flags = SA_RESETHAND, + }; + sigemptyset(&sa.sa_mask); + sigaction(SIGTSTP, &sa, NULL); + sigaction(SIGQUIT, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + + do { + char buf[1]; + ssize_t nrecv; + + pfd[0].fd = fd; + pfd[0].events = POLLIN; + + rcvd_signal = 0; + +#if defined(HAVE_PPOLL) + ret = ppoll(pfd, 1, NULL, &prevsigs); +#elif defined(HAVE_POLLTS) + ret = pollts(pfd, 1, NULL, &prevsigs); +#else + /* racy -- only used on FreeBSD 9 */ + sigset_t tmpsigs; + sigprocmask(SIG_SETMASK, &prevsigs, &tmpsigs); + ret = poll(pfd, 1, -1); + sigprocmask(SIG_SETMASK, &tmpsigs, NULL); +#endif + if (ret < 0 && errno != EINTR && errno != EAGAIN) { + perror("poll()"); + exit(1); + } + switch (rcvd_signal) { + case SIGTSTP: + send(fd, "S", 1, 0); + do { + nrecv = recv(fd, buf, sizeof(buf), 0); + } while (nrecv == -1 + && (errno == EINTR || errno == EAGAIN)); + + raise(SIGTSTP); + sigaction(SIGTSTP, &sa, NULL); + send(fd, "R", 1, 0); + break; + case SIGINT: + send(fd, "I", 1, 0); + break; + case SIGQUIT: + send(fd, "Q", 1, 0); + break; + } + } while (ret <= 0); + + exitpid = waitpid(-1, &exitstat, WNOHANG); + if (exitpid == 0) + /* child successfully went to main loop & closed socket */ + exit(0); + + /* child failed one way or another ... */ + if (WIFEXITED(exitstat)) + fprintf(stderr, "%s failed to start, exited %d\n", di->name, + WEXITSTATUS(exitstat)); + else if (WIFSIGNALED(exitstat)) + fprintf(stderr, "%s crashed in startup, signal %d\n", di->name, + WTERMSIG(exitstat)); + else + fprintf(stderr, "%s failed to start, unknown problem\n", + di->name); + exit(1); +} + +static int daemon_ctl_sock = -1; + +static void frr_daemonize(void) +{ + int fds[2]; + pid_t pid; + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) { + perror("socketpair() for daemon control"); + exit(1); + } + set_cloexec(fds[0]); + set_cloexec(fds[1]); + + pid = fork(); + if (pid < 0) { + perror("fork()"); + exit(1); + } + if (pid == 0) { + /* child */ + close(fds[0]); + if (setsid() < 0) { + perror("setsid()"); + exit(1); + } + + daemon_ctl_sock = fds[1]; + return; + } + + close(fds[1]); + frr_daemon_wait(fds[0]); +} + void frr_config_fork(void) { hook_call(frr_late_init, master); @@ -385,11 +702,8 @@ void frr_config_fork(void) if (di->dryrun) exit(0); - /* Daemonize. */ - if (di->daemon_mode && daemon(0, 0) < 0) { - zlog_err("Zebra daemon failed: %s", strerror(errno)); - exit(1); - } + if (di->daemon_mode || di->terminal) + frr_daemonize(); if (!di->pid_file) di->pid_file = pidfile_default; @@ -417,6 +731,67 @@ void frr_vty_serv(void) vty_serv_sock(di->vty_addr, di->vty_port, di->vty_path); } +static void frr_terminal_close(int isexit) +{ + if (daemon_ctl_sock != -1) { + close(daemon_ctl_sock); + daemon_ctl_sock = -1; + } + + if (!di->daemon_mode || isexit) { + printf("\n%s exiting\n", di->name); + if (!isexit) + raise(SIGINT); + return; + } else { + printf("\n%s daemonizing\n", di->name); + fflush(stdout); + } + + int nullfd = open("/dev/null", O_RDONLY | O_NOCTTY); + dup2(nullfd, 0); + dup2(nullfd, 1); + dup2(nullfd, 2); + close(nullfd); +} + +static struct thread *daemon_ctl_thread = NULL; + +static int frr_daemon_ctl(struct thread *t) +{ + char buf[1]; + ssize_t nr; + + nr = recv(daemon_ctl_sock, buf, sizeof(buf), 0); + if (nr < 0 && (errno == EINTR || errno == EAGAIN)) + goto out; + if (nr <= 0) + return 0; + + switch (buf[0]) { + case 'S': /* SIGTSTP */ + vty_stdio_suspend(); + send(daemon_ctl_sock, "s", 1, 0); + break; + case 'R': /* SIGTCNT [implicit] */ + vty_stdio_resume(); + break; + case 'I': /* SIGINT */ + di->daemon_mode = false; + raise(SIGINT); + break; + case 'Q': /* SIGQUIT */ + di->daemon_mode = true; + vty_stdio_close(); + break; + } + +out: + thread_add_read(master, frr_daemon_ctl, NULL, daemon_ctl_sock, + &daemon_ctl_thread); + return 0; +} + void frr_run(struct thread_master *master) { char instanceinfo[64] = ""; @@ -430,6 +805,28 @@ void frr_run(struct thread_master *master) zlog_notice("%s %s starting: %svty@%d%s", di->name, FRR_VERSION, instanceinfo, di->vty_port, di->startinfo); + if (di->terminal) { + vty_stdio(frr_terminal_close); + if (daemon_ctl_sock != -1) { + set_nonblocking(daemon_ctl_sock); + thread_add_read(master, frr_daemon_ctl, NULL, + daemon_ctl_sock, &daemon_ctl_thread); + } + } else { + int nullfd = open("/dev/null", O_RDONLY | O_NOCTTY); + dup2(nullfd, 0); + dup2(nullfd, 1); + dup2(nullfd, 2); + close(nullfd); + + if (daemon_ctl_sock != -1) + close(daemon_ctl_sock); + daemon_ctl_sock = -1; + } + + /* end fixed stderr startup logging */ + zlog_startup_stderr = false; + struct thread thread; while (thread_fetch(master, &thread)) thread_call(&thread); diff --git a/lib/libfrr.h b/lib/libfrr.h index 0f6ed0cb00..1710fc9a84 100644 --- a/lib/libfrr.h +++ b/lib/libfrr.h @@ -49,6 +49,7 @@ struct frr_daemon_info { char *vty_sock_path; bool dryrun; bool daemon_mode; + bool terminal; const char *config_file; const char *pid_file; const char *vty_path; @@ -100,7 +101,11 @@ extern void frr_vty_serv(void); /* note: contains call to frr_vty_serv() */ extern void frr_run(struct thread_master *master); +extern bool frr_zclient_addr(struct sockaddr_storage *sa, socklen_t *sa_len, + const char *path); + extern char config_default[256]; +extern char frr_zclientpath[256]; extern const char frr_sysconfdir[]; extern const char frr_vtydir[]; extern const char frr_moduledir[]; @@ -41,6 +41,7 @@ DEFINE_MTYPE_STATIC(LIB, ZLOG, "Logging") static int logfile_fd = -1; /* Used in signal handler. */ struct zlog *zlog_default = NULL; +bool zlog_startup_stderr = true; const char *zlog_priority[] = { "emergencies", "alerts", "critical", "errors", "warnings", @@ -172,6 +173,25 @@ static void time_print(FILE *fp, struct timestamp_control *ctl) } +static void vzlog_file(struct zlog *zl, struct timestamp_control *tsctl, + const char *proto_str, int record_priority, + int priority, FILE *fp, const char *format, + va_list args) +{ + va_list ac; + + time_print(fp, tsctl); + if (record_priority) + fprintf(fp, "%s: ", zlog_priority[priority]); + + fprintf(fp, "%s", proto_str); + va_copy(ac, args); + vfprintf(fp, format, ac); + va_end(ac); + fprintf(fp, "\n"); + fflush(fp); +} + /* va_list version of zlog. */ void vzlog(int priority, const char *format, va_list args) { @@ -210,32 +230,21 @@ void vzlog(int priority, const char *format, va_list args) sprintf(proto_str, "%s: ", zl->protoname); /* File output. */ - if ((priority <= zl->maxlvl[ZLOG_DEST_FILE]) && zl->fp) { - va_list ac; - time_print(zl->fp, &tsctl); - if (zl->record_priority) - fprintf(zl->fp, "%s: ", zlog_priority[priority]); - fprintf(zl->fp, "%s", proto_str); - va_copy(ac, args); - vfprintf(zl->fp, format, ac); - va_end(ac); - fprintf(zl->fp, "\n"); - fflush(zl->fp); - } - - /* stdout output. */ - if (priority <= zl->maxlvl[ZLOG_DEST_STDOUT]) { - va_list ac; - time_print(stdout, &tsctl); - if (zl->record_priority) - fprintf(stdout, "%s: ", zlog_priority[priority]); - fprintf(stdout, "%s", proto_str); - va_copy(ac, args); - vfprintf(stdout, format, ac); - va_end(ac); - fprintf(stdout, "\n"); - fflush(stdout); - } + if ((priority <= zl->maxlvl[ZLOG_DEST_FILE]) && zl->fp) + vzlog_file(zl, &tsctl, proto_str, zl->record_priority, + priority, zl->fp, format, args); + + /* fixed-config logging to stderr while we're stating up & haven't + * daemonized / reached mainloop yet + * + * note the "else" on stdout output -- we don't want to print the same + * message to both stderr and stdout. */ + if (zlog_startup_stderr && priority <= LOG_WARNING) + vzlog_file(zl, &tsctl, proto_str, 1, + priority, stderr, format, args); + else if (priority <= zl->maxlvl[ZLOG_DEST_STDOUT]) + vzlog_file(zl, &tsctl, proto_str, zl->record_priority, + priority, stdout, format, args); /* Terminal monitor. */ if (priority <= zl->maxlvl[ZLOG_DEST_MONITOR]) @@ -908,6 +917,7 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_GET_LABEL_CHUNK), DESC_ENTRY(ZEBRA_RELEASE_LABEL_CHUNK), DESC_ENTRY(ZEBRA_ADVERTISE_ALL_VNI), + DESC_ENTRY(ZEBRA_ADVERTISE_DEFAULT_GW), DESC_ENTRY(ZEBRA_VNI_ADD), DESC_ENTRY(ZEBRA_VNI_DEL), DESC_ENTRY(ZEBRA_REMOTE_VTEP_ADD), @@ -24,6 +24,7 @@ #include <syslog.h> #include <stdint.h> +#include <stdbool.h> #include <stdio.h> /* Here is some guidance on logging levels to use: @@ -54,6 +55,8 @@ typedef enum { } zlog_dest_t; #define ZLOG_NUM_DESTS (ZLOG_DEST_FILE+1) +extern bool zlog_startup_stderr; + /* Message structure. */ struct message { int key; diff --git a/lib/prefix.c b/lib/prefix.c index 33b6ff1987..de521b2e3e 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -37,390 +37,262 @@ static const u_char maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0, 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}}}}; + /* /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 @@ -429,6 +301,18 @@ static const struct in6_addr maskbytes6[] = { #define MASKBIT(offset) ((0xff << (PNBBY - (offset))) & 0xff) +static int is_zero_mac(const struct ethaddr *mac) +{ + int i = 0; + + for (i = 0; i < ETH_ALEN; i++) { + if (mac->octet[i]) + return 0; + } + + return 1; +} + unsigned int prefix_bit(const u_char *prefix, const u_char prefixlen) { unsigned int offset = prefixlen / 8; @@ -450,6 +334,8 @@ int str2family(const char *string) return AF_INET6; else if (!strcmp("ethernet", string)) return AF_ETHERNET; + else if (!strcmp("evpn", string)) + return AF_EVPN; return -1; } @@ -462,6 +348,7 @@ int afi2family(afi_t afi) return AF_INET6; else if (afi == AFI_L2VPN) return AF_ETHERNET; + /* NOTE: EVPN code should NOT use this interface. */ return 0; } @@ -471,7 +358,7 @@ afi_t family2afi(int family) return AFI_IP; else if (family == AF_INET6) return AFI_IP6; - else if (family == AF_ETHERNET) + else if (family == AF_ETHERNET || family == AF_EVPN) return AFI_L2VPN; return 0; } @@ -577,6 +464,9 @@ void prefix_copy(struct prefix *dest, const struct prefix *src) else if (src->family == AF_INET6) dest->u.prefix6 = src->u.prefix6; else if (src->family == AF_ETHERNET) { + memcpy(&dest->u.prefix_eth, &src->u.prefix_eth, + sizeof(struct ethaddr)); + } else if (src->family == AF_EVPN) { memcpy(&dest->u.prefix_evpn, &src->u.prefix_evpn, sizeof(struct evpn_addr)); } else if (src->family == AF_UNSPEC) { @@ -615,6 +505,10 @@ int prefix_same(const struct prefix *p1, const struct prefix *p2) &p2->u.prefix6.s6_addr)) return 1; if (p1->family == AF_ETHERNET) + if (!memcmp(&p1->u.prefix_eth, &p2->u.prefix_eth, + sizeof(struct ethaddr))) + return 1; + if (p1->family == AF_EVPN) if (!memcmp(&p1->u.prefix_evpn, &p2->u.prefix_evpn, sizeof(struct evpn_addr))) return 1; @@ -679,6 +573,8 @@ int prefix_common_bits(const struct prefix *p1, const struct prefix *p2) if (p1->family == AF_INET6) length = IPV6_MAX_BYTELEN; if (p1->family == AF_ETHERNET) + length = ETH_ALEN; + if (p1->family == AF_EVPN) length = 8 * sizeof(struct evpn_addr); if (p1->family != p2->family || !length) @@ -707,6 +603,8 @@ const char *prefix_family_str(const struct prefix *p) return "inet6"; if (p->family == AF_ETHERNET) return "ether"; + if (p->family == AF_EVPN) + return "evpn"; return "unspec"; } @@ -783,6 +681,13 @@ int str2prefix_eth(const char *str, struct prefix_eth *p) const char *str_addr = str; unsigned int a[6]; int i; + bool slash = false; + + if (!strcmp(str, "any")) { + memset(p, 0, sizeof(*p)); + p->family = AF_ETHERNET; + return 1; + } /* Find slash inside string. */ pnt = strchr(str, '/'); @@ -800,6 +705,7 @@ int str2prefix_eth(const char *str, struct prefix_eth *p) *(cp + (pnt - str)) = '\0'; str_addr = cp; + slash = true; } /* Convert string to prefix. */ @@ -814,6 +720,15 @@ int str2prefix_eth(const char *str, struct prefix_eth *p) } p->prefixlen = plen; p->family = AF_ETHERNET; + + /* + * special case to allow old configurations to work + * Since all zero's is implicitly meant to allow + * a comparison to zero, let's assume + */ + if (!slash && is_zero_mac(&(p->eth_addr))) + p->prefixlen = 0; + ret = 1; done: @@ -1063,6 +978,7 @@ int prefix_blen(const struct prefix *p) break; case AF_ETHERNET: return ETH_ALEN; + break; } return 0; } @@ -1090,7 +1006,7 @@ int str2prefix(const char *str, struct prefix *p) return 0; } -static const char *prefixeth2str(const struct prefix *p, char *str, int size) +static const char *prefixevpn2str(const struct prefix *p, char *str, int size) { u_char family; char buf[PREFIX2STR_BUFFER]; @@ -1134,12 +1050,8 @@ static const char *prefixeth2str(const struct prefix *p, char *str, int size) PREFIX2STR_BUFFER), p->prefixlen); } else { - sprintf(str, "UNK AF_ETHER prefix"); - snprintf(str, size, "%02x:%02x:%02x:%02x:%02x:%02x/%d", - p->u.prefix_eth.octet[0], p->u.prefix_eth.octet[1], - p->u.prefix_eth.octet[2], p->u.prefix_eth.octet[3], - p->u.prefix_eth.octet[4], p->u.prefix_eth.octet[5], - p->prefixlen); + sprintf(str, "Unsupported EVPN route type %d", + p->u.prefix_evpn.route_type); } return str; @@ -1159,7 +1071,13 @@ const char *prefix2str(union prefixconstptr pu, char *str, int size) break; case AF_ETHERNET: - prefixeth2str(p, str, size); + snprintf(str, size, "%s/%d", + prefix_mac2str(&p->u.prefix_eth, buf, sizeof(buf)), + p->prefixlen); + break; + + case AF_EVPN: + prefixevpn2str(p, str, size); break; default: diff --git a/lib/prefix.h b/lib/prefix.h index 5f2b57ccce..f0644ea88e 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -116,7 +116,18 @@ struct evpn_addr { #endif #endif -/* IPv4 and IPv6 unified prefix structure. */ +/* The 'family' in the prefix structure is internal to FRR and need not + * map to standard OS AF_ definitions except where needed for interacting + * with the kernel. However, AF_ definitions are currently in use and + * prevalent across the code. Define a new FRR-specific AF for EVPN to + * distinguish between 'ethernet' (MAC-only) and 'evpn' prefixes and + * ensure it does not conflict with any OS AF_ definition. + */ +#if !defined(AF_EVPN) +#define AF_EVPN (AF_MAX + 1) +#endif + +/* FRR generic prefix structure. */ struct prefix { u_char family; u_char prefixlen; @@ -131,7 +142,7 @@ struct prefix { struct ethaddr prefix_eth; /* AF_ETHERNET */ u_char val[8]; uintptr_t ptr; - struct evpn_addr prefix_evpn; + struct evpn_addr prefix_evpn; /* AF_EVPN */ } u __attribute__((aligned(8))); }; @@ -356,6 +367,7 @@ static inline int ipv6_martian(struct in6_addr *addr) } extern int all_digit(const char *); +extern int macstr2prefix_evpn(const char *str, struct prefix_evpn *p); /* NOTE: This routine expects the address argument in network byte order. */ static inline int ipv4_martian(struct in_addr *addr) diff --git a/lib/privs.c b/lib/privs.c index c971596117..eda3fb02d4 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -696,13 +696,10 @@ static int getgrouplist(const char *user, gid_t group, gid_t *groups, } #endif /* HAVE_GETGROUPLIST */ -void zprivs_init(struct zebra_privs_t *zprivs) +void zprivs_preinit(struct zebra_privs_t *zprivs) { struct passwd *pwentry = NULL; struct group *grentry = NULL; - gid_t groups[NGROUPS_MAX]; - int i, ngroups = 0; - int found = 0; if (!zprivs) { fprintf(stderr, "zprivs_init: called with NULL arg!\n"); @@ -751,6 +748,18 @@ void zprivs_init(struct zebra_privs_t *zprivs) zprivs_state.zgid = grentry->gr_gid; } +} + +void zprivs_init(struct zebra_privs_t *zprivs) +{ + gid_t groups[NGROUPS_MAX]; + int i, ngroups = 0; + int found = 0; + + /* NULL privs */ + if (!(zprivs->user || zprivs->group || zprivs->cap_num_p + || zprivs->cap_num_i)) + return; if (zprivs->user) { ngroups = sizeof(groups); diff --git a/lib/privs.h b/lib/privs.h index c18fe78add..7fe59328b2 100644 --- a/lib/privs.h +++ b/lib/privs.h @@ -74,6 +74,7 @@ struct zprivs_ids_t { }; /* initialise zebra privileges */ +extern void zprivs_preinit(struct zebra_privs_t *zprivs); extern void zprivs_init(struct zebra_privs_t *zprivs); /* drop all and terminate privileges */ extern void zprivs_terminate(struct zebra_privs_t *); diff --git a/lib/subdir.am b/lib/subdir.am index 15ce8ec199..6a62cbb678 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -125,7 +125,6 @@ pkginclude_HEADERS += \ lib/ptm_lib.h \ lib/pw.h \ lib/qobj.h \ - lib/route_types.h \ lib/routemap.h \ lib/sbuf.h \ lib/sha256.h \ @@ -142,7 +141,6 @@ pkginclude_HEADERS += \ lib/termtable.h \ lib/thread.h \ lib/vector.h \ - lib/version.h \ lib/vlan.h \ lib/vrf.h \ lib/vrf_int.h \ @@ -155,6 +153,11 @@ pkginclude_HEADERS += \ lib/zebra.h \ # end +nodist_pkginclude_HEADERS += \ + lib/route_types.h \ + lib/version.h \ + # end + noinst_HEADERS += \ lib/clippy.h \ lib/log_int.h \ @@ -181,16 +184,22 @@ lib_libfrrsnmp_la_SOURCES = \ # CLI utilities # noinst_PROGRAMS += \ - lib/clippy \ lib/grammar_sandbox \ # end +if BUILD_CLIPPY +noinst_PROGRAMS += lib/clippy +else +$(HOSTTOOLS)lib/clippy: + @$(MAKE) -C $(top_builddir)/$(HOSTTOOLS) lib/route_types.h lib/clippy +endif + lib_grammar_sandbox_SOURCES = \ lib/grammar_sandbox_main.c lib_grammar_sandbox_LDADD = \ lib/libfrr.la -lib_clippy_CPPFLAGS = -D_GNU_SOURCE -I$(top_srcdir)/lib +lib_clippy_CPPFLAGS = $(AM_CPPFLAGS) -D_GNU_SOURCE lib_clippy_CFLAGS = $(PYTHON_CFLAGS) lib_clippy_LDADD = $(PYTHON_LIBS) lib_clippy_SOURCES = \ @@ -211,6 +220,7 @@ lib_clippy_SOURCES = \ # EXTRA_DIST += \ lib/command_lex.h \ + lib/command_parse.h \ lib/gitversion.pl \ lib/queue.h \ lib/route_types.pl \ @@ -218,8 +228,6 @@ EXTRA_DIST += \ # end BUILT_SOURCES += \ - lib/command_lex.h \ - lib/command_parse.h \ lib/gitversion.h \ lib/route_types.h \ # end @@ -1663,24 +1663,82 @@ static struct vty *vty_create(int vty_sock, union sockunion *su) /* create vty for stdio */ static struct termios stdio_orig_termios; static struct vty *stdio_vty = NULL; -static void (*stdio_vty_atclose)(void); +static bool stdio_termios = false; +static void (*stdio_vty_atclose)(int isexit); -static void vty_stdio_reset(void) +static void vty_stdio_reset(int isexit) { if (stdio_vty) { - tcsetattr(0, TCSANOW, &stdio_orig_termios); + if (stdio_termios) + tcsetattr(0, TCSANOW, &stdio_orig_termios); + stdio_termios = false; + stdio_vty = NULL; if (stdio_vty_atclose) - stdio_vty_atclose(); + stdio_vty_atclose(isexit); stdio_vty_atclose = NULL; } } -struct vty *vty_stdio(void (*atclose)()) +static void vty_stdio_atexit(void) +{ + vty_stdio_reset(1); +} + +void vty_stdio_suspend(void) +{ + if (!stdio_vty) + return; + + if (stdio_vty->t_write) + thread_cancel(stdio_vty->t_write); + if (stdio_vty->t_read) + thread_cancel(stdio_vty->t_read); + if (stdio_vty->t_timeout) + thread_cancel(stdio_vty->t_timeout); + + if (stdio_termios) + tcsetattr(0, TCSANOW, &stdio_orig_termios); + stdio_termios = false; +} + +void vty_stdio_resume(void) +{ + if (!stdio_vty) + return; + + if (!tcgetattr(0, &stdio_orig_termios)) { + struct termios termios; + + termios = stdio_orig_termios; + termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR + | IGNCR | ICRNL | IXON); + termios.c_oflag &= ~OPOST; + termios.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN); + termios.c_cflag &= ~(CSIZE | PARENB); + termios.c_cflag |= CS8; + tcsetattr(0, TCSANOW, &termios); + stdio_termios = true; + } + + vty_prompt(stdio_vty); + + /* Add read/write thread. */ + vty_event(VTY_WRITE, 1, stdio_vty); + vty_event(VTY_READ, 0, stdio_vty); +} + +void vty_stdio_close(void) +{ + if (!stdio_vty) + return; + vty_close(stdio_vty); +} + +struct vty *vty_stdio(void (*atclose)(int isexit)) { struct vty *vty; - struct termios termios; /* refuse creating two vtys on stdio */ if (stdio_vty) @@ -1698,23 +1756,7 @@ struct vty *vty_stdio(void (*atclose)()) vty->v_timeout = 0; strcpy(vty->address, "console"); - if (!tcgetattr(0, &stdio_orig_termios)) { - termios = stdio_orig_termios; - termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR - | IGNCR | ICRNL | IXON); - termios.c_oflag &= ~OPOST; - termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); - termios.c_cflag &= ~(CSIZE | PARENB); - termios.c_cflag |= CS8; - tcsetattr(0, TCSANOW, &termios); - } - - vty_prompt(vty); - - /* Add read/write thread. */ - vty_event(VTY_WRITE, 1, vty); - vty_event(VTY_READ, 0, vty); - + vty_stdio_resume(); return vty; } @@ -1813,7 +1855,7 @@ static void vty_serv_sock_addrinfo(const char *hostname, unsigned short port) ret = getaddrinfo(hostname, port_str, &req, &ainfo); if (ret != 0) { - fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(ret)); + zlog_err("getaddrinfo failed: %s", gai_strerror(ret)); exit(1); } @@ -2163,7 +2205,7 @@ void vty_close(struct vty *vty) XFREE(MTYPE_VTY, vty); if (was_stdio) - vty_stdio_reset(); + vty_stdio_reset(0); } /* When time out occur output message then close connection. */ @@ -2213,23 +2255,22 @@ static void vty_read_file(FILE *confp) if (!((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO))) { const char *message = NULL; + char *nl; + switch (ret) { case CMD_ERR_AMBIGUOUS: - message = - "*** Error reading config: Ambiguous command."; + message = "Ambiguous command"; break; case CMD_ERR_NO_MATCH: - message = - "*** Error reading config: There is no such command."; + message = "No such command"; break; } - fprintf(stderr, "%s\n", message); - zlog_err("%s", message); - fprintf(stderr, - "*** Error occurred processing line %u, below:\n%s\n", - line_num, vty->error_buf); - zlog_err("*** Error occurred processing line %u, below:\n%s", - line_num, vty->error_buf); + + nl = strchr(vty->error_buf, '\n'); + if (nl) + *nl = '\0'; + zlog_err("ERROR: %s on config line %u: %s", + message, line_num, vty->error_buf); } vty_close(vty); @@ -2301,8 +2342,7 @@ void vty_read_config(const char *config_file, char *config_default_dir) if (config_file != NULL) { if (!IS_DIRECTORY_SEP(config_file[0])) { if (getcwd(cwd, MAXPATHLEN) == NULL) { - fprintf(stderr, - "Failure to determine Current Working Directory %d!\n", + zlog_err("Failure to determine Current Working Directory %d!", errno); exit(1); } @@ -2316,17 +2356,14 @@ void vty_read_config(const char *config_file, char *config_default_dir) confp = fopen(fullpath, "r"); if (confp == NULL) { - fprintf(stderr, - "%s: failed to open configuration file %s: %s\n", + zlog_err("%s: failed to open configuration file %s: %s", __func__, fullpath, safe_strerror(errno)); confp = vty_use_backup_config(fullpath); if (confp) - fprintf(stderr, - "WARNING: using backup configuration file!\n"); + zlog_warn("WARNING: using backup configuration file!"); else { - fprintf(stderr, - "can't open configuration file [%s]\n", + zlog_err("can't open configuration file [%s]", config_file); exit(1); } @@ -2361,19 +2398,16 @@ void vty_read_config(const char *config_file, char *config_default_dir) #endif /* VTYSH */ confp = fopen(config_default_dir, "r"); if (confp == NULL) { - fprintf(stderr, - "%s: failed to open configuration file %s: %s\n", + zlog_err("%s: failed to open configuration file %s: %s", __func__, config_default_dir, safe_strerror(errno)); confp = vty_use_backup_config(config_default_dir); if (confp) { - fprintf(stderr, - "WARNING: using backup configuration file!\n"); + zlog_warn("WARNING: using backup configuration file!"); fullpath = config_default_dir; } else { - fprintf(stderr, - "can't open configuration file [%s]\n", + zlog_err("can't open configuration file [%s]", config_default_dir); goto tmp_free_and_out; } @@ -2883,12 +2917,12 @@ static void vty_save_cwd(void) * Hence not worrying about it too much. */ if (!chdir(SYSCONFDIR)) { - fprintf(stderr, "Failure to chdir to %s, errno: %d\n", + zlog_err("Failure to chdir to %s, errno: %d", SYSCONFDIR, errno); exit(-1); } if (getcwd(cwd, MAXPATHLEN) == NULL) { - fprintf(stderr, "Failure to getcwd, errno: %d\n", + zlog_err("Failure to getcwd, errno: %d", errno); exit(-1); } @@ -2928,7 +2962,7 @@ void vty_init(struct thread_master *master_thread) vty_master = master_thread; - atexit(vty_stdio_reset); + atexit(vty_stdio_atexit); /* Initilize server thread vector. */ Vvty_serv_thread = vector_init(VECTOR_MIN_SIZE); @@ -257,7 +257,7 @@ extern void vty_init_vtysh(void); extern void vty_terminate(void); extern void vty_reset(void); extern struct vty *vty_new(void); -extern struct vty *vty_stdio(void (*atclose)(void)); +extern struct vty *vty_stdio(void (*atclose)(int isexit)); extern int vty_out(struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3); extern void vty_read_config(const char *, char *); extern void vty_time_print(struct vty *, int); @@ -273,6 +273,11 @@ extern int vty_shell(struct vty *); extern int vty_shell_serv(struct vty *); extern void vty_hello(struct vty *); +/* ^Z / SIGTSTP handling */ +extern void vty_stdio_suspend(void); +extern void vty_stdio_resume(void); +extern void vty_stdio_close(void); + /* Send a fixed-size message to all vty terminal monitors; this should be an async-signal-safe function. */ extern void vty_log_fixed(char *buf, size_t len); diff --git a/lib/zclient.c b/lib/zclient.c index 893d769e3a..24cb699196 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -45,7 +45,8 @@ enum event { ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT }; /* Prototype for event manager. */ static void zclient_event(enum event, struct zclient *); -const char *zclient_serv_path = NULL; +struct sockaddr_storage zclient_addr; +socklen_t zclient_addr_len; /* This file local debug flag. */ int zclient_debug = 0; @@ -183,31 +184,28 @@ void zclient_reset(struct zclient *zclient) zclient_init(zclient, zclient->redist_default, zclient->instance); } -#ifdef HAVE_TCP_ZEBRA - -/* Make socket to zebra daemon. Return zebra socket. */ -static int zclient_socket(void) +/** + * Connect to zebra daemon. + * @param zclient a pointer to zclient structure + * @return socket fd just to make sure that connection established + * @see zclient_init + * @see zclient_new + */ +int zclient_socket_connect(struct zclient *zclient) { int sock; int ret; - struct sockaddr_in serv; /* We should think about IPv6 connection. */ - sock = socket(AF_INET, SOCK_STREAM, 0); + sock = socket(zclient_addr.ss_family, SOCK_STREAM, 0); if (sock < 0) return -1; - /* Make server socket. */ - memset(&serv, 0, sizeof(struct sockaddr_in)); - serv.sin_family = AF_INET; - serv.sin_port = htons(ZEBRA_PORT); -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - serv.sin_len = sizeof(struct sockaddr_in); -#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - serv.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + set_cloexec(sock); /* Connect to zebra. */ - ret = connect(sock, (struct sockaddr *)&serv, sizeof(serv)); + ret = connect(sock, (struct sockaddr *)&zclient_addr, + zclient_addr_len); if (ret < 0) { if (zclient_debug) zlog_warn("%s connect failure: %d(%s)", @@ -216,65 +214,11 @@ static int zclient_socket(void) close(sock); return -1; } - return sock; -} -#else - -/* For sockaddr_un. */ -#include <sys/un.h> - -static int zclient_socket_un(const char *path) -{ - int ret; - int sock, len; - struct sockaddr_un addr; - - sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (sock < 0) - return -1; - - /* Make server socket. */ - memset(&addr, 0, sizeof(struct sockaddr_un)); - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, path, strlen(path)); -#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN - len = addr.sun_len = SUN_LEN(&addr); -#else - len = sizeof(addr.sun_family) + strlen(addr.sun_path); -#endif /* HAVE_STRUCT_SOCKADDR_UN_SUN_LEN */ - - ret = connect(sock, (struct sockaddr *)&addr, len); - if (ret < 0) { - if (zclient_debug) - zlog_warn("%s connect failure: %d(%s)", - __PRETTY_FUNCTION__, errno, - safe_strerror(errno)); - close(sock); - return -1; - } + zclient->sock = sock; return sock; } -#endif /* HAVE_TCP_ZEBRA */ - -/** - * Connect to zebra daemon. - * @param zclient a pointer to zclient structure - * @return socket fd just to make sure that connection established - * @see zclient_init - * @see zclient_new - */ -int zclient_socket_connect(struct zclient *zclient) -{ -#ifdef HAVE_TCP_ZEBRA - zclient->sock = zclient_socket(); -#else - zclient->sock = zclient_socket_un(zclient_serv_path_get()); -#endif - return zclient->sock; -} - static int zclient_failed(struct zclient *zclient) { zclient->fail++; @@ -2225,34 +2169,6 @@ static void zclient_event(enum event event, struct zclient *zclient) } } -const char *zclient_serv_path_get() -{ - return zclient_serv_path ? zclient_serv_path : ZEBRA_SERV_PATH; -} - -void zclient_serv_path_set(char *path) -{ - struct stat sb; - - /* reset */ - zclient_serv_path = NULL; - - /* test if `path' is socket. don't set it otherwise. */ - if (stat(path, &sb) == -1) { - zlog_warn("%s: zebra socket `%s' does not exist", __func__, - path); - return; - } - - if ((sb.st_mode & S_IFMT) != S_IFSOCK) { - zlog_warn("%s: `%s' is not unix socket, sir", __func__, path); - return; - } - - /* it seems that path is unix socket */ - zclient_serv_path = path; -} - void zclient_interface_set_master(struct zclient *client, struct interface *master, struct interface *slave) diff --git a/lib/zclient.h b/lib/zclient.h index 8a2729543f..15d1858d84 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -42,6 +42,14 @@ /* Zebra header size. */ #define ZEBRA_HEADER_SIZE 8 +/* special socket path name to use TCP + * @ is used as first character because that's abstract socket names on Linux + */ +#define ZAPI_TCP_PATHNAME "@tcp" + +extern struct sockaddr_storage zclient_addr; +extern socklen_t zclient_addr_len; + /* Zebra message types. */ typedef enum { ZEBRA_INTERFACE_ADD, @@ -103,6 +111,7 @@ typedef enum { ZEBRA_FEC_REGISTER, ZEBRA_FEC_UNREGISTER, ZEBRA_FEC_UPDATE, + ZEBRA_ADVERTISE_DEFAULT_GW, ZEBRA_ADVERTISE_ALL_VNI, ZEBRA_VNI_ADD, ZEBRA_VNI_DEL, @@ -297,6 +306,10 @@ struct zapi_pw_status { uint32_t status; }; +/* Zebra MAC types */ +#define ZEBRA_MAC_TYPE_STICKY 0x01 /* Sticky MAC*/ +#define ZEBRA_MAC_TYPE_GW 0x02 /* gateway (SVI) mac*/ + /* Prototypes of zebra client service functions. */ extern struct zclient *zclient_new(struct thread_master *); extern void zclient_init(struct zclient *, int, u_short); @@ -306,8 +319,6 @@ extern void zclient_reset(struct zclient *); extern void zclient_free(struct zclient *); extern int zclient_socket_connect(struct zclient *); -extern void zclient_serv_path_set(char *path); -extern const char *zclient_serv_path_get(void); extern u_short *redist_check_instance(struct redist_proto *, u_short); extern void redist_add_instance(struct redist_proto *, u_short); |
