[ovs-dev] [PATCH v3 07/11] lib/ofp-actions: Set field OF 1.0/1.1 compatibility.

Jarno Rajahalme jrajahalme at nicira.com
Wed Oct 23 19:53:02 UTC 2013


Output set field actions as standard OF1.0/1.1 set actions or to
reg_load instructions, when a compatible set action(s) do not exist.

Signed-off-by: Jarno Rajahalme <jrajahalme at nicira.com>
---
 lib/ofp-actions.c  |  209 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/ofp-actions.h  |    1 +
 tests/ovs-ofctl.at |    4 +-
 3 files changed, 212 insertions(+), 2 deletions(-)

diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
index 2cb1d54..f97ed09 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -832,6 +832,206 @@ set_field_to_openflow(const struct ofpact_set_field *sf,
 
     mf = mf_from_id(sf->field);
 
+    /* Check if can convert to standard actions.
+     * We check only meta-flow types that can appear within set field actions
+     * and that have a mapping to compatible action types.
+     * These struct mf_field definitions have a defined OXM or NXM header
+     * value and specify the field as writeable.
+     * If an action with compatible semantics does not exist, we translate
+     * to NXM reg_load action in the hope that it would be useful for the
+     * other end.
+     */
+    if (oh->version == OFP10_VERSION) {
+        switch ((int)mf->id) {
+
+        case MFF_VLAN_TCI:
+            /* NXM_OF_VLAN_TCI to OpenFlow 1.0 mapping:
+             *
+             * If CFI=1, Add or modify VLAN VID & PCP.
+             * If CFI=0, strip VLAN header, if any.
+             */
+            if (sf->value.be16 & htons(VLAN_CFI)) {
+                ofputil_put_OFPAT10_SET_VLAN_VID(openflow)->vlan_vid
+                    = sf->value.be16 & htons(VLAN_VID_MASK);
+                ofputil_put_OFPAT10_SET_VLAN_PCP(openflow)->vlan_pcp
+                    = vlan_tci_to_pcp(sf->value.be16);
+            } else {
+                ofputil_put_OFPAT10_STRIP_VLAN(openflow);
+            }
+            return;
+
+        case MFF_VLAN_VID:
+            /* OXM VLAN_VID to OpenFlow 1.0.
+             * Set field on OXM_OF_VLAN_VID only has 12 VID bits and only
+             * applies to existing vlan tag. */
+            ofputil_put_OFPAT10_SET_VLAN_VID(openflow)->vlan_vid
+                = sf->value.be16;
+            return;
+
+        case MFF_VLAN_PCP:
+            /* OXM VLAN_PCP to OpenFlow 1.0.
+             * OXM_OF_VLAN_PCP only applies to existing vlan tag. */
+            ofputil_put_OFPAT10_SET_VLAN_PCP(openflow)->vlan_pcp
+                = sf->value.u8;
+            return;
+
+        case MFF_ETH_SRC:
+            memcpy(ofputil_put_OFPAT10_SET_DL_SRC(openflow)->dl_addr,
+                   sf->value.mac, ETH_ADDR_LEN);
+            return;
+
+        case MFF_ETH_DST:
+            memcpy(ofputil_put_OFPAT10_SET_DL_DST(openflow)->dl_addr,
+                   sf->value.mac, ETH_ADDR_LEN);
+            return;
+
+        case MFF_IPV4_SRC:
+            ofputil_put_OFPAT10_SET_NW_SRC(openflow)->nw_addr
+                = sf->value.be32;
+            return;
+
+        case MFF_IPV4_DST:
+            ofputil_put_OFPAT10_SET_NW_DST(openflow)->nw_addr
+                = sf->value.be32;
+            return;
+
+        case MFF_IP_DSCP:
+            ofputil_put_OFPAT10_SET_NW_TOS(openflow)->nw_tos
+                = sf->value.u8;
+            return;
+
+        case MFF_IP_DSCP_SHIFTED:
+            ofputil_put_OFPAT10_SET_NW_TOS(openflow)->nw_tos
+                = sf->value.u8 << 2;
+            return;
+
+        case MFF_TCP_SRC:
+        case MFF_UDP_SRC:
+            ofputil_put_OFPAT10_SET_TP_SRC(openflow)->tp_port
+                = sf->value.be16;
+            return;
+
+        case MFF_TCP_DST:
+        case MFF_UDP_DST:
+            ofputil_put_OFPAT10_SET_TP_DST(openflow)->tp_port
+                = sf->value.be16;
+            return;
+        }
+    } else { /* OpenFlow 1.1 */
+        switch ((int)mf->id) {
+
+        case MFF_VLAN_TCI:
+            /* NXM_OF_VLAN_TCI to OpenFlow 1.1 mapping:
+             *
+             * If CFI=1, Add or modify VLAN VID & PCP.
+             *    OpenFlow 1.1 set actions only apply if the packet
+             *    already has VLAN tags.  To be sure that is the case
+             *    we have to push a VLAN header.  As we do not support
+             *    multiple layers of VLANs, this is a no-op, if a VLAN
+             *    header already exists.  This may backfire, however,
+             *    when we start supporting multiple layers of VLANs.
+             * If CFI=0, strip VLAN header, if any.
+             */
+            if (sf->value.be16 & htons(VLAN_CFI)) {
+                /* Push a VLAN tag, if one was not seen at action validation
+                 * time. */
+                if (!sf->flow_has_vlan) {
+                    ofputil_put_OFPAT11_PUSH_VLAN(openflow)->ethertype
+                        = htons(ETH_TYPE_VLAN_8021Q);
+                }
+                ofputil_put_OFPAT11_SET_VLAN_VID(openflow)->vlan_vid
+                    = sf->value.be16 & htons(VLAN_VID_MASK);
+                ofputil_put_OFPAT11_SET_VLAN_PCP(openflow)->vlan_pcp
+                    = vlan_tci_to_pcp(sf->value.be16);
+            } else {
+                /* If the flow did not match on vlan, we have no way of
+                 * knowing if the vlan tag exists, so we must POP just to be
+                 * sure. */
+                ofputil_put_OFPAT11_POP_VLAN(openflow);
+            }
+            return;
+
+        case MFF_VLAN_VID:
+            /* OXM VLAN_PCP to OpenFlow 1.1.
+             * Set field on OXM_VLAN_VID only has 12 VID bits and only
+             * applies to existing vlan tag. */
+            ofputil_put_OFPAT11_SET_VLAN_VID(openflow)->vlan_vid
+                = sf->value.be16;
+            return;
+
+        case MFF_VLAN_PCP:
+            /* OXM VLAN_PCP to OpenFlow 1.1.
+             * OXM_OF_VLAN_PCP only applies to existing vlan tag. */
+            ofputil_put_OFPAT11_SET_VLAN_PCP(openflow)->vlan_pcp
+                = sf->value.u8;
+            return;
+
+        case MFF_ETH_SRC:
+            memcpy(ofputil_put_OFPAT11_SET_DL_SRC(openflow)->dl_addr,
+                   sf->value.mac, ETH_ADDR_LEN);
+            return;
+
+        case MFF_ETH_DST:
+            memcpy(ofputil_put_OFPAT11_SET_DL_DST(openflow)->dl_addr,
+                   sf->value.mac, ETH_ADDR_LEN);
+            return;
+
+        case MFF_MPLS_LABEL:
+            /* ofputil_put_OFPAT11_SET_MPLS_LABEL(openflow)->label =
+               sf->value.be32; */
+            break;
+
+        case MFF_MPLS_TC:
+            /* ofputil_put_OFPAT11_SET_MPLS_TC(openflow)->tc =
+               sf->value.u8; */
+            break;
+
+        case MFF_IPV4_SRC:
+            ofputil_put_OFPAT11_SET_NW_SRC(openflow)->nw_addr
+                = sf->value.be32;
+            return;
+
+        case MFF_IPV4_DST:
+            ofputil_put_OFPAT11_SET_NW_DST(openflow)->nw_addr
+                = sf->value.be32;
+            return;
+
+        case MFF_IP_DSCP:
+            ofputil_put_OFPAT11_SET_NW_TOS(openflow)->nw_tos
+                = sf->value.u8;
+            return;
+
+        case MFF_IP_DSCP_SHIFTED:
+            ofputil_put_OFPAT11_SET_NW_TOS(openflow)->nw_tos
+                = sf->value.u8 << 2;
+            return;
+
+        case MFF_IP_ECN:
+            ofputil_put_OFPAT11_SET_NW_ECN(openflow)->nw_ecn
+                = sf->value.u8;
+            return;
+
+        case MFF_IP_TTL:
+            ofputil_put_OFPAT11_SET_NW_TTL(openflow)->nw_ttl
+                = sf->value.u8;
+            return;
+
+        case MFF_TCP_SRC:
+        case MFF_UDP_SRC:
+        case MFF_SCTP_SRC:
+            ofputil_put_OFPAT11_SET_TP_SRC(openflow)->tp_port
+                = sf->value.be16;
+            return;
+
+        case MFF_TCP_DST:
+        case MFF_UDP_DST:
+        case MFF_SCTP_DST:
+            ofputil_put_OFPAT11_SET_TP_DST(openflow)->tp_port
+                = sf->value.be16;
+            return;
+        }
+    }
+
     /* Convert to one or two REG_LOADs */
 
     if (mf->n_bits > 64) {
@@ -1771,6 +1971,15 @@ ofpact_check__(struct ofpact *a, struct flow *flow, ofp_port_t max_ports,
                          mf->name);
             return OFPERR_OFPBAC_MATCH_INCONSISTENT;
         }
+        /* Remember if we saw a vlan tag in the flow to aid translating to
+         * OpenFlow 1.1 if need be. */
+        ofpact_get_SET_FIELD(a)->flow_has_vlan =
+            (flow->vlan_tci & htons(VLAN_CFI)) == htons(VLAN_CFI);
+        if (mf->id == MFF_VLAN_TCI) {
+            /* The set field may add or remove the vlan tag,
+             * Mark the status temporarily. */
+            flow->vlan_tci = ofpact_get_SET_FIELD(a)->value.be16;
+        }
         return 0;
 
     case OFPACT_STACK_PUSH:
diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h
index 1809db0..9234558 100644
--- a/lib/ofp-actions.h
+++ b/lib/ofp-actions.h
@@ -379,6 +379,7 @@ enum ofpact_mpls_position {
 struct ofpact_set_field {
     struct ofpact ofpact;
     enum mf_field_id field;
+    bool flow_has_vlan;   /* VLAN present at action validation time. */
     union mf_value value; /* Most-significant bits are used. */
 };
 
diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at
index 6f0456f..b62afec 100644
--- a/tests/ovs-ofctl.at
+++ b/tests/ovs-ofctl.at
@@ -131,7 +131,7 @@ OFPT_FLOW_MOD: ADD tcp,nw_src=192.168.0.3,tp_dst=80 actions=set_queue:37,output:
 OFPT_FLOW_MOD: ADD udp,nw_src=192.168.0.3,tp_dst=53 actions=pop_queue,output:1
 OFPT_FLOW_MOD: ADD priority=60000 cookie:0x123456789abcdef hard:10 actions=CONTROLLER:65535
 OFPT_FLOW_MOD: ADD actions=note:41.42.43.00.00.00,note:00.01.02.03.04.05.06.07.00.00.00.00.00.00,note:00.00.00.00.00.00
-OFPT_FLOW_MOD: ADD ip actions=load:0xa04034d->NXM_OF_IP_SRC[]
+OFPT_FLOW_MOD: ADD ip actions=mod_nw_src:10.4.3.77
 OFPT_FLOW_MOD: ADD sctp actions=drop
 OFPT_FLOW_MOD: ADD sctp actions=drop
 OFPT_FLOW_MOD: ADD in_port=0 actions=resubmit:0
@@ -168,7 +168,7 @@ OFPT_FLOW_MOD (OF1.1): ADD table:255 tcp,nw_src=192.168.0.3,tp_dst=80 actions=se
 OFPT_FLOW_MOD (OF1.1): ADD table:255 udp,nw_src=192.168.0.3,tp_dst=53 actions=mod_nw_ecn:2,output:1
 OFPT_FLOW_MOD (OF1.1): ADD table:255 priority=60000 cookie:0x123456789abcdef hard:10 actions=CONTROLLER:65535
 OFPT_FLOW_MOD (OF1.1): ADD table:255 actions=note:41.42.43.00.00.00,note:00.01.02.03.04.05.06.07.00.00.00.00.00.00,note:00.00.00.00.00.00
-OFPT_FLOW_MOD (OF1.1): ADD table:255 ip actions=mod_nw_ttl:1,load:0xa04034d->NXM_OF_IP_SRC[]
+OFPT_FLOW_MOD (OF1.1): ADD table:255 ip actions=mod_nw_ttl:1,mod_nw_src:10.4.3.77
 OFPT_FLOW_MOD (OF1.1): ADD table:255 sctp actions=drop
 OFPT_FLOW_MOD (OF1.1): ADD table:255 sctp actions=drop
 OFPT_FLOW_MOD (OF1.1): ADD table:255 in_port=0 actions=resubmit:0
-- 
1.7.10.4




More information about the dev mailing list