diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/command.c | 4 | ||||
-rw-r--r-- | lib/distribute.c | 13 | ||||
-rw-r--r-- | lib/hash.c | 11 | ||||
-rw-r--r-- | lib/hash.h | 2 | ||||
-rw-r--r-- | lib/if.c | 20 | ||||
-rw-r--r-- | lib/if.h | 1 | ||||
-rw-r--r-- | lib/if_rmap.c | 9 | ||||
-rw-r--r-- | lib/log.c | 3 | ||||
-rw-r--r-- | lib/memory.c | 42 | ||||
-rw-r--r-- | lib/memtypes.c | 1 | ||||
-rw-r--r-- | lib/prefix.c | 13 | ||||
-rw-r--r-- | lib/prefix.h | 4 | ||||
-rw-r--r-- | lib/sockunion.c | 40 | ||||
-rw-r--r-- | lib/sockunion.h | 2 | ||||
-rw-r--r-- | lib/table.c | 14 | ||||
-rw-r--r-- | lib/thread.c | 142 | ||||
-rw-r--r-- | lib/thread.h | 3 | ||||
-rw-r--r-- | lib/vty.c | 2 | ||||
-rw-r--r-- | lib/workqueue.c | 17 | ||||
-rw-r--r-- | lib/zclient.c | 6 |
20 files changed, 280 insertions, 69 deletions
diff --git a/lib/command.c b/lib/command.c index 478125f2..264e0f7b 100644 --- a/lib/command.c +++ b/lib/command.c @@ -3056,7 +3056,7 @@ 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 : "")); + zlog(NULL, level, "%s", ((message = argv_concat(argv, argc, 1)) ? message : "")); if (message) XFREE(MTYPE_TMP, message); return CMD_SUCCESS; @@ -3650,6 +3650,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/distribute.c b/lib/distribute.c index 242a225c..420849da 100644 --- a/lib/distribute.c +++ b/lib/distribute.c @@ -114,16 +114,11 @@ distribute_get (const char *ifname) } static unsigned int -distribute_hash_make (struct distribute *dist) +distribute_hash_make (void *arg) { - unsigned int i, key; + const struct distribute *dist = arg; - key = 0; - if (dist->ifname) - for (i = 0; i < strlen (dist->ifname); i++) - key += dist->ifname[i]; - - return key; + return dist->ifname ? string_hash_make (dist->ifname) : 0; } /* If two distribute-list have same value then return 1 else return @@ -763,7 +758,7 @@ distribute_list_reset () void distribute_list_init (int node) { - disthash = hash_create ((unsigned int (*) (void *)) distribute_hash_make, + disthash = hash_create (distribute_hash_make, (int (*) (const void *, const void *)) distribute_cmp); if(node==RIP_NODE) { @@ -101,6 +101,17 @@ hash_lookup (struct hash *hash, void *data) return hash_get (hash, data, NULL); } +/* Simple Bernstein hash which is simple and fast for common case */ +unsigned int string_hash_make (const char *str) +{ + unsigned int hash = 0; + + while (*str) + hash = (hash * 33) ^ (unsigned int) *str++; + + return hash; +} + /* This function release registered value from specified hash. When release is successfully finished, return the data pointer in the hash backet. */ @@ -70,4 +70,6 @@ extern void hash_iterate (struct hash *, extern void hash_clean (struct hash *, void (*) (void *)); extern void hash_free (struct hash *); +extern unsigned int string_hash_make (const char *); + #endif /* _ZEBRA_HASH_H */ @@ -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. */ @@ -878,3 +878,21 @@ if_init (void) memset (&if_master, 0, sizeof if_master); } + +void +if_terminate (void) +{ + for (;;) + { + struct interface *ifp; + + ifp = listnode_head (iflist); + if (ifp == NULL) + break; + + if_delete (ifp); + } + + list_delete (iflist); + iflist = NULL; +} @@ -266,6 +266,7 @@ extern int if_is_pointopoint (struct interface *); extern int if_is_multicast (struct interface *); extern void if_add_hook (int, int (*)(struct interface *)); extern void if_init (void); +extern void if_terminate (void); extern void if_dump_all (void); extern const char *if_flag_dump(unsigned long); diff --git a/lib/if_rmap.c b/lib/if_rmap.c index ddc62fd5..9774be4b 100644 --- a/lib/if_rmap.c +++ b/lib/if_rmap.c @@ -109,14 +109,9 @@ if_rmap_get (const char *ifname) static unsigned int if_rmap_hash_make (void *data) { - struct if_rmap *if_rmap = data; - unsigned int i, key; + const struct if_rmap *if_rmap = data; - key = 0; - for (i = 0; i < strlen (if_rmap->ifname); i++) - key += if_rmap->ifname[i]; - - return key; + return string_hash_make (if_rmap->ifname); } static int @@ -653,6 +653,9 @@ closezlog (struct zlog *zl) if (zl->fp != NULL) fclose (zl->fp); + if (zl->filename != NULL) + free (zl->filename); + XFREE (MTYPE_ZLOG, zl); } diff --git a/lib/memory.c b/lib/memory.c index dc09d8a6..4090fd90 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -58,7 +58,11 @@ zerror (const char *fname, int type, size_t size) abort(); } -/* Memory allocation. */ +/* + * Allocate memory of a given size, to be tracked by a given type. + * Effects: Returns a pointer to usable memory. If memory cannot + * be allocated, aborts execution. + */ void * zmalloc (int type, size_t size) { @@ -74,7 +78,9 @@ zmalloc (int type, size_t size) return memory; } -/* Memory allocation with num * size with cleared. */ +/* + * Allocate memory as in zmalloc, and also clear the memory. + */ void * zcalloc (int type, size_t size) { @@ -90,7 +96,13 @@ zcalloc (int type, size_t size) return memory; } -/* Memory reallocation. */ +/* + * Given a pointer returned by zmalloc or zcalloc, free it and + * return a pointer to a new size, basically acting like realloc(). + * Requires: ptr was returned by zmalloc, zcalloc, or zrealloc with the + * same type. + * Effects: Returns a pointer to the new memory, or aborts. + */ void * zrealloc (int type, void *ptr, size_t size) { @@ -99,18 +111,34 @@ zrealloc (int type, void *ptr, size_t size) memory = realloc (ptr, size); if (memory == NULL) zerror ("realloc", type, size); + if (ptr == NULL) + alloc_inc (type); + return memory; } -/* Memory free. */ +/* + * Free memory allocated by z*alloc or zstrdup. + * Requires: ptr was returned by zmalloc, zcalloc, or zrealloc with the + * same type. + * Effects: The memory is freed and may no longer be referenced. + */ void zfree (int type, void *ptr) { - alloc_dec (type); - free (ptr); + if (ptr != NULL) + { + alloc_dec (type); + free (ptr); + } } -/* String duplication. */ +/* + * Duplicate a string, counting memory usage by type. + * Effects: The string is duplicated, and the return value must + * eventually be passed to zfree with the same type. The function will + * succeed or abort. + */ char * zstrdup (int type, const char *str) { diff --git a/lib/memtypes.c b/lib/memtypes.c index 05d93225..59020671 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -108,6 +108,7 @@ struct memory_list memory_list_bgp[] = { MTYPE_BGP_NODE, "BGP node" }, { MTYPE_BGP_ROUTE, "BGP route" }, { MTYPE_BGP_ROUTE_EXTRA, "BGP ancillary route info" }, + { MTYPE_BGP_CONN, "BGP connected" }, { MTYPE_BGP_STATIC, "BGP static" }, { MTYPE_BGP_ADVERTISE_ATTR, "BGP adv attr" }, { MTYPE_BGP_ADVERTISE, "BGP adv" }, diff --git a/lib/prefix.c b/lib/prefix.c index c85e6594..61a278ca 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -41,7 +41,7 @@ static const u_char maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0, /* Address Famiy Identifier to Address Family converter. */ int -afi2family (int afi) +afi2family (afi_t afi) { if (afi == AFI_IP) return AF_INET; @@ -52,7 +52,7 @@ afi2family (int afi) return 0; } -int +afi_t family2afi (int family) { if (family == AF_INET) @@ -70,15 +70,16 @@ prefix_match (const struct prefix *n, const struct prefix *p) { int offset; int shift; - - /* Set both prefix's head pointer. */ - const u_char *np = (const u_char *)&n->u.prefix; - const u_char *pp = (const u_char *)&p->u.prefix; + const u_char *np, *pp; /* If n's prefix is longer than p's one return 0. */ if (n->prefixlen > p->prefixlen) return 0; + /* Set both prefix's head pointer. */ + np = (const u_char *)&n->u.prefix; + pp = (const u_char *)&p->u.prefix; + offset = n->prefixlen / PNBBY; shift = n->prefixlen % PNBBY; diff --git a/lib/prefix.h b/lib/prefix.h index a7598b7e..5f1ff05c 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -144,8 +144,8 @@ prefix6_bit (const struct in6_addr *prefix, const u_char prefixlen) } /* Prototypes. */ -extern int afi2family (int); -extern int family2afi (int); +extern int afi2family (afi_t); +extern afi_t family2afi (int); extern struct prefix *prefix_new (void); extern void prefix_free (struct prefix *); diff --git a/lib/sockunion.c b/lib/sockunion.c index 6a40f332..a5382a72 100644 --- a/lib/sockunion.c +++ b/lib/sockunion.c @@ -527,6 +527,46 @@ sockopt_ttl (int family, int sock, int ttl) 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 +} + +int +sockopt_minttl (int family, int sock, int minttl) +{ +#ifdef IP_MINTTL + if (family == AF_INET) + { + int ret = setsockopt (sock, IPPROTO_IP, IP_MINTTL, &minttl, sizeof(minttl)); + if (ret < 0) + zlog (NULL, LOG_WARNING, + "can't set sockopt IP_MINTTL to %d on socket %d: %s", + minttl, sock, safe_strerror (errno)); + return ret; + } +#endif /* IP_MINTTL */ +#ifdef IPV6_MINHOPCNT + if (family == AF_INET6) + { + int ret = setsockopt (sock, IPPROTO_IPV6, IPV6_MINHOPCNT, &minttl, sizeof(minttl)); + if (ret < 0) + zlog (NULL, LOG_WARNING, + "can't set sockopt IPV6_MINHOPCNT to %d on socket %d: %s", + minttl, sock, safe_strerror (errno)); + return ret; + } +#endif + + errno = EOPNOTSUPP; + return -1; +} + /* 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..0ee2d63b 100644 --- a/lib/sockunion.h +++ b/lib/sockunion.h @@ -102,6 +102,8 @@ extern int sockopt_reuseport (int); 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_minttl (int family, int sock, int minttl); +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/table.c b/lib/table.c index 04df3af5..e40e6707 100644 --- a/lib/table.c +++ b/lib/table.c @@ -209,6 +209,10 @@ route_node_match (const struct route_table *table, const struct prefix *p) { if (node->info) matched = node; + + if (node->p.prefixlen == p->prefixlen) + break; + node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)]; } @@ -260,8 +264,8 @@ route_node_lookup (struct route_table *table, struct prefix *p) while (node && node->p.prefixlen <= p->prefixlen && prefix_match (&node->p, p)) { - if (node->p.prefixlen == p->prefixlen && node->info) - return route_lock_node (node); + if (node->p.prefixlen == p->prefixlen) + return node->info ? route_lock_node (node) : NULL; node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)]; } @@ -283,10 +287,8 @@ route_node_get (struct route_table *table, struct prefix *p) prefix_match (&node->p, p)) { if (node->p.prefixlen == p->prefixlen) - { - route_lock_node (node); - return node; - } + return route_lock_node (node); + match = node; node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)]; } diff --git a/lib/thread.c b/lib/thread.c index e89af541..fd841c21 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -303,7 +303,7 @@ cpu_record_print(struct vty *vty, thread_type filter) void *args[3] = {&tmp, vty, &filter}; memset(&tmp, 0, sizeof tmp); - tmp.funcname = "TOTAL"; + tmp.funcname = (char *)"TOTAL"; tmp.types = filter; #ifdef HAVE_RUSAGE @@ -382,6 +382,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 +986,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) @@ -911,41 +1012,48 @@ thread_fetch (struct thread_master *m, struct thread *fetch) 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); diff --git a/lib/thread.h b/lib/thread.h index b52bc541..978aa6b0 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -82,7 +82,7 @@ struct thread struct cpu_thread_history { int (*func)(struct thread *); - const char *funcname; + char *funcname; unsigned int total_calls; struct time_stats { @@ -197,6 +197,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 @@ -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. */ 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..52a3627d 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -339,12 +339,12 @@ zclient_start (struct zclient *zclient) /* Create read thread. */ zclient_event (ZCLIENT_READ, zclient); - /* We need interface information. */ - zebra_message_send (zclient, ZEBRA_INTERFACE_ADD); - /* We need router-id information. */ zebra_message_send (zclient, ZEBRA_ROUTER_ID_ADD); + /* We need interface information. */ + zebra_message_send (zclient, ZEBRA_INTERFACE_ADD); + /* Flush all redistribute request. */ for (i = 0; i < ZEBRA_ROUTE_MAX; i++) if (i != zclient->redist_default && zclient->redist[i]) |