From: Alan T. DeKok Date: Sat, 11 Mar 2023 14:25:44 +0000 (-0500) Subject: rearrange in preparation for punting packets to unlang X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ef550d1186382e4ba879fc718cd2b5434468054b;p=thirdparty%2Ffreeradius-server.git rearrange in preparation for punting packets to unlang --- diff --git a/src/listen/bfd/proto_bfd.c b/src/listen/bfd/proto_bfd.c index a096e3715d6..4e70cffeb25 100644 --- a/src/listen/bfd/proto_bfd.c +++ b/src/listen/bfd/proto_bfd.c @@ -43,15 +43,15 @@ static CONF_PARSER const proto_bfd_config[] = { }; static const CONF_PARSER peer_config[] = { - { FR_CONF_OFFSET("min_transmit_interval", FR_TYPE_TIME_DELTA, proto_bfd_peer_t, desired_min_tx_interval ) }, - { FR_CONF_OFFSET("min_receive_interval", FR_TYPE_TIME_DELTA, proto_bfd_peer_t, required_min_rx_interval ) }, - { FR_CONF_OFFSET("max_timeouts", FR_TYPE_UINT32, proto_bfd_peer_t, detect_multi ) }, - { FR_CONF_OFFSET("demand", FR_TYPE_BOOL, proto_bfd_peer_t, demand_mode ) }, + { FR_CONF_OFFSET("min_transmit_interval", FR_TYPE_TIME_DELTA, bfd_session_t, desired_min_tx_interval ) }, + { FR_CONF_OFFSET("min_receive_interval", FR_TYPE_TIME_DELTA, bfd_session_t, required_min_rx_interval ) }, + { FR_CONF_OFFSET("max_timeouts", FR_TYPE_UINT32, bfd_session_t, detect_multi ) }, + { FR_CONF_OFFSET("demand", FR_TYPE_BOOL, bfd_session_t, demand_mode ) }, - { FR_CONF_OFFSET("auth_type", FR_TYPE_VOID, proto_bfd_peer_t, auth_type ), + { FR_CONF_OFFSET("auth_type", FR_TYPE_VOID, bfd_session_t, auth_type ), .func = auth_type_parse }, - { FR_CONF_OFFSET("port", FR_TYPE_UINT16, proto_bfd_peer_t, port ) }, + { FR_CONF_OFFSET("port", FR_TYPE_UINT16, bfd_session_t, port ) }, CONF_PARSER_TERMINATOR }; @@ -448,11 +448,11 @@ static int mod_bootstrap(module_inst_ctx_t const *mctx) while ((cs = cf_section_find_next(server, cs, "peer", CF_IDENT_ANY))) { fr_client_t *c; - proto_bfd_peer_t *peer; + bfd_session_t *peer; if (cf_section_rules_push(cs, peer_config) < 0) return -1; - c = client_afrom_cs(cs, cs, server, sizeof(proto_bfd_peer_t)); + c = client_afrom_cs(cs, cs, server, sizeof(bfd_session_t)); if (!c) { error: cf_log_err(cs, "Failed to parse peer %s", cf_section_name2(cs)); @@ -465,7 +465,7 @@ static int mod_bootstrap(module_inst_ctx_t const *mctx) goto error; } - peer = (proto_bfd_peer_t *) c; + peer = (bfd_session_t *) c; FR_TIME_DELTA_BOUND_CHECK("peer.min_transmit_interval", peer->desired_min_tx_interval, >=, fr_time_delta_from_usec(32)); FR_TIME_DELTA_BOUND_CHECK("peer.min_transmit_interval", peer->desired_min_tx_interval, <=, fr_time_delta_from_sec(2)); diff --git a/src/listen/bfd/proto_bfd.h b/src/listen/bfd/proto_bfd.h index ec3663f4a22..749ee386adb 100644 --- a/src/listen/bfd/proto_bfd.h +++ b/src/listen/bfd/proto_bfd.h @@ -25,6 +25,7 @@ */ #include #include +#include "session.h" /** An instance of a proto_radius listen section * @@ -37,85 +38,3 @@ typedef struct { fr_rb_tree_t *peers; } proto_bfd_t; - -typedef struct { - fr_client_t client; //!< might as well re-use this, others need it - - uint16_t port; //!< peer port where packets are sent to - - /* - * Peers are defined globally to a virtual server. Each - * peer can only have one session associated with it. - */ - void *inst; //!< proto_bfd_udp instance using this session - fr_listen_t *listen; //!< associated listener - - int sockfd; //!< cached for laziness - fr_event_list_t *el; //!< event list - fr_network_t *nr; //!< network side of things - - struct sockaddr_storage remote_sockaddr; //!< cached for laziness - socklen_t remote_salen; - - struct sockaddr_storage local_sockaddr; //!< cached for laziness - socklen_t local_salen; - - /* - * Internal state management - */ - fr_event_timer_t const *ev_timeout; //!< when we time out for not receiving a packet - fr_event_timer_t const *ev_packet; //!< for when we next send a packet - fr_time_t last_recv; //!< last received packet - fr_time_t next_recv; //!< when we next expect to receive a packet - fr_time_t last_sent; //!< the last time we sent a packet - - bfd_session_state_t session_state; //!< our view of the session state - bfd_session_state_t remote_session_state; //!< their view of the session state - - /* - * BFD state machine, and fields we use to manage it. - * - * The public names in the configuration files are what makes sense. - * - * The names here are the names from the protocol, so that we can be sure the state machine is - * implemented correctly. - */ - uint32_t local_disc; //!< our session ID, which is unique to this session - uint32_t remote_disc; //!< their session ID - - bfd_diag_t local_diag; //!< diagnostics for errors - - uint32_t detect_multi; - - fr_time_delta_t desired_min_tx_interval; //!< intervals between transmits - fr_time_delta_t required_min_rx_interval; //!< intervals between receives - - fr_time_delta_t remote_min_rx_interval; //!< their min_rx_interval - - fr_time_delta_t my_min_echo_rx_interval; //!< what we send for echo_rx_interval - - fr_time_delta_t next_min_tx_interval; //!< how to update this when we're polling - - - bool demand_mode; //!< demand is "once session is up, stop sending packets" - bool remote_demand_mode; //!< their demand mode - - bool doing_poll; - - /* - * Authentication configuration and states. - */ - bool auth_seq_known; //!< do we know the authentication sequence number? - - bfd_auth_type_t auth_type; //!< what kind of authentication is used - - uint32_t recv_auth_seq; //!< their auth_seq number - uint32_t xmit_auth_seq; //!< our auth_seq number - - size_t secret_len; //!< doesn't change while we're running - - fr_time_delta_t detection_time; //!< used to set ev_timeout - int detection_timeouts; //!< too many timeouts means !auth_seq_known - - bool passive; //!< active or passive role from RFC 5880 - unused -} proto_bfd_peer_t; diff --git a/src/listen/bfd/proto_bfd_udp.c b/src/listen/bfd/proto_bfd_udp.c index 93a7d30ada2..ee76f90c135 100644 --- a/src/listen/bfd/proto_bfd_udp.c +++ b/src/listen/bfd/proto_bfd_udp.c @@ -59,6 +59,8 @@ typedef struct { uint8_t ttl; //!< default ttl + bool only_state_changes; //!< on read(), only send packets which signal a state change + bool recv_buff_is_set; //!< Whether we were provided with a recv_buff bool send_buff_is_set; //!< Whether we were provided with a send_buff bool dynamic_clients; //!< whether we have dynamic clients @@ -91,6 +93,8 @@ static const CONF_PARSER udp_listen_config[] = { { FR_CONF_OFFSET("ttl", FR_TYPE_UINT8, proto_bfd_udp_t, ttl), .dflt = "255" }, + { FR_CONF_OFFSET("only_state_changes", FR_TYPE_BOOL, proto_bfd_udp_t, only_state_changes), .dflt = "yes" }, + { FR_CONF_OFFSET_IS_SET("recv_buff", FR_TYPE_UINT32, proto_bfd_udp_t, recv_buff) }, { FR_CONF_OFFSET_IS_SET("send_buff", FR_TYPE_UINT32, proto_bfd_udp_t, send_buff) }, @@ -115,6 +119,7 @@ static ssize_t mod_read(fr_listen_t *li, void **packet_ctx, fr_time_t *recv_time bfd_packet_t *packet; char const *err = NULL; + bfd_state_change_t state_change; *leftover = 0; /* always for UDP */ @@ -176,7 +181,10 @@ static ssize_t mod_read(fr_listen_t *li, void **packet_ctx, fr_time_t *recv_time * Run the BFD state machine. Depending on that result, * we either send the packet through to unlang, or not. */ - if (!bfd_session_process((proto_bfd_peer_t *) client, packet)) return 0; + state_change = bfd_session_process((bfd_session_t *) client, packet); + if ((state_change == BFD_STATE_CHANGE_INVALID) || (state_change == BFD_STATE_CHANGE_ADMIN_DOWN)) return 0; + + if ((state_change == BFD_STATE_CHANGE_NONE) && inst->only_state_changes) return 0; return packet_len; } @@ -348,7 +356,7 @@ static int mod_bootstrap(module_inst_ctx_t const *mctx) CONF_ITEM *ci; CONF_SECTION *server_cs; fr_rb_iter_inorder_t iter; - proto_bfd_peer_t *peer; + bfd_session_t *peer; inst->cs = conf; @@ -477,7 +485,7 @@ static void mod_event_list_set(fr_listen_t *li, fr_event_list_t *el, void *nr) proto_bfd_udp_t const *inst = talloc_get_type_abort_const(li->app_io_instance, proto_bfd_udp_t); proto_bfd_udp_thread_t *thread = talloc_get_type_abort(li->thread_instance, proto_bfd_udp_thread_t); fr_rb_iter_inorder_t iter; - proto_bfd_peer_t *peer; + bfd_session_t *peer; /* * Walk over the list of peers, associating them with this listener. diff --git a/src/listen/bfd/session.c b/src/listen/bfd/session.c index 7c9bee9dac8..e95eec13cc3 100644 --- a/src/listen/bfd/session.c +++ b/src/listen/bfd/session.c @@ -33,20 +33,19 @@ #include #include #include -#include #include "session.h" -static void bfd_sign(proto_bfd_peer_t *session, bfd_packet_t *bfd); -static int bfd_authenticate(proto_bfd_peer_t *session, bfd_packet_t *bfd); -static void bfd_control_packet_init(proto_bfd_peer_t *session, bfd_packet_t *bfd); +static void bfd_sign(bfd_session_t *session, bfd_packet_t *bfd); +static int bfd_authenticate(bfd_session_t *session, bfd_packet_t *bfd); +static void bfd_control_packet_init(bfd_session_t *session, bfd_packet_t *bfd); -static void bfd_set_desired_min_tx_interval(proto_bfd_peer_t *session, fr_time_delta_t value); +static void bfd_set_desired_min_tx_interval(bfd_session_t *session, fr_time_delta_t value); -static void bfd_start_packets(proto_bfd_peer_t *session); -static void bfd_start_control(proto_bfd_peer_t *session); -static int bfd_stop_control(proto_bfd_peer_t *session); -static void bfd_set_timeout(proto_bfd_peer_t *session, fr_time_t when); +static void bfd_start_packets(bfd_session_t *session); +static void bfd_start_control(bfd_session_t *session); +static int bfd_stop_control(bfd_session_t *session); +static void bfd_set_timeout(bfd_session_t *session, fr_time_t when); /* @@ -56,7 +55,7 @@ static void bfd_set_timeout(proto_bfd_peer_t *session, fr_time_t when); * we will need to define some other kind of fake packet to send to the process * module. */ -static void bfd_trigger(proto_bfd_peer_t *session) +static void bfd_trigger(bfd_session_t *session, UNUSED bfd_state_change_t change) { // fr_radius_packet_t packet; // request_t *request = request_local_alloc_external(session, NULL); @@ -75,7 +74,7 @@ static void bfd_trigger(proto_bfd_peer_t *session) /* * Stop polling for packets. */ -static int bfd_stop_poll(proto_bfd_peer_t *session) +static int bfd_stop_poll(bfd_session_t *session) { if (!session->doing_poll) return 0; @@ -114,7 +113,7 @@ static int bfd_stop_poll(proto_bfd_peer_t *session) * Note that this doesn't affect our "last_sent" timer. * That's set only when we intend to send a packet. */ -static void bfd_poll_response(proto_bfd_peer_t *session) +static void bfd_poll_response(bfd_session_t *session) { bfd_packet_t bfd; @@ -139,9 +138,9 @@ static void bfd_poll_response(proto_bfd_peer_t *session) /* * Implement the requirements of RFC 5880 Section 6.8.6. */ -int bfd_session_process(proto_bfd_peer_t *session, bfd_packet_t *bfd) +bfd_state_change_t bfd_session_process(bfd_session_t *session, bfd_packet_t *bfd) { - bool state_change = false; + bfd_state_change_t state_change = BFD_STATE_CHANGE_NONE; /* * @@ -152,7 +151,7 @@ int bfd_session_process(proto_bfd_peer_t *session, bfd_packet_t *bfd) if ((bfd->your_disc != 0) && (bfd->your_disc != session->local_disc)) { DEBUG("BFD %s packet has unexpected Your-Discriminator (got %08x, expected %08x", session->client.shortname, bfd->your_disc, session->local_disc); - return 0; + return BFD_STATE_CHANGE_INVALID; } /* @@ -162,7 +161,7 @@ int bfd_session_process(proto_bfd_peer_t *session, bfd_packet_t *bfd) if (bfd->auth_present && (session->auth_type == BFD_AUTH_RESERVED)) { DEBUG("BFD %s packet asked to authenticate an unauthenticated session.", session->client.shortname); - return 0; + return BFD_STATE_CHANGE_INVALID; } /* @@ -172,7 +171,7 @@ int bfd_session_process(proto_bfd_peer_t *session, bfd_packet_t *bfd) if (!bfd->auth_present && (session->auth_type != BFD_AUTH_RESERVED)) { DEBUG("BFD %s packet failed to authenticate an authenticated session.", session->client.shortname); - return 0; + return BFD_STATE_CHANGE_INVALID; } /* @@ -182,7 +181,7 @@ int bfd_session_process(proto_bfd_peer_t *session, bfd_packet_t *bfd) */ if (bfd->auth_present && !bfd_authenticate(session, bfd)) { DEBUG("BFD %s authentication failed", session->client.shortname); - return 0; + return BFD_STATE_CHANGE_INVALID; } DEBUG("BFD %s processing packet", session->client.shortname); @@ -261,7 +260,7 @@ int bfd_session_process(proto_bfd_peer_t *session, bfd_packet_t *bfd) */ if (session->session_state == BFD_STATE_ADMIN_DOWN) { DEBUG("Discarding BFD packet (admin down)"); - return 0; + return BFD_STATE_CHANGE_ADMIN_DOWN; } /* @@ -280,8 +279,7 @@ int bfd_session_process(proto_bfd_peer_t *session, bfd_packet_t *bfd) fr_bfd_packet_names[session->session_state], fr_bfd_packet_names[bfd->state]); session->session_state = BFD_STATE_DOWN; - bfd_trigger(session); - state_change = true; + state_change = BFD_STATE_CHANGE_PEER_DOWN; } } else { @@ -292,16 +290,14 @@ int bfd_session_process(proto_bfd_peer_t *session, bfd_packet_t *bfd) DEBUG("BFD %s State DOWN -> INIT (neighbor DOWN)", session->client.shortname); session->session_state = BFD_STATE_INIT; - bfd_trigger(session); - state_change = true; + state_change = BFD_STATE_CHANGE_INIT; break; case BFD_STATE_INIT: DEBUG("BFD %s State DOWN -> UP (neighbor INIT)", session->client.shortname); session->session_state = BFD_STATE_UP; - bfd_trigger(session); - state_change = true; + state_change = BFD_STATE_CHANGE_UP; break; default: /* don't change anything */ @@ -316,8 +312,7 @@ int bfd_session_process(proto_bfd_peer_t *session, bfd_packet_t *bfd) DEBUG("BFD %s State INIT -> UP", session->client.shortname); session->session_state = BFD_STATE_UP; - bfd_trigger(session); - state_change = true; + state_change = BFD_STATE_CHANGE_UP; break; default: /* don't change anything */ @@ -337,7 +332,7 @@ int bfd_session_process(proto_bfd_peer_t *session, bfd_packet_t *bfd) default: DEBUG("Internal sanity check failed"); - return 0; + return BFD_STATE_CHANGE_INVALID; } } @@ -433,7 +428,7 @@ int bfd_session_process(proto_bfd_peer_t *session, bfd_packet_t *bfd) /* * Verify and/or calculate passwords */ -static void bfd_calc_simple(proto_bfd_peer_t *session, bfd_packet_t *bfd) +static void bfd_calc_simple(bfd_session_t *session, bfd_packet_t *bfd) { bfd_auth_simple_t *simple = &bfd->auth.password; @@ -443,7 +438,7 @@ static void bfd_calc_simple(proto_bfd_peer_t *session, bfd_packet_t *bfd) simple->auth_len = session->secret_len; } -static void bfd_auth_simple(proto_bfd_peer_t *session, bfd_packet_t *bfd) +static void bfd_auth_simple(bfd_session_t *session, bfd_packet_t *bfd) { bfd_auth_simple_t *simple = &bfd->auth.password; @@ -459,7 +454,7 @@ static void bfd_auth_simple(proto_bfd_peer_t *session, bfd_packet_t *bfd) /* * Verify and/or calculate auth-type digests. */ -static void bfd_calc_md5(proto_bfd_peer_t *session, bfd_packet_t *bfd) +static void bfd_calc_md5(bfd_session_t *session, bfd_packet_t *bfd) { bfd_auth_md5_t *md5 = &bfd->auth.md5; @@ -472,7 +467,7 @@ static void bfd_calc_md5(proto_bfd_peer_t *session, bfd_packet_t *bfd) fr_md5_calc(md5->digest,(const uint8_t *) bfd, bfd->length); } -static void bfd_auth_md5(proto_bfd_peer_t *session, bfd_packet_t *bfd) +static void bfd_auth_md5(bfd_session_t *session, bfd_packet_t *bfd) { bfd_auth_md5_t *md5 = &bfd->auth.md5; @@ -486,7 +481,7 @@ static void bfd_auth_md5(proto_bfd_peer_t *session, bfd_packet_t *bfd) bfd_calc_md5(session, bfd); } -static void bfd_calc_sha1(proto_bfd_peer_t *session, bfd_packet_t *bfd) +static void bfd_calc_sha1(bfd_session_t *session, bfd_packet_t *bfd) { fr_sha1_ctx ctx; bfd_auth_sha1_t *sha1 = &bfd->auth.sha1; @@ -502,7 +497,7 @@ static void bfd_calc_sha1(proto_bfd_peer_t *session, bfd_packet_t *bfd) fr_sha1_final(sha1->digest, &ctx); } -static void bfd_auth_sha1(proto_bfd_peer_t *session, bfd_packet_t *bfd) +static void bfd_auth_sha1(bfd_session_t *session, bfd_packet_t *bfd) { bfd_auth_sha1_t *sha1 = &bfd->auth.sha1; @@ -516,7 +511,7 @@ static void bfd_auth_sha1(proto_bfd_peer_t *session, bfd_packet_t *bfd) bfd_calc_sha1(session, bfd); } -static int bfd_verify_sequence(proto_bfd_peer_t *session, uint32_t sequence_no, +static int bfd_verify_sequence(bfd_session_t *session, uint32_t sequence_no, int keyed) { uint32_t start, stop; @@ -543,7 +538,7 @@ static int bfd_verify_sequence(proto_bfd_peer_t *session, uint32_t sequence_no, return 1; } -static int bfd_verify_simple(proto_bfd_peer_t *session, bfd_packet_t *bfd) +static int bfd_verify_simple(bfd_session_t *session, bfd_packet_t *bfd) { bfd_auth_simple_t *simple = &bfd->auth.password; @@ -554,7 +549,7 @@ static int bfd_verify_simple(proto_bfd_peer_t *session, bfd_packet_t *bfd) return (fr_digest_cmp((uint8_t const *) session->client.secret, simple->password, session->secret_len) == 0); } -static int bfd_verify_md5(proto_bfd_peer_t *session, bfd_packet_t *bfd) +static int bfd_verify_md5(bfd_session_t *session, bfd_packet_t *bfd) { int rcode; bfd_auth_md5_t *md5 = &bfd->auth.md5; @@ -593,7 +588,7 @@ static int bfd_verify_md5(proto_bfd_peer_t *session, bfd_packet_t *bfd) return 1; } -static int bfd_verify_sha1(proto_bfd_peer_t *session, bfd_packet_t *bfd) +static int bfd_verify_sha1(bfd_session_t *session, bfd_packet_t *bfd) { int rcode; bfd_auth_sha1_t *sha1 = &bfd->auth.sha1; @@ -632,7 +627,7 @@ static int bfd_verify_sha1(proto_bfd_peer_t *session, bfd_packet_t *bfd) return 1; } -static int bfd_authenticate(proto_bfd_peer_t *session, bfd_packet_t *bfd) +static int bfd_authenticate(bfd_session_t *session, bfd_packet_t *bfd) { switch (bfd->auth.basic.auth_type) { case BFD_AUTH_RESERVED: @@ -655,7 +650,7 @@ static int bfd_authenticate(proto_bfd_peer_t *session, bfd_packet_t *bfd) } -static void bfd_sign(proto_bfd_peer_t *session, bfd_packet_t *bfd) +static void bfd_sign(bfd_session_t *session, bfd_packet_t *bfd) { if (bfd->auth_present) { switch (session->auth_type) { @@ -683,7 +678,7 @@ static void bfd_sign(proto_bfd_peer_t *session, bfd_packet_t *bfd) /* * Initialize a control packet. */ -static void bfd_control_packet_init(proto_bfd_peer_t *session, bfd_packet_t *bfd) +static void bfd_control_packet_init(bfd_session_t *session, bfd_packet_t *bfd) { memset(bfd, 0, sizeof(*bfd)); @@ -731,7 +726,7 @@ static void bfd_control_packet_init(proto_bfd_peer_t *session, bfd_packet_t *bfd */ static void bfd_send_packet(UNUSED fr_event_list_t *el, UNUSED fr_time_t now, void *ctx) { - proto_bfd_peer_t *session = ctx; + bfd_session_t *session = ctx; bfd_packet_t bfd; bfd_control_packet_init(session, &bfd); @@ -747,6 +742,8 @@ static void bfd_send_packet(UNUSED fr_event_list_t *el, UNUSED fr_time_t now, vo DEBUG("BFD %s sending packet state %s", session->client.shortname, fr_bfd_packet_names[session->session_state]); + session->last_sent = fr_time(); + if (sendfromto(session->sockfd, &bfd, bfd.length, 0, 0, (struct sockaddr *) &session->local_sockaddr, session->local_salen, (struct sockaddr *) &session->remote_sockaddr, session->remote_salen) < 0) { @@ -758,7 +755,7 @@ static void bfd_send_packet(UNUSED fr_event_list_t *el, UNUSED fr_time_t now, vo /* * Start sending packets. */ -static void bfd_start_packets(proto_bfd_peer_t *session) +static void bfd_start_packets(bfd_session_t *session) { uint64_t interval, base; uint64_t jitter; @@ -768,8 +765,6 @@ static void bfd_start_packets(proto_bfd_peer_t *session) */ fr_event_timer_delete(&session->ev_packet); - session->last_sent = fr_time(); - if (fr_time_delta_cmp(session->desired_min_tx_interval, session->remote_min_rx_interval) >= 0) { interval = fr_time_delta_unwrap(session->desired_min_tx_interval); } else { @@ -817,7 +812,7 @@ static void bfd_start_packets(proto_bfd_peer_t *session) /* * Start polling for the peer. */ -static void bfd_start_poll(proto_bfd_peer_t *session) +static void bfd_start_poll(bfd_session_t *session) { if (session->doing_poll) return; @@ -841,7 +836,7 @@ static void bfd_start_poll(proto_bfd_peer_t *session) /* * Timer functions */ -static void bfd_set_desired_min_tx_interval(proto_bfd_peer_t *session, fr_time_delta_t value) +static void bfd_set_desired_min_tx_interval(bfd_session_t *session, fr_time_delta_t value) { /* * Increasing the value: don't change it if we're already @@ -884,7 +879,7 @@ static void bfd_set_desired_min_tx_interval(proto_bfd_peer_t *session, fr_time_d */ static void bfd_detection_timeout(UNUSED fr_event_list_t *el, fr_time_t now, void *ctx) { - proto_bfd_peer_t *session = ctx; + bfd_session_t *session = ctx; DEBUG("BFD %s Timeout state %s ****** ", session->client.shortname, fr_bfd_packet_names[session->session_state]); @@ -904,7 +899,7 @@ static void bfd_detection_timeout(UNUSED fr_event_list_t *el, fr_time_t now, voi DEBUG("BFD %s State -> DOWN (control expired)", session->client.shortname); session->session_state = BFD_STATE_DOWN; session->local_diag = BFD_CTRL_EXPIRED; - bfd_trigger(session); /* @todo - send timeout state change to unlang */ + bfd_trigger(session, BFD_STATE_CHANGE_TIMEOUT_DOWN); bfd_set_desired_min_tx_interval(session, fr_time_delta_from_sec(1)); } @@ -924,7 +919,7 @@ static void bfd_detection_timeout(UNUSED fr_event_list_t *el, fr_time_t now, voi * Set the timeout for when we've lost enough packets to be * worried. */ -static void bfd_set_timeout(proto_bfd_peer_t *session, fr_time_t when) +static void bfd_set_timeout(bfd_session_t *session, fr_time_t when) { fr_time_t timeout; uint64_t delay; @@ -955,14 +950,14 @@ static void bfd_set_timeout(proto_bfd_peer_t *session, fr_time_t when) /* * Start / stop control packets. */ -static int bfd_stop_control(proto_bfd_peer_t *session) +static int bfd_stop_control(bfd_session_t *session) { fr_event_timer_delete(&session->ev_timeout); fr_event_timer_delete(&session->ev_packet); return 1; } -static void bfd_start_control(proto_bfd_peer_t *session) +static void bfd_start_control(bfd_session_t *session) { /* * @todo - change our discriminator? @@ -1012,7 +1007,7 @@ static void bfd_start_control(proto_bfd_peer_t *session) } -int bfd_session_init(proto_bfd_peer_t *session) +int bfd_session_init(bfd_session_t *session) { session->session_state = BFD_STATE_DOWN; session->local_disc = fr_rand(); @@ -1037,7 +1032,7 @@ int bfd_session_init(proto_bfd_peer_t *session) return 0; } -void bfd_session_start(proto_bfd_peer_t *session) +void bfd_session_start(bfd_session_t *session) { DEBUG("Starting BFD for %s", session->client.shortname); diff --git a/src/listen/bfd/session.h b/src/listen/bfd/session.h index ff8d6a6b993..87021ef278a 100644 --- a/src/listen/bfd/session.h +++ b/src/listen/bfd/session.h @@ -25,8 +25,128 @@ */ #include "proto_bfd.h" -int bfd_session_init(proto_bfd_peer_t *session); +typedef struct { + fr_client_t client; //!< might as well re-use this, others need it -void bfd_session_start(proto_bfd_peer_t *session); + uint16_t port; //!< peer port where packets are sent to -int bfd_session_process(proto_bfd_peer_t *session, bfd_packet_t *bfd); + /* + * Peers are defined globally to a virtual server. Each + * peer can only have one session associated with it. + */ + void *inst; //!< proto_bfd_udp instance using this session + fr_listen_t *listen; //!< associated listener + + int sockfd; //!< cached for laziness + fr_event_list_t *el; //!< event list + fr_network_t *nr; //!< network side of things + + struct sockaddr_storage remote_sockaddr; //!< cached for laziness + socklen_t remote_salen; + + struct sockaddr_storage local_sockaddr; //!< cached for laziness + socklen_t local_salen; + + /* + * Internal state management + */ + fr_event_timer_t const *ev_timeout; //!< when we time out for not receiving a packet + fr_event_timer_t const *ev_packet; //!< for when we next send a packet + fr_time_t last_recv; //!< last received packet + fr_time_t next_recv; //!< when we next expect to receive a packet + fr_time_t last_sent; //!< the last time we sent a packet + + bfd_session_state_t session_state; //!< our view of the session state + bfd_session_state_t remote_session_state; //!< their view of the session state + + /* + * BFD state machine, and fields we use to manage it. + * + * The public names in the configuration files are what makes sense. + * + * The names here are the names from the protocol, so that we can be sure the state machine is + * implemented correctly. + */ + uint32_t local_disc; //!< our session ID, which is unique to this session + uint32_t remote_disc; //!< their session ID + + bfd_diag_t local_diag; //!< diagnostics for errors + + uint32_t detect_multi; + + fr_time_delta_t desired_min_tx_interval; //!< intervals between transmits + fr_time_delta_t required_min_rx_interval; //!< intervals between receives + + fr_time_delta_t remote_min_rx_interval; //!< their min_rx_interval + + fr_time_delta_t my_min_echo_rx_interval; //!< what we send for echo_rx_interval + + fr_time_delta_t next_min_tx_interval; //!< how to update this when we're polling + + + bool demand_mode; //!< demand is "once session is up, stop sending packets" + bool remote_demand_mode; //!< their demand mode + + bool doing_poll; + + /* + * Authentication configuration and states. + */ + bool auth_seq_known; //!< do we know the authentication sequence number? + + bfd_auth_type_t auth_type; //!< what kind of authentication is used + + uint32_t recv_auth_seq; //!< their auth_seq number + uint32_t xmit_auth_seq; //!< our auth_seq number + + size_t secret_len; //!< doesn't change while we're running + + fr_time_delta_t detection_time; //!< used to set ev_timeout + int detection_timeouts; //!< too many timeouts means !auth_seq_known + + bool passive; //!< active or passive role from RFC 5880 - unused +} bfd_session_t; + +/* + * Common APIs between the listen and process routines. There's no real reason for these definitions to + * be here, other than it's an easy place to put common code and definitions. + * + * Unlike other protocols, BFD has no association between request and reply. Instead, there are two + * independent streams of packets. One is sent by us to the peer, and the other is sent by the peer to + * us. + * + * In addition, there are state changes associated with BFD packets. + */ +typedef enum { + BFD_WRAPPER_INVALID = 0, + BFD_WRAPPER_RECV_PACKET, + BFD_WRAPPER_SEND_PACKET, + BFD_WRAPPER_STATE_CHANGE, +} bfd_wrapper_type_t; + +typedef enum { + BFD_STATE_CHANGE_INVALID = 0, + BFD_STATE_CHANGE_NONE, //!< no state change + BFD_STATE_CHANGE_ADMIN_DOWN, //!< we are admin-down + BFD_STATE_CHANGE_PEER_DOWN, //!< the peer has signalled us that he's Down. + BFD_STATE_CHANGE_INIT, //!< we are going to INIT + BFD_STATE_CHANGE_UP, //!< we are going to UP + BFD_STATE_CHANGE_TIMEOUT_DOWN, +} bfd_state_change_t; + +typedef struct { + uint32_t type; + union { + bfd_packet_t packet; + struct { + bfd_state_change_t state_change; + bfd_session_t *peer; + }; + }; +} bfd_wrapper_t; + +int bfd_session_init(bfd_session_t *session); + +void bfd_session_start(bfd_session_t *session); + +bfd_state_change_t bfd_session_process(bfd_session_t *session, bfd_packet_t *bfd);