From cf31112f0d7618464097f71228f84bd534f1bc0f Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sun, 3 Jan 2010 12:17:52 +0100 Subject: Implements MRTdump feature. --- proto/bgp/bgp.c | 29 +++++++++++--- proto/bgp/bgp.h | 8 ++++ proto/bgp/packets.c | 105 ++++++++++++++++++++++++++++++++++++++++++++------ proto/ospf/iface.c | 9 +++-- proto/ospf/neighbor.c | 6 +-- proto/ospf/ospf.c | 4 +- proto/ospf/topology.c | 6 ++- 7 files changed, 139 insertions(+), 28 deletions(-) (limited to 'proto') diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 3cbcb6d..215dc81 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 7cbd655..24d6974 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 91b4792..03cc4ee 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 8db086e..e514a5d 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 ba8d7b9..0411d48 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 9ebef6b..232803d 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 3ca5e77..870c0bc 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; -- cgit v1.2.3