PROTOCOL_L3VPN,
PROTOCOL_OSPF,
PROTOCOL_MRT,
+ PROTOCOL_MRTLOAD,
PROTOCOL_PERF,
PROTOCOL_PIPE,
PROTOCOL_RADV,
extern struct protocol
proto_device, proto_radv, proto_rip, proto_static, proto_mrt,
- proto_ospf, proto_perf, proto_l3vpn, proto_aggregator,
+ proto_mrtload, proto_ospf, proto_perf, proto_l3vpn, proto_aggregator,
proto_pipe, proto_bgp, proto_bmp, proto_bfd, proto_babel, proto_rpki;
/*
rta_free(he->src);
if (he->uc)
- log(L_ERR "Hostcache is not empty in table %s", tab->name);
+ log(L_ERR "Hostcache is not empty in table %s, count %i", tab->name, he->uc);
}
/* Freed automagically by the resource pool
#define REPORT(msg, args...) \
- ({ log(L_REMOTE "%s: " msg, s->proto->p.name, ## args); })
+ ({ log(L_REMOTE "%s: " msg, s->proto_name, ## args); })
+
+#define RTRACE(msg, args...) \
+ ({ if (s->debug & D_ROUTES) \
+ log(L_TRACE "%s: " msg, s->proto_name, ## args); })
#define DISCARD(msg, args...) \
({ REPORT(msg, ## args); return; })
static void
bgp_decode_as_path(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
{
- struct bgp_proto *p = s->proto;
int as_length = s->as4_session ? 4 : 2;
- int as_sets = p->cf->allow_as_sets;
- int as_confed = p->cf->confederation && p->is_interior;
+ int as_sets = s->allow_as_sets;
+ int as_confed = s->confederation && s->is_interior;
char err[128];
if (!as_path_valid(data, len, as_length, as_sets, as_confed, err, sizeof(err)))
}
/* In some circumstances check for initial AS_CONFED_SEQUENCE; RFC 5065 5.0 */
- if (p->is_interior && !p->is_internal &&
+ if (s->is_interior && !s->is_internal &&
((len < 2) || (data[0] != AS_PATH_CONFED_SEQUENCE)))
WITHDRAW("Malformed AS_PATH attribute - %s", "missing initial AS_CONFED_SEQUENCE");
/* Reject routes with first AS in AS_PATH not matching neighbor AS; RFC 4271 6.3 */
- if (!p->is_internal && p->cf->enforce_first_as &&
- !bgp_as_path_first_as_equal(data, len, p->remote_as))
+ if (!s->is_internal && s->enforce_first_as &&
+ !bgp_as_path_first_as_equal(data, len, s->remote_as))
WITHDRAW("Malformed AS_PATH attribute - %s", "First AS differs from neigbor AS");
bgp_set_attr_data(to, s->pool, BA_AS_PATH, flags, data, len);
static void
bgp_decode_local_pref(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
{
- if (!s->proto->is_interior && !s->proto->cf->allow_local_pref)
+ if (!s->is_interior && !s->allow_local_pref)
DISCARD(BAD_EBGP, "LOCAL_PREF");
if (len != 4)
static void
bgp_decode_originator_id(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
{
- if (!s->proto->is_internal)
+ if (!s->is_internal)
DISCARD(BAD_EBGP, "ORIGINATOR_ID");
if (len != 4)
static void
bgp_decode_cluster_list(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
{
- if (!s->proto->is_internal)
+ if (!s->is_internal)
DISCARD(BAD_EBGP, "CLUSTER_LIST");
if (!len || (len % 4))
static void
bgp_decode_as4_path(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
{
- struct bgp_proto *p = s->proto;
- int sets = p->cf->allow_as_sets;
+ int sets = s->allow_as_sets;
char err[128];
static void bgp_process_as4_attrs(ea_list **attrs, struct linpool *pool);
static inline int
-bgp_as_path_loopy(struct bgp_proto *p, ea_list *attrs, u32 asn)
+bgp_as_path_loopy(struct bgp_parse_state *s, ea_list *attrs, u32 asn)
{
eattr *e = bgp_find_attr(attrs, BA_AS_PATH);
- int num = p->cf->allow_local_as + 1;
+ int num = s->allow_local_as + 1;
return (e && (num > 0) && as_path_contains(e->u.ptr, asn, num));
}
static inline int
-bgp_originator_id_loopy(struct bgp_proto *p, ea_list *attrs)
+bgp_originator_id_loopy(struct bgp_parse_state *s, ea_list *attrs)
{
eattr *e = bgp_find_attr(attrs, BA_ORIGINATOR_ID);
- return (e && (e->u.data == p->local_id));
+ return (e && (e->u.data == s->local_id));
}
static inline int
-bgp_cluster_list_loopy(struct bgp_proto *p, ea_list *attrs)
+bgp_cluster_list_loopy(u32 rr_cluster_id, ea_list *attrs)
{
eattr *e = bgp_find_attr(attrs, BA_CLUSTER_LIST);
- return (e && int_set_contains(e->u.ptr, p->rr_cluster_id));
+ return (e && int_set_contains(e->u.ptr, rr_cluster_id));
}
static inline void
if (BIT32_TEST(s->attrs_seen, code))
{
if ((code == BA_MP_REACH_NLRI) || (code == BA_MP_UNREACH_NLRI))
- bgp_parse_error(s, 1);
+ s->parse_error(s, 1);
else
DISCARD("Discarding duplicate attribute (code %u)", code);
}
* by an (uncached) &rta.
*/
ea_list *
-bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len, void (*parse_error)(struct bgp_parse_state *, uint))
+bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len)
{
- struct bgp_proto *p = s->proto;
ea_list *attrs = NULL;
uint code, flags, alen;
byte *pos = data;
/* When receiving attributes from non-AS4-aware BGP speaker, we have to
reconstruct AS_PATH and AGGREGATOR attributes; RFC 6793 4.2.3 */
- if (!p->as4_session)
+ if (!s->as4_session)
bgp_process_as4_attrs(&attrs, s->pool);
+#define IS_LOOP(msg, args...) { RTRACE("update is loop (" msg "), treating as withdraw", ##args); goto loop; }
+
/* Reject routes with our ASN in AS_PATH attribute */
- if (bgp_as_path_loopy(p, attrs, p->local_as))
+ if (bgp_as_path_loopy(s, attrs, s->local_as))
goto loop;
/* 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 ((s->public_as != s->local_as) && bgp_as_path_loopy(s, attrs, s->public_as))
goto loop;
/* Reject routes with our Router ID in ORIGINATOR_ID attribute; RFC 4456 8 */
- if (p->is_internal && bgp_originator_id_loopy(p, attrs))
+ if (s->is_internal && bgp_originator_id_loopy(s, attrs))
goto loop;
/* Reject routes with our Cluster ID in CLUSTER_LIST attribute; RFC 4456 8 */
- if (p->rr_client && bgp_cluster_list_loopy(p, attrs))
+ if (s->rr_client && bgp_cluster_list_loopy(s->rr_cluster_id, attrs))
goto loop;
/* If there is no local preference, define one */
if (!BIT32_TEST(s->attrs_seen, BA_LOCAL_PREF))
- bgp_set_attr_u32(&attrs, s->pool, BA_LOCAL_PREF, 0, p->cf->default_local_pref);
+ bgp_set_attr_u32(&attrs, s->pool, BA_LOCAL_PREF, 0, s->default_local_pref);
return attrs;
withdraw:
/* RFC 7606 5.2 - handle missing NLRI during errors */
if (!s->ip_reach_len && !s->mp_reach_len)
- parse_error(s, 1);
+ s->parse_error(s, 1);
s->err_withdraw = 1;
return NULL;
bgp_finish_attrs(struct bgp_parse_state *s, rta *a)
{
/* AIGP test here instead of in bgp_decode_aigp() - we need to know channel */
- if (BIT32_TEST(s->attrs_seen, BA_AIGP) && !s->channel->cf->aigp)
+ struct bgp_channel *c = SKIP_BACK(struct bgp_channel, c, s->channel);
+ if (BIT32_TEST(s->attrs_seen, BA_AIGP) && !c->cf->aigp)
{
REPORT("Discarding AIGP attribute received on non-AIGP session");
bgp_unset_attr(&a->eattrs, s->pool, BA_AIGP);
}
/* Handle OTC ingress procedure, RFC 9234 */
- if (bgp_channel_is_role_applicable(s->channel))
+ if (bgp_channel_is_role_applicable(c))
{
- struct bgp_proto *p = s->proto;
eattr *e = bgp_find_attr(a->eattrs, BA_ONLY_TO_CUSTOMER);
/* Reject routes from downstream if they are leaked */
- if (e && (p->cf->local_role == BGP_ROLE_PROVIDER ||
- p->cf->local_role == BGP_ROLE_RS_SERVER))
+ if (e && (s->local_role == BGP_ROLE_PROVIDER ||
+ s->local_role == BGP_ROLE_RS_SERVER))
WITHDRAW("Route leak detected - OTC attribute from downstream");
/* Reject routes from peers if they are leaked */
- if (e && (p->cf->local_role == BGP_ROLE_PEER) && (e->u.data != p->cf->remote_as))
+ if (e && (s->local_role == BGP_ROLE_PEER) && (e->u.data != s->remote_as))
WITHDRAW("Route leak detected - OTC attribute with mismatched ASN (%u)",
(uint) e->u.data);
/* Mark routes from upstream if it did not happened before */
- if (!e && (p->cf->local_role == BGP_ROLE_CUSTOMER ||
- p->cf->local_role == BGP_ROLE_PEER ||
- p->cf->local_role == BGP_ROLE_RS_CLIENT))
- bgp_set_attr_u32(&a->eattrs, s->pool, BA_ONLY_TO_CUSTOMER, 0, p->cf->remote_as);
+ if (!e && (s->local_role == BGP_ROLE_CUSTOMER ||
+ s->local_role == BGP_ROLE_PEER ||
+ s->local_role == BGP_ROLE_RS_CLIENT))
+ bgp_set_attr_u32(&a->eattrs, s->pool, BA_ONLY_TO_CUSTOMER, 0, s->remote_as);
}
/* Apply MPLS policy for labeled SAFIs */
- if (s->mpls && s->proto->p.mpls_channel)
+ if (s->mpls && s->mpls_channel)
{
- struct mpls_channel *mc = (void *) s->proto->p.mpls_channel;
+ struct mpls_channel *mc = (void *) s->mpls_channel;
ea_set_attr_u32(&a->eattrs, s->pool, EA_MPLS_POLICY, 0, EAF_TYPE_INT, mc->label_policy);
}
}
/* Generally, this should be handled when path is received, but we check it
also here as rr_cluster_id may be undefined or different in src. */
- if (p->rr_cluster_id && bgp_cluster_list_loopy(p, e->attrs->eattrs))
+ if (p->rr_cluster_id && bgp_cluster_list_loopy(p->rr_cluster_id, e->attrs->eattrs))
return -1;
}
return P;
}
-static void
+void
bgp_channel_init(struct channel *C, struct channel_config *CF)
{
struct bgp_channel *c = (void *) C;
return 0; /* XXXX: Currently undefined */
}
-static void
+void
bgp_channel_shutdown(struct channel *C)
{
struct bgp_channel *c = (void *) C;
c->packets_to_send = 0;
}
-static void
+void
bgp_channel_cleanup(struct channel *C)
{
struct bgp_channel *c = (void *) C;
};
struct bgp_parse_state {
- struct bgp_proto *proto;
- struct bgp_channel *channel;
+ // instead of struct bgp_proto *proto;
+ struct proto *p;
+ u32 local_as;
+ u32 public_as;
+ u32 remote_as;
+ u32 rr_cluster_id;
+ u32 local_id;
+ u8 is_mrt_parse;
+ u8 is_interior;
+ u8 is_internal;
+ const char *proto_name;
+ u32 debug; /* Debugging flags */
+ struct channel *mpls_channel;
+
+ // from config
+ int allow_as_sets;
+ int allow_local_pref;
+ int allow_local_as;
+ int enforce_first_as;
+ u32 default_local_pref;
+ u32 confederation;
+ u8 local_role;
+ int rr_client;
+ ip_addr remote_ip;
+
+ struct channel *channel;
struct linpool *pool;
-, void (*parse_error)(struct bgp_parse_state *, uint);
- void (*rte_update)(struct bgp_parse_state *, ...);
+ void (*parse_error)(struct bgp_parse_state *, uint);
+ void (*rte_update)(struct bgp_parse_state *, const net_addr *, u32, rta *);
+ void (*bgp_apply_next_hop)(struct bgp_parse_state *, rta *, ip_addr, ip_addr);
+ bool (*get_channel)(struct bgp_parse_state *, u32);
+ void (*apply_mpls_labels)(struct bgp_parse_state *, rta *, u32 *, uint);
+ void (*end_mark)(struct bgp_parse_state *, u32);
int as4_session;
int add_path;
int mpls;
int reach_nlri_step;
+ const struct bgp_af_desc *desc;
+ u16 preference;
u32 attrs_seen[256/32];
void bgp_store_error(struct bgp_proto *p, struct bgp_conn *c, u8 class, u32 code);
void bgp_stop(struct bgp_proto *p, int subcode, byte *data, uint len);
const char *bgp_format_role_name(u8 role);
+void bgp_rte_update(struct bgp_parse_state *s, const net_addr *n, u32 path_id, rta *a0);
+
+void bgp_channel_init(struct channel *C, struct channel_config *CF);
+void bgp_channel_shutdown(struct channel *C);
+void bgp_channel_cleanup(struct channel *C);
void bgp_fix_attr_flags(ea_list *attrs);
const char * bgp_attr_name(uint code);
int bgp_encode_attrs(struct bgp_write_state *s, ea_list *attrs, byte *buf, byte *end);
ea_list * bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len);
-int bgp_parse_update(struct bgp_parse_state *s, byte *pkt, uint len, ea_list **ea);
+void bgp_parse_update(struct bgp_parse_state *s, byte *pkt, uint len, ea_list **ea);
void bgp_finish_attrs(struct bgp_parse_state *s, rta *a);
void bgp_init_bucket_table(struct bgp_channel *c);
return NULL;
}
+bool
+bgp_get_channel_to_parse(struct bgp_parse_state *s, u32 afi)
+{
+ struct bgp_proto *p = (struct bgp_proto *) s->p;
+ struct bgp_channel *c = bgp_get_channel(p, afi);
+
+ if (!c)
+ return false;
+
+ s->channel = &c->c;
+ s->add_path = c->add_path_rx;
+ s->mpls = c->desc->mpls;
+
+ s->last_id = 0;
+ s->last_src = s->p->main_source;
+ s->desc = c->desc;
+ return true;
+}
+
static inline void
put_af3(byte *buf, u32 id)
{
*/
#define REPORT(msg, args...) \
- ({ log(L_REMOTE "%s: " msg, s->proto->p.name, ## args); })
+ ({ log(L_REMOTE "%s: " msg, s->p->name, ## args); })
#define DISCARD(msg, args...) \
({ REPORT(msg, ## args); return; })
static void
bgp_apply_next_hop(struct bgp_parse_state *s, rta *a, ip_addr gw, ip_addr ll)
{
- struct bgp_proto *p = s->proto;
- struct bgp_channel *c = s->channel;
+ ASSERT_DIE(s->p);
+ struct bgp_proto *p = (struct bgp_proto *) s->p;
+ struct bgp_channel *c = SKIP_BACK(struct bgp_channel, c, s->channel);
if (c->cf->gw_mode == GW_DIRECT)
{
if ((lnum == 1) && (labels[0] == BGP_MPLS_NULL))
lnum = 0;
- if (s->channel->cf->gw_mode == GW_DIRECT)
+ struct bgp_channel *c = SKIP_BACK(struct bgp_channel, c, s->channel);
+ if (c->cf->gw_mode == GW_DIRECT)
{
a->nh.labels = lnum;
memcpy(a->nh.label, labels, 4*lnum);
static void
bgp_apply_flow_validation(struct bgp_parse_state *s, const net_addr *n, rta *a)
{
- struct bgp_channel *c = s->channel;
- int valid = rt_flowspec_check(c->base_table, c->c.table, n, a, s->proto->is_interior);
+ struct bgp_channel *c = SKIP_BACK(struct bgp_channel, c, s->channel);
+ int valid = rt_flowspec_check(c->base_table, c->c.table, n, a, s->is_interior);
a->dest = valid ? RTD_NONE : RTD_UNREACHABLE;
/* Invalidate cached rta if dest changes */
bgp_use_next_hop(struct bgp_export_state *s, eattr *a)
{
struct bgp_proto *p = s->proto;
- struct bgp_channel *c = s->channel;
+ struct bgp_channel *c = SKIP_BACK(struct bgp_channel, c, s->channel);
ip_addr *nh = (void *) a->u.ptr->data;
/* Handle next hop self option */
bgp_use_gateway(struct bgp_export_state *s)
{
struct bgp_proto *p = s->proto;
- struct bgp_channel *c = s->channel;
+ struct bgp_channel *c = SKIP_BACK(struct bgp_channel, c, s->channel);
rta *ra = s->route->attrs;
/* Handle next hop self option - also applies to gateway */
static void
bgp_decode_next_hop_ip(struct bgp_parse_state *s, byte *data, uint len, rta *a)
{
- struct bgp_channel *c = s->channel;
struct adata *ad = lp_alloc_adata(s->pool, 32);
ip_addr *nh = (void *) ad->data;
if (ipa_zero(nh[1]))
ad->length = 16;
- if ((bgp_channel_is_ipv4(c) != ipa_is_ip4(nh[0])) && !c->ext_next_hop)
- WITHDRAW(BAD_NEXT_HOP MISMATCHED_AF, nh[0], c->desc->name);
+ if (!s->is_mrt_parse)
+ {
+ struct bgp_channel *c = SKIP_BACK(struct bgp_channel, c, s->channel);
+ if ((bgp_channel_is_ipv4(c) != ipa_is_ip4(nh[0])) && !c->ext_next_hop)
+ WITHDRAW(BAD_NEXT_HOP MISMATCHED_AF, nh[0], c->desc->name);
+ }
// XXXX validate next hop
static void
bgp_decode_next_hop_vpn(struct bgp_parse_state *s, byte *data, uint len, rta *a)
{
- struct bgp_channel *c = s->channel;
struct adata *ad = lp_alloc_adata(s->pool, 32);
ip_addr *nh = (void *) ad->data;
if ((get_u64(data) != 0) || ((len == 48) && (get_u64(data+24) != 0)))
bgp_parse_error(s, 9);
- if ((bgp_channel_is_ipv4(c) != ipa_is_ip4(nh[0])) && !c->ext_next_hop)
- WITHDRAW(BAD_NEXT_HOP MISMATCHED_AF, nh[0], c->desc->name);
+ if (!s->is_mrt_parse)
+ {
+ struct bgp_channel *c = SKIP_BACK(struct bgp_channel, c, s->channel);
+
+ if ((bgp_channel_is_ipv4(c) != ipa_is_ip4(nh[0])) && !c->ext_next_hop)
+ WITHDRAW(BAD_NEXT_HOP MISMATCHED_AF, nh[0], c->desc->name);
+ }
// XXXX validate next hop
* UPDATE
*/
-static void
+void
bgp_rte_update(struct bgp_parse_state *s, const net_addr *n, u32 path_id, rta *a0)
{
+ ASSERT_DIE(s->p);
+
if (path_id != s->last_id)
{
- s->last_src = rt_get_source(&s->proto->p, path_id);
+ s->last_src = rt_get_source(s->p, path_id);
s->last_id = path_id;
rta_free(s->cached_rta);
REPORT("Invalid route %N withdrawn", n);
/* Route withdraw */
- rte_update3(&s->channel->c, n, NULL, s->last_src);
+ rte_update3(s->channel, n, NULL, s->last_src);
return;
}
rta *a = rta_clone(s->cached_rta);
rte *e = rte_get_temp(a, s->last_src);
- rte_update3(&s->channel->c, n, e, s->last_src);
+ rte_update3(s->channel, n, e, s->last_src);
}
static void
memcpy(s->mpls_labels->data, labels, 4*lnum);
/* Update next hop entry in rta */
- bgp_apply_mpls_labels(s, a, labels, lnum);
+ s->apply_mpls_labels(s, a, labels, lnum);
/* Attributes were changed, invalidate cached entry */
rta_free(s->cached_rta);
enum flow_validated_state r = flow4_validate(data, dlen);
if (r != FLOW_ST_VALID)
{
- log(L_REMOTE "%s: Invalid flow route: %s", s->proto->p.name, flow_validated_state_str(r));
+ log(L_REMOTE "%s: Invalid flow route: %s", s->proto_name, flow_validated_state_str(r));
bgp_parse_error(s, 1);
}
ADVANCE(pos, len, flen);
/* Apply validation procedure per RFC 8955 (6) */
- if (a && s->channel->cf->validate)
- bgp_apply_flow_validation(s, n, a);
+ if (!s->is_mrt_parse)
+ {
+ struct bgp_channel *c = SKIP_BACK(struct bgp_channel, c, s->channel);
+
+ if (a && c->cf->validate)
+ bgp_apply_flow_validation(s, n, a);
+ }
bgp_rte_update(s, n, path_id, a);
}
enum flow_validated_state r = flow6_validate(data, dlen);
if (r != FLOW_ST_VALID)
{
- log(L_REMOTE "%s: Invalid flow route: %s", s->proto->p.name, flow_validated_state_str(r));
+ log(L_REMOTE "%s: Invalid flow route: %s", s->proto_name, flow_validated_state_str(r));
bgp_parse_error(s, 1);
}
ADVANCE(pos, len, flen);
/* Apply validation procedure per RFC 8955 (6) */
- if (a && s->channel->cf->validate)
- bgp_apply_flow_validation(s, n, a);
+ if (!s->is_mrt_parse)
+ {
+ struct bgp_channel *c = SKIP_BACK(struct bgp_channel, c, s->channel);
+
+ if (a && c->cf->validate)
+ bgp_apply_flow_validation(s, n, a);
+ }
bgp_rte_update(s, n, path_id, a);
}
static inline void
bgp_rx_end_mark(struct bgp_parse_state *s, u32 afi)
{
- struct bgp_proto *p = s->proto;
+ struct bgp_proto *p = (struct bgp_proto *) s->p;
struct bgp_channel *c = bgp_get_channel(p, afi);
BGP_TRACE(D_PACKETS, "Got END-OF-RIB");
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)
{
- struct bgp_channel *c = bgp_get_channel(s->proto, afi);
- rta *a = NULL;
-
- if (!c)
+ if (!s->get_channel(s, afi))
DISCARD(BAD_AFI, BGP_AFI(afi), BGP_SAFI(afi));
- s->channel = c;
- s->add_path = c->add_path_rx;
- s->mpls = c->desc->mpls;
-
- s->last_id = 0;
- s->last_src = s->proto->p.main_source;
+ rta *a = NULL;
/*
* IPv4 BGP and MP-BGP may be used together in one update, therefore we do not
a->source = RTS_BGP;
a->scope = SCOPE_UNIVERSE;
- a->from = s->proto->remote_ip;
+ a->from = s->remote_ip;
a->eattrs = ea;
- a->pref = c->c.preference;
+ a->pref = s->channel->preference;
- c->desc->decode_next_hop(s, nh, nh_len, a);
+ s->desc->decode_next_hop(s, nh, nh_len, a);
bgp_finish_attrs(s, a);
/* Handle withdraw during next hop decoding */
a = NULL;
}
- c->desc->decode_nlri(s, nlri, len, a);
+ s->desc->decode_nlri(s, nlri, len, a);
rta_free(s->cached_rta);
s->cached_rta = NULL;
}
-int
-bgp_parse_update(struct bgp_parse_state *s, byte *pkt, uint len, ea_list **ea, void (*parse_error)(struct bgp_parse_state *, uint))
+void
+bgp_parse_update(struct bgp_parse_state *s, byte *pkt, uint len, ea_list **ea)
{
/*
* UPDATE message format
* var Path Attributes
* var IPv4 Reachable Routes NLRI
*/
- log("in parse update, len %i", len);
uint pos = 0;
s->ip_unreach_len = get_u16(pkt + pos);
- log("s->ip_unreach_len %i", s->ip_unreach_len);
s->ip_unreach_nlri = pkt + pos + 2;
pos += 2 + s->ip_unreach_len;
if (pos + 2 > len)
{
- parse_error(s, 1);
- return 0;
+ s->parse_error(s, 1);
+ return;
}
s->attr_len = get_u16(pkt + pos);
- log("s->attr_len %i", s->attr_len);
s->attrs = pkt + pos + 2;
pos += 2 + s->attr_len;
if (pos > len)
{
- parse_error(s, 1);
- return 0;
+ s->parse_error(s, 1);
+ return;
}
s->ip_reach_len = len - pos;
s->ip_reach_nlri = pkt + pos;
if (s->attr_len)
- *ea = bgp_decode_attrs(s, s->attrs, s->attr_len, parse_error);
+ *ea = bgp_decode_attrs(s, s->attrs, s->attr_len);
else
*ea = NULL;
- return 1;
+
+ /* Check for End-of-RIB marker */
+ if (!s->attr_len && !s->ip_unreach_len && !s->ip_reach_len)
+ { s->end_mark(s, BGP_AF_IPV4); return; }
+
+ /* Check for MP End-of-RIB marker */
+ if ((s->attr_len < 8) && !s->ip_unreach_len && !s->ip_reach_len &&
+ !s->mp_reach_len && !s->mp_unreach_len && s->mp_unreach_af)
+ { s->end_mark(s, s->mp_unreach_af); return; }
+
+ if (s->ip_unreach_len)
+ bgp_decode_nlri(s, BGP_AF_IPV4, s->ip_unreach_nlri, s->ip_unreach_len, NULL, NULL, 0);
+
+ if (s->mp_unreach_len)
+ bgp_decode_nlri(s, s->mp_unreach_af, s->mp_unreach_nlri, s->mp_unreach_len, NULL, NULL, 0);
+
+ s->reach_nlri_step = 1;
+
+ if (s->ip_reach_len)
+ bgp_decode_nlri(s, BGP_AF_IPV4, s->ip_reach_nlri, s->ip_reach_len,
+ *ea, s->ip_next_hop_data, s->ip_next_hop_len);
+
+ if (s->mp_reach_len)
+ bgp_decode_nlri(s, s->mp_reach_af, s->mp_reach_nlri, s->mp_reach_len,
+ *ea, s->mp_next_hop_data, s->mp_next_hop_len);
}
static void
bgp_rx_update(struct bgp_conn *conn, byte *pkt, uint len)
{
- log("bgp_rx_update");
struct bgp_proto *p = conn->bgp;
ea_list *ea = NULL;
/* Initialize parse state */
struct bgp_parse_state s = {
- .proto = p,
+ .p = &p->p,
+ .parse_error = bgp_parse_error,
+ .end_mark = bgp_rx_end_mark,
+ .get_channel = bgp_get_channel_to_parse,
+ .apply_mpls_labels = bgp_apply_mpls_labels,
+
+ .local_as = p->local_as,
+ .remote_ip = p->remote_ip,
+ .public_as = p->public_as,
+ .remote_as = p->remote_as,
+ .rr_cluster_id = p->rr_cluster_id,
+ .local_id = p->local_id,
+ .is_interior = p->is_interior,
+ .is_internal = p->is_internal,
+ .proto_name = p->p.name,
+ .is_mrt_parse = 0,
+ .debug = p->p.debug,
+ .mpls_channel = p->p.mpls_channel,
+
+ // from config
+ .default_local_pref = p->cf->default_local_pref,
+ .allow_local_pref = p->cf->allow_local_pref,
+ .allow_as_sets = p->cf->allow_as_sets,
+ .allow_local_as = p->cf->allow_local_as,
+ .confederation = p->cf->confederation,
+ .enforce_first_as = p->cf->enforce_first_as,
+ .local_role = p->cf->local_role,
+ .rr_client = p->cf->rr_client,
+
.pool = tmp_linpool,
.as4_session = p->as4_session,
};
if (len < 23)
{ bgp_error(conn, 1, 2, pkt+16, 2); return; }
- bgp_parse_update(&s, pkt + 19, len - 19, &ea, bgp_parse_error); /* add 19 to skip fixed header */
- log("yay update parsed");
-
- /* Check for End-of-RIB marker */
- if (!s.attr_len && !s.ip_unreach_len && !s.ip_reach_len)
- { bgp_rx_end_mark(&s, BGP_AF_IPV4); goto done; }
-
- /* Check for MP End-of-RIB marker */
- if ((s.attr_len < 8) && !s.ip_unreach_len && !s.ip_reach_len &&
- !s.mp_reach_len && !s.mp_unreach_len && s.mp_unreach_af)
- { bgp_rx_end_mark(&s, s.mp_unreach_af); goto done; }
-
- if (s.ip_unreach_len)
- bgp_decode_nlri(&s, BGP_AF_IPV4, s.ip_unreach_nlri, s.ip_unreach_len, NULL, NULL, 0);
-
- if (s.mp_unreach_len)
- bgp_decode_nlri(&s, s.mp_unreach_af, s.mp_unreach_nlri, s.mp_unreach_len, NULL, NULL, 0);
-
- s.reach_nlri_step = 1;
-
- if (s.ip_reach_len)
- bgp_decode_nlri(&s, BGP_AF_IPV4, s.ip_reach_nlri, s.ip_reach_len,
- ea, s.ip_next_hop_data, s.ip_next_hop_len);
-
- if (s.mp_reach_len)
- bgp_decode_nlri(&s, s.mp_reach_af, s.mp_reach_nlri, s.mp_reach_len,
- ea, s.mp_next_hop_data, s.mp_next_hop_len);
+ bgp_parse_update(&s, pkt + 19, len - 19, &ea); /* add 19 to skip fixed header */
done:
rta_free(s.cached_rta);
byte type = pkt[18];
DBG("BGP: Got packet %02x (%d bytes)\n", type, len);
- log("BGP: Got packet %02x (%d bytes) !!!!!!!!!!!!!!!!!!\n", type, len);
conn->bgp->stats.rx_messages++;
conn->bgp->stats.rx_bytes += len;
- log("do we want to do mrt dump ? conn->bgp->p.mrtdump %x & MD_MESSAGES %x", conn->bgp->p.mrtdump, MD_MESSAGES);
if (conn->bgp->p.mrtdump & MD_MESSAGES)
bgp_dump_message(conn, pkt, len);
-src := mrt.c mrt_parse.c
+src := mrt.c mrt_load.c
obj := $(src-o-files)
$(all-daemon)
$(cf-local)
+$(conf-y-targets): $(s)mrtload.Y
tests_objs := $(tests_objs) $(src-o-files)
cli_printf(c, 0, "");
mrt_table_dump_free(c->rover);
c->cont = c->cleanup = c->rover = NULL;
- mrt_load("mrt_dump.txt");
- log("____________________________");
- mrt_load("dump.mrt");
- mrt_load("dump_bgp.mrt");
}
static void
void
mrt_dump_bgp_message(struct mrt_bgp_data *d)
{
- log("mrt_dump_bgp_message");
const u16 subtypes[] = {
MRT_BGP4MP_MESSAGE, MRT_BGP4MP_MESSAGE_AS4,
MRT_BGP4MP_MESSAGE_LOCAL, MRT_BGP4MP_MESSAGE_AS4_LOCAL,
#include "nest/route.h"
#include "lib/event.h"
#include "lib/hash.h"
-#include "proto/bgp/bgp.h"
struct mrt_config {
static inline void mrt_dump_bgp_state_change(struct mrt_bgp_data *d UNUSED) { }
#endif
-void mrt_load(char *file);
-
#endif /* _BIRD_MRT_H_ */
--- /dev/null
+
+#include <stdio.h>
+
+#include "mrt.h"
+#include "mrt_load.h"
+
+
+byte
+mrtload_one(FILE *fp, u64 *remains)
+{
+ remains[0]--;
+ return fgetc(fp);
+}
+
+void
+mrtload_n_octet(FILE *fp, u64 *remains, byte *buff, int n)
+{
+ for (int i = 0; i < n; i++)
+ buff[i] = fgetc(fp);
+
+ remains[0] = remains[0] - n;
+}
+
+u64
+mrtload_four_octet(FILE *fp, u64 *remains)
+{
+ u64 ret = 0;
+
+ for (int i = 0; i < 4; i++)
+ {
+ ret = ret << 8;
+ ret += fgetc(fp);
+ }
+
+ remains[0] = remains[0] - 4;
+
+ return ret;
+}
+
+void
+mrtload_ip(FILE *fp, u64 *remains, ip_addr *addr, bool is_ip6)
+{
+ if (is_ip6)
+ for (int i = 0; i < 4; i++)
+ addr->addr[i] = mrtload_four_octet(fp, remains);
+ else
+ {
+ addr->addr[0] = addr->addr[1] = addr->addr[2] = 0;
+ addr->addr[3] = mrtload_four_octet(fp, remains);
+ }
+}
+
+u32
+mrtload_two_octet(FILE *fp, u64 *remains)
+{
+ remains[0] = remains[0] - 2;
+ return (fgetc(fp) << 8) + fgetc(fp);
+}
+
+void
+mrt_parse_error(struct bgp_parse_state * ps UNUSED, uint e UNUSED)
+{
+ log(L_WARN "mrt load: run into a parsing error");
+}
+
+/*
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Peer AS Number | Local AS Number |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Interface Index | Address Family |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Peer IP Address (variable) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Local IP Address (variable) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | BGP Message... (variable)
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ Figure 12: BGP4MP_MESSAGE Subtype
+*/
+void
+mrt_parse_bgp_message(FILE *fp, u64 *remains, bool as4)
+{
+ u64 peer_as, local_as;
+ if (as4)
+ {
+ peer_as = mrtload_four_octet(fp, remains);
+ local_as = mrtload_four_octet(fp, remains);
+ } else
+ {
+ peer_as = mrtload_two_octet(fp, remains);
+ local_as = mrtload_two_octet(fp, remains);
+ }
+
+ int interface_id = mrtload_two_octet(fp, remains);
+ int addr_fam = mrtload_two_octet(fp, remains);
+
+ ip_addr peer_addr, local_addr;
+ mrtload_ip(fp, remains, &peer_addr, addr_fam == 2);
+ mrtload_ip(fp, remains, &local_addr, addr_fam == 2);
+
+ log("peer as %lx local as %lx interface %x add fam %i peer %I loc %I", peer_as, local_as, interface_id, addr_fam, peer_addr, local_addr);
+}
+
+static void
+mrt_rx_end_mark(struct bgp_parse_state *s UNUSED, u32 afi UNUSED)
+{
+ /* Do nothing */
+}
+
+bool
+mrt_get_channel_to_parse(struct bgp_parse_state *s UNUSED, u32 afi UNUSED)
+{
+ struct mrtload_proto *p = SKIP_BACK(struct mrtload_proto, p, s->p);
+ s->channel = &p->channel->c;
+ s->last_id = 0;
+ s->last_src = s->p->main_source;
+ s->desc = p->channel->desc;
+ s->channel->proto = s->p;
+ channel_set_state(s->channel, CS_START);
+ channel_set_state(s->channel, CS_UP);
+ return true;
+}
+
+static void
+mrt_apply_mpls_labels(struct bgp_parse_state *s UNUSED, rta *a UNUSED, u32 *labels UNUSED, uint lnum UNUSED)
+{
+ /* Do nothing */
+}
+
+static void
+mrt_parse_bgp4mp_message(FILE *fp, u64 *remains, bool as4, struct proto *P)
+{
+ mrt_parse_bgp_message(fp, remains, as4);
+
+ if (*remains < 19)
+ {
+ log(L_WARN "MRT parse BGP message: BGP message is too short (%i)", *remains);
+ return;
+ }
+
+ for (int i = 0; i < 16; i++) /* skip marker */
+ fgetc(fp);
+
+ remains[0] = remains[0] - 16;
+ u64 length = mrtload_two_octet(fp, remains) - 16 - 2 -1; /* length without header (marker, length, type) */
+ int type = mrtload_one(fp, remains);
+
+ if (type != PKT_UPDATE)
+ return;
+
+ /* This is usually done in proto_do_up, but the protocol will be used immediately */
+ P->main_source = rt_get_source(P, 0);
+ rt_lock_source(P->main_source);
+
+ struct bgp_parse_state s = {
+ .pool = lp_new(P->pool),
+ .parse_error = mrt_parse_error,
+ .end_mark = mrt_rx_end_mark,
+ .get_channel = mrt_get_channel_to_parse,
+ .apply_mpls_labels = mrt_apply_mpls_labels,
+ .is_mrt_parse = 1,
+ .p = P,
+ };
+
+ byte buf[length];
+ ASSERT_DIE(length <= remains[0]);
+ mrtload_n_octet(fp, remains, buf, length);
+ ea_list *ea = NULL;
+ bgp_parse_update(&s, buf, length, &ea);
+}
+
+int
+mrt_parse_general_header(FILE *fp, struct proto *P)
+{
+ char is_eof = fgetc(fp);
+ u64 timestamp = is_eof;
+
+ if (is_eof == EOF)
+ return 0;
+ else
+ {
+ for (int i = 0; i < 3; i++)
+ {
+ timestamp = timestamp << 8;
+ timestamp += fgetc(fp);
+ }
+ }
+
+ int type = (fgetc(fp) << 8) + fgetc(fp);
+ int subtype = (fgetc(fp) << 8) + fgetc(fp);
+ u64 length = 0;
+
+ for (int i = 0; i < 4; i++)
+ {
+ length = length << 8;
+ length += fgetc(fp);
+ }
+ u64 remains = length;
+
+ /* We do not load MRT_TABLE_DUMP_V2 type and MRT_BGP4MP_STATE_CHANGE_AS4. */
+ if (type == MRT_BGP4MP)
+ {
+ switch (subtype)
+ {
+ case (MRT_BGP4MP_MESSAGE):
+ case (MRT_BGP4MP_MESSAGE_LOCAL):
+ case (MRT_BGP4MP_MESSAGE_ADDPATH):
+ mrt_parse_bgp4mp_message(fp, &remains, false, P);
+ break;
+ case (MRT_BGP4MP_STATE_CHANGE_AS4):
+ break;
+ case (MRT_BGP4MP_MESSAGE_AS4):
+ case (MRT_BGP4MP_MESSAGE_AS4_LOCAL):
+ case (MRT_BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH):
+ case (MRT_BGP4MP_MESSAGE_AS4_ADDPATH):
+ mrt_parse_bgp4mp_message(fp, &remains, true, P);
+ break;
+ }
+ }
+
+ ASSERT_DIE(remains <= length);
+
+ for (u64 i = 0; i < remains; i++)
+ fgetc(fp);
+
+ return 1;
+}
+
+void
+mrtload(struct proto *P)
+{
+ struct mrt_config *cf = SKIP_BACK(struct mrt_config, c, P->cf);
+ FILE *fp = fopen(cf->filename, "r");
+
+ if (fp == NULL)
+ {
+ log(L_WARN "Can not open file %s", fp);
+ return;
+ }
+
+ /* Parsing mrt headers in loop. MRT_BGP4MP messages are loaded, the rest is skipped. */
+ while (mrt_parse_general_header(fp, P));
+}
+
+void
+mrtload_check_config(struct proto_config *CF, struct bgp_channel_config *CC)
+{
+ struct mrtload_config *cf = (void *) CF;
+
+ if (!cf->table_cf)
+ cf_error("Table not specified");
+
+ if (!cf->filename)
+ cf_error("File not specified");
+
+ if (!CC->desc)
+ cf_error("Afi not specified.");
+}
+
+static struct proto *
+mrtload_init(struct proto_config *CF)
+{
+ struct proto *P = proto_new(CF);
+ struct mrtload_config *mlc = (struct mrtload_config *) CF;
+ proto_add_channel(P, &mlc->channel_cf->c);
+
+ return P;
+}
+
+static int
+mrtload_start(struct proto *P)
+{
+ struct mrtload_proto *p = (void *) P;
+ struct mrtload_config *cf = (void *) (P->cf);
+
+ p->channel = (void *) proto_add_channel(P, &cf->channel_cf->c);
+
+ p->channel->afi = cf->channel_cf->afi;
+ p->channel->desc = cf->channel_cf->desc;
+ p->channel->c.channel = &channel_mrtload;
+ p->channel->c.table = cf->table_cf->table;
+
+ if (cf->channel_cf->igp_table_ip4)
+ p->channel->igp_table_ip4 = cf->channel_cf->igp_table_ip4->table;
+
+ if (cf->channel_cf->igp_table_ip6)
+ p->channel->igp_table_ip6 = cf->channel_cf->igp_table_ip6->table;
+
+ mrtload(P);
+
+ return PS_UP;
+}
+
+
+static int
+mrtload_shutdown(struct proto *P)
+{
+ struct mrtload_proto *p = (void *) P;
+ proto_notify_state(&p->p, PS_DOWN);
+ return PS_DOWN;
+}
+
+static int
+mrtload_reconfigure(struct proto *P, struct proto_config *CF)
+{
+ //TODO where do we want reload mrt ?
+ P->cf = CF;
+ mrtload(P);
+
+ return 1;
+}
+
+
+static void
+mrtload_copy_config(struct proto_config *dest UNUSED, struct proto_config *src UNUSED)
+{
+ /* Do nothing */
+}
+
+static int
+mrtload_channel_start(struct channel *C)
+{
+ struct mrtload_proto *p = (void *) C->proto;
+ struct bgp_channel *c = (void *) C;
+ c->pool = p->p.pool;
+ return 0;
+}
+
+void
+mrtload_postconfig(struct proto_config *CF)
+{
+ struct mrtload_config *cf = (void *) CF;
+ if (cf->channel_cf->c.in_filter != FILTER_ACCEPT)
+ cf_error("MRT load channel in filter must be set to accept");
+ if (cf->channel_cf->c.out_filter != FILTER_REJECT)
+ cf_error("MRT load channel out filter must be set to reject");
+}
+
+
+static int
+mrtload_channel_reconfigure(struct channel *C UNUSED, struct channel_config *CC UNUSED,
+ int *import_changed UNUSED, int *export_changed UNUSED)
+{
+ struct bgp_channel *c = (void *) C;
+ struct bgp_channel_config *new = (void *) CC;
+ struct bgp_channel_config *old = c->cf;
+
+ if (old->afi != new->afi)
+ return 0;
+ if (old->desc != new->desc)
+ return 0;
+ if (old->c.table != new->c.table)
+ return 0;
+
+ if (old->igp_table_ip4)
+ if (!new->igp_table_ip4 || old->igp_table_ip4->table != new->igp_table_ip4->table)
+ return 0;
+
+ if (old->igp_table_ip6)
+ if (!new->igp_table_ip6 || old->igp_table_ip6->table != new->igp_table_ip6->table)
+ return 0;
+
+ c->cf = new;
+ return 1;
+}
+
+const struct channel_class channel_mrtload = {
+ .channel_size = sizeof(struct bgp_channel),
+ .config_size = sizeof(struct bgp_channel_config),
+ .init = bgp_channel_init,
+ .start = mrtload_channel_start,
+ .shutdown = bgp_channel_shutdown,
+ .cleanup = bgp_channel_cleanup,
+ .reconfigure = mrtload_channel_reconfigure,
+};
+
+
+struct protocol proto_mrtload = {
+ .name = "mrtload",
+ .template = "mrt%d",
+ .class = PROTOCOL_MRTLOAD,
+ .proto_size = sizeof(struct mrtload_proto),
+ .config_size = sizeof(struct mrt_config),
+ .init = mrtload_init,
+ .start = mrtload_start,
+ .shutdown = mrtload_shutdown,
+ .reconfigure = mrtload_reconfigure,
+ .postconfig = mrtload_postconfig,
+ .copy_config = mrtload_copy_config,
+ .channel_mask = NB_IP | NB_VPN | NB_FLOW | NB_MPLS,
+};
+
+void
+mrtload_build(void)
+{
+ proto_build(&proto_mrtload);
+}
--- /dev/null
+#ifndef _BIRD_MRT_LOAD_H_
+#define _BIRD_MRT_LOAD_H_
+
+#include "nest/bird.h"
+#include "nest/protocol.h"
+#include "lib/lists.h"
+#include "nest/route.h"
+#include "proto/bgp/bgp.h"
+#include "filter/filter.h"
+#include "proto/mrt/mrt.h"
+
+extern const struct channel_class channel_mrtload;
+
+struct mrtload_config {
+ struct proto_config c;
+
+ struct rtable_config *table_cf;
+ const char *table_expr;
+ const struct filter *filter;
+ const char *filename;
+ int always_add_path;
+ struct bgp_channel_config *channel_cf;
+ const struct bgp_af_desc *desc;
+};
+
+struct mrtload_proto {
+ struct proto p;
+
+ struct mrt_table_dump_state *table_dump;
+ struct bgp_channel *channel;
+};
+
+
+void mrtload_check_config(struct proto_config *CF, struct bgp_channel_config *CC);
+
+#endif /* _BIRD_MRT_LOAD_H_ */
+++ /dev/null
-
-#include "mrt.h"
-#include <stdio.h>
-
-
-byte
-mrt_load_one(FILE *fp, u64 *remains)
-{
- remains[0]--;
- return fgetc(fp);
-}
-
-void
-mrt_load_n_octet(FILE *fp, u64 *remains, byte *buff, int n)
-{
- for (int i = 0; i < n; i++)
- buff[i] = fgetc(fp);
- remains[0] = remains[0] - n;
-}
-
-u64
-mrt_load_four_octet(FILE *fp, u64 *remains)
-{
- u64 ret = 0;
- for (int i = 0; i < 4; i++)
- {
- ret = ret << 8;
- ret += fgetc(fp);
- }
- remains[0] = remains[0] - 4;
- return ret;
-}
-
-void
-mrt_load_ip(FILE *fp, u64 *remains, ip_addr *addr, bool is_ip6)
-{
- if (is_ip6)
- for (int i = 0; i < 4; i++)
- addr->addr[i] = mrt_load_four_octet(fp, remains);
- else
- {
- addr->addr[0] = addr->addr[1] = addr->addr[2] = 0;
- addr->addr[3] = mrt_load_four_octet(fp, remains);
- }
-}
-
-u32
-mrt_load_two_octet(FILE *fp, u64 *remains)
-{
- remains[0] = remains[0] - 2;
- return (fgetc(fp) << 8) + fgetc(fp);
-}
-
-/*
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Peer Type |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Peer BGP ID |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Peer IP Address (variable) |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Peer AS (variable) |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
- Figure 6: Peer Entries
-*/
-
-void
-mrt_parse_peer(FILE *fp, u64 *remains)
-{
- int peer_type = mrt_load_one(fp, remains);
- u64 peer_bgp_id = mrt_load_four_octet(fp, remains);
- ip_addr addr;
- u64 peer_as;
- mrt_load_ip(fp, remains, &addr, peer_type & MRT_PEER_TYPE_IPV6);
-
- if (peer_type & MRT_PEER_TYPE_32BIT_ASN)
- peer_as = mrt_load_four_octet(fp,remains);
- else
- peer_as = mrt_load_two_octet(fp, remains);
- log("peer type %i, bgp id %li adddr %I as %li", peer_type, peer_bgp_id, addr, peer_as);
-}
-
-/*
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Collector BGP ID |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | View Name Length | View Name (variable) |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Peer Count | Peer Entries (variable)
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
- Figure 5: PEER_INDEX_TABLE Subtype
-*/
-
-void
-mrt_parse_peer_index_table(FILE *fp, u64 *remains)
-{
- u64 collector = mrt_load_four_octet(fp, remains);
- int name_len = mrt_load_two_octet(fp, remains);
- log("name len %i collector %lx", name_len, collector);
- char name[name_len + 1];
- name[name_len] = 0;
- mrt_load_n_octet(fp, remains, name, name_len);
- int peer_count = mrt_load_two_octet(fp, remains);
- log("name %s, count %i", name, peer_count);
-
- for (int i = 0; i < peer_count; i++)
- mrt_parse_peer(fp, remains);
-}
-
-/*
-0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Peer Index |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Originated Time |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Attribute Length |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | BGP Attributes... (variable)
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-*/
-
-void
-mrt_parse_rib_entry(FILE *fp, u64 *remains, bool add_path)
-{
- int peer_index = mrt_load_two_octet(fp, remains);
- u64 orig_time = mrt_load_four_octet(fp, remains);
- u64 path_id;
-
- if (add_path)
- path_id = mrt_load_four_octet(fp, remains);
-
- int attr_len = mrt_load_two_octet(fp, remains);
- log("rib entry index %lx, time %lx, attr len %i (rem %li) path %li", peer_index, orig_time, attr_len, *remains, path_id);
- //TODO how are encoded the attrs?
- remains[0] = remains[0] - attr_len;
-
- for (int i = 0; i < attr_len; i++)
- fgetc(fp);
-}
-
-
-void
-mrt_parse_rib_generic(FILE *fp, u64 *remains)
-{
- u64 seq_num = mrt_load_four_octet(fp, remains);
- int addr_fam_id = mrt_load_two_octet(fp, remains);
- int subs_afi = mrt_load_one(fp, remains);
- log("seq num %lx, fam %i, subs %i", seq_num, addr_fam_id, subs_afi);
- //TODO length of Network layer reachebility
-}
-
-
-/*
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Sequence Number |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Prefix Length |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Prefix (variable) |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Entry Count | RIB Entries (variable)
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-*/
-void
-mrt_parse_rib4_unicast(FILE *fp, u64 *remains, bool add_path)
-{
- u64 seq_num = mrt_load_four_octet(fp, remains);
- int pref_len = mrt_load_one(fp, remains);
- byte prefix[pref_len/8];
- mrt_load_n_octet(fp, remains, prefix, pref_len/8);
- int entry_count = mrt_load_two_octet(fp, remains);
- log("seq %lx, pref len %i, enties %i", seq_num, pref_len, entry_count);
-
- for (int i = 0; i < entry_count; i++)
- mrt_parse_rib_entry(fp, remains, add_path);
-}
-
-
-void
-mrt_parse_error(struct bgp_parse_state * UNUSED, uint UNUSED)
-{
- log("run into a parsing error");
-}
-
-/*
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Peer AS Number | Local AS Number |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Interface Index | Address Family |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Peer IP Address (variable) |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Local IP Address (variable) |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | BGP Message... (variable)
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
- Figure 12: BGP4MP_MESSAGE Subtype
-*/
-void
-mrt_parse_bgp_message(FILE *fp, u64 *remains, bool as4)
-{
- u64 peer_as, local_as;
- if (as4)
- {
- peer_as = mrt_load_four_octet(fp, remains);
- local_as = mrt_load_four_octet(fp, remains);
- } else
- {
- peer_as = mrt_load_two_octet(fp, remains);
- local_as = mrt_load_two_octet(fp, remains);
- }
-
- int interface_id = mrt_load_two_octet(fp, remains);
- int addr_fam = mrt_load_two_octet(fp, remains);
-
- ip_addr peer_addr, local_addr;
- mrt_load_ip(fp, remains, &peer_addr, addr_fam == 2);
- mrt_load_ip(fp, remains, &local_addr, addr_fam == 2);
-
- log("peer as %lx local as %lx interface %x add fam %i peer %I loc %I", peer_as, local_as, interface_id, addr_fam, peer_addr, local_addr);
-}
-
-
-void
-mrt_parse_bgp4mp_message(FILE *fp, u64 *remains, bool as4)
-{
- log("hereeeee bgp message");
- mrt_parse_bgp_message(fp, remains, as4);
-
- if (*remains < 23)
- {
- log(L_WARN "MRT parse BGP message: BGP message is too short (%i)", *remains);
- return;
- }
-
- for (int i = 0; i < 16; i++) // marker
- fgetc(fp);
-
- remains[0] = remains[0] - 16;
- int length = mrt_load_two_octet(fp, remains);
- int type = mrt_load_one(fp, remains);
- log("message type %i", type);
-
- if (type != PKT_UPDATE)
- {
- log("Another BGP type");
- return;
- }
-
- struct bgp_parse_state s = {
- .pool = lp_new(&root_pool),
- };
- byte buf[length];
- mrt_load_n_octet(fp, remains, buf, length);
- ea_list *ea = NULL;
- log("try to parse bgp update");
- bgp_parse_update(&s, buf, length, &ea, bgp_parse_error);
- log("ok, seems parsed?");
-}
-
-
-void
-mrt_parse_bgp4mp_change_state(FILE *fp, u64 *remains, bool as4)
-{
- mrt_parse_bgp_message(fp, remains, as4);
- int old_state = mrt_load_two_octet(fp, remains);
- int new_state = mrt_load_two_octet(fp, remains);
- log("old state %i new state %i", old_state, new_state);
-}
-
-
-int
-mrt_parse_general_header(FILE *fp)
-{
- char is_eof = fgetc(fp);
- u64 timestamp = is_eof;
-
- if (is_eof == EOF)
- return 0;
- else
- {
- for (int i = 0; i < 3; i++)
- {
- log("t %lx", timestamp);
- timestamp = timestamp << 8;
- timestamp += fgetc(fp);
- }
- }
-
- log("timestamp is %lx", timestamp);
- int type = (fgetc(fp) << 8) + fgetc(fp);
- int subtype = (fgetc(fp) << 8) + fgetc(fp);
- log("type is %i, subtype %x", type, subtype);
- u64 length = 0;
-
- for (int i = 0; i < 4; i++)
- {
- length = length << 8;
- length += fgetc(fp);
- }
- u64 remains = length;
- log("remains is %li", remains);
-
- if (type == MRT_TABLE_DUMP_V2)
- {
- switch (subtype)
- {
- case (MRT_PEER_INDEX_TABLE):
- mrt_parse_peer_index_table(fp, &remains);
- break;
- case (MRT_RIB_IPV4_UNICAST):
- case (MRT_RIB_IPV6_UNICAST):
- case (MRT_RIB_IPV4_MULTICAST):
- case (MRT_RIB_IPV6_MULTICAST):
- mrt_parse_rib4_unicast(fp, &remains, false);
- break;
- case (MRT_RIB_IPV4_UNICAST_ADDPATH):
- case (MRT_RIB_IPV6_UNICAST_ADDPATH):
- case (MRT_RIB_IPV4_MULTICAST_ADDPATH):
- case (MRT_RIB_IPV6_MULTICAST_ADDPATH):
- mrt_parse_rib4_unicast(fp, &remains, true);
- break;
- case (MRT_RIB_GENERIC):
- case (MRT_RIB_GENERIC_ADDPATH):
- mrt_parse_rib_generic(fp, &remains);
- break;
- default:
- bug("mrt: unknown mrt table dump subtype");
- }
- } else
- {
- ASSERT_DIE(type == MRT_BGP4MP);
-
- switch (subtype)
- {
- case (MRT_BGP4MP_MESSAGE):
- case (MRT_BGP4MP_MESSAGE_LOCAL):
- case (MRT_BGP4MP_MESSAGE_ADDPATH):
- mrt_parse_bgp4mp_message(fp, &remains, false);
- break;
- case (MRT_BGP4MP_STATE_CHANGE_AS4):
- mrt_parse_bgp4mp_change_state(fp, &remains, true);
- break;
- case (MRT_BGP4MP_MESSAGE_AS4):
- case (MRT_BGP4MP_MESSAGE_AS4_LOCAL):
- case (MRT_BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH):
- case (MRT_BGP4MP_MESSAGE_AS4_ADDPATH):
- mrt_parse_bgp4mp_message(fp, &remains, true);
- break;
- }
- }
-
- ASSERT_DIE(remains < length);
-
- for (u64 i = 0; i < remains; i++)
- fgetc(fp);
-
- return 1;
-}
-
-
-void
-mrt_load(char *file)
-{
- FILE *fp = fopen(file, "r");
-
- if (fp == NULL)
- {
- log(L_WARN "Can not open file %s", fp);
- return;
- }
-
- while (mrt_parse_general_header(fp));
-}
--- /dev/null
+
+CF_HDR
+
+#include "proto/mrt/mrt_load.h"
+
+CF_DEFINES
+
+#define MRTLOAD_CFG ((struct mrtload_config *) this_proto)
+#define MRT_BGP_CC ((struct bgp_channel_config *) this_channel)
+
+CF_DECLS
+
+CF_KEYWORDS(TABLE, FILTER, FILENAME, ADD, MRTLOAD,
+ IPV4, IPV6, MULTICAST, MPLS, VPN4, VPN6, FLOW4, FLOW6)
+
+
+CF_GRAMMAR
+
+proto: mrtload_proto;
+
+mrtload_proto_start: proto_start MRTLOAD
+{
+ this_proto = proto_config_new(&proto_mrtload, $1);
+};
+
+
+mrtload_proto_item:
+ proto_item
+ | TABLE rtable { MRTLOAD_CFG->table_cf = $2; }
+ | FILENAME text { MRTLOAD_CFG->filename = $2; }
+ ;
+
+
+
+mrt_get_table:
+ /* empty */
+ | TABLE rtable ';' {
+ MRTLOAD_CFG->table_cf = $2;
+ log("table_cf %x", $2);
+ if ($2->addr_type == NET_IP4){
+ BGP_CC->igp_table_ip4 = $2;
+ log("BGP_CC->igp_table_ip4");}
+ else if ($2->addr_type == NET_IP6){
+ BGP_CC->igp_table_ip6 = $2;
+ log("BGP_CC->igp_table_ip4");}
+ else
+ cf_error("Mismatched IGP table type");
+ }
+ ;
+
+mrtload_tab:
+ /* empty */
+ | '{' mrt_get_table '}'
+
+mrt_get_bgp_channel: bgp_afi
+{
+ log("%x", $1);
+ const struct bgp_af_desc *desc = bgp_get_af_desc($1);
+
+ if (!desc)
+ cf_error("Unknown AFI/SAFI");
+
+ this_channel = channel_config_get(&channel_mrtload, desc->name, desc->net, this_proto);
+ MRTLOAD_CFG->channel_cf = MRT_BGP_CC;
+
+ /* New channel */
+ if (!MRT_BGP_CC->desc)
+ {
+ MRT_BGP_CC->c.in_filter = FILTER_ACCEPT;
+ MRT_BGP_CC->c.out_filter = FILTER_REJECT;
+ MRT_BGP_CC->c.ra_mode = RA_UNDEF;
+ MRT_BGP_CC->afi = $1;
+ MRT_BGP_CC->desc = desc;
+ MRT_BGP_CC->next_hop_keep = 0xff; /* undefined */
+ MRT_BGP_CC->gr_able = 0xff; /* undefined */
+ MRT_BGP_CC->llgr_able = 0xff; /* undefined */
+ MRT_BGP_CC->llgr_time = ~0U; /* undefined */
+ MRT_BGP_CC->min_llgr_time = ~0U; /* undefined */
+ MRT_BGP_CC->max_llgr_time = ~0U; /* undefined */
+ MRT_BGP_CC->aigp = 0xff; /* undefined */
+ }
+};
+
+
+mrtload_proto_opts:
+ /* empty */
+ | mrtload_proto_opts mrt_get_bgp_channel mrtload_tab ';'
+ | mrtload_proto_opts mrtload_proto_item ';'
+ ;
+
+
+mrtload_proto:
+ mrtload_proto_start proto_name '{' mrtload_proto_opts '}' { mrtload_check_config(this_proto, MRT_BGP_CC); };
+
+
+CF_CODE
+
+CF_END