2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-31 06:15:47 +00:00

OF 1.1 set vlan vid/pcp compatibility.

OpenFlow 1.1 set vlan actions only modify existing vlan
headers, while OF 1.0 actions push a new vlan header if one
does not exist already.

Signed-off-by: Jarno Rajahalme <jrajahalme@nicira.com>
Signed-off-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
Jarno Rajahalme
2013-10-24 13:19:25 -07:00
committed by Ben Pfaff
parent 255842d953
commit ca287d2062
7 changed files with 127 additions and 28 deletions

View File

@@ -501,6 +501,8 @@ ofpact_from_openflow10(const union ofp_action *a, struct ofpbuf *out)
{
enum ofputil_action_code code;
enum ofperr error;
struct ofpact_vlan_vid *vlan_vid;
struct ofpact_vlan_pcp *vlan_pcp;
error = decode_openflow10_action(a, &code);
if (error) {
@@ -520,14 +522,20 @@ ofpact_from_openflow10(const union ofp_action *a, struct ofpbuf *out)
if (a->vlan_vid.vlan_vid & ~htons(0xfff)) {
return OFPERR_OFPBAC_BAD_ARGUMENT;
}
ofpact_put_SET_VLAN_VID(out)->vlan_vid = ntohs(a->vlan_vid.vlan_vid);
vlan_vid = ofpact_put_SET_VLAN_VID(out);
vlan_vid->vlan_vid = ntohs(a->vlan_vid.vlan_vid);
vlan_vid->push_vlan_if_needed = true;
vlan_vid->ofpact.compat = code;
break;
case OFPUTIL_OFPAT10_SET_VLAN_PCP:
if (a->vlan_pcp.vlan_pcp & ~7) {
return OFPERR_OFPBAC_BAD_ARGUMENT;
}
ofpact_put_SET_VLAN_PCP(out)->vlan_pcp = a->vlan_pcp.vlan_pcp;
vlan_pcp = ofpact_put_SET_VLAN_PCP(out);
vlan_pcp->vlan_pcp = a->vlan_pcp.vlan_pcp;
vlan_pcp->push_vlan_if_needed = true;
vlan_pcp->ofpact.compat = code;
break;
case OFPUTIL_OFPAT10_STRIP_VLAN:
@@ -774,6 +782,8 @@ ofpact_from_openflow11(const union ofp_action *a, struct ofpbuf *out)
{
enum ofputil_action_code code;
enum ofperr error;
struct ofpact_vlan_vid *vlan_vid;
struct ofpact_vlan_pcp *vlan_pcp;
error = decode_openflow11_action(a, &code);
if (error) {
@@ -793,14 +803,20 @@ ofpact_from_openflow11(const union ofp_action *a, struct ofpbuf *out)
if (a->vlan_vid.vlan_vid & ~htons(0xfff)) {
return OFPERR_OFPBAC_BAD_ARGUMENT;
}
ofpact_put_SET_VLAN_VID(out)->vlan_vid = ntohs(a->vlan_vid.vlan_vid);
vlan_vid = ofpact_put_SET_VLAN_VID(out);
vlan_vid->vlan_vid = ntohs(a->vlan_vid.vlan_vid);
vlan_vid->push_vlan_if_needed = false;
vlan_vid->ofpact.compat = code;
break;
case OFPUTIL_OFPAT11_SET_VLAN_PCP:
if (a->vlan_pcp.vlan_pcp & ~7) {
return OFPERR_OFPBAC_BAD_ARGUMENT;
}
ofpact_put_SET_VLAN_PCP(out)->vlan_pcp = a->vlan_pcp.vlan_pcp;
vlan_pcp = ofpact_put_SET_VLAN_PCP(out);
vlan_pcp->vlan_pcp = a->vlan_pcp.vlan_pcp;
vlan_pcp->push_vlan_if_needed = false;
vlan_pcp->ofpact.compat = code;
break;
case OFPUTIL_OFPAT11_PUSH_VLAN:
@@ -1538,9 +1554,12 @@ exit:
return error;
}
/* May modify flow->dl_type, caller must restore it. */
/* May modify flow->dl_type and flow->vlan_tci, caller must restore them.
*
* Modifies some actions, filling in fields that could not be properly set
* without context. */
static enum ofperr
ofpact_check__(const struct ofpact *a, struct flow *flow, ofp_port_t max_ports,
ofpact_check__(struct ofpact *a, struct flow *flow, ofp_port_t max_ports,
uint8_t table_id, bool enforce_consistency)
{
const struct ofpact_enqueue *enqueue;
@@ -1569,13 +1588,37 @@ ofpact_check__(const struct ofpact *a, struct flow *flow, ofp_port_t max_ports,
return bundle_check(ofpact_get_BUNDLE(a), max_ports, flow);
case OFPACT_SET_VLAN_VID:
/* Remember if we saw a vlan tag in the flow to aid translating to
* OpenFlow 1.1+ if need be. */
ofpact_get_SET_VLAN_VID(a)->flow_has_vlan =
(flow->vlan_tci & htons(VLAN_CFI)) == htons(VLAN_CFI);
if (!(flow->vlan_tci & htons(VLAN_CFI)) &&
!ofpact_get_SET_VLAN_VID(a)->push_vlan_if_needed) {
goto inconsistent;
}
/* Temporary mark that we have a vlan tag. */
flow->vlan_tci |= htons(VLAN_CFI);
return 0;
case OFPACT_SET_VLAN_PCP:
/* Remember if we saw a vlan tag in the flow to aid translating to
* OpenFlow 1.1+ if need be. */
ofpact_get_SET_VLAN_PCP(a)->flow_has_vlan =
(flow->vlan_tci & htons(VLAN_CFI)) == htons(VLAN_CFI);
if (!(flow->vlan_tci & htons(VLAN_CFI)) &&
!ofpact_get_SET_VLAN_PCP(a)->push_vlan_if_needed) {
goto inconsistent;
}
/* Temporary mark that we have a vlan tag. */
flow->vlan_tci |= htons(VLAN_CFI);
return 0;
case OFPACT_STRIP_VLAN:
if (!(flow->vlan_tci & htons(VLAN_CFI))) {
goto inconsistent;
}
/* Temporary mark that we have no vlan tag. */
flow->vlan_tci = htons(0);
return 0;
case OFPACT_PUSH_VLAN:
@@ -1583,6 +1626,8 @@ ofpact_check__(const struct ofpact *a, struct flow *flow, ofp_port_t max_ports,
/* Multiple VLAN headers not supported. */
return OFPERR_OFPBAC_BAD_TAG;
}
/* Temporary mark that we have a vlan tag. */
flow->vlan_tci |= htons(VLAN_CFI);
return 0;
case OFPACT_SET_ETH_SRC:
@@ -1713,14 +1758,17 @@ ofpact_check__(const struct ofpact *a, struct flow *flow, ofp_port_t max_ports,
* appropriate for a packet with the prerequisites satisfied by 'flow' in a
* switch with no more than 'max_ports' ports.
*
* May annotate ofpacts with information gathered from the 'flow'.
*
* May temporarily modify 'flow', but restores the changes before returning. */
enum ofperr
ofpacts_check(const struct ofpact ofpacts[], size_t ofpacts_len,
ofpacts_check(struct ofpact ofpacts[], size_t ofpacts_len,
struct flow *flow, ofp_port_t max_ports, uint8_t table_id,
bool enforce_consistency)
{
const struct ofpact *a;
struct ofpact *a;
ovs_be16 dl_type = flow->dl_type;
ovs_be16 vlan_tci = flow->vlan_tci;
enum ofperr error = 0;
OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
@@ -1730,7 +1778,9 @@ ofpacts_check(const struct ofpact ofpacts[], size_t ofpacts_len,
break;
}
}
flow->dl_type = dl_type; /* Restore. */
/* Restore fields that may have been modified. */
flow->dl_type = dl_type;
flow->vlan_tci = vlan_tci;
return error;
}
@@ -2114,6 +2164,10 @@ ofpact_to_openflow10(const struct ofpact *a, struct ofpbuf *out)
break;
case OFPACT_PUSH_VLAN:
/* PUSH is a side effect of a SET_VLAN_VID/PCP, which should
* follow this action. */
break;
case OFPACT_CLEAR_ACTIONS:
case OFPACT_WRITE_ACTIONS:
case OFPACT_GOTO_TABLE:
@@ -2206,11 +2260,23 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out)
break;
case OFPACT_SET_VLAN_VID:
/* Push a VLAN tag, if one was not seen at action validation time. */
if (!ofpact_get_SET_VLAN_VID(a)->flow_has_vlan
&& ofpact_get_SET_VLAN_VID(a)->push_vlan_if_needed) {
ofputil_put_OFPAT11_PUSH_VLAN(out)->ethertype
= htons(ETH_TYPE_VLAN_8021Q);
}
ofputil_put_OFPAT11_SET_VLAN_VID(out)->vlan_vid
= htons(ofpact_get_SET_VLAN_VID(a)->vlan_vid);
break;
case OFPACT_SET_VLAN_PCP:
/* Push a VLAN tag, if one was not seen at action validation time. */
if (!ofpact_get_SET_VLAN_PCP(a)->flow_has_vlan
&& ofpact_get_SET_VLAN_PCP(a)->push_vlan_if_needed) {
ofputil_put_OFPAT11_PUSH_VLAN(out)->ethertype
= htons(ETH_TYPE_VLAN_8021Q);
}
ofputil_put_OFPAT11_SET_VLAN_PCP(out)->vlan_pcp
= ofpact_get_SET_VLAN_PCP(a)->vlan_pcp;
break;
@@ -2690,12 +2756,18 @@ ofpact_format(const struct ofpact *a, struct ds *s)
break;
case OFPACT_SET_VLAN_VID:
ds_put_format(s, "mod_vlan_vid:%"PRIu16,
ds_put_format(s, "%s:%"PRIu16,
(a->compat == OFPUTIL_OFPAT11_SET_VLAN_VID
? "set_vlan_vid"
: "mod_vlan_vid"),
ofpact_get_SET_VLAN_VID(a)->vlan_vid);
break;
case OFPACT_SET_VLAN_PCP:
ds_put_format(s, "mod_vlan_pcp:%"PRIu8,
ds_put_format(s, "%s:%"PRIu8,
(a->compat == OFPUTIL_OFPAT11_SET_VLAN_PCP
? "set_vlan_pcp"
: "mod_vlan_pcp"),
ofpact_get_SET_VLAN_PCP(a)->vlan_pcp);
break;