]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Implements MRTdump feature.
authorOndrej Zajicek <santiago@crfreenet.org>
Sun, 3 Jan 2010 11:17:52 +0000 (12:17 +0100)
committerOndrej Zajicek <santiago@crfreenet.org>
Sun, 3 Jan 2010 11:17:52 +0000 (12:17 +0100)
19 files changed:
conf/conf.c
conf/conf.h
doc/bird.sgml
lib/ipv4.h
lib/ipv6.h
nest/config.Y
nest/mrtdump.h [new file with mode: 0644]
nest/proto.c
nest/protocol.h
proto/bgp/bgp.c
proto/bgp/bgp.h
proto/bgp/packets.c
proto/ospf/iface.c
proto/ospf/neighbor.c
proto/ospf/ospf.c
proto/ospf/topology.c
sysdep/unix/config.Y
sysdep/unix/io.c
sysdep/unix/log.c

index eeffd4a855d41966ed2fb85fce44ac2d906ad979..7ffe8d1314e96645a0f4f975f196ad744cae6cc1 100644 (file)
@@ -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);
index 951dde3ca8c2c3752ffc2a08420396d7b7786d18..f8ab71312c6be68125e5def6b3e527b378f2bbd3 100644 (file)
@@ -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 */
index 53d87b6b91c84045a455093021fb46575f07c9d8..0eb476d5a9571ad012a3410403a946efe9c68e8a 100644 (file)
@@ -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/.
index 5c8c3907550946600ddce15a105059d7085f08ae..52bed16ff6b9fae61cfdd9e81412e475471cdd38 100644 (file)
@@ -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
 
index 53888ff043d575812eb472b8b26afd2e10bcf7ec..e15c57af3ab4a70cf537d56cc4a79c3c39f48f6c 100644 (file)
@@ -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
index dbb10adabe460042e0a9f9a65ad5da65ec27cb9a..11f0a9b21c03ab60fb9c06826252aab53ccb65f4 100644 (file)
@@ -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 (file)
index 0000000..8638804
--- /dev/null
@@ -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
+
index 4f352a6fbe532a356953368356d9673fa71dad5b..9f0311f6dbf13b47491307adac3f1de1b84d62f9 100644 (file)
@@ -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)
index 21a1c1b438ea49c73f2b0dc6d267bd82f47a245f..5a69b33b48f28b1dc152791df24a5af19df88332 100644 (file)
@@ -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
@@ -306,6 +308,13 @@ void proto_notify_state(struct proto *p, unsigned state);
 #define D_EVENTS 16            /* Protocol events */
 #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
  */
index 3cbcb6d75f5673b1e1869676eef7530ba610ed17..215dc817e3f5b17c9972323e3c6ab120d9b6a38c 100644 (file)
@@ -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);
index 7cbd6557fb9327cbbe554d23664c85bf83121cee..24d69741f46430f52a37e9171dfb52518155a2e0 100644 (file)
@@ -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
index 91b47927347b175c314d5b3a0b248e46b8b331ab..03cc4ee0d27155e6a2e16b8f466ce854a27432b8 100644 (file)
@@ -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"
 
 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);
index 8db086ec20f91b3067f612f5e7964fc95434a5f4..e514a5d59ecdb8d8452f14531ef777364e0ce393 100644 (file)
@@ -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)
        {
index ba8d7b98b3bf01097507e3da3fec1ecf8de12435..0411d48e5fef4733702b9bfc3398a608eb9b55df 100644 (file)
@@ -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
index 9ebef6b7e02213a180102984b8e388d8961c874a..232803d7d1f2065596bc70bf2e1ab3b92dfdc307 100644 (file)
@@ -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)
index 3ca5e774e13ba43ae5938b9db74bfa80452c6ca5..870c0bc21841c53b838d20e188e6959226c9ce3c 100644 (file)
@@ -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;
index 1917fe685c3ec8f0c5cfc79366c141e0c1fac341..46c5862b6e8da8564bbd01bd134ac236d771fa74 100644 (file)
@@ -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]])
index cd5c5db7b9559cc6e7655b34263d8f9614b1b0fb..74612acd2972d13386749073eaaa3cc953ec3f28 100644 (file)
@@ -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))
        {
index eb08309908460aaa1f32864c94246bfda3b5d32f..dad0c5db4403e00a981669b32ee1f99ecd4145ba 100644 (file)
@@ -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);
+}