Merge branch 'master' into int-new-channels
This commit is contained in:
commit
7a7ac65682
26 changed files with 227 additions and 163 deletions
|
@ -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 <name> {
|
||||||
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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
29
lib/lists.c
29
lib/lists.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
18
lib/lists.h
18
lib/lists.h
|
@ -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 *);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
@ -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--;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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])
|
||||||
|
|
126
sysdep/unix/io.c
126
sysdep/unix/io.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue