#include <errno.h>
+#include "bfd.h"
#include "bond.h"
#include "bundle.h"
#include "byte-order.h"
struct ofbundle *bundle; /* Bundle that contains this port, if any. */
struct list bundle_node; /* In struct ofbundle's "ports" list. */
struct cfm *cfm; /* Connectivity Fault Management, if any. */
+ struct bfd *bfd; /* BFD, if any. */
tag_type tag; /* Tag associated with this port. */
bool may_enable; /* May be enabled in bonds. */
long long int carrier_seq; /* Carrier status changes. */
ofproto->backer->need_revalidate = REV_RECONFIGURE;
port->bundle = NULL;
port->cfm = NULL;
+ port->bfd = NULL;
port->tag = tag_create_random();
port->may_enable = true;
port->stp_port = NULL;
port->carrier_seq = netdev_get_carrier_resets(netdev);
if (netdev_vport_is_patch(netdev)) {
- /* XXX By bailing out here, we don't do required sFlow work. */
+ /* By bailing out here, we don't submit the port to the sFlow module
+ * to be considered for counter polling export. This is correct
+ * because the patch port represents an interface that sFlow considers
+ * to be "internal" to the switch as a whole, and therefore not an
+ * candidate for counter polling. */
port->odp_port = OVSP_NONE;
return 0;
}
return false;
}
}
+
+static int
+set_bfd(struct ofport *ofport_, const struct smap *cfg)
+{
+ struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofport_->ofproto);
+ struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
+ struct bfd *old;
+
+ old = ofport->bfd;
+ ofport->bfd = bfd_configure(old, netdev_get_name(ofport->up.netdev), cfg);
+ if (ofport->bfd != old) {
+ ofproto->backer->need_revalidate = REV_RECONFIGURE;
+ }
+
+ return 0;
+}
+
+static int
+get_bfd_status(struct ofport *ofport_, struct smap *smap)
+{
+ struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
+
+ if (ofport->bfd) {
+ bfd_get_status(ofport->bfd, smap);
+ return 0;
+ } else {
+ return ENOENT;
+ }
+}
\f
/* Spanning Tree. */
send_packet(ofport, &packet);
ofpbuf_uninit(&packet);
}
+
+ if (ofport->bfd && bfd_should_send_packet(ofport->bfd)) {
+ struct ofpbuf packet;
+
+ ofpbuf_init(&packet, 0);
+ bfd_put_packet(ofport->bfd, &packet, ofport->up.pp.hw_addr);
+ send_packet(ofport, &packet);
+ ofpbuf_uninit(&packet);
+ }
}
static void
}
}
+ if (ofport->bfd) {
+ bfd_run(ofport->bfd);
+ enable = enable && bfd_forwarding(ofport->bfd);
+ }
+
if (ofport->bundle) {
enable = enable && lacp_slave_may_enable(ofport->bundle->lacp, ofport);
if (carrier_changed) {
if (ofport->cfm) {
cfm_wait(ofport->cfm);
}
+
+ if (ofport->bfd) {
+ bfd_wait(ofport->bfd);
+ }
}
static int
cfm_process_heartbeat(ofport->cfm, packet);
}
return SLOW_CFM;
+ } else if (ofport->bfd && bfd_should_process_flow(flow)) {
+ if (packet) {
+ bfd_process_packet(ofport->bfd, flow, packet);
+ }
+ return SLOW_BFD;
} else if (ofport->bundle && ofport->bundle->lacp
&& flow->dl_type == htons(ETH_TYPE_LACP)) {
if (packet) {
&ofproto->subfacets) {
long long int cutoff;
- cutoff = (subfacet->slow & (SLOW_CFM | SLOW_LACP | SLOW_STP)
+ cutoff = (subfacet->slow & (SLOW_CFM | SLOW_BFD | SLOW_LACP | SLOW_STP)
? special_cutoff
: normal_cutoff);
if (subfacet->used < cutoff) {
cookie.slow_path.reason = slow;
ofpbuf_use_stack(&buf, stub, stub_size);
- if (slow & (SLOW_CFM | SLOW_LACP | SLOW_STP)) {
+ if (slow & (SLOW_CFM | SLOW_BFD | SLOW_LACP | SLOW_STP)) {
uint32_t pid = dpif_port_get_pid(ofproto->backer->dpif, UINT32_MAX);
odp_put_userspace_action(pid, &cookie, sizeof cookie.slow_path, &buf);
} else {
}
cookie = ofpbuf_at(ctx->odp_actions, ctx->user_cookie_offset,
- sizeof(*cookie));
+ sizeof cookie->sflow);
ovs_assert(cookie->type == USER_ACTION_COOKIE_SFLOW);
compose_sflow_cookie(ctx->ofproto, base->vlan_tci,
case SLOW_STP:
ds_put_cstr(ds, "\n\t- Consists of STP packets.");
break;
+ case SLOW_BFD:
+ ds_put_cstr(ds, "\n\t- Consists of BFD packets.");
+ break;
case SLOW_IN_BAND:
ds_put_cstr(ds, "\n\t- Needs in-band special case "
"processing.");
set_ipfix,
set_cfm,
get_cfm_status,
+ set_bfd,
+ get_bfd_status,
set_stp,
get_stp_status,
set_stp_port,