summaryrefslogtreecommitdiff
path: root/sysdep/unix
diff options
context:
space:
mode:
Diffstat (limited to 'sysdep/unix')
-rw-r--r--sysdep/unix/config.Y9
-rw-r--r--sysdep/unix/io.c24
-rw-r--r--sysdep/unix/krt.Y8
-rw-r--r--sysdep/unix/krt.c61
-rw-r--r--sysdep/unix/krt.h8
-rw-r--r--sysdep/unix/main.c8
-rw-r--r--sysdep/unix/unix.h2
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 */