Major progress in Packet building module and VM instruction sets.
authorDan Klein <[email protected]>
Thu, 10 Sep 2015 10:39:18 +0000 (13:39 +0300)
committerDan Klein <[email protected]>
Thu, 10 Sep 2015 10:39:18 +0000 (13:39 +0300)
added dot1q into dpkt lib
First abstractino of HLTAPI layer

scripts/automation/trex_control_plane/client/trex_client.py
scripts/automation/trex_control_plane/client/trex_hltapi.py [new file with mode: 0644]
scripts/automation/trex_control_plane/client/trex_root_path.py [new file with mode: 0644]
scripts/automation/trex_control_plane/client_utils/packet_builder.py
scripts/external_libs/dpkt-1.8.6/dpkt/dot1q.py [new file with mode: 0644]

diff --git a/scripts/automation/trex_control_plane/client/trex_hltapi.py b/scripts/automation/trex_control_plane/client/trex_hltapi.py
new file mode 100644 (file)
index 0000000..46c283f
--- /dev/null
@@ -0,0 +1,18 @@
+#!/router/bin/python
+
+import trex_root_path
+from client_utils.packet_builder import CTRexPktBuilder
+
+print "done!"
+
+class CTRexHltApi(object):
+
+    def __init__(self):
+        pass
+
+    def config_traffic(self):
+        pass
+
+if __name__ == "__main__":
+    pass
+
diff --git a/scripts/automation/trex_control_plane/client/trex_root_path.py b/scripts/automation/trex_control_plane/client/trex_root_path.py
new file mode 100644 (file)
index 0000000..de4ec03
--- /dev/null
@@ -0,0 +1,15 @@
+#!/router/bin/python
+
+import os
+import sys
+
+def add_root_to_path ():
+    """adds trex_control_plane root dir to script path, up to `depth` parent dirs"""
+    root_dirname = 'trex_control_plane'
+    file_path    = os.path.dirname(os.path.realpath(__file__))
+
+    components = file_path.split(os.sep)
+    sys.path.append( str.join(os.sep, components[:components.index(root_dirname)+1]) )
+    return
+
+add_root_to_path()
index 0d31f28..abe98db 100644 (file)
@@ -5,23 +5,207 @@ import outer_packages
 import dpkt
 import socket
 import binascii
+import copy
+import random
+import string
+import struct
+import re
 
 
 class CTRexPktBuilder(object):
-    """docstring for CTRexPktBuilder"""
-    def __init__(self):
+    """
+    This class defines the TRex API of building a packet using dpkt package.
+    Using this class the user can also define how TRex will handle the packet by specifying the VM setting.
+    """
+    def __init__(self, max_pkt_size=dpkt.ethernet.ETH_LEN_MAX):
+        """
+        Instantiate a CTRexPktBuilder object
+
+        :parameters:
+             None
+
+        """
         super(CTRexPktBuilder, self).__init__()
-        self.packet = None
-        self.vm = CTRexPktBuilder.CTRexVM(self.packet)
+        self._packet = None
+        self._pkt_by_hdr = {}
+        self._pkt_top_layer = None
+        self._max_pkt_size = max_pkt_size
+        self.payload_generator = CTRexPktBuilder.CTRexPayloadGen(self._packet, self._max_pkt_size)
+        self.vm = CTRexPktBuilder.CTRexVM()
+
+    def add_pkt_layer(self, layer_name, pkt_layer):
+        """
+        This method adds additional header to the already existing packet
 
-    def add_l2_header(self):
-        pass
+        :parameters:
+            layer_name: str
+                a string representing the name of the layer.
+                Example: "l2", "l4_tcp", etc.
 
-    def add_l3_header(self):
-        pass
+            pkt_layer : dpkt.Packet obj
+                a dpkt object, generally from higher layer, that will be added on top of existing layer.
 
-    def add_pkt_payload(self):
-        pass
+        """
+        assert isinstance(pkt_layer, dpkt.Packet)
+        if layer_name in self._pkt_by_hdr:
+            raise ValueError("Given layer name '{0}' already exists.".format(layer_name))
+        else:
+            dup_pkt = copy.copy(pkt_layer)  # using copy of layer to avoid cyclic packets that may lead to infinite loop
+            if not self._pkt_top_layer:     # this is the first header added
+                self._packet = dup_pkt
+            else:
+                self._pkt_top_layer.data = dup_pkt
+            self._pkt_top_layer = dup_pkt
+            self._pkt_by_hdr[layer_name] = dup_pkt
+            return
+
+    def set_ip_layer_addr(self, layer_name, attr, ip_addr, ip_type="ipv4"):
+        try:
+            layer = self._pkt_by_hdr[layer_name.lower()]
+            if not (isinstance(layer, dpkt.ip.IP) or isinstance(layer, dpkt.ip6.IP6)):
+                raise ValueError("The specified layer '{0}' is not of IPv4/IPv6 type.".format(layer_name))
+            else:
+                decoded_ip = CTRexPktBuilder._decode_ip_addr(ip_addr, ip_type)
+                setattr(layer, attr, decoded_ip)
+        except KeyError:
+            raise KeyError("Specified layer '{0}' doesn't exist on packet.".format(layer_name))
+
+    def set_ipv6_layer_addr(self, layer_name, attr, ip_addr):
+        self.set_ip_layer_addr(self, layer_name, attr, ip_addr, ip_type="ipv6")
+
+    def set_eth_layer_addr(self, layer_name, attr, mac_addr):
+        try:
+            layer = self._pkt_by_hdr[layer_name.lower()]
+            if not isinstance(layer, dpkt.ethernet.Ethernet):
+                raise ValueError("The specified layer '{0}' is not of Ethernet type.".format(layer_name))
+            else:
+                decoded_mac = CTRexPktBuilder._decode_mac_addr(mac_addr)
+                setattr(layer, attr, decoded_mac)
+        except KeyError:
+            raise KeyError("Specified layer '{0}' doesn't exist on packet.".format(layer_name))
+
+    def set_layer_attr(self, layer_name, attr, val):
+        """
+        This method enables the user to change a value of a previously defined packet layer.
+        This method isn't to be used to set the data attribute of a packet with payload.
+        Use :func:`packet_builder.CTRexPktBuilder.set_payload` instead.
+
+        :parameters:
+            layer_name: str
+                a string representing the name of the layer.
+                Example: "l2", "l4_tcp", etc.
+
+            attr : str
+                a string representing the attribute to be changed on desired layer
+
+            val :
+                value of attribute.
+
+        :raises:
+            + :exc:`KeyError`, in case of missing layer (the desired layer isn't part of packet)
+            + :exc:`ValueError`, in case invalid attribute to the specified layer.
+
+        """
+        try:
+            layer = self._pkt_by_hdr[layer_name.lower()]
+            if attr == 'data' and not isinstance(val, dpkt.Packet):
+                # Don't allow setting 'data' attribute
+                raise ValueError("Set a data attribute with obejct that is not dpkt.Packet is not allowed using "
+                                 "set_layer_attr method.\nUse set_payload method instead.")
+            if hasattr(layer, attr):
+                setattr(layer, attr, val)
+                if attr == 'data':
+                    # re-evaluate packet from the start, possible broken link between layers
+                    self._reevaluate_packet(layer_name.lower())
+            else:
+                raise ValueError("Given attr name '{0}' doesn't exists on specified layer ({1}).".format(layer_name,
+                                                                                                         attr))
+        except KeyError:
+            raise KeyError("Specified layer '{0}' doesn't exist on packet.".format(layer_name))
+
+    def set_pkt_payload(self, payload):
+        """
+        This method sets a payload to the topmost layer of the generated packet.
+        This method isn't to be used to set another networking layer to the packet.
+        Use :func:`packet_builder.CTRexPktBuilder.set_layer_attr` instead.
+
+
+        :parameters:
+            payload:
+                a payload to be added to the packet at the topmost layer.
+                this object cannot be of type dpkt.Packet.
+
+        :raises:
+            + :exc:`AttributeError`, in case no underlying header to host the payload.
+
+        """
+        assert isinstance(payload, str)
+        try:
+            self._pkt_top_layer.data = payload
+        except AttributeError:
+            raise AttributeError("The so far built packet doesn't contain an option for payload attachment.\n"
+                                 "Make sure to set appropriate underlying header before adding payload")
+
+    def load_packet(self, packet):
+        """
+        This method enables the user to change a value of a previously defined packet layer.
+
+        :parameters:
+            packet: dpkt.Packet obj
+                a dpkt object that represents a packet.
+
+
+        :raises:
+            + :exc:`CTRexPktBuilder.IPAddressError`, in case invalid ip type option specified.
+
+        """
+        assert isinstance(packet, dpkt.Packet)
+        self._packet = copy.copy(packet)
+
+        self._pkt_by_hdr.clear()
+        self._pkt_top_layer = self._packet
+        # analyze packet to layers
+        tmp_layer = self._packet
+        while True:
+            if isinstance(tmp_layer, dpkt.Packet):
+                layer_name = self._gen_layer_name(type(tmp_layer).__name__)
+                self._pkt_by_hdr[layer_name] = tmp_layer
+                self._pkt_top_layer = tmp_layer
+                try:
+                    # check existence of upper layer
+                    tmp_layer = tmp_layer.data
+                except AttributeError:
+                    # this is the most upper header
+                    self._pkt_by_hdr['pkt_final_payload'] = tmp_layer.data
+                    break
+            else:
+                self._pkt_by_hdr['pkt_final_payload'] = tmp_layer
+                break
+        return
+
+    def get_packet(self, get_ptr=False):
+        """
+        This method enables the user to change a value of a previously defined packet layer.
+
+        :parameters:
+            get_ptr : bool
+                indicate whether to get a reference to packet or a copy.
+                Use only in advanced modes
+                if set to true, metadata for packet is cleared, and any further modification is not guaranteed.
+
+                default value : False
+
+        :return:
+                the current packet built by CTRexPktBuilder object.
+
+        """
+        if get_ptr:
+            self._pkt_by_hdr = {}
+            self._pkt_top_layer = None
+            return self._packet
+
+        else:
+            return copy.copy(self._packet)
 
     # VM access methods
     def set_vm_ip_range(self, ip_start, ip_end, ip_type="ipv4"):
@@ -37,7 +221,7 @@ class CTRexPktBuilder(object):
         pass
 
     def dump_pkt(self):
-        pkt_in_hex = binascii.hexlify(str(self.packet))
+        pkt_in_hex = binascii.hexlify(str(self._packet))
         return [pkt_in_hex[i:i+2] for i in range(0, len(pkt_in_hex), 2)]
 
     # ----- useful shortcut methods ----- #
@@ -45,118 +229,334 @@ class CTRexPktBuilder(object):
         pass
 
     # ----- internal methods ----- #
+    def _reevaluate_packet(self, layer_name):
+        cur_layer = self._packet
+        known_layers = set(self._pkt_by_hdr.keys())
+        found_layers = set()
+        while True:
+            pointing_layer_name = self._find_pointing_layer(known_layers, cur_layer)
+            found_layers.add(pointing_layer_name)
+            if self._pkt_by_hdr[layer_name] is cur_layer:
+                self._pkt_top_layer = cur_layer
+                disconnected_layers = known_layers.difference(found_layers)
+                # remove disconnected layers
+                for layer in disconnected_layers:
+                    self._pkt_by_hdr.pop(layer)
+                break
+            else:
+                cur_layer = cur_layer.data
+
+    def _gen_layer_name(self, layer_class_name):
+        assert isinstance(layer_class_name, str)
+        layer_name = layer_class_name.lower()
+        idx = 1
+        while True:
+            tmp_name = "{name}_{id}".format(name=layer_name, id=idx)
+            if tmp_name not in self._pkt_by_hdr:
+                return tmp_name
+            else:
+                idx += 1
+
+    def _find_pointing_layer(self, known_layers, layer_obj):
+        assert isinstance(known_layers, set)
+        for layer in known_layers:
+            if self._pkt_by_hdr[layer] is layer_obj:
+                return layer
+
+    @staticmethod
+    def _decode_mac_addr(mac_addr):
+        """
+        Static method to test for MAC address validity.
+
+        :parameters:
+            mac_addr : str
+                a string representing an MAC address, separated by ':' or '-'.
+
+                examples: '00:de:34:ef:2e:f4', '00-de-34-ef-2e-f4
+
+        :return:
+            + an hex-string representation of the MAC address.
+              for example, ip 00:de:34:ef:2e:f4 will return '\x00\xdeU\xef.\xf4'
+
+        :raises:
+            + :exc:`CTRexPktBuilder.MACAddressError`, in case invalid ip type option specified.
+
+        """
+        tmp_mac = mac_addr.lower().replace('-', ':')
+        if re.match("[0-9a-f]{2}([-:])[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$", tmp_mac):
+            return binascii.unhexlify(tmp_mac.replace(':', ''))
+            # another option for both Python 2 and 3: 
+            # codecs.decode(tmp_mac.replace(':', ''), 'hex')
+        else:
+            raise CTRexPktBuilder.MACAddressError()
+
     @staticmethod
-    def _is_valid_ip_addr(ip_addr, ip_type):
+    def _decode_ip_addr(ip_addr, ip_type):
+        """
+        Static method to test for IPv4/IPv6 address validity.
+
+        :parameters:
+            ip_addr : str
+                a string representing an IP address (IPv4/IPv6)
+
+            ip_type : str
+                The type of IP to be checked.
+                Valid types: "ipv4", "ipv6".
+
+        :return:
+            + an hex-string representation of the ip address.
+              for example, ip 1.2.3.4 will return '\x01\x02\x03\x04'
+
+        :raises:
+            + :exc:`CTRexPktBuilder.IPAddressError`, in case invalid ip type option specified.
+
+        """
         if ip_type == "ipv4":
             try:
-                socket.inet_pton(socket.AF_INET, ip_addr)
+                return socket.inet_pton(socket.AF_INET, ip_addr)
             except AttributeError:  # no inet_pton here, sorry
-                try:
-                    socket.inet_aton(ip_addr)
-                except socket.error:
-                    return False
-                return ip_addr.count('.') == 3
+                try:
+                return socket.inet_aton(ip_addr)
+                except socket.error:
+                    return False
+                return ip_addr.count('.') == 3
             except socket.error:  # not a valid address
-                return False
-            return True
+                raise CTRexPktBuilder.IPAddressError()
         elif ip_type == "ipv6":
             try:
-                socket.inet_pton(socket.AF_INET6, ip_addr)
+                return socket.inet_pton(socket.AF_INET6, ip_addr)
             except socket.error:  # not a valid address
-                return False
-            return True
+                raise CTRexPktBuilder.IPAddressError()
         else:
             raise CTRexPktBuilder.IPAddressError()
 
-    # ------ private classes ------
+    # ------ private classes ------ #
+    class CTRexPayloadGen(object):
+
+        def __init__(self, packet_ref, max_pkt_size):
+            self._pkt_ref = packet_ref
+            self._max_pkt_size = max_pkt_size
+
+        def gen_random_str(self):
+            gen_length = self._calc_gen_length()
+            # return a string of size gen_length bytes, to pad the packet to its max_size
+            return ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits)
+                           for _ in range(gen_length))
+
+        def gen_repeat_ptrn(self, ptrn_to_repeat):
+            gen_length = self._calc_gen_length()
+            if isinstance(ptrn_to_repeat, str):
+                # generate repeated string
+                return (ptrn_to_repeat * (gen_length/len(ptrn_to_repeat) + 1))[:gen_length]
+            elif isinstance(ptrn_to_repeat, int):
+                ptrn = binascii.unhexlify(hex(ptrn_to_repeat)[2:])
+                return (ptrn * (gen_length/len(ptrn) + 1))[:gen_length]
+            elif isinstance(ptrn_to_repeat, tuple):
+                if not all((isinstance(x, int) and (x < 255) and (x >= 0))
+                           for x in ptrn_to_repeat):
+                    raise ValueError("All numbers in tuple must be in range 0 <= number <= 255 ")
+                # generate repeated sequence
+                to_pack = (ptrn_to_repeat * (gen_length/len(ptrn_to_repeat) + 1))[:gen_length]
+                return struct.pack('B'*gen_length, *to_pack)
+            else:
+                raise ValueError("Given ptrn_to_repeat argument type ({0}) is illegal.".
+                                 format(type(ptrn_to_repeat)))
+
+        def _calc_gen_length(self):
+            return self._max_pkt_size - len(self._pkt_ref)
+
     class CTRexVM(object):
-        """docstring for CTRexVM"""
-        def __init__(self, packet):
+        """
+        This class defines the TRex VM which represents how TRex will regenerate packets.
+        The packets will be regenerated based on the built packet containing this class.
+        """
+        def __init__(self):
+            """
+            Instantiate a CTRexVM object
+
+            :parameters:
+                None
+            """
             super(CTRexPktBuilder.CTRexVM, self).__init__()
-            self.packet = packet
             self.vm_variables = {}
 
-        def add_vm_variable(self, name):
+        def set_vm_var_field(self, var_name, field_name, val):
+            """
+            Set VM variable field. Only existing variables are allowed to be changed.
+
+            :parameters:
+                var_name : str
+                    a string representing the name of the VM variable to be changed.
+                field_name : str
+                    a string representing the field name of the VM variable to be changed.
+                val :
+                    a value to be applied to field_name field of the var_name VM variable.
+
+            :raises:
+                + :exc:`KeyError`, in case invalid var_name has been specified.
+                + :exc:`CTRexPktBuilder.VMVarFieldTypeError`, in case mismatch between `val` and allowed type.
+                + :exc:`CTRexPktBuilder.VMVarValueError`, in case val isn't one of allowed options of field_name.
+
+            """
+            return self.vm_variables[var_name].set_field(field_name, val)
+
+        def add_flow_man_simple(self, name, **kwargs):
+            """
+            Adds a new flow manipulation object to the VM instance.
+
+            :parameters:
+                name : str
+                    name of the manipulation, must be distinct.
+                    Example: 'source_ip_change'
+
+                **kwargs : dict
+                    optional, set flow_man fields on initialization (key = field_name, val = field_val).
+                    Must be used with legit fields, see :func:`CTRexPktBuilder.CTRexVM.CTRexVMVariable.set_field`.
+
+            :return:
+                None
+
+            :raises:
+                + :exc:`CTRexPktBuilder.VMVarNameExistsError`, in case of desired flow_man name already taken.
+                + Exceptions from :func:`CTRexPktBuilder.CTRexVM.CTRexVMVariable.set_field` method.
+                  Will rise when VM variables were misconfiguration.
+            """
             if name not in self.vm_variables.keys():
                 self.vm_variables[name] = self.CTRexVMVariable(name)
+                # try configuring VM var attributes
+                for (field, value) in kwargs.items():
+                    self.vm_variables[name].set_field(field, value)
             else:
                 raise CTRexPktBuilder.VMVarNameExistsError(name)
 
-        def set_vm_var_field(self, var_name, field_name, val):
-            pass
-            return self.vm_variables[var_name].set_field(field_name, val)
+        def load_flow_man(self, flow_obj):
+            """
+            Loads an outer VM variable (instruction) into current VM.
+            The outer VM variable must contain different name than existing VM variables currently registered on VM.
 
+            :parameters:
+                flow_obj : CTRexVMVariable
+                    a CTRexVMVariable to be loaded into VM variable sets.
 
-        def fix_checksum_ipv4(self):
-            pass
+            :return:
+                list holds variables data of VM
 
-        def flow_man_simple(self):
-            pass
-
-        def write_to_pkt(self):
-            pass
+            """
+            assert isinstance(flow_obj, CTRexPktBuilder.CTRexVM.CTRexVMVariable)
+            if flow_obj.name not in self.vm_variables.keys():
+                self.vm_variables[flow_obj.name] = flow_obj
+            else:
+                raise CTRexPktBuilder.VMVarNameExistsError(flow_obj.name)
 
         def dump(self):
+            """
+            dumps a VM variables (instructions) into an list data structure.
+
+            :parameters:
+                None
+
+            :return:
+                list holds variables data of VM
+
+            """
             return [var.dump()
-                    for var in self.vm_variables]
+                    for key, var in self.vm_variables.items()]
 
         class CTRexVMVariable(object):
+            """
+            This class defines a single VM variable to be used as part of CTRexVar object.
+            """
             VALID_SIZE = [1, 2, 4, 8]
-            VALID_TYPE = ["inc", "dec", "random"]
-            VALID_CORE_MASK = ["split", "none"]
+            VALID_OPERATION = ["inc", "dec", "random"]
 
             def __init__(self, name):
+                """
+                Instantiate a CTRexVMVariable object
+
+                :parameters:
+                    name : str
+                        a string representing the name of the VM variable.
+                """
                 super(CTRexPktBuilder.CTRexVM.CTRexVMVariable, self).__init__()
                 self.name = name
                 self.size = 4
                 self.big_endian = True
-                self.type = "inc"
-                self.core_mask = "none"
-                self.init_addr = "10.0.0.1"
-                self.min_addr = str(self.init_addr)
-                self.max_addr = str(self.init_addr)
+                self.operation = "inc"
+                self.split_by_core = False
+                self.init_value = 1
+                self.min_value = self.init_value
+                self.max_value = self.init_value
 
             def set_field(self, field_name, val):
-                if field_name == "size":
+                """
+                Set VM variable field. Only existing variables are allowed to be changed.
+
+                :parameters:
+                    field_name : str
+                        a string representing the field name of the VM variable to be changed.
+                    val :
+                        a value to be applied to field_name field of the var_name VM variable.
+
+                :return:
+                    None
+
+                :raises:
+                    + :exc:`CTRexPktBuilder.VMVarNameError`, in case of illegal field name.
+                    + :exc:`CTRexPktBuilder.VMVarFieldTypeError`, in case mismatch between `val` and allowed type.
+                    + :exc:`CTRexPktBuilder.VMVarValueError`, in case val isn't one of allowed options of field_name.
+
+                """
+                if not hasattr(self, field_name):
+                    raise CTRexPktBuilder.VMVarNameError(field_name)
+                elif field_name == "size":
                     if type(val) != int:
                         raise CTRexPktBuilder.VMVarFieldTypeError("size", int)
                     elif val not in self.VALID_SIZE:
                         raise CTRexPktBuilder.VMVarValueError("size", self.VALID_SIZE)
-                elif field_name == "type":
-                    if type(val) != str:
-                        raise CTRexPktBuilder.VMVarFieldTypeError("type", str)
-                    elif val not in self.VALID_TYPE:
-                        raise CTRexPktBuilder.VMVarValueError("type", self.VALID_TYPE)
-                elif field_name == "core_mask":
+                elif field_name == "init_value":
+                    if type(val) != int:
+                        raise CTRexPktBuilder.VMVarFieldTypeError("init_value", int)
+                elif field_name == "operation":
                     if type(val) != str:
-                        raise CTRexPktBuilder.VMVarFieldTypeError("core_mask", str)
-                    elif val not in self.VALID_TYPE:
-                        raise CTRexPktBuilder.VMVarValueError("core_mask", self.VALID_CORE_MASK)
+                        raise CTRexPktBuilder.VMVarFieldTypeError("operation", str)
+                    elif val not in self.VALID_OPERATION:
+                        raise CTRexPktBuilder.VMVarValueError("operation", self.VALID_OPERATION)
+                elif field_name == "split_by_core":
+                    val = bool(val)
                 # update field value on success
                 setattr(self, field_name, val)
 
             def is_valid(self):
                 if self.size not in self.VALID_SIZE:
                     return False
-                if self.type not in self.VALID_TYPE:
-                    return False
-                if self.core_mask not in self.VALID_CORE_MASK:
+                if self.type not in self.VALID_OPERATION:
                     return False
                 return True
 
             def dump(self):
-                return {"name" : self.name,
-                        "Size" : self.size,
-                        "big_endian" : self.big_endian,
-                        "type" : self.type,
-                        "core_mask" : self.core_mask,
-                        "init_addr" : self.init_addr,
-                        "min_addr" : self.min_addr,
-                        "max_addr" : self.max_addr}
+                """
+                dumps a variable fields in a dictionary data structure.
+
+                :parameters:
+                    None
+
+                :return:
+                    dictionary holds variable data of VM variable
+
+                """
+                return {"ins_name": "flow_man_simple",  # VM variable dump always refers to manipulate instruction.
+                        "flow_variable_name": self.name,
+                        "object_size": self.size,
+                        # "big_endian": self.big_endian,
+                        "Operation": self.operation,
+                        "split_by_core": self.split_by_core,
+                        "init_value": self.init_value,
+                        "min_value": self.min_value,
+                        "max_value": self.max_value}
 
     class CPacketBuildException(Exception):
         """
-        This is the general Packet error exception class.
+        This is the general Packet Building error exception class.
         """
         def __init__(self, code, message):
             self.code = code
@@ -173,22 +573,40 @@ class CTRexPktBuilder(object):
         This exception is used to indicate an error on the IP addressing part of the packet.
         """
         def __init__(self, message=''):
-            self._default_message = 'Illegal type of IP addressing has been provided.'
+            self._default_message = 'Illegal type or value of IP address has been provided.'
             self.message = message or self._default_message
             super(CTRexPktBuilder.IPAddressError, self).__init__(-11, self.message)
 
+    class MACAddressError(CPacketBuildException):
+        """
+        This exception is used to indicate an error on the MAC addressing part of the packet.
+        """
+        def __init__(self, message=''):
+            self._default_message = 'Illegal MAC address has been provided.'
+            self.message = message or self._default_message
+            super(CTRexPktBuilder.MACAddressError, self).__init__(-11, self.message)
+
     class VMVarNameExistsError(CPacketBuildException):
         """
-        This exception is used to indicate an error on the IP addressing part of the packet.
+        This exception is used to indicate a duplicate usage of VM variable.
         """
         def __init__(self, name, message=''):
-            self._default_message = 'The given VM name ({0})already exists as part of the stream.'.format(name)
+            self._default_message = 'The given VM name ({0}) already exists as part of the stream.'.format(name)
             self.message = message or self._default_message
             super(CTRexPktBuilder.VMVarNameExistsError, self).__init__(-21, self.message)
 
+    class VMVarNameError(CPacketBuildException):
+        """
+        This exception is used to indicate that an undefined VM var field name has been accessed.
+        """
+        def __init__(self, name, message=''):
+            self._default_message = "The given VM field name ({0}) is not defined and isn't legal.".format(name)
+            self.message = message or self._default_message
+            super(CTRexPktBuilder.VMVarNameError, self).__init__(-22, self.message)
+
     class VMVarFieldTypeError(CPacketBuildException):
         """
-        This exception is used to indicate an error on the IP addressing part of the packet.
+        This exception is used to indicate an illegal value has type has been given to VM variable field.
         """
         def __init__(self, name, ok_type, message=''):
             self._default_message = 'The desired value of field {field_name} is of type {field_type}, \
@@ -196,11 +614,11 @@ class CTRexPktBuilder(object):
                                                            field_type=type(name).__name__,
                                                            allowed_type=ok_type.__name__)
             self.message = message or self._default_message
-            super(CTRexPktBuilder.VMVarNameExistsError, self).__init__(-31, self.message)
+            super(CTRexPktBuilder.VMVarFieldTypeError, self).__init__(-31, self.message)
 
     class VMVarValueError(CPacketBuildException):
         """
-        This exception is used to indicate an error on the IP addressing part of the packet.
+        This exception is used to indicate an error an illegal value has been assigned to VM variable field.
         """
         def __init__(self, name, ok_opts, message=''):
             self._default_message = 'The desired value of field {field_name} is illegal.\n \
diff --git a/scripts/external_libs/dpkt-1.8.6/dpkt/dot1q.py b/scripts/external_libs/dpkt-1.8.6/dpkt/dot1q.py
new file mode 100644 (file)
index 0000000..ac6eb18
--- /dev/null
@@ -0,0 +1,1110 @@
+
+
+
+<!DOCTYPE html>
+<html lang="en" class=" is-copy-enabled">
+  <head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# object: http://ogp.me/ns/object# article: http://ogp.me/ns/article# profile: http://ogp.me/ns/profile#">
+    <meta charset='utf-8'>
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta http-equiv="Content-Language" content="en">
+    <meta name="viewport" content="width=1020">
+    
+    
+    <title>hexcap/dot1q.py at master Â· hexcap/hexcap</title>
+    <link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="GitHub">
+    <link rel="fluid-icon" href="https://github.com/fluidicon.png" title="GitHub">
+    <link rel="apple-touch-icon" sizes="57x57" href="/apple-touch-icon-114.png">
+    <link rel="apple-touch-icon" sizes="114x114" href="/apple-touch-icon-114.png">
+    <link rel="apple-touch-icon" sizes="72x72" href="/apple-touch-icon-144.png">
+    <link rel="apple-touch-icon" sizes="144x144" href="/apple-touch-icon-144.png">
+    <meta property="fb:app_id" content="1401488693436528">
+
+      <meta content="@github" name="twitter:site" /><meta content="summary" name="twitter:card" /><meta content="hexcap/hexcap" name="twitter:title" /><meta content="hexcap - ncurses based hex editor for pcap files" name="twitter:description" /><meta content="https://avatars3.githubusercontent.com/u/5732830?v=3&amp;s=400" name="twitter:image:src" />
+      <meta content="GitHub" property="og:site_name" /><meta content="object" property="og:type" /><meta content="https://avatars3.githubusercontent.com/u/5732830?v=3&amp;s=400" property="og:image" /><meta content="hexcap/hexcap" property="og:title" /><meta content="https://github.com/hexcap/hexcap" property="og:url" /><meta content="hexcap - ncurses based hex editor for pcap files" property="og:description" />
+      <meta name="browser-stats-url" content="https://api.github.com/_private/browser/stats">
+    <meta name="browser-errors-url" content="https://api.github.com/_private/browser/errors">
+    <link rel="assets" href="https://assets-cdn.github.com/">
+    <link rel="web-socket" href="wss://live.github.com/_sockets/NjE1MjA5Mjo4ZmY1YzBmYTBhNTQ0YzIzMTlkOWNlMDA3ZWQzNDM2Mzo1ZjcyZGY3ZTViMDQ2ODJlNjhjMDQzMDM5MjE3ZTIxNmI3ZTAwM2IyYmFhMDYyNjZlMTI0YmM1MDZlMzY2YTMw--521096dfee0071c38c7c0cbb37a19125d136bade">
+    <meta name="pjax-timeout" content="1000">
+    <link rel="sudo-modal" href="/sessions/sudo_modal">
+
+    <meta name="msapplication-TileImage" content="/windows-tile.png">
+    <meta name="msapplication-TileColor" content="#ffffff">
+    <meta name="selected-link" value="repo_source" data-pjax-transient>
+
+    <meta name="google-site-verification" content="KT5gs8h0wvaagLKAVWq8bbeNwnZZK1r1XQysX3xurLU">
+        <meta name="google-analytics" content="UA-3769691-2">
+
+    <meta content="collector.githubapp.com" name="octolytics-host" /><meta content="collector-cdn.github.com" name="octolytics-script-host" /><meta content="github" name="octolytics-app-id" /><meta content="C0764E39:0F18:5EE73AA:55ED75B0" name="octolytics-dimension-request_id" /><meta content="6152092" name="octolytics-actor-id" /><meta content="danklein10" name="octolytics-actor-login" /><meta content="a094d7c15626ff3dfc327b66cc85ebc7fb8bf99dd6502952c19c58263e0a4131" name="octolytics-actor-hash" />
+    
+    <meta content="Rails, view, blob#show" data-pjax-transient="true" name="analytics-event" />
+    <meta class="js-ga-set" name="dimension1" content="Logged In">
+      <meta class="js-ga-set" name="dimension4" content="Current repo nav">
+    <meta name="is-dotcom" content="true">
+        <meta name="hostname" content="github.com">
+    <meta name="user-login" content="danklein10">
+
+      <link rel="mask-icon" href="https://assets-cdn.github.com/pinned-octocat.svg" color="#4078c0">
+      <link rel="icon" type="image/x-icon" href="https://assets-cdn.github.com/favicon.ico">
+
+    <!-- </textarea> --><!-- '"` --><meta content="authenticity_token" name="csrf-param" />
+<meta content="38AGn6qyEzkQYOxGwzHrOFJlA8PVe1dGcw8fNEwl4eRgd01lt1QnIGHZA2qAEVIlvKBjuwlN1tMuWBkCq8W7Gg==" name="csrf-token" />
+    <meta content="ac3d26b394d1e74b2cb512f7e309125427b6279a" name="form-nonce" />
+
+    <link crossorigin="anonymous" href="https://assets-cdn.github.com/assets/github-20ef81825cb67c29f98949804b58cf91dbf3de37cb09ccaa59c93970272e0b35.css" media="all" rel="stylesheet" />
+    <link crossorigin="anonymous" href="https://assets-cdn.github.com/assets/github2-726d0810d308c486e226fbd3d4392b84987fddf613a311c76e816dbaf2461c38.css" media="all" rel="stylesheet" />
+    
+    
+
+
+    <meta http-equiv="x-pjax-version" content="e21519a1f589ffb51c1a9b6cfaa2bbfc">
+
+      
+  <meta name="description" content="hexcap - ncurses based hex editor for pcap files">
+  <meta name="go-import" content="github.com/hexcap/hexcap git https://github.com/hexcap/hexcap.git">
+
+  <meta content="5732830" name="octolytics-dimension-user_id" /><meta content="hexcap" name="octolytics-dimension-user_login" /><meta content="9747136" name="octolytics-dimension-repository_id" /><meta content="hexcap/hexcap" name="octolytics-dimension-repository_nwo" /><meta content="true" name="octolytics-dimension-repository_public" /><meta content="false" name="octolytics-dimension-repository_is_fork" /><meta content="9747136" name="octolytics-dimension-repository_network_root_id" /><meta content="hexcap/hexcap" name="octolytics-dimension-repository_network_root_nwo" />
+  <link href="https://github.com/hexcap/hexcap/commits/master.atom" rel="alternate" title="Recent Commits to hexcap:master" type="application/atom+xml">
+
+  </head>
+
+
+  <body class="logged_in  env-production windows vis-public page-blob">
+    <a href="#start-of-content" tabindex="1" class="accessibility-aid js-skip-to-content">Skip to content</a>
+
+    
+    
+    
+
+
+
+      <div class="header header-logged-in true" role="banner">
+  <div class="container clearfix">
+
+    <a class="header-logo-invertocat" href="https://github.com/orgs/cisco-system-traffic-generator/dashboard" data-hotkey="g d" aria-label="Homepage" data-ga-click="Header, go to dashboard, icon:logo">
+  <span class="mega-octicon octicon-mark-github"></span>
+</a>
+
+
+      <div class="site-search repo-scope js-site-search" role="search">
+          <!-- </textarea> --><!-- '"` --><form accept-charset="UTF-8" action="/hexcap/hexcap/search" class="js-site-search-form" data-global-search-url="/search" data-repo-search-url="/hexcap/hexcap/search" method="get"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="&#x2713;" /></div>
+  <label class="js-chromeless-input-container form-control">
+    <div class="scope-badge">This repository</div>
+    <input type="text"
+      class="js-site-search-focus js-site-search-field is-clearable chromeless-input"
+      data-hotkey="s"
+      name="q"
+      placeholder="Search"
+      aria-label="Search this repository"
+      data-global-scope-placeholder="Search GitHub"
+      data-repo-scope-placeholder="Search"
+      tabindex="1"
+      autocapitalize="off">
+  </label>
+</form>
+      </div>
+
+      <ul class="header-nav left" role="navigation">
+        <li class="header-nav-item">
+          <a href="/pulls" class="js-selected-navigation-item header-nav-link" data-ga-click="Header, click, Nav menu - item:pulls context:user" data-hotkey="g p" data-selected-links="/pulls /pulls/assigned /pulls/mentioned /pulls">
+            Pull requests
+</a>        </li>
+        <li class="header-nav-item">
+          <a href="/issues" class="js-selected-navigation-item header-nav-link" data-ga-click="Header, click, Nav menu - item:issues context:user" data-hotkey="g i" data-selected-links="/issues /issues/assigned /issues/mentioned /issues">
+            Issues
+</a>        </li>
+          <li class="header-nav-item">
+            <a class="header-nav-link" href="https://gist.github.com/" data-ga-click="Header, go to gist, text:gist">Gist</a>
+          </li>
+      </ul>
+
+    
+<ul class="header-nav user-nav right" id="user-links">
+  <li class="header-nav-item">
+      <span class="js-socket-channel js-updatable-content"
+        data-channel="notification-changed:danklein10"
+        data-url="/notifications/header">
+      <a href="/notifications" aria-label="You have no unread notifications" class="header-nav-link notification-indicator tooltipped tooltipped-s" data-ga-click="Header, go to notifications, icon:read" data-hotkey="g n">
+          <span class="mail-status all-read"></span>
+          <span class="octicon octicon-bell"></span>
+</a>  </span>
+
+  </li>
+
+  <li class="header-nav-item dropdown js-menu-container">
+    <a class="header-nav-link tooltipped tooltipped-s js-menu-target" href="/new"
+       aria-label="Create new…"
+       data-ga-click="Header, create new, icon:add">
+      <span class="octicon octicon-plus left"></span>
+      <span class="dropdown-caret"></span>
+    </a>
+
+    <div class="dropdown-menu-content js-menu-content">
+      <ul class="dropdown-menu dropdown-menu-sw">
+        
+<a class="dropdown-item" href="/new" data-ga-click="Header, create new repository">
+  New repository
+</a>
+
+
+  <a class="dropdown-item" href="/organizations/new" data-ga-click="Header, create new organization">
+    New organization
+  </a>
+
+
+
+  <div class="dropdown-divider"></div>
+  <div class="dropdown-header">
+    <span title="hexcap/hexcap">This repository</span>
+  </div>
+    <a class="dropdown-item" href="/hexcap/hexcap/issues/new" data-ga-click="Header, create new issue">
+      New issue
+    </a>
+
+      </ul>
+    </div>
+  </li>
+
+  <li class="header-nav-item dropdown js-menu-container">
+    <a class="header-nav-link name tooltipped tooltipped-s js-menu-target" href="/danklein10"
+       aria-label="View profile and more"
+       data-ga-click="Header, show menu, icon:avatar">
+      <img alt="@danklein10" class="avatar" height="20" src="https://avatars1.githubusercontent.com/u/6152092?v=3&amp;s=40" width="20" />
+      <span class="dropdown-caret"></span>
+    </a>
+
+    <div class="dropdown-menu-content js-menu-content">
+      <div class="dropdown-menu dropdown-menu-sw">
+        <div class="dropdown-header header-nav-current-user css-truncate">
+          Signed in as <strong class="css-truncate-target">danklein10</strong>
+        </div>
+        <div class="dropdown-divider"></div>
+
+        <a class="dropdown-item" href="/danklein10" data-ga-click="Header, go to profile, text:your profile">
+          Your profile
+        </a>
+        <a class="dropdown-item" href="/stars" data-ga-click="Header, go to starred repos, text:your stars">
+          Your stars
+        </a>
+        <a class="dropdown-item" href="/explore" data-ga-click="Header, go to explore, text:explore">
+          Explore
+        </a>
+        <a class="dropdown-item" href="https://help.github.com" data-ga-click="Header, go to help, text:help">
+          Help
+        </a>
+        <div class="dropdown-divider"></div>
+
+        <a class="dropdown-item" href="/settings/profile" data-ga-click="Header, go to settings, icon:settings">
+          Settings
+        </a>
+
+        <!-- </textarea> --><!-- '"` --><form accept-charset="UTF-8" action="/logout" class="logout-form" data-form-nonce="ac3d26b394d1e74b2cb512f7e309125427b6279a" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="&#x2713;" /><input name="authenticity_token" type="hidden" value="N8m5Se0EOXw1Ui0v3MX+KEHzjZjgzzddbmLRz+Tv22u2OVzVM6Ztj/KT5sYvuJ3Krimi+7iKMVFWvkrAdu18aQ==" /></div>
+          <button class="dropdown-item dropdown-signout" data-ga-click="Header, sign out, icon:logout">
+            Sign out
+          </button>
+</form>      </div>
+    </div>
+  </li>
+</ul>
+
+
+    
+  </div>
+</div>
+
+      
+
+      
+
+
+    <div id="start-of-content" class="accessibility-aid"></div>
+
+    <div id="js-flash-container">
+</div>
+
+
+        <div itemscope itemtype="http://schema.org/WebPage">
+    <div class="pagehead repohead instapaper_ignore readability-menu">
+      <div class="container">
+
+        <div class="clearfix">
+          
+<ul class="pagehead-actions">
+
+  <li>
+      <!-- </textarea> --><!-- '"` --><form accept-charset="UTF-8" action="/notifications/subscribe" class="js-social-container" data-autosubmit="true" data-form-nonce="ac3d26b394d1e74b2cb512f7e309125427b6279a" data-remote="true" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="&#x2713;" /><input name="authenticity_token" type="hidden" value="oH+kDkXDGZ0VSv7TIzO+kQpjN+0KO7kmbf3Ltx0zg8M7XTbRwpsfJQpVrG2t3+0JACcc2FDlXzzNGCHk8MBhIA==" /></div>    <input id="repository_id" name="repository_id" type="hidden" value="9747136" />
+
+      <div class="select-menu js-menu-container js-select-menu">
+        <a href="/hexcap/hexcap/subscription"
+          class="btn btn-sm btn-with-count select-menu-button js-menu-target" role="button" tabindex="0" aria-haspopup="true"
+          data-ga-click="Repository, click Watch settings, action:blob#show">
+          <span class="js-select-button">
+            <span class="octicon octicon-eye"></span>
+            Watch
+          </span>
+        </a>
+        <a class="social-count js-social-count" href="/hexcap/hexcap/watchers">
+          1
+        </a>
+
+        <div class="select-menu-modal-holder">
+          <div class="select-menu-modal subscription-menu-modal js-menu-content" aria-hidden="true">
+            <div class="select-menu-header">
+              <span class="select-menu-title">Notifications</span>
+              <span class="octicon octicon-x js-menu-close" role="button" aria-label="Close"></span>
+            </div>
+
+            <div class="select-menu-list js-navigation-container" role="menu">
+
+              <div class="select-menu-item js-navigation-item selected" role="menuitem" tabindex="0">
+                <span class="select-menu-item-icon octicon octicon-check"></span>
+                <div class="select-menu-item-text">
+                  <input checked="checked" id="do_included" name="do" type="radio" value="included" />
+                  <span class="select-menu-item-heading">Not watching</span>
+                  <span class="description">Be notified when participating or @mentioned.</span>
+                  <span class="js-select-button-text hidden-select-button-text">
+                    <span class="octicon octicon-eye"></span>
+                    Watch
+                  </span>
+                </div>
+              </div>
+
+              <div class="select-menu-item js-navigation-item " role="menuitem" tabindex="0">
+                <span class="select-menu-item-icon octicon octicon octicon-check"></span>
+                <div class="select-menu-item-text">
+                  <input id="do_subscribed" name="do" type="radio" value="subscribed" />
+                  <span class="select-menu-item-heading">Watching</span>
+                  <span class="description">Be notified of all conversations.</span>
+                  <span class="js-select-button-text hidden-select-button-text">
+                    <span class="octicon octicon-eye"></span>
+                    Unwatch
+                  </span>
+                </div>
+              </div>
+
+              <div class="select-menu-item js-navigation-item " role="menuitem" tabindex="0">
+                <span class="select-menu-item-icon octicon octicon-check"></span>
+                <div class="select-menu-item-text">
+                  <input id="do_ignore" name="do" type="radio" value="ignore" />
+                  <span class="select-menu-item-heading">Ignoring</span>
+                  <span class="description">Never be notified.</span>
+                  <span class="js-select-button-text hidden-select-button-text">
+                    <span class="octicon octicon-mute"></span>
+                    Stop ignoring
+                  </span>
+                </div>
+              </div>
+
+            </div>
+
+          </div>
+        </div>
+      </div>
+</form>
+  </li>
+
+  <li>
+    
+  <div class="js-toggler-container js-social-container starring-container ">
+
+    <!-- </textarea> --><!-- '"` --><form accept-charset="UTF-8" action="/hexcap/hexcap/unstar" class="js-toggler-form starred js-unstar-button" data-form-nonce="ac3d26b394d1e74b2cb512f7e309125427b6279a" data-remote="true" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="&#x2713;" /><input name="authenticity_token" type="hidden" value="JgpGes1Y6iXFjyvt8la+hHwYGri9NzgLW6Fm/4Irc/gcJTASeXTPJc4DMFLoiG1jiPAke7zt61iMUnXyibSo/g==" /></div>
+      <button
+        class="btn btn-sm btn-with-count js-toggler-target"
+        aria-label="Unstar this repository" title="Unstar hexcap/hexcap"
+        data-ga-click="Repository, click unstar button, action:blob#show; text:Unstar">
+        <span class="octicon octicon-star"></span>
+        Unstar
+      </button>
+        <a class="social-count js-social-count" href="/hexcap/hexcap/stargazers">
+          9
+        </a>
+</form>
+    <!-- </textarea> --><!-- '"` --><form accept-charset="UTF-8" action="/hexcap/hexcap/star" class="js-toggler-form unstarred js-star-button" data-form-nonce="ac3d26b394d1e74b2cb512f7e309125427b6279a" data-remote="true" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="&#x2713;" /><input name="authenticity_token" type="hidden" value="dWxeklRDfQhNmhahVOQuj1ONldm0pP66i9Wgz7xH3GeyuP9g6mXjnP/tSyp4qMR263/J9ch0SGGk5ownYVPsWg==" /></div>
+      <button
+        class="btn btn-sm btn-with-count js-toggler-target"
+        aria-label="Star this repository" title="Star hexcap/hexcap"
+        data-ga-click="Repository, click star button, action:blob#show; text:Star">
+        <span class="octicon octicon-star"></span>
+        Star
+      </button>
+        <a class="social-count js-social-count" href="/hexcap/hexcap/stargazers">
+          9
+        </a>
+</form>  </div>
+
+  </li>
+
+        <li>
+          <a href="#fork-destination-box" class="btn btn-sm btn-with-count"
+              title="Fork your own copy of hexcap/hexcap to your account"
+              aria-label="Fork your own copy of hexcap/hexcap to your account"
+              rel="facebox"
+              data-ga-click="Repository, show fork modal, action:blob#show; text:Fork">
+            <span class="octicon octicon-repo-forked"></span>
+            Fork
+          </a>
+          <a href="/hexcap/hexcap/network" class="social-count">0</a>
+
+          <div id="fork-destination-box" style="display: none;">
+            <h2 class="facebox-header" data-facebox-id="facebox-header">Where should we fork this repository?</h2>
+            <include-fragment src=""
+                class="js-fork-select-fragment fork-select-fragment"
+                data-url="/hexcap/hexcap/fork?fragment=1">
+              <img alt="Loading" height="64" src="https://assets-cdn.github.com/images/spinners/octocat-spinner-128.gif" width="64" />
+            </include-fragment>
+          </div>
+        </li>
+
+</ul>
+
+          <h1 itemscope itemtype="http://data-vocabulary.org/Breadcrumb" class="entry-title public ">
+  <span class="mega-octicon octicon-repo"></span>
+  <span class="author"><a href="/hexcap" class="url fn" itemprop="url" rel="author"><span itemprop="title">hexcap</span></a></span><!--
+--><span class="path-divider">/</span><!--
+--><strong><a href="/hexcap/hexcap" data-pjax="#js-repo-pjax-container">hexcap</a></strong>
+
+  <span class="page-context-loader">
+    <img alt="" height="16" src="https://assets-cdn.github.com/images/spinners/octocat-spinner-32.gif" width="16" />
+  </span>
+
+</h1>
+
+        </div>
+      </div>
+    </div>
+
+    <div class="container">
+      <div class="repository-with-sidebar repo-container new-discussion-timeline ">
+        <div class="repository-sidebar clearfix">
+          
+<nav class="sunken-menu repo-nav js-repo-nav js-sidenav-container-pjax js-octicon-loaders"
+     role="navigation"
+     data-pjax="#js-repo-pjax-container"
+     data-issue-count-url="/hexcap/hexcap/issues/counts">
+  <ul class="sunken-menu-group">
+    <li class="tooltipped tooltipped-w" aria-label="Code">
+      <a href="/hexcap/hexcap" aria-label="Code" aria-selected="true" class="js-selected-navigation-item selected sunken-menu-item" data-hotkey="g c" data-selected-links="repo_source repo_downloads repo_commits repo_releases repo_tags repo_branches /hexcap/hexcap">
+        <span class="octicon octicon-code"></span> <span class="full-word">Code</span>
+        <img alt="" class="mini-loader" height="16" src="https://assets-cdn.github.com/images/spinners/octocat-spinner-32.gif" width="16" />
+</a>    </li>
+
+      <li class="tooltipped tooltipped-w" aria-label="Issues">
+        <a href="/hexcap/hexcap/issues" aria-label="Issues" class="js-selected-navigation-item sunken-menu-item" data-hotkey="g i" data-selected-links="repo_issues repo_labels repo_milestones /hexcap/hexcap/issues">
+          <span class="octicon octicon-issue-opened"></span> <span class="full-word">Issues</span>
+          <span class="js-issue-replace-counter"></span>
+          <img alt="" class="mini-loader" height="16" src="https://assets-cdn.github.com/images/spinners/octocat-spinner-32.gif" width="16" />
+</a>      </li>
+
+    <li class="tooltipped tooltipped-w" aria-label="Pull requests">
+      <a href="/hexcap/hexcap/pulls" aria-label="Pull requests" class="js-selected-navigation-item sunken-menu-item" data-hotkey="g p" data-selected-links="repo_pulls /hexcap/hexcap/pulls">
+          <span class="octicon octicon-git-pull-request"></span> <span class="full-word">Pull requests</span>
+          <span class="js-pull-replace-counter"></span>
+          <img alt="" class="mini-loader" height="16" src="https://assets-cdn.github.com/images/spinners/octocat-spinner-32.gif" width="16" />
+</a>    </li>
+
+      <li class="tooltipped tooltipped-w" aria-label="Wiki">
+        <a href="/hexcap/hexcap/wiki" aria-label="Wiki" class="js-selected-navigation-item sunken-menu-item" data-hotkey="g w" data-selected-links="repo_wiki /hexcap/hexcap/wiki">
+          <span class="octicon octicon-book"></span> <span class="full-word">Wiki</span>
+          <img alt="" class="mini-loader" height="16" src="https://assets-cdn.github.com/images/spinners/octocat-spinner-32.gif" width="16" />
+</a>      </li>
+  </ul>
+  <div class="sunken-menu-separator"></div>
+  <ul class="sunken-menu-group">
+
+    <li class="tooltipped tooltipped-w" aria-label="Pulse">
+      <a href="/hexcap/hexcap/pulse" aria-label="Pulse" class="js-selected-navigation-item sunken-menu-item" data-selected-links="pulse /hexcap/hexcap/pulse">
+        <span class="octicon octicon-pulse"></span> <span class="full-word">Pulse</span>
+        <img alt="" class="mini-loader" height="16" src="https://assets-cdn.github.com/images/spinners/octocat-spinner-32.gif" width="16" />
+</a>    </li>
+
+    <li class="tooltipped tooltipped-w" aria-label="Graphs">
+      <a href="/hexcap/hexcap/graphs" aria-label="Graphs" class="js-selected-navigation-item sunken-menu-item" data-selected-links="repo_graphs repo_contributors /hexcap/hexcap/graphs">
+        <span class="octicon octicon-graph"></span> <span class="full-word">Graphs</span>
+        <img alt="" class="mini-loader" height="16" src="https://assets-cdn.github.com/images/spinners/octocat-spinner-32.gif" width="16" />
+</a>    </li>
+  </ul>
+
+
+</nav>
+
+            <div class="only-with-full-nav">
+                
+<div class="js-clone-url clone-url open"
+  data-protocol-type="http">
+  <h3><span class="text-emphasized">HTTPS</span> clone URL</h3>
+  <div class="input-group js-zeroclipboard-container">
+    <input type="text" class="input-mini input-monospace js-url-field js-zeroclipboard-target"
+           value="https://github.com/hexcap/hexcap.git" readonly="readonly" aria-label="HTTPS clone URL">
+    <span class="input-group-button">
+      <button aria-label="Copy to clipboard" class="js-zeroclipboard btn btn-sm zeroclipboard-button tooltipped tooltipped-s" data-copied-hint="Copied!" type="button"><span class="octicon octicon-clippy"></span></button>
+    </span>
+  </div>
+</div>
+
+  
+<div class="js-clone-url clone-url "
+  data-protocol-type="ssh">
+  <h3><span class="text-emphasized">SSH</span> clone URL</h3>
+  <div class="input-group js-zeroclipboard-container">
+    <input type="text" class="input-mini input-monospace js-url-field js-zeroclipboard-target"
+           value="[email protected]:hexcap/hexcap.git" readonly="readonly" aria-label="SSH clone URL">
+    <span class="input-group-button">
+      <button aria-label="Copy to clipboard" class="js-zeroclipboard btn btn-sm zeroclipboard-button tooltipped tooltipped-s" data-copied-hint="Copied!" type="button"><span class="octicon octicon-clippy"></span></button>
+    </span>
+  </div>
+</div>
+
+  
+<div class="js-clone-url clone-url "
+  data-protocol-type="subversion">
+  <h3><span class="text-emphasized">Subversion</span> checkout URL</h3>
+  <div class="input-group js-zeroclipboard-container">
+    <input type="text" class="input-mini input-monospace js-url-field js-zeroclipboard-target"
+           value="https://github.com/hexcap/hexcap" readonly="readonly" aria-label="Subversion checkout URL">
+    <span class="input-group-button">
+      <button aria-label="Copy to clipboard" class="js-zeroclipboard btn btn-sm zeroclipboard-button tooltipped tooltipped-s" data-copied-hint="Copied!" type="button"><span class="octicon octicon-clippy"></span></button>
+    </span>
+  </div>
+</div>
+
+
+
+  <div class="clone-options">You can clone with
+    <!-- </textarea> --><!-- '"` --><form accept-charset="UTF-8" action="/users/set_protocol?protocol_selector=http&amp;protocol_type=clone" class="inline-form js-clone-selector-form is-enabled" data-form-nonce="ac3d26b394d1e74b2cb512f7e309125427b6279a" data-remote="true" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="&#x2713;" /><input name="authenticity_token" type="hidden" value="T3BePf/8xkb6d6hQ1WxSRPwxd0cVHJD04Qcvw7XDgDf2KRpWMc1KDQXjof8YNA9SMwlC0J+/rLdH0uf+d3FtGw==" /></div><button class="btn-link js-clone-selector" data-protocol="http" type="submit">HTTPS</button></form>, <!-- </textarea> --><!-- '"` --><form accept-charset="UTF-8" action="/users/set_protocol?protocol_selector=ssh&amp;protocol_type=clone" class="inline-form js-clone-selector-form is-enabled" data-form-nonce="ac3d26b394d1e74b2cb512f7e309125427b6279a" data-remote="true" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="&#x2713;" /><input name="authenticity_token" type="hidden" value="3ZZHZ1uyO2YyXJllsAEy6Uyl5IzKd9pnlMqcxOr6siiIUSr9yHihssjv9CD7IZ6VhlEbKvHuVODR80DN4nF2MQ==" /></div><button class="btn-link js-clone-selector" data-protocol="ssh" type="submit">SSH</button></form>, or <!-- </textarea> --><!-- '"` --><form accept-charset="UTF-8" action="/users/set_protocol?protocol_selector=subversion&amp;protocol_type=clone" class="inline-form js-clone-selector-form is-enabled" data-form-nonce="ac3d26b394d1e74b2cb512f7e309125427b6279a" data-remote="true" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="&#x2713;" /><input name="authenticity_token" type="hidden" value="kwiF8pqkQsMfxWxA65L8G9PRBro/xPHPAN3GTPg9dbRP/w7eUuTJu4tyT6Kxk2iP8bRpg53eQ+KYY8UiaGq19A==" /></div><button class="btn-link js-clone-selector" data-protocol="subversion" type="submit">Subversion</button></form>.
+    <a href="https://help.github.com/articles/which-remote-url-should-i-use" class="help tooltipped tooltipped-n" aria-label="Get help on which URL is right for you.">
+      <span class="octicon octicon-question"></span>
+    </a>
+  </div>
+    <a href="https://windows.github.com" class="btn btn-sm sidebar-button" title="Save hexcap/hexcap to your computer and use it in GitHub Desktop." aria-label="Save hexcap/hexcap to your computer and use it in GitHub Desktop.">
+      <span class="octicon octicon-desktop-download"></span>
+      Clone in Desktop
+    </a>
+
+              <a href="/hexcap/hexcap/archive/master.zip"
+                 class="btn btn-sm sidebar-button"
+                 aria-label="Download the contents of hexcap/hexcap as a zip file"
+                 title="Download the contents of hexcap/hexcap as a zip file"
+                 rel="nofollow">
+                <span class="octicon octicon-cloud-download"></span>
+                Download ZIP
+              </a>
+            </div>
+        </div>
+        <div id="js-repo-pjax-container" class="repository-content context-loader-container" data-pjax-container>
+
+          
+
+<a href="/hexcap/hexcap/blob/ee8686e7c7a4cc4a1d836895fda01012fb930251/dpkt/dpkt/dot1q.py" class="hidden js-permalink-shortcut" data-hotkey="y">Permalink</a>
+
+<!-- blob contrib key: blob_contributors:v21:46bde8b0229c416e6f538e044b428839 -->
+
+  <div class="file-navigation js-zeroclipboard-container">
+    
+<div class="select-menu js-menu-container js-select-menu left">
+  <span class="btn btn-sm select-menu-button js-menu-target css-truncate" data-hotkey="w"
+    data-ref="master"
+    title="master"
+    role="button" aria-label="Switch branches or tags" tabindex="0" aria-haspopup="true">
+    <i>Branch:</i>
+    <span class="js-select-button css-truncate-target">master</span>
+  </span>
+
+  <div class="select-menu-modal-holder js-menu-content js-navigation-container" data-pjax aria-hidden="true">
+
+    <div class="select-menu-modal">
+      <div class="select-menu-header">
+        <span class="select-menu-title">Switch branches/tags</span>
+        <span class="octicon octicon-x js-menu-close" role="button" aria-label="Close"></span>
+      </div>
+
+      <div class="select-menu-filters">
+        <div class="select-menu-text-filter">
+          <input type="text" aria-label="Filter branches/tags" id="context-commitish-filter-field" class="js-filterable-field js-navigation-enable" placeholder="Filter branches/tags">
+        </div>
+        <div class="select-menu-tabs">
+          <ul>
+            <li class="select-menu-tab">
+              <a href="#" data-tab-filter="branches" data-filter-placeholder="Filter branches/tags" class="js-select-menu-tab" role="tab">Branches</a>
+            </li>
+            <li class="select-menu-tab">
+              <a href="#" data-tab-filter="tags" data-filter-placeholder="Find a tag…" class="js-select-menu-tab" role="tab">Tags</a>
+            </li>
+          </ul>
+        </div>
+      </div>
+
+      <div class="select-menu-list select-menu-tab-bucket js-select-menu-tab-bucket" data-tab-filter="branches" role="menu">
+
+        <div data-filterable-for="context-commitish-filter-field" data-filterable-type="substring">
+
+
+            <a class="select-menu-item js-navigation-item js-navigation-open selected"
+               href="/hexcap/hexcap/blob/master/dpkt/dpkt/dot1q.py"
+               data-name="master"
+               data-skip-pjax="true"
+               rel="nofollow">
+              <span class="select-menu-item-icon octicon octicon-check"></span>
+              <span class="select-menu-item-text css-truncate-target" title="master">
+                master
+              </span>
+            </a>
+        </div>
+
+          <div class="select-menu-no-results">Nothing to show</div>
+      </div>
+
+      <div class="select-menu-list select-menu-tab-bucket js-select-menu-tab-bucket" data-tab-filter="tags">
+        <div data-filterable-for="context-commitish-filter-field" data-filterable-type="substring">
+
+
+        </div>
+
+        <div class="select-menu-no-results">Nothing to show</div>
+      </div>
+
+    </div>
+  </div>
+</div>
+
+    <div class="btn-group right">
+      <a href="/hexcap/hexcap/find/master"
+            class="js-show-file-finder btn btn-sm empty-icon tooltipped tooltipped-nw"
+            data-pjax
+            data-hotkey="t"
+            aria-label="Quickly jump between files">
+        <span class="octicon octicon-list-unordered"></span>
+      </a>
+      <button aria-label="Copy file path to clipboard" class="js-zeroclipboard btn btn-sm zeroclipboard-button tooltipped tooltipped-s" data-copied-hint="Copied!" type="button"><span class="octicon octicon-clippy"></span></button>
+    </div>
+
+    <div class="breadcrumb js-zeroclipboard-target">
+      <span class="repo-root js-repo-root"><span itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb"><a href="/hexcap/hexcap" class="" data-branch="master" data-pjax="true" itemscope="url"><span itemprop="title">hexcap</span></a></span></span><span class="separator">/</span><span itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb"><a href="/hexcap/hexcap/tree/master/dpkt" class="" data-branch="master" data-pjax="true" itemscope="url"><span itemprop="title">dpkt</span></a></span><span class="separator">/</span><span itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb"><a href="/hexcap/hexcap/tree/master/dpkt/dpkt" class="" data-branch="master" data-pjax="true" itemscope="url"><span itemprop="title">dpkt</span></a></span><span class="separator">/</span><strong class="final-path">dot1q.py</strong>
+    </div>
+  </div>
+
+
+  <div class="commit file-history-tease">
+    <div class="file-history-tease-header">
+        <img alt="@smutt" class="avatar" height="24" src="https://avatars3.githubusercontent.com/u/1223204?v=3&amp;s=48" width="24" />
+        <span class="author"><a href="/smutt" rel="contributor">smutt</a></span>
+        <time datetime="2014-06-11T23:12:09Z" is="relative-time">Jun 11, 2014</time>
+        <div class="commit-title">
+            <a href="/hexcap/hexcap/commit/1e35c451e857e98e9a572700f88b89e3847e53aa" class="message" data-pjax="true" title="Renamed dpkt-read-only/ to dpkt/">Renamed dpkt-read-only/ to dpkt/</a>
+        </div>
+    </div>
+
+    <div class="participation">
+      <p class="quickstat">
+        <a href="#blob_contributors_box" rel="facebox">
+          <strong>1</strong>
+           contributor
+        </a>
+      </p>
+      
+    </div>
+    <div id="blob_contributors_box" style="display:none">
+      <h2 class="facebox-header" data-facebox-id="facebox-header">Users who have contributed to this file</h2>
+      <ul class="facebox-user-list" data-facebox-id="facebox-description">
+          <li class="facebox-user-list-item">
+            <img alt="@smutt" height="24" src="https://avatars3.githubusercontent.com/u/1223204?v=3&amp;s=48" width="24" />
+            <a href="/smutt">smutt</a>
+          </li>
+      </ul>
+    </div>
+  </div>
+
+<div class="file">
+  <div class="file-header">
+    <div class="file-actions">
+
+      <div class="btn-group">
+        <a href="/hexcap/hexcap/raw/master/dpkt/dpkt/dot1q.py" class="btn btn-sm " id="raw-url">Raw</a>
+          <a href="/hexcap/hexcap/blame/master/dpkt/dpkt/dot1q.py" class="btn btn-sm js-update-url-with-hash">Blame</a>
+        <a href="/hexcap/hexcap/commits/master/dpkt/dpkt/dot1q.py" class="btn btn-sm " rel="nofollow">History</a>
+      </div>
+
+        <a class="octicon-btn tooltipped tooltipped-nw"
+           href="https://windows.github.com"
+           aria-label="Open this file in GitHub Desktop"
+           data-ga-click="Repository, open with desktop, type:windows">
+            <span class="octicon octicon-device-desktop"></span>
+        </a>
+
+            <!-- </textarea> --><!-- '"` --><form accept-charset="UTF-8" action="/hexcap/hexcap/edit/master/dpkt/dpkt/dot1q.py" class="inline-form" data-form-nonce="ac3d26b394d1e74b2cb512f7e309125427b6279a" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="&#x2713;" /><input name="authenticity_token" type="hidden" value="SU0n03ayv7838ksqISz81DL+rsSEUTJ8VWf2X1NBBMo9p5gPaM9YXCNa6Sezt7xjvJJLjZP1eBMl7fduX9rrpw==" /></div>
+              <button class="octicon-btn tooltipped tooltipped-n" type="submit" aria-label="Fork this project and edit the file" data-hotkey="e" data-disable-with>
+                <span class="octicon octicon-pencil"></span>
+              </button>
+</form>
+          <!-- </textarea> --><!-- '"` --><form accept-charset="UTF-8" action="/hexcap/hexcap/delete/master/dpkt/dpkt/dot1q.py" class="inline-form" data-form-nonce="ac3d26b394d1e74b2cb512f7e309125427b6279a" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="&#x2713;" /><input name="authenticity_token" type="hidden" value="e3j1i6vBsJAzzNVXfe8zggdfxap3rh2bJPDs6A9KfsXTcxVc8/fqgnyjGgf61qd9qj5NUp6K+wZ7/IU756EzQA==" /></div>
+            <button class="octicon-btn octicon-btn-danger tooltipped tooltipped-n" type="submit" aria-label="Fork this project and delete this file" data-disable-with>
+              <span class="octicon octicon-trashcan"></span>
+            </button>
+</form>    </div>
+
+    <div class="file-info">
+        <span class="file-mode" title="File mode">executable file</span>
+        <span class="file-info-divider"></span>
+        93 lines (79 sloc)
+        <span class="file-info-divider"></span>
+      3.071 kB
+    </div>
+  </div>
+  
+
+  <div class="blob-wrapper data type-python">
+      <table class="highlight tab-size js-file-line-container" data-tab-size="8">
+      <tr>
+        <td id="L1" class="blob-num js-line-number" data-line-number="1"></td>
+        <td id="LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-s"><span class="pl-pds">&quot;&quot;&quot;</span>IEEE 802.1q<span class="pl-pds">&quot;&quot;&quot;</span></span></td>
+      </tr>
+      <tr>
+        <td id="L2" class="blob-num js-line-number" data-line-number="2"></td>
+        <td id="LC2" class="blob-code blob-code-inner js-file-line">
+</td>
+      </tr>
+      <tr>
+        <td id="L3" class="blob-num js-line-number" data-line-number="3"></td>
+        <td id="LC3" class="blob-code blob-code-inner js-file-line"><span class="pl-k">import</span> struct</td>
+      </tr>
+      <tr>
+        <td id="L4" class="blob-num js-line-number" data-line-number="4"></td>
+        <td id="LC4" class="blob-code blob-code-inner js-file-line"><span class="pl-k">import</span> dpkt</td>
+      </tr>
+      <tr>
+        <td id="L5" class="blob-num js-line-number" data-line-number="5"></td>
+        <td id="LC5" class="blob-code blob-code-inner js-file-line">
+</td>
+      </tr>
+      <tr>
+        <td id="L6" class="blob-num js-line-number" data-line-number="6"></td>
+        <td id="LC6" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Ethernet payload types - http://standards.ieee.org/regauth/ethertype</span></td>
+      </tr>
+      <tr>
+        <td id="L7" class="blob-num js-line-number" data-line-number="7"></td>
+        <td id="LC7" class="blob-code blob-code-inner js-file-line">ETH_TYPE_PUP       <span class="pl-k">=</span> <span class="pl-c1">0x</span>0200           <span class="pl-c"># PUP protocol</span></td>
+      </tr>
+      <tr>
+        <td id="L8" class="blob-num js-line-number" data-line-number="8"></td>
+        <td id="LC8" class="blob-code blob-code-inner js-file-line">ETH_TYPE_IP        <span class="pl-k">=</span> <span class="pl-c1">0x</span>0800           <span class="pl-c"># IP protocol</span></td>
+      </tr>
+      <tr>
+        <td id="L9" class="blob-num js-line-number" data-line-number="9"></td>
+        <td id="LC9" class="blob-code blob-code-inner js-file-line">ETH_TYPE_ARP       <span class="pl-k">=</span> <span class="pl-c1">0x</span>0806           <span class="pl-c"># address resolution protocol</span></td>
+      </tr>
+      <tr>
+        <td id="L10" class="blob-num js-line-number" data-line-number="10"></td>
+        <td id="LC10" class="blob-code blob-code-inner js-file-line">ETH_TYPE_CDP      <span class="pl-k">=</span> <span class="pl-c1">0x</span>2000           <span class="pl-c"># Cisco Discovery Protocol</span></td>
+      </tr>
+      <tr>
+        <td id="L11" class="blob-num js-line-number" data-line-number="11"></td>
+        <td id="LC11" class="blob-code blob-code-inner js-file-line">ETH_TYPE_DTP      <span class="pl-k">=</span> <span class="pl-c1">0x</span>2004           <span class="pl-c"># Cisco Dynamic Trunking Protocol</span></td>
+      </tr>
+      <tr>
+        <td id="L12" class="blob-num js-line-number" data-line-number="12"></td>
+        <td id="LC12" class="blob-code blob-code-inner js-file-line">ETH_TYPE_REVARP   <span class="pl-k">=</span> <span class="pl-c1">0x</span>8035           <span class="pl-c"># reverse addr resolution protocol</span></td>
+      </tr>
+      <tr>
+        <td id="L13" class="blob-num js-line-number" data-line-number="13"></td>
+        <td id="LC13" class="blob-code blob-code-inner js-file-line">ETH_TYPE_DOT1Q    <span class="pl-k">=</span> <span class="pl-c1">0x</span>8100           <span class="pl-c"># IEEE 802.1Q VLAN tagging</span></td>
+      </tr>
+      <tr>
+        <td id="L14" class="blob-num js-line-number" data-line-number="14"></td>
+        <td id="LC14" class="blob-code blob-code-inner js-file-line">ETH_TYPE_IPX      <span class="pl-k">=</span> <span class="pl-c1">0x</span>8137           <span class="pl-c"># Internetwork Packet Exchange</span></td>
+      </tr>
+      <tr>
+        <td id="L15" class="blob-num js-line-number" data-line-number="15"></td>
+        <td id="LC15" class="blob-code blob-code-inner js-file-line">ETH_TYPE_IP6      <span class="pl-k">=</span> <span class="pl-c1">0x</span>86DD           <span class="pl-c"># IPv6 protocol</span></td>
+      </tr>
+      <tr>
+        <td id="L16" class="blob-num js-line-number" data-line-number="16"></td>
+        <td id="LC16" class="blob-code blob-code-inner js-file-line">ETH_TYPE_PPP      <span class="pl-k">=</span> <span class="pl-c1">0x</span>880B           <span class="pl-c"># PPP</span></td>
+      </tr>
+      <tr>
+        <td id="L17" class="blob-num js-line-number" data-line-number="17"></td>
+        <td id="LC17" class="blob-code blob-code-inner js-file-line">ETH_TYPE_MPLS     <span class="pl-k">=</span> <span class="pl-c1">0x</span>8847           <span class="pl-c"># MPLS</span></td>
+      </tr>
+      <tr>
+        <td id="L18" class="blob-num js-line-number" data-line-number="18"></td>
+        <td id="LC18" class="blob-code blob-code-inner js-file-line">ETH_TYPE_MPLS_MCAST       <span class="pl-k">=</span> <span class="pl-c1">0x</span>8848   <span class="pl-c"># MPLS Multicast</span></td>
+      </tr>
+      <tr>
+        <td id="L19" class="blob-num js-line-number" data-line-number="19"></td>
+        <td id="LC19" class="blob-code blob-code-inner js-file-line">ETH_TYPE_PPPoE_DISC       <span class="pl-k">=</span> <span class="pl-c1">0x</span>8863   <span class="pl-c"># PPP Over Ethernet Discovery Stage</span></td>
+      </tr>
+      <tr>
+        <td id="L20" class="blob-num js-line-number" data-line-number="20"></td>
+        <td id="LC20" class="blob-code blob-code-inner js-file-line">ETH_TYPE_PPPoE            <span class="pl-k">=</span> <span class="pl-c1">0x</span>8864   <span class="pl-c"># PPP Over Ethernet Session Stage</span></td>
+      </tr>
+      <tr>
+        <td id="L21" class="blob-num js-line-number" data-line-number="21"></td>
+        <td id="LC21" class="blob-code blob-code-inner js-file-line">
+</td>
+      </tr>
+      <tr>
+        <td id="L22" class="blob-num js-line-number" data-line-number="22"></td>
+        <td id="LC22" class="blob-code blob-code-inner js-file-line"><span class="pl-k">class</span> <span class="pl-en">DOT1Q</span>(<span class="pl-e">dpkt.Packet</span>):</td>
+      </tr>
+      <tr>
+        <td id="L23" class="blob-num js-line-number" data-line-number="23"></td>
+        <td id="LC23" class="blob-code blob-code-inner js-file-line">    __hdr__ <span class="pl-k">=</span> (</td>
+      </tr>
+      <tr>
+        <td id="L24" class="blob-num js-line-number" data-line-number="24"></td>
+        <td id="LC24" class="blob-code blob-code-inner js-file-line">        (<span class="pl-s"><span class="pl-pds">&#39;</span>x2<span class="pl-pds">&#39;</span></span>, <span class="pl-s"><span class="pl-pds">&#39;</span>H<span class="pl-pds">&#39;</span></span>, <span class="pl-c1">0</span>),</td>
+      </tr>
+      <tr>
+        <td id="L25" class="blob-num js-line-number" data-line-number="25"></td>
+        <td id="LC25" class="blob-code blob-code-inner js-file-line">        (<span class="pl-s"><span class="pl-pds">&#39;</span>type<span class="pl-pds">&#39;</span></span>, <span class="pl-s"><span class="pl-pds">&#39;</span>H<span class="pl-pds">&#39;</span></span>, <span class="pl-c1">0</span>)</td>
+      </tr>
+      <tr>
+        <td id="L26" class="blob-num js-line-number" data-line-number="26"></td>
+        <td id="LC26" class="blob-code blob-code-inner js-file-line">        )</td>
+      </tr>
+      <tr>
+        <td id="L27" class="blob-num js-line-number" data-line-number="27"></td>
+        <td id="LC27" class="blob-code blob-code-inner js-file-line">    _typesw <span class="pl-k">=</span> {}</td>
+      </tr>
+      <tr>
+        <td id="L28" class="blob-num js-line-number" data-line-number="28"></td>
+        <td id="LC28" class="blob-code blob-code-inner js-file-line">
+</td>
+      </tr>
+      <tr>
+        <td id="L29" class="blob-num js-line-number" data-line-number="29"></td>
+        <td id="LC29" class="blob-code blob-code-inner js-file-line">    <span class="pl-c"># pcp == Priority Code Point(802.1p)</span></td>
+      </tr>
+      <tr>
+        <td id="L30" class="blob-num js-line-number" data-line-number="30"></td>
+        <td id="LC30" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">_get_pcp</span>(<span class="pl-smi">self</span>): <span class="pl-k">return</span> <span class="pl-v">self</span>.x2 <span class="pl-k">&gt;&gt;</span> <span class="pl-c1">13</span></td>
+      </tr>
+      <tr>
+        <td id="L31" class="blob-num js-line-number" data-line-number="31"></td>
+        <td id="LC31" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">_set_pcp</span>(<span class="pl-smi">self</span>, <span class="pl-smi">pcp</span>): <span class="pl-v">self</span>.x2 <span class="pl-k">=</span> (<span class="pl-v">self</span>.x2 <span class="pl-k">&amp;</span> <span class="pl-c1">0x</span>1fff) <span class="pl-k">|</span> (pcp <span class="pl-k">&lt;&lt;</span> <span class="pl-c1">13</span>)</td>
+      </tr>
+      <tr>
+        <td id="L32" class="blob-num js-line-number" data-line-number="32"></td>
+        <td id="LC32" class="blob-code blob-code-inner js-file-line">    pcp <span class="pl-k">=</span> <span class="pl-c1">property</span>(_get_pcp, _set_pcp)</td>
+      </tr>
+      <tr>
+        <td id="L33" class="blob-num js-line-number" data-line-number="33"></td>
+        <td id="LC33" class="blob-code blob-code-inner js-file-line">
+</td>
+      </tr>
+      <tr>
+        <td id="L34" class="blob-num js-line-number" data-line-number="34"></td>
+        <td id="LC34" class="blob-code blob-code-inner js-file-line">    <span class="pl-c"># dei == Drop Eligible Indicator(almost never actually used)</span></td>
+      </tr>
+      <tr>
+        <td id="L35" class="blob-num js-line-number" data-line-number="35"></td>
+        <td id="LC35" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">_get_dei</span>(<span class="pl-smi">self</span>): <span class="pl-k">return</span> (<span class="pl-v">self</span>.x2 <span class="pl-k">&gt;&gt;</span> <span class="pl-c1">12</span>) <span class="pl-k">&amp;</span> <span class="pl-c1">1</span> </td>
+      </tr>
+      <tr>
+        <td id="L36" class="blob-num js-line-number" data-line-number="36"></td>
+        <td id="LC36" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">_set_dei</span>(<span class="pl-smi">self</span>, <span class="pl-smi">dei</span>): <span class="pl-v">self</span>.x2 <span class="pl-k">=</span> (<span class="pl-v">self</span>.x2 <span class="pl-k">&amp;</span> <span class="pl-c1">61439</span>) <span class="pl-k">|</span> (dei <span class="pl-k">&lt;&lt;</span> <span class="pl-c1">12</span>)</td>
+      </tr>
+      <tr>
+        <td id="L37" class="blob-num js-line-number" data-line-number="37"></td>
+        <td id="LC37" class="blob-code blob-code-inner js-file-line">    dei <span class="pl-k">=</span> <span class="pl-c1">property</span>(_get_dei, _set_dei)</td>
+      </tr>
+      <tr>
+        <td id="L38" class="blob-num js-line-number" data-line-number="38"></td>
+        <td id="LC38" class="blob-code blob-code-inner js-file-line">
+</td>
+      </tr>
+      <tr>
+        <td id="L39" class="blob-num js-line-number" data-line-number="39"></td>
+        <td id="LC39" class="blob-code blob-code-inner js-file-line">    <span class="pl-c"># tag == vlan tag</span></td>
+      </tr>
+      <tr>
+        <td id="L40" class="blob-num js-line-number" data-line-number="40"></td>
+        <td id="LC40" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">_get_tag</span>(<span class="pl-smi">self</span>): <span class="pl-k">return</span> <span class="pl-v">self</span>.x2 <span class="pl-k">&amp;</span> (<span class="pl-c1">65535</span> <span class="pl-k">&gt;&gt;</span> <span class="pl-c1">4</span>)</td>
+      </tr>
+      <tr>
+        <td id="L41" class="blob-num js-line-number" data-line-number="41"></td>
+        <td id="LC41" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">_set_tag</span>(<span class="pl-smi">self</span>, <span class="pl-smi">tag</span>): <span class="pl-v">self</span>.x2 <span class="pl-k">=</span> (<span class="pl-v">self</span>.x2 <span class="pl-k">&amp;</span> <span class="pl-c1">0x</span>fff) <span class="pl-k">|</span> tag</td>
+      </tr>
+      <tr>
+        <td id="L42" class="blob-num js-line-number" data-line-number="42"></td>
+        <td id="LC42" class="blob-code blob-code-inner js-file-line">    tag <span class="pl-k">=</span> <span class="pl-c1">property</span>(_get_tag, _set_tag)</td>
+      </tr>
+      <tr>
+        <td id="L43" class="blob-num js-line-number" data-line-number="43"></td>
+        <td id="LC43" class="blob-code blob-code-inner js-file-line">
+</td>
+      </tr>
+      <tr>
+        <td id="L44" class="blob-num js-line-number" data-line-number="44"></td>
+        <td id="LC44" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">set_type</span>(<span class="pl-smi">cls</span>, <span class="pl-smi">t</span>, <span class="pl-smi">pktclass</span>):</td>
+      </tr>
+      <tr>
+        <td id="L45" class="blob-num js-line-number" data-line-number="45"></td>
+        <td id="LC45" class="blob-code blob-code-inner js-file-line">        <span class="pl-v">cls</span>._typesw[t] <span class="pl-k">=</span> pktclass</td>
+      </tr>
+      <tr>
+        <td id="L46" class="blob-num js-line-number" data-line-number="46"></td>
+        <td id="LC46" class="blob-code blob-code-inner js-file-line">    set_type <span class="pl-k">=</span> <span class="pl-c1">classmethod</span>(set_type)</td>
+      </tr>
+      <tr>
+        <td id="L47" class="blob-num js-line-number" data-line-number="47"></td>
+        <td id="LC47" class="blob-code blob-code-inner js-file-line">
+</td>
+      </tr>
+      <tr>
+        <td id="L48" class="blob-num js-line-number" data-line-number="48"></td>
+        <td id="LC48" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">get_type</span>(<span class="pl-smi">cls</span>, <span class="pl-smi">t</span>):</td>
+      </tr>
+      <tr>
+        <td id="L49" class="blob-num js-line-number" data-line-number="49"></td>
+        <td id="LC49" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">return</span> <span class="pl-v">cls</span>._typesw[t]</td>
+      </tr>
+      <tr>
+        <td id="L50" class="blob-num js-line-number" data-line-number="50"></td>
+        <td id="LC50" class="blob-code blob-code-inner js-file-line">    get_type <span class="pl-k">=</span> <span class="pl-c1">classmethod</span>(get_type)</td>
+      </tr>
+      <tr>
+        <td id="L51" class="blob-num js-line-number" data-line-number="51"></td>
+        <td id="LC51" class="blob-code blob-code-inner js-file-line">
+</td>
+      </tr>
+      <tr>
+        <td id="L52" class="blob-num js-line-number" data-line-number="52"></td>
+        <td id="LC52" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">_unpack_data</span>(<span class="pl-smi">self</span>, <span class="pl-smi">buf</span>):</td>
+      </tr>
+      <tr>
+        <td id="L53" class="blob-num js-line-number" data-line-number="53"></td>
+        <td id="LC53" class="blob-code blob-code-inner js-file-line">      <span class="pl-k">if</span> <span class="pl-v">self</span>.type <span class="pl-k">==</span> ETH_TYPE_MPLS <span class="pl-k">or</span> \</td>
+      </tr>
+      <tr>
+        <td id="L54" class="blob-num js-line-number" data-line-number="54"></td>
+        <td id="LC54" class="blob-code blob-code-inner js-file-line">            <span class="pl-v">self</span>.type <span class="pl-k">==</span> ETH_TYPE_MPLS_MCAST:</td>
+      </tr>
+      <tr>
+        <td id="L55" class="blob-num js-line-number" data-line-number="55"></td>
+        <td id="LC55" class="blob-code blob-code-inner js-file-line">        <span class="pl-c"># XXX - skip labels (max # of labels is undefined, just use 24)</span></td>
+      </tr>
+      <tr>
+        <td id="L56" class="blob-num js-line-number" data-line-number="56"></td>
+        <td id="LC56" class="blob-code blob-code-inner js-file-line">        <span class="pl-v">self</span>.labels <span class="pl-k">=</span> []</td>
+      </tr>
+      <tr>
+        <td id="L57" class="blob-num js-line-number" data-line-number="57"></td>
+        <td id="LC57" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">for</span> i <span class="pl-k">in</span> <span class="pl-c1">range</span>(<span class="pl-c1">24</span>):</td>
+      </tr>
+      <tr>
+        <td id="L58" class="blob-num js-line-number" data-line-number="58"></td>
+        <td id="LC58" class="blob-code blob-code-inner js-file-line">          entry <span class="pl-k">=</span> struct.unpack(<span class="pl-s"><span class="pl-pds">&#39;</span>&gt;I<span class="pl-pds">&#39;</span></span>, buf[i<span class="pl-k">*</span><span class="pl-c1">4</span>:i<span class="pl-k">*</span><span class="pl-c1">4</span><span class="pl-k">+</span><span class="pl-c1">4</span>])[<span class="pl-c1">0</span>]</td>
+      </tr>
+      <tr>
+        <td id="L59" class="blob-num js-line-number" data-line-number="59"></td>
+        <td id="LC59" class="blob-code blob-code-inner js-file-line">          label <span class="pl-k">=</span> ((entry <span class="pl-k">&amp;</span> MPLS_LABEL_MASK) <span class="pl-k">&gt;&gt;</span> MPLS_LABEL_SHIFT, \</td>
+      </tr>
+      <tr>
+        <td id="L60" class="blob-num js-line-number" data-line-number="60"></td>
+        <td id="LC60" class="blob-code blob-code-inner js-file-line">                     (entry <span class="pl-k">&amp;</span> MPLS_QOS_MASK) <span class="pl-k">&gt;&gt;</span> MPLS_QOS_SHIFT, \</td>
+      </tr>
+      <tr>
+        <td id="L61" class="blob-num js-line-number" data-line-number="61"></td>
+        <td id="LC61" class="blob-code blob-code-inner js-file-line">                     (entry <span class="pl-k">&amp;</span> MPLS_TTL_MASK) <span class="pl-k">&gt;&gt;</span> MPLS_TTL_SHIFT)</td>
+      </tr>
+      <tr>
+        <td id="L62" class="blob-num js-line-number" data-line-number="62"></td>
+        <td id="LC62" class="blob-code blob-code-inner js-file-line">          <span class="pl-v">self</span>.labels.append(label)</td>
+      </tr>
+      <tr>
+        <td id="L63" class="blob-num js-line-number" data-line-number="63"></td>
+        <td id="LC63" class="blob-code blob-code-inner js-file-line">          <span class="pl-k">if</span> entry <span class="pl-k">&amp;</span> MPLS_STACK_BOTTOM:</td>
+      </tr>
+      <tr>
+        <td id="L64" class="blob-num js-line-number" data-line-number="64"></td>
+        <td id="LC64" class="blob-code blob-code-inner js-file-line">            <span class="pl-k">break</span></td>
+      </tr>
+      <tr>
+        <td id="L65" class="blob-num js-line-number" data-line-number="65"></td>
+        <td id="LC65" class="blob-code blob-code-inner js-file-line">          <span class="pl-v">self</span>.type <span class="pl-k">=</span> ETH_TYPE_IP</td>
+      </tr>
+      <tr>
+        <td id="L66" class="blob-num js-line-number" data-line-number="66"></td>
+        <td id="LC66" class="blob-code blob-code-inner js-file-line">          buf <span class="pl-k">=</span> buf[(i <span class="pl-k">+</span> <span class="pl-c1">1</span>) <span class="pl-k">*</span> <span class="pl-c1">4</span>:]</td>
+      </tr>
+      <tr>
+        <td id="L67" class="blob-num js-line-number" data-line-number="67"></td>
+        <td id="LC67" class="blob-code blob-code-inner js-file-line">      <span class="pl-k">try</span>:</td>
+      </tr>
+      <tr>
+        <td id="L68" class="blob-num js-line-number" data-line-number="68"></td>
+        <td id="LC68" class="blob-code blob-code-inner js-file-line">        <span class="pl-v">self</span>.data <span class="pl-k">=</span> <span class="pl-v">self</span>._typesw[<span class="pl-v">self</span>.type](buf)</td>
+      </tr>
+      <tr>
+        <td id="L69" class="blob-num js-line-number" data-line-number="69"></td>
+        <td id="LC69" class="blob-code blob-code-inner js-file-line">        <span class="pl-c1">setattr</span>(<span class="pl-v">self</span>, <span class="pl-v">self</span>.data.<span class="pl-c1">__class__</span>.<span class="pl-c1">__name__</span>.lower(), <span class="pl-v">self</span>.data)</td>
+      </tr>
+      <tr>
+        <td id="L70" class="blob-num js-line-number" data-line-number="70"></td>
+        <td id="LC70" class="blob-code blob-code-inner js-file-line">      <span class="pl-k">except</span> (<span class="pl-c1">KeyError</span>, dpkt.UnpackError):</td>
+      </tr>
+      <tr>
+        <td id="L71" class="blob-num js-line-number" data-line-number="71"></td>
+        <td id="LC71" class="blob-code blob-code-inner js-file-line">        <span class="pl-v">self</span>.data <span class="pl-k">=</span> buf</td>
+      </tr>
+      <tr>
+        <td id="L72" class="blob-num js-line-number" data-line-number="72"></td>
+        <td id="LC72" class="blob-code blob-code-inner js-file-line">
+</td>
+      </tr>
+      <tr>
+        <td id="L73" class="blob-num js-line-number" data-line-number="73"></td>
+        <td id="LC73" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">unpack</span>(<span class="pl-smi">self</span>, <span class="pl-smi">buf</span>):</td>
+      </tr>
+      <tr>
+        <td id="L74" class="blob-num js-line-number" data-line-number="74"></td>
+        <td id="LC74" class="blob-code blob-code-inner js-file-line">        dpkt.Packet.unpack(<span class="pl-v">self</span>, buf)</td>
+      </tr>
+      <tr>
+        <td id="L75" class="blob-num js-line-number" data-line-number="75"></td>
+        <td id="LC75" class="blob-code blob-code-inner js-file-line">        <span class="pl-v">self</span>._unpack_data(<span class="pl-v">self</span>.data)</td>
+      </tr>
+      <tr>
+        <td id="L76" class="blob-num js-line-number" data-line-number="76"></td>
+        <td id="LC76" class="blob-code blob-code-inner js-file-line">
+</td>
+      </tr>
+      <tr>
+        <td id="L77" class="blob-num js-line-number" data-line-number="77"></td>
+        <td id="LC77" class="blob-code blob-code-inner js-file-line">
+</td>
+      </tr>
+      <tr>
+        <td id="L78" class="blob-num js-line-number" data-line-number="78"></td>
+        <td id="LC78" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># XXX - auto-load Ethernet dispatch table from ETH_TYPE_* definitions</span></td>
+      </tr>
+      <tr>
+        <td id="L79" class="blob-num js-line-number" data-line-number="79"></td>
+        <td id="LC79" class="blob-code blob-code-inner js-file-line"><span class="pl-k">def</span> <span class="pl-en">__load_types</span>():</td>
+      </tr>
+      <tr>
+        <td id="L80" class="blob-num js-line-number" data-line-number="80"></td>
+        <td id="LC80" class="blob-code blob-code-inner js-file-line">  g <span class="pl-k">=</span> <span class="pl-c1">globals</span>()</td>
+      </tr>
+      <tr>
+        <td id="L81" class="blob-num js-line-number" data-line-number="81"></td>
+        <td id="LC81" class="blob-code blob-code-inner js-file-line">  <span class="pl-k">for</span> k, v <span class="pl-k">in</span> g.iteritems():</td>
+      </tr>
+      <tr>
+        <td id="L82" class="blob-num js-line-number" data-line-number="82"></td>
+        <td id="LC82" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">if</span> k.startswith(<span class="pl-s"><span class="pl-pds">&#39;</span>ETH_TYPE_<span class="pl-pds">&#39;</span></span>):</td>
+      </tr>
+      <tr>
+        <td id="L83" class="blob-num js-line-number" data-line-number="83"></td>
+        <td id="LC83" class="blob-code blob-code-inner js-file-line">      name <span class="pl-k">=</span> k[<span class="pl-c1">9</span>:]</td>
+      </tr>
+      <tr>
+        <td id="L84" class="blob-num js-line-number" data-line-number="84"></td>
+        <td id="LC84" class="blob-code blob-code-inner js-file-line">      modname <span class="pl-k">=</span> name.lower()</td>
+      </tr>
+      <tr>
+        <td id="L85" class="blob-num js-line-number" data-line-number="85"></td>
+        <td id="LC85" class="blob-code blob-code-inner js-file-line">      <span class="pl-k">try</span>:</td>
+      </tr>
+      <tr>
+        <td id="L86" class="blob-num js-line-number" data-line-number="86"></td>
+        <td id="LC86" class="blob-code blob-code-inner js-file-line">        mod <span class="pl-k">=</span> <span class="pl-c1">__import__</span>(modname, g)</td>
+      </tr>
+      <tr>
+        <td id="L87" class="blob-num js-line-number" data-line-number="87"></td>
+        <td id="LC87" class="blob-code blob-code-inner js-file-line">      <span class="pl-k">except</span> <span class="pl-c1">ImportError</span>:</td>
+      </tr>
+      <tr>
+        <td id="L88" class="blob-num js-line-number" data-line-number="88"></td>
+        <td id="LC88" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">continue</span></td>
+      </tr>
+      <tr>
+        <td id="L89" class="blob-num js-line-number" data-line-number="89"></td>
+        <td id="LC89" class="blob-code blob-code-inner js-file-line">      DOT1Q.set_type(v, <span class="pl-c1">getattr</span>(mod, name))</td>
+      </tr>
+      <tr>
+        <td id="L90" class="blob-num js-line-number" data-line-number="90"></td>
+        <td id="LC90" class="blob-code blob-code-inner js-file-line">
+</td>
+      </tr>
+      <tr>
+        <td id="L91" class="blob-num js-line-number" data-line-number="91"></td>
+        <td id="LC91" class="blob-code blob-code-inner js-file-line"><span class="pl-k">if</span> <span class="pl-k">not</span> DOT1Q._typesw:</td>
+      </tr>
+      <tr>
+        <td id="L92" class="blob-num js-line-number" data-line-number="92"></td>
+        <td id="LC92" class="blob-code blob-code-inner js-file-line">  __load_types()</td>
+      </tr>
+</table>
+
+  </div>
+
+</div>
+
+<a href="#jump-to-line" rel="facebox[.linejump]" data-hotkey="l" style="display:none">Jump to Line</a>
+<div id="jump-to-line" style="display:none">
+  <!-- </textarea> --><!-- '"` --><form accept-charset="UTF-8" action="" class="js-jump-to-line-form" method="get"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="&#x2713;" /></div>
+    <input class="linejump-input js-jump-to-line-field" type="text" placeholder="Jump to line&hellip;" aria-label="Jump to line" autofocus>
+    <button type="submit" class="btn">Go</button>
+</form></div>
+
+        </div>
+      </div>
+      <div class="modal-backdrop"></div>
+    </div>
+  </div>
+
+
+
+      <div class="container">
+  <div class="site-footer" role="contentinfo">
+    <ul class="site-footer-links right">
+        <li><a href="https://status.github.com/" data-ga-click="Footer, go to status, text:status">Status</a></li>
+      <li><a href="https://developer.github.com" data-ga-click="Footer, go to api, text:api">API</a></li>
+      <li><a href="https://training.github.com" data-ga-click="Footer, go to training, text:training">Training</a></li>
+      <li><a href="https://shop.github.com" data-ga-click="Footer, go to shop, text:shop">Shop</a></li>
+        <li><a href="https://github.com/blog" data-ga-click="Footer, go to blog, text:blog">Blog</a></li>
+        <li><a href="https://github.com/about" data-ga-click="Footer, go to about, text:about">About</a></li>
+        <li><a href="https://github.com/pricing" data-ga-click="Footer, go to pricing, text:pricing">Pricing</a></li>
+
+    </ul>
+
+    <a href="https://github.com" aria-label="Homepage">
+      <span class="mega-octicon octicon-mark-github" title="GitHub"></span>
+</a>
+    <ul class="site-footer-links">
+      <li>&copy; 2015 <span title="0.09612s from github-fe127-cp1-prd.iad.github.net">GitHub</span>, Inc.</li>
+        <li><a href="https://github.com/site/terms" data-ga-click="Footer, go to terms, text:terms">Terms</a></li>
+        <li><a href="https://github.com/site/privacy" data-ga-click="Footer, go to privacy, text:privacy">Privacy</a></li>
+        <li><a href="https://github.com/security" data-ga-click="Footer, go to security, text:security">Security</a></li>
+        <li><a href="https://github.com/contact" data-ga-click="Footer, go to contact, text:contact">Contact</a></li>
+        <li><a href="https://help.github.com" data-ga-click="Footer, go to help, text:help">Help</a></li>
+    </ul>
+  </div>
+</div>
+
+
+
+    
+    
+
+    <div id="ajax-error-message" class="flash flash-error">
+      <span class="octicon octicon-alert"></span>
+      <button type="button" class="flash-close js-flash-close js-ajax-error-dismiss" aria-label="Dismiss error">
+        <span class="octicon octicon-x"></span>
+      </button>
+      Something went wrong with that request. Please try again.
+    </div>
+
+
+      <script crossorigin="anonymous" src="https://assets-cdn.github.com/assets/frameworks-06e65f5639cc52d1aaada53115a54614b60fa90ab446a673e3e1818df167663b.js"></script>
+      <script async="async" crossorigin="anonymous" src="https://assets-cdn.github.com/assets/github-435b0c380a8b91b3f42654ca3dbe8b623eebe6dfa2314a80f961d364de7e3f42.js"></script>
+      
+      
+    <div class="js-stale-session-flash stale-session-flash flash flash-warn flash-banner hidden">
+      <span class="octicon octicon-alert"></span>
+      <span class="signed-in-tab-flash">You signed in with another tab or window. <a href="">Reload</a> to refresh your session.</span>
+      <span class="signed-out-tab-flash">You signed out in another tab or window. <a href="">Reload</a> to refresh your session.</span>
+    </div>
+  </body>
+</html>
+