#include <netinet/ip.h>
#include "byte-order.h"
+#include "connectivity.h"
#include "csum.h"
#include "dpif.h"
#include "dynamic-string.h"
#include "packets.h"
#include "poll-loop.h"
#include "random.h"
+#include "seq.h"
#include "smap.h"
#include "timeval.h"
#include "unaligned.h"
uint8_t eth_dst[ETH_ADDR_LEN];/* Ethernet destination address. */
bool eth_dst_set; /* 'eth_dst' set through database. */
+ ovs_be32 ip_src; /* IPv4 source address. */
+ ovs_be32 ip_dst; /* IPv4 destination address. */
+
uint16_t udp_src; /* UDP source port. */
/* All timers in milliseconds. */
int forwarding_override; /* Manual override of 'forwarding' status. */
atomic_bool check_tnl_key; /* Verify tunnel key of inbound packets? */
- atomic_int ref_cnt;
+ struct ovs_refcount ref_cnt;
/* When forward_if_rx is true, bfd_forwarding() will return
* true as long as there are incoming packets received.
static struct hmap all_bfds__ = HMAP_INITIALIZER(&all_bfds__);
static struct hmap *const all_bfds OVS_GUARDED_BY(mutex) = &all_bfds__;
+static bool bfd_lookup_ip(const char *host_name, struct in_addr *)
+ OVS_REQUIRES(mutex);
static bool bfd_forwarding__(struct bfd *) OVS_REQUIRES(mutex);
static bool bfd_in_poll(const struct bfd *) OVS_REQUIRES(mutex);
static void bfd_poll(struct bfd *bfd) OVS_REQUIRES(mutex);
bool need_poll = false;
bool cfg_min_rx_changed = false;
bool cpath_down, forwarding_if_rx;
- const char *hwaddr;
+ const char *hwaddr, *ip_src, *ip_dst;
+ struct in_addr in_addr;
uint8_t ea[ETH_ADDR_LEN];
if (ovsthread_once_start(&once)) {
bfd->diag = DIAG_NONE;
bfd->min_tx = 1000;
bfd->mult = 3;
- atomic_init(&bfd->ref_cnt, 1);
+ ovs_refcount_init(&bfd->ref_cnt);
bfd->netdev = netdev_ref(netdev);
bfd->rx_packets = bfd_rx_packets(bfd);
bfd->in_decay = false;
cpath_down = smap_get_bool(cfg, "cpath_down", false);
if (bfd->cpath_down != cpath_down) {
bfd->cpath_down = cpath_down;
- if (bfd->diag == DIAG_NONE || bfd->diag == DIAG_CPATH_DOWN) {
- bfd_set_state(bfd, bfd->state, DIAG_NONE);
- }
+ bfd_set_state(bfd, bfd->state, DIAG_NONE);
need_poll = true;
}
bfd->eth_dst_set = false;
}
+ ip_src = smap_get(cfg, "bfd_src_ip");
+ if (ip_src && bfd_lookup_ip(ip_src, &in_addr)) {
+ memcpy(&bfd->ip_src, &in_addr, sizeof in_addr);
+ } else {
+ bfd->ip_src = htonl(0xA9FE0100); /* 169.254.1.0. */
+ }
+
+ ip_dst = smap_get(cfg, "bfd_dst_ip");
+ if (ip_dst && bfd_lookup_ip(ip_dst, &in_addr)) {
+ memcpy(&bfd->ip_dst, &in_addr, sizeof in_addr);
+ } else {
+ bfd->ip_dst = htonl(0xA9FE0101); /* 169.254.1.1. */
+ }
+
forwarding_if_rx = smap_get_bool(cfg, "forwarding_if_rx", false);
if (bfd->forwarding_if_rx != forwarding_if_rx) {
bfd->forwarding_if_rx = forwarding_if_rx;
{
struct bfd *bfd = CONST_CAST(struct bfd *, bfd_);
if (bfd) {
- int orig;
- atomic_add(&bfd->ref_cnt, 1, &orig);
- ovs_assert(orig > 0);
+ ovs_refcount_ref(&bfd->ref_cnt);
}
return bfd;
}
void
bfd_unref(struct bfd *bfd) OVS_EXCLUDED(mutex)
{
- if (bfd) {
- int orig;
-
- atomic_sub(&bfd->ref_cnt, 1, &orig);
- ovs_assert(orig > 0);
- if (orig == 1) {
- ovs_mutex_lock(&mutex);
- hmap_remove(all_bfds, &bfd->node);
- netdev_close(bfd->netdev);
- free(bfd->name);
- free(bfd);
- ovs_mutex_unlock(&mutex);
- }
+ if (bfd && ovs_refcount_unref(&bfd->ref_cnt) == 1) {
+ ovs_mutex_lock(&mutex);
+ hmap_remove(all_bfds, &bfd->node);
+ netdev_close(bfd->netdev);
+ ovs_refcount_destroy(&bfd->ref_cnt);
+ free(bfd->name);
+ free(bfd);
+ ovs_mutex_unlock(&mutex);
}
}
if (bfd->state > STATE_DOWN && now >= bfd->detect_time) {
bfd_set_state(bfd, STATE_DOWN, DIAG_EXPIRED);
- bfd_forwarding__(bfd);
}
+ bfd_forwarding__(bfd);
/* Decay may only happen when state is STATE_UP, bfd->decay_min_rx is
* configured, and decay_detect_time is reached. */
ip->ip_ttl = MAXTTL;
ip->ip_tos = IPTOS_LOWDELAY | IPTOS_THROUGHPUT;
ip->ip_proto = IPPROTO_UDP;
- /* Use link local addresses: */
- put_16aligned_be32(&ip->ip_src, htonl(0xA9FE0100)); /* 169.254.1.0. */
- put_16aligned_be32(&ip->ip_dst, htonl(0xA9FE0101)); /* 169.254.1.1. */
+ put_16aligned_be32(&ip->ip_src, bfd->ip_src);
+ put_16aligned_be32(&ip->ip_dst, bfd->ip_dst);
ip->ip_csum = csum(ip, sizeof *ip);
udp = ofpbuf_put_zeros(p, sizeof *udp);
goto out;
}
+ if (bfd->rmt_state != rmt_state) {
+ seq_change(connectivity_seq_get());
+ }
+
bfd->rmt_disc = ntohl(msg->my_disc);
bfd->rmt_state = rmt_state;
bfd->rmt_flags = flags;
rmt_min_rx = MAX(ntohl(msg->min_rx) / 1000, 1);
if (bfd->rmt_min_rx != rmt_min_rx) {
bfd->rmt_min_rx = rmt_min_rx;
- bfd_set_next_tx(bfd);
+ if (bfd->next_tx) {
+ bfd_set_next_tx(bfd);
+ }
log_msg(VLL_INFO, msg, "New remote min_rx", bfd);
}
break;
case STATE_ADMIN_DOWN:
default:
- NOT_REACHED();
+ OVS_NOT_REACHED();
}
}
/* XXX: RFC 5880 Section 6.8.6 Demand mode related calculations here. */
&& bfd->rmt_diag != DIAG_RCPATH_DOWN;
if (bfd->last_forwarding != last_forwarding) {
bfd->flap_count++;
+ seq_change(connectivity_seq_get());
}
return bfd->last_forwarding;
}
/* Helpers. */
+static bool
+bfd_lookup_ip(const char *host_name, struct in_addr *addr)
+{
+ if (!inet_aton(host_name, addr)) {
+ VLOG_ERR_RL(&rl, "\"%s\" is not a valid IP address", host_name);
+ return false;
+ }
+ return true;
+}
+
static bool
bfd_in_poll(const struct bfd *bfd) OVS_REQUIRES(mutex)
{
bfd_set_state(struct bfd *bfd, enum state state, enum diag diag)
OVS_REQUIRES(mutex)
{
- if (diag == DIAG_NONE && bfd->cpath_down) {
+ if (bfd->cpath_down) {
diag = DIAG_CPATH_DOWN;
}
if (bfd->state == STATE_UP && bfd->decay_min_rx) {
bfd_decay_update(bfd);
}
+
+ seq_change(connectivity_seq_get());
}
}