Merge branch 'master' into int-new-channels

This commit is contained in:
Jan Moskyto Matejka 2016-04-08 12:09:31 +02:00
commit 7a7ac65682
26 changed files with 227 additions and 163 deletions

View file

@ -318,8 +318,9 @@ protocol rip {
<p><descrip> <p><descrip>
<tag>include "<m/filename/"</tag> <tag>include "<m/filename/"</tag>
This statement causes inclusion of a new file. <m/Filename/ could also This statement causes inclusion of a new file. <m/Filename/ could also
be a wildcard. The maximal depth is 8. Note that this statement could be be a wildcard, in that case matching files are included in alphabetic
used anywhere in the config file, not just as a top-level option. order. The maximal depth is 8. Note that this statement could be used
anywhere in the config file, not just as a top-level option.
<tag><label id="dsc-log">log "<m/filename/"|syslog [name <m/name/]|stderr all|{ <m/list of classes/ }</tag> <tag><label id="dsc-log">log "<m/filename/"|syslog [name <m/name/]|stderr all|{ <m/list of classes/ }</tag>
Set logging of messages having the given class (either <cf/all/ or Set logging of messages having the given class (either <cf/all/ or
@ -1119,9 +1120,12 @@ foot).
<cf><m/P/.last</cf> returns the last ASN (the source ASN) in path <m/P/. <cf><m/P/.last</cf> returns the last ASN (the source ASN) in path <m/P/.
<cf><m/P/.last_nonaggregated</cf> returns the last ASN in the non-aggregated part of the path <m/P/.
Both <cf/first/ and <cf/last/ return zero if there is no appropriate Both <cf/first/ and <cf/last/ return zero if there is no appropriate
ASN, for example if the path contains an AS set element as the first (or ASN, for example if the path contains an AS set element as the first (or
the last) part. the last) part. If the path ends with an AS set, <cf/last_nonaggregated/
may be used to get last ASN before any AS set.
<cf><m/P/.len</cf> returns the length of path <m/P/. <cf><m/P/.len</cf> returns the length of path <m/P/.
@ -1859,6 +1863,11 @@ using the following configuration parameters:
in neighbor's implementation of 4B AS extension. Even when disabled in neighbor's implementation of 4B AS extension. Even when disabled
(off), BIRD behaves internally as AS4-aware BGP router. Default: on. (off), BIRD behaves internally as AS4-aware BGP router. Default: on.
<tag>enable extended messages <m/switch/</tag>
The BGP protocol uses maximum message length of 4096 bytes. This option
provides an extension to allow extended messages with length up
to 65535 bytes. Default: off.
<tag>capabilities <m/switch/</tag> <tag>capabilities <m/switch/</tag>
Use capability advertisement to advertise optional capabilities. This is Use capability advertisement to advertise optional capabilities. This is
standard behavior for newer BGP implementations, but there might be some standard behavior for newer BGP implementations, but there might be some
@ -2054,7 +2063,7 @@ protocol bgp {
multihop; # ... which is connected indirectly multihop; # ... which is connected indirectly
export filter { # We use non-trivial export rules export filter { # We use non-trivial export rules
if source = RTS_STATIC then { # Export only static routes if source = RTS_STATIC then { # Export only static routes
# Assign our community # Assign our community
bgp_community.add((65000,64501)); bgp_community.add((65000,64501));
# Artificially increase path length # Artificially increase path length
# by advertising local AS number twice # by advertising local AS number twice
@ -2263,7 +2272,7 @@ these attributes:
<tag>ip <cf/krt_prefsrc/</tag> (Linux) <tag>ip <cf/krt_prefsrc/</tag> (Linux)
The preferred source address. Used in source address selection for The preferred source address. Used in source address selection for
outgoing packets. Has to be one of the IP addresses of the router. outgoing packets. Has to be one of the IP addresses of the router.
<tag>int <cf/krt_realm/</tag> (Linux) <tag>int <cf/krt_realm/</tag> (Linux)
The realm of the route. Can be used for traffic classification. The realm of the route. Can be used for traffic classification.
@ -2608,8 +2617,8 @@ protocol ospf &lt;name&gt; {
updates. Default value is 5. updates. Default value is 5.
<tag>priority <M>num</M></tag> <tag>priority <M>num</M></tag>
On every multiple access network (e.g., the Ethernet) Designed Router On every multiple access network (e.g., the Ethernet) Designated Router
and Backup Designed router are elected. These routers have some special and Backup Designated router are elected. These routers have some special
functions in the flooding process. Higher priority increases preferences functions in the flooding process. Higher priority increases preferences
in this election. Routers with priority 0 are not eligible. Default in this election. Routers with priority 0 are not eligible. Default
value is 1. value is 1.

View file

@ -282,7 +282,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
LEN, LEN,
DEFINED, DEFINED,
ADD, DELETE, CONTAINS, RESET, ADD, DELETE, CONTAINS, RESET,
PREPEND, FIRST, LAST, MATCH, PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
EMPTY, EMPTY,
FILTER, WHERE, EVAL) FILTER, WHERE, EVAL)
@ -743,6 +743,7 @@ term:
| term '.' MASK '(' term ')' { $$ = f_new_inst(); $$->code = P('i','M'); $$->a1.p = $1; $$->a2.p = $5; } | term '.' MASK '(' term ')' { $$ = f_new_inst(); $$->code = P('i','M'); $$->a1.p = $1; $$->a2.p = $5; }
| term '.' FIRST { $$ = f_new_inst(); $$->code = P('a','f'); $$->a1.p = $1; } | term '.' FIRST { $$ = f_new_inst(); $$->code = P('a','f'); $$->a1.p = $1; }
| term '.' LAST { $$ = f_new_inst(); $$->code = P('a','l'); $$->a1.p = $1; } | term '.' LAST { $$ = f_new_inst(); $$->code = P('a','l'); $$->a1.p = $1; }
| term '.' LAST_NONAGGREGATED { $$ = f_new_inst(); $$->code = P('a','L'); $$->a1.p = $1; }
/* Communities */ /* Communities */
/* This causes one shift/reduce conflict /* This causes one shift/reduce conflict

View file

@ -1056,6 +1056,14 @@ interpret(struct f_inst *what)
res.type = T_INT; res.type = T_INT;
res.val.i = as; res.val.i = as;
break; break;
case P('a','L'): /* Get last ASN from non-aggregated part of AS PATH */
ONEARG;
if (v1.type != T_PATH)
runtime( "AS path expected" );
res.type = T_INT;
res.val.i = as_path_get_last_nonaggregated(v1.val.ad);
break;
case 'r': case 'r':
ONEARG; ONEARG;
res = v1; res = v1;

View file

@ -41,7 +41,7 @@ add_tail(list *l, node *n)
{ {
node *z = l->tail; node *z = l->tail;
n->next = (node *) &l->null; n->next = &l->tail_node;
n->prev = z; n->prev = z;
z->next = n; z->next = n;
l->tail = n; l->tail = n;
@ -60,7 +60,7 @@ add_head(list *l, node *n)
node *z = l->head; node *z = l->head;
n->next = z; n->next = z;
n->prev = (node *) &l->head; n->prev = &l->head_node;
z->prev = n; z->prev = n;
l->head = n; l->head = n;
} }
@ -88,7 +88,7 @@ insert_node(node *n, node *after)
* rem_node - remove a node from a list * rem_node - remove a node from a list
* @n: node to be removed * @n: node to be removed
* *
* Removes a node @n from the list it's linked in. * Removes a node @n from the list it's linked in. Afterwards, node @n is cleared.
*/ */
LIST_INLINE void LIST_INLINE void
rem_node(node *n) rem_node(node *n)
@ -96,23 +96,6 @@ rem_node(node *n)
node *z = n->prev; node *z = n->prev;
node *x = n->next; node *x = n->next;
z->next = x;
x->prev = z;
}
/**
* rem2_node - remove a node from a list, with cleanup
* @n: node to be removed
*
* Removes a node @n from the list it's linked in and resets its pointers to NULL.
* Useful if you want to distinguish between linked and unlinked nodes.
*/
LIST_INLINE void
rem2_node(node *n)
{
node *z = n->prev;
node *x = n->next;
z->next = x; z->next = x;
x->prev = z; x->prev = z;
n->next = NULL; n->next = NULL;
@ -150,9 +133,9 @@ replace_node(node *old, node *new)
LIST_INLINE void LIST_INLINE void
init_list(list *l) init_list(list *l)
{ {
l->head = (node *) &l->null; l->head = &l->tail_node;
l->null = NULL; l->null = NULL;
l->tail = (node *) &l->head; l->tail = &l->head_node;
} }
/** /**
@ -172,6 +155,6 @@ add_tail_list(list *to, list *l)
p->next = q; p->next = q;
q->prev = p; q->prev = p;
q = l->tail; q = l->tail;
q->next = (node *) &to->null; q->next = &to->tail_node;
to->tail = q; to->tail = q;
} }

View file

@ -26,10 +26,23 @@ typedef struct node {
struct node *next, *prev; struct node *next, *prev;
} node; } node;
typedef struct list { /* In fact two overlayed nodes */ typedef union list { /* In fact two overlayed nodes */
struct node *head, *null, *tail; struct { /* Head node */
struct node head_node;
void *head_padding;
};
struct { /* Tail node */
void *tail_padding;
struct node tail_node;
};
struct { /* Split to separate pointers */
struct node *head;
struct node *null;
struct node *tail;
};
} list; } list;
#define NODE (node *) #define NODE (node *)
#define HEAD(list) ((void *)((list).head)) #define HEAD(list) ((void *)((list).head))
#define TAIL(list) ((void *)((list).tail)) #define TAIL(list) ((void *)((list).tail))
@ -64,7 +77,6 @@ typedef struct list { /* In fact two overlayed nodes */
void add_tail(list *, node *); void add_tail(list *, node *);
void add_head(list *, node *); void add_head(list *, node *);
void rem_node(node *); void rem_node(node *);
void rem2_node(node *);
void add_tail_list(list *, list *); void add_tail_list(list *, list *);
void init_list(list *); void init_list(list *);
void insert_node(node *, node *); void insert_node(node *, node *);

View file

@ -163,6 +163,7 @@ rfree(void *res)
if (r->n.next) if (r->n.next)
rem_node(&r->n); rem_node(&r->n);
r->class->free(r); r->class->free(r);
r->class = NULL;
xfree(r); xfree(r);
} }
@ -383,16 +384,9 @@ mb_allocz(pool *p, unsigned size)
void * void *
mb_realloc(void *m, unsigned size) mb_realloc(void *m, unsigned size)
{ {
struct mblock *ob = NULL; struct mblock *b = SKIP_BACK(struct mblock, data, m);
if (m) b = xrealloc(b, sizeof(struct mblock) + size);
{
ob = SKIP_BACK(struct mblock, data, m);
if (ob->r.n.next)
rem_node(&ob->r.n);
}
struct mblock *b = xrealloc(ob, sizeof(struct mblock) + size);
replace_node(&b->r.n, &b->r.n); replace_node(&b->r.n, &b->r.n);
b->size = size; b->size = size;
return b->data; return b->data;

View file

@ -27,6 +27,7 @@ typedef struct birdsock {
struct iface *iface; /* Interface; specify this for broad/multicast sockets */ struct iface *iface; /* Interface; specify this for broad/multicast sockets */
byte *rbuf, *rpos; /* NULL=allocate automatically */ byte *rbuf, *rpos; /* NULL=allocate automatically */
uint fast_rx; /* RX has higher priority in event loop */
uint rbsize; uint rbsize;
int (*rx_hook)(struct birdsock *, int size); /* NULL=receiving turned off, returns 1 to clear rx buffer */ int (*rx_hook)(struct birdsock *, int size); /* NULL=receiving turned off, returns 1 to clear rx buffer */

View file

@ -220,7 +220,7 @@ as_path_get_last(struct adata *path, u32 *orig_as)
p += BS * len; p += BS * len;
} }
break; break;
default: bug("as_path_get_first: Invalid path segment"); default: bug("Invalid path segment");
} }
} }
@ -229,6 +229,35 @@ as_path_get_last(struct adata *path, u32 *orig_as)
return found; return found;
} }
u32
as_path_get_last_nonaggregated(struct adata *path)
{
u8 *p = path->data;
u8 *q = p+path->length;
u32 res = 0;
int len;
while (p<q)
{
switch (*p++)
{
case AS_PATH_SET:
return res;
case AS_PATH_SEQUENCE:
if (len = *p++)
res = get_as(p + BS * (len - 1));
p += BS * len;
break;
default: bug("Invalid path segment");
}
}
return res;
}
int int
as_path_get_first(struct adata *path, u32 *last_as) as_path_get_first(struct adata *path, u32 *last_as)
{ {

View file

@ -35,6 +35,7 @@ int as_path_getlen(struct adata *path);
int as_path_getlen_int(struct adata *path, int bs); int as_path_getlen_int(struct adata *path, int bs);
int as_path_get_first(struct adata *path, u32 *orig_as); int as_path_get_first(struct adata *path, u32 *orig_as);
int as_path_get_last(struct adata *path, u32 *last_as); int as_path_get_last(struct adata *path, u32 *last_as);
u32 as_path_get_last_nonaggregated(struct adata *path);
int as_path_contains(struct adata *path, u32 as, int min); int as_path_contains(struct adata *path, u32 as, int min);
int as_path_match_set(struct adata *path, struct f_tree *set); int as_path_match_set(struct adata *path, struct f_tree *set);
struct adata *as_path_filter(struct linpool *pool, struct adata *path, struct f_tree *set, u32 key, int pos); struct adata *as_path_filter(struct linpool *pool, struct adata *path, struct f_tree *set, u32 key, int pos);

View file

@ -112,7 +112,7 @@ idval:
else if (($1->class == (SYM_CONSTANT | T_IP)) && ipa_is_ip4(SYM_VAL($1).ip)) else if (($1->class == (SYM_CONSTANT | T_IP)) && ipa_is_ip4(SYM_VAL($1).ip))
$$ = ipa_to_u32(SYM_VAL($1).ip); $$ = ipa_to_u32(SYM_VAL($1).ip);
else else
cf_error("Number of IPv4 address constant expected"); cf_error("Number or IPv4 address constant expected");
} }
; ;

View file

@ -264,6 +264,7 @@ channel_stop_export(struct channel *c)
rt_feed_channel_abort(c); rt_feed_channel_abort(c);
c->export_state = ES_DOWN; c->export_state = ES_DOWN;
c->stats.exp_routes = 0;
} }
static void static void
@ -299,7 +300,7 @@ channel_do_flush(struct channel *c)
static void static void
channel_do_down(struct channel *c) channel_do_down(struct channel *c)
{ {
rem2_node(&c->table_node); rem_node(&c->table_node);
rt_unlock_table(c->table); rt_unlock_table(c->table);
c->proto->active_channels--; c->proto->active_channels--;

View file

@ -232,8 +232,8 @@ typedef struct rte {
struct { /* Routes generated by krt sync (both temporary and inherited ones) */ struct { /* Routes generated by krt sync (both temporary and inherited ones) */
s8 src; /* Alleged route source (see krt.h) */ s8 src; /* Alleged route source (see krt.h) */
u8 proto; /* Kernel source protocol ID */ u8 proto; /* Kernel source protocol ID */
u8 type; /* Kernel route type */
u8 seen; /* Seen during last scan */ u8 seen; /* Seen during last scan */
u8 best; /* Best route in network, propagated to core */
u32 metric; /* Kernel metric */ u32 metric; /* Kernel metric */
} krt; } krt;
} u; } u;

View file

@ -872,7 +872,7 @@ bfd_notify_hook(sock *sk, int len)
WALK_LIST_FIRST(s, tmp_list) WALK_LIST_FIRST(s, tmp_list)
{ {
bfd_lock_sessions(p); bfd_lock_sessions(p);
rem2_node(&s->n); rem_node(&s->n);
state = s->loc_state; state = s->loc_state;
diag = s->loc_diag; diag = s->loc_diag;
bfd_unlock_sessions(p); bfd_unlock_sessions(p);

View file

@ -576,7 +576,7 @@ sockets_close_fds(struct birdloop *loop)
loop->close_scheduled = 0; loop->close_scheduled = 0;
} }
int sk_read(sock *s); int sk_read(sock *s, int revents);
int sk_write(sock *s); int sk_write(sock *s);
static void static void
@ -605,7 +605,7 @@ sockets_fire(struct birdloop *loop)
if (pfd->revents & POLLIN) if (pfd->revents & POLLIN)
while (e && *psk && (*psk)->rx_hook) while (e && *psk && (*psk)->rx_hook)
e = sk_read(*psk); e = sk_read(*psk, 0);
e = 1; e = 1;
if (pfd->revents & POLLOUT) if (pfd->revents & POLLOUT)

View file

@ -374,6 +374,8 @@ bgp_conn_enter_established_state(struct bgp_conn *conn)
if (ipa_zero(p->source_addr)) if (ipa_zero(p->source_addr))
p->source_addr = conn->sk->saddr; p->source_addr = conn->sk->saddr;
conn->sk->fast_rx = 0;
p->conn = conn; p->conn = conn;
p->last_error_class = 0; p->last_error_class = 0;
p->last_error_code = 0; p->last_error_code = 0;
@ -666,6 +668,10 @@ bgp_keepalive_timeout(timer *t)
DBG("BGP: Keepalive timer\n"); DBG("BGP: Keepalive timer\n");
bgp_schedule_packet(conn, PKT_KEEPALIVE); bgp_schedule_packet(conn, PKT_KEEPALIVE);
/* Kick TX a bit faster */
if (ev_active(conn->tx_ev))
ev_run(conn->tx_ev);
} }
static void static void
@ -696,6 +702,7 @@ bgp_setup_sk(struct bgp_conn *conn, sock *s)
{ {
s->data = conn; s->data = conn;
s->err_hook = bgp_sock_err; s->err_hook = bgp_sock_err;
s->fast_rx = 1;
conn->sk = s; conn->sk = s;
} }
@ -813,7 +820,13 @@ bgp_incoming_connection(sock *sk, int dummy UNUSED)
return 0; return 0;
} }
/* We are in proper state and there is no other incoming connection */ /*
* BIRD should keep multiple incoming connections in OpenSent state (for
* details RFC 4271 8.2.1 par 3), but it keeps just one. Duplicate incoming
* connections are rejected istead. The exception is the case where an
* incoming connection triggers a graceful restart.
*/
acc = (p->p.proto_state == PS_START || p->p.proto_state == PS_UP) && acc = (p->p.proto_state == PS_START || p->p.proto_state == PS_UP) &&
(p->start_state >= BSS_CONNECT) && (!p->incoming_conn.sk); (p->start_state >= BSS_CONNECT) && (!p->incoming_conn.sk);
@ -823,6 +836,10 @@ bgp_incoming_connection(sock *sk, int dummy UNUSED)
bgp_handle_graceful_restart(p); bgp_handle_graceful_restart(p);
bgp_conn_enter_idle_state(p->conn); bgp_conn_enter_idle_state(p->conn);
acc = 1; acc = 1;
/* There might be separate incoming connection in OpenSent state */
if (p->incoming_conn.state > BS_ACTIVE)
bgp_close_conn(&p->incoming_conn);
} }
BGP_TRACE(D_EVENTS, "Incoming connection from %I%J (port %d) %s", BGP_TRACE(D_EVENTS, "Incoming connection from %I%J (port %d) %s",

View file

@ -163,6 +163,14 @@ bgp_put_cap_rr(struct bgp_proto *p UNUSED, byte *buf)
return buf; return buf;
} }
static byte *
bgp_put_cap_ext_msg(struct bgp_proto *p UNUSED, byte *buf)
{
*buf++ = 6; /* Capability 6: Support for extended messages */
*buf++ = 0; /* Capability data length */
return buf;
}
static byte * static byte *
bgp_put_cap_gr1(struct bgp_proto *p, byte *buf) bgp_put_cap_gr1(struct bgp_proto *p, byte *buf)
{ {
@ -223,14 +231,6 @@ bgp_put_cap_err(struct bgp_proto *p UNUSED, byte *buf)
return buf; return buf;
} }
static byte *
bgp_put_cap_ext_msg(struct bgp_proto *p UNUSED, byte *buf)
{
*buf++ = 230; /* Capability TBD: Support for extended messages */
*buf++ = 0; /* Capability data length */
return buf;
}
static byte * static byte *
bgp_create_open(struct bgp_conn *conn, byte *buf) bgp_create_open(struct bgp_conn *conn, byte *buf)
@ -827,6 +827,12 @@ bgp_parse_capabilities(struct bgp_conn *conn, byte *opt, int len)
conn->peer_refresh_support = 1; conn->peer_refresh_support = 1;
break; break;
case 6: /* Extended message length capability, draft */
if (cl != 0)
goto err;
conn->peer_ext_messages_support = 1;
break;
case 64: /* Graceful restart capability, RFC 4724 */ case 64: /* Graceful restart capability, RFC 4724 */
if (cl % 4 != 2) if (cl % 4 != 2)
goto err; goto err;
@ -867,12 +873,6 @@ bgp_parse_capabilities(struct bgp_conn *conn, byte *opt, int len)
conn->peer_enhanced_refresh_support = 1; conn->peer_enhanced_refresh_support = 1;
break; break;
case 230: /* Extended message length capability, draft, cap number TBD */
if (cl != 0)
goto err;
conn->peer_ext_messages_support = 1;
break;
/* We can safely ignore all other capabilities */ /* We can safely ignore all other capabilities */
} }
len -= 2 + cl; len -= 2 + cl;

View file

@ -595,10 +595,10 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
if (ospf_is_v2(p) && (ifa->type == OSPF_IT_NBMA) && (addr->flags & IA_PEER)) if (ospf_is_v2(p) && (ifa->type == OSPF_IT_NBMA) && (addr->flags & IA_PEER))
ifa->type = OSPF_IT_PTMP; ifa->type = OSPF_IT_PTMP;
if ((ifa->type == OSPF_IT_BCAST) && !(iface->flags & if_multi_flag)) if ((ifa->type == OSPF_IT_BCAST) && !(iface->flags & if_multi_flag) && !ifa->stub)
ifa->type = OSPF_IT_NBMA; ifa->type = OSPF_IT_NBMA;
if ((ifa->type == OSPF_IT_PTP) && !(iface->flags & if_multi_flag)) if ((ifa->type == OSPF_IT_PTP) && !(iface->flags & if_multi_flag) && !ifa->stub)
ifa->type = OSPF_IT_PTMP; ifa->type = OSPF_IT_PTMP;
if (ifa->type != old_type) if (ifa->type != old_type)

View file

@ -108,6 +108,7 @@ ospf_neigh_down(struct ospf_neighbor *n)
{ {
struct ospf_iface *ifa = n->ifa; struct ospf_iface *ifa = n->ifa;
struct ospf_proto *p = ifa->oa->po; struct ospf_proto *p = ifa->oa->po;
u32 rid = n->rid;
if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP)) if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP))
{ {
@ -121,7 +122,7 @@ ospf_neigh_down(struct ospf_neighbor *n)
rem_node(NODE n); rem_node(NODE n);
rfree(n->pool); rfree(n->pool);
OSPF_TRACE(D_EVENTS, "Neighbor %R on %s removed", n->rid, ifa->ifname); OSPF_TRACE(D_EVENTS, "Neighbor %R on %s removed", rid, ifa->ifname);
} }
/** /**

View file

@ -278,7 +278,7 @@ ospf_originate_lsa(struct ospf_proto *p, struct ospf_new_lsa *lsa)
if (!SNODE_VALID(en)) if (!SNODE_VALID(en))
s_add_tail(&p->lsal, SNODE en); s_add_tail(&p->lsal, SNODE en);
if (en->lsa_body == NULL) if (!en->nf || !en->lsa_body)
en->nf = lsa->nf; en->nf = lsa->nf;
if (en->nf != lsa->nf) if (en->nf != lsa->nf)

View file

@ -137,7 +137,7 @@ rip_iface_item:
| TIMEOUT TIME expr { RIP_IFACE->timeout_time = $3; if ($3<=0) cf_error("Timeout time must be positive"); } | TIMEOUT TIME expr { RIP_IFACE->timeout_time = $3; if ($3<=0) cf_error("Timeout time must be positive"); }
| GARBAGE TIME expr { RIP_IFACE->garbage_time = $3; if ($3<=0) cf_error("Garbage time must be positive"); } | GARBAGE TIME expr { RIP_IFACE->garbage_time = $3; if ($3<=0) cf_error("Garbage time must be positive"); }
| ECMP WEIGHT expr { RIP_IFACE->ecmp_weight = $3 - 1; if (($3<1) || ($3>256)) cf_error("ECMP weight must be in range 1-256"); } | ECMP WEIGHT expr { RIP_IFACE->ecmp_weight = $3 - 1; if (($3<1) || ($3>256)) cf_error("ECMP weight must be in range 1-256"); }
| RX BUFFER expr { RIP_IFACE->rx_buffer = $3; if (($3<256) || ($3>65535)) cf_error("TX length must be in range 256-65535"); } | RX BUFFER expr { RIP_IFACE->rx_buffer = $3; if (($3<256) || ($3>65535)) cf_error("RX length must be in range 256-65535"); }
| TX LENGTH expr { RIP_IFACE->tx_length = $3; if (($3<256) || ($3>65535)) cf_error("TX length must be in range 256-65535"); } | TX LENGTH expr { RIP_IFACE->tx_length = $3; if (($3<256) || ($3>65535)) cf_error("TX length must be in range 256-65535"); }
| TX tos { RIP_IFACE->tx_tos = $2; } | TX tos { RIP_IFACE->tx_tos = $2; }
| TX PRIORITY expr { RIP_IFACE->tx_priority = $3; } | TX PRIORITY expr { RIP_IFACE->tx_priority = $3; }

View file

@ -528,9 +528,8 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
e->net = net; e->net = net;
e->u.krt.src = src; e->u.krt.src = src;
e->u.krt.proto = src2; e->u.krt.proto = src2;
e->u.krt.seen = 0;
/* These are probably too Linux-specific */ e->u.krt.best = 0;
e->u.krt.type = 0;
e->u.krt.metric = 0; e->u.krt.metric = 0;
if (scan) if (scan)

View file

@ -1204,7 +1204,8 @@ nl_parse_route(struct nlmsghdr *h, int scan)
e->net = net; e->net = net;
e->u.krt.src = src; e->u.krt.src = src;
e->u.krt.proto = i->rtm_protocol; e->u.krt.proto = i->rtm_protocol;
e->u.krt.type = i->rtm_type; e->u.krt.seen = 0;
e->u.krt.best = 0;
e->u.krt.metric = 0; e->u.krt.metric = 0;
if (a[RTA_PRIORITY]) if (a[RTA_PRIORITY])

View file

@ -19,6 +19,7 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/uio.h> #include <sys/uio.h>
#include <sys/un.h> #include <sys/un.h>
#include <poll.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <errno.h> #include <errno.h>
@ -41,12 +42,12 @@
#include "lib/sysio.h" #include "lib/sysio.h"
/* Maximum number of calls of tx handler for one socket in one /* Maximum number of calls of tx handler for one socket in one
* select iteration. Should be small enough to not monopolize CPU by * poll iteration. Should be small enough to not monopolize CPU by
* one protocol instance. * one protocol instance.
*/ */
#define MAX_STEPS 4 #define MAX_STEPS 4
/* Maximum number of calls of rx handler for all sockets in one select /* Maximum number of calls of rx handler for all sockets in one poll
iteration. RX callbacks are often much more costly so we limit iteration. RX callbacks are often much more costly so we limit
this to gen small latencies */ this to gen small latencies */
#define MAX_RX_STEPS 4 #define MAX_RX_STEPS 4
@ -1023,7 +1024,6 @@ sk_log_error(sock *s, const char *p)
static list sock_list; static list sock_list;
static struct birdsock *current_sock; static struct birdsock *current_sock;
static struct birdsock *stored_sock; static struct birdsock *stored_sock;
static int sock_recalc_fdsets_p;
static inline sock * static inline sock *
sk_next(sock *s) sk_next(sock *s)
@ -1079,7 +1079,6 @@ sk_free(resource *r)
if (s == stored_sock) if (s == stored_sock)
stored_sock = sk_next(s); stored_sock = sk_next(s);
rem_node(&s->n); rem_node(&s->n);
sock_recalc_fdsets_p = 1;
} }
} }
@ -1277,7 +1276,6 @@ static void
sk_insert(sock *s) sk_insert(sock *s)
{ {
add_tail(&sock_list, &s->n); add_tail(&sock_list, &s->n);
sock_recalc_fdsets_p = 1;
} }
static void static void
@ -1329,18 +1327,6 @@ sk_passive_connected(sock *s, int type)
log(L_WARN "SOCK: Cannot get remote IP address for TCP<"); log(L_WARN "SOCK: Cannot get remote IP address for TCP<");
} }
if (fd >= FD_SETSIZE)
{
/* FIXME: Call err_hook instead ? */
log(L_ERR "SOCK: Incoming connection from %I%J (port %d) %s",
t->daddr, ipa_is_link_local(t->daddr) ? t->iface : NULL,
t->dport, "rejected due to FD_SETSIZE limit");
close(fd);
t->fd = -1;
rfree(t);
return 1;
}
if (sk_setup(t) < 0) if (sk_setup(t) < 0)
{ {
/* FIXME: Call err_hook instead ? */ /* FIXME: Call err_hook instead ? */
@ -1416,9 +1402,6 @@ sk_open(sock *s)
if (fd < 0) if (fd < 0)
ERR("socket"); ERR("socket");
if (fd >= FD_SETSIZE)
ERR2("FD_SETSIZE limit reached");
s->fd = fd; s->fd = fd;
if (sk_setup(s) < 0) if (sk_setup(s) < 0)
@ -1696,19 +1679,12 @@ sk_maybe_write(sock *s)
int int
sk_rx_ready(sock *s) sk_rx_ready(sock *s)
{ {
fd_set rd, wr;
struct timeval timo;
int rv; int rv;
struct pollfd pfd = { .fd = s->fd };
FD_ZERO(&rd); pfd.events |= POLLIN;
FD_ZERO(&wr);
FD_SET(s->fd, &rd);
timo.tv_sec = 0;
timo.tv_usec = 0;
redo: redo:
rv = select(s->fd+1, &rd, &wr, NULL, &timo); rv = poll(&pfd, 1, 0);
if ((rv < 0) && (errno == EINTR || errno == EAGAIN)) if ((rv < 0) && (errno == EINTR || errno == EAGAIN))
goto redo; goto redo;
@ -1777,7 +1753,7 @@ sk_send_full(sock *s, unsigned len, struct iface *ifa,
/* sk_read() and sk_write() are called from BFD's event loop */ /* sk_read() and sk_write() are called from BFD's event loop */
int int
sk_read(sock *s) sk_read(sock *s, int revents)
{ {
switch (s->type) switch (s->type)
{ {
@ -1796,6 +1772,11 @@ sk_read(sock *s)
{ {
if (errno != EINTR && errno != EAGAIN) if (errno != EINTR && errno != EAGAIN)
s->err_hook(s, errno); s->err_hook(s, errno);
else if (errno == EAGAIN && !(revents & POLLIN))
{
log(L_ERR "Got EAGAIN from read when revents=%x (without POLLIN)", revents);
s->err_hook(s, 0);
}
} }
else if (!c) else if (!c)
s->err_hook(s, 0); s->err_hook(s, 0);
@ -2068,62 +2049,63 @@ static int short_loops = 0;
void void
io_loop(void) io_loop(void)
{ {
fd_set rd, wr; int poll_tout;
struct timeval timo;
time_t tout; time_t tout;
int hi, events; int nfds, events, pout;
sock *s; sock *s;
node *n; node *n;
int fdmax = 256;
struct pollfd *pfd = xmalloc(fdmax * sizeof(struct pollfd));
watchdog_start1(); watchdog_start1();
sock_recalc_fdsets_p = 1;
for(;;) for(;;)
{ {
events = ev_run_list(&global_event_list); events = ev_run_list(&global_event_list);
timers:
update_times(); update_times();
tout = tm_first_shot(); tout = tm_first_shot();
if (tout <= now) if (tout <= now)
{ {
tm_shot(); tm_shot();
continue; goto timers;
} }
timo.tv_sec = events ? 0 : MIN(tout - now, 3); poll_tout = (events ? 0 : MIN(tout - now, 3)) * 1000; /* Time in milliseconds */
timo.tv_usec = 0;
io_close_event(); io_close_event();
if (sock_recalc_fdsets_p) nfds = 0;
{
sock_recalc_fdsets_p = 0;
FD_ZERO(&rd);
FD_ZERO(&wr);
}
hi = 0;
WALK_LIST(n, sock_list) WALK_LIST(n, sock_list)
{ {
pfd[nfds] = (struct pollfd) { .fd = -1 }; /* everything other set to 0 by this */
s = SKIP_BACK(sock, n, n); s = SKIP_BACK(sock, n, n);
if (s->rx_hook) if (s->rx_hook)
{ {
FD_SET(s->fd, &rd); pfd[nfds].fd = s->fd;
if (s->fd > hi) pfd[nfds].events |= POLLIN;
hi = s->fd;
} }
else
FD_CLR(s->fd, &rd);
if (s->tx_hook && s->ttx != s->tpos) if (s->tx_hook && s->ttx != s->tpos)
{ {
FD_SET(s->fd, &wr); pfd[nfds].fd = s->fd;
if (s->fd > hi) pfd[nfds].events |= POLLOUT;
hi = s->fd; }
if (pfd[nfds].fd != -1)
{
s->index = nfds;
nfds++;
} }
else else
FD_CLR(s->fd, &wr); s->index = -1;
if (nfds >= fdmax)
{
fdmax *= 2;
pfd = xrealloc(pfd, fdmax * sizeof(struct pollfd));
}
} }
/* /*
* Yes, this is racy. But even if the signal comes before this test * Yes, this is racy. But even if the signal comes before this test
* and entering select(), it gets caught on the next timer tick. * and entering poll(), it gets caught on the next timer tick.
*/ */
if (async_config_flag) if (async_config_flag)
@ -2148,18 +2130,18 @@ io_loop(void)
continue; continue;
} }
/* And finally enter select() to find active sockets */ /* And finally enter poll() to find active sockets */
watchdog_stop(); watchdog_stop();
hi = select(hi+1, &rd, &wr, NULL, &timo); pout = poll(pfd, nfds, poll_tout);
watchdog_start(); watchdog_start();
if (hi < 0) if (pout < 0)
{ {
if (errno == EINTR || errno == EAGAIN) if (errno == EINTR || errno == EAGAIN)
continue; continue;
die("select: %m"); die("poll: %m");
} }
if (hi) if (pout)
{ {
/* guaranteed to be non-empty */ /* guaranteed to be non-empty */
current_sock = SKIP_BACK(sock, n, HEAD(sock_list)); current_sock = SKIP_BACK(sock, n, HEAD(sock_list));
@ -2167,23 +2149,29 @@ io_loop(void)
while (current_sock) while (current_sock)
{ {
sock *s = current_sock; sock *s = current_sock;
if (s->index == -1)
{
current_sock = sk_next(s);
goto next;
}
int e; int e;
int steps; int steps;
steps = MAX_STEPS; steps = MAX_STEPS;
if ((s->type >= SK_MAGIC) && FD_ISSET(s->fd, &rd) && s->rx_hook) if (s->fast_rx && (pfd[s->index].revents & (POLLIN | POLLHUP | POLLERR)) && s->rx_hook)
do do
{ {
steps--; steps--;
io_log_event(s->rx_hook, s->data); io_log_event(s->rx_hook, s->data);
e = sk_read(s); e = sk_read(s, pfd[s->index].revents);
if (s != current_sock) if (s != current_sock)
goto next; goto next;
} }
while (e && s->rx_hook && steps); while (e && s->rx_hook && steps);
steps = MAX_STEPS; steps = MAX_STEPS;
if (FD_ISSET(s->fd, &wr)) if (pfd[s->index].revents & POLLOUT)
do do
{ {
steps--; steps--;
@ -2210,13 +2198,17 @@ io_loop(void)
while (current_sock && count < MAX_RX_STEPS) while (current_sock && count < MAX_RX_STEPS)
{ {
sock *s = current_sock; sock *s = current_sock;
int e UNUSED; if (s->index == -1)
{
current_sock = sk_next(s);
goto next2;
}
if ((s->type < SK_MAGIC) && FD_ISSET(s->fd, &rd) && s->rx_hook) if (!s->fast_rx && (pfd[s->index].revents & (POLLIN | POLLHUP | POLLERR)) && s->rx_hook)
{ {
count++; count++;
io_log_event(s->rx_hook, s->data); io_log_event(s->rx_hook, s->data);
e = sk_read(s); sk_read(s, pfd[s->index].revents);
if (s != current_sock) if (s != current_sock)
goto next2; goto next2;
} }

View file

@ -412,46 +412,58 @@ again:
{ {
rte *e, **ee, *best, **pbest, *old_best; rte *e, **ee, *best, **pbest, *old_best;
old_best = n->routes; /*
* Note that old_best may be NULL even if there was an old best route in
* the previous step, because it might be replaced in krt_learn_scan().
* But in that case there is a new valid best route.
*/
old_best = NULL;
best = NULL; best = NULL;
pbest = NULL; pbest = NULL;
ee = &n->routes; ee = &n->routes;
while (e = *ee) while (e = *ee)
{ {
if (e->u.krt.best)
old_best = e;
if (!e->u.krt.seen) if (!e->u.krt.seen)
{ {
*ee = e->next; *ee = e->next;
rte_free(e); rte_free(e);
continue; continue;
} }
if (!best || best->u.krt.metric > e->u.krt.metric) if (!best || best->u.krt.metric > e->u.krt.metric)
{ {
best = e; best = e;
pbest = ee; pbest = ee;
} }
e->u.krt.seen = 0; e->u.krt.seen = 0;
e->u.krt.best = 0;
ee = &e->next; ee = &e->next;
} }
if (!n->routes) if (!n->routes)
{ {
DBG("%I/%d: deleting\n", n->n.prefix, n->n.pxlen); DBG("%I/%d: deleting\n", n->n.prefix, n->n.pxlen);
if (old_best) if (old_best)
{ krt_learn_announce_delete(p, n);
krt_learn_announce_delete(p, n);
n->n.flags &= ~KRF_INSTALLED;
}
FIB_ITERATE_PUT(&fit); FIB_ITERATE_PUT(&fit);
fib_delete(fib, n); fib_delete(fib, n);
goto again; goto again;
} }
best->u.krt.best = 1;
*pbest = best->next; *pbest = best->next;
best->next = n->routes; best->next = n->routes;
n->routes = best; n->routes = best;
if (best != old_best || !(n->n.flags & KRF_INSTALLED) || p->reload)
if ((best != old_best) || p->reload)
{ {
DBG("%I/%d: announcing (metric=%d)\n", n->n.prefix, n->n.pxlen, best->u.krt.metric); DBG("%I/%d: announcing (metric=%d)\n", n->n.prefix, n->n.pxlen, best->u.krt.metric);
krt_learn_announce_update(p, best); krt_learn_announce_update(p, best);
n->n.flags |= KRF_INSTALLED;
} }
else else
DBG("%I/%d: uptodate (metric=%d)\n", n->n.prefix, n->n.pxlen, best->u.krt.metric); DBG("%I/%d: uptodate (metric=%d)\n", n->n.prefix, n->n.pxlen, best->u.krt.metric);
@ -510,31 +522,31 @@ krt_learn_async(struct krt_proto *p, rte *e, int new)
best = n->routes; best = n->routes;
bestp = &n->routes; bestp = &n->routes;
for(gg=&n->routes; g=*gg; gg=&g->next) for(gg=&n->routes; g=*gg; gg=&g->next)
{
if (best->u.krt.metric > g->u.krt.metric) if (best->u.krt.metric > g->u.krt.metric)
{ {
best = g; best = g;
bestp = gg; bestp = gg;
} }
g->u.krt.best = 0;
}
if (best) if (best)
{ {
best->u.krt.best = 1;
*bestp = best->next; *bestp = best->next;
best->next = n->routes; best->next = n->routes;
n->routes = best; n->routes = best;
} }
if (best != old_best) if (best != old_best)
{ {
DBG("krt_learn_async: distributing change\n"); DBG("krt_learn_async: distributing change\n");
if (best) if (best)
{ krt_learn_announce_update(p, best);
krt_learn_announce_update(p, best);
n->n.flags |= KRF_INSTALLED;
}
else else
{ krt_learn_announce_delete(p, n);
n->routes = NULL;
krt_learn_announce_delete(p, n);
n->n.flags &= ~KRF_INSTALLED;
}
} }
} }
@ -559,7 +571,7 @@ krt_dump(struct proto *P)
static void static void
krt_dump_attrs(rte *e) krt_dump_attrs(rte *e)
{ {
debug(" [m=%d,p=%d,t=%d]", e->u.krt.metric, e->u.krt.proto, e->u.krt.type); debug(" [m=%d,p=%d]", e->u.krt.metric, e->u.krt.proto);
} }
#endif #endif

View file

@ -284,17 +284,18 @@ log_switch(int debug, list *l, char *new_syslog_name)
current_log_list = l; current_log_list = l;
#ifdef HAVE_SYSLOG #ifdef HAVE_SYSLOG
if (current_syslog_name && new_syslog_name && char *old_syslog_name = current_syslog_name;
!strcmp(current_syslog_name, new_syslog_name)) current_syslog_name = new_syslog_name;
if (old_syslog_name && new_syslog_name &&
!strcmp(old_syslog_name, new_syslog_name))
return; return;
if (current_syslog_name) if (old_syslog_name)
closelog(); closelog();
if (new_syslog_name) if (new_syslog_name)
openlog(new_syslog_name, LOG_CONS | LOG_NDELAY, LOG_DAEMON); openlog(new_syslog_name, LOG_CONS | LOG_NDELAY, LOG_DAEMON);
current_syslog_name = new_syslog_name;
#endif #endif
} }

View file

@ -450,6 +450,7 @@ cli_connect(sock *s, int size UNUSED)
s->err_hook = cli_err; s->err_hook = cli_err;
s->data = c = cli_new(s); s->data = c = cli_new(s);
s->pool = c->pool; /* We need to have all the socket buffers allocated in the cli pool */ s->pool = c->pool; /* We need to have all the socket buffers allocated in the cli pool */
s->fast_rx = 1;
c->rx_pos = c->rx_buf; c->rx_pos = c->rx_buf;
c->rx_aux = NULL; c->rx_aux = NULL;
rmove(s, c->pool); rmove(s, c->pool);
@ -466,6 +467,7 @@ cli_init_unix(uid_t use_uid, gid_t use_gid)
s->type = SK_UNIX_PASSIVE; s->type = SK_UNIX_PASSIVE;
s->rx_hook = cli_connect; s->rx_hook = cli_connect;
s->rbsize = 1024; s->rbsize = 1024;
s->fast_rx = 1;
/* Return value intentionally ignored */ /* Return value intentionally ignored */
unlink(path_control_socket); unlink(path_control_socket);