summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--conf/conf.c1
-rw-r--r--conf/conf.h5
-rw-r--r--doc/bird.sgml26
-rw-r--r--lib/ipv4.h7
-rw-r--r--lib/ipv6.h11
-rw-r--r--nest/config.Y36
-rw-r--r--nest/mrtdump.h27
-rw-r--r--nest/proto.c10
-rw-r--r--nest/protocol.h15
-rw-r--r--proto/bgp/bgp.c29
-rw-r--r--proto/bgp/bgp.h8
-rw-r--r--proto/bgp/packets.c105
-rw-r--r--proto/ospf/iface.c9
-rw-r--r--proto/ospf/neighbor.c6
-rw-r--r--proto/ospf/ospf.c4
-rw-r--r--proto/ospf/topology.c6
-rw-r--r--sysdep/unix/config.Y14
-rw-r--r--sysdep/unix/io.c9
-rw-r--r--sysdep/unix/log.c14
19 files changed, 300 insertions, 42 deletions
diff --git a/conf/conf.c b/conf/conf.c
index eeffd4a8..7ffe8d13 100644
--- a/conf/conf.c
+++ b/conf/conf.c
@@ -75,6 +75,7 @@ config_alloc(byte *name)
linpool *l = lp_new(p, 4080);
struct config *c = lp_allocz(l, sizeof(struct config));
+ c->mrtdump_file = -1; /* Hack, this should be sysdep-specific */
c->pool = p;
cfg_mem = c->mem = l;
c->file_name = cfg_strdup(name);
diff --git a/conf/conf.h b/conf/conf.h
index 951dde3c..f8ab7131 100644
--- a/conf/conf.h
+++ b/conf/conf.h
@@ -20,12 +20,15 @@ struct config {
list protos; /* Configured protocol instances (struct proto_config) */
list tables; /* Configured routing tables (struct rtable_config) */
list logfiles; /* Configured log fils (sysdep) */
+ int mrtdump_file; /* Configured MRTDump file (sysdep, fd in unix) */
struct rtable_config *master_rtc; /* Configuration of master routing table */
+
u32 router_id; /* Our Router ID */
ip_addr listen_bgp_addr; /* Listening BGP socket should use this address */
unsigned listen_bgp_port; /* Listening BGP socket should use this port (0 is default) */
u32 listen_bgp_flags; /* Listening BGP socket should use these flags */
- unsigned int proto_default_debug; /* Default protocol debug mask */
+ unsigned proto_default_debug; /* Default protocol debug mask */
+ unsigned proto_default_mrtdump; /* Default protocol mrtdump mask */
int cli_debug; /* Tracing of CLI connections and commands */
char *err_msg; /* Parser error message */
int err_lino; /* Line containing error */
diff --git a/doc/bird.sgml b/doc/bird.sgml
index 53d87b6b..0eb476d5 100644
--- a/doc/bird.sgml
+++ b/doc/bird.sgml
@@ -238,6 +238,14 @@ protocol rip {
logging of connects and disconnects, 2 and higher for logging of
all client commands). Default: 0.
+ <tag>mrtdump "<m/filename/"</tag>
+ Set MRTdump file name. This option must be specified to allow MRTdump feature.
+ Default: no dump file.
+
+ <tag>mrtdump protocols all|off|{ states, messages }</tag>
+ Set global defaults of MRTdump options. See <cf/mrtdump/ in the following section.
+ Default: off.
+
<tag>filter <m/name local variables/{ <m/commands/ }</tag> Define a filter. You can learn more about filters
in the following chapter.
@@ -301,8 +309,22 @@ to zero to disable it. An empty <cf><m/switch/</cf> is equivalent to <cf/on/
<cf/events/ for events internal to the protocol and
<cf/packets/ for packets sent and received by the protocol. Default: off.
- <tag>router id <m/IPv4 address/</tag> This option can be used to override global
- router id for a given protocol. Default: uses global router id.
+ <tag>mrtdump all|off|{ states, messages }</tag>
+
+ Set protocol MRTdump flags. MRTdump is a standard binary
+ format for logging information from routing protocols and
+ daemons. These flags control what kind of information is
+ logged from the protocol to the MRTdump file (which must be
+ specified by global <cf/mrtdump/ option, see the previous
+ section). Although these flags are similar to flags of
+ <cf/debug/ option, their meaning is different and
+ protocol-specific. For BGP protocol, <cf/states/ logs BGP
+ state changes and <cf/messages/ logs received BGP messages.
+ Other protocols does not support MRTdump yet.
+
+ <tag>router id <m/IPv4 address/</tag> This option can be used
+ to override global router id for a given protocol. Default:
+ uses global router id.
<tag>import all | none | filter <m/name/ | filter { <m/filter commands/ } | where <m/filter expression/</tag>
Specify a filter to be used for filtering routes coming from the protocol to the routing table. <cf/all/ is shorthand for <cf/where true/ and <cf/none/ is shorthand for <cf/where false/. Default: <cf/all/.
diff --git a/lib/ipv4.h b/lib/ipv4.h
index 5c8c3907..52bed16f 100644
--- a/lib/ipv4.h
+++ b/lib/ipv4.h
@@ -11,6 +11,7 @@
#include "lib/endian.h"
#include "lib/bitops.h"
+#include "lib/unaligned.h"
#ifdef DEBUGGING
@@ -63,6 +64,7 @@ typedef u32 ip_addr;
/* ipa_pxlen() requires that x != y */
#define ipa_pxlen(x, y) ipv4_pxlen(_I(x), _I(y))
#define ipa_getbit(x, y) (_I(x) & (0x80000000 >> (y)))
+#define ipa_put_addr(x, y) ipv4_put_addr(x, y)
#define ip_skip_header(x, y) ipv4_skip_header(x, y)
@@ -93,6 +95,11 @@ static inline u32 ipv4_pxlen(u32 a, u32 b)
return 31 - u32_log2(a ^ b);
}
+static inline byte * ipv4_put_addr(byte *buf, ip_addr a)
+{
+ put_u32(buf, _I(a));
+ return buf+4;
+}
#define IP_PREC_INTERNET_CONTROL 0xc0
diff --git a/lib/ipv6.h b/lib/ipv6.h
index 53888ff0..e15c57af 100644
--- a/lib/ipv6.h
+++ b/lib/ipv6.h
@@ -14,6 +14,7 @@
#include <netinet/in.h>
#include "lib/string.h"
#include "lib/bitops.h"
+#include "lib/unaligned.h"
typedef struct ipv6_addr {
u32 addr[4];
@@ -68,6 +69,7 @@ typedef struct ipv6_addr {
/* ipa_pxlen() requires that x != y */
#define ipa_pxlen(x, y) ipv6_pxlen(x, y)
#define ipa_getbit(x, y) ipv6_getbit(x, y)
+#define ipa_put_addr(x, y) ipv6_put_addr(x, y)
#define ipa_absolutize(x,y) ipv6_absolutize(x,y)
/* In IPv6, SOCK_RAW does not return packet header */
@@ -115,6 +117,15 @@ static inline u32 ipv6_pxlen(ip_addr a, ip_addr b)
return 32 * i + 31 - u32_log2(a.addr[i] ^ b.addr[i]);
}
+static inline byte * ipv6_put_addr(byte *buf, ip_addr a)
+{
+ put_u32(buf+0, _I0(a));
+ put_u32(buf+4, _I1(a));
+ put_u32(buf+8, _I2(a));
+ put_u32(buf+12, _I3(a));
+ return buf+16;
+}
+
/*
* RFC 1883 defines packet precendece, but RFC 2460 replaces it
* by generic Traffic Class ID with no defined semantics. Better
diff --git a/nest/config.Y b/nest/config.Y
index dbb10ada..11f0a9b2 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -45,7 +45,7 @@ CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILT
CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, GENERATE)
CF_KEYWORDS(LISTEN, BGP, V6ONLY, ADDRESS, PORT, PASSWORDS, DESCRIPTION)
-CF_KEYWORDS(RELOAD, IN, OUT)
+CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES)
CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT,
RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE)
@@ -58,7 +58,7 @@ CF_ENUM(T_ENUM_RTD, RTD_, ROUTER, DEVICE, BLACKHOLE, UNREACHABLE, PROHIBIT)
%type <r> rtable
%type <s> optsym
%type <ra> r_args
-%type <i> echo_mask echo_size debug_mask debug_list debug_flag export_or_preexport
+%type <i> echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_or_preexport
%type <t> proto_patt
CF_GRAMMAR
@@ -138,6 +138,7 @@ proto_item:
}
| DISABLED bool { this_proto->disabled = $2; }
| DEBUG debug_mask { this_proto->debug = $2; }
+ | MRTDUMP mrtdump_mask { this_proto->mrtdump = $2; }
| IMPORT imexport { this_proto->in_filter = $2; }
| EXPORT imexport { this_proto->out_filter = $2; }
| TABLE rtable { this_proto->table = $2; }
@@ -166,6 +167,8 @@ debug_default:
| DEBUG COMMANDS expr { new_config->cli_debug = $3; }
;
+/* MRTDUMP PROTOCOLS is in systep/unix/config.Y */
+
/* Interface patterns */
iface_patt_node_init:
@@ -251,6 +254,24 @@ debug_flag:
| PACKETS { $$ = D_PACKETS; }
;
+/* MRTDump flags */
+
+mrtdump_mask:
+ ALL { $$ = ~0; }
+ | OFF { $$ = 0; }
+ | '{' mrtdump_list '}' { $$ = $2; }
+ ;
+
+mrtdump_list:
+ mrtdump_flag
+ | mrtdump_list ',' mrtdump_flag { $$ = $1 | $3; }
+ ;
+
+mrtdump_flag:
+ STATES { $$ = MD_STATES; }
+ | MESSAGES { $$ = MD_MESSAGES; }
+ ;
+
/* Password lists */
password_list:
@@ -450,9 +471,14 @@ CF_CLI(RELOAD IN, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protoco
CF_CLI(RELOAD OUT, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol (just exported routes)]])
{ proto_xxable($3, XX_RELOAD_OUT); } ;
-CF_CLI_HELP(DEBUG, ..., [[Control protocol debugging]])
-CF_CLI(DEBUG, proto_patt debug_mask, (<protocol> | <pattern> | all) (all | off | { states | routes | filters | events | packets }), [[Control protocol debugging]])
-{ proto_debug($2, $3); }
+CF_CLI_HELP(DEBUG, ..., [[Control protocol debugging via BIRD logs]])
+CF_CLI(DEBUG, proto_patt debug_mask, (<protocol> | <pattern> | all) (all | off | { states | routes | filters | events | packets }), [[Control protocol debugging via BIRD logs]])
+{ proto_debug($2, 0, $3); }
+ ;
+
+CF_CLI_HELP(MRTDUMP, ..., [[Control protocol debugging via MRTdump files]])
+CF_CLI(MRTDUMP, proto_patt mrtdump_mask, (<protocol> | <pattern> | all) (all | off | { states | messages }), [[Control protocol debugging via MRTdump format]])
+{ proto_debug($2, 1, $3); }
;
proto_patt:
diff --git a/nest/mrtdump.h b/nest/mrtdump.h
new file mode 100644
index 00000000..8638804a
--- /dev/null
+++ b/nest/mrtdump.h
@@ -0,0 +1,27 @@
+/*
+ * BIRD -- Password handling
+ *
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#ifndef MRTDUMP_H
+#define MRTDUMP_H
+#include "nest/protocol.h"
+
+/* MRTDump values */
+
+#define MRTDUMP_HDR_LENGTH 12
+
+#define BGP4MP 16
+
+#define BGP4MP_MESSAGE 1
+#define BGP4MP_MESSAGE_AS4 4
+#define BGP4MP_STATE_CHANGE_AS4 5
+
+
+/* implemented in sysdep */
+void mrt_dump_message(struct proto *p, u16 type, u16 subtype, byte *buf, u32 len);
+
+#endif
+
diff --git a/nest/proto.c b/nest/proto.c
index 4f352a6f..9f0311f6 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -111,6 +111,7 @@ proto_new(struct proto_config *c, unsigned size)
p->cf = c;
p->debug = c->debug;
+ p->mrtdump = c->mrtdump;
p->name = c->name;
p->preference = c->preference;
p->disabled = c->disabled;
@@ -201,6 +202,7 @@ proto_config_new(struct protocol *pr, unsigned size)
c->out_filter = FILTER_REJECT;
c->table = c->global->master_rtc;
c->debug = new_config->proto_default_debug;
+ c->mrtdump = new_config->proto_default_mrtdump;
return c;
}
@@ -325,6 +327,7 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty
{
/* Generic attributes match, try converting them and then ask the protocol */
p->debug = nc->debug;
+ p->mrtdump = nc->mrtdump;
if (p->proto->reconfigure && p->proto->reconfigure(p, nc))
{
DBG("\t%s: same\n", oc->name);
@@ -901,14 +904,17 @@ proto_xxable(char *pattern, int xx)
}
void
-proto_debug(char *pattern, unsigned int mask)
+proto_debug(char *pattern, int which, unsigned int mask)
{
int cnt = 0;
WALK_PROTO_LIST(p)
if (patmatch(pattern, p->name))
{
cnt++;
- p->debug = mask;
+ if (which == 0)
+ p->debug = mask;
+ else
+ p->mrtdump = mask;
}
WALK_PROTO_LIST_END;
if (!cnt)
diff --git a/nest/protocol.h b/nest/protocol.h
index 21a1c1b4..5a69b33b 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -82,7 +82,8 @@ struct proto_config {
struct proto *proto; /* Instance we've created */
char *name;
char *dsc;
- unsigned debug, preference, disabled; /* Generic parameters */
+ u32 debug, mrtdump; /* Debugging bitfields, both use D_* constants */
+ unsigned preference, disabled; /* Generic parameters */
u32 router_id; /* Protocol specific router ID */
struct rtable_config *table; /* Table we're attached to */
struct filter *in_filter, *out_filter; /* Attached filters */
@@ -125,7 +126,8 @@ struct proto {
struct event *attn; /* "Pay attention" event */
char *name; /* Name of this instance (== cf->name) */
- unsigned debug; /* Debugging flags */
+ u32 debug; /* Debugging flags */
+ u32 mrtdump; /* MRTDump flags */
unsigned preference; /* Default route preference */
int min_scope; /* Minimal route scope accepted */
unsigned accept_ra_types; /* Which types of route announcements are accepted (RA_OPTIMAL or RA_ANY) */
@@ -199,7 +201,7 @@ void proto_request_feeding(struct proto *p);
void proto_show(struct symbol *, int);
struct proto *proto_get_named(struct symbol *, struct protocol *);
void proto_xxable(char *, int);
-void proto_debug(char *, unsigned int);
+void proto_debug(char *, int, unsigned int);
#define XX_DISABLE 0
#define XX_ENABLE 1
@@ -307,6 +309,13 @@ void proto_notify_state(struct proto *p, unsigned state);
#define D_PACKETS 32 /* Packets sent/received */
/*
+ * MRTDump flags
+ */
+
+#define MD_STATES 1 /* Protocol state changes (BGP4MP_MESSAGE_AS4) */
+#define MD_MESSAGES 2 /* Protocol packets (BGP4MP_MESSAGE_AS4) */
+
+/*
* Known unique protocol instances as referenced by config routines
*/
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index 3cbcb6d7..215dc817 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -313,6 +313,22 @@ bgp_stop(struct bgp_proto *p, unsigned subcode)
ev_schedule(p->event);
}
+static inline void
+bgp_conn_set_state(struct bgp_conn *conn, unsigned new_state)
+{
+ if (conn->bgp->p.mrtdump & MD_STATES)
+ mrt_dump_bgp_state_change(conn, conn->state, new_state);
+
+ conn->state = new_state;
+}
+
+void
+bgp_conn_enter_openconfirm_state(struct bgp_conn *conn)
+{
+ /* Really, most of the work is done in bgp_rx_open(). */
+ bgp_conn_set_state(conn, BS_OPENCONFIRM);
+}
+
void
bgp_conn_enter_established_state(struct bgp_conn *conn)
{
@@ -325,7 +341,7 @@ bgp_conn_enter_established_state(struct bgp_conn *conn)
p->last_error_class = 0;
p->last_error_code = 0;
bgp_attr_init(conn->bgp);
- conn->state = BS_ESTABLISHED;
+ bgp_conn_set_state(conn, BS_ESTABLISHED);
proto_notify_state(&p->p, PS_UP);
}
@@ -345,7 +361,7 @@ bgp_conn_enter_close_state(struct bgp_conn *conn)
struct bgp_proto *p = conn->bgp;
int os = conn->state;
- conn->state = BS_CLOSE;
+ bgp_conn_set_state(conn, BS_CLOSE);
tm_stop(conn->hold_timer);
tm_stop(conn->keepalive_timer);
conn->sk->rx_hook = NULL;
@@ -361,7 +377,7 @@ bgp_conn_enter_idle_state(struct bgp_conn *conn)
int os = conn->state;
bgp_close_conn(conn);
- conn->state = BS_IDLE;
+ bgp_conn_set_state(conn, BS_IDLE);
ev_schedule(p->event);
if (os == BS_ESTABLISHED)
@@ -374,13 +390,14 @@ bgp_send_open(struct bgp_conn *conn)
conn->start_state = conn->bgp->start_state;
conn->want_as4_support = conn->bgp->cf->enable_as4 && (conn->start_state != BSS_CONNECT_NOCAP);
conn->peer_as4_support = 0; // Default value, possibly changed by receiving capability.
+ conn->advertised_as = 0;
DBG("BGP: Sending open\n");
conn->sk->rx_hook = bgp_rx;
conn->sk->tx_hook = bgp_tx;
tm_stop(conn->connect_retry_timer);
bgp_schedule_packet(conn, PKT_OPEN);
- conn->state = BS_OPENSENT;
+ bgp_conn_set_state(conn, BS_OPENSENT);
bgp_start_timer(conn->hold_timer, conn->bgp->cf->initial_hold_time);
}
@@ -490,7 +507,7 @@ bgp_active(struct bgp_proto *p)
BGP_TRACE(D_EVENTS, "Connect delayed by %d seconds", delay);
bgp_setup_conn(p, conn);
- conn->state = BS_ACTIVE;
+ bgp_conn_set_state(conn, BS_ACTIVE);
bgp_start_timer(conn->connect_retry_timer, delay);
}
@@ -539,7 +556,7 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c
BGP_TRACE(D_EVENTS, "Connecting to %I from local address %I", s->daddr, s->saddr);
bgp_setup_conn(p, conn);
bgp_setup_sk(p, conn, s);
- conn->state = BS_CONNECT;
+ bgp_conn_set_state(conn, BS_CONNECT);
if (sk_open(s))
{
bgp_sock_err(s, 0);
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index 7cbd6557..24d69741 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -138,6 +138,7 @@ void bgp_check(struct bgp_config *c);
void bgp_error(struct bgp_conn *c, unsigned code, unsigned subcode, byte *data, int len);
void bgp_close_conn(struct bgp_conn *c);
void bgp_update_startup_delay(struct bgp_proto *p);
+void bgp_conn_enter_openconfirm_state(struct bgp_conn *conn);
void bgp_conn_enter_established_state(struct bgp_conn *conn);
void bgp_conn_enter_close_state(struct bgp_conn *conn);
void bgp_conn_enter_idle_state(struct bgp_conn *conn);
@@ -189,6 +190,7 @@ inline static void bgp_attach_attr_ip(struct ea_list **to, struct linpool *pool,
/* packets.c */
+void mrt_dump_bgp_state_change(struct bgp_conn *conn, unsigned old, unsigned new);
void bgp_schedule_packet(struct bgp_conn *conn, int type);
void bgp_kick_tx(void *vconn);
void bgp_tx(struct birdsock *sk);
@@ -294,4 +296,10 @@ void bgp_log_error(struct bgp_proto *p, u8 class, char *msg, unsigned code, unsi
#define BGP_AF_IPV4 1
#define BGP_AF_IPV6 2
+#ifdef IPV6
+#define BGP_AF BGP_AF_IPV6
+#else
+#define BGP_AF BGP_AF_IPV4
+#endif
+
#endif
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index 91b47927..03cc4ee0 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -13,6 +13,7 @@
#include "nest/protocol.h"
#include "nest/route.h"
#include "nest/attrs.h"
+#include "nest/mrtdump.h"
#include "conf/conf.h"
#include "lib/unaligned.h"
#include "lib/socket.h"
@@ -23,6 +24,84 @@
static struct rate_limit rl_rcv_update, rl_snd_update;
+/*
+ * MRT Dump format is not semantically specified.
+ * We will use these values in appropriate fields:
+ *
+ * Local AS, Remote AS - configured AS numbers for given BGP instance.
+ * Local IP, Remote IP - IP addresses of the TCP connection (0 if no connection)
+ *
+ * We dump two kinds of MRT messages: STATE_CHANGE (for BGP state
+ * changes) and MESSAGE (for received BGP messages).
+ *
+ * STATE_CHANGE uses always AS4 variant, but MESSAGE uses AS4 variant
+ * only when AS4 session is established and even in that case MESSAGE
+ * does not use AS4 variant for initial OPEN message. This strange
+ * behavior is here for compatibility with Quagga and Bgpdump,
+ */
+
+static byte *
+mrt_put_bgp4_hdr(byte *buf, struct bgp_conn *conn, int as4)
+{
+ struct bgp_proto *p = conn->bgp;
+ ip_addr local_addr;
+
+ if (as4)
+ {
+ put_u32(buf+0, p->remote_as);
+ put_u32(buf+4, p->local_as);
+ buf+=8;
+ }
+ else
+ {
+ put_u16(buf+0, (p->remote_as <= 0xFFFF) ? p->remote_as : AS_TRANS);
+ put_u16(buf+2, (p->local_as <= 0xFFFF) ? p->local_as : AS_TRANS);
+ buf+=4;
+ }
+
+ put_u16(buf+0, p->neigh->iface->index);
+ put_u16(buf+2, BGP_AF);
+ buf+=4;
+ buf = ipa_put_addr(buf, conn->sk ? conn->sk->daddr : IPA_NONE);
+ buf = ipa_put_addr(buf, conn->sk ? conn->sk->saddr : IPA_NONE);
+
+ return buf;
+}
+
+static void
+mrt_dump_bgp_packet(struct bgp_conn *conn, byte *pkt, unsigned len)
+{
+ byte buf[BGP_MAX_PACKET_LENGTH + 128];
+ byte *bp = buf + MRTDUMP_HDR_LENGTH;
+ int as4 = conn->bgp->as4_session;
+
+ bp = mrt_put_bgp4_hdr(bp, conn, as4);
+ memcpy(bp, pkt, len);
+ bp += len;
+ mrt_dump_message(&conn->bgp->p, BGP4MP, as4 ? BGP4MP_MESSAGE_AS4 : BGP4MP_MESSAGE,
+ buf, bp-buf);
+}
+
+static inline u16
+convert_state(unsigned state)
+{
+ /* Convert state from our BS_* values to values used in MRTDump */
+ return (state == BS_CLOSE) ? 1 : state + 1;
+}
+
+void
+mrt_dump_bgp_state_change(struct bgp_conn *conn, unsigned old, unsigned new)
+{
+ byte buf[128];
+ byte *bp = buf + MRTDUMP_HDR_LENGTH;
+
+ bp = mrt_put_bgp4_hdr(bp, conn, 1);
+ put_u16(bp+0, convert_state(old));
+ put_u16(bp+2, convert_state(new));
+ bp += 4;
+ mrt_dump_message(&conn->bgp->p, BGP4MP, BGP4MP_STATE_CHANGE_AS4, buf, bp-buf);
+}
+
static byte *
bgp_create_notification(struct bgp_conn *conn, byte *buf)
{
@@ -403,13 +482,8 @@ bgp_create_route_refresh(struct bgp_conn *conn, byte *buf)
struct bgp_proto *p = conn->bgp;
BGP_TRACE(D_PACKETS, "Sending ROUTE-REFRESH");
-#ifdef IPV6
- *buf++ = 0; /* AFI IPv6 */
- *buf++ = BGP_AF_IPV6;
-#else
- *buf++ = 0; /* AFI IPv4 */
- *buf++ = BGP_AF_IPV4;
-#endif
+ *buf++ = 0;
+ *buf++ = BGP_AF;
*buf++ = 0; /* RFU */
*buf++ = 1; /* and SAFI 1 */
return buf;
@@ -552,12 +626,13 @@ bgp_parse_capabilities(struct bgp_conn *conn, byte *opt, int len)
switch (opt[0])
{
- case 2:
+ case 2: /* Route refresh capability, RFC 2918 */
if (cl != 0)
goto err;
conn->peer_refresh_support = 1;
break;
- case 65:
+
+ case 65: /* AS4 capability, RFC 4893 */
if (cl != 4)
goto err;
conn->peer_as4_support = 1;
@@ -709,7 +784,7 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, int len)
bgp_schedule_packet(conn, PKT_KEEPALIVE);
bgp_start_timer(conn->hold_timer, conn->hold_time);
- conn->state = BS_OPENCONFIRM;
+ bgp_conn_enter_openconfirm_state(conn);
}
#define DECODE_PREFIX(pp, ll) do { \
@@ -1160,8 +1235,14 @@ bgp_rx_route_refresh(struct bgp_conn *conn, byte *pkt, int len)
static void
bgp_rx_packet(struct bgp_conn *conn, byte *pkt, unsigned len)
{
- DBG("BGP: Got packet %02x (%d bytes)\n", pkt[18], len);
- switch (pkt[18])
+ byte type = pkt[18];
+
+ DBG("BGP: Got packet %02x (%d bytes)\n", type, len);
+
+ if (conn->bgp->p.mrtdump & MD_MESSAGES)
+ mrt_dump_bgp_packet(conn, pkt, len);
+
+ switch (type)
{
case PKT_OPEN: return bgp_rx_open(conn, pkt, len);
case PKT_UPDATE: return bgp_rx_update(conn, pkt, len);
diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c
index 8db086ec..e514a5d5 100644
--- a/proto/ospf/iface.c
+++ b/proto/ospf/iface.c
@@ -152,9 +152,12 @@ ospf_iface_chstate(struct ospf_iface *ifa, u8 state)
if ((ifa->type != OSPF_IT_NBMA) && (ifa->ioprob == OSPF_I_OK) &&
((state == OSPF_IS_BACKUP) || (state == OSPF_IS_DR)))
{
- /* FIXME some error handing ? */
- sk_join_group(ifa->sk, AllDRouters);
- ifa->dr_up = 1;
+ if (!ifa->dr_up == 0)
+ {
+ /* FIXME some error handing ? */
+ sk_join_group(ifa->sk, AllDRouters);
+ ifa->dr_up = 1;
+ }
}
else if (ifa->dr_up)
{
diff --git a/proto/ospf/neighbor.c b/proto/ospf/neighbor.c
index ba8d7b98..0411d48e 100644
--- a/proto/ospf/neighbor.c
+++ b/proto/ospf/neighbor.c
@@ -623,9 +623,9 @@ ospf_sh_neigh_info(struct ospf_neighbor *n)
if ((n->ifa->type == OSPF_IT_PTP) || (n->ifa->type == OSPF_IT_VLINK))
pos = "ptp ";
- cli_msg(-1013, "%-1R\t%3u\t%s/%s\t%-5s\t%-1I\t%-10s", n->rid, n->priority,
- ospf_ns[n->state], pos, etime, n->ip,
- (ifa->type == OSPF_IT_VLINK ? "vlink" : ifa->iface->name));
+ cli_msg(-1013, "%-1R\t%3u\t%s/%s\t%-5s\t%-10s %-1I", n->rid, n->priority,
+ ospf_ns[n->state], pos, etime,
+ (ifa->type == OSPF_IT_VLINK ? "vlink" : ifa->iface->name), n->ip);
}
static void
diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c
index 9ebef6b7..232803d7 100644
--- a/proto/ospf/ospf.c
+++ b/proto/ospf/ospf.c
@@ -917,8 +917,8 @@ ospf_sh_neigh(struct proto *p, char *iff)
}
cli_msg(-1013, "%s:", p->name);
- cli_msg(-1013, "%-12s\t%3s\t%-15s\t%-5s\t%-12s\t%-10s", "Router ID", "Pri",
- " State", "DTime", "Router IP", "Interface");
+ cli_msg(-1013, "%-12s\t%3s\t%-15s\t%-5s\t%-10s %-12s", "Router ID", "Pri",
+ " State", "DTime", "Interface", "Router IP");
WALK_LIST(ifa, po->iface_list)
if ((iff == NULL) || patmatch(iff, ifa->iface->name))
WALK_LIST(n, ifa->neigh_list)
diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c
index 3ca5e774..870c0bc2 100644
--- a/proto/ospf/topology.c
+++ b/proto/ospf/topology.c
@@ -433,9 +433,11 @@ originate_rt_lsa(struct ospf_area *oa)
#ifdef OSPFv2
lsa.options = oa->options;
-#endif
-
lsa.id = po->router_id;
+#else /* OSPFv3 */
+ lsa.id = 0;
+#endif
+
lsa.rt = po->router_id;
lsa.sn = oa->rt ? (oa->rt->lsa.sn + 1) : LSA_INITSEQNO;
u32 dom = oa->areaid;
diff --git a/sysdep/unix/config.Y b/sysdep/unix/config.Y
index 1917fe68..46c5862b 100644
--- a/sysdep/unix/config.Y
+++ b/sysdep/unix/config.Y
@@ -63,6 +63,20 @@ log_cat:
| BUG { $$ = L_BUG[0]; }
;
+
+CF_ADDTO(conf, mrtdump_base)
+
+mrtdump_base:
+ MRTDUMP PROTOCOLS mrtdump_mask ';' { new_config->proto_default_mrtdump = $3; }
+ | MRTDUMP TEXT ';' {
+ FILE *f = tracked_fopen(new_config->pool, $2, "a");
+ if (!f) cf_error("Unable to open MRTDump file '%s': %m", $2);
+ new_config->mrtdump_file = fileno(f);
+ }
+ ;
+
+
+
/* Unix specific commands */
CF_CLI_HELP(CONFIGURE, [soft] [\"<file>\"], [[Reload configuration]])
diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c
index cd5c5db7..74612acd 100644
--- a/sysdep/unix/io.c
+++ b/sysdep/unix/io.c
@@ -947,7 +947,14 @@ sk_passive_connected(sock *s, struct sockaddr *sa, int al, int type)
t->rbsize = s->rbsize;
t->tbsize = s->tbsize;
if (type == SK_TCP)
- get_sockaddr((sockaddr *) sa, &t->daddr, &t->dport, 1);
+ {
+ sockaddr lsa;
+ int lsa_len = sizeof(lsa);
+ if (getsockname(fd, (struct sockaddr *) &lsa, &lsa_len) == 0)
+ get_sockaddr(&lsa, &t->saddr, &t->sport, 1);
+
+ get_sockaddr((sockaddr *) sa, &t->daddr, &t->dport, 1);
+ }
sk_insert(t);
if (err = sk_setup(t))
{
diff --git a/sysdep/unix/log.c b/sysdep/unix/log.c
index eb083099..dad0c5db 100644
--- a/sysdep/unix/log.c
+++ b/sysdep/unix/log.c
@@ -22,6 +22,7 @@
#include "nest/bird.h"
#include "nest/cli.h"
+#include "nest/mrtdump.h"
#include "lib/string.h"
#include "lib/lists.h"
#include "lib/unix.h"
@@ -261,3 +262,16 @@ log_init_debug(char *f)
if (dbgf)
setvbuf(dbgf, NULL, _IONBF, 0);
}
+
+void
+mrt_dump_message(struct proto *p, u16 type, u16 subtype, byte *buf, u32 len)
+{
+ /* Prepare header */
+ put_u32(buf+0, now_real);
+ put_u16(buf+4, type);
+ put_u16(buf+6, subtype);
+ put_u32(buf+8, len - MRTDUMP_HDR_LENGTH);
+
+ if (p->cf->global->mrtdump_file != -1)
+ write(p->cf->global->mrtdump_file, buf, len);
+}