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

Reply via email to