#include "nest/bird.h"
#include "lib/lists.h"
#include "lib/resource.h"
-#include "sysdep/unix/timer.h"
#include "lib/socket.h"
#include "lib/event.h"
#include "lib/timer.h"
#include "lib/string.h"
#include "nest/iface.h"
+#include "conf/conf.h"
#include "sysdep/unix/unix.h"
#include CONFIG_INCLUDE_SYSIO_H
this to gen small latencies */
#define MAX_RX_STEPS 4
+
/*
* Tracked Files
*/
NULL
};
-void *
-tracked_fopen(pool *p, char *name, char *mode)
+struct rfile *
+rf_open(pool *p, char *name, char *mode)
{
FILE *f = fopen(name, mode);
- if (f)
- {
- struct rfile *r = ralloc(p, &rf_class);
- r->f = f;
- }
- return f;
-}
-
-/**
- * DOC: Timers
- *
- * Timers are resources which represent a wish of a module to call
- * a function at the specified time. The platform dependent code
- * doesn't guarantee exact timing, only that a timer function
- * won't be called before the requested time.
- *
- * In BIRD, time is represented by values of the &bird_clock_t type
- * which are integral numbers interpreted as a relative number of seconds since
- * some fixed time point in past. The current time can be read
- * from variable @now with reasonable accuracy and is monotonic. There is also
- * a current 'absolute' time in variable @now_real reported by OS.
- *
- * Each timer is described by a &timer structure containing a pointer
- * to the handler function (@hook), data private to this function (@data),
- * time the function should be called at (@expires, 0 for inactive timers),
- * for the other fields see |timer.h|.
- */
-
-#define NEAR_TIMER_LIMIT 4
-
-static list near_timers, far_timers;
-static bird_clock_t first_far_timer = TIME_INFINITY;
-
-/* now must be different from 0, because 0 is a special value in timer->expires */
-bird_clock_t now = 1, now_real, boot_time;
-
-static void
-update_times_plain(void)
-{
- bird_clock_t new_time = time(NULL);
- int delta = new_time - now_real;
-
- if ((delta >= 0) && (delta < 60))
- now += delta;
- else if (now_real != 0)
- log(L_WARN "Time jump, delta %d s", delta);
-
- now_real = new_time;
-}
-
-static void
-update_times_gettime(void)
-{
- struct timespec ts;
- int rv;
-
- rv = clock_gettime(CLOCK_MONOTONIC, &ts);
- if (rv != 0)
- die("clock_gettime: %m");
-
- if (ts.tv_sec != now) {
- if (ts.tv_sec < now)
- log(L_ERR "Monotonic timer is broken");
-
- now = ts.tv_sec;
- now_real = time(NULL);
- }
-}
-
-static int clock_monotonic_available;
-
-static inline void
-update_times(void)
-{
- if (clock_monotonic_available)
- update_times_gettime();
- else
- update_times_plain();
-}
-
-static inline void
-init_times(void)
-{
- struct timespec ts;
- clock_monotonic_available = (clock_gettime(CLOCK_MONOTONIC, &ts) == 0);
- if (!clock_monotonic_available)
- log(L_WARN "Monotonic timer is missing");
-}
-
-
-static void
-tm_free(resource *r)
-{
- timer *t = (timer *) r;
-
- tm_stop(t);
-}
-
-static void
-tm_dump(resource *r)
-{
- timer *t = (timer *) r;
-
- debug("(code %p, data %p, ", t->hook, t->data);
- if (t->randomize)
- debug("rand %d, ", t->randomize);
- if (t->recurrent)
- debug("recur %d, ", t->recurrent);
- if (t->expires)
- debug("expires in %d sec)\n", t->expires - now);
- else
- debug("inactive)\n");
-}
-
-static struct resclass tm_class = {
- "Timer",
- sizeof(timer),
- tm_free,
- tm_dump,
- NULL,
- NULL
-};
-
-/**
- * tm_new - create a timer
- * @p: pool
- *
- * This function creates a new timer resource and returns
- * a pointer to it. To use the timer, you need to fill in
- * the structure fields and call tm_start() to start timing.
- */
-timer *
-tm_new(pool *p)
-{
- timer *t = ralloc(p, &tm_class);
- return t;
-}
-
-static inline void
-tm_insert_near(timer *t)
-{
- node *n = HEAD(near_timers);
-
- while (n->next && (SKIP_BACK(timer, n, n)->expires < t->expires))
- n = n->next;
- insert_node(&t->n, n->prev);
-}
-
-/**
- * tm_start - start a timer
- * @t: timer
- * @after: number of seconds the timer should be run after
- *
- * This function schedules the hook function of the timer to
- * be called after @after seconds. If the timer has been already
- * started, it's @expire time is replaced by the new value.
- *
- * You can have set the @randomize field of @t, the timeout
- * will be increased by a random number of seconds chosen
- * uniformly from range 0 .. @randomize.
- *
- * You can call tm_start() from the handler function of the timer
- * to request another run of the timer. Also, you can set the @recurrent
- * field to have the timer re-added automatically with the same timeout.
- */
-void
-tm_start(timer *t, unsigned after)
-{
- bird_clock_t when;
-
- if (t->randomize)
- after += random() % (t->randomize + 1);
- when = now + after;
- if (t->expires == when)
- return;
- if (t->expires)
- rem_node(&t->n);
- t->expires = when;
- if (after <= NEAR_TIMER_LIMIT)
- tm_insert_near(t);
- else
- {
- if (!first_far_timer || first_far_timer > when)
- first_far_timer = when;
- add_tail(&far_timers, &t->n);
- }
-}
-
-/**
- * tm_stop - stop a timer
- * @t: timer
- *
- * This function stops a timer. If the timer is already stopped,
- * nothing happens.
- */
-void
-tm_stop(timer *t)
-{
- if (t->expires)
- {
- rem_node(&t->n);
- t->expires = 0;
- }
-}
-
-static void
-tm_dump_them(char *name, list *l)
-{
- node *n;
- timer *t;
-
- debug("%s timers:\n", name);
- WALK_LIST(n, *l)
- {
- t = SKIP_BACK(timer, n, n);
- debug("%p ", t);
- tm_dump(&t->r);
- }
- debug("\n");
-}
-
-void
-tm_dump_all(void)
-{
- tm_dump_them("Near", &near_timers);
- tm_dump_them("Far", &far_timers);
-}
-
-static inline time_t
-tm_first_shot(void)
-{
- time_t x = first_far_timer;
-
- if (!EMPTY_LIST(near_timers))
- {
- timer *t = SKIP_BACK(timer, n, HEAD(near_timers));
- if (t->expires < x)
- x = t->expires;
- }
- return x;
-}
-
-void io_log_event(void *hook, void *data);
-
-static void
-tm_shot(void)
-{
- timer *t;
- node *n, *m;
-
- if (first_far_timer <= now)
- {
- bird_clock_t limit = now + NEAR_TIMER_LIMIT;
- first_far_timer = TIME_INFINITY;
- n = HEAD(far_timers);
- while (m = n->next)
- {
- t = SKIP_BACK(timer, n, n);
- if (t->expires <= limit)
- {
- rem_node(n);
- tm_insert_near(t);
- }
- else if (t->expires < first_far_timer)
- first_far_timer = t->expires;
- n = m;
- }
- }
- while ((n = HEAD(near_timers)) -> next)
- {
- int delay;
- t = SKIP_BACK(timer, n, n);
- if (t->expires > now)
- break;
- rem_node(n);
- delay = t->expires - now;
- t->expires = 0;
- if (t->recurrent)
- {
- int i = t->recurrent - delay;
- if (i < 0)
- i = 0;
- tm_start(t, i);
- }
- io_log_event(t->hook, t->data);
- t->hook(t);
- }
-}
-
-/**
- * tm_parse_datetime - parse a date and time
- * @x: datetime string
- *
- * tm_parse_datetime() takes a textual representation of
- * a date and time (dd-mm-yyyy hh:mm:ss)
- * and converts it to the corresponding value of type &bird_clock_t.
- */
-bird_clock_t
-tm_parse_datetime(char *x)
-{
- struct tm tm;
- int n;
- time_t t;
-
- if (sscanf(x, "%d-%d-%d %d:%d:%d%n", &tm.tm_mday, &tm.tm_mon, &tm.tm_year, &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &n) != 6 || x[n])
- return tm_parse_date(x);
- tm.tm_mon--;
- tm.tm_year -= 1900;
- t = mktime(&tm);
- if (t == (time_t) -1)
- return 0;
- return t;
-}
-/**
- * tm_parse_date - parse a date
- * @x: date string
- *
- * tm_parse_date() takes a textual representation of a date (dd-mm-yyyy)
- * and converts it to the corresponding value of type &bird_clock_t.
- */
-bird_clock_t
-tm_parse_date(char *x)
-{
- struct tm tm;
- int n;
- time_t t;
+ if (!f)
+ return NULL;
- if (sscanf(x, "%d-%d-%d%n", &tm.tm_mday, &tm.tm_mon, &tm.tm_year, &n) != 3 || x[n])
- return 0;
- tm.tm_mon--;
- tm.tm_year -= 1900;
- tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
- t = mktime(&tm);
- if (t == (time_t) -1)
- return 0;
- return t;
+ struct rfile *r = ralloc(p, &rf_class);
+ r->f = f;
+ return r;
}
-static void
-tm_format_reltime(char *x, struct tm *tm, bird_clock_t delta)
+void *
+rf_file(struct rfile *f)
{
- static char *month_names[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
-
- if (delta < 20*3600)
- bsprintf(x, "%02d:%02d", tm->tm_hour, tm->tm_min);
- else if (delta < 360*86400)
- bsprintf(x, "%s%02d", month_names[tm->tm_mon], tm->tm_mday);
- else
- bsprintf(x, "%d", tm->tm_year+1900);
+ return f->f;
}
-#include "conf/conf.h"
-
-/**
- * tm_format_datetime - convert date and time to textual representation
- * @x: destination buffer of size %TM_DATETIME_BUFFER_SIZE
- * @fmt_spec: specification of resulting textual representation of the time
- * @t: time
- *
- * This function formats the given relative time value @t to a textual
- * date/time representation (dd-mm-yyyy hh:mm:ss) in real time.
- */
-void
-tm_format_datetime(char *x, struct timeformat *fmt_spec, bird_clock_t t)
+int
+rf_fileno(struct rfile *f)
{
- const char *fmt_used;
- struct tm *tm;
- bird_clock_t delta = now - t;
- t = now_real - delta;
- tm = localtime(&t);
-
- if (fmt_spec->fmt1 == NULL)
- return tm_format_reltime(x, tm, delta);
-
- if ((fmt_spec->limit == 0) || (delta < fmt_spec->limit))
- fmt_used = fmt_spec->fmt1;
- else
- fmt_used = fmt_spec->fmt2;
-
- int rv = strftime(x, TM_DATETIME_BUFFER_SIZE, fmt_used, tm);
- if (((rv == 0) && fmt_used[0]) || (rv == TM_DATETIME_BUFFER_SIZE))
- strcpy(x, "<too-long>");
+ return fileno(f->f);
}
* Time clock
*/
+btime boot_time;
+
void
times_init(struct timeloop *loop)
{
if (rv < 0)
die("Monotonic clock is missing");
- if ((ts.tv_sec < 0) || (((s64) ts.tv_sec) > ((s64) 1 << 40)))
+ if ((ts.tv_sec < 0) || (((u64) ts.tv_sec) > ((u64) 1 << 40)))
log(L_WARN "Monotonic clock is crazy");
- loop->last_time = ((s64) ts.tv_sec S) + (ts.tv_nsec / 1000);
+ loop->last_time = ts.tv_sec S + ts.tv_nsec NS;
loop->real_time = 0;
}
if (rv < 0)
die("clock_gettime: %m");
- btime new_time = ((s64) ts.tv_sec S) + (ts.tv_nsec / 1000);
+ btime new_time = ts.tv_sec S + ts.tv_nsec NS;
if (new_time < loop->last_time)
log(L_ERR "Monotonic clock is broken");
loop->real_time = 0;
}
+void
+times_update_real_time(struct timeloop *loop)
+{
+ struct timespec ts;
+ int rv;
+
+ rv = clock_gettime(CLOCK_REALTIME, &ts);
+ if (rv < 0)
+ die("clock_gettime: %m");
+
+ loop->real_time = ts.tv_sec S + ts.tv_nsec NS;
+}
+
/**
* DOC: Sockets
}
#endif
+ if (s->vrf && !s->iface)
+ {
+ /* Bind socket to associated VRF interface.
+ This is Linux-specific, but so is SO_BINDTODEVICE. */
+#ifdef SO_BINDTODEVICE
+ struct ifreq ifr = {};
+ strcpy(ifr.ifr_name, s->vrf->name);
+ if (setsockopt(s->fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0)
+ ERR("SO_BINDTODEVICE");
+#endif
+ }
+
if (s->iface)
{
#ifdef SO_BINDTODEVICE
#endif
}
- if (s->priority >= 0)
- if (sk_set_priority(s, s->priority) < 0)
- return -1;
-
if (sk_is_ipv4(s))
{
if (s->flags & SKF_LADDR_RX)
return -1;
}
+ /* Must be after sk_set_tos4() as setting ToS on Linux also mangles priority */
+ if (s->priority >= 0)
+ if (sk_set_priority(s, s->priority) < 0)
+ return -1;
+
return 0;
}
sock *t = sk_new(s->pool);
t->type = type;
+ t->data = s->data;
t->af = s->af;
t->fd = fd;
t->ttl = s->ttl;
t->tos = s->tos;
+ t->vrf = s->vrf;
t->rbsize = s->rbsize;
t->tbsize = s->tbsize;
default:
return SSH_ERROR;
}
- }
+ } /* fallthrough */
case SK_SSH_SERVER_KNOWN:
{
if (!server_identity_is_ok)
return SSH_ERROR;
}
- }
+ } /* fallthrough */
case SK_SSH_USERAUTH:
{
default:
return SSH_ERROR;
}
- }
+ } /* fallthrough */
case SK_SSH_CHANNEL:
{
s->ssh->channel = ssh_channel_new(s->ssh->session);
if (s->ssh->channel == NULL)
return SSH_ERROR;
- }
+ } /* fallthrough */
case SK_SSH_SESSION:
{
default:
return SSH_ERROR;
}
- }
+ } /* fallthrough */
case SK_SSH_SUBSYSTEM:
{
return SSH_ERROR;
}
}
- }
+ } /* fallthrough */
case SK_SSH_ESTABLISHED:
s->ssh->state = SK_SSH_ESTABLISHED;
struct iovec iov = {s->tbuf, s->tpos - s->tbuf};
byte cmsg_buf[CMSG_TX_SPACE];
sockaddr dst;
+ int flags = 0;
sockaddr_fill(&dst, s->af, s->daddr, s->iface, s->dport);
.msg_iovlen = 1
};
+#ifdef CONFIG_DONTROUTE_UNICAST
+ /* FreeBSD silently changes TTL to 1 when MSG_DONTROUTE is used, therefore we
+ cannot use it for other cases (e.g. when TTL security is used). */
+ if (ipa_is_ip4(s->daddr) && ip4_is_unicast(ipa_to_ip4(s->daddr)) && (s->ttl == 1))
+ flags = MSG_DONTROUTE;
+#endif
+
#ifdef CONFIG_USE_HDRINCL
byte hdr[20];
struct iovec iov2[2] = { {hdr, 20}, iov };
if (s->flags & SKF_PKTINFO)
sk_prepare_cmsgs(s, &msg, cmsg_buf, sizeof(cmsg_buf));
- return sendmsg(s->fd, &msg, 0);
+ return sendmsg(s->fd, &msg, flags);
}
static inline int
struct timespec ts;
int rv;
- if (!clock_monotonic_available)
- return;
-
/*
* This is third time-tracking procedure (after update_times() above and
* times_update() in BFD), dedicated to internal event log and latency
if (rv < 0)
die("clock_gettime: %m");
- last_time = ((s64) ts.tv_sec S) + (ts.tv_nsec / 1000);
+ last_time = ts.tv_sec S + ts.tv_nsec NS;
if (event_open)
{
void
io_init(void)
{
- init_list(&near_timers);
- init_list(&far_timers);
init_list(&sock_list);
init_list(&global_event_list);
krt_io_init();
- init_times();
- update_times();
- boot_time = now;
- srandom((int) now_real);
+ // XXX init_times();
+ // XXX update_times();
+ boot_time = current_time();
+
+ u64 now = (u64) current_real_time();
+ srandom((uint) (now ^ (now >> 32)));
}
static int short_loops = 0;
io_loop(void)
{
int poll_tout, timeout;
- time_t tout;
int nfds, events, pout;
- timer2 *t;
+ timer *t;
sock *s;
node *n;
int fdmax = 256;
times_update(&main_timeloop);
events = ev_run_list(&global_event_list);
timers_fire(&main_timeloop);
- timers:
- update_times();
- tout = tm_first_shot();
- if (tout <= now)
- {
- tm_shot();
- goto timers;
- }
io_close_event();
- poll_tout = (events ? 0 : MIN(tout - now, 3)) * 1000; /* Time in milliseconds */
+ // FIXME
+ poll_tout = (events ? 0 : 3000); /* Time in milliseconds */
if (t = timers_first(&main_timeloop))
{
times_update(&main_timeloop);
- timeout = (tm2_remains(t) TO_MS) + 1;
+ timeout = (tm_remains(t) TO_MS) + 1;
poll_tout = MIN(poll_tout, timeout);
}