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 <jrajaha...@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 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev