mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 01:31:55 +00:00
Merge branch 'master' into int-new-channels
This commit is contained in:
commit
7a7ac65682
@ -318,8 +318,9 @@ protocol rip {
|
||||
<p><descrip>
|
||||
<tag>include "<m/filename/"</tag>
|
||||
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
|
||||
used anywhere in the config file, not just as a top-level option.
|
||||
be a wildcard, in that case matching files are included in alphabetic
|
||||
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>
|
||||
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_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
|
||||
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/.
|
||||
|
||||
@ -1859,6 +1863,11 @@ using the following configuration parameters:
|
||||
in neighbor's implementation of 4B AS extension. Even when disabled
|
||||
(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>
|
||||
Use capability advertisement to advertise optional capabilities. This is
|
||||
standard behavior for newer BGP implementations, but there might be some
|
||||
@ -2054,7 +2063,7 @@ protocol bgp {
|
||||
multihop; # ... which is connected indirectly
|
||||
export filter { # We use non-trivial export rules
|
||||
if source = RTS_STATIC then { # Export only static routes
|
||||
# Assign our community
|
||||
# Assign our community
|
||||
bgp_community.add((65000,64501));
|
||||
# Artificially increase path length
|
||||
# by advertising local AS number twice
|
||||
@ -2263,7 +2272,7 @@ these attributes:
|
||||
|
||||
<tag>ip <cf/krt_prefsrc/</tag> (Linux)
|
||||
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)
|
||||
The realm of the route. Can be used for traffic classification.
|
||||
@ -2608,8 +2617,8 @@ protocol ospf <name> {
|
||||
updates. Default value is 5.
|
||||
|
||||
<tag>priority <M>num</M></tag>
|
||||
On every multiple access network (e.g., the Ethernet) Designed Router
|
||||
and Backup Designed router are elected. These routers have some special
|
||||
On every multiple access network (e.g., the Ethernet) Designated Router
|
||||
and Backup Designated router are elected. These routers have some special
|
||||
functions in the flooding process. Higher priority increases preferences
|
||||
in this election. Routers with priority 0 are not eligible. Default
|
||||
value is 1.
|
||||
|
@ -282,7 +282,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
|
||||
LEN,
|
||||
DEFINED,
|
||||
ADD, DELETE, CONTAINS, RESET,
|
||||
PREPEND, FIRST, LAST, MATCH,
|
||||
PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
|
||||
EMPTY,
|
||||
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 '.' 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_NONAGGREGATED { $$ = f_new_inst(); $$->code = P('a','L'); $$->a1.p = $1; }
|
||||
|
||||
/* Communities */
|
||||
/* This causes one shift/reduce conflict
|
||||
|
@ -1056,6 +1056,14 @@ interpret(struct f_inst *what)
|
||||
res.type = T_INT;
|
||||
res.val.i = as;
|
||||
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':
|
||||
ONEARG;
|
||||
res = v1;
|
||||
|
29
lib/lists.c
29
lib/lists.c
@ -41,7 +41,7 @@ add_tail(list *l, node *n)
|
||||
{
|
||||
node *z = l->tail;
|
||||
|
||||
n->next = (node *) &l->null;
|
||||
n->next = &l->tail_node;
|
||||
n->prev = z;
|
||||
z->next = n;
|
||||
l->tail = n;
|
||||
@ -60,7 +60,7 @@ add_head(list *l, node *n)
|
||||
node *z = l->head;
|
||||
|
||||
n->next = z;
|
||||
n->prev = (node *) &l->head;
|
||||
n->prev = &l->head_node;
|
||||
z->prev = n;
|
||||
l->head = n;
|
||||
}
|
||||
@ -88,7 +88,7 @@ insert_node(node *n, node *after)
|
||||
* rem_node - remove a node from a list
|
||||
* @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
|
||||
rem_node(node *n)
|
||||
@ -96,23 +96,6 @@ rem_node(node *n)
|
||||
node *z = n->prev;
|
||||
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;
|
||||
x->prev = z;
|
||||
n->next = NULL;
|
||||
@ -150,9 +133,9 @@ replace_node(node *old, node *new)
|
||||
LIST_INLINE void
|
||||
init_list(list *l)
|
||||
{
|
||||
l->head = (node *) &l->null;
|
||||
l->head = &l->tail_node;
|
||||
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;
|
||||
q->prev = p;
|
||||
q = l->tail;
|
||||
q->next = (node *) &to->null;
|
||||
q->next = &to->tail_node;
|
||||
to->tail = q;
|
||||
}
|
||||
|
18
lib/lists.h
18
lib/lists.h
@ -26,10 +26,23 @@ typedef struct node {
|
||||
struct node *next, *prev;
|
||||
} node;
|
||||
|
||||
typedef struct list { /* In fact two overlayed nodes */
|
||||
struct node *head, *null, *tail;
|
||||
typedef union list { /* In fact two overlayed nodes */
|
||||
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;
|
||||
|
||||
|
||||
#define NODE (node *)
|
||||
#define HEAD(list) ((void *)((list).head))
|
||||
#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_head(list *, node *);
|
||||
void rem_node(node *);
|
||||
void rem2_node(node *);
|
||||
void add_tail_list(list *, list *);
|
||||
void init_list(list *);
|
||||
void insert_node(node *, node *);
|
||||
|
@ -163,6 +163,7 @@ rfree(void *res)
|
||||
if (r->n.next)
|
||||
rem_node(&r->n);
|
||||
r->class->free(r);
|
||||
r->class = NULL;
|
||||
xfree(r);
|
||||
}
|
||||
|
||||
@ -383,16 +384,9 @@ mb_allocz(pool *p, unsigned size)
|
||||
void *
|
||||
mb_realloc(void *m, unsigned size)
|
||||
{
|
||||
struct mblock *ob = NULL;
|
||||
struct mblock *b = SKIP_BACK(struct mblock, data, m);
|
||||
|
||||
if (m)
|
||||
{
|
||||
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);
|
||||
b = xrealloc(b, sizeof(struct mblock) + size);
|
||||
replace_node(&b->r.n, &b->r.n);
|
||||
b->size = size;
|
||||
return b->data;
|
||||
|
@ -27,6 +27,7 @@ typedef struct birdsock {
|
||||
struct iface *iface; /* Interface; specify this for broad/multicast sockets */
|
||||
|
||||
byte *rbuf, *rpos; /* NULL=allocate automatically */
|
||||
uint fast_rx; /* RX has higher priority in event loop */
|
||||
uint rbsize;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
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_get_first(struct adata *path, u32 *orig_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_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);
|
||||
|
@ -112,7 +112,7 @@ idval:
|
||||
else if (($1->class == (SYM_CONSTANT | T_IP)) && ipa_is_ip4(SYM_VAL($1).ip))
|
||||
$$ = ipa_to_u32(SYM_VAL($1).ip);
|
||||
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);
|
||||
|
||||
c->export_state = ES_DOWN;
|
||||
c->stats.exp_routes = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -299,7 +300,7 @@ channel_do_flush(struct channel *c)
|
||||
static void
|
||||
channel_do_down(struct channel *c)
|
||||
{
|
||||
rem2_node(&c->table_node);
|
||||
rem_node(&c->table_node);
|
||||
rt_unlock_table(c->table);
|
||||
c->proto->active_channels--;
|
||||
|
||||
|
@ -232,8 +232,8 @@ typedef struct rte {
|
||||
struct { /* Routes generated by krt sync (both temporary and inherited ones) */
|
||||
s8 src; /* Alleged route source (see krt.h) */
|
||||
u8 proto; /* Kernel source protocol ID */
|
||||
u8 type; /* Kernel route type */
|
||||
u8 seen; /* Seen during last scan */
|
||||
u8 best; /* Best route in network, propagated to core */
|
||||
u32 metric; /* Kernel metric */
|
||||
} krt;
|
||||
} u;
|
||||
|
@ -872,7 +872,7 @@ bfd_notify_hook(sock *sk, int len)
|
||||
WALK_LIST_FIRST(s, tmp_list)
|
||||
{
|
||||
bfd_lock_sessions(p);
|
||||
rem2_node(&s->n);
|
||||
rem_node(&s->n);
|
||||
state = s->loc_state;
|
||||
diag = s->loc_diag;
|
||||
bfd_unlock_sessions(p);
|
||||
|
@ -576,7 +576,7 @@ sockets_close_fds(struct birdloop *loop)
|
||||
loop->close_scheduled = 0;
|
||||
}
|
||||
|
||||
int sk_read(sock *s);
|
||||
int sk_read(sock *s, int revents);
|
||||
int sk_write(sock *s);
|
||||
|
||||
static void
|
||||
@ -605,7 +605,7 @@ sockets_fire(struct birdloop *loop)
|
||||
|
||||
if (pfd->revents & POLLIN)
|
||||
while (e && *psk && (*psk)->rx_hook)
|
||||
e = sk_read(*psk);
|
||||
e = sk_read(*psk, 0);
|
||||
|
||||
e = 1;
|
||||
if (pfd->revents & POLLOUT)
|
||||
|
@ -374,6 +374,8 @@ bgp_conn_enter_established_state(struct bgp_conn *conn)
|
||||
if (ipa_zero(p->source_addr))
|
||||
p->source_addr = conn->sk->saddr;
|
||||
|
||||
conn->sk->fast_rx = 0;
|
||||
|
||||
p->conn = conn;
|
||||
p->last_error_class = 0;
|
||||
p->last_error_code = 0;
|
||||
@ -666,6 +668,10 @@ bgp_keepalive_timeout(timer *t)
|
||||
|
||||
DBG("BGP: Keepalive timer\n");
|
||||
bgp_schedule_packet(conn, PKT_KEEPALIVE);
|
||||
|
||||
/* Kick TX a bit faster */
|
||||
if (ev_active(conn->tx_ev))
|
||||
ev_run(conn->tx_ev);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -696,6 +702,7 @@ bgp_setup_sk(struct bgp_conn *conn, sock *s)
|
||||
{
|
||||
s->data = conn;
|
||||
s->err_hook = bgp_sock_err;
|
||||
s->fast_rx = 1;
|
||||
conn->sk = s;
|
||||
}
|
||||
|
||||
@ -813,7 +820,13 @@ bgp_incoming_connection(sock *sk, int dummy UNUSED)
|
||||
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) &&
|
||||
(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_conn_enter_idle_state(p->conn);
|
||||
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",
|
||||
|
@ -163,6 +163,14 @@ bgp_put_cap_rr(struct bgp_proto *p UNUSED, byte *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 *
|
||||
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;
|
||||
}
|
||||
|
||||
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 *
|
||||
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;
|
||||
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 */
|
||||
if (cl % 4 != 2)
|
||||
goto err;
|
||||
@ -867,12 +873,6 @@ bgp_parse_capabilities(struct bgp_conn *conn, byte *opt, int len)
|
||||
conn->peer_enhanced_refresh_support = 1;
|
||||
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 */
|
||||
}
|
||||
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))
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
if (ifa->type != old_type)
|
||||
|
@ -108,6 +108,7 @@ ospf_neigh_down(struct ospf_neighbor *n)
|
||||
{
|
||||
struct ospf_iface *ifa = n->ifa;
|
||||
struct ospf_proto *p = ifa->oa->po;
|
||||
u32 rid = n->rid;
|
||||
|
||||
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);
|
||||
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))
|
||||
s_add_tail(&p->lsal, SNODE en);
|
||||
|
||||
if (en->lsa_body == NULL)
|
||||
if (!en->nf || !en->lsa_body)
|
||||
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"); }
|
||||
| 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"); }
|
||||
| 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 tos { RIP_IFACE->tx_tos = $2; }
|
||||
| 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->u.krt.src = src;
|
||||
e->u.krt.proto = src2;
|
||||
|
||||
/* These are probably too Linux-specific */
|
||||
e->u.krt.type = 0;
|
||||
e->u.krt.seen = 0;
|
||||
e->u.krt.best = 0;
|
||||
e->u.krt.metric = 0;
|
||||
|
||||
if (scan)
|
||||
|
@ -1204,7 +1204,8 @@ nl_parse_route(struct nlmsghdr *h, int scan)
|
||||
e->net = net;
|
||||
e->u.krt.src = src;
|
||||
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;
|
||||
|
||||
if (a[RTA_PRIORITY])
|
||||
|
126
sysdep/unix/io.c
126
sysdep/unix/io.c
@ -19,6 +19,7 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/un.h>
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
@ -41,12 +42,12 @@
|
||||
#include "lib/sysio.h"
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
#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
|
||||
this to gen small latencies */
|
||||
#define MAX_RX_STEPS 4
|
||||
@ -1023,7 +1024,6 @@ sk_log_error(sock *s, const char *p)
|
||||
static list sock_list;
|
||||
static struct birdsock *current_sock;
|
||||
static struct birdsock *stored_sock;
|
||||
static int sock_recalc_fdsets_p;
|
||||
|
||||
static inline sock *
|
||||
sk_next(sock *s)
|
||||
@ -1079,7 +1079,6 @@ sk_free(resource *r)
|
||||
if (s == stored_sock)
|
||||
stored_sock = sk_next(s);
|
||||
rem_node(&s->n);
|
||||
sock_recalc_fdsets_p = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1277,7 +1276,6 @@ static void
|
||||
sk_insert(sock *s)
|
||||
{
|
||||
add_tail(&sock_list, &s->n);
|
||||
sock_recalc_fdsets_p = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1329,18 +1327,6 @@ sk_passive_connected(sock *s, int type)
|
||||
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)
|
||||
{
|
||||
/* FIXME: Call err_hook instead ? */
|
||||
@ -1416,9 +1402,6 @@ sk_open(sock *s)
|
||||
if (fd < 0)
|
||||
ERR("socket");
|
||||
|
||||
if (fd >= FD_SETSIZE)
|
||||
ERR2("FD_SETSIZE limit reached");
|
||||
|
||||
s->fd = fd;
|
||||
|
||||
if (sk_setup(s) < 0)
|
||||
@ -1696,19 +1679,12 @@ sk_maybe_write(sock *s)
|
||||
int
|
||||
sk_rx_ready(sock *s)
|
||||
{
|
||||
fd_set rd, wr;
|
||||
struct timeval timo;
|
||||
int rv;
|
||||
|
||||
FD_ZERO(&rd);
|
||||
FD_ZERO(&wr);
|
||||
FD_SET(s->fd, &rd);
|
||||
|
||||
timo.tv_sec = 0;
|
||||
timo.tv_usec = 0;
|
||||
struct pollfd pfd = { .fd = s->fd };
|
||||
pfd.events |= POLLIN;
|
||||
|
||||
redo:
|
||||
rv = select(s->fd+1, &rd, &wr, NULL, &timo);
|
||||
rv = poll(&pfd, 1, 0);
|
||||
|
||||
if ((rv < 0) && (errno == EINTR || errno == EAGAIN))
|
||||
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 */
|
||||
|
||||
int
|
||||
sk_read(sock *s)
|
||||
sk_read(sock *s, int revents)
|
||||
{
|
||||
switch (s->type)
|
||||
{
|
||||
@ -1796,6 +1772,11 @@ sk_read(sock *s)
|
||||
{
|
||||
if (errno != EINTR && errno != EAGAIN)
|
||||
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)
|
||||
s->err_hook(s, 0);
|
||||
@ -2068,62 +2049,63 @@ static int short_loops = 0;
|
||||
void
|
||||
io_loop(void)
|
||||
{
|
||||
fd_set rd, wr;
|
||||
struct timeval timo;
|
||||
int poll_tout;
|
||||
time_t tout;
|
||||
int hi, events;
|
||||
int nfds, events, pout;
|
||||
sock *s;
|
||||
node *n;
|
||||
int fdmax = 256;
|
||||
struct pollfd *pfd = xmalloc(fdmax * sizeof(struct pollfd));
|
||||
|
||||
watchdog_start1();
|
||||
sock_recalc_fdsets_p = 1;
|
||||
for(;;)
|
||||
{
|
||||
events = ev_run_list(&global_event_list);
|
||||
timers:
|
||||
update_times();
|
||||
tout = tm_first_shot();
|
||||
if (tout <= now)
|
||||
{
|
||||
tm_shot();
|
||||
continue;
|
||||
goto timers;
|
||||
}
|
||||
timo.tv_sec = events ? 0 : MIN(tout - now, 3);
|
||||
timo.tv_usec = 0;
|
||||
poll_tout = (events ? 0 : MIN(tout - now, 3)) * 1000; /* Time in milliseconds */
|
||||
|
||||
io_close_event();
|
||||
|
||||
if (sock_recalc_fdsets_p)
|
||||
{
|
||||
sock_recalc_fdsets_p = 0;
|
||||
FD_ZERO(&rd);
|
||||
FD_ZERO(&wr);
|
||||
}
|
||||
|
||||
hi = 0;
|
||||
nfds = 0;
|
||||
WALK_LIST(n, sock_list)
|
||||
{
|
||||
pfd[nfds] = (struct pollfd) { .fd = -1 }; /* everything other set to 0 by this */
|
||||
s = SKIP_BACK(sock, n, n);
|
||||
if (s->rx_hook)
|
||||
{
|
||||
FD_SET(s->fd, &rd);
|
||||
if (s->fd > hi)
|
||||
hi = s->fd;
|
||||
pfd[nfds].fd = s->fd;
|
||||
pfd[nfds].events |= POLLIN;
|
||||
}
|
||||
else
|
||||
FD_CLR(s->fd, &rd);
|
||||
if (s->tx_hook && s->ttx != s->tpos)
|
||||
{
|
||||
FD_SET(s->fd, &wr);
|
||||
if (s->fd > hi)
|
||||
hi = s->fd;
|
||||
pfd[nfds].fd = s->fd;
|
||||
pfd[nfds].events |= POLLOUT;
|
||||
}
|
||||
if (pfd[nfds].fd != -1)
|
||||
{
|
||||
s->index = nfds;
|
||||
nfds++;
|
||||
}
|
||||
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
|
||||
* 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)
|
||||
@ -2148,18 +2130,18 @@ io_loop(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* And finally enter select() to find active sockets */
|
||||
/* And finally enter poll() to find active sockets */
|
||||
watchdog_stop();
|
||||
hi = select(hi+1, &rd, &wr, NULL, &timo);
|
||||
pout = poll(pfd, nfds, poll_tout);
|
||||
watchdog_start();
|
||||
|
||||
if (hi < 0)
|
||||
if (pout < 0)
|
||||
{
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
continue;
|
||||
die("select: %m");
|
||||
die("poll: %m");
|
||||
}
|
||||
if (hi)
|
||||
if (pout)
|
||||
{
|
||||
/* guaranteed to be non-empty */
|
||||
current_sock = SKIP_BACK(sock, n, HEAD(sock_list));
|
||||
@ -2167,23 +2149,29 @@ io_loop(void)
|
||||
while (current_sock)
|
||||
{
|
||||
sock *s = current_sock;
|
||||
if (s->index == -1)
|
||||
{
|
||||
current_sock = sk_next(s);
|
||||
goto next;
|
||||
}
|
||||
|
||||
int e;
|
||||
int 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
|
||||
{
|
||||
steps--;
|
||||
io_log_event(s->rx_hook, s->data);
|
||||
e = sk_read(s);
|
||||
e = sk_read(s, pfd[s->index].revents);
|
||||
if (s != current_sock)
|
||||
goto next;
|
||||
}
|
||||
while (e && s->rx_hook && steps);
|
||||
|
||||
steps = MAX_STEPS;
|
||||
if (FD_ISSET(s->fd, &wr))
|
||||
if (pfd[s->index].revents & POLLOUT)
|
||||
do
|
||||
{
|
||||
steps--;
|
||||
@ -2210,13 +2198,17 @@ io_loop(void)
|
||||
while (current_sock && count < MAX_RX_STEPS)
|
||||
{
|
||||
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++;
|
||||
io_log_event(s->rx_hook, s->data);
|
||||
e = sk_read(s);
|
||||
sk_read(s, pfd[s->index].revents);
|
||||
if (s != current_sock)
|
||||
goto next2;
|
||||
}
|
||||
|
@ -412,46 +412,58 @@ again:
|
||||
{
|
||||
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;
|
||||
pbest = NULL;
|
||||
ee = &n->routes;
|
||||
while (e = *ee)
|
||||
{
|
||||
if (e->u.krt.best)
|
||||
old_best = e;
|
||||
|
||||
if (!e->u.krt.seen)
|
||||
{
|
||||
*ee = e->next;
|
||||
rte_free(e);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!best || best->u.krt.metric > e->u.krt.metric)
|
||||
{
|
||||
best = e;
|
||||
pbest = ee;
|
||||
}
|
||||
|
||||
e->u.krt.seen = 0;
|
||||
e->u.krt.best = 0;
|
||||
ee = &e->next;
|
||||
}
|
||||
if (!n->routes)
|
||||
{
|
||||
DBG("%I/%d: deleting\n", n->n.prefix, n->n.pxlen);
|
||||
if (old_best)
|
||||
{
|
||||
krt_learn_announce_delete(p, n);
|
||||
n->n.flags &= ~KRF_INSTALLED;
|
||||
}
|
||||
krt_learn_announce_delete(p, n);
|
||||
|
||||
FIB_ITERATE_PUT(&fit);
|
||||
fib_delete(fib, n);
|
||||
goto again;
|
||||
}
|
||||
|
||||
best->u.krt.best = 1;
|
||||
*pbest = best->next;
|
||||
best->next = n->routes;
|
||||
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);
|
||||
krt_learn_announce_update(p, best);
|
||||
n->n.flags |= KRF_INSTALLED;
|
||||
}
|
||||
else
|
||||
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;
|
||||
bestp = &n->routes;
|
||||
for(gg=&n->routes; g=*gg; gg=&g->next)
|
||||
{
|
||||
if (best->u.krt.metric > g->u.krt.metric)
|
||||
{
|
||||
best = g;
|
||||
bestp = gg;
|
||||
}
|
||||
|
||||
g->u.krt.best = 0;
|
||||
}
|
||||
|
||||
if (best)
|
||||
{
|
||||
best->u.krt.best = 1;
|
||||
*bestp = best->next;
|
||||
best->next = n->routes;
|
||||
n->routes = best;
|
||||
}
|
||||
|
||||
if (best != old_best)
|
||||
{
|
||||
DBG("krt_learn_async: distributing change\n");
|
||||
if (best)
|
||||
{
|
||||
krt_learn_announce_update(p, best);
|
||||
n->n.flags |= KRF_INSTALLED;
|
||||
}
|
||||
krt_learn_announce_update(p, best);
|
||||
else
|
||||
{
|
||||
n->routes = NULL;
|
||||
krt_learn_announce_delete(p, n);
|
||||
n->n.flags &= ~KRF_INSTALLED;
|
||||
}
|
||||
krt_learn_announce_delete(p, n);
|
||||
}
|
||||
}
|
||||
|
||||
@ -559,7 +571,7 @@ krt_dump(struct proto *P)
|
||||
static void
|
||||
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
|
||||
|
@ -284,17 +284,18 @@ log_switch(int debug, list *l, char *new_syslog_name)
|
||||
current_log_list = l;
|
||||
|
||||
#ifdef HAVE_SYSLOG
|
||||
if (current_syslog_name && new_syslog_name &&
|
||||
!strcmp(current_syslog_name, new_syslog_name))
|
||||
char *old_syslog_name = current_syslog_name;
|
||||
current_syslog_name = new_syslog_name;
|
||||
|
||||
if (old_syslog_name && new_syslog_name &&
|
||||
!strcmp(old_syslog_name, new_syslog_name))
|
||||
return;
|
||||
|
||||
if (current_syslog_name)
|
||||
if (old_syslog_name)
|
||||
closelog();
|
||||
|
||||
if (new_syslog_name)
|
||||
openlog(new_syslog_name, LOG_CONS | LOG_NDELAY, LOG_DAEMON);
|
||||
|
||||
current_syslog_name = new_syslog_name;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -450,6 +450,7 @@ cli_connect(sock *s, int size UNUSED)
|
||||
s->err_hook = cli_err;
|
||||
s->data = c = cli_new(s);
|
||||
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_aux = NULL;
|
||||
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->rx_hook = cli_connect;
|
||||
s->rbsize = 1024;
|
||||
s->fast_rx = 1;
|
||||
|
||||
/* Return value intentionally ignored */
|
||||
unlink(path_control_socket);
|
||||
|
Loading…
Reference in New Issue
Block a user