This implementes push_vlan with 802.1Q. NOTE: 802.1AD (QinQ) is not supported. It requires another effort.
Signed-off-by: Isaku Yamahata <yamah...@valinux.co.jp> --- lib/ofp-actions.c | 25 +++++++++++++++++++++++++ lib/ofp-actions.h | 9 +++++++++ lib/ofp-parse.c | 13 +++++++++++++ lib/ofp-util.def | 2 +- lib/packets.h | 7 ++++++- ofproto/ofproto-dpif.c | 5 +++++ tests/ofp-actions.at | 3 +++ 7 files changed, 62 insertions(+), 2 deletions(-) diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c index c6ba131..ed22db9 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -714,6 +714,11 @@ ofpact_from_openflow11(const union ofp_action *a, struct ofpbuf *out) ofpact_put_SET_VLAN_PCP(out)->vlan_pcp = a->vlan_pcp.vlan_pcp; break; + case OFPUTIL_OFPAT11_PUSH_VLAN: + ofpact_put_PUSH_VLAN(out)->ethertype = + ((const struct ofp11_action_push *)a)->ethertype; + break; + case OFPUTIL_OFPAT11_POP_VLAN: ofpact_put_STRIP_VLAN(out); break; @@ -1062,6 +1067,13 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports) case OFPACT_BUNDLE: return bundle_check(ofpact_get_BUNDLE(a), max_ports, flow); + case OFPACT_PUSH_VLAN: + if (ofpact_get_PUSH_VLAN(a)->ethertype != htons(ETH_TYPE_VLAN_8021Q)) { + /* TODO:XXX 802.1AD(QinQ) isn't supported at the moment */ + return OFPERR_OFPET_BAD_ACTION; + } + return 0; + case OFPACT_SET_VLAN_VID: case OFPACT_SET_VLAN_PCP: case OFPACT_STRIP_VLAN: @@ -1358,6 +1370,7 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out) case OFPACT_SET_VLAN_VID: case OFPACT_SET_VLAN_PCP: case OFPACT_STRIP_VLAN: + case OFPACT_PUSH_VLAN: case OFPACT_SET_ETH_SRC: case OFPACT_SET_ETH_DST: case OFPACT_SET_IPV4_SRC: @@ -1456,6 +1469,7 @@ ofpact_to_openflow10(const struct ofpact *a, struct ofpbuf *out) = htons(ofpact_get_SET_L4_DST_PORT(a)->port); break; + case OFPACT_PUSH_VLAN: case OFPACT_CLEAR_ACTIONS: case OFPACT_GOTO_TABLE: /* TODO:XXX */ @@ -1548,6 +1562,11 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out) ofputil_put_OFPAT11_POP_VLAN(out); break; + case OFPACT_PUSH_VLAN: + ofputil_put_OFPAT11_PUSH_VLAN(out)->ethertype = + ofpact_get_PUSH_VLAN(a)->ethertype; + break; + case OFPACT_SET_ETH_SRC: memcpy(ofputil_put_OFPAT11_SET_DL_SRC(out)->dl_addr, ofpact_get_SET_ETH_SRC(a)->mac, ETH_ADDR_LEN); @@ -1711,6 +1730,7 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, uint16_t port) case OFPACT_SET_VLAN_VID: case OFPACT_SET_VLAN_PCP: case OFPACT_STRIP_VLAN: + case OFPACT_PUSH_VLAN: case OFPACT_SET_ETH_SRC: case OFPACT_SET_ETH_DST: case OFPACT_SET_IPV4_SRC: @@ -1894,6 +1914,11 @@ ofpact_format(const struct ofpact *a, struct ds *s) ds_put_cstr(s, "strip_vlan"); break; + case OFPACT_PUSH_VLAN: + ds_put_format(s, "push_vlan:%#"PRIx16, + ntohs(ofpact_get_PUSH_VLAN(a)->ethertype)); + break; + case OFPACT_SET_ETH_SRC: ds_put_format(s, "mod_dl_src:"ETH_ADDR_FMT, ETH_ADDR_ARGS(ofpact_get_SET_ETH_SRC(a)->mac)); diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h index 410103e..26ce791 100644 --- a/lib/ofp-actions.h +++ b/lib/ofp-actions.h @@ -60,6 +60,7 @@ DEFINE_OFPACT(SET_VLAN_VID, ofpact_vlan_vid, ofpact) \ DEFINE_OFPACT(SET_VLAN_PCP, ofpact_vlan_pcp, ofpact) \ DEFINE_OFPACT(STRIP_VLAN, ofpact_null, ofpact) \ + DEFINE_OFPACT(PUSH_VLAN, ofpact_push, ofpact) \ DEFINE_OFPACT(SET_ETH_SRC, ofpact_mac, ofpact) \ DEFINE_OFPACT(SET_ETH_DST, ofpact_mac, ofpact) \ DEFINE_OFPACT(SET_IPV4_SRC, ofpact_ipv4, ofpact) \ @@ -309,6 +310,14 @@ struct ofpact_reg_load { union mf_subvalue subvalue; /* Least-significant bits are used. */ }; +/* OFPACT_PUSH_VLAN/MPLS/PBB + * + * used for NXAST_PUSH_MPLS, OFPAT13_PUSH_VLAN/MPLS/PBB */ +struct ofpact_push { + struct ofpact ofpact; + ovs_be16 ethertype; +}; + /* OFPACT_SET_TUNNEL. * * Used for NXAST_SET_TUNNEL, NXAST_SET_TUNNEL64. */ diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index 33065aa..fce3c51 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -384,6 +384,7 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow, { struct ofpact_tunnel *tunnel; uint16_t vid; + uint16_t ethertype; ovs_be32 ip; uint8_t pcp; uint8_t tos; @@ -424,6 +425,18 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow, ofpact_put_STRIP_VLAN(ofpacts); break; + case OFPUTIL_OFPAT11_PUSH_VLAN: + ethertype = str_to_u16(arg, "ethertype"); + if (ethertype != ETH_TYPE_VLAN_8021Q && + ethertype != ETH_TYPE_VLAN_8021AD && + ethertype != ETH_TYPE_VLAN_QINQ1 && + ethertype != ETH_TYPE_VLAN_QINQ2 && + ethertype != ETH_TYPE_VLAN_QINQ3) { + ovs_fatal(0, "%s: not a valid VLAN ethertype", arg); + } + ofpact_put_PUSH_VLAN(ofpacts)->ethertype = htons(ethertype); + break; + case OFPUTIL_OFPAT10_SET_DL_SRC: case OFPUTIL_OFPAT11_SET_DL_SRC: str_to_mac(arg, ofpact_put_SET_ETH_SRC(ofpacts)->mac); diff --git a/lib/ofp-util.def b/lib/ofp-util.def index 0b867c2..39575ba 100644 --- a/lib/ofp-util.def +++ b/lib/ofp-util.def @@ -30,7 +30,7 @@ OFPAT11_ACTION(OFPAT11_SET_NW_TOS, ofp_action_nw_tos, 0, "mod_nw_tos") //OFPAT11_ACTION(OFPAT11_SET_NW_ECN, ofp11_action_nw_ecn, "0, mod_nw_ecn") OFPAT11_ACTION(OFPAT11_SET_TP_SRC, ofp_action_tp_port, 0, "mod_tp_src") OFPAT11_ACTION(OFPAT11_SET_TP_DST, ofp_action_tp_port, 0, "mod_tp_dst") -//OFPAT11_ACTION(OFPAT11_PUSH_VLAN, ofp11_action_push, 0, "push_vlan") +OFPAT11_ACTION(OFPAT11_PUSH_VLAN, ofp11_action_push, 0, "push_vlan") OFPAT11_ACTION(OFPAT11_POP_VLAN, ofp_action_header, 0, "pop_vlan") //OFPAT11_ACTION(OFPAT11_SET_QUEUE, ofp11_action_set_queue, 0, "set_queue") //OFPAT11_ACTION(OFPAT11_SET_NW_TTL, ofp11_action_nw_ttl, 0, "set_nw_ttl") diff --git a/lib/packets.h b/lib/packets.h index 24b51da..960af20 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -177,12 +177,17 @@ void eth_addr_bitand(const uint8_t src[ETH_ADDR_LEN], #define ETH_TYPE_IP 0x0800 #define ETH_TYPE_ARP 0x0806 -#define ETH_TYPE_VLAN 0x8100 +#define ETH_TYPE_VLAN_8021Q 0x8100 +#define ETH_TYPE_VLAN ETH_TYPE_VLAN_8021Q +#define ETH_TYPE_VLAN_8021AD 0x88a8 #define ETH_TYPE_IPV6 0x86dd #define ETH_TYPE_LACP 0x8809 #define ETH_TYPE_RARP 0x8035 #define ETH_TYPE_MPLS 0x8847 #define ETH_TYPE_MPLS_MCAST 0x8848 +#define ETH_TYPE_VLAN_QINQ1 0x9100 +#define ETH_TYPE_VLAN_QINQ2 0x9200 +#define ETH_TYPE_VLAN_QINQ3 0x9300 /* Minimum value for an Ethernet type. Values below this are IEEE 802.2 frame * lengths. */ diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index c800386..fea4dac 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -5500,6 +5500,11 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, ctx->flow.vlan_tci = htons(0); break; + case OFPACT_PUSH_VLAN: + /* TODO:XXX 802.1AD(QinQ) */ + ctx->flow.vlan_tci = htons(VLAN_CFI); + break; + case OFPACT_SET_ETH_SRC: memcpy(ctx->flow.dl_src, ofpact_get_SET_ETH_SRC(a)->mac, ETH_ADDR_LEN); diff --git a/tests/ofp-actions.at b/tests/ofp-actions.at index 4875844..0785130 100644 --- a/tests/ofp-actions.at +++ b/tests/ofp-actions.at @@ -169,6 +169,9 @@ AT_DATA([test-data], [dnl # actions=strip_vlan 0012 0008 00000000 +# actions=push_vlan:0x8100 +0011 0008 8100 0000 + # actions=resubmit:5 ffff 0010 00002320 0001 0005 00000000 -- 1.7.10.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev