/* Storage for a single subfacet, to reduce malloc() time and space
* overhead. (A facet always has at least one subfacet and in the common
- * case has exactly one subfacet.) */
+ * case has exactly one subfacet. However, 'one_subfacet' may not
+ * always be valid, since it could have been removed after newer
+ * subfacets were pushed onto the 'subfacets' list.) */
struct subfacet one_subfacet;
};
static void facet_learn(struct facet *);
static void facet_account(struct facet *);
+static struct subfacet *facet_get_subfacet(struct facet *);
+
static bool facet_is_controller_flow(struct facet *);
struct ofport_dpif {
facet_account(struct facet *facet)
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(facet->rule->up.ofproto);
- struct subfacet *subfacet;
+ struct subfacet *subfacet = facet_get_subfacet(facet);
const struct nlattr *a;
unsigned int left;
ovs_be16 vlan_tci;
*
* We use the actions from an arbitrary subfacet because they should all
* be equally valid for our purpose. */
- subfacet = CONTAINER_OF(list_front(&facet->subfacets),
- struct subfacet, list_node);
vlan_tci = facet->flow.vlan_tci;
NL_ATTR_FOR_EACH_UNSAFE (a, left,
subfacet->actions, subfacet->actions_len) {
return facet;
}
+/* Return a subfacet from 'facet'. A facet consists of one or more
+ * subfacets, and this function returns one of them. */
+static struct subfacet *facet_get_subfacet(struct facet *facet)
+{
+ return CONTAINER_OF(list_front(&facet->subfacets), struct subfacet,
+ list_node);
+}
+
static const char *
subfacet_path_to_string(enum subfacet_path path)
{
{
struct rule_dpif *rule = facet->rule;
struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
- struct subfacet *subfacet = CONTAINER_OF(list_front(&facet->subfacets),
- struct subfacet, list_node);
+ struct subfacet *subfacet = facet_get_subfacet(facet);
struct action_xlate_ctx ctx;
ofproto_rule_update_used(&rule->up, stats->used);
return false;
}
- if (ttl > 0) {
+ if (ttl > 1) {
ttl--;
set_mpls_lse_ttl(&ctx->flow.mpls_lse, ttl);
return false;
tunnel_ecn_ok(struct action_xlate_ctx *ctx)
{
if (is_ip_any(&ctx->base_flow)
- && (ctx->base_flow.tunnel.ip_tos & IP_ECN_MASK) == IP_ECN_CE
- && (ctx->base_flow.nw_tos & IP_ECN_MASK) == IP_ECN_NOT_ECT) {
- VLOG_WARN_RL(&rl, "dropping tunnel packet marked ECN CE but is not ECN"
- " capable");
- return false;
+ && (ctx->base_flow.tunnel.ip_tos & IP_ECN_MASK) == IP_ECN_CE) {
+ if ((ctx->base_flow.nw_tos & IP_ECN_MASK) == IP_ECN_NOT_ECT) {
+ VLOG_WARN_RL(&rl, "dropping tunnel packet marked ECN CE"
+ " but is not ECN capable");
+ return false;
+ } else {
+ /* Set the ECN CE value in the tunneled packet. */
+ ctx->flow.nw_tos |= IP_ECN_CE;
+ }
}
return true;