From d11f748b30d6867e13a77ed83666cb34881a2f53 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 27 Jul 2016 19:39:44 +0200 Subject: *: fixup snmp support - HAVE_POLL is overloaded by net-snmp - missing includes - ospf6_snmp converted to vrf_iflist() Signed-off-by: David Lamparter --- lib/thread.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'lib/thread.c') diff --git a/lib/thread.c b/lib/thread.c index 8d75509b1d..a8ccb8b3d0 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -33,11 +33,23 @@ #include "sigevent.h" #if defined HAVE_SNMP && defined SNMP_AGENTX + +#ifdef HAVE_POLL +#define QUAGGA_HAVE_POLL +#endif + #include #include #include #include +#ifdef HAVE_POLL +#undef HAVE_POLL +#endif +#ifdef QUAGGA_HAVE_POLL +#define HAVE_POLL +#endif + extern int agentx_enabled; #endif -- cgit v1.2.3 From a05d8b7ae46410c6782729375090306fd56b4561 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 28 Jul 2016 17:23:36 +0200 Subject: ospfd: monotonic clock for lsa_refresher_started ospf->lsa_refresher_started is only used in relative timing to itself; replace with monotonic clock which is appropriate for this. Signed-off-by: David Lamparter --- lib/thread.c | 8 ++++++++ lib/thread.h | 1 + ospfd/ospf_lsa.c | 6 +++--- ospfd/ospfd.c | 6 +++--- 4 files changed, 15 insertions(+), 6 deletions(-) (limited to 'lib/thread.c') diff --git a/lib/thread.c b/lib/thread.c index a8ccb8b3d0..717210b950 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -237,6 +237,14 @@ quagga_gettime (enum quagga_clkid clkid, struct timeval *tv) } } +time_t +quagga_monotime (void) +{ + struct timeval tv; + quagga_get_relative(&tv); + return tv.tv_sec; +} + /* time_t value in terms of stabilised absolute time. * replacement for POSIX time() */ diff --git a/lib/thread.h b/lib/thread.h index 8b42ffe58a..ac87595ee4 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -253,6 +253,7 @@ extern struct cmd_element clear_thread_cpu_cmd; * all systems, and fully monotonic on /some/ systems. */ extern int quagga_gettime (enum quagga_clkid, struct timeval *); +extern time_t quagga_monotime (void); extern time_t quagga_time (time_t *); /* Returns elapsed real (wall clock) time. */ diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index ec0eab5f0a..7e34e5dd9e 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -3731,7 +3731,7 @@ ospf_refresher_register_lsa (struct ospf *ospf, struct ospf_lsa *lsa) */ delay = (random() % (max_delay - min_delay)) + min_delay; - current_index = ospf->lsa_refresh_queue.index + (quagga_time (NULL) + current_index = ospf->lsa_refresh_queue.index + (quagga_monotime () - ospf->lsa_refresher_started)/OSPF_LSA_REFRESHER_GRANULARITY; index = (current_index + delay/OSPF_LSA_REFRESHER_GRANULARITY) @@ -3795,7 +3795,7 @@ ospf_lsa_refresh_walker (struct thread *t) modulus. */ ospf->lsa_refresh_queue.index = ((unsigned long)(ospf->lsa_refresh_queue.index + - (quagga_time (NULL) - ospf->lsa_refresher_started) + (quagga_monotime () - ospf->lsa_refresher_started) / OSPF_LSA_REFRESHER_GRANULARITY)) % OSPF_LSA_REFRESHER_SLOTS; @@ -3836,7 +3836,7 @@ ospf_lsa_refresh_walker (struct thread *t) ospf->t_lsa_refresher = thread_add_timer (master, ospf_lsa_refresh_walker, ospf, ospf->lsa_refresh_interval); - ospf->lsa_refresher_started = quagga_time (NULL); + ospf->lsa_refresher_started = quagga_monotime (); for (ALL_LIST_ELEMENTS (lsa_to_refresh, node, nnode, lsa)) { diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 2034ed1dbd..2a3f9c1d08 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -272,7 +272,7 @@ ospf_new (u_short instance) new->lsa_refresh_interval = OSPF_LSA_REFRESH_INTERVAL_DEFAULT; new->t_lsa_refresher = thread_add_timer (master, ospf_lsa_refresh_walker, new, new->lsa_refresh_interval); - new->lsa_refresher_started = quagga_time (NULL); + new->lsa_refresher_started = quagga_monotime (); if ((new->fd = ospf_sock_init()) < 0) { @@ -1598,7 +1598,7 @@ ospf_timers_refresh_set (struct ospf *ospf, int interval) return 1; time_left = ospf->lsa_refresh_interval - - (quagga_time (NULL) - ospf->lsa_refresher_started); + (quagga_monotime () - ospf->lsa_refresher_started); if (time_left > interval) { @@ -1617,7 +1617,7 @@ ospf_timers_refresh_unset (struct ospf *ospf) int time_left; time_left = ospf->lsa_refresh_interval - - (quagga_time (NULL) - ospf->lsa_refresher_started); + (quagga_monotime () - ospf->lsa_refresher_started); if (time_left > OSPF_LSA_REFRESH_INTERVAL_DEFAULT) { -- cgit v1.2.3 From 16f5949d44f7d9bec5b0402845754e9aca9b6f32 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 28 Jul 2016 17:23:40 +0200 Subject: lib: remove a whole bunch of unused time stuff QUAGGA_CLK_REALTIME and QUAGGA_CLK_REALTIME_STABILISED aren't used anywhere in the code. Remove. The enum is kept to avoid having to change the calls everywhere. Same applies to the workaround code for systems that don't have a monotonic clock. None of the systems Quagga works on fall into that category; Linux, BSD and Solaris all do clock_gettime, for OSX we have mach_absolute_time() - that covers everything. Signed-off-by: David Lamparter --- lib/thread.c | 64 +----------------------------------------------------------- lib/thread.h | 5 +---- 2 files changed, 2 insertions(+), 67 deletions(-) (limited to 'lib/thread.c') diff --git a/lib/thread.c b/lib/thread.c index 717210b950..0b50f9edeb 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -60,12 +60,8 @@ extern int agentx_enabled; /* Recent absolute time of day */ struct timeval recent_time; -static struct timeval last_recent_time; /* Relative time, since startup */ static struct timeval relative_time; -static struct timeval relative_time_base; -/* init flag */ -static unsigned short timers_inited; static struct hash *cpu_record = NULL; @@ -118,27 +114,6 @@ timeval_elapsed (struct timeval a, struct timeval b) + (a.tv_usec - b.tv_usec)); } -#if !defined(HAVE_CLOCK_MONOTONIC) && !defined(__APPLE__) -static void -quagga_gettimeofday_relative_adjust (void) -{ - struct timeval diff; - if (timeval_cmp (recent_time, last_recent_time) < 0) - { - relative_time.tv_sec++; - relative_time.tv_usec = 0; - } - else - { - diff = timeval_subtract (recent_time, last_recent_time); - relative_time.tv_sec += diff.tv_sec; - relative_time.tv_usec += diff.tv_usec; - relative_time = timeval_adjust (relative_time); - } - last_recent_time = recent_time; -} -#endif /* !HAVE_CLOCK_MONOTONIC && !__APPLE__ */ - /* gettimeofday wrapper, to keep recent_time updated */ static int quagga_gettimeofday (struct timeval *tv) @@ -149,12 +124,6 @@ quagga_gettimeofday (struct timeval *tv) if (!(ret = gettimeofday (&recent_time, NULL))) { - /* init... */ - if (!timers_inited) - { - relative_time_base = last_recent_time = recent_time; - timers_inited = 1; - } /* avoid copy if user passed recent_time pointer.. */ if (tv != &recent_time) *tv = recent_time; @@ -194,8 +163,7 @@ quagga_get_relative (struct timeval *tv) return 0; } #else /* !HAVE_CLOCK_MONOTONIC && !__APPLE__ */ - if (!(ret = quagga_gettimeofday (&recent_time))) - quagga_gettimeofday_relative_adjust(); +#error no monotonic clock on this system #endif /* HAVE_CLOCK_MONOTONIC */ if (tv) @@ -204,18 +172,6 @@ quagga_get_relative (struct timeval *tv) return ret; } -/* Get absolute time stamp, but in terms of the internal timer - * Could be wrong, but at least won't go back. - */ -static void -quagga_real_stabilised (struct timeval *tv) -{ - *tv = relative_time_base; - tv->tv_sec += relative_time.tv_sec; - tv->tv_usec += relative_time.tv_usec; - *tv = timeval_adjust (*tv); -} - /* Exported Quagga timestamp function. * Modelled on POSIX clock_gettime. */ @@ -224,13 +180,8 @@ quagga_gettime (enum quagga_clkid clkid, struct timeval *tv) { switch (clkid) { - case QUAGGA_CLK_REALTIME: - return quagga_gettimeofday (tv); case QUAGGA_CLK_MONOTONIC: return quagga_get_relative (tv); - case QUAGGA_CLK_REALTIME_STABILISED: - quagga_real_stabilised (tv); - return 0; default: errno = EINVAL; return -1; @@ -245,19 +196,6 @@ quagga_monotime (void) return tv.tv_sec; } -/* time_t value in terms of stabilised absolute time. - * replacement for POSIX time() - */ -time_t -quagga_time (time_t *t) -{ - struct timeval tv; - quagga_real_stabilised (&tv); - if (t) - *t = tv.tv_sec; - return tv.tv_sec; -} - /* Public export of recent_relative_time by value */ struct timeval recent_relative_time (void) diff --git a/lib/thread.h b/lib/thread.h index ac87595ee4..3c0387eb11 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -130,9 +130,7 @@ struct cpu_thread_history /* Clocks supported by Quagga */ enum quagga_clkid { - QUAGGA_CLK_REALTIME = 0, /* ala gettimeofday() */ - QUAGGA_CLK_MONOTONIC, /* monotonic, against an indeterminate base */ - QUAGGA_CLK_REALTIME_STABILISED, /* like realtime, but non-decrementing */ + QUAGGA_CLK_MONOTONIC = 1, /* monotonic, against an indeterminate base */ }; /* Struct timeval's tv_usec one second value. */ @@ -254,7 +252,6 @@ extern struct cmd_element clear_thread_cpu_cmd; */ extern int quagga_gettime (enum quagga_clkid, struct timeval *); extern time_t quagga_monotime (void); -extern time_t quagga_time (time_t *); /* Returns elapsed real (wall clock) time. */ extern unsigned long thread_consumed_time(RUSAGE_T *after, RUSAGE_T *before, -- cgit v1.2.3 From d03c4cbd9ac03926501fbb822b05b1c9a04b65cb Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 28 Jul 2016 17:23:42 +0200 Subject: lib: add thread_add_timer_tv (struct timeval) Another zoo extension, this adds a timer scheduling function that takes a struct timeval argument (which is actually what the wrappers boil down to, yet it's not exposed...) Signed-off-by: David Lamparter --- lib/thread.c | 11 +++++++++++ lib/thread.h | 5 +++++ 2 files changed, 16 insertions(+) (limited to 'lib/thread.c') diff --git a/lib/thread.c b/lib/thread.c index 0b50f9edeb..f3b0bdf8a5 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -941,6 +941,17 @@ funcname_thread_add_timer_msec (struct thread_master *m, arg, &trel, debugargpass); } +/* Add timer event thread with "millisecond" resolution */ +struct thread * +funcname_thread_add_timer_tv (struct thread_master *m, + int (*func) (struct thread *), + void *arg, struct timeval *tv, + debugargdef) +{ + return funcname_thread_add_timer_timeval (m, func, THREAD_TIMER, + arg, tv, debugargpass); +} + /* Add a background thread, with an optional millisec delay */ struct thread * funcname_thread_add_background (struct thread_master *m, diff --git a/lib/thread.h b/lib/thread.h index 3c0387eb11..c692142839 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -197,6 +197,7 @@ enum quagga_clkid { #define thread_add_write(m,f,a,v) funcname_thread_add_read_write(THREAD_WRITE,m,f,a,v,#f,__FILE__,__LINE__) #define thread_add_timer(m,f,a,v) funcname_thread_add_timer(m,f,a,v,#f,__FILE__,__LINE__) #define thread_add_timer_msec(m,f,a,v) funcname_thread_add_timer_msec(m,f,a,v,#f,__FILE__,__LINE__) +#define thread_add_timer_tv(m,f,a,v) funcname_thread_add_timer_tv(m,f,a,v,#f,__FILE__,__LINE__) #define thread_add_event(m,f,a,v) funcname_thread_add_event(m,f,a,v,#f,__FILE__,__LINE__) #define thread_execute(m,f,a,v) funcname_thread_execute(m,f,a,v,#f,__FILE__,__LINE__) @@ -217,6 +218,10 @@ extern struct thread *funcname_thread_add_timer (struct thread_master *, extern struct thread *funcname_thread_add_timer_msec (struct thread_master *, int (*)(struct thread *), void *, long, debugargdef); +extern struct thread *funcname_thread_add_timer_tv (struct thread_master *, + int (*)(struct thread *), + void *, struct timeval *, + debugargdef); extern struct thread *funcname_thread_add_event (struct thread_master *, int (*)(struct thread *), void *, int, debugargdef); -- cgit v1.2.3 From 56e2c5e8471704b3f28210a96f3e5ef7e8557b97 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 28 Jul 2016 17:23:43 +0200 Subject: lib: AgentX: use threads instead of eventloop hack AgentX fd/timeout handling is rather hackishly monkeyed into thread.c. Replace with code that uses plain thread_* functions. NB: Net-SNMP's API rivals Quagga's in terms of age and absence of documentation. netsnmp_check_outstanding_agent_requests() in particular seems to be unused and is therefore untested. The most useful documentation on this is actually the blog post Vincent Bernat wrote when he originally integrated this into lldpd and Quagga: https://vincent.bernat.im/en/blog/2012-snmp-event-loop.html Signed-off-by: David Lamparter --- lib/agentx.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- lib/thread.c | 82 ++-------------------------------------------- 2 files changed, 106 insertions(+), 81 deletions(-) (limited to 'lib/thread.c') diff --git a/lib/agentx.c b/lib/agentx.c index 9dc5b47de3..5996b34a0f 100644 --- a/lib/agentx.c +++ b/lib/agentx.c @@ -24,12 +24,110 @@ #if defined HAVE_SNMP && defined SNMP_AGENTX #include #include +#include +#include #include "command.h" #include "smux.h" #include "memory.h" +#include "linklist.h" -int agentx_enabled = 0; +static int agentx_enabled = 0; + +static struct thread_master *agentx_tm; +static struct thread *timeout_thr = NULL; +static struct list *events = NULL; + +static void agentx_events_update(void); + +static int +agentx_timeout(struct thread *t) +{ + timeout_thr = NULL; + + snmp_timeout (); + run_alarms (); + netsnmp_check_outstanding_agent_requests (); + agentx_events_update (); + return 0; +} + +static int +agentx_read(struct thread *t) +{ + fd_set fds; + struct listnode *ln = THREAD_ARG (t); + list_delete_node (events, ln); + + FD_ZERO (&fds); + FD_SET (THREAD_FD (t), &fds); + snmp_read (&fds); + + netsnmp_check_outstanding_agent_requests (); + agentx_events_update (); + return 0; +} + +static void +agentx_events_update(void) +{ + int maxfd = 0; + int block = 1; + struct timeval timeout = { .tv_sec = 0, .tv_usec = 0 }; + fd_set fds; + struct listnode *ln; + struct thread *thr; + int fd, thr_fd; + + THREAD_OFF (timeout_thr); + + FD_ZERO (&fds); + snmp_select_info (&maxfd, &fds, &timeout, &block); + + if (!block) + timeout_thr = thread_add_timer_tv (agentx_tm, agentx_timeout, NULL, &timeout); + + ln = listhead (events); + thr = ln ? listgetdata (ln) : NULL; + thr_fd = thr ? THREAD_FD (thr) : -1; + + /* "two-pointer" / two-list simultaneous iteration + * ln/thr/thr_fd point to the next existing event listener to hit while + * fd counts to catch up */ + for (fd = 0; fd < maxfd; fd++) + { + /* caught up */ + if (thr_fd == fd) + { + struct listnode *nextln = listnextnode (ln); + if (!FD_ISSET (fd, &fds)) + { + thread_cancel (thr); + list_delete_node (events, ln); + } + ln = nextln; + thr = ln ? listgetdata (ln) : NULL; + thr_fd = thr ? THREAD_FD (thr) : -1; + } + /* need listener, but haven't hit one where it would be */ + else if (FD_ISSET (fd, &fds)) + { + struct listnode *newln; + thr = thread_add_read (agentx_tm, agentx_read, NULL, fd); + newln = listnode_add_before (events, ln, thr); + thr->arg = newln; + } + } + + /* leftover event listeners at this point have fd > maxfd, delete them */ + while (ln) + { + struct listnode *nextln = listnextnode (ln); + thread_cancel (listgetdata (ln)); + list_delete_node (events, ln); + ln = nextln; + } +} /* AgentX node. */ static struct cmd_node agentx_node = @@ -78,6 +176,8 @@ DEFUN (agentx_enable, if (!agentx_enabled) { init_snmp("quagga"); + events = list_new(); + agentx_events_update (); agentx_enabled = 1; return CMD_SUCCESS; } @@ -100,6 +200,8 @@ DEFUN (no_agentx, void smux_init (struct thread_master *tm) { + agentx_tm = tm; + netsnmp_enable_subagent (); snmp_disable_log (); snmp_enable_calllog (); @@ -208,6 +310,7 @@ smux_trap (struct variable *vp, size_t vp_len, send_v2trap (notification_vars); snmp_free_varbind (notification_vars); + agentx_events_update (); return 1; } diff --git a/lib/thread.c b/lib/thread.c index f3b0bdf8a5..a128786c3d 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -32,27 +32,6 @@ #include "command.h" #include "sigevent.h" -#if defined HAVE_SNMP && defined SNMP_AGENTX - -#ifdef HAVE_POLL -#define QUAGGA_HAVE_POLL -#endif - -#include -#include -#include -#include - -#ifdef HAVE_POLL -#undef HAVE_POLL -#endif -#ifdef QUAGGA_HAVE_POLL -#define HAVE_POLL -#endif - -extern int agentx_enabled; -#endif - #if defined(__APPLE__) #include #include @@ -1312,12 +1291,7 @@ thread_fetch (struct thread_master *m, struct thread *fetch) while (1) { int num = 0; -#if defined HAVE_SNMP && defined SNMP_AGENTX - struct timeval snmp_timer_wait; - int snmpblock = 0; - int fdsetsize; -#endif - + /* Signals pre-empt everything */ quagga_sigevent_process (); @@ -1353,35 +1327,7 @@ thread_fetch (struct thread_master *m, struct thread *fetch) (!timer_wait || (timeval_cmp (*timer_wait, *timer_wait_bg) > 0))) timer_wait = timer_wait_bg; } - -#if defined HAVE_SNMP && defined SNMP_AGENTX - /* When SNMP is enabled, we may have to select() on additional - FD. snmp_select_info() will add them to `readfd'. The trick - with this function is its last argument. We need to set it to - 0 if timer_wait is not NULL and we need to use the provided - new timer only if it is still set to 0. */ - if (agentx_enabled) - { - fdsetsize = FD_SETSIZE; - snmpblock = 1; - if (timer_wait) - { - snmpblock = 0; - memcpy(&snmp_timer_wait, timer_wait, sizeof(struct timeval)); - } -#if defined(HAVE_POLL) - /* clear fdset since there are no other fds in fd_set, - then add injected fds from snmp_select_info into pollset */ - FD_ZERO(&readfd); -#endif - snmp_select_info(&fdsetsize, &readfd, &snmp_timer_wait, &snmpblock); -#if defined(HAVE_POLL) - add_snmp_pollfds(m, &readfd, fdsetsize); -#endif - if (snmpblock == 0) - timer_wait = &snmp_timer_wait; - } -#endif + num = fd_select (m, FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait); /* Signals should get quick treatment */ @@ -1393,30 +1339,6 @@ thread_fetch (struct thread_master *m, struct thread *fetch) return NULL; } -#if defined HAVE_SNMP && defined SNMP_AGENTX -#if defined(HAVE_POLL) - /* re-enter pollfds in fd_set for handling in snmp_read */ - FD_ZERO(&readfd); - nfds_t i; - for (i = m->handler.pfdcount; i < m->handler.pfdcountsnmp; ++i) - { - if (m->handler.pfds[i].revents == POLLIN) - FD_SET(m->handler.pfds[i].fd, &readfd); - } -#endif - if (agentx_enabled) - { - if (num > 0) - snmp_read(&readfd); - else if (num == 0) - { - snmp_timeout(); - run_alarms(); - } - netsnmp_check_outstanding_agent_requests(); - } -#endif - /* Check foreground timers. Historically, they have had higher priority than I/O threads, so let's push them onto the ready list in front of the I/O threads. */ -- cgit v1.2.3