aboutsummaryrefslogtreecommitdiff
path: root/ofproto
diff options
context:
space:
mode:
authorBen Pfaff <blp@nicira.com>2011-03-18 16:56:31 -0700
committerBen Pfaff <blp@nicira.com>2011-03-18 16:56:31 -0700
commite7934396351524d390b5f1d5f1de1a6694b4144f (patch)
tree868affa31f4c59b1f68647d4bcffe28a0421453e /ofproto
parent3cf10406a77e200454bbe2c79fcd4f6c153f1a33 (diff)
ofproto: Take responsibility for connectivity fault management (CFM).
This takes one step toward the larger goal of getting rid of all of the hooks from ofproto back into vswitchd, by eliminating one of the reasons that they are required.
Diffstat (limited to 'ofproto')
-rw-r--r--ofproto/ofproto.c135
-rw-r--r--ofproto/ofproto.h11
2 files changed, 137 insertions, 9 deletions
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 580f45da..e914bbf8 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -25,6 +25,7 @@
#include <stdbool.h>
#include <stdlib.h>
#include "byte-order.h"
+#include "cfm.h"
#include "classifier.h"
#include "coverage.h"
#include "dpif.h"
@@ -100,9 +101,12 @@ struct ofport {
struct netdev *netdev;
struct ofp_phy_port opp; /* In host byte order. */
uint16_t odp_port;
+ struct cfm *cfm; /* Connectivity Fault Management, if any. */
};
static void ofport_free(struct ofport *);
+static void ofport_run(struct ofproto *, struct ofport *);
+static void ofport_wait(struct ofport *);
static void hton_ofp_phy_port(struct ofp_phy_port *);
struct action_xlate_ctx {
@@ -947,7 +951,71 @@ ofproto_set_sflow(struct ofproto *ofproto,
ofproto->sflow = NULL;
}
}
+
+/* Connectivity Fault Management configuration. */
+
+/* Clears the CFM configuration from 'port_no' on 'ofproto'. */
+void
+ofproto_iface_clear_cfm(struct ofproto *ofproto, uint32_t port_no)
+{
+ struct ofport *ofport = get_port(ofproto, port_no);
+ if (ofport && ofport->cfm){
+ cfm_destroy(ofport->cfm);
+ ofport->cfm = NULL;
+ }
+}
+/* Configures connectivity fault management on 'port_no' in 'ofproto'. Takes
+ * basic configuration from the configuration members in 'cfm', and the set of
+ * remote maintenance points from the 'n_remote_mps' elements in 'remote_mps'.
+ * Ignores the statistics members of 'cfm'.
+ *
+ * This function has no effect if 'ofproto' does not have a port 'port_no'. */
+void
+ofproto_iface_set_cfm(struct ofproto *ofproto, uint32_t port_no,
+ const struct cfm *cfm,
+ const uint16_t *remote_mps, size_t n_remote_mps)
+{
+ struct ofport *ofport;
+
+ ofport = get_port(ofproto, port_no);
+ if (!ofport) {
+ VLOG_WARN("%s: cannot configure CFM on nonexistent port %"PRIu32,
+ dpif_name(ofproto->dpif), port_no);
+ return;
+ }
+
+ if (!ofport->cfm) {
+ ofport->cfm = cfm_create();
+ }
+
+ ofport->cfm->mpid = cfm->mpid;
+ ofport->cfm->interval = cfm->interval;
+ memcpy(ofport->cfm->eth_src, cfm->eth_src, ETH_ADDR_LEN);
+ memcpy(ofport->cfm->maid, cfm->maid, CCM_MAID_LEN);
+
+ cfm_update_remote_mps(ofport->cfm, remote_mps, n_remote_mps);
+
+ if (!cfm_configure(ofport->cfm)) {
+ VLOG_WARN("%s: CFM configuration on port %"PRIu32" (%s) failed",
+ dpif_name(ofproto->dpif), port_no,
+ netdev_get_name(ofport->netdev));
+ cfm_destroy(ofport->cfm);
+ ofport->cfm = NULL;
+ }
+}
+
+/* Returns the connectivity fault management object associated with 'port_no'
+ * within 'ofproto', or a null pointer if 'ofproto' does not have a port
+ * 'port_no' or if that port does not have CFM configured. The caller must not
+ * modify or destroy the returned object. */
+const struct cfm *
+ofproto_iface_get_cfm(struct ofproto *ofproto, uint32_t port_no)
+{
+ struct ofport *ofport = get_port(ofproto, port_no);
+ return ofport ? ofport->cfm : NULL;
+}
+
uint64_t
ofproto_get_datapath_id(const struct ofproto *ofproto)
{
@@ -1110,6 +1178,7 @@ ofproto_run1(struct ofproto *p)
{
struct ofconn *ofconn, *next_ofconn;
struct ofservice *ofservice;
+ struct ofport *ofport;
char *devname;
int error;
int i;
@@ -1146,6 +1215,10 @@ ofproto_run1(struct ofproto *p)
process_port_change(p, error, devname);
}
+ HMAP_FOR_EACH (ofport, hmap_node, &p->ports) {
+ ofport_run(p, ofport);
+ }
+
if (p->in_band) {
if (time_msec() >= p->next_in_band_update) {
update_in_band_remotes(p);
@@ -1246,11 +1319,15 @@ ofproto_wait(struct ofproto *p)
{
struct ofservice *ofservice;
struct ofconn *ofconn;
+ struct ofport *ofport;
size_t i;
dpif_recv_wait(p->dpif);
dpif_port_poll_wait(p->dpif);
netdev_monitor_poll_wait(p->netdev_monitor);
+ HMAP_FOR_EACH (ofport, hmap_node, &p->ports) {
+ ofport_wait(ofport);
+ }
LIST_FOR_EACH (ofconn, node, &p->all_conns) {
ofconn_wait(ofconn);
}
@@ -1649,9 +1726,30 @@ ofport_remove(struct ofproto *p, struct ofport *ofport)
}
static void
+ofport_run(struct ofproto *ofproto, struct ofport *ofport)
+{
+ if (ofport->cfm) {
+ struct ofpbuf *packet = cfm_run(ofport->cfm);
+ if (packet) {
+ ofproto_send_packet(ofproto, ofport->odp_port, 0, packet);
+ ofpbuf_delete(packet);
+ }
+ }
+}
+
+static void
+ofport_wait(struct ofport *ofport)
+{
+ if (ofport->cfm) {
+ cfm_wait(ofport->cfm);
+ }
+}
+
+static void
ofport_free(struct ofport *ofport)
{
if (ofport) {
+ cfm_destroy(ofport->cfm);
netdev_close(ofport->netdev);
free(ofport);
}
@@ -3081,6 +3179,18 @@ action_xlate_ctx_init(struct action_xlate_ctx *ctx,
ctx->check_special = true;
}
+static void
+ofproto_process_cfm(struct ofproto *ofproto, const struct flow *flow,
+ const struct ofpbuf *packet)
+{
+ struct ofport *ofport;
+
+ ofport = get_port(ofproto, flow->in_port);
+ if (ofport && ofport->cfm) {
+ cfm_process_heartbeat(ofport->cfm, packet);
+ }
+}
+
static struct ofpbuf *
xlate_actions(struct action_xlate_ctx *ctx,
const union ofp_action *in, size_t n_in)
@@ -3094,13 +3204,18 @@ xlate_actions(struct action_xlate_ctx *ctx,
ctx->recurse = 0;
ctx->last_pop_priority = -1;
- if (!ctx->check_special
- || !ctx->ofproto->ofhooks->special_cb
- || ctx->ofproto->ofhooks->special_cb(&ctx->flow, ctx->packet,
- ctx->ofproto->aux)) {
- do_xlate_actions(in, n_in, ctx);
- } else {
+ if (ctx->check_special && cfm_should_process_flow(&ctx->flow)) {
+ if (ctx->packet) {
+ ofproto_process_cfm(ctx->ofproto, &ctx->flow, ctx->packet);
+ }
ctx->may_set_up_flow = false;
+ } else if (ctx->check_special
+ && ctx->ofproto->ofhooks->special_cb
+ && !ctx->ofproto->ofhooks->special_cb(&ctx->flow, ctx->packet,
+ ctx->ofproto->aux)) {
+ ctx->may_set_up_flow = false;
+ } else {
+ do_xlate_actions(in, n_in, ctx);
}
remove_pop_action(ctx);
@@ -4375,8 +4490,12 @@ handle_miss_upcall(struct ofproto *p, struct dpif_upcall *upcall)
/* Set header pointers in 'flow'. */
flow_extract(upcall->packet, flow.tun_id, flow.in_port, &flow);
- if (p->ofhooks->special_cb
- && !p->ofhooks->special_cb(&flow, upcall->packet, p->aux)) {
+ if (cfm_should_process_flow(&flow)) {
+ ofproto_process_cfm(p, &flow, upcall->packet);
+ ofpbuf_delete(upcall->packet);
+ return;
+ } else if (p->ofhooks->special_cb
+ && !p->ofhooks->special_cb(&flow, upcall->packet, p->aux)) {
ofpbuf_delete(upcall->packet);
return;
}
diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h
index 4baf99fe..b049fe1a 100644
--- a/ofproto/ofproto.h
+++ b/ofproto/ofproto.h
@@ -105,7 +105,7 @@ bool ofproto_is_alive(const struct ofproto *);
int ofproto_port_del(struct ofproto *, uint16_t odp_port);
bool ofproto_port_is_floodable(struct ofproto *, uint16_t odp_port);
-/* Configuration. */
+/* Top-level configuration. */
void ofproto_set_datapath_id(struct ofproto *, uint64_t datapath_id);
void ofproto_set_controllers(struct ofproto *,
const struct ofproto_controller *, size_t n);
@@ -123,6 +123,15 @@ int ofproto_set_netflow(struct ofproto *,
const struct netflow_options *nf_options);
void ofproto_set_sflow(struct ofproto *, const struct ofproto_sflow_options *);
+/* Configuration of individual interfaces. */
+struct cfm;
+
+void ofproto_iface_clear_cfm(struct ofproto *, uint32_t port_no);
+void ofproto_iface_set_cfm(struct ofproto *, uint32_t port_no,
+ const struct cfm *,
+ const uint16_t *remote_mps, size_t n_remote_mps);
+const struct cfm *ofproto_iface_get_cfm(struct ofproto *, uint32_t port_no);
+
/* Configuration querying. */
uint64_t ofproto_get_datapath_id(const struct ofproto *);
bool ofproto_has_primary_controller(const struct ofproto *);