[ovs-dev] [PATCH v4 06/10] lib/ofp-actions: Set field OF 1.0/1.1 compatibility.
Jarno Rajahalme
jrajahalme at nicira.com
Thu Oct 24 20:19:30 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>
---
v4: Clear the OFPVID_PRESENT bit when translating Set-Field
OXM_OF_VLAN_VID to OpenFlow 1.0/1.1.
lib/ofp-actions.c | 211 ++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/ofp-actions.h | 1 +
tests/ovs-ofctl.at | 4 +-
3 files changed, 214 insertions(+), 2 deletions(-)
diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
index d15c824..5a95797 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -844,6 +844,208 @@ 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 onlyapplies to an existing vlan
+ * tag. Clear the OFPVID_PRESENT bit.
+ */
+ ofputil_put_OFPAT10_SET_VLAN_VID(openflow)->vlan_vid
+ = sf->value.be16 & htons(VLAN_VID_MASK);
+ 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_OF_VLAN_VID onlyapplies to an existing vlan
+ * tag. Clear the OFPVID_PRESENT bit.
+ */
+ ofputil_put_OFPAT11_SET_VLAN_VID(openflow)->vlan_vid
+ = sf->value.be16 & htons(VLAN_VID_MASK);
+ 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) {
@@ -1785,6 +1987,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 9165721..a7d5618 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