]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
RPKI: protocol version 2, loading ASPA
authorKaterina Kubecova <katerina.kubecova@nic.cz>
Fri, 8 Nov 2024 14:26:37 +0000 (15:26 +0100)
committerOndrej Zajicek <santiago@crfreenet.org>
Tue, 26 Nov 2024 03:14:36 +0000 (04:14 +0100)
Implemented draft-ietf-sidrops-8210bis-16, interoperable with StayRTR
development branches.

proto/rpki/packets.c
proto/rpki/packets.h
proto/rpki/rpki.c
proto/rpki/rpki.h

index d246dd500aac3466fe13a2e630d2843f4b7a21b9..de9e861953d07c65128d8c5c9d1d403249c98794 100644 (file)
@@ -62,6 +62,7 @@ enum pdu_type {
   CACHE_RESET                  = 8,
   ROUTER_KEY                   = 9,
   ERROR                        = 10,
+  ASPA                         = 11,
   PDU_TYPE_MAX
 };
 
@@ -76,7 +77,8 @@ static const char *str_pdu_type_[] = {
   [END_OF_DATA]                = "End of Data",
   [CACHE_RESET]                = "Cache Reset",
   [ROUTER_KEY]                         = "Router Key",
-  [ERROR]                      = "Error"
+  [ERROR]                      = "Error",
+  [ASPA]                       = "ASPA",
 };
 
 static const char *str_pdu_type(uint type) {
@@ -193,6 +195,35 @@ struct pdu_error {
                                 * Error Diagnostic Message */
 } PACKED;
 
+/*
+ *0          8          16         24        31
+ *  .-------------------------------------------.
+ *  | Protocol |   PDU    |          |          |
+ *  | Version  |   Type   |   Flags  |   zero   |
+ *  |    2     |    11    |          |          |
+ *  +-------------------------------------------+
+ *  |                                           |
+ *  |                 Length                    |
+ *  |                                           |
+ *  +-------------------------------------------+
+ *  |                                           |
+ *  |    Customer Autonomous System Number      |
+ *  |                                           |
+ *  +-------------------------------------------+
+ *  |                                           |
+ *  ~    Provider Autonomous System Numbers     ~
+ *  |                                           |
+ *  ~-------------------------------------------~ */
+struct pdu_aspa {
+  u8 ver;
+  u8 type;
+  u8 flags;
+  u8 zero;
+  u32 len;
+  u32 customer_as_num;
+  u32 provider_as_nums[0];
+} PACKED;
+
 struct pdu_reset_query {
   u8 ver;
   u8 type;
@@ -230,9 +261,13 @@ static const size_t min_pdu_size[] = {
   [END_OF_DATA]                = sizeof(struct pdu_end_of_data_v0),
   [CACHE_RESET]                = sizeof(struct pdu_cache_response),
   [ROUTER_KEY]                         = sizeof(struct pdu_header), /* FIXME */
+  [ASPA]                       = sizeof(struct pdu_aspa),
   [ERROR]                      = 16,
 };
 
+static inline int rpki_pdu_aspa_provider_asn_count(const struct pdu_aspa *pdu)
+{ return (pdu->len - sizeof(struct pdu_aspa)) / (sizeof(u32)); }
+
 static int rpki_send_error_pdu(struct rpki_cache *cache, const enum pdu_error_type error_code, const u32 err_pdu_len, const struct pdu_header *erroneous_pdu, const char *fmt, ...);
 
 static void
@@ -293,7 +328,7 @@ rpki_pdu_to_host_byte_order(struct pdu_header *pdu)
     struct pdu_end_of_data_v0 *eod0 = (void *) pdu;
     eod0->serial_num = ntohl(eod0->serial_num); /* Same either for version 1 */
 
-    if (pdu->ver == RPKI_VERSION_1)
+    if (pdu->ver > RPKI_VERSION_0)
     {
       struct pdu_end_of_data_v1 *eod1 = (void *) pdu;
       eod1->expire_interval = ntohl(eod1->expire_interval);
@@ -329,6 +364,21 @@ rpki_pdu_to_host_byte_order(struct pdu_header *pdu)
     break;
   }
 
+  case ASPA:
+  {
+    struct pdu_aspa *aspa = (void *) pdu;
+    int provider_asn_count = rpki_pdu_aspa_provider_asn_count(aspa);
+
+    /* Convert customer ASN */
+    aspa->customer_as_num = ntohl(aspa->customer_as_num);
+
+    /* Convert provider ASNs */
+    for (int i = 0; i < provider_asn_count ; i++)
+      aspa->provider_as_nums[i] = ntohl(aspa->provider_as_nums[i]);
+
+    break;
+  }
+
   case ROUTER_KEY:
     /* Router Key PDU is not supported yet */
 
@@ -354,6 +404,9 @@ rpki_pdu_to_host_byte_order(struct pdu_header *pdu)
 static struct pdu_header *
 rpki_pdu_back_to_network_byte_order(struct pdu_header *out, const struct pdu_header *in)
 {
+  /* Only valid for fixed-length PDUs */
+  ASSERT_DIE(in->type != ERROR && in->type != ASPA);
+
   memcpy(out, in, in->len);
   rpki_pdu_to_host_byte_order(out);
   return out;
@@ -387,7 +440,7 @@ rpki_log_packet(struct rpki_cache *cache, const struct pdu_header *pdu, const en
   case END_OF_DATA:
   {
     const struct pdu_end_of_data_v1 *eod = (void *) pdu;
-    if (eod->ver == RPKI_VERSION_1)
+    if (eod->ver > RPKI_VERSION_0)
       SAVE(bsnprintf(detail, sizeof(detail), "(session id: %u, serial number: %u, refresh: %us, retry: %us, expire: %us)", eod->session_id, eod->serial_num, eod->refresh_interval, eod->retry_interval, eod->expire_interval));
     else
       SAVE(bsnprintf(detail, sizeof(detail), "(session id: %u, serial number: %u)", eod->session_id, eod->serial_num));
@@ -455,6 +508,25 @@ rpki_log_packet(struct rpki_cache *cache, const struct pdu_header *pdu, const en
     break;
   }
 
+  case ASPA:
+  {
+    const struct pdu_aspa *aspa = (void *) pdu;
+    int provider_asn_count = rpki_pdu_aspa_provider_asn_count(aspa);
+
+    if (provider_asn_count <= 0)
+      SAVE(bsnprintf(detail + strlen(detail), sizeof(detail) - strlen(detail),
+           "%u transit", aspa->customer_as_num));
+    else
+    {
+      SAVE(bsnprintf(detail + strlen(detail), sizeof(detail) - strlen(detail),
+           "%u (providers", aspa->customer_as_num));
+      for (int i = 0; i < provider_asn_count; i++)
+       SAVE(bsnprintf(detail + strlen(detail), sizeof(detail) - strlen(detail),
+             " %u%c", aspa->provider_as_nums[i], (i == provider_asn_count-1) ? ')' : ','));
+    }
+    break;
+  }
+
   default:
     *detail = '\0';
   }
@@ -571,7 +643,9 @@ rpki_check_receive_packet(struct rpki_cache *cache, const struct pdu_header *pdu
     }
   }
 
-  if ((pdu->type >= PDU_TYPE_MAX) || (pdu->ver == RPKI_VERSION_0 && pdu->type == ROUTER_KEY))
+  if ((pdu->type >= PDU_TYPE_MAX) ||
+      (pdu->ver < RPKI_VERSION_1 && pdu->type == ROUTER_KEY) ||
+      (pdu->ver < RPKI_VERSION_2 && pdu->type == ASPA))
   {
     rpki_send_error_pdu(cache, UNSUPPORTED_PDU_TYPE, pdu_len, pdu, "Unsupported PDU type %u received", pdu->type);
     return RPKI_ERROR;
@@ -797,6 +871,29 @@ rpki_handle_prefix_pdu(struct rpki_cache *cache, const struct pdu_header *pdu)
   return RPKI_SUCCESS;
 }
 
+static int
+rpki_handle_aspa_pdu(struct rpki_cache *cache, const struct pdu_header *pdu)
+{
+  struct pdu_aspa *aspa = (void *) pdu;
+  struct channel *channel = cache->p->aspa_channel;
+  uint providers_length = aspa->len - sizeof(struct pdu_aspa);
+
+  if (!channel)
+  {
+    CACHE_TRACE(D_ROUTES, cache, "Skip AS%u, missing aspa channel", aspa->customer_as_num);
+    return RPKI_ERROR;
+  }
+
+  cache->last_rx_prefix = current_time();
+
+  if (aspa->flags & RPKI_ADD_FLAG)
+    rpki_table_add_aspa(cache, channel, aspa->customer_as_num, aspa->provider_as_nums, providers_length);
+  else
+    rpki_table_remove_aspa(cache, channel, aspa->customer_as_num);
+
+  return RPKI_SUCCESS;
+}
+
 static uint
 rpki_check_interval(struct rpki_cache *cache, const char *(check_fn)(uint), uint interval)
 {
@@ -822,7 +919,7 @@ rpki_handle_end_of_data_pdu(struct rpki_cache *cache, const struct pdu_end_of_da
     return;
   }
 
-  if (pdu->ver == RPKI_VERSION_1)
+  if (pdu->ver > RPKI_VERSION_0)
   {
     if (!cf->keep_refresh_interval && rpki_check_interval(cache, rpki_check_refresh_interval, pdu->refresh_interval))
       cache->refresh_interval = pdu->refresh_interval;
@@ -849,6 +946,8 @@ rpki_handle_end_of_data_pdu(struct rpki_cache *cache, const struct pdu_end_of_da
       rt_refresh_end(cache->p->roa4_channel->table, cache->p->roa4_channel);
     if (cache->p->roa6_channel)
       rt_refresh_end(cache->p->roa6_channel->table, cache->p->roa6_channel);
+    if (cache->p->aspa_channel)
+      rt_refresh_end(cache->p->aspa_channel->table, cache->p->aspa_channel);
   }
 
   cache->last_update = current_time();
@@ -913,6 +1012,10 @@ rpki_rx_packet(struct rpki_cache *cache, struct pdu_header *pdu)
     /* TODO: Implement Router Key PDU handling */
     break;
 
+  case ASPA:
+    rpki_handle_aspa_pdu(cache, (void *) pdu);
+    break;
+
   default:
     CACHE_TRACE(D_PACKETS, cache, "Received unsupported type (%u)", pdu->type);
   };
index d6f8a249baa99a17240f4e2820d878efed2e6932..f7897d9af29e30a62ca34d52117f6091a1c88481 100644 (file)
  *        +4 bytes (Length of inserted text)
  *      +800 bytes (UTF-8 text 400*2 bytes)
  *     ------------
- *     = 848 bytes (Maximal expected PDU size) */
-#define RPKI_PDU_MAX_LEN       848
+ *     = 848 bytes (Maximal expected PDU size)
+ *
+ * Received ASPA PDU can have any size, so let's start with 4k */
+#define RPKI_PDU_MAX_LEN       4096
 
 /* RX buffer size has a great impact to scheduler granularity */
 #define RPKI_RX_BUFFER_SIZE    4096
index cbd94492d113d80abc79970f9a712da7282bca77..e9d2a60aa6fc6d067719a189b4282925b7ed61c7 100644 (file)
@@ -140,6 +140,37 @@ rpki_table_remove_roa(struct rpki_cache *cache, struct channel *channel, const n
   rte_update2(channel, &pfxr->n, NULL, p->p.main_source);
 }
 
+void
+rpki_table_add_aspa(struct rpki_cache *cache, struct channel *channel,
+    u32 customer, void *providers, uint providers_length)
+{
+  struct rpki_proto *p = cache->p;
+
+  net_addr_union n = { .aspa = NET_ADDR_ASPA(customer) };
+  rta a0 = {
+    .pref = channel->preference,
+    .source = RTS_RPKI,
+    .scope = SCOPE_UNIVERSE,
+    .dest = RTD_NONE,
+  };
+
+  ea_set_attr_data(&a0.eattrs, tmp_linpool, EA_ASPA_PROVIDERS, 0,
+                  EAF_TYPE_INT_SET, providers, providers_length);
+
+  rta *a = rta_lookup(&a0);
+  rte *e = rte_get_temp(a, p->p.main_source);
+
+  rte_update2(channel, &n.n, e, e->src);
+}
+
+void
+rpki_table_remove_aspa(struct rpki_cache *cache, struct channel *channel, u32 customer)
+{
+  struct rpki_proto *p = cache->p;
+  net_addr_union n = { .aspa = NET_ADDR_ASPA(customer) };
+  rte_update2(channel, &n.n, NULL, p->p.main_source);
+}
+
 
 /*
  *     RPKI Protocol Logic
@@ -773,7 +804,8 @@ rpki_reconfigure(struct proto *P, struct proto_config *CF)
   struct rpki_cache *cache = p->cache;
 
   if (!proto_configure_channel(&p->p, &p->roa4_channel, proto_cf_find_channel(CF, NET_ROA4)) ||
-      !proto_configure_channel(&p->p, &p->roa6_channel, proto_cf_find_channel(CF, NET_ROA6)))
+      !proto_configure_channel(&p->p, &p->roa6_channel, proto_cf_find_channel(CF, NET_ROA6)) ||
+      !proto_configure_channel(&p->p, &p->aspa_channel, proto_cf_find_channel(CF, NET_ASPA)))
     return NEED_RESTART;
 
   if (rpki_reconfigure_cache(p, cache, new, old) != SUCCESSFUL_RECONF)
@@ -795,6 +827,7 @@ rpki_init(struct proto_config *CF)
 
   proto_configure_channel(&p->p, &p->roa4_channel, proto_cf_find_channel(CF, NET_ROA4));
   proto_configure_channel(&p->p, &p->roa6_channel, proto_cf_find_channel(CF, NET_ROA6));
+  proto_configure_channel(&p->p, &p->aspa_channel, proto_cf_find_channel(CF, NET_ASPA));
 
   return P;
 }
@@ -908,6 +941,11 @@ rpki_show_proto_info(struct proto *P)
       channel_show_info(p->roa6_channel);
     else
       cli_msg(-1006, "  No roa6 channel");
+
+    if (p->aspa_channel)
+      channel_show_info(p->aspa_channel);
+    else
+      cli_msg(-1006, "  No aspa channel");
   }
 }
 
@@ -979,7 +1017,7 @@ struct protocol proto_rpki = {
   .init =              rpki_init,
   .start =             rpki_start,
   .postconfig =        rpki_postconfig,
-  .channel_mask =      (NB_ROA4 | NB_ROA6),
+  .channel_mask =      (NB_ROA4 | NB_ROA6 | NB_ASPA),
   .show_proto_info =   rpki_show_proto_info,
   .shutdown =          rpki_shutdown,
   .copy_config =       rpki_copy_config,
index e67eb0e3b0646bfa95140ffb9195f91a4db1a5c8..307ec315a178d2e60d311c2ccbc222e2f4342fd6 100644 (file)
@@ -29,7 +29,8 @@
 
 #define RPKI_VERSION_0         0
 #define RPKI_VERSION_1         1
-#define RPKI_MAX_VERSION       RPKI_VERSION_1
+#define RPKI_VERSION_2         2
+#define RPKI_MAX_VERSION       RPKI_VERSION_2
 
 
 /*
@@ -83,6 +84,9 @@ const char *rpki_cache_state_to_str(enum rpki_cache_state state);
 void rpki_table_add_roa(struct rpki_cache *cache, struct channel *channel, const net_addr_union *pfxr);
 void rpki_table_remove_roa(struct rpki_cache *cache, struct channel *channel, const net_addr_union *pfxr);
 
+void rpki_table_add_aspa(struct rpki_cache *cache, struct channel *channel, u32 customer, void *providers, uint providers_length);
+void rpki_table_remove_aspa(struct rpki_cache *cache, struct channel *channel, u32 customer);
+
 
 /*
  *     RPKI Protocol Logic
@@ -110,6 +114,7 @@ struct rpki_proto {
 
   struct channel *roa4_channel;
   struct channel *roa6_channel;
+  struct channel *aspa_channel;
   u8 refresh_channels;                 /* For non-incremental updates using rt_refresh_begin(), rt_refresh_end() */
 };