SRv6 tests

Change-Id: Ib1d2fc5a83d9d007a0468591a73881675f1bec9b
Signed-off-by: Kris Michielsen <kmichiel@cisco.com>
diff --git a/test/patches/scapy-2.3.3/inet6.py.patch b/test/patches/scapy-2.3.3/inet6.py.patch
new file mode 100644
index 0000000..f98e709
--- /dev/null
+++ b/test/patches/scapy-2.3.3/inet6.py.patch
@@ -0,0 +1,185 @@
+diff --git a/scapy/layers/inet6.py b/scapy/layers/inet6.py
+--- a/scapy/layers/inet6.py	2017-06-01 14:04:18.160881034 +0200
++++ b/scapy/layers/inet6.py	2017-06-02 09:08:40.133800208 +0200
+@@ -369,6 +369,8 @@
+             return Raw
+         elif self.nh == 135 and len(p) > 3: # Mobile IPv6
+             return _mip6_mhtype2cls.get(ord(p[2]), MIP6MH_Generic)
++        elif self.nh == 43 and ord(p[2]) == 4:  # Segment Routing header
++            return IPv6ExtHdrSegmentRouting
+         else:
+             return get_cls(ipv6nhcls.get(self.nh,"Raw"), "Raw")
+
+@@ -430,6 +432,14 @@
+                     sd = strxor(sd, a)
+                 sd = inet_ntop(socket.AF_INET6, sd)
+
++        if self.nh == 43 and isinstance(self.payload, IPv6ExtHdrSegmentRouting):
++            # With segment routing header (rh == 4), the destination is
++            # the first address of the IPv6 addresses list
++            try:
++                sd = self.addresses[0]
++            except IndexError:
++                sd = self.dst
++
+         if self.nh == 44 and isinstance(self.payload, IPv6ExtHdrFragment):
+             nh = self.payload.nh
+
+@@ -489,6 +499,8 @@
+             return self.payload.answers(other.payload.payload)
+         elif other.nh == 43 and isinstance(other.payload, IPv6ExtHdrRouting):
+             return self.payload.answers(other.payload.payload) # Buggy if self.payload is a IPv6ExtHdrRouting
++        elif other.nh == 43 and isinstance(other.payload, IPv6ExtHdrSegmentRouting):
++            return self.payload.answers(other.payload.payload)  # Buggy if self.payload is a IPv6ExtHdrRouting
+         elif other.nh == 60 and isinstance(other.payload, IPv6ExtHdrDestOpt):
+             return self.payload.payload.answers(other.payload.payload)
+         elif self.nh == 60 and isinstance(self.payload, IPv6ExtHdrDestOpt): # BU in reply to BRR, for instance
+@@ -919,6 +931,148 @@
+             pkt = pkt[:3]+struct.pack("B", len(self.addresses))+pkt[4:]
+         return _IPv6ExtHdr.post_build(self, pkt, pay)
+
++######################### Segment Routing Header ############################
++
++# This implementation is based on draft 06, available at:
++# https://tools.ietf.org/html/draft-ietf-6man-segment-routing-header-06
++
++class IPv6ExtHdrSegmentRoutingTLV(Packet):
++    name = "IPv6 Option Header Segment Routing - Generic TLV"
++    fields_desc = [ ByteField("type", 0),
++                    ByteField("len", 0),
++                    ByteField("reserved", 0),
++                    ByteField("flags", 0),
++                    StrLenField("value", "", length_from=lambda pkt: pkt.len) ]
++
++    def extract_padding(self, p):
++        return "",p
++
++    registered_sr_tlv = {}
++    @classmethod
++    def register_variant(cls):
++        cls.registered_sr_tlv[cls.type.default] = cls
++
++    @classmethod
++    def dispatch_hook(cls, pkt=None, *args, **kargs):
++        if pkt:
++            tmp_type = ord(pkt[0])
++            return cls.registered_sr_tlv.get(tmp_type, cls)
++        return cls
++
++
++class IPv6ExtHdrSegmentRoutingTLVIngressNode(IPv6ExtHdrSegmentRoutingTLV):
++    name = "IPv6 Option Header Segment Routing - Ingress Node TLV"
++    fields_desc = [ ByteField("type", 1),
++                    ByteField("len", 18),
++                    ByteField("reserved", 0),
++                    ByteField("flags", 0),
++                    IP6Field("ingress_node", "::1") ]
++
++
++class IPv6ExtHdrSegmentRoutingTLVEgressNode(IPv6ExtHdrSegmentRoutingTLV):
++    name = "IPv6 Option Header Segment Routing - Egress Node TLV"
++    fields_desc = [ ByteField("type", 2),
++                    ByteField("len", 18),
++                    ByteField("reserved", 0),
++                    ByteField("flags", 0),
++                    IP6Field("egress_node", "::1") ]
++
++
++class IPv6ExtHdrSegmentRoutingTLVPadding(IPv6ExtHdrSegmentRoutingTLV):
++    name = "IPv6 Option Header Segment Routing - Padding TLV"
++    fields_desc = [ ByteField("type", 4),
++                    FieldLenField("len", None, length_of="padding", fmt="B"),
++                    StrLenField("padding", b"\x00", length_from=lambda pkt: pkt.len) ]
++
++
++class IPv6ExtHdrSegmentRouting(_IPv6ExtHdr):
++    # 0                   1                   2                   3
++    # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++    #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++    #| Next Header   |  Hdr Ext Len  | Routing Type  | Segments Left |
++    #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++    #|  Last Entry   |     Flags     |              Tag              |
++    #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++    #|                                                               |
++    #|            Segment List[0] (128 bits IPv6 address)            |
++    #|                                                               |
++    #|                                                               |
++    #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++    #|                                                               |
++    #|                                                               |
++    #                              ...
++    #|                                                               |
++    #|                                                               |
++    #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++    #|                                                               |
++    #|            Segment List[n] (128 bits IPv6 address)            |
++    #|                                                               |
++    #|                                                               |
++    #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++    #//                                                             //
++    #//         Optional Type Length Value objects (variable)       //
++    #//                                                             //
++    #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++    #
++    #      0 1 2 3 4 5 6 7
++    #     +-+-+-+-+-+-+-+-+
++    #     |U|P|O|A|H|  U  |
++    #     +-+-+-+-+-+-+-+-+
++
++    name = "IPv6 Segment Routing Extension Header"
++    fields_desc = [ ByteEnumField("nh", 59, ipv6nh),
++                    ByteField("len", None),
++                    ByteField("type", 4),
++                    ByteField("segleft", None),
++                    ByteField("lastentry", None),
++                    BitField("unused1", 0, 1),
++                    BitField("protected", 0, 1),
++                    BitField("oam", 0, 1),
++                    BitField("alert", 0, 1),
++                    BitField("hmac", 0, 1),
++                    BitField("unused2", 0, 3),
++                    ShortField("tag", 0),
++                    IP6ListField("addresses", ["::1"],
++                        count_from=lambda pkt: pkt.lastentry+1),
++                    PacketListField("tlv_objects", [], IPv6ExtHdrSegmentRoutingTLV,
++                        length_from=lambda pkt: 8*pkt.len - 16*(pkt.lastentry+1)) ]
++
++    overload_fields = { IPv6: { "nh": 43 } }
++
++    def post_build(self, pkt, pay):
++
++        if self.len is None:
++
++            # The extension must be align on 8 bytes
++            tmp_mod = (len(pkt) - 8) % 8
++            if tmp_mod == 1:
++                warning("IPv6ExtHdrSegmentRouting(): can't pad 1 byte !")
++            elif tmp_mod >= 2:
++                #Add the padding extension
++                tmp_pad = b"\x00" * (tmp_mod-2)
++                tlv = IPv6ExtHdrSegmentRoutingTLVPadding(padding=tmp_pad)
++                pkt += str(tlv)
++
++            tmp_len = (len(pkt) - 8) / 8
++            pkt = pkt[:1] + struct.pack("B", tmp_len)+ pkt[2:]
++
++        if self.segleft is None:
++            tmp_len = len(self.addresses)
++            if tmp_len:
++                tmp_len -= 1
++            pkt = pkt[:3] + struct.pack("B", tmp_len) + pkt[4:]
++
++        if self.lastentry is None:
++            #km - changed to contain n-1
++            tmp_len = len(self.addresses)
++            if tmp_len:
++                tmp_len -= 1
++            #pkt = pkt[:4] + struct.pack("B", len(self.addresses)) + pkt[5:]
++            pkt = pkt[:4] + struct.pack("B", tmp_len) + pkt[5:]
++
++        return _IPv6ExtHdr.post_build(self, pkt, pay)
++
++
+ ########################### Fragmentation Header ############################
+
+ class IPv6ExtHdrFragment(_IPv6ExtHdr):