Merge branch '271-aap2-link-duplicates' into 'master'

bundle_processor: Only send changes in FIB to agent

Closes #271

See merge request d3tn/ud3tn!243
This commit is contained in:
Felix Walter 2026-03-23 08:46:18 +01:00
commit 3349040b3a
4 changed files with 142 additions and 8 deletions

View file

@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Support for [RFC 9758](https://www.rfc-editor.org/rfc/rfc9758.html): implement the `ipn` 3-element format and LocalNode (`ipn:!.x`) EIDs
- Custom source EIDs (including `dtn:none`) can be specified via AAP 2.0 and the corresponding tools (e.g. `aap2-send --source <eid>`), as long as the client provides the administrative (BDM) secret and requests BDM authorization
- Add a compile-time flag `CLA_MTCP_ION_STCP_COMPATIBILITY` to make the MTCP CLA compatible with ION's STCP, which uses a different encoding for the length field. Note that this breaks compatibility with other implementations of the current MTCP draft specification.
- Add a small Python tool (`aap2-fib-logger`) to show FIB changes propagated via AAP 2.0 (also as an example how to handle this)
### Removed
@ -33,6 +34,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- AAP 2.0 agents can now registered without an agent ID in case they do not wish to send/receive bundles (e.g. if they only do FIB control).
- The full FIB is now only sent once to AAP 2.0 FIB subscribers, when they connect. Then, only changes are propagated.
## [v0.14.5] - 2025-09-26

View file

@ -81,7 +81,7 @@ static inline void handle_signal(
static void inform_link_status_change(
struct bp_context *const ctx,
const char *cla_addr,
enum fib_link_status);
enum fib_link_status status);
static bool send_fib_to_agent(
void *context, const char *node_id,
const struct fib_entry *entry,
@ -370,7 +370,7 @@ static inline void handle_signal(
&agent_feedback
);
if (aaps->agent.auth_fib)
if (aaps->agent.auth_fib && aaps->agent.is_subscriber)
fib_foreach(ctx->fib, send_fib_to_agent, ctx, NULL);
free(aaps);
break;
@ -458,9 +458,24 @@ static void inform_link_status_change(
ctx,
cla_addr
);
if (status == FIB_LINK_STATUS_DOWN)
if (status == FIB_LINK_STATUS_DOWN) {
struct fib_link *const link = fib_lookup_cla_addr(ctx->fib, cla_addr);
const struct fib_entry entry = { .cla_addr = cla_addr };
// After Link deletion (by request), there is no node mapping anymore, but we need
// to report the CLA link being down anyway.
if (link && !link->reflist)
agent_send_fib_info(
ctx->agent_manager,
&entry,
NULL,
status,
ctx
);
// This MAY drop the Link, but only if the refcnt is zero.
fib_remove_link(ctx->fib, cla_addr);
}
}
void bundle_processor_execute_bdm_dispatch(
@ -646,7 +661,8 @@ void bundle_processor_handle_fib_update_request(
)
);
// Treat as successful establishment to trigger agents.
// Always treat as successful establishment to trigger agents, as this will
// also notify agents other than the one that triggered the change.
if (lur == CLA_LINK_UPDATE_UNCHANGED ||
lur == CLA_LINK_UPDATE_PERFORMED)
inform_link_status_change(
@ -675,11 +691,24 @@ void bundle_processor_handle_fib_update_request(
);
// This will call fib_remove_link via
// BP_SIGNAL_LINK_DOWN.
cla_config->vtable->cla_end_scheduled_contact(
cla_config,
fib_request->node_id,
fib_request->cla_addr
const enum cla_link_update_result lur = (
cla_config->vtable->cla_end_scheduled_contact(
cla_config,
fib_request->node_id,
fib_request->cla_addr
)
);
// Note that we notify the agents even if there are no changes, as we do it
// with FIB_REQUEST_CREATE_LINK. This will also notify agents other than
// the one that triggered the change.
if (lur == CLA_LINK_UPDATE_UNCHANGED ||
lur == CLA_LINK_UPDATE_PERFORMED)
inform_link_status_change(
ctx,
fib_request->cla_addr,
FIB_LINK_STATUS_DOWN
);
}
bool drop_assoc = true;

View file

@ -31,6 +31,7 @@ aap2-bdm-static = "ud3tn_utils.aap2.bin.aap2_bdm_static:main"
aap2-bdm-ud3tn-routing = "ud3tn_utils.aap2.bin.aap2_bdm_ud3tn_routing:main"
aap2-config = "ud3tn_utils.aap2.bin.aap2_config:main"
aap2-configure-link = "ud3tn_utils.aap2.bin.aap2_configure_link:main"
aap2-fib-logger = "ud3tn_utils.aap2.bin.aap2_fib_logger:main"
aap2-ping = "ud3tn_utils.aap2.bin.aap2_ping:main"
aap2-receive = "ud3tn_utils.aap2.bin.aap2_receive:main"
aap2-send = "ud3tn_utils.aap2.bin.aap2_send:main"

View file

@ -0,0 +1,102 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: BSD-3-Clause OR Apache-2.0
# encoding: utf-8
"""Simple debug tool to log FIB updates issued by µD3TN."""
import argparse
import logging
import sys
from ud3tn_utils.aap2 import (
AAP2UnixClient,
AAP2TCPClient,
AAP2ServerDisconnected,
AuthType,
LinkStatus,
ResponseStatus,
)
from ud3tn_utils.aap2.bin.helpers import (
add_common_parser_arguments,
add_keepalive_parser_argument,
get_secret_from_args,
initialize_logger,
)
logger = logging.getLogger(__name__)
def run_fib_logger(aap2_client):
logger.info("Waiting for FIB events...")
while True:
try:
msg = aap2_client.receive_msg()
except AAP2ServerDisconnected:
logger.warning("µD3TN has closed the connection.")
sys.exit(1)
except KeyboardInterrupt:
logger.info("Terminated by keyboard interrupt.")
sys.exit(130) # exit status for SIGINT
if msg.WhichOneof("msg") == "link":
logger.warning(
"%s: %s%s",
{
LinkStatus.LINK_STATUS_UNSPECIFIED: "CONNECTING",
LinkStatus.LINK_STATUS_UP: "UP",
LinkStatus.LINK_STATUS_DOWN: "DOWN",
}.get(msg.link.status, f"(status={msg.link.status})"),
(
f"{msg.link.peer_node_id} via "
if msg.link.peer_node_id else ""
),
msg.link.peer_cla_addr,
)
aap2_client.send_response_status(
ResponseStatus.RESPONSE_STATUS_SUCCESS,
)
else:
if msg.WhichOneof("msg") != "keepalive":
logger.warning(
"Received unhandled '%s' message discarding.",
msg.WhichOneof("msg"),
)
# ACK the message in any case -- same response KA, unhandled
aap2_client.send_response_status(
ResponseStatus.RESPONSE_STATUS_ACK,
)
def main():
parser = argparse.ArgumentParser(
description="FIB update logger for µD3TN",
)
add_common_parser_arguments(parser)
add_keepalive_parser_argument(parser)
args = parser.parse_args()
global logger
logger = initialize_logger(args.verbosity)
if args.tcp:
aap2_client = AAP2TCPClient(address=args.tcp)
else:
aap2_client = AAP2UnixClient(address=args.socket)
with aap2_client:
secret = aap2_client.configure(
args.agentid,
subscribe=True,
secret=get_secret_from_args(args),
auth_type=AuthType.AUTH_TYPE_FIB_CONTROL,
keepalive_seconds=args.keepalive_seconds,
)
logger.info("AAP 2.0 agent configured as FIB subscriber!")
logger.debug("Assigned agent secret: '%s'", secret)
run_fib_logger(aap2_client)
if __name__ == "__main__":
main()