adding EthType to secure handling ether types

this will also pretty print ethertypes in flow output

Change-Id: I9363070ad308f3c756735e29b3992c500e503636
diff --git a/apps/reactive-routing/src/main/java/org/onosproject/reactive/routing/SdnIpReactiveRouting.java b/apps/reactive-routing/src/main/java/org/onosproject/reactive/routing/SdnIpReactiveRouting.java
index 46f7fd9..c75fd3b 100644
--- a/apps/reactive-routing/src/main/java/org/onosproject/reactive/routing/SdnIpReactiveRouting.java
+++ b/apps/reactive-routing/src/main/java/org/onosproject/reactive/routing/SdnIpReactiveRouting.java
@@ -114,7 +114,7 @@
             ConnectPoint srcConnectPoint = pkt.receivedFrom();
 
             switch (ethPkt.getEtherType()) {
-            case Ethernet.TYPE_ARP:
+            case 0x806:
                 ARP arpPacket = (ARP) ethPkt.getPayload();
                 Ip4Address targetIpAddress = Ip4Address
                         .valueOf(arpPacket.getTargetProtocolAddress());
@@ -141,7 +141,7 @@
                             ByteBuffer.wrap(eth.serialize())));
                 }
                 break;
-            case Ethernet.TYPE_IPV4:
+            case 0x800:
                 // Parse packet
                 IPv4 ipv4Packet = (IPv4) ethPkt.getPayload();
                 IpAddress dstIp =
diff --git a/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java b/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java
index a163cea..f285496 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java
@@ -15,6 +15,7 @@
  */
 package org.onosproject.net.flow.criteria;
 
+import org.onlab.packet.EthType;
 import org.onosproject.net.IndexedLambda;
 import org.onosproject.net.Lambda;
 import org.onosproject.net.OchSignal;
@@ -101,6 +102,16 @@
     }
 
     /**
+     * Creates a match on ETH_TYPE field using the specified value.
+     *
+     * @param ethType eth type value
+     * @return match criterion
+     */
+    public static Criterion matchEthType(EthType ethType) {
+        return new EthTypeCriterion(ethType);
+    }
+
+    /**
      * Creates a match on VLAN ID field using the specified value.
      *
      * @param vlanId vlan id value
diff --git a/core/api/src/main/java/org/onosproject/net/flow/criteria/EthTypeCriterion.java b/core/api/src/main/java/org/onosproject/net/flow/criteria/EthTypeCriterion.java
index a42d8d3..465de6b 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/criteria/EthTypeCriterion.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/criteria/EthTypeCriterion.java
@@ -15,6 +15,8 @@
  */
 package org.onosproject.net.flow.criteria;
 
+import org.onlab.packet.EthType;
+
 import java.util.Objects;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
@@ -24,7 +26,7 @@
  */
 public final class EthTypeCriterion implements Criterion {
     private static final int MASK = 0xffff;
-    private final int ethType;              // Ethernet type value: 16 bits
+    private final EthType ethType;              // Ethernet type value: 16 bits
 
     /**
      * Constructor.
@@ -33,7 +35,16 @@
      * integer)
      */
     EthTypeCriterion(int ethType) {
-        this.ethType = ethType & MASK;
+        this.ethType = new EthType(ethType & MASK);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param ethType the Ethernet frame type to match
+     */
+    EthTypeCriterion(EthType ethType) {
+        this.ethType = ethType;
     }
 
     @Override
@@ -46,14 +57,14 @@
      *
      * @return the Ethernet frame type to match (16 bits unsigned integer)
      */
-    public int ethType() {
+    public EthType ethType() {
         return ethType;
     }
 
     @Override
     public String toString() {
         return toStringHelper(type().toString())
-                .add("ethType", Long.toHexString(ethType))
+                .add("ethType", ethType.toString())
                 .toString();
     }
 
diff --git a/core/api/src/test/java/org/onosproject/net/flow/criteria/CriteriaTest.java b/core/api/src/test/java/org/onosproject/net/flow/criteria/CriteriaTest.java
index bad60a0..4733cb9 100644
--- a/core/api/src/test/java/org/onosproject/net/flow/criteria/CriteriaTest.java
+++ b/core/api/src/test/java/org/onosproject/net/flow/criteria/CriteriaTest.java
@@ -16,6 +16,7 @@
 package org.onosproject.net.flow.criteria;
 
 import org.junit.Test;
+import org.onlab.packet.EthType;
 import org.onosproject.net.ChannelSpacing;
 import org.onosproject.net.GridType;
 import org.onosproject.net.Lambda;
@@ -418,8 +419,8 @@
      */
     @Test
     public void testMatchEthTypeMethod() {
-        int ethType = 12;
-        Criterion matchEthType = Criteria.matchEthType(ethType);
+        EthType ethType = new EthType(12);
+        Criterion matchEthType = Criteria.matchEthType(new EthType(12));
         EthTypeCriterion ethTypeCriterion =
                 checkAndConvert(matchEthType,
                                 Criterion.Type.ETH_TYPE,
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodec.java b/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodec.java
index 0ca344d..04cdb4f 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodec.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodec.java
@@ -165,7 +165,7 @@
         public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) {
             final EthTypeCriterion ethTypeCriterion =
                     (EthTypeCriterion) criterion;
-            return root.put(CriterionCodec.ETH_TYPE, ethTypeCriterion.ethType());
+            return root.put(CriterionCodec.ETH_TYPE, ethTypeCriterion.ethType().toShort());
         }
     }
 
diff --git a/core/common/src/test/java/org/onosproject/codec/impl/CriterionJsonMatcher.java b/core/common/src/test/java/org/onosproject/codec/impl/CriterionJsonMatcher.java
index 2bc611c..2a4c138 100644
--- a/core/common/src/test/java/org/onosproject/codec/impl/CriterionJsonMatcher.java
+++ b/core/common/src/test/java/org/onosproject/codec/impl/CriterionJsonMatcher.java
@@ -134,7 +134,7 @@
      * @return true if the JSON matches the criterion, false otherwise.
      */
     private boolean matchCriterion(EthTypeCriterion criterion) {
-        final int ethType = criterion.ethType();
+        final int ethType = criterion.ethType().toShort();
         final int jsonEthType = jsonCriterion.get("ethType").intValue();
         if (ethType != jsonEthType) {
             description.appendText("ethType was "
diff --git a/core/common/src/test/java/org/onosproject/codec/impl/FlowRuleCodecTest.java b/core/common/src/test/java/org/onosproject/codec/impl/FlowRuleCodecTest.java
index 2e0e8b3..2a93b55 100644
--- a/core/common/src/test/java/org/onosproject/codec/impl/FlowRuleCodecTest.java
+++ b/core/common/src/test/java/org/onosproject/codec/impl/FlowRuleCodecTest.java
@@ -22,6 +22,7 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.onlab.packet.EthType;
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
@@ -148,7 +149,7 @@
         assertThat(rule.selector().criteria().size(), is(1));
         Criterion criterion1 = rule.selector().criteria().iterator().next();
         assertThat(criterion1.type(), is(Criterion.Type.ETH_TYPE));
-        assertThat(((EthTypeCriterion) criterion1).ethType(), is(2054));
+        assertThat(((EthTypeCriterion) criterion1).ethType(), is(new EthType(2054)));
 
         assertThat(rule.treatment().allInstructions().size(), is(1));
         Instruction instruction1 = rule.treatment().allInstructions().get(0);
@@ -356,7 +357,7 @@
         Criterion criterion;
 
         criterion = getCriterion(Criterion.Type.ETH_TYPE);
-        assertThat(((EthTypeCriterion) criterion).ethType(), is(2054));
+        assertThat(((EthTypeCriterion) criterion).ethType(), is(new EthType(2054)));
 
         criterion = getCriterion(Criterion.Type.ETH_DST);
         assertThat(((EthCriterion) criterion).mac(),
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompiler.java
index f9e445a..c133483 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompiler.java
@@ -243,7 +243,7 @@
             Criterion c = intent.selector().getCriterion(Criterion.Type.ETH_TYPE);
             if (c != null && c instanceof EthTypeCriterion) {
                 EthTypeCriterion ethertype = (EthTypeCriterion) c;
-                treat.popMpls((short) ethertype.ethType());
+                treat.popMpls(ethertype.ethType().toShort());
             } else {
                 treat.popMpls(Ethernet.TYPE_IPV4);
             }
diff --git a/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java b/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
index f930f8c..3c14cb0 100644
--- a/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
+++ b/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
@@ -20,6 +20,7 @@
 import com.google.common.collect.ImmutableSet;
 
 import org.onlab.packet.ChassisId;
+import org.onlab.packet.EthType;
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.Ip4Prefix;
 import org.onlab.packet.Ip6Address;
@@ -293,6 +294,7 @@
                     PortCriterion.class,
                     MetadataCriterion.class,
                     EthCriterion.class,
+                    EthType.class,
                     EthTypeCriterion.class,
                     VlanIdCriterion.class,
                     VlanPcpCriterion.class,
diff --git a/drivers/src/main/java/org/onosproject/driver/pipeline/CentecV350Pipeline.java b/drivers/src/main/java/org/onosproject/driver/pipeline/CentecV350Pipeline.java
index a7be6a1..ae5b621 100644
--- a/drivers/src/main/java/org/onosproject/driver/pipeline/CentecV350Pipeline.java
+++ b/drivers/src/main/java/org/onosproject/driver/pipeline/CentecV350Pipeline.java
@@ -295,7 +295,7 @@
         TrafficSelector selector = fwd.selector();
         EthTypeCriterion ethType =
                 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
-        if (ethType == null || ethType.ethType() != Ethernet.TYPE_IPV4) {
+        if (ethType == null || ethType.ethType().toShort() != Ethernet.TYPE_IPV4) {
             fail(fwd, ObjectiveError.UNSUPPORTED);
             return Collections.emptySet();
         }
diff --git a/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA1Pipeline.java b/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA1Pipeline.java
index 2f5d548..54f8df5 100644
--- a/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA1Pipeline.java
+++ b/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA1Pipeline.java
@@ -510,7 +510,7 @@
             fail(fwd, ObjectiveError.UNKNOWN);
             return Collections.emptySet();
         }
-        if (ethType.ethType() == Ethernet.TYPE_ARP) {
+        if (ethType.ethType().toShort() == Ethernet.TYPE_ARP) {
             log.warn("Installing ARP rule to table 60");
 
             // currently need to punt from ACL table should use:
@@ -551,7 +551,7 @@
         EthTypeCriterion ethType =
                 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
         // XXX currently supporting only the L3 unicast table
-        if (ethType == null || ethType.ethType() != Ethernet.TYPE_IPV4) {
+        if (ethType == null || ethType.ethType().toShort() != Ethernet.TYPE_IPV4) {
             fail(fwd, ObjectiveError.UNSUPPORTED);
             return Collections.emptySet();
         }
diff --git a/drivers/src/main/java/org/onosproject/driver/pipeline/OVSCorsaPipeline.java b/drivers/src/main/java/org/onosproject/driver/pipeline/OVSCorsaPipeline.java
index ddcb4d9..5993d96 100644
--- a/drivers/src/main/java/org/onosproject/driver/pipeline/OVSCorsaPipeline.java
+++ b/drivers/src/main/java/org/onosproject/driver/pipeline/OVSCorsaPipeline.java
@@ -257,17 +257,17 @@
             fail(fwd, ObjectiveError.UNKNOWN);
             return Collections.emptySet();
         }
-        if (ethType.ethType() == Ethernet.TYPE_ARP) {
+        if (ethType.ethType().toShort() == Ethernet.TYPE_ARP) {
             log.warn("Driver automatically handles ARP packets by punting to controller "
                     + " from ETHER table");
             pass(fwd);
             return Collections.emptySet();
-        } else if (ethType.ethType() == Ethernet.TYPE_LLDP ||
-                ethType.ethType() == Ethernet.TYPE_BSN) {
+        } else if (ethType.ethType().toShort() == Ethernet.TYPE_LLDP ||
+                ethType.ethType().toShort() == Ethernet.TYPE_BSN) {
             log.warn("Driver currently does not currently handle LLDP packets");
             fail(fwd, ObjectiveError.UNSUPPORTED);
             return Collections.emptySet();
-        } else if (ethType.ethType() == Ethernet.TYPE_IPV4) {
+        } else if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
             IPCriterion ipSrc = (IPCriterion) selector
                     .getCriterion(Criterion.Type.IPV4_SRC);
             IPCriterion ipDst = (IPCriterion) selector
@@ -303,7 +303,7 @@
         TrafficSelector selector = fwd.selector();
         EthTypeCriterion ethType =
                 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
-        if (ethType == null || ethType.ethType() != Ethernet.TYPE_IPV4) {
+        if (ethType == null || ethType.ethType().toShort() != Ethernet.TYPE_IPV4) {
             fail(fwd, ObjectiveError.UNSUPPORTED);
             return Collections.emptySet();
         }
diff --git a/drivers/src/main/java/org/onosproject/driver/pipeline/PicaPipeline.java b/drivers/src/main/java/org/onosproject/driver/pipeline/PicaPipeline.java
index 21541b0..0c3d8a2 100644
--- a/drivers/src/main/java/org/onosproject/driver/pipeline/PicaPipeline.java
+++ b/drivers/src/main/java/org/onosproject/driver/pipeline/PicaPipeline.java
@@ -243,7 +243,7 @@
             return Collections.emptySet();
         }
 
-        if (ethType.ethType() == Ethernet.TYPE_ARP) {
+        if (ethType.ethType().toShort() == Ethernet.TYPE_ARP) {
             if (filters.isEmpty()) {
                 pendingVersatiles.add(fwd);
                 return Collections.emptySet();
@@ -253,12 +253,12 @@
                 flowrules.addAll(processVersatilesWithFilters(filter, fwd));
             }
             return flowrules;
-        } else if (ethType.ethType() == Ethernet.TYPE_LLDP ||
-                ethType.ethType() == Ethernet.TYPE_BSN) {
+        } else if (ethType.ethType().toShort() == Ethernet.TYPE_LLDP ||
+                ethType.ethType().toShort() == Ethernet.TYPE_BSN) {
             log.warn("Driver currently does not currently handle LLDP packets");
             fail(fwd, ObjectiveError.UNSUPPORTED);
             return Collections.emptySet();
-        } else if (ethType.ethType() == Ethernet.TYPE_IPV4) {
+        } else if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
             IPCriterion ipSrc = (IPCriterion) selector
                     .getCriterion(Criterion.Type.IPV4_SRC);
             IPCriterion ipDst = (IPCriterion) selector
@@ -339,7 +339,7 @@
         TrafficSelector selector = fwd.selector();
         EthTypeCriterion ethType =
                 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
-        if (ethType == null || ethType.ethType() != Ethernet.TYPE_IPV4) {
+        if (ethType == null || ethType.ethType().toShort() != Ethernet.TYPE_IPV4) {
             fail(fwd, ObjectiveError.UNSUPPORTED);
             return Collections.emptySet();
         }
diff --git a/drivers/src/main/java/org/onosproject/driver/pipeline/SoftRouterPipeline.java b/drivers/src/main/java/org/onosproject/driver/pipeline/SoftRouterPipeline.java
index 2240520..220be86 100644
--- a/drivers/src/main/java/org/onosproject/driver/pipeline/SoftRouterPipeline.java
+++ b/drivers/src/main/java/org/onosproject/driver/pipeline/SoftRouterPipeline.java
@@ -367,7 +367,7 @@
             return Collections.emptySet();
         }
 
-        if (ethType.ethType() == Ethernet.TYPE_ARP) {
+        if (ethType.ethType().toShort() == Ethernet.TYPE_ARP) {
             // need to install ARP request & reply flow rules for each interface filter
 
             // rule for ARP replies
@@ -425,7 +425,7 @@
         EthTypeCriterion ethType =
                 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
         // XXX currently supporting only the L3 unicast table
-        if (ethType == null || ethType.ethType() != Ethernet.TYPE_IPV4) {
+        if (ethType == null || ethType.ethType().toShort() != Ethernet.TYPE_IPV4) {
             fail(fwd, ObjectiveError.UNSUPPORTED);
             return Collections.emptySet();
         }
@@ -474,7 +474,7 @@
      * the dummy group is fetched from the distributed store and the enclosed
      * treatment is applied as a flow rule action.
      *
-     * @param nextObjective the next objective of type simple
+     * @param nextObj the next objective of type simple
      */
     private void processSimpleNextObjective(NextObjective nextObj) {
         // Simple next objective has a single treatment (not a collection)
diff --git a/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java b/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java
index d2948e9..c02ba3c 100644
--- a/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java
+++ b/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java
@@ -440,8 +440,8 @@
         EthTypeCriterion ethType = (EthTypeCriterion) selector
                 .getCriterion(Criterion.Type.ETH_TYPE);
         if ((ethType == null) ||
-                ((((short) ethType.ethType()) != Ethernet.TYPE_IPV4) &&
-                (((short) ethType.ethType()) != Ethernet.MPLS_UNICAST))) {
+                (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
+                (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST)) {
             log.warn("processSpecific: Unsupported "
                     + "forwarding objective criteraia");
             fail(fwd, ObjectiveError.UNSUPPORTED);
@@ -451,7 +451,7 @@
         TrafficSelector.Builder filteredSelectorBuilder =
                 DefaultTrafficSelector.builder();
         int forTableId = -1;
-        if (((short) ethType.ethType()) == Ethernet.TYPE_IPV4) {
+        if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
             filteredSelectorBuilder = filteredSelectorBuilder
                 .matchEthType(Ethernet.TYPE_IPV4)
                 .matchIPDst(((IPCriterion) selector
diff --git a/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTPDell.java b/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTPDell.java
index f68a665..3267d550 100644
--- a/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTPDell.java
+++ b/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTPDell.java
@@ -81,8 +81,8 @@
         EthTypeCriterion ethType = (EthTypeCriterion) selector
                 .getCriterion(Criterion.Type.ETH_TYPE);
         if ((ethType == null) ||
-                ((((short) ethType.ethType()) != Ethernet.TYPE_IPV4) &&
-                (((short) ethType.ethType()) != Ethernet.MPLS_UNICAST))) {
+                (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
+                (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST)) {
             log.debug("processSpecific: Unsupported "
                     + "forwarding objective criteraia");
             fail(fwd, ObjectiveError.UNSUPPORTED);
@@ -92,7 +92,7 @@
         TrafficSelector.Builder filteredSelectorBuilder =
                 DefaultTrafficSelector.builder();
         int forTableId = -1;
-        if (((short) ethType.ethType()) == Ethernet.TYPE_IPV4) {
+        if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
             if (deviceTMac == null) {
                 log.debug("processSpecific: ETH_DST filtering "
                         + "objective is not set which is required "
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java
index 71327e5..d34fd5e 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java
@@ -198,7 +198,7 @@
                 break;
             case ETH_TYPE:
                 EthTypeCriterion ethType = (EthTypeCriterion) c;
-                mBuilder.setExact(MatchField.ETH_TYPE, EthType.of(ethType.ethType()));
+                mBuilder.setExact(MatchField.ETH_TYPE, EthType.of(ethType.ethType().toShort()));
                 break;
             case VLAN_VID:
                 VlanIdCriterion vid = (VlanIdCriterion) c;
diff --git a/utils/misc/src/main/java/org/onlab/packet/EthType.java b/utils/misc/src/main/java/org/onlab/packet/EthType.java
new file mode 100644
index 0000000..4f52b7d
--- /dev/null
+++ b/utils/misc/src/main/java/org/onlab/packet/EthType.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onlab.packet;
+
+import com.google.common.collect.Maps;
+
+import java.util.Map;
+
+/**
+ * Representation of an Ethertype.
+ */
+public class EthType {
+
+    public static final short ARP = EtherType.ARP.ethType.toShort();
+    public static final short RARP = EtherType.RARP.ethType.toShort();
+    public static final short VLAN = EtherType.VLAN.ethType.toShort();
+    public static final short IPV4 = EtherType.IPV4.ethType.toShort();
+    public static final short IPV6 = EtherType.IPV6.ethType.toShort();
+    public static final short LLDP = EtherType.LLDP.ethType.toShort();
+    public static final short BDDP = EtherType.BDDP.ethType.toShort();
+    public static final short MPLS_MULTICAST = EtherType.MPLS_UNICAST.ethType.toShort();
+    public static final short MPLS_UNICAST = EtherType.MPLS_UNICAST.ethType.toShort();
+
+    private short etherType;
+
+    /*
+     * Reverse-lookup map for getting a EtherType enum
+     */
+    private static final Map<Short, EtherType> LOOKUP = Maps.newHashMap();
+
+    static {
+        for (EtherType eth : EtherType.values()) {
+            LOOKUP.put(eth.ethType().toShort(), eth);
+        }
+    }
+
+    public EthType(int etherType) {
+        this.etherType = (short) (etherType & 0xFFFF);
+    }
+
+    public EthType(short etherType) {
+        this.etherType = etherType;
+    }
+
+    public short toShort() {
+        return etherType;
+    }
+
+    public static EtherType lookup(short etherType) {
+        return LOOKUP.get(etherType);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        EthType ethType = (EthType) o;
+
+        if (etherType != ethType.etherType) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return (int) etherType;
+    }
+
+    public String toString() {
+        EtherType ethType = lookup(this.etherType);
+        return (ethType == null ? "unknown" : ethType.toString());
+    }
+
+    public static enum EtherType {
+
+        ARP(0x806, "arp", ARP.class),
+        RARP(0x8035, "rarp", null),
+        IPV4(0x800, "ipv4", IPv4.class),
+        IPV6(0x86dd, "ipv6", IPv6.class),
+        LLDP(0x88cc, "lldp", LLDP.class),
+        VLAN(0x8100, "vlan", null),
+        BDDP(0x8942, "bddp", LLDP.class),
+        MPLS_UNICAST(0x8847, "mpls_unicast", null),
+        MPLS_MULTICAST(0x8848, "mpls_unicast", null);
+
+
+        private final Class clazz;
+        private EthType ethType;
+        private String type;
+
+        EtherType(int ethType, String type, Class clazz) {
+            this.ethType = new EthType(ethType);
+            this.type = type;
+            this.clazz = clazz;
+        }
+
+        public EthType ethType() {
+            return ethType;
+        }
+
+        @Override
+        public String toString() {
+            return type;
+        }
+
+        public Class clazz() {
+            return clazz;
+        }
+
+
+    }
+}
diff --git a/utils/misc/src/main/java/org/onlab/packet/Ethernet.java b/utils/misc/src/main/java/org/onlab/packet/Ethernet.java
index 714266e..779d96c 100644
--- a/utils/misc/src/main/java/org/onlab/packet/Ethernet.java
+++ b/utils/misc/src/main/java/org/onlab/packet/Ethernet.java
@@ -31,28 +31,28 @@
  */
 public class Ethernet extends BasePacket {
     private static final String HEXES = "0123456789ABCDEF";
-    public static final short TYPE_ARP = (short) 0x0806;
-    public static final short TYPE_RARP = (short) 0x8035;
-    public static final short TYPE_IPV4 = (short) 0x0800;
-    public static final short TYPE_IPV6 = (short) 0x86dd;
-    public static final short TYPE_LLDP = (short) 0x88cc;
-    public static final short TYPE_VLAN = (short) 0x8100;
-    public static final short TYPE_BSN = (short) 0x8942;
-    public static final short VLAN_UNTAGGED = (short) 0xffff;
-    public static final short MPLS_UNICAST = (short) 0x8847;
-    public static final short MPLS_MULTICAST = (short) 0x8848;
+    public static final short TYPE_ARP = EthType.ARP;
+    public static final short TYPE_RARP = EthType.RARP;
+    public static final short TYPE_IPV4 = EthType.IPV4;
+    public static final short TYPE_IPV6 = EthType.IPV6;
+    public static final short TYPE_LLDP = EthType.LLDP;
+    public static final short TYPE_VLAN = EthType.VLAN;
+    public static final short TYPE_BSN = EthType.BDDP;
 
+    public static final short MPLS_UNICAST = EthType.MPLS_UNICAST;
+    public static final short MPLS_MULTICAST = EthType.MPLS_MULTICAST;
+
+    public static final short VLAN_UNTAGGED = (short) 0xffff;
     public static final short DATALAYER_ADDRESS_LENGTH = 6; // bytes
     public static final Map<Short, Class<? extends IPacket>> ETHER_TYPE_CLASS_MAP =
         new HashMap<>();
 
     static {
-        Ethernet.ETHER_TYPE_CLASS_MAP.put(Ethernet.TYPE_ARP, ARP.class);
-        Ethernet.ETHER_TYPE_CLASS_MAP.put(Ethernet.TYPE_RARP, ARP.class);
-        Ethernet.ETHER_TYPE_CLASS_MAP.put(Ethernet.TYPE_IPV4, IPv4.class);
-        Ethernet.ETHER_TYPE_CLASS_MAP.put(Ethernet.TYPE_IPV6, IPv6.class);
-        Ethernet.ETHER_TYPE_CLASS_MAP.put(Ethernet.TYPE_LLDP, LLDP.class);
-        Ethernet.ETHER_TYPE_CLASS_MAP.put(Ethernet.TYPE_BSN, LLDP.class);
+       for (EthType.EtherType ethType : EthType.EtherType.values()) {
+           if (ethType.clazz() != null) {
+               ETHER_TYPE_CLASS_MAP.put(ethType.ethType().toShort(), ethType.clazz());
+           }
+       }
     }
 
     protected MacAddress destinationMACAddress;