diff options
Diffstat (limited to 'sysdep/unix')
-rw-r--r-- | sysdep/unix/config.Y | 9 | ||||
-rw-r--r-- | sysdep/unix/io.c | 24 | ||||
-rw-r--r-- | sysdep/unix/krt.Y | 8 | ||||
-rw-r--r-- | sysdep/unix/krt.c | 61 | ||||
-rw-r--r-- | sysdep/unix/krt.h | 8 | ||||
-rw-r--r-- | sysdep/unix/main.c | 8 | ||||
-rw-r--r-- | sysdep/unix/unix.h | 2 |
7 files changed, 108 insertions, 12 deletions
diff --git a/sysdep/unix/config.Y b/sysdep/unix/config.Y index 5176be62..1917fe68 100644 --- a/sysdep/unix/config.Y +++ b/sysdep/unix/config.Y @@ -13,7 +13,7 @@ CF_HDR CF_DECLS -CF_KEYWORDS(LOG, SYSLOG, ALL, DEBUG, TRACE, INFO, REMOTE, WARNING, ERROR, AUTH, FATAL, BUG, STDERR) +CF_KEYWORDS(LOG, SYSLOG, ALL, DEBUG, TRACE, INFO, REMOTE, WARNING, ERROR, AUTH, FATAL, BUG, STDERR, SOFT) %type <i> log_mask log_mask_list log_cat %type <g> log_file @@ -65,8 +65,13 @@ log_cat: /* Unix specific commands */ +CF_CLI_HELP(CONFIGURE, [soft] [\"<file>\"], [[Reload configuration]]) + CF_CLI(CONFIGURE, cfg_name, [\"<file>\"], [[Reload configuration]]) -{ cmd_reconfig($2); } ; +{ cmd_reconfig($2, RECONFIG_HARD); } ; + +CF_CLI(CONFIGURE SOFT, cfg_name, [\"<file>\"], [[Reload configuration and ignore changes in filters]]) +{ cmd_reconfig($3, RECONFIG_SOFT); } ; CF_CLI(DOWN,,, [[Shut the daemon down]]) { cli_msg(7, "Shutdown requested"); order_shutdown(); } ; diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 50992fb4..c86c1200 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -30,6 +30,12 @@ #include "lib/unix.h" #include "lib/sysio.h" +/* Maximum number of calls of rx/tx handler for one socket in one + * select iteration. Should be small enough to not monopolize CPU by + * one protocol instance. + */ +#define MAX_STEPS 4 + /* * Tracked Files */ @@ -593,6 +599,7 @@ sk_new(pool *p) s->saddr = s->daddr = IPA_NONE; s->sport = s->dport = 0; s->tos = s->ttl = -1; + s->flags = 0; s->iface = NULL; s->rbuf = NULL; s->rx_hook = NULL; @@ -703,7 +710,13 @@ sk_setup(sock *s) if ((s->tos >= 0) && setsockopt(fd, SOL_IP, IP_TOS, &s->tos, sizeof(s->tos)) < 0) WARN("IP_TOS"); #endif - + +#ifdef IPV6 + int v = 1; + if ((s->flags & SKF_V6ONLY) && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &v, sizeof(v)) < 0) + WARN("IPV6_V6ONLY"); +#endif + if (s->ttl >= 0) err = sk_set_ttl_int(s); else @@ -1335,22 +1348,27 @@ io_loop(void) { sock *s = current_sock; int e; + int steps = MAX_STEPS; if (FD_ISSET(s->fd, &rd) && s->rx_hook) do { + steps--; e = sk_read(s); if (s != current_sock) goto next; } - while (e && s->rx_hook); + while (e && s->rx_hook && steps); + + steps = MAX_STEPS; if (FD_ISSET(s->fd, &wr)) do { + steps--; e = sk_write(s); if (s != current_sock) goto next; } - while (e); + while (e && steps); current_sock = sk_next(s); next: ; } diff --git a/sysdep/unix/krt.Y b/sysdep/unix/krt.Y index 11fd0c01..40f1af9f 100644 --- a/sysdep/unix/krt.Y +++ b/sysdep/unix/krt.Y @@ -68,6 +68,7 @@ kif_proto_start: proto_start DEVICE { cf_kif = this_proto = proto_config_new(&proto_unix_iface, sizeof(struct kif_config)); this_proto->preference = DEF_PREF_DIRECT; THIS_KIF->scan_time = 60; + init_list(&THIS_KIF->primary); krt_if_construct(THIS_KIF); } ; @@ -81,6 +82,13 @@ kif_item: /* Scan time of 0 means scan on startup only */ THIS_KIF->scan_time = $3; } + | PRIMARY text_or_none prefix_or_ipa { + struct kif_primary_item *kpi = cfg_alloc(sizeof (struct kif_primary_item)); + kpi->pattern = $2; + kpi->prefix = $3.addr; + kpi->pxlen = $3.len; + add_tail(&THIS_KIF->primary, &kpi->n); + } ; CF_CODE diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index 6208f689..488447b7 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -151,6 +151,49 @@ kif_shutdown(struct proto *P) return PS_DOWN; } + +static inline int +prefer_scope(struct ifa *a, struct ifa *b) +{ return (a->scope > SCOPE_LINK) && (b->scope <= SCOPE_LINK); } + +static inline int +prefer_addr(struct ifa *a, struct ifa *b) +{ return ipa_compare(a->ip, b->ip) < 0; } + +static inline struct ifa * +find_preferred_ifa(struct iface *i, ip_addr prefix, ip_addr mask) +{ + struct ifa *a, *b = NULL; + + WALK_LIST(a, i->addrs) + { + if (!(a->flags & IA_SECONDARY) && + ipa_equal(ipa_and(a->ip, mask), prefix) && + (!b || prefer_scope(a, b) || prefer_addr(a, b))) + b = a; + } + + return b; +} + +struct ifa * +kif_choose_primary(struct iface *i) +{ + struct kif_config *cf = (struct kif_config *) (kif_proto->p.cf); + struct kif_primary_item *it; + struct ifa *a; + + WALK_LIST(it, cf->primary) + { + if (!it->pattern || patmatch(it->pattern, i->name)) + if (a = find_preferred_ifa(i, it->prefix, ipa_mkmask(it->pxlen))) + return a; + } + + return find_preferred_ifa(i, IPA_NONE, IPA_NONE); +} + + static int kif_reconfigure(struct proto *p, struct proto_config *new) { @@ -159,6 +202,7 @@ kif_reconfigure(struct proto *p, struct proto_config *new) if (!kif_params_same(&o->iface, &n->iface)) return 0; + if (o->scan_time != n->scan_time) { tm_stop(kif_scan_timer); @@ -166,6 +210,18 @@ kif_reconfigure(struct proto *p, struct proto_config *new) kif_scan(kif_scan_timer); tm_start(kif_scan_timer, n->scan_time); } + + if (!EMPTY_LIST(o->primary) || !EMPTY_LIST(n->primary)) + { + /* This is hack, we have to update a configuration + * to the new value just now, because it is used + * for recalculation of primary addresses. + */ + p->cf = new; + + ifa_recalc_all_primary_addresses(); + } + return 1; } @@ -224,7 +280,7 @@ krt_learn_announce_update(struct krt_proto *p, rte *e) ee->pflags = 0; ee->pref = p->p.preference; ee->u.krt = e->u.krt; - rte_update(p->p.table, nn, &p->p, ee); + rte_update(p->p.table, nn, &p->p, &p->p, ee); } static void @@ -232,7 +288,7 @@ krt_learn_announce_delete(struct krt_proto *p, net *n) { n = net_find(p->p.table, n->n.prefix, n->n.pxlen); if (n) - rte_update(p->p.table, n, &p->p, NULL); + rte_update(p->p.table, n, &p->p, &p->p, NULL); } static void @@ -819,6 +875,7 @@ krt_init(struct proto_config *c) { struct krt_proto *p = proto_new(c, sizeof(struct krt_proto)); + p->p.accept_ra_types = RA_OPTIMAL; p->p.rt_notify = krt_notify; p->p.min_scope = SCOPE_HOST; return &p->p; diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h index 10da1a8f..607e6993 100644 --- a/sysdep/unix/krt.h +++ b/sysdep/unix/krt.h @@ -86,10 +86,18 @@ void krt_got_route_async(struct krt_proto *p, struct rte *e, int new); extern struct protocol proto_unix_iface; +struct kif_primary_item { + node n; + byte *pattern; + ip_addr prefix; + int pxlen; +}; + struct kif_config { struct proto_config c; struct krt_if_params iface; int scan_time; /* How often we re-scan interfaces */ + list primary; /* Preferences for primary addresses */ }; struct kif_proto { diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c index 4df4e9fe..5f5b165f 100644 --- a/sysdep/unix/main.c +++ b/sysdep/unix/main.c @@ -115,7 +115,7 @@ read_config(void) else die("Unable to open configuration file %s: %m", config_name); } - config_commit(conf); + config_commit(conf, RECONFIG_HARD); } void @@ -133,11 +133,11 @@ async_config(void) config_free(conf); } else - config_commit(conf); + config_commit(conf, RECONFIG_HARD); } void -cmd_reconfig(char *name) +cmd_reconfig(char *name, int type) { struct config *conf; @@ -154,7 +154,7 @@ cmd_reconfig(char *name) } else { - switch (config_commit(conf)) + switch (config_commit(conf, type)) { case CONF_DONE: cli_msg(3, "Reconfigured."); diff --git a/sysdep/unix/unix.h b/sysdep/unix/unix.h index 997a4088..83f61af9 100644 --- a/sysdep/unix/unix.h +++ b/sysdep/unix/unix.h @@ -16,7 +16,7 @@ struct pool; void async_config(void); void async_dump(void); void async_shutdown(void); -void cmd_reconfig(char *name); +void cmd_reconfig(char *name, int type); /* io.c */ |