-/* Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include "ofp-actions.h"
#include "ofproto/ofproto-dpif-ipfix.h"
#include "ofproto/ofproto-dpif-mirror.h"
+#include "ofproto/ofproto-dpif-monitor.h"
#include "ofproto/ofproto-dpif-sflow.h"
#include "ofproto/ofproto-dpif.h"
#include "ofproto/ofproto-provider.h"
enum ofp_config_flags frag; /* Fragmentation handling. */
bool has_in_band; /* Bridge has in band control? */
bool forward_bpdu; /* Bridge forwards STP BPDUs? */
+
+ /* True if the datapath supports variable-length
+ * OVS_USERSPACE_ATTR_USERDATA in OVS_ACTION_ATTR_USERSPACE actions.
+ * False if the datapath supports only 8-byte (or shorter) userdata. */
+ bool variable_length_userdata;
};
struct xbundle {
const struct dpif_sflow *sflow,
const struct dpif_ipfix *ipfix,
const struct netflow *netflow, enum ofp_config_flags frag,
- bool forward_bpdu, bool has_in_band)
+ bool forward_bpdu, bool has_in_band,
+ bool variable_length_userdata)
{
struct xbridge *xbridge = xbridge_lookup(ofproto);
xbridge->frag = frag;
xbridge->miss_rule = miss_rule;
xbridge->no_packet_in_rule = no_packet_in_rule;
+ xbridge->variable_length_userdata = variable_length_userdata;
}
void
/* Make the packet resemble the flow, so that it gets sent to
* an OpenFlow controller properly, so that it looks correct
* for sFlow, and so that flow_extract() will get the correct
- * vlan_tci if it is called on 'packet'.
- *
- * The allocated space inside 'packet' probably also contains
- * 'key', that is, both 'packet' and 'key' are probably part of
- * a struct dpif_upcall (see the large comment on that
- * structure definition), so pushing data on 'packet' is in
- * general not a good idea since it could overwrite 'key' or
- * free it as a side effect. However, it's OK in this special
- * case because we know that 'packet' is inside a Netlink
- * attribute: pushing 4 bytes will just overwrite the 4-byte
- * "struct nlattr", which is fine since we don't need that
- * header anymore. */
+ * vlan_tci if it is called on 'packet'. */
eth_push_vlan(packet, flow->vlan_tci);
}
/* We can't reproduce 'key' from 'flow'. */
bool has_mirror;
int out_vlan;
- has_mirror = mirror_get(xbridge->mbridge, mirror_mask_ffs(mirrors) - 1,
+ has_mirror = mirror_get(xbridge->mbridge, raw_ctz(mirrors),
&vlans, &dup_mirrors, &out, &out_vlan);
ovs_assert(has_mirror);
return vid ? vid : in_xbundle->vlan;
default:
- NOT_REACHED();
+ OVS_NOT_REACHED();
}
}
return true;
default:
- NOT_REACHED();
+ OVS_NOT_REACHED();
}
}
return vlan == out_xbundle->vlan ? 0 : vlan;
default:
- NOT_REACHED();
+ OVS_NOT_REACHED();
}
}
} else if (xport->bfd && bfd_should_process_flow(xport->bfd, flow, wc)) {
if (packet) {
bfd_process_packet(xport->bfd, flow, packet);
+ /* If POLL received, immediately sends FINAL back. */
+ if (bfd_should_send_packet(xport->bfd)) {
+ if (xport->peer) {
+ ofproto_dpif_monitor_port_send_soon(xport->ofport);
+ } else {
+ ofproto_dpif_monitor_port_send_soon_safe(xport->ofport);
+ }
+ }
}
return SLOW_BFD;
} else if (xport->xbundle && xport->xbundle->lacp
ofp_port_t in_port, uint8_t table_id, bool may_packet_in)
{
if (xlate_resubmit_resource_check(ctx)) {
- struct rule_dpif *rule;
ofp_port_t old_in_port = ctx->xin->flow.in_port.ofp_port;
+ bool skip_wildcards = ctx->xin->skip_wildcards;
uint8_t old_table_id = ctx->table_id;
+ struct rule_dpif *rule;
ctx->table_id = table_id;
* original input port (otherwise OFPP_NORMAL and OFPP_IN_PORT will
* have surprising behavior). */
ctx->xin->flow.in_port.ofp_port = in_port;
- rule_dpif_lookup_in_table(ctx->xbridge->ofproto,
- &ctx->xin->flow, &ctx->xout->wc,
+ rule_dpif_lookup_in_table(ctx->xbridge->ofproto, &ctx->xin->flow,
+ !skip_wildcards ? &ctx->xout->wc : NULL,
table_id, &rule);
ctx->xin->flow.in_port.ofp_port = old_in_port;
xlate_ff_group(ctx, group);
break;
default:
- NOT_REACHED();
+ OVS_NOT_REACHED();
}
group_dpif_release(group);
}
{
struct ofproto_packet_in *pin;
struct ofpbuf *packet;
- struct flow key;
+ struct pkt_metadata md = PKT_METADATA_INITIALIZER(0);
ctx->xout->slow |= SLOW_CONTROLLER;
if (!ctx->xin->packet) {
packet = ofpbuf_clone(ctx->xin->packet);
- key.skb_priority = 0;
- key.pkt_mark = 0;
- memset(&key.tunnel, 0, sizeof key.tunnel);
-
ctx->xout->slow |= commit_odp_actions(&ctx->xin->flow, &ctx->base_flow,
&ctx->xout->odp_actions,
&ctx->xout->wc,
&ctx->mpls_depth_delta);
- odp_execute_actions(NULL, packet, &key, ctx->xout->odp_actions.data,
- ctx->xout->odp_actions.size, NULL, NULL);
+ odp_execute_actions(NULL, packet, &md, ctx->xout->odp_actions.data,
+ ctx->xout->odp_actions.size, NULL);
pin = xmalloc(sizeof *pin);
pin->up.packet_len = packet->size;
* the same percentage. */
uint32_t probability = (os->probability << 16) | os->probability;
+ if (!ctx->xbridge->variable_length_userdata) {
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
+
+ VLOG_ERR_RL(&rl, "ignoring NXAST_SAMPLE action because datapath "
+ "lacks support (needs Linux 3.10+ or kernel module from "
+ "OVS 1.11+)");
+ return;
+ }
+
ctx->xout->slow |= commit_odp_actions(&ctx->xin->flow, &ctx->base_flow,
&ctx->xout->odp_actions,
&ctx->xout->wc,
* applicable header fields. Do nothing if no header exists. */
if ((mf->id != MFF_VLAN_VID || flow->vlan_tci & htons(VLAN_CFI))
&& ((mf->id != MFF_MPLS_LABEL && mf->id != MFF_MPLS_TC)
- || flow->mpls_lse)) {
+ || eth_type_mpls(flow->dl_type))) {
mf_set_flow_value(mf, &set_field->value, flow);
}
break;
xin->resubmit_hook = NULL;
xin->report_hook = NULL;
xin->resubmit_stats = NULL;
+ xin->skip_wildcards = false;
}
void
/* Thread safe call to xlate_actions__(). */
void
xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
+ OVS_EXCLUDED(xlate_rwlock)
{
ovs_rwlock_rdlock(&xlate_rwlock);
xlate_actions__(xin, xout);
memset(&wc->masks.in_port, 0xff, sizeof wc->masks.in_port);
memset(&wc->masks.skb_priority, 0xff, sizeof wc->masks.skb_priority);
memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type);
- wc->masks.nw_frag |= FLOW_NW_FRAG_MASK;
+ if (is_ip_any(flow)) {
+ wc->masks.nw_frag |= FLOW_NW_FRAG_MASK;
+ }
tnl_may_send = tnl_xlate_init(&ctx.base_flow, flow, wc);
if (ctx.xbridge->netflow) {
ctx.mpls_depth_delta = 0;
if (!xin->ofpacts && !ctx.rule) {
- rule_dpif_lookup(ctx.xbridge->ofproto, flow, wc, &rule);
+ rule_dpif_lookup(ctx.xbridge->ofproto, flow,
+ !xin->skip_wildcards ? wc : NULL, &rule);
if (ctx.xin->resubmit_stats) {
rule_dpif_credit_stats(rule, ctx.xin->resubmit_stats);
}
ofpacts = actions->ofpacts;
ofpacts_len = actions->ofpacts_len;
} else {
- NOT_REACHED();
+ OVS_NOT_REACHED();
}
ofpbuf_use_stub(&ctx.stack, ctx.init_stack, sizeof ctx.init_stack);
goto out;
case OFPC_FRAG_REASM:
- NOT_REACHED();
+ OVS_NOT_REACHED();
case OFPC_FRAG_NX_MATCH:
/* Nothing to do. */
break;
case OFPC_INVALID_TTL_TO_CONTROLLER:
- NOT_REACHED();
+ OVS_NOT_REACHED();
}
}
struct ofpact_output output;
struct flow flow;
union flow_in_port in_port_;
- int error;
ofpact_init(&output.ofpact, OFPACT_OUTPUT, sizeof output);
/* Use OFPP_NONE as the in_port to avoid special packet processing. */
}
output.port = xport->ofp_port;
output.max_len = 0;
- error = ofproto_dpif_execute_actions(xport->xbridge->ofproto, &flow, NULL,
- &output.ofpact, sizeof output,
- packet);
ovs_rwlock_unlock(&xlate_rwlock);
- return error;
+
+ return ofproto_dpif_execute_actions(xport->xbridge->ofproto, &flow, NULL,
+ &output.ofpact, sizeof output,
+ packet);
}