]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
rearrange in preparation for punting packets to unlang
authorAlan T. DeKok <aland@freeradius.org>
Sat, 11 Mar 2023 14:25:44 +0000 (09:25 -0500)
committerAlan T. DeKok <aland@freeradius.org>
Tue, 14 Mar 2023 21:10:37 +0000 (17:10 -0400)
src/listen/bfd/proto_bfd.c
src/listen/bfd/proto_bfd.h
src/listen/bfd/proto_bfd_udp.c
src/listen/bfd/session.c
src/listen/bfd/session.h

index a096e3715d635b0fac541edd4f7b4ea985323a54..4e70cffeb2529c2041329c22b66b560d1d07472f 100644 (file)
@@ -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));
index ec3663f4a2235a749bc65775f063228b85be9b3c..749ee386adbcd25d7794dd9ec6428d548cf56e95 100644 (file)
@@ -25,6 +25,7 @@
  */
 #include <freeradius-devel/io/master.h>
 #include <freeradius-devel/bfd/bfd.h>
+#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;
index 93a7d30ada2709cb5ec34406579140e2a64dd46c..ee76f90c13536e3d807df6f3162967701699136c 100644 (file)
@@ -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.
index 7c9bee9dac84b2763dbb1d49e14fbd0c8b358996..e95eec13cc3023179db59ecba0bbb400dae455ea 100644 (file)
 #include <freeradius-devel/util/sha1.h>
 #include <freeradius-devel/util/socket.h>
 #include <freeradius-devel/util/time.h>
-#include <freeradius-devel/server/trigger.h>
 
 #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 <timeout> -> 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);
 
index ff8d6a6b993e5ad2e4fb58b93d0f1fa5409c7347..87021ef278a9a7fcd002fd23ed87aa8118bea55f 100644 (file)
  */
 #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);