#include <stdbool.h>
#include <stdlib.h>
#include "byte-order.h"
+#include "cfm.h"
#include "classifier.h"
#include "coverage.h"
#include "dpif.h"
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 {
ofproto->sflow = NULL;
}
}
+\f
+/* 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->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;
+}
+\f
uint64_t
ofproto_get_datapath_id(const struct ofproto *ofproto)
{
{
struct ofconn *ofconn, *next_ofconn;
struct ofservice *ofservice;
+ struct ofport *ofport;
char *devname;
int error;
int i;
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);
{
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);
}
}
}
+static void
+ofport_run(struct ofproto *ofproto, struct ofport *ofport)
+{
+ if (ofport->cfm) {
+ cfm_run(ofport->cfm);
+
+ if (cfm_should_send_ccm(ofport->cfm)) {
+ struct ofpbuf packet;
+ struct ccm *ccm;
+
+ ofpbuf_init(&packet, 0);
+ ccm = compose_packet(&packet, eth_addr_ccm, ofport->opp.hw_addr,
+ ETH_TYPE_CFM, sizeof *ccm);
+ cfm_compose_ccm(ofport->cfm, ccm);
+ ofproto_send_packet(ofproto, ofport->odp_port, 0, &packet);
+ ofpbuf_uninit(&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);
}
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)
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);
/* 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;
}
goto exit;
}
- tun_id = htonll(strtoull(tun_id_s, NULL, 10));
+ tun_id = htonll(strtoull(tun_id_s, NULL, 0));
in_port = ofp_port_to_odp_port(atoi(in_port_s));
packet_s = ofpbuf_put_hex(&packet, packet_s, NULL);
uint16_t *nf_output_iface, void *ofproto_)
{
struct ofproto *ofproto = ofproto_;
- int out_port;
+ struct mac_entry *dst_mac;
/* Drop frames for reserved multicast addresses. */
if (eth_addr_is_reserved(flow->dl_dst)) {
}
/* Learn source MAC (but don't try to learn from revalidation). */
- if (packet != NULL) {
- tag_type rev_tag = mac_learning_learn(ofproto->ml, flow->dl_src,
- 0, flow->in_port,
- GRAT_ARP_LOCK_NONE);
- if (rev_tag) {
+ if (packet != NULL
+ && mac_learning_may_learn(ofproto->ml, flow->dl_src, 0)) {
+ struct mac_entry *src_mac;
+
+ src_mac = mac_learning_insert(ofproto->ml, flow->dl_src, 0);
+ if (mac_entry_is_new(src_mac) || src_mac->port.i != flow->in_port) {
/* The log messages here could actually be useful in debugging,
* so keep the rate limit relatively high. */
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 300);
VLOG_DBG_RL(&rl, "learned that "ETH_ADDR_FMT" is on port %"PRIu16,
ETH_ADDR_ARGS(flow->dl_src), flow->in_port);
- ofproto_revalidate(ofproto, rev_tag);
+
+ ofproto_revalidate(ofproto,
+ mac_learning_changed(ofproto->ml, src_mac));
+ src_mac->port.i = flow->in_port;
}
}
/* Determine output port. */
- out_port = mac_learning_lookup_tag(ofproto->ml, flow->dl_dst, 0, tags,
- NULL);
- if (out_port < 0) {
+ dst_mac = mac_learning_lookup(ofproto->ml, flow->dl_dst, 0, tags);
+ if (!dst_mac) {
flood_packets(ofproto, flow->in_port, OFPPC_NO_FLOOD,
nf_output_iface, odp_actions);
- } else if (out_port != flow->in_port) {
- nl_msg_put_u32(odp_actions, ODP_ACTION_ATTR_OUTPUT, out_port);
- *nf_output_iface = out_port;
} else {
- /* Drop. */
+ int out_port = dst_mac->port.i;
+ if (out_port != flow->in_port) {
+ nl_msg_put_u32(odp_actions, ODP_ACTION_ATTR_OUTPUT, out_port);
+ *nf_output_iface = out_port;
+ } else {
+ /* Drop. */
+ }
}
return true;