|
Packit |
c22fc9 |
/*
|
|
Packit |
c22fc9 |
* Soft: Keepalived is a failover program for the LVS project
|
|
Packit |
c22fc9 |
* <www.linuxvirtualserver.org>. It monitor & manipulate
|
|
Packit |
c22fc9 |
* a loadbalanced server pool using multi-layer checks.
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* Part: Scheduling framework for bfd code
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* Author: Ilya Voronin, <ivoronin@gmail.com>
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
c22fc9 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
c22fc9 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
Packit |
c22fc9 |
* See the GNU General Public License for more details.
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* This program is free software; you can redistribute it and/or
|
|
Packit |
c22fc9 |
* modify it under the terms of the GNU General Public License
|
|
Packit |
c22fc9 |
* as published by the Free Software Foundation; either version
|
|
Packit |
c22fc9 |
* 2 of the License, or (at your option) any later version.
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* Copyright (C) 2015-2017 Alexandre Cassen, <acassen@gmail.com>
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#include "config.h"
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#include <sys/socket.h>
|
|
Packit |
c22fc9 |
#include <unistd.h>
|
|
Packit |
c22fc9 |
#include <assert.h>
|
|
Packit |
c22fc9 |
#include <netdb.h>
|
|
Packit |
c22fc9 |
#include <inttypes.h>
|
|
Packit |
c22fc9 |
#include <stdio.h>
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#include "bfd.h"
|
|
Packit |
c22fc9 |
#include "bfd_data.h"
|
|
Packit |
c22fc9 |
#include "bfd_scheduler.h"
|
|
Packit |
c22fc9 |
#include "bfd_event.h"
|
|
Packit |
c22fc9 |
#include "parser.h"
|
|
Packit |
c22fc9 |
#include "logger.h"
|
|
Packit |
c22fc9 |
#include "memory.h"
|
|
Packit |
c22fc9 |
#include "main.h"
|
|
Packit |
c22fc9 |
#include "bitops.h"
|
|
Packit |
c22fc9 |
#include "utils.h"
|
|
Packit |
c22fc9 |
#include "signals.h"
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
static int bfd_send_packet(int, bfdpkt_t *, bool);
|
|
Packit |
c22fc9 |
static void bfd_sender_schedule(bfd_t *);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
static void bfd_state_down(bfd_t *, char diag);
|
|
Packit |
c22fc9 |
static void bfd_state_admindown(bfd_t *);
|
|
Packit |
c22fc9 |
static void bfd_state_up(bfd_t *);
|
|
Packit |
c22fc9 |
static void bfd_dump_timers(FILE *fp, bfd_t *);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/*
|
|
Packit |
c22fc9 |
* Session sender thread
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* Runs every local_tx_intv, or after reception of a packet
|
|
Packit |
c22fc9 |
* with Poll bit set
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
inline static long
|
|
Packit |
c22fc9 |
thread_time_to_wakeup(thread_t *thread)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
struct timeval tmp_time;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
timersub(&thread->sands, &time_now, &tmp_time);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return timer_long(tmp_time);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Sends one BFD control packet and reschedules itself if needed */
|
|
Packit |
c22fc9 |
static int
|
|
Packit |
c22fc9 |
bfd_sender_thread(thread_t *thread)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
bfd_t *bfd;
|
|
Packit |
c22fc9 |
bfdpkt_t pkt;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
assert(thread);
|
|
Packit |
c22fc9 |
bfd = THREAD_ARG(thread);
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
assert(!BFD_ISADMINDOWN(bfd));
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (thread->type != THREAD_EVENT)
|
|
Packit |
c22fc9 |
bfd->thread_out = NULL;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
bfd_build_packet(&pkt, bfd, bfd_buffer, BFD_BUFFER_SIZE);
|
|
Packit |
c22fc9 |
if (bfd_send_packet(bfd->fd_out, &pkt, !bfd->send_error) == -1) {
|
|
Packit |
c22fc9 |
if (!bfd->send_error) {
|
|
Packit |
c22fc9 |
log_message(LOG_ERR, "BFD_Instance(%s) Error sending packet", bfd->iname);
|
|
Packit |
c22fc9 |
bfd->send_error = true;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
} else
|
|
Packit |
c22fc9 |
bfd->send_error = false;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Reset final flag if set */
|
|
Packit |
c22fc9 |
bfd->final = 0;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Schedule next run if not called as an event thread */
|
|
Packit |
c22fc9 |
if (thread->type != THREAD_EVENT)
|
|
Packit |
c22fc9 |
bfd_sender_schedule(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return 0;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Schedules bfd_sender_thread to run in local_tx_intv minus applied jitter */
|
|
Packit |
c22fc9 |
static uint32_t
|
|
Packit |
c22fc9 |
get_jitter(bfd_t * bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
uint32_t min_jitter;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/*
|
|
Packit |
c22fc9 |
* RFC5880:
|
|
Packit |
c22fc9 |
* The periodic transmission of BFD Control packets MUST be jittered
|
|
Packit |
c22fc9 |
* on a per-packet basis by up to 25%, that is, the interval MUST be
|
|
Packit |
c22fc9 |
* reduced by a random value of 0 to 25% <...>
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* If bfd.DetectMult is equal to 1, the interval between transmitted
|
|
Packit |
c22fc9 |
* BFD Control packets MUST be no more than 90% of the negotiated
|
|
Packit |
c22fc9 |
* transmission interval, and MUST be no less than 75% of the
|
|
Packit |
c22fc9 |
* negotiated transmission interval.
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
if (bfd->local_detect_mult)
|
|
Packit |
c22fc9 |
min_jitter = bfd->local_tx_intv * 0.1;
|
|
Packit |
c22fc9 |
else
|
|
Packit |
c22fc9 |
min_jitter = 0;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return rand_intv(min_jitter, bfd->local_tx_intv * 0.25);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Schedules bfd_sender_thread to run in local_tx_intv minus applied jitter */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
bfd_sender_schedule(bfd_t *bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
assert(!bfd->thread_out);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
bfd->thread_out =
|
|
Packit |
c22fc9 |
thread_add_timer(master, bfd_sender_thread, bfd,
|
|
Packit |
c22fc9 |
bfd->local_tx_intv - get_jitter(bfd));
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Cancels bfd_sender_thread run */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
bfd_sender_cancel(bfd_t *bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
assert(bfd->thread_out);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
thread_cancel(bfd->thread_out);
|
|
Packit |
c22fc9 |
bfd->thread_out = NULL;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Reschedules bfd_sender_thread run (usually after local_tx_intv change) */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
bfd_sender_reschedule(bfd_t *bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
assert(bfd->thread_out);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
timer_thread_update_timeout(bfd->thread_out, bfd->local_tx_intv - get_jitter(bfd));
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Returns 1 if bfd_sender_thread is scheduled to run, 0 otherwise */
|
|
Packit |
c22fc9 |
static int
|
|
Packit |
c22fc9 |
bfd_sender_scheduled(bfd_t *bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return bfd->thread_out != NULL;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Suspends sender thread. Needs freshly updated time_now */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
bfd_sender_suspend(bfd_t * bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
assert(bfd->thread_out);
|
|
Packit |
c22fc9 |
assert(bfd->sands_out == -1);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
bfd->sands_out = thread_time_to_wakeup(bfd->thread_out);
|
|
Packit |
c22fc9 |
bfd_sender_cancel(bfd);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Resumes sender thread */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
bfd_sender_resume(bfd_t *bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
assert(!bfd->thread_out);
|
|
Packit |
c22fc9 |
assert(bfd->sands_out != -1);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (!bfd->passive || bfd->local_state == BFD_STATE_UP)
|
|
Packit |
c22fc9 |
bfd->thread_out =
|
|
Packit |
c22fc9 |
thread_add_timer(master, bfd_sender_thread, bfd, bfd->sands_out);
|
|
Packit |
c22fc9 |
bfd->sands_out = -1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Returns 1 if bfd_sender_thread is suspended, 0 otherwise */
|
|
Packit |
c22fc9 |
static int
|
|
Packit |
c22fc9 |
bfd_sender_suspended(bfd_t *bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return bfd->sands_out != -1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
bfd_sender_discard(bfd_t *bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
assert(bfd->sands_out != -1);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
bfd->sands_out = -1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/*
|
|
Packit |
c22fc9 |
* Session expiration thread
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* Runs after local_detect_time has passed since receipt of last
|
|
Packit |
c22fc9 |
* BFD control packet from neighbor
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Marks session as down because of Control Detection Time Expiration */
|
|
Packit |
c22fc9 |
static int
|
|
Packit |
c22fc9 |
bfd_expire_thread(thread_t *thread)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
bfd_t *bfd;
|
|
Packit |
c22fc9 |
uint32_t dead_time, overdue_time;
|
|
Packit |
c22fc9 |
timeval_t dead_time_tv;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
assert(thread);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
bfd = THREAD_ARG(thread);
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Session cannot expire while not in Up or Init states */
|
|
Packit |
c22fc9 |
assert(BFD_ISUP(bfd) || BFD_ISINIT(bfd));
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
bfd->thread_exp = NULL;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Time since last received control packet */
|
|
Packit |
c22fc9 |
timersub(&time_now, &bfd->last_seen, &dead_time_tv);
|
|
Packit |
c22fc9 |
dead_time = timer_long(dead_time_tv);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Difference between expected and actual failure detection time */
|
|
Packit |
c22fc9 |
overdue_time = dead_time - bfd->local_detect_time;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (bfd->local_state == BFD_STATE_UP ||
|
|
Packit |
c22fc9 |
__test_bit(LOG_EXTRA_DETAIL_BIT, &debug))
|
|
Packit |
c22fc9 |
log_message(LOG_WARNING, "BFD_Instance(%s) Expired after"
|
|
Packit |
c22fc9 |
" %i ms (%i usec overdue)",
|
|
Packit |
c22fc9 |
bfd->iname, dead_time / 1000, overdue_time);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/*
|
|
Packit |
c22fc9 |
* RFC5880:
|
|
Packit |
c22fc9 |
* <...> If a period of a Detection Time passes without the
|
|
Packit |
c22fc9 |
* receipt of a valid, authenticated BFD packet from the remote
|
|
Packit |
c22fc9 |
* system, this <bfd.RemoteDiscr> variable MUST be set to zero.
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
bfd->remote_discr = 0;
|
|
Packit |
c22fc9 |
bfd_state_down(bfd, BFD_DIAG_EXPIRED);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return 0;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Schedules bfd_expire_thread to run in local_detect_time */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
bfd_expire_schedule(bfd_t *bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
assert(!bfd->thread_exp);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
bfd->thread_exp =
|
|
Packit |
c22fc9 |
thread_add_timer(master, bfd_expire_thread, bfd,
|
|
Packit |
c22fc9 |
bfd->local_detect_time);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Cancels bfd_expire_thread run */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
bfd_expire_cancel(bfd_t *bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
assert(bfd->thread_exp);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
thread_cancel(bfd->thread_exp);
|
|
Packit |
c22fc9 |
bfd->thread_exp = NULL;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Reschedules bfd_expire_thread run (usually after control packet receipt) */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
bfd_expire_reschedule(bfd_t *bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
assert(bfd->thread_exp);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
timer_thread_update_timeout(bfd->thread_exp, bfd->local_detect_time);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Returns 1 if bfd_expire_thread is scheduled to run, 0 otherwise */
|
|
Packit |
c22fc9 |
static int
|
|
Packit |
c22fc9 |
bfd_expire_scheduled(bfd_t *bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return bfd->thread_exp != NULL;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Suspends expire thread. Needs freshly updated time_now */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
bfd_expire_suspend(bfd_t *bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
assert(bfd->thread_exp);
|
|
Packit |
c22fc9 |
assert(bfd->sands_exp == -1);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
bfd->sands_exp = thread_time_to_wakeup(bfd->thread_exp);
|
|
Packit |
c22fc9 |
bfd_expire_cancel(bfd);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Resumes expire thread */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
bfd_expire_resume(bfd_t *bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
assert(!bfd->thread_exp);
|
|
Packit |
c22fc9 |
assert(bfd->sands_exp != -1);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
bfd->thread_exp =
|
|
Packit |
c22fc9 |
thread_add_timer(master, bfd_expire_thread, bfd, bfd->sands_exp);
|
|
Packit |
c22fc9 |
bfd->sands_exp = -1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Returns 1 if bfd_expire_thread is suspended, 0 otherwise */
|
|
Packit |
c22fc9 |
static int
|
|
Packit |
c22fc9 |
bfd_expire_suspended(bfd_t *bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return bfd->sands_exp != -1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
bfd_expire_discard(bfd_t *bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
assert(bfd->sands_exp != -1);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
bfd->sands_exp = -1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/*
|
|
Packit |
c22fc9 |
* Session reset thread
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* Runs after local_detect_time has passed after BFD session
|
|
Packit |
c22fc9 |
* gone to Down state.
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Resets BFD session to initial state */
|
|
Packit |
c22fc9 |
static int
|
|
Packit |
c22fc9 |
bfd_reset_thread(thread_t *thread)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
bfd_t *bfd;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
assert(thread);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
bfd = THREAD_ARG(thread);
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
assert(bfd->thread_rst);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
bfd->thread_rst = NULL;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
bfd_reset_state(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return 0;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Schedules bfd_reset_thread to run in local_detect_time */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
bfd_reset_schedule(bfd_t * bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
assert(!bfd->thread_rst);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
bfd->thread_rst =
|
|
Packit |
c22fc9 |
thread_add_timer(master, bfd_reset_thread, bfd,
|
|
Packit |
c22fc9 |
bfd->local_detect_time);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Cancels bfd_reset_thread run */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
bfd_reset_cancel(bfd_t *bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
assert(bfd->thread_rst);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
thread_cancel(bfd->thread_rst);
|
|
Packit |
c22fc9 |
bfd->thread_rst = NULL;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Returns 1 if bfd_reset_thread is scheduled to run, 0 otherwise */
|
|
Packit |
c22fc9 |
static int
|
|
Packit |
c22fc9 |
bfd_reset_scheduled(bfd_t *bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return bfd->thread_rst != NULL;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Suspends reset thread. Needs freshly updated time_now */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
bfd_reset_suspend(bfd_t *bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
assert(bfd->thread_rst);
|
|
Packit |
c22fc9 |
assert(bfd->sands_rst == -1);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
bfd->sands_rst = thread_time_to_wakeup(bfd->thread_rst);
|
|
Packit |
c22fc9 |
bfd_reset_cancel(bfd);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Resumes reset thread */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
bfd_reset_resume(bfd_t *bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
assert(!bfd->thread_rst);
|
|
Packit |
c22fc9 |
assert(bfd->sands_rst != -1);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
bfd->thread_rst =
|
|
Packit |
c22fc9 |
thread_add_timer(master, bfd_reset_thread, bfd, bfd->sands_rst);
|
|
Packit |
c22fc9 |
bfd->sands_rst = -1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Returns 1 if bfd_reset_thread is suspended, 0 otherwise */
|
|
Packit |
c22fc9 |
static int
|
|
Packit |
c22fc9 |
bfd_reset_suspended(bfd_t *bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return bfd->sands_rst != -1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
bfd_reset_discard(bfd_t *bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
assert(bfd->sands_rst != -1);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
bfd->sands_rst = -1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/*
|
|
Packit |
c22fc9 |
* State change handlers
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
/* Common actions for Down and AdminDown states */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
bfd_state_fall(bfd_t *bfd, bool send_event)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/*
|
|
Packit |
c22fc9 |
* RFC5880:
|
|
Packit |
c22fc9 |
* When bfd.SessionState is not Up, the system MUST set
|
|
Packit |
c22fc9 |
* bfd.DesiredMinTxInterval to a value of not less than
|
|
Packit |
c22fc9 |
* one second (1,000,000 microseconds)
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
bfd_idle_local_tx_intv(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (bfd_expire_scheduled(bfd))
|
|
Packit |
c22fc9 |
bfd_expire_cancel(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (send_event &&
|
|
Packit |
c22fc9 |
bfd->remote_state != BFD_STATE_ADMINDOWN)
|
|
Packit |
c22fc9 |
bfd_event_send(bfd);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Runs when BFD session state goes Down */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
bfd_state_down(bfd_t *bfd, char diag)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
assert(BFD_VALID_DIAG(diag));
|
|
Packit |
c22fc9 |
int old_state = bfd->local_state;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (bfd->local_state == BFD_STATE_UP)
|
|
Packit |
c22fc9 |
bfd->local_discr = bfd_get_random_discr(bfd_data);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (bfd->local_state == BFD_STATE_UP ||
|
|
Packit |
c22fc9 |
__test_bit(LOG_EXTRA_DETAIL_BIT, &debug))
|
|
Packit |
c22fc9 |
log_message(LOG_WARNING, "BFD_Instance(%s) Entering %s state"
|
|
Packit |
c22fc9 |
" (Local diagnostic - %s, Remote diagnostic - %s)",
|
|
Packit |
c22fc9 |
bfd->iname, BFD_STATE_STR(BFD_STATE_DOWN),
|
|
Packit |
c22fc9 |
BFD_DIAG_STR(diag),
|
|
Packit |
c22fc9 |
BFD_DIAG_STR(bfd->remote_diag));
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
bfd->local_state = BFD_STATE_DOWN;
|
|
Packit |
c22fc9 |
bfd->local_diag = diag;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
bfd_reset_schedule(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (bfd->passive && bfd_sender_scheduled(bfd))
|
|
Packit |
c22fc9 |
bfd_sender_cancel(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
bfd_state_fall(bfd, old_state == BFD_STATE_UP);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Runs when BFD session state goes AdminDown */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
bfd_state_admindown(bfd_t *bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
bfd->local_state = BFD_STATE_ADMINDOWN;
|
|
Packit |
c22fc9 |
bfd->local_diag = BFD_DIAG_ADMIN_DOWN;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (bfd_sender_scheduled(bfd))
|
|
Packit |
c22fc9 |
bfd_sender_cancel(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
log_message(LOG_WARNING, "BFD_Instance(%s) Entering %s state",
|
|
Packit |
c22fc9 |
bfd->iname, BFD_STATE_STR(bfd->local_state));
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
bfd_state_fall(bfd, false);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Common actions for Init and Up states */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
bfd_state_rise(bfd_t *bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
/* RFC5880 doesn't state if this must be done or not */
|
|
Packit |
c22fc9 |
bfd->local_diag = BFD_DIAG_NO_DIAG;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (bfd->local_state == BFD_STATE_UP ||
|
|
Packit |
c22fc9 |
__test_bit(LOG_EXTRA_DETAIL_BIT, &debug))
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "BFD_Instance(%s) Entering %s state",
|
|
Packit |
c22fc9 |
bfd->iname, BFD_STATE_STR(bfd->local_state));
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (bfd_reset_scheduled(bfd))
|
|
Packit |
c22fc9 |
bfd_reset_cancel(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (!bfd_expire_scheduled(bfd))
|
|
Packit |
c22fc9 |
bfd_expire_schedule(bfd);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Runs when BFD session state goes Up */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
bfd_state_up(bfd_t *bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
bfd->local_state = BFD_STATE_UP;
|
|
Packit |
c22fc9 |
bfd_state_rise(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (bfd->local_idle_tx_intv != bfd->local_min_tx_intv)
|
|
Packit |
c22fc9 |
bfd_set_poll(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
bfd_event_send(bfd);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Runs when BFD session state goes Init */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
bfd_state_init(bfd_t *bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* According to RFC5880 session cannot directly
|
|
Packit |
c22fc9 |
transition from Init to Up state */
|
|
Packit |
c22fc9 |
assert(!BFD_ISUP(bfd));
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
bfd->local_state = BFD_STATE_INIT;
|
|
Packit |
c22fc9 |
bfd_state_rise(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (bfd->passive && !bfd_sender_scheduled(bfd))
|
|
Packit |
c22fc9 |
bfd_sender_schedule(bfd);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Dumps current timers values */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
bfd_dump_timers(FILE *fp, bfd_t *bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
conf_write(fp, "BFD_Instance(%s)"
|
|
Packit |
c22fc9 |
" --------------< Session parameters >-------------",
|
|
Packit |
c22fc9 |
bfd->iname);
|
|
Packit |
c22fc9 |
conf_write(fp, "BFD_Instance(%s)"
|
|
Packit |
c22fc9 |
" min_tx min_rx tx_intv mult detect_time",
|
|
Packit |
c22fc9 |
bfd->iname);
|
|
Packit |
c22fc9 |
conf_write(fp, "BFD_Instance(%s)"
|
|
Packit |
c22fc9 |
" local %7u %7u %8u %5u %12" PRIu64,
|
|
Packit |
c22fc9 |
bfd->iname, (bfd->local_state == BFD_STATE_UP ? bfd->local_min_tx_intv : bfd->local_idle_tx_intv) / 1000,
|
|
Packit |
c22fc9 |
bfd->local_min_rx_intv / 1000,
|
|
Packit |
c22fc9 |
bfd->local_tx_intv / 1000, bfd->local_detect_mult,
|
|
Packit |
c22fc9 |
bfd->local_detect_time / 1000);
|
|
Packit |
c22fc9 |
conf_write(fp, "BFD_Instance(%s)" " remote %6u %7u %8u %5u %12" PRIu64,
|
|
Packit |
c22fc9 |
bfd->iname, bfd->remote_min_tx_intv / 1000,
|
|
Packit |
c22fc9 |
bfd->remote_min_rx_intv / 1000,
|
|
Packit |
c22fc9 |
bfd->remote_tx_intv / 1000, bfd->remote_detect_mult,
|
|
Packit |
c22fc9 |
bfd->remote_detect_time / 1000);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/*
|
|
Packit |
c22fc9 |
* Packet handling functions
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Sends a control packet to the neighbor (called from bfd_sender_thread)
|
|
Packit |
c22fc9 |
returns -1 on error */
|
|
Packit |
c22fc9 |
static int
|
|
Packit |
c22fc9 |
bfd_send_packet(int fd, bfdpkt_t *pkt, bool log_error)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
int ret;
|
|
Packit |
c22fc9 |
socklen_t dstlen;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
assert(fd >= 0);
|
|
Packit |
c22fc9 |
assert(pkt);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (pkt->dst_addr.ss_family == AF_INET)
|
|
Packit |
c22fc9 |
dstlen = sizeof (struct sockaddr_in);
|
|
Packit |
c22fc9 |
else
|
|
Packit |
c22fc9 |
dstlen = sizeof (struct sockaddr_in6);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
ret =
|
|
Packit |
c22fc9 |
sendto(fd, pkt->buf, pkt->len, 0,
|
|
Packit |
c22fc9 |
(struct sockaddr *) &pkt->dst_addr, dstlen);
|
|
Packit |
c22fc9 |
if (ret == -1 && log_error)
|
|
Packit |
c22fc9 |
log_message(LOG_ERR, "sendto() error (%m)");
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return ret;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Handles incoming control packet (called from bfd_receiver_thread) and
|
|
Packit |
c22fc9 |
processes it through a BFD state machine. */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
bfd_handle_packet(bfdpkt_t *pkt)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
uint32_t old_local_tx_intv;
|
|
Packit |
c22fc9 |
uint32_t old_remote_rx_intv;
|
|
Packit |
c22fc9 |
uint32_t old_remote_tx_intv;
|
|
Packit |
c22fc9 |
uint8_t old_remote_detect_mult;
|
|
Packit |
c22fc9 |
uint64_t old_local_detect_time;
|
|
Packit |
c22fc9 |
bfd_t *bfd;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
assert(pkt);
|
|
Packit |
c22fc9 |
assert(pkt->hdr);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Perform sanity checks on a packet */
|
|
Packit |
c22fc9 |
if (bfd_check_packet(pkt)) {
|
|
Packit |
c22fc9 |
if (__test_bit(LOG_DETAIL_BIT, &debug))
|
|
Packit |
c22fc9 |
log_message(LOG_ERR,
|
|
Packit |
c22fc9 |
"Discarding bogus packet from %s",
|
|
Packit |
c22fc9 |
inet_sockaddrtopair(&pkt->src_addr));
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Lookup session */
|
|
Packit |
c22fc9 |
if (!pkt->hdr->remote_discr)
|
|
Packit |
c22fc9 |
bfd = find_bfd_by_addr(&pkt->src_addr);
|
|
Packit |
c22fc9 |
else
|
|
Packit |
c22fc9 |
bfd = find_bfd_by_discr(ntohl(pkt->hdr->remote_discr));
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (!bfd) {
|
|
Packit |
c22fc9 |
if (__test_bit(LOG_DETAIL_BIT, &debug))
|
|
Packit |
c22fc9 |
log_message(LOG_ERR, "Discarding packet from %s"
|
|
Packit |
c22fc9 |
" (session is not found - your"
|
|
Packit |
c22fc9 |
" discriminator field is %u)",
|
|
Packit |
c22fc9 |
inet_sockaddrtopair(&pkt->src_addr),
|
|
Packit |
c22fc9 |
pkt->hdr->remote_discr);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* We can't check the TTL any earlier, since we need to know what
|
|
Packit |
c22fc9 |
* is configured for this particular instance */
|
|
Packit |
c22fc9 |
if (bfd->max_hops != UCHAR_MAX && bfd_check_packet_ttl(pkt, bfd))
|
|
Packit |
c22fc9 |
return;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Authentication is not supported for now */
|
|
Packit |
c22fc9 |
if (pkt->hdr->auth != 0) {
|
|
Packit |
c22fc9 |
if (__test_bit(LOG_DETAIL_BIT, &debug))
|
|
Packit |
c22fc9 |
log_message(LOG_ERR, "Discarding packet from %s"
|
|
Packit |
c22fc9 |
" (auth bit is set, but no authentication"
|
|
Packit |
c22fc9 |
" is in use)",
|
|
Packit |
c22fc9 |
inet_sockaddrtopair(&pkt->src_addr));
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Discard all packets while in AdminDown state */
|
|
Packit |
c22fc9 |
if (bfd->local_state == BFD_STATE_ADMINDOWN) {
|
|
Packit |
c22fc9 |
if (__test_bit(LOG_DETAIL_BIT, &debug))
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "Discarding packet from %s"
|
|
Packit |
c22fc9 |
" (session is in AdminDown state)",
|
|
Packit |
c22fc9 |
inet_sockaddrtopair(&pkt->src_addr));
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Save old timers */
|
|
Packit |
c22fc9 |
old_remote_rx_intv = bfd->remote_min_rx_intv;
|
|
Packit |
c22fc9 |
old_remote_tx_intv = bfd->remote_min_tx_intv;
|
|
Packit |
c22fc9 |
old_remote_detect_mult = bfd->remote_detect_mult;
|
|
Packit |
c22fc9 |
old_local_detect_time = bfd->local_detect_time ;
|
|
Packit |
c22fc9 |
old_local_tx_intv = bfd->local_tx_intv ;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Update state variables */
|
|
Packit |
c22fc9 |
bfd->remote_discr = ntohl(pkt->hdr->local_discr);
|
|
Packit |
c22fc9 |
bfd->remote_state = pkt->hdr->state;
|
|
Packit |
c22fc9 |
bfd->remote_diag = pkt->hdr->diag;
|
|
Packit |
c22fc9 |
bfd->remote_min_rx_intv = ntohl(pkt->hdr->min_rx_intv);
|
|
Packit |
c22fc9 |
bfd->remote_min_tx_intv = ntohl(pkt->hdr->min_tx_intv);
|
|
Packit |
c22fc9 |
bfd->remote_demand = pkt->hdr->demand;
|
|
Packit |
c22fc9 |
bfd->remote_detect_mult = pkt->hdr->detect_mult;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Terminate poll sequence */
|
|
Packit |
c22fc9 |
if (pkt->hdr->final)
|
|
Packit |
c22fc9 |
bfd->poll = 0;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/*
|
|
Packit |
c22fc9 |
* Recalculate local and remote TX intervals if:
|
|
Packit |
c22fc9 |
* Control packet with 'Final' bit is received OR
|
|
Packit |
c22fc9 |
* Control packet with 'Poll' bit is received OR
|
|
Packit |
c22fc9 |
* Session is not UP
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
if ((bfd->local_state == BFD_STATE_UP &&
|
|
Packit |
c22fc9 |
(pkt->hdr->poll || pkt->hdr->final)) ||
|
|
Packit |
c22fc9 |
bfd->local_state != BFD_STATE_UP) {
|
|
Packit |
c22fc9 |
if (bfd->remote_state == BFD_STATE_UP &&
|
|
Packit |
c22fc9 |
(bfd->local_state == BFD_STATE_INIT || bfd->local_state == BFD_STATE_UP))
|
|
Packit |
c22fc9 |
bfd_update_local_tx_intv(bfd);
|
|
Packit |
c22fc9 |
else
|
|
Packit |
c22fc9 |
bfd_idle_local_tx_intv(bfd);
|
|
Packit |
c22fc9 |
bfd_update_remote_tx_intv(bfd);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Update the Detection Time */
|
|
Packit |
c22fc9 |
bfd->local_detect_time = bfd->remote_detect_mult * bfd->remote_tx_intv;
|
|
Packit |
c22fc9 |
bfd->remote_detect_time = bfd->local_detect_mult * bfd->local_tx_intv;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Check if timers are changed */
|
|
Packit |
c22fc9 |
if (__test_bit(LOG_EXTRA_DETAIL_BIT, &debug) ||
|
|
Packit |
c22fc9 |
(__test_bit(LOG_DETAIL_BIT, &debug) &&
|
|
Packit |
c22fc9 |
(bfd->remote_min_rx_intv != old_remote_rx_intv ||
|
|
Packit |
c22fc9 |
bfd->remote_min_tx_intv != old_remote_tx_intv ||
|
|
Packit |
c22fc9 |
bfd->remote_detect_mult != old_remote_detect_mult ||
|
|
Packit |
c22fc9 |
bfd->local_tx_intv != old_local_tx_intv)))
|
|
Packit |
c22fc9 |
bfd_dump_timers(NULL, bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Reschedule sender if local_tx_intv is being reduced */
|
|
Packit |
c22fc9 |
if (bfd->local_tx_intv < old_local_tx_intv &&
|
|
Packit |
c22fc9 |
bfd_sender_scheduled(bfd))
|
|
Packit |
c22fc9 |
bfd_sender_reschedule(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Report detection time changes */
|
|
Packit |
c22fc9 |
if (bfd->local_detect_time != old_local_detect_time)
|
|
Packit |
c22fc9 |
log_message(LOG_INFO, "BFD_Instance(%s) Detection time"
|
|
Packit |
c22fc9 |
" is %" PRIu64 " ms (was %" PRIu64 " ms)", bfd->iname,
|
|
Packit |
c22fc9 |
bfd->local_detect_time / 1000,
|
|
Packit |
c22fc9 |
old_local_detect_time / 1000);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* BFD state machine */
|
|
Packit |
c22fc9 |
if (bfd->remote_state == BFD_STATE_ADMINDOWN &&
|
|
Packit |
c22fc9 |
bfd->local_state != BFD_STATE_DOWN)
|
|
Packit |
c22fc9 |
bfd_state_down(bfd, BFD_DIAG_NBR_SIGNALLED_DOWN);
|
|
Packit |
c22fc9 |
else {
|
|
Packit |
c22fc9 |
if (bfd->local_state == BFD_STATE_DOWN) {
|
|
Packit |
c22fc9 |
if (bfd->remote_state == BFD_STATE_DOWN)
|
|
Packit |
c22fc9 |
bfd_state_init(bfd);
|
|
Packit |
c22fc9 |
else if (bfd->remote_state == BFD_STATE_INIT)
|
|
Packit |
c22fc9 |
bfd_state_up(bfd);
|
|
Packit |
c22fc9 |
} else if (bfd->local_state == BFD_STATE_INIT) {
|
|
Packit |
c22fc9 |
if (bfd->remote_state == BFD_STATE_INIT ||
|
|
Packit |
c22fc9 |
bfd->remote_state == BFD_STATE_UP)
|
|
Packit |
c22fc9 |
bfd_state_up(bfd);
|
|
Packit |
c22fc9 |
} else if (bfd->local_state == BFD_STATE_UP)
|
|
Packit |
c22fc9 |
if (bfd->remote_state == BFD_STATE_DOWN)
|
|
Packit |
c22fc9 |
bfd_state_down(bfd, BFD_DIAG_NBR_SIGNALLED_DOWN);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (bfd->remote_demand &&
|
|
Packit |
c22fc9 |
bfd->local_state == BFD_STATE_UP &&
|
|
Packit |
c22fc9 |
bfd->remote_state == BFD_STATE_UP)
|
|
Packit |
c22fc9 |
if (bfd_sender_scheduled(bfd))
|
|
Packit |
c22fc9 |
bfd_sender_cancel(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (!bfd->remote_demand ||
|
|
Packit |
c22fc9 |
bfd->local_state != BFD_STATE_UP ||
|
|
Packit |
c22fc9 |
bfd->remote_state != BFD_STATE_UP)
|
|
Packit |
c22fc9 |
if (!bfd_sender_scheduled(bfd))
|
|
Packit |
c22fc9 |
bfd_sender_schedule(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (pkt->hdr->poll) {
|
|
Packit |
c22fc9 |
bfd->final = 1;
|
|
Packit |
c22fc9 |
thread_add_event(master, bfd_sender_thread, bfd, 0);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Update last seen timer */
|
|
Packit |
c22fc9 |
bfd->last_seen = timer_now();
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Delay expiration if scheduled */
|
|
Packit |
c22fc9 |
if (bfd->local_state == BFD_STATE_UP &&
|
|
Packit |
c22fc9 |
bfd_expire_scheduled(bfd))
|
|
Packit |
c22fc9 |
bfd_expire_reschedule(bfd);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Reads one packet from input socket */
|
|
Packit |
c22fc9 |
static int
|
|
Packit |
c22fc9 |
bfd_receive_packet(bfdpkt_t *pkt, int fd, char *buf, ssize_t bufsz)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
ssize_t len;
|
|
Packit |
c22fc9 |
unsigned int ttl = 0;
|
|
Packit |
c22fc9 |
struct msghdr msg = { 0 };
|
|
Packit |
c22fc9 |
struct cmsghdr *cmsg = NULL;
|
|
Packit |
c22fc9 |
char cbuf[CMSG_SPACE(sizeof (ttl))] = { 0 };
|
|
Packit |
c22fc9 |
struct iovec iov[1] = { {0} };
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
assert(pkt);
|
|
Packit |
c22fc9 |
assert(fd >= 0);
|
|
Packit |
c22fc9 |
assert(buf);
|
|
Packit |
c22fc9 |
assert(bufsz);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
iov[0].iov_base = buf;
|
|
Packit |
c22fc9 |
iov[0].iov_len = bufsz;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
msg.msg_name = &pkt->src_addr;
|
|
Packit |
c22fc9 |
msg.msg_namelen = sizeof (pkt->src_addr);
|
|
Packit |
c22fc9 |
msg.msg_iov = iov;
|
|
Packit |
c22fc9 |
msg.msg_iovlen = 1;
|
|
Packit |
c22fc9 |
msg.msg_control = cbuf;
|
|
Packit |
c22fc9 |
msg.msg_controllen = sizeof (cbuf);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
len = recvmsg(fd, &msg, MSG_DONTWAIT);
|
|
Packit |
c22fc9 |
if (len == -1) {
|
|
Packit |
c22fc9 |
log_message(LOG_ERR, "recvmsg() error (%m)");
|
|
Packit |
c22fc9 |
return 1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (msg.msg_flags & MSG_TRUNC) {
|
|
Packit |
c22fc9 |
log_message(LOG_WARNING, "recvmsg() message truncated");
|
|
Packit |
c22fc9 |
return 1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (msg.msg_flags & MSG_CTRUNC)
|
|
Packit |
c22fc9 |
log_message(LOG_WARNING, "recvmsg() control message truncated");
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
for (cmsg = CMSG_FIRSTHDR(&msg;; cmsg != NULL;
|
|
Packit |
c22fc9 |
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
|
|
Packit |
c22fc9 |
if ((cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_TTL) ||
|
|
Packit |
c22fc9 |
(cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_HOPLIMIT))
|
|
Packit |
c22fc9 |
ttl = *CMSG_DATA(cmsg);
|
|
Packit |
c22fc9 |
else
|
|
Packit |
c22fc9 |
log_message(LOG_WARNING, "recvmsg() received"
|
|
Packit |
c22fc9 |
" unexpected control message (level %d type %d)",
|
|
Packit |
c22fc9 |
cmsg->cmsg_level, cmsg->cmsg_type);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (!ttl)
|
|
Packit |
c22fc9 |
log_message(LOG_WARNING, "recvmsg() returned no TTL control message");
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
pkt->hdr = (bfdhdr_t *) buf;
|
|
Packit |
c22fc9 |
pkt->len = len;
|
|
Packit |
c22fc9 |
pkt->ttl = ttl;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Convert an IPv4-mapped IPv6 address to a real IPv4 address */
|
|
Packit |
c22fc9 |
if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&pkt->src_addr)->sin6_addr)) {
|
|
Packit |
c22fc9 |
((struct sockaddr_in *)&pkt->src_addr)->sin_addr.s_addr = ((struct sockaddr_in6 *)&pkt->src_addr)->sin6_addr.s6_addr32[3];
|
|
Packit |
c22fc9 |
pkt->src_addr.ss_family = AF_INET;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return 0;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/*
|
|
Packit |
c22fc9 |
* Reciever thread
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Runs when data is available in listening socket */
|
|
Packit |
c22fc9 |
static int
|
|
Packit |
c22fc9 |
bfd_receiver_thread(thread_t *thread)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
bfd_data_t *data;
|
|
Packit |
c22fc9 |
bfdpkt_t pkt;
|
|
Packit |
c22fc9 |
int fd;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
assert(thread);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
data = THREAD_ARG(thread);
|
|
Packit |
c22fc9 |
assert(data);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
fd = thread->u.fd;
|
|
Packit |
c22fc9 |
assert(fd >= 0);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
data->thread_in = NULL;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Ignore THREAD_READ_TIMEOUT */
|
|
Packit |
c22fc9 |
if (thread->type == THREAD_READY_FD) {
|
|
Packit |
c22fc9 |
if (!bfd_receive_packet(&pkt, fd, bfd_buffer, BFD_BUFFER_SIZE))
|
|
Packit |
c22fc9 |
bfd_handle_packet(&pkt);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
data->thread_in =
|
|
Packit |
c22fc9 |
thread_add_read(thread->master, bfd_receiver_thread, data,
|
|
Packit |
c22fc9 |
fd, TIMER_NEVER);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return 0;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/*
|
|
Packit |
c22fc9 |
* Initialization functions
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Prepares UDP socket for listening on *:3784 (both IPv4 and IPv6) */
|
|
Packit |
c22fc9 |
static int
|
|
Packit |
c22fc9 |
bfd_open_fd_in(bfd_data_t *data)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
struct addrinfo hints;
|
|
Packit |
c22fc9 |
struct addrinfo *ai_in;
|
|
Packit |
c22fc9 |
int ret;
|
|
Packit |
c22fc9 |
int yes = 1;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
assert(data);
|
|
Packit |
c22fc9 |
assert(data->fd_in == -1);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
memset(&hints, 0, sizeof hints);
|
|
Packit |
c22fc9 |
hints.ai_family = AF_INET6;
|
|
Packit |
c22fc9 |
hints.ai_flags = AI_NUMERICSERV | AI_PASSIVE;
|
|
Packit |
c22fc9 |
hints.ai_protocol = IPPROTO_UDP;
|
|
Packit |
c22fc9 |
hints.ai_socktype = SOCK_DGRAM;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if ((ret = getaddrinfo(NULL, BFD_CONTROL_PORT, &hints, &ai_in)))
|
|
Packit |
c22fc9 |
log_message(LOG_ERR, "getaddrinfo() error (%s)", gai_strerror(ret));
|
|
Packit |
c22fc9 |
else if ((data->fd_in = socket(AF_INET6, ai_in->ai_socktype, ai_in->ai_protocol)) == -1)
|
|
Packit |
c22fc9 |
log_message(LOG_ERR, "socket() error (%m)");
|
|
Packit |
c22fc9 |
else if ((ret = setsockopt(data->fd_in, IPPROTO_IP, IP_RECVTTL, &yes, sizeof (yes))) == -1)
|
|
Packit |
c22fc9 |
log_message(LOG_ERR, "setsockopt(IP_RECVTTL) error (%m)");
|
|
Packit |
c22fc9 |
else if ((ret = setsockopt(data->fd_in, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &yes, sizeof (yes))) == -1)
|
|
Packit |
c22fc9 |
log_message(LOG_ERR, "setsockopt(IPV6_RECVHOPLIMIT) error (%m)");
|
|
Packit |
c22fc9 |
else if ((ret = bind(data->fd_in, ai_in->ai_addr, ai_in->ai_addrlen)) == -1)
|
|
Packit |
c22fc9 |
log_message(LOG_ERR, "bind() error (%m)");
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (ret)
|
|
Packit |
c22fc9 |
ret = 1;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
freeaddrinfo(ai_in);
|
|
Packit |
c22fc9 |
return ret;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Prepares UDP socket for sending data to neighbor */
|
|
Packit |
c22fc9 |
static int
|
|
Packit |
c22fc9 |
bfd_open_fd_out(bfd_t *bfd)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
int ttl;
|
|
Packit |
c22fc9 |
int ret;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
assert(bfd->fd_out == -1);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
bfd->fd_out = socket(bfd->nbr_addr.ss_family, SOCK_DGRAM, IPPROTO_UDP);
|
|
Packit |
c22fc9 |
if (bfd->fd_out == -1) {
|
|
Packit |
c22fc9 |
log_message(LOG_ERR, "BFD_Instance(%s) socket() error (%m)",
|
|
Packit |
c22fc9 |
bfd->iname);
|
|
Packit |
c22fc9 |
return 1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (bfd->src_addr.ss_family) {
|
|
Packit |
c22fc9 |
ret =
|
|
Packit |
c22fc9 |
bind(bfd->fd_out, (struct sockaddr *) &bfd->src_addr,
|
|
Packit |
c22fc9 |
sizeof (struct sockaddr));
|
|
Packit |
c22fc9 |
if (ret == -1) {
|
|
Packit |
c22fc9 |
log_message(LOG_ERR,
|
|
Packit |
c22fc9 |
"BFD_Instance(%s) bind() error (%m)",
|
|
Packit |
c22fc9 |
bfd->iname);
|
|
Packit |
c22fc9 |
return 1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
ttl = bfd->ttl;
|
|
Packit |
c22fc9 |
if (bfd->nbr_addr.ss_family == AF_INET)
|
|
Packit |
c22fc9 |
ret = setsockopt(bfd->fd_out, IPPROTO_IP, IP_TTL, &ttl, sizeof (ttl));
|
|
Packit |
c22fc9 |
else
|
|
Packit |
c22fc9 |
ret = setsockopt(bfd->fd_out, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof (ttl));
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (ret == -1) {
|
|
Packit |
c22fc9 |
log_message(LOG_ERR, "BFD_Instance(%s) setsockopt() "
|
|
Packit |
c22fc9 |
" error (%m)", bfd->iname);
|
|
Packit |
c22fc9 |
return 1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return 0;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Opens all needed sockets */
|
|
Packit |
c22fc9 |
static int
|
|
Packit |
c22fc9 |
bfd_open_fds(bfd_data_t *data)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
bfd_t *bfd;
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
assert(data);
|
|
Packit |
c22fc9 |
assert(data->bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Do not reopen input socket on reload */
|
|
Packit |
c22fc9 |
if (bfd_data->fd_in == -1) {
|
|
Packit |
c22fc9 |
if (bfd_open_fd_in(data)) {
|
|
Packit |
c22fc9 |
log_message(LOG_ERR, "Unable to open listening socket");
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* There is no point to stay alive w/o listening socket */
|
|
Packit |
c22fc9 |
return 1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
for (e = LIST_HEAD(data->bfd); e; ELEMENT_NEXT(e)) {
|
|
Packit |
c22fc9 |
bfd = ELEMENT_DATA(e);
|
|
Packit |
c22fc9 |
assert(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (bfd_open_fd_out(bfd)) {
|
|
Packit |
c22fc9 |
log_message(LOG_ERR, "BFD_Instance(%s) Unable to"
|
|
Packit |
c22fc9 |
" open output socket, disabling instance",
|
|
Packit |
c22fc9 |
bfd->iname);
|
|
Packit |
c22fc9 |
bfd_state_admindown(bfd);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return 0;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Registers sender and receiver threads */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
bfd_register_workers(bfd_data_t *data)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
bfd_t *bfd;
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
assert(data);
|
|
Packit |
c22fc9 |
assert(!data->thread_in);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Set timeout to not expire */
|
|
Packit |
c22fc9 |
data->thread_in = thread_add_read(master, bfd_receiver_thread,
|
|
Packit |
c22fc9 |
data, data->fd_in, TIMER_NEVER);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Resume or schedule threads */
|
|
Packit |
c22fc9 |
for (e = LIST_HEAD(data->bfd); e; ELEMENT_NEXT(e)) {
|
|
Packit |
c22fc9 |
bfd = ELEMENT_DATA(e);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Do not start anything if instance is in AdminDown state.
|
|
Packit |
c22fc9 |
Discard saved state if any */
|
|
Packit |
c22fc9 |
if (bfd_sender_suspended(bfd)) {
|
|
Packit |
c22fc9 |
if (BFD_ISADMINDOWN(bfd))
|
|
Packit |
c22fc9 |
bfd_sender_discard(bfd);
|
|
Packit |
c22fc9 |
else
|
|
Packit |
c22fc9 |
bfd_sender_resume(bfd);
|
|
Packit |
c22fc9 |
} else if (!BFD_ISADMINDOWN(bfd) && !bfd->passive)
|
|
Packit |
c22fc9 |
bfd_sender_schedule(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (bfd_expire_suspended(bfd)) {
|
|
Packit |
c22fc9 |
if (BFD_ISADMINDOWN(bfd))
|
|
Packit |
c22fc9 |
bfd_expire_discard(bfd);
|
|
Packit |
c22fc9 |
else
|
|
Packit |
c22fc9 |
bfd_expire_resume(bfd);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (bfd_reset_suspended(bfd)) {
|
|
Packit |
c22fc9 |
if (BFD_ISADMINDOWN(bfd))
|
|
Packit |
c22fc9 |
bfd_reset_discard(bfd);
|
|
Packit |
c22fc9 |
else
|
|
Packit |
c22fc9 |
bfd_reset_resume(bfd);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Send our status to VRRP process */
|
|
Packit |
c22fc9 |
bfd_event_send(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* If we are starting up, send a packet */
|
|
Packit |
c22fc9 |
if (!reload && !bfd->passive)
|
|
Packit |
c22fc9 |
thread_add_event(master, bfd_sender_thread, bfd, 0);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Suspends threads, closes sockets */
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
bfd_dispatcher_release(bfd_data_t *data)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
bfd_t *bfd;
|
|
Packit |
c22fc9 |
element e;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
assert(data);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Looks like dispatcher wasn't initialized yet
|
|
Packit |
c22fc9 |
This can happen is case of a configuration error */
|
|
Packit |
c22fc9 |
if (!data->thread_in)
|
|
Packit |
c22fc9 |
return;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
assert(data->fd_in != -1);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
thread_cancel(data->thread_in);
|
|
Packit |
c22fc9 |
data->thread_in = NULL;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Do not close fd_in on reload */
|
|
Packit |
c22fc9 |
if (!reload) {
|
|
Packit |
c22fc9 |
close(data->fd_in);
|
|
Packit |
c22fc9 |
data->fd_in = -1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Suspend threads for possible resuming after reconfiguration */
|
|
Packit |
c22fc9 |
set_time_now();
|
|
Packit |
c22fc9 |
for (e = LIST_HEAD(data->bfd); e; ELEMENT_NEXT(e)) {
|
|
Packit |
c22fc9 |
bfd = ELEMENT_DATA(e);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (bfd_sender_scheduled(bfd))
|
|
Packit |
c22fc9 |
bfd_sender_suspend(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (bfd_expire_scheduled(bfd))
|
|
Packit |
c22fc9 |
bfd_expire_suspend(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if (bfd_reset_scheduled(bfd))
|
|
Packit |
c22fc9 |
bfd_reset_suspend(bfd);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
assert(bfd->fd_out != -1);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
close(bfd->fd_out);
|
|
Packit |
c22fc9 |
bfd->fd_out = -1;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
cancel_signal_read_thread();
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Starts BFD dispatcher */
|
|
Packit |
c22fc9 |
int
|
|
Packit |
c22fc9 |
bfd_dispatcher_init(thread_t *thread)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
bfd_data_t *data;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
assert(thread);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
data = THREAD_ARG(thread);
|
|
Packit |
c22fc9 |
if (bfd_open_fds(data))
|
|
Packit |
c22fc9 |
exit(EXIT_FAILURE);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
bfd_register_workers(data);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return 0;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#ifdef THREAD_DUMP
|
|
Packit |
c22fc9 |
void
|
|
Packit |
c22fc9 |
register_bfd_scheduler_addresses(void)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
register_thread_address("bfd_sender_thread", bfd_sender_thread);
|
|
Packit |
c22fc9 |
register_thread_address("bfd_expire_thread", bfd_expire_thread);
|
|
Packit |
c22fc9 |
register_thread_address("bfd_reset_thread", bfd_reset_thread);
|
|
Packit |
c22fc9 |
register_thread_address("bfd_receiver_thread", bfd_receiver_thread);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
#endif
|