#include <arpa/inet.h>
+#include "byte-order.h"
#include "csum.h"
#include "dpif.h"
#include "dynamic-string.h"
*
* - Set TOS/PCP on inner BFD frame, and outer tunnel header when encapped.
*
- * - CFM "check_tnl_key" option equivalent.
- *
- * - CFM "fault override" equivalent.
- *
* - Sending BFD messages should be in its own thread/process.
*
* - Scale testing. How does it operate when there are large number of bfd
long long int last_tx; /* Last TX time. */
long long int next_tx; /* Next TX time. */
long long int detect_time; /* RFC 5880 6.8.4 Detection time. */
+
+ int ref_cnt;
+ int forwarding_override; /* Manual override of 'forwarding' status. */
+ bool check_tnl_key; /* Verify tunnel key of inbound packets? */
};
static bool bfd_in_poll(const struct bfd *);
static void bfd_put_details(struct ds *, const struct bfd *);
static void bfd_unixctl_show(struct unixctl_conn *, int argc,
const char *argv[], void *aux OVS_UNUSED);
+static void bfd_unixctl_set_forwarding_override(struct unixctl_conn *,
+ int argc, const char *argv[],
+ void *aux OVS_UNUSED);
static void log_msg(enum vlog_level, const struct msg *, const char *message,
const struct bfd *);
bool
bfd_forwarding(const struct bfd *bfd)
{
+ if (bfd->forwarding_override != -1) {
+ return bfd->forwarding_override == 1;
+ }
+
return bfd->state == STATE_UP
&& bfd->rmt_diag != DIAG_PATH_DOWN
&& bfd->rmt_diag != DIAG_CPATH_DOWN
/* Initializes, destroys, or reconfigures the BFD session 'bfd' (named 'name'),
* according to the database configuration contained in 'cfg'. Takes ownership
* of 'bfd', which may be NULL. Returns a BFD object which may be used as a
- * handle for the session, or NULL if BFD is not enabled according to 'cfg'. */
+ * handle for the session, or NULL if BFD is not enabled according to 'cfg'.
+ * Also returns NULL if cfg is NULL. */
struct bfd *
bfd_configure(struct bfd *bfd, const char *name,
const struct smap *cfg)
if (!init) {
unixctl_command_register("bfd/show", "[interface]", 0, 1,
bfd_unixctl_show, NULL);
+ unixctl_command_register("bfd/set-forwarding",
+ "[interface] normal|false|true", 1, 2,
+ bfd_unixctl_set_forwarding_override, NULL);
init = true;
}
- if (!smap_get_bool(cfg, "enable", false)) {
- if (bfd) {
- hmap_remove(&all_bfds, &bfd->node);
- free(bfd->name);
- free(bfd);
- }
+ if (!cfg || !smap_get_bool(cfg, "enable", false)) {
+ bfd_unref(bfd);
return NULL;
}
if (!bfd) {
bfd = xzalloc(sizeof *bfd);
bfd->name = xstrdup(name);
+ bfd->forwarding_override = -1;
bfd->disc = generate_discriminator();
hmap_insert(&all_bfds, &bfd->node, bfd->disc);
bfd->diag = DIAG_NONE;
bfd->min_tx = 1000;
bfd->mult = 3;
+ bfd->ref_cnt = 1;
/* RFC 5881 section 4
* The source port MUST be in the range 49152 through 65535. The same
bfd_set_state(bfd, STATE_DOWN, DIAG_NONE);
}
+ bfd->check_tnl_key = smap_get_bool(cfg, "check_tnl_key", false);
min_tx = smap_get_int(cfg, "min_tx", 100);
min_tx = MAX(min_tx, 100);
if (bfd->cfg_min_tx != min_tx) {
return bfd;
}
+struct bfd *
+bfd_ref(const struct bfd *bfd_)
+{
+ struct bfd *bfd = CONST_CAST(struct bfd *, bfd_);
+ if (bfd) {
+ ovs_assert(bfd->ref_cnt > 0);
+ bfd->ref_cnt++;
+ }
+ return bfd;
+}
+
+void
+bfd_unref(struct bfd *bfd)
+{
+ if (bfd) {
+ ovs_assert(bfd->ref_cnt > 0);
+ if (!--bfd->ref_cnt) {
+ hmap_remove(&all_bfds, &bfd->node);
+ free(bfd->name);
+ free(bfd);
+ }
+ }
+}
+
void
bfd_wait(const struct bfd *bfd)
{
}
bool
-bfd_should_process_flow(const struct flow *flow)
+bfd_should_process_flow(const struct bfd *bfd, const struct flow *flow,
+ struct flow_wildcards *wc)
{
+ memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
+ memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst);
+ if (bfd->check_tnl_key) {
+ memset(&wc->masks.tunnel.tun_id, 0xff, sizeof wc->masks.tunnel.tun_id);
+ }
return (flow->dl_type == htons(ETH_TYPE_IP)
&& flow->nw_proto == IPPROTO_UDP
- && flow->tp_dst == htons(3784));
+ && flow->tp_dst == htons(3784)
+ && (!bfd->check_tnl_key || flow->tunnel.tun_id == htonll(0)));
}
void
while (!disc) {
struct bfd *bfd;
- /* 'disc' is by defnition random, so there's no reason to waste time
+ /* 'disc' is by definition random, so there's no reason to waste time
* hashing it. */
disc = random_uint32();
HMAP_FOR_EACH_IN_BUCKET (bfd, node, disc, &all_bfds) {
unixctl_command_reply(conn, ds_cstr(&ds));
ds_destroy(&ds);
}
+
+
+static void
+bfd_unixctl_set_forwarding_override(struct unixctl_conn *conn, int argc,
+ const char *argv[], void *aux OVS_UNUSED)
+{
+ const char *forward_str = argv[argc - 1];
+ int forwarding_override;
+ struct bfd *bfd;
+
+ if (!strcasecmp("true", forward_str)) {
+ forwarding_override = 1;
+ } else if (!strcasecmp("false", forward_str)) {
+ forwarding_override = 0;
+ } else if (!strcasecmp("normal", forward_str)) {
+ forwarding_override = -1;
+ } else {
+ unixctl_command_reply_error(conn, "unknown fault string");
+ return;
+ }
+
+ if (argc > 2) {
+ bfd = bfd_find_by_name(argv[1]);
+ if (!bfd) {
+ unixctl_command_reply_error(conn, "no such BFD object");
+ return;
+ }
+ bfd->forwarding_override = forwarding_override;
+ } else {
+ HMAP_FOR_EACH (bfd, node, &all_bfds) {
+ bfd->forwarding_override = forwarding_override;
+ }
+ }
+
+ unixctl_command_reply(conn, "OK");
+}