mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2025-03-21 13:57:04 +00:00
Merge branch 'maarten' into mq-ordered
This commit is contained in:
commit
c217fe593a
@ -1094,8 +1094,10 @@ bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len)
|
|||||||
ADVANCE(pos, len, alen);
|
ADVANCE(pos, len, alen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define FAIL(KEY) ({ STATS(KEY); goto fail; })
|
||||||
|
|
||||||
if (s->err_withdraw)
|
if (s->err_withdraw)
|
||||||
goto withdraw;
|
FAIL(bad_attribute);
|
||||||
|
|
||||||
/* If there is no reachability NLRI, we are finished */
|
/* If there is no reachability NLRI, we are finished */
|
||||||
if (!s->ip_reach_len && !s->mp_reach_len)
|
if (!s->ip_reach_len && !s->mp_reach_len)
|
||||||
@ -1104,10 +1106,10 @@ bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len)
|
|||||||
|
|
||||||
/* Handle missing mandatory attributes; RFC 7606 3 (d) */
|
/* Handle missing mandatory attributes; RFC 7606 3 (d) */
|
||||||
if (!BIT32_TEST(s->attrs_seen, BA_ORIGIN))
|
if (!BIT32_TEST(s->attrs_seen, BA_ORIGIN))
|
||||||
{ REPORT(NO_MANDATORY, "ORIGIN"); goto withdraw; }
|
{ REPORT(NO_MANDATORY, "ORIGIN"); FAIL(no_mandatory); }
|
||||||
|
|
||||||
if (!BIT32_TEST(s->attrs_seen, BA_AS_PATH))
|
if (!BIT32_TEST(s->attrs_seen, BA_AS_PATH))
|
||||||
{ REPORT(NO_MANDATORY, "AS_PATH"); goto withdraw; }
|
{ REPORT(NO_MANDATORY, "AS_PATH"); FAIL(no_mandatory); }
|
||||||
|
|
||||||
/* When receiving attributes from non-AS4-aware BGP speaker, we have to
|
/* When receiving attributes from non-AS4-aware BGP speaker, we have to
|
||||||
reconstruct AS_PATH and AGGREGATOR attributes; RFC 6793 4.2.3 */
|
reconstruct AS_PATH and AGGREGATOR attributes; RFC 6793 4.2.3 */
|
||||||
@ -1116,19 +1118,19 @@ bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len)
|
|||||||
|
|
||||||
/* Reject routes with our ASN in AS_PATH attribute */
|
/* Reject routes with our ASN in AS_PATH attribute */
|
||||||
if (bgp_as_path_loopy(p, attrs, p->local_as))
|
if (bgp_as_path_loopy(p, attrs, p->local_as))
|
||||||
goto withdraw;
|
FAIL(loopy);
|
||||||
|
|
||||||
/* Reject routes with our Confederation ID in AS_PATH attribute; RFC 5065 4.0 */
|
/* Reject routes with our Confederation ID in AS_PATH attribute; RFC 5065 4.0 */
|
||||||
if ((p->public_as != p->local_as) && bgp_as_path_loopy(p, attrs, p->public_as))
|
if ((p->public_as != p->local_as) && bgp_as_path_loopy(p, attrs, p->public_as))
|
||||||
goto withdraw;
|
FAIL(loopy);
|
||||||
|
|
||||||
/* Reject routes with our Router ID in ORIGINATOR_ID attribute; RFC 4456 8 */
|
/* Reject routes with our Router ID in ORIGINATOR_ID attribute; RFC 4456 8 */
|
||||||
if (p->is_internal && bgp_originator_id_loopy(p, attrs))
|
if (p->is_internal && bgp_originator_id_loopy(p, attrs))
|
||||||
goto withdraw;
|
FAIL(loopy);
|
||||||
|
|
||||||
/* Reject routes with our Cluster ID in CLUSTER_LIST attribute; RFC 4456 8 */
|
/* Reject routes with our Cluster ID in CLUSTER_LIST attribute; RFC 4456 8 */
|
||||||
if (p->rr_client && bgp_cluster_list_loopy(p, attrs))
|
if (p->rr_client && bgp_cluster_list_loopy(p, attrs))
|
||||||
goto withdraw;
|
FAIL(loopy);
|
||||||
|
|
||||||
/* If there is no local preference, define one */
|
/* If there is no local preference, define one */
|
||||||
if (!BIT32_TEST(s->attrs_seen, BA_LOCAL_PREF))
|
if (!BIT32_TEST(s->attrs_seen, BA_LOCAL_PREF))
|
||||||
@ -1141,8 +1143,11 @@ framing_error:
|
|||||||
/* RFC 7606 4 - handle attribute framing errors */
|
/* RFC 7606 4 - handle attribute framing errors */
|
||||||
REPORT("Malformed attribute list - framing error (%u/%u) at %d",
|
REPORT("Malformed attribute list - framing error (%u/%u) at %d",
|
||||||
alen, len, (int) (pos - s->attrs));
|
alen, len, (int) (pos - s->attrs));
|
||||||
|
FAIL(bad_alist);
|
||||||
|
|
||||||
withdraw:
|
#undef FAIL
|
||||||
|
|
||||||
|
fail:
|
||||||
/* RFC 7606 5.2 - handle missing NLRI during errors */
|
/* RFC 7606 5.2 - handle missing NLRI during errors */
|
||||||
if (!s->ip_reach_len && !s->mp_reach_len)
|
if (!s->ip_reach_len && !s->mp_reach_len)
|
||||||
bgp_parse_error(s, 1);
|
bgp_parse_error(s, 1);
|
||||||
@ -2009,11 +2014,13 @@ bgp_get_attr(eattr *a, byte *buf, int buflen)
|
|||||||
void
|
void
|
||||||
bgp_get_route_info(rte *e, byte *buf, ea_list *attrs)
|
bgp_get_route_info(rte *e, byte *buf, ea_list *attrs)
|
||||||
{
|
{
|
||||||
|
struct bgp_proto *bgp = (void *) e->attrs->src->proto;
|
||||||
eattr *p = ea_find(attrs, EA_CODE(EAP_BGP, BA_AS_PATH));
|
eattr *p = ea_find(attrs, EA_CODE(EAP_BGP, BA_AS_PATH));
|
||||||
eattr *o = ea_find(attrs, EA_CODE(EAP_BGP, BA_ORIGIN));
|
eattr *o = ea_find(attrs, EA_CODE(EAP_BGP, BA_ORIGIN));
|
||||||
u32 origas;
|
u32 origas;
|
||||||
|
|
||||||
buf += bsprintf(buf, " (%d", e->pref);
|
char c = bgp->is_internal ? 'I' : (bgp->is_interior ? 'C' : 'E');
|
||||||
|
buf += bsprintf(buf, " %c (%d", c, e->pref);
|
||||||
|
|
||||||
if (e->u.bgp.suppressed)
|
if (e->u.bgp.suppressed)
|
||||||
buf += bsprintf(buf, "-");
|
buf += bsprintf(buf, "-");
|
||||||
|
@ -1328,6 +1328,8 @@ bgp_start(struct proto *P)
|
|||||||
p->source_addr = p->cf->local_ip;
|
p->source_addr = p->cf->local_ip;
|
||||||
p->link_addr = IPA_NONE;
|
p->link_addr = IPA_NONE;
|
||||||
|
|
||||||
|
memset(&(p->stats), 0, sizeof(struct bgp_stats));
|
||||||
|
|
||||||
/* Lock all channels when in GR recovery mode */
|
/* Lock all channels when in GR recovery mode */
|
||||||
if (p->p.gr_recovery && p->cf->gr_mode)
|
if (p->p.gr_recovery && p->cf->gr_mode)
|
||||||
{
|
{
|
||||||
@ -2104,6 +2106,15 @@ bgp_show_proto_info(struct proto *P)
|
|||||||
tm_remains(p->conn->keepalive_timer), p->conn->keepalive_time);
|
tm_remains(p->conn->keepalive_timer), p->conn->keepalive_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct bgp_stats *s = &p->stats;
|
||||||
|
cli_msg(-1006, " Statistics:");
|
||||||
|
cli_msg(-1006, " rx-open %u rx-update %u rx-notify %u rx-keepalive %u rx-refresh %u",
|
||||||
|
s->rx_pkts[0], s->rx_pkts[1], s->rx_pkts[2], s->rx_pkts[3], s->rx_pkts[4]);
|
||||||
|
cli_msg(-1006, " tx-open %u tx-update %u tx-notify %u tx-keepalive %u tx-refresh %u",
|
||||||
|
s->tx_pkts[0], s->tx_pkts[1], s->tx_pkts[2], s->tx_pkts[3], s->tx_pkts[4]);
|
||||||
|
cli_msg(-1006, " bad-alist %u bad-attribute %u bad-next-hop %u no-mandatory %u loopy %u",
|
||||||
|
s->bad_alist, s->bad_attribute, s->bad_next_hop, s->no_mandatory, s->loopy);
|
||||||
|
|
||||||
if ((p->last_error_class != BE_NONE) &&
|
if ((p->last_error_class != BE_NONE) &&
|
||||||
(p->last_error_class != BE_MAN_DOWN))
|
(p->last_error_class != BE_MAN_DOWN))
|
||||||
{
|
{
|
||||||
@ -2120,6 +2131,9 @@ bgp_show_proto_info(struct proto *P)
|
|||||||
|
|
||||||
if (c->c.channel_state == CS_UP)
|
if (c->c.channel_state == CS_UP)
|
||||||
{
|
{
|
||||||
|
cli_msg(-1006, " Enqueued updates: %u", c->bucket_hash.count);
|
||||||
|
cli_msg(-1006, " Enqueued prefixes: %u", c->prefix_hash.count);
|
||||||
|
|
||||||
if (ipa_zero(c->link_addr))
|
if (ipa_zero(c->link_addr))
|
||||||
cli_msg(-1006, " BGP Next hop: %I", c->next_hop_addr);
|
cli_msg(-1006, " BGP Next hop: %I", c->next_hop_addr);
|
||||||
else
|
else
|
||||||
|
@ -55,6 +55,8 @@ struct eattr;
|
|||||||
#define BGP_AF_FLOW4 BGP_AF( BGP_AFI_IPV4, BGP_SAFI_FLOW )
|
#define BGP_AF_FLOW4 BGP_AF( BGP_AFI_IPV4, BGP_SAFI_FLOW )
|
||||||
#define BGP_AF_FLOW6 BGP_AF( BGP_AFI_IPV6, BGP_SAFI_FLOW )
|
#define BGP_AF_FLOW6 BGP_AF( BGP_AFI_IPV6, BGP_SAFI_FLOW )
|
||||||
|
|
||||||
|
#define BGP_PKT_TYPES 5 /* PKT_OPEN .. PKT_ROUTE_REFRESH */
|
||||||
|
|
||||||
|
|
||||||
struct bgp_write_state;
|
struct bgp_write_state;
|
||||||
struct bgp_parse_state;
|
struct bgp_parse_state;
|
||||||
@ -196,6 +198,14 @@ struct bgp_caps {
|
|||||||
#define WALK_AF_CAPS(caps,ac) \
|
#define WALK_AF_CAPS(caps,ac) \
|
||||||
for (ac = caps->af_data; ac < &caps->af_data[caps->af_count]; ac++)
|
for (ac = caps->af_data; ac < &caps->af_data[caps->af_count]; ac++)
|
||||||
|
|
||||||
|
struct bgp_stats {
|
||||||
|
uint rx_pkts[BGP_PKT_TYPES], tx_pkts[BGP_PKT_TYPES];
|
||||||
|
uint bad_alist, bad_attribute, bad_next_hop, no_mandatory, loopy;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef PARSER
|
||||||
|
#define STATS(KEY) ({ p->stats.KEY++; })
|
||||||
|
#endif
|
||||||
|
|
||||||
struct bgp_socket {
|
struct bgp_socket {
|
||||||
node n; /* Node in global bgp_sockets */
|
node n; /* Node in global bgp_sockets */
|
||||||
@ -254,6 +264,7 @@ struct bgp_proto {
|
|||||||
struct neighbor *neigh; /* Neighbor entry corresponding to remote ip, NULL if multihop */
|
struct neighbor *neigh; /* Neighbor entry corresponding to remote ip, NULL if multihop */
|
||||||
struct bgp_socket *sock; /* Shared listening socket */
|
struct bgp_socket *sock; /* Shared listening socket */
|
||||||
struct bfd_request *bfd_req; /* BFD request, if BFD is used */
|
struct bfd_request *bfd_req; /* BFD request, if BFD is used */
|
||||||
|
struct bgp_stats stats; /* Packet statistics */
|
||||||
ip_addr source_addr; /* Local address used as an advertised next hop */
|
ip_addr source_addr; /* Local address used as an advertised next hop */
|
||||||
ip_addr link_addr; /* Link-local version of source_addr */
|
ip_addr link_addr; /* Link-local version of source_addr */
|
||||||
event *event; /* Event for respawning and shutting process */
|
event *event; /* Event for respawning and shutting process */
|
||||||
|
@ -2174,6 +2174,7 @@ bgp_rx_end_mark(struct bgp_parse_state *s, u32 afi)
|
|||||||
static inline void
|
static inline void
|
||||||
bgp_decode_nlri(struct bgp_parse_state *s, u32 afi, byte *nlri, uint len, ea_list *ea, byte *nh, uint nh_len)
|
bgp_decode_nlri(struct bgp_parse_state *s, u32 afi, byte *nlri, uint len, ea_list *ea, byte *nh, uint nh_len)
|
||||||
{
|
{
|
||||||
|
struct bgp_proto *p = s->proto;
|
||||||
struct bgp_channel *c = bgp_get_channel(s->proto, afi);
|
struct bgp_channel *c = bgp_get_channel(s->proto, afi);
|
||||||
rta *a = NULL;
|
rta *a = NULL;
|
||||||
|
|
||||||
@ -2207,7 +2208,10 @@ bgp_decode_nlri(struct bgp_parse_state *s, u32 afi, byte *nlri, uint len, ea_lis
|
|||||||
|
|
||||||
/* Handle withdraw during next hop decoding */
|
/* Handle withdraw during next hop decoding */
|
||||||
if (s->err_withdraw)
|
if (s->err_withdraw)
|
||||||
|
{
|
||||||
|
STATS(bad_next_hop);
|
||||||
a = NULL;
|
a = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c->desc->decode_nlri(s, nlri, len, a);
|
c->desc->decode_nlri(s, nlri, len, a);
|
||||||
@ -2446,6 +2450,7 @@ found:
|
|||||||
static inline int
|
static inline int
|
||||||
bgp_send(struct bgp_conn *conn, uint type, uint len)
|
bgp_send(struct bgp_conn *conn, uint type, uint len)
|
||||||
{
|
{
|
||||||
|
struct bgp_proto *p = conn->bgp;
|
||||||
sock *sk = conn->sk;
|
sock *sk = conn->sk;
|
||||||
byte *buf = sk->tbuf;
|
byte *buf = sk->tbuf;
|
||||||
|
|
||||||
@ -2453,6 +2458,7 @@ bgp_send(struct bgp_conn *conn, uint type, uint len)
|
|||||||
put_u16(buf+16, len);
|
put_u16(buf+16, len);
|
||||||
buf[18] = type;
|
buf[18] = type;
|
||||||
|
|
||||||
|
STATS(tx_pkts[type - 1]);
|
||||||
return sk_send(sk, len);
|
return sk_send(sk, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2812,13 +2818,22 @@ bgp_rx_keepalive(struct bgp_conn *conn)
|
|||||||
static void
|
static void
|
||||||
bgp_rx_packet(struct bgp_conn *conn, byte *pkt, uint len)
|
bgp_rx_packet(struct bgp_conn *conn, byte *pkt, uint len)
|
||||||
{
|
{
|
||||||
|
struct bgp_proto *p = conn->bgp;
|
||||||
byte type = pkt[18];
|
byte type = pkt[18];
|
||||||
|
|
||||||
DBG("BGP: Got packet %02x (%d bytes)\n", type, len);
|
DBG("BGP: Got packet %02x (%d bytes)\n", type, len);
|
||||||
|
|
||||||
if (conn->bgp->p.mrtdump & MD_MESSAGES)
|
if (p->p.mrtdump & MD_MESSAGES)
|
||||||
mrt_dump_bgp_packet(conn, pkt, len);
|
mrt_dump_bgp_packet(conn, pkt, len);
|
||||||
|
|
||||||
|
if (type < PKT_OPEN || type > PKT_ROUTE_REFRESH)
|
||||||
|
{
|
||||||
|
bgp_error(conn, 1, 3, pkt+18, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATS(rx_pkts[type - 1]);
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case PKT_OPEN: return bgp_rx_open(conn, pkt, len);
|
case PKT_OPEN: return bgp_rx_open(conn, pkt, len);
|
||||||
@ -2826,7 +2841,6 @@ bgp_rx_packet(struct bgp_conn *conn, byte *pkt, uint len)
|
|||||||
case PKT_NOTIFICATION: return bgp_rx_notification(conn, pkt, len);
|
case PKT_NOTIFICATION: return bgp_rx_notification(conn, pkt, len);
|
||||||
case PKT_KEEPALIVE: return bgp_rx_keepalive(conn);
|
case PKT_KEEPALIVE: return bgp_rx_keepalive(conn);
|
||||||
case PKT_ROUTE_REFRESH: return bgp_rx_route_refresh(conn, pkt, len);
|
case PKT_ROUTE_REFRESH: return bgp_rx_route_refresh(conn, pkt, len);
|
||||||
default: bgp_error(conn, 1, 3, pkt+18, 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,6 +135,8 @@ stat_route:
|
|||||||
|
|
||||||
stat_route_item:
|
stat_route_item:
|
||||||
cmd { *this_srt_last_cmd = $1; this_srt_last_cmd = &($1->next); }
|
cmd { *this_srt_last_cmd = $1; this_srt_last_cmd = &($1->next); }
|
||||||
|
| PREFERENCE expr ';' { this_srt->preference = $2; check_u16($2); }
|
||||||
|
| DISTANCE expr ';' { this_srt->preference = $2; check_u16($2); }
|
||||||
;
|
;
|
||||||
|
|
||||||
stat_route_opts:
|
stat_route_opts:
|
||||||
|
@ -53,7 +53,7 @@ static void
|
|||||||
static_announce_rte(struct static_proto *p, struct static_route *r)
|
static_announce_rte(struct static_proto *p, struct static_route *r)
|
||||||
{
|
{
|
||||||
rta *a = allocz(RTA_MAX_SIZE);
|
rta *a = allocz(RTA_MAX_SIZE);
|
||||||
a->src = p->p.main_source;
|
a->src = rt_get_source(&p->p, r->preference);
|
||||||
a->source = RTS_STATIC;
|
a->source = RTS_STATIC;
|
||||||
a->scope = SCOPE_UNIVERSE;
|
a->scope = SCOPE_UNIVERSE;
|
||||||
a->dest = r->dest;
|
a->dest = r->dest;
|
||||||
@ -101,11 +101,13 @@ static_announce_rte(struct static_proto *p, struct static_route *r)
|
|||||||
/* We skip rta_lookup() here */
|
/* We skip rta_lookup() here */
|
||||||
rte *e = rte_get_temp(a);
|
rte *e = rte_get_temp(a);
|
||||||
e->pflags = 0;
|
e->pflags = 0;
|
||||||
|
e->pref = r->preference;
|
||||||
|
|
||||||
if (r->cmds)
|
if (r->cmds)
|
||||||
f_eval_rte(r->cmds, &e, static_lp);
|
f_eval_rte(r->cmds, &e, static_lp);
|
||||||
|
|
||||||
rte_update(&p->p, r->net, e);
|
e->pref = r->preference; /* Avoid preference from filter */
|
||||||
|
rte_update2(p->p.main_channel, r->net, e, a->src);
|
||||||
r->state = SRS_CLEAN;
|
r->state = SRS_CLEAN;
|
||||||
|
|
||||||
if (r->cmds)
|
if (r->cmds)
|
||||||
@ -117,7 +119,7 @@ withdraw:
|
|||||||
if (r->state == SRS_DOWN)
|
if (r->state == SRS_DOWN)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
rte_update(&p->p, r->net, NULL);
|
rte_update2(p->p.main_channel, r->net, NULL, a->src);
|
||||||
r->state = SRS_DOWN;
|
r->state = SRS_DOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,7 +252,7 @@ static void
|
|||||||
static_remove_rte(struct static_proto *p, struct static_route *r)
|
static_remove_rte(struct static_proto *p, struct static_route *r)
|
||||||
{
|
{
|
||||||
if (r->state)
|
if (r->state)
|
||||||
rte_update(&p->p, r->net, NULL);
|
rte_update2(p->p.main_channel, r->net, NULL, rt_get_source(&p->p, r->preference));
|
||||||
|
|
||||||
static_reset_rte(p, r);
|
static_reset_rte(p, r);
|
||||||
}
|
}
|
||||||
@ -380,8 +382,13 @@ static_postconfig(struct proto_config *CF)
|
|||||||
cc->table : cf->c.global->def_tables[NET_IP6];
|
cc->table : cf->c.global->def_tables[NET_IP6];
|
||||||
|
|
||||||
WALK_LIST(r, cf->routes)
|
WALK_LIST(r, cf->routes)
|
||||||
|
{
|
||||||
if (r->net && (r->net->type != CF->net_type))
|
if (r->net && (r->net->type != CF->net_type))
|
||||||
cf_error("Route %N incompatible with channel type", r->net);
|
cf_error("Route %N incompatible with channel type", r->net);
|
||||||
|
|
||||||
|
if (!r->preference)
|
||||||
|
r->preference = cc->preference;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct proto *
|
static struct proto *
|
||||||
@ -488,11 +495,17 @@ static_dump(struct proto *P)
|
|||||||
|
|
||||||
#define IGP_TABLE(cf, sym) ((cf)->igp_table_##sym ? (cf)->igp_table_##sym ->table : NULL )
|
#define IGP_TABLE(cf, sym) ((cf)->igp_table_##sym ? (cf)->igp_table_##sym ->table : NULL )
|
||||||
|
|
||||||
|
static inline int srt_equal(struct static_route *a, struct static_route *b)
|
||||||
|
{ return net_equal(a->net, b->net) && (a->preference == b->preference); }
|
||||||
|
|
||||||
|
static inline int srt_compare(struct static_route *a, struct static_route *b)
|
||||||
|
{ return net_compare(a->net, b->net) ?: uint_cmp(a->preference, b->preference); }
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
static_cmp_rte(const void *X, const void *Y)
|
static_cmp_rte(const void *X, const void *Y)
|
||||||
{
|
{
|
||||||
struct static_route *x = *(void **)X, *y = *(void **)Y;
|
struct static_route *x = *(void **)X, *y = *(void **)Y;
|
||||||
return net_compare(x->net, y->net);
|
return srt_compare(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -521,7 +534,7 @@ static_reconfigure(struct proto *P, struct proto_config *CF)
|
|||||||
|
|
||||||
/* Reconfigure initial matching sequence */
|
/* Reconfigure initial matching sequence */
|
||||||
for (or = HEAD(o->routes), nr = HEAD(n->routes);
|
for (or = HEAD(o->routes), nr = HEAD(n->routes);
|
||||||
NODE_VALID(or) && NODE_VALID(nr) && net_equal(or->net, nr->net);
|
NODE_VALID(or) && NODE_VALID(nr) && srt_equal(or, nr);
|
||||||
or = NODE_NEXT(or), nr = NODE_NEXT(nr))
|
or = NODE_NEXT(or), nr = NODE_NEXT(nr))
|
||||||
static_reconfigure_rte(p, or, nr);
|
static_reconfigure_rte(p, or, nr);
|
||||||
|
|
||||||
@ -552,7 +565,7 @@ static_reconfigure(struct proto *P, struct proto_config *CF)
|
|||||||
|
|
||||||
while ((orpos < ornum) && (nrpos < nrnum))
|
while ((orpos < ornum) && (nrpos < nrnum))
|
||||||
{
|
{
|
||||||
int x = net_compare(orbuf[orpos]->net, nrbuf[nrpos]->net);
|
int x = srt_compare(orbuf[orpos], nrbuf[nrpos]);
|
||||||
if (x < 0)
|
if (x < 0)
|
||||||
static_remove_rte(p, orbuf[orpos++]);
|
static_remove_rte(p, orbuf[orpos++]);
|
||||||
else if (x > 0)
|
else if (x > 0)
|
||||||
|
@ -40,6 +40,7 @@ struct static_route {
|
|||||||
struct static_route *mp_head; /* First nexthop of this route */
|
struct static_route *mp_head; /* First nexthop of this route */
|
||||||
struct static_route *mp_next; /* Nexthops for multipath routes */
|
struct static_route *mp_next; /* Nexthops for multipath routes */
|
||||||
struct f_inst *cmds; /* List of commands for setting attributes */
|
struct f_inst *cmds; /* List of commands for setting attributes */
|
||||||
|
u16 preference; /* Route preference */
|
||||||
byte dest; /* Destination type (RTD_*) */
|
byte dest; /* Destination type (RTD_*) */
|
||||||
byte state; /* State of route announcement (SRS_*) */
|
byte state; /* State of route announcement (SRS_*) */
|
||||||
byte active; /* Next hop is active (nbr/iface/BFD available) */
|
byte active; /* Next hop is active (nbr/iface/BFD available) */
|
||||||
|
@ -11,13 +11,16 @@ CF_HDR
|
|||||||
#include "sysdep/unix/unix.h"
|
#include "sysdep/unix/unix.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
CF_DEFINES
|
||||||
|
|
||||||
|
static struct log_config *this_log;
|
||||||
|
|
||||||
CF_DECLS
|
CF_DECLS
|
||||||
|
|
||||||
CF_KEYWORDS(LOG, SYSLOG, ALL, DEBUG, TRACE, INFO, REMOTE, WARNING, ERROR, AUTH, FATAL, BUG, STDERR, SOFT)
|
CF_KEYWORDS(LOG, SYSLOG, ALL, DEBUG, TRACE, INFO, REMOTE, WARNING, ERROR, AUTH, FATAL, BUG, STDERR, SOFT)
|
||||||
CF_KEYWORDS(NAME, CONFIRM, UNDO, CHECK, TIMEOUT, DEBUG, LATENCY, LIMIT, WATCHDOG, WARNING)
|
CF_KEYWORDS(NAME, CONFIRM, UNDO, CHECK, TIMEOUT, DEBUG, LATENCY, LIMIT, WATCHDOG, WARNING)
|
||||||
|
|
||||||
%type <i> log_mask log_mask_list log_cat cfg_timeout
|
%type <i> log_mask log_mask_list log_cat cfg_timeout
|
||||||
%type <g> log_file
|
|
||||||
%type <t> cfg_name
|
%type <t> cfg_name
|
||||||
%type <tf> timeformat_which
|
%type <tf> timeformat_which
|
||||||
%type <t> syslog_name
|
%type <t> syslog_name
|
||||||
@ -26,11 +29,11 @@ CF_GRAMMAR
|
|||||||
|
|
||||||
CF_ADDTO(conf, log_config)
|
CF_ADDTO(conf, log_config)
|
||||||
|
|
||||||
log_config: LOG log_file log_mask ';' {
|
log_begin: { this_log = cfg_allocz(sizeof(struct log_config)); };
|
||||||
struct log_config *c = cfg_allocz(sizeof(struct log_config));
|
|
||||||
c->fh = $2;
|
log_config: LOG log_begin log_file log_mask ';' {
|
||||||
c->mask = $3;
|
this_log->mask = $4;
|
||||||
add_tail(&new_config->logfiles, &c->n);
|
add_tail(&new_config->logfiles, &this_log->n);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -39,14 +42,21 @@ syslog_name:
|
|||||||
| { $$ = bird_name; }
|
| { $$ = bird_name; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
log_limit:
|
||||||
|
/* empty */
|
||||||
|
| expr text { this_log->limit = $1; this_log->backup = $2; }
|
||||||
|
;
|
||||||
|
|
||||||
log_file:
|
log_file:
|
||||||
text {
|
text log_limit {
|
||||||
FILE *f = tracked_fopen(new_config->pool, $1, "a");
|
this_log->rf = rf_open(new_config->pool, $1, "a");
|
||||||
if (!f) cf_error("Unable to open log file `%s': %m", $1);
|
if (!this_log->rf) cf_error("Unable to open log file '%s': %m", $1);
|
||||||
$$ = f;
|
this_log->fh = rf_file(this_log->rf);
|
||||||
|
this_log->pos = -1;
|
||||||
|
this_log->filename = $1;
|
||||||
}
|
}
|
||||||
| SYSLOG syslog_name { $$ = NULL; new_config->syslog_name = $2; }
|
| SYSLOG syslog_name { this_log->fh = NULL; new_config->syslog_name = $2; }
|
||||||
| STDERR { $$ = stderr; }
|
| STDERR { this_log->fh = stderr; }
|
||||||
;
|
;
|
||||||
|
|
||||||
log_mask:
|
log_mask:
|
||||||
@ -77,9 +87,9 @@ CF_ADDTO(conf, mrtdump_base)
|
|||||||
mrtdump_base:
|
mrtdump_base:
|
||||||
MRTDUMP PROTOCOLS mrtdump_mask ';' { new_config->proto_default_mrtdump = $3; }
|
MRTDUMP PROTOCOLS mrtdump_mask ';' { new_config->proto_default_mrtdump = $3; }
|
||||||
| MRTDUMP text ';' {
|
| MRTDUMP text ';' {
|
||||||
FILE *f = tracked_fopen(new_config->pool, $2, "a");
|
struct rfile *f = rf_open(new_config->pool, $2, "a");
|
||||||
if (!f) cf_error("Unable to open MRTDump file '%s': %m", $2);
|
if (!f) cf_error("Unable to open MRTDump file '%s': %m", $2);
|
||||||
new_config->mrtdump_file = fileno(f);
|
new_config->mrtdump_file = rf_fileno(f);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -55,6 +55,7 @@
|
|||||||
this to gen small latencies */
|
this to gen small latencies */
|
||||||
#define MAX_RX_STEPS 4
|
#define MAX_RX_STEPS 4
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tracked Files
|
* Tracked Files
|
||||||
*/
|
*/
|
||||||
@ -89,17 +90,29 @@ static struct resclass rf_class = {
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
void *
|
struct rfile *
|
||||||
tracked_fopen(pool *p, char *name, char *mode)
|
rf_open(pool *p, char *name, char *mode)
|
||||||
{
|
{
|
||||||
FILE *f = fopen(name, mode);
|
FILE *f = fopen(name, mode);
|
||||||
|
|
||||||
if (f)
|
if (!f)
|
||||||
{
|
return NULL;
|
||||||
struct rfile *r = ralloc(p, &rf_class);
|
|
||||||
r->f = f;
|
struct rfile *r = ralloc(p, &rf_class);
|
||||||
}
|
r->f = f;
|
||||||
return f;
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
rf_file(struct rfile *f)
|
||||||
|
{
|
||||||
|
return f->f;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
rf_fileno(struct rfile *f)
|
||||||
|
{
|
||||||
|
return fileno(f->f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
@ -86,6 +88,54 @@ static char *class_names[] = {
|
|||||||
"BUG"
|
"BUG"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline off_t
|
||||||
|
log_size(struct log_config *l)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
return (!fstat(rf_fileno(l->rf), &st) && S_ISREG(st.st_mode)) ? st.st_size : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
log_close(struct log_config *l)
|
||||||
|
{
|
||||||
|
rfree(l->rf);
|
||||||
|
l->rf = NULL;
|
||||||
|
l->fh = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
log_open(struct log_config *l)
|
||||||
|
{
|
||||||
|
l->rf = rf_open(config->pool, l->filename, "a");
|
||||||
|
if (!l->rf)
|
||||||
|
{
|
||||||
|
/* Well, we cannot do much in case of error as log is closed */
|
||||||
|
l->mask = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
l->fh = rf_file(l->rf);
|
||||||
|
l->pos = log_size(l);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
log_rotate(struct log_config *l)
|
||||||
|
{
|
||||||
|
log_close(l);
|
||||||
|
|
||||||
|
/* If we cannot rename the logfile, we at least try to delete it
|
||||||
|
in order to continue logging and not exceeding logfile size */
|
||||||
|
if ((rename(l->filename, l->backup) < 0) &&
|
||||||
|
(unlink(l->filename) < 0))
|
||||||
|
{
|
||||||
|
l->mask = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return log_open(l);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* log_commit - commit a log message
|
* log_commit - commit a log message
|
||||||
@ -121,6 +171,22 @@ log_commit(int class, buffer *buf)
|
|||||||
{
|
{
|
||||||
byte tbuf[TM_DATETIME_BUFFER_SIZE];
|
byte tbuf[TM_DATETIME_BUFFER_SIZE];
|
||||||
tm_format_real_time(tbuf, config->tf_log.fmt1, current_real_time());
|
tm_format_real_time(tbuf, config->tf_log.fmt1, current_real_time());
|
||||||
|
|
||||||
|
if (l->limit)
|
||||||
|
{
|
||||||
|
off_t msg_len = strlen(tbuf) + strlen(class_names[class]) +
|
||||||
|
(buf->pos - buf->start) + 5;
|
||||||
|
|
||||||
|
if (l->pos < 0)
|
||||||
|
l->pos = log_size(l);
|
||||||
|
|
||||||
|
if (l->pos + msg_len > l->limit)
|
||||||
|
if (log_rotate(l) < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
l->pos += msg_len;
|
||||||
|
}
|
||||||
|
|
||||||
fprintf(l->fh, "%s <%s> ", tbuf, class_names[class]);
|
fprintf(l->fh, "%s <%s> ", tbuf, class_names[class]);
|
||||||
}
|
}
|
||||||
fputs(buf->start, l->fh);
|
fputs(buf->start, l->fh);
|
||||||
@ -279,12 +345,26 @@ default_log_list(int debug, int init, char **syslog_name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
log_switch(int debug, list *l, char *new_syslog_name)
|
log_switch(int debug, list *logs, char *new_syslog_name)
|
||||||
{
|
{
|
||||||
if (!l || EMPTY_LIST(*l))
|
struct log_config *l;
|
||||||
l = default_log_list(debug, !l, &new_syslog_name);
|
|
||||||
|
|
||||||
current_log_list = l;
|
if (!logs || EMPTY_LIST(*logs))
|
||||||
|
logs = default_log_list(debug, !logs, &new_syslog_name);
|
||||||
|
|
||||||
|
/* Close the logs to avoid pinning them on disk when deleted */
|
||||||
|
if (current_log_list)
|
||||||
|
WALK_LIST(l, *current_log_list)
|
||||||
|
if (l->rf)
|
||||||
|
log_close(l);
|
||||||
|
|
||||||
|
/* Reopen the logs, needed for 'configure undo' */
|
||||||
|
if (logs)
|
||||||
|
WALK_LIST(l, *logs)
|
||||||
|
if (l->filename && !l->rf)
|
||||||
|
log_open(l);
|
||||||
|
|
||||||
|
current_log_list = logs;
|
||||||
|
|
||||||
#ifdef HAVE_SYSLOG_H
|
#ifdef HAVE_SYSLOG_H
|
||||||
if (current_syslog_name && new_syslog_name &&
|
if (current_syslog_name && new_syslog_name &&
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
struct pool;
|
struct pool;
|
||||||
struct iface;
|
struct iface;
|
||||||
struct birdsock;
|
struct birdsock;
|
||||||
|
struct rfile;
|
||||||
|
|
||||||
/* main.c */
|
/* main.c */
|
||||||
|
|
||||||
@ -102,7 +103,9 @@ void io_init(void);
|
|||||||
void io_loop(void);
|
void io_loop(void);
|
||||||
void io_log_dump(void);
|
void io_log_dump(void);
|
||||||
int sk_open_unix(struct birdsock *s, char *name);
|
int sk_open_unix(struct birdsock *s, char *name);
|
||||||
void *tracked_fopen(struct pool *, char *name, char *mode);
|
struct rfile *rf_open(struct pool *, char *name, char *mode);
|
||||||
|
void *rf_file(struct rfile *f);
|
||||||
|
int rf_fileno(struct rfile *f);
|
||||||
void test_old_bird(char *path);
|
void test_old_bird(char *path);
|
||||||
|
|
||||||
/* krt.c bits */
|
/* krt.c bits */
|
||||||
@ -119,6 +122,11 @@ struct log_config {
|
|||||||
node n;
|
node n;
|
||||||
uint mask; /* Classes to log */
|
uint mask; /* Classes to log */
|
||||||
void *fh; /* FILE to log to, NULL=syslog */
|
void *fh; /* FILE to log to, NULL=syslog */
|
||||||
|
struct rfile *rf; /* Resource for log file */
|
||||||
|
char *filename; /* Log filename */
|
||||||
|
char *backup; /* Secondary filename (for log rotation) */
|
||||||
|
off_t pos; /* Position/size of current log */
|
||||||
|
off_t limit; /* Log size limit */
|
||||||
int terminal_flag;
|
int terminal_flag;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user