]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
bgp: Editing bgp route parsing so it can fit parsing routes from mrtload. Renaming...
authorKaterina Kubecova <katerina.kubecova@nic.cz>
Thu, 22 May 2025 09:09:31 +0000 (11:09 +0200)
committerKaterina Kubecova <katerina.kubecova@nic.cz>
Thu, 19 Jun 2025 14:59:18 +0000 (16:59 +0200)
13 files changed:
nest/protocol.h
nest/rt-table.c
proto/bgp/attrs.c
proto/bgp/bgp.c
proto/bgp/bgp.h
proto/bgp/packets.c
proto/mrt/Makefile
proto/mrt/mrt.c
proto/mrt/mrt.h
proto/mrt/mrt_load.c [new file with mode: 0644]
proto/mrt/mrt_load.h [new file with mode: 0644]
proto/mrt/mrt_parse.c [deleted file]
proto/mrt/mrtload.Y [new file with mode: 0644]

index 97a2ba4065ad18365fd565395c20385f6de77da7..68da8fd9ee7aaf7c927129873aaa95ba882f5c74 100644 (file)
@@ -51,6 +51,7 @@ enum protocol_class {
   PROTOCOL_L3VPN,
   PROTOCOL_OSPF,
   PROTOCOL_MRT,
+  PROTOCOL_MRTLOAD,
   PROTOCOL_PERF,
   PROTOCOL_PIPE,
   PROTOCOL_RADV,
@@ -106,7 +107,7 @@ void protos_dump_all(struct dump_request *);
 
 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;
 
 /*
index ee3f11882fd613c43eb4c87be9e9f5217d9699fc..1be8a381d1591220b76551b4d578f6c95416ea11 100644 (file)
@@ -3445,7 +3445,7 @@ rt_free_hostcache(rtable *tab)
       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
index 51193d1707a80fafe4e854d791f68608ac51c3e6..489405134996f1afe1133cf482b6cc0325cc5e71 100644 (file)
@@ -98,7 +98,11 @@ bgp_set_attr(ea_list **attrs, struct linpool *pool, uint code, uint flags, uintp
 
 
 #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; })
@@ -444,10 +448,9 @@ bgp_encode_as_path(struct bgp_write_state *s, eattr *a, byte *buf, uint size)
 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)))
@@ -462,13 +465,13 @@ bgp_decode_as_path(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte
   }
 
   /* 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);
@@ -557,7 +560,7 @@ bgp_export_local_pref(struct bgp_export_state *s, eattr *a)
 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)
@@ -651,7 +654,7 @@ bgp_export_originator_id(struct bgp_export_state *s, eattr *a)
 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)
@@ -675,7 +678,7 @@ bgp_export_cluster_list(struct bgp_export_state *s UNUSED, eattr *a)
 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))
@@ -821,8 +824,7 @@ bgp_decode_as4_aggregator(struct bgp_parse_state *s, uint code UNUSED, uint flag
 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];
 
@@ -1301,25 +1303,25 @@ bgp_encode_attrs(struct bgp_write_state *s, ea_list *attrs, byte *buf, byte *end
 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
@@ -1329,7 +1331,7 @@ bgp_decode_attr(struct bgp_parse_state *s, uint code, uint flags, byte *data, ui
   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);
   }
@@ -1366,9 +1368,8 @@ bgp_decode_attr(struct bgp_parse_state *s, uint code, uint flags, byte *data, ui
  * 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;
@@ -1430,28 +1431,30 @@ bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len, void (*parse_e
 
   /* 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;
 
@@ -1464,7 +1467,7 @@ framing_error:
 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;
@@ -1478,39 +1481,39 @@ void
 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);
   }
 }
@@ -1769,7 +1772,7 @@ bgp_preexport(struct channel *C, rte *e)
 
     /* 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;
   }
 
index c8f90fadb5d773b3bd8b41d32767b89f37c620e1..1f3ae87ca3a32d9687a0fe6ab29fda30a40e2d16 100644 (file)
@@ -2278,7 +2278,7 @@ bgp_init(struct proto_config *CF)
   return P;
 }
 
-static void
+void
 bgp_channel_init(struct channel *C, struct channel_config *CF)
 {
   struct bgp_channel *c = (void *) C;
@@ -2380,7 +2380,7 @@ bgp_channel_start(struct channel *C)
   return 0; /* XXXX: Currently undefined */
 }
 
-static void
+void
 bgp_channel_shutdown(struct channel *C)
 {
   struct bgp_channel *c = (void *) C;
@@ -2390,7 +2390,7 @@ bgp_channel_shutdown(struct channel *C)
   c->packets_to_send = 0;
 }
 
-static void
+void
 bgp_channel_cleanup(struct channel *C)
 {
   struct bgp_channel *c = (void *) C;
index 017677f5c4d3aaf6990015db50e42e38ff74635f..adc1e83594025f846e735b9d7fbf38a087b2c1b7 100644 (file)
@@ -493,17 +493,47 @@ struct bgp_write_state {
 };
 
 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];
 
@@ -606,6 +636,11 @@ void bgp_refresh_end(struct bgp_channel *c);
 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);
 
@@ -664,7 +699,7 @@ int bgp_encode_mp_reach_mrt(struct bgp_write_state *s, eattr *a, byte *buf, uint
 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);
index b93d4a385bc112fa2095d8cd60895629adb59dbc..42af4c99bc17ac67a506c891963e2404d88c1d33 100644 (file)
@@ -64,6 +64,25 @@ bgp_get_channel(struct bgp_proto *p, u32 afi)
   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)
 {
@@ -1057,7 +1076,7 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len)
  */
 
 #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; })
@@ -1078,8 +1097,9 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len)
 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)
   {
@@ -1137,7 +1157,8 @@ bgp_apply_mpls_labels(struct bgp_parse_state *s, rta *a, u32 *labels, uint lnum)
   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);
@@ -1155,8 +1176,8 @@ bgp_apply_mpls_labels(struct bgp_parse_state *s, rta *a, u32 *labels, uint 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 */
@@ -1184,7 +1205,7 @@ static inline int
 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 */
@@ -1221,7 +1242,7 @@ static inline int
 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 */
@@ -1383,7 +1404,6 @@ bgp_encode_next_hop_ip(struct bgp_write_state *s, eattr *a, byte *buf, uint size
 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;
 
@@ -1417,8 +1437,12 @@ bgp_decode_next_hop_ip(struct bgp_parse_state *s, byte *data, uint len, rta *a)
   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
 
@@ -1470,7 +1494,6 @@ bgp_encode_next_hop_vpn(struct bgp_write_state *s, eattr *a, byte *buf, uint siz
 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;
 
@@ -1508,8 +1531,13 @@ bgp_decode_next_hop_vpn(struct bgp_parse_state *s, byte *data, uint len, rta *a)
   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
 
@@ -1550,12 +1578,14 @@ bgp_update_next_hop_none(struct bgp_export_state *s, eattr *a, ea_list **to)
  *     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);
@@ -1569,7 +1599,7 @@ bgp_rte_update(struct bgp_parse_state *s, const net_addr *n, u32 path_id, rta *a
       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;
   }
 
@@ -1585,7 +1615,7 @@ bgp_rte_update(struct bgp_parse_state *s, const net_addr *n, u32 path_id, rta *a
   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
@@ -1644,7 +1674,7 @@ bgp_decode_mpls_labels(struct bgp_parse_state *s, byte **pos, uint *len, uint *p
   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);
@@ -2095,7 +2125,7 @@ bgp_decode_nlri_flow4(struct bgp_parse_state *s, byte *pos, uint len, rta *a)
     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);
     }
 
@@ -2115,8 +2145,13 @@ bgp_decode_nlri_flow4(struct bgp_parse_state *s, byte *pos, uint len, rta *a)
     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);
   }
@@ -2190,7 +2225,7 @@ bgp_decode_nlri_flow6(struct bgp_parse_state *s, byte *pos, uint len, rta *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);
     }
 
@@ -2210,8 +2245,13 @@ bgp_decode_nlri_flow6(struct bgp_parse_state *s, byte *pos, uint len, rta *a)
     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);
   }
@@ -2723,7 +2763,7 @@ bgp_create_end_mark(struct bgp_channel *c, byte *buf)
 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");
@@ -2744,18 +2784,10 @@ bgp_rx_end_mark(struct bgp_parse_state *s, u32 afi)
 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
@@ -2770,11 +2802,11 @@ bgp_decode_nlri(struct bgp_parse_state *s, u32 afi, byte *nlri, uint len, ea_lis
 
     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 */
@@ -2782,14 +2814,14 @@ bgp_decode_nlri(struct bgp_parse_state *s, u32 afi, byte *nlri, uint len, ea_lis
       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
@@ -2800,44 +2832,64 @@ bgp_parse_update(struct bgp_parse_state *s, byte *pkt, uint len, ea_list **ea, v
    *   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;
 
@@ -2859,7 +2911,35 @@ bgp_rx_update(struct bgp_conn *conn, byte *pkt, uint len)
 
   /* 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,
   };
@@ -2875,33 +2955,7 @@ bgp_rx_update(struct bgp_conn *conn, byte *pkt, uint len)
   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);
@@ -3504,11 +3558,9 @@ bgp_rx_packet(struct bgp_conn *conn, byte *pkt, uint len)
   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);
 
index a78f11a5a28587850451ac26ea28ff5615d24d29..93958defa7ccaa280a094626d68b077931261825 100644 (file)
@@ -1,6 +1,7 @@
-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)
index 3369c9de9dd3076dfebd80d05041824889c3d649..1336837a80f4621fc7512db3f38b33b2706af7f9 100644 (file)
@@ -710,10 +710,6 @@ mrt_dump_cont(struct cli *c)
   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
@@ -800,7 +796,6 @@ mrt_bgp_header(buffer *b, struct mrt_bgp_data *d)
 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,
index 9371ce16c0d730e444ef4716e6e26d07cd16a760..4ff94c120dbf8768d5b8147a743f322bfa93588a 100644 (file)
@@ -16,7 +16,6 @@
 #include "nest/route.h"
 #include "lib/event.h"
 #include "lib/hash.h"
-#include "proto/bgp/bgp.h"
 
 
 struct mrt_config {
@@ -156,6 +155,4 @@ static inline void mrt_dump_bgp_message(struct mrt_bgp_data *d UNUSED) { }
 static inline void mrt_dump_bgp_state_change(struct mrt_bgp_data *d UNUSED) { }
 #endif
 
-void mrt_load(char *file);
-
 #endif /* _BIRD_MRT_H_ */
diff --git a/proto/mrt/mrt_load.c b/proto/mrt/mrt_load.c
new file mode 100644 (file)
index 0000000..9ef35bd
--- /dev/null
@@ -0,0 +1,400 @@
+
+#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);
+}
diff --git a/proto/mrt/mrt_load.h b/proto/mrt/mrt_load.h
new file mode 100644 (file)
index 0000000..6609d1c
--- /dev/null
@@ -0,0 +1,36 @@
+#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_ */
diff --git a/proto/mrt/mrt_parse.c b/proto/mrt/mrt_parse.c
deleted file mode 100644 (file)
index e7f2b45..0000000
+++ /dev/null
@@ -1,387 +0,0 @@
-
-#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));
-}
diff --git a/proto/mrt/mrtload.Y b/proto/mrt/mrtload.Y
new file mode 100644 (file)
index 0000000..51eba57
--- /dev/null
@@ -0,0 +1,98 @@
+
+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