#!/usr/bin/env python

import unittest
import socket

from framework import VppTestCase, VppTestRunner
from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsRoute, \
    VppMplsIpBind, VppIpMRoute, VppMRoutePath, \
    MRouteItfFlags, MRouteEntryFlags, DpoProto, VppIpTable, VppMplsTable
from vpp_mpls_tunnel_interface import VppMPLSTunnelInterface

from scapy.packet import Raw
from scapy.layers.l2 import Ether
from scapy.layers.inet import IP, UDP, ICMP
from scapy.layers.inet6 import IPv6, ICMPv6TimeExceeded
from scapy.contrib.mpls import MPLS


def verify_filter(capture, sent):
    if not len(capture) == len(sent):
        # filter out any IPv6 RAs from the capture
        for p in capture:
            if p.haslayer(IPv6):
                capture.remove(p)
    return capture


def verify_mpls_stack(tst, rx, mpls_labels, ttl=255, num=0):
    # the rx'd packet has the MPLS label popped
    eth = rx[Ether]
    tst.assertEqual(eth.type, 0x8847)

    rx_mpls = rx[MPLS]

    for ii in range(len(mpls_labels)):
        tst.assertEqual(rx_mpls.label, mpls_labels[ii])
        tst.assertEqual(rx_mpls.cos, 0)
        if ii == num:
            tst.assertEqual(rx_mpls.ttl, ttl)
        else:
            tst.assertEqual(rx_mpls.ttl, 255)
        if ii == len(mpls_labels) - 1:
            tst.assertEqual(rx_mpls.s, 1)
        else:
            # not end of stack
            tst.assertEqual(rx_mpls.s, 0)
            # pop the label to expose the next
            rx_mpls = rx_mpls[MPLS].payload


class TestMPLS(VppTestCase):
    """ MPLS Test Case """

    def setUp(self):
        super(TestMPLS, self).setUp()

        # create 2 pg interfaces
        self.create_pg_interfaces(range(4))

        # setup both interfaces
        # assign them different tables.
        table_id = 0
        self.tables = []

        tbl = VppMplsTable(self, 0)
        tbl.add_vpp_config()
        self.tables.append(tbl)

        for i in self.pg_interfaces:
            i.admin_up()

            if table_id != 0:
                tbl = VppIpTable(self, table_id)
                tbl.add_vpp_config()
                self.tables.append(tbl)
                tbl = VppIpTable(self, table_id, is_ip6=1)
                tbl.add_vpp_config()
                self.tables.append(tbl)

            i.set_table_ip4(table_id)
            i.set_table_ip6(table_id)
            i.config_ip4()
            i.resolve_arp()
            i.config_ip6()
            i.resolve_ndp()
            i.enable_mpls()
            table_id += 1

    def tearDown(self):
        for i in self.pg_interfaces:
            i.unconfig_ip4()
            i.unconfig_ip6()
            i.ip6_disable()
            i.set_table_ip4(0)
            i.set_table_ip6(0)
            i.disable_mpls()
            i.admin_down()
        super(TestMPLS, self).tearDown()

    # the default of 64 matches the IP packet TTL default
    def create_stream_labelled_ip4(
            self,
            src_if,
            mpls_labels,
            mpls_ttl=255,
            ping=0,
            ip_itf=None,
            dst_ip=None,
            chksum=None,
            n=257):
        self.reset_packet_infos()
        pkts = []
        for i in range(0, n):
            info = self.create_packet_info(src_if, src_if)
            payload = self.info_to_payload(info)
            p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)

            for ii in range(len(mpls_labels)):
                if ii == len(mpls_labels) - 1:
                    p = p / MPLS(label=mpls_labels[ii], ttl=mpls_ttl, s=1)
                else:
                    p = p / MPLS(label=mpls_labels[ii], ttl=mpls_ttl, s=0)
            if not ping:
                if not dst_ip:
                    p = (p / IP(src=src_if.local_ip4, dst=src_if.remote_ip4) /
                         UDP(sport=1234, dport=1234) /
                         Raw(payload))
                else:
                    p = (p / IP(src=src_if.local_ip4, dst=dst_ip) /
                         UDP(sport=1234, dport=1234) /
                         Raw(payload))
            else:
                p = (p / IP(src=ip_itf.remote_ip4,
                            dst=ip_itf.local_ip4) /
                     ICMP())

            if chksum:
                p[IP].chksum = chksum
            info.data = p.copy()
            pkts.append(p)
        return pkts

    def create_stream_ip4(self, src_if, dst_ip):
        self.reset_packet_infos()
        pkts = []
        for i in range(0, 257):
            info = self.create_packet_info(src_if, src_if)
            payload = self.info_to_payload(info)
            p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                 IP(src=src_if.remote_ip4, dst=dst_ip) /
                 UDP(sport=1234, dport=1234) /
                 Raw(payload))
            info.data = p.copy()
            pkts.append(p)
        return pkts

    def create_stream_labelled_ip6(self, src_if, mpls_label, mpls_ttl,
                                   dst_ip=None, hlim=64):
        if dst_ip is None:
            dst_ip = src_if.remote_ip6
        self.reset_packet_infos()
        pkts = []
        for i in range(0, 257):
            info = self.create_packet_info(src_if, src_if)
            payload = self.info_to_payload(info)
            p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                 MPLS(label=mpls_label, ttl=mpls_ttl) /
                 IPv6(src=src_if.remote_ip6, dst=dst_ip, hlim=hlim) /
                 UDP(sport=1234, dport=1234) /
                 Raw(payload))
            info.data = p.copy()
            pkts.append(p)
        return pkts

    def verify_capture_ip4(self, src_if, capture, sent, ping_resp=0):
        try:
            capture = verify_filter(capture, sent)

            self.assertEqual(len(capture), len(sent))

            for i in range(len(capture)):
                tx = sent[i]
                rx = capture[i]

                # the rx'd packet has the MPLS label popped
                eth = rx[Ether]
                self.assertEqual(eth.type, 0x800)

                tx_ip = tx[IP]
                rx_ip = rx[IP]

                if not ping_resp:
                    self.assertEqual(rx_ip.src, tx_ip.src)
                    self.assertEqual(rx_ip.dst, tx_ip.dst)
                    # IP processing post pop has decremented the TTL
                    self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
                else:
                    self.assertEqual(rx_ip.src, tx_ip.dst)
                    self.assertEqual(rx_ip.dst, tx_ip.src)

        except:
            raise

    def verify_capture_labelled_ip4(self, src_if, capture, sent,
                                    mpls_labels):
        try:
            capture = verify_filter(capture, sent)

            self.assertEqual(len(capture), len(sent))

            for i in range(len(capture)):
                tx = sent[i]
                rx = capture[i]
                tx_ip = tx[IP]
                rx_ip = rx[IP]

                # the MPLS TTL is copied from the IP
                verify_mpls_stack(self, rx, mpls_labels, rx_ip.ttl,
                                  len(mpls_labels) - 1)

                self.assertEqual(rx_ip.src, tx_ip.src)
                self.assertEqual(rx_ip.dst, tx_ip.dst)
                # IP processing post pop has decremented the TTL
                self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)

        except:
            raise

    def verify_capture_tunneled_ip4(self, src_if, capture, sent, mpls_labels,
                                    ttl=255, top=None):
        if top is None:
            top = len(mpls_labels) - 1
        try:
            capture = verify_filter(capture, sent)

            self.assertEqual(len(capture), len(sent))

            for i in range(len(capture)):
                tx = sent[i]
                rx = capture[i]
                tx_ip = tx[IP]
                rx_ip = rx[IP]

                # the MPLS TTL is 255 since it enters a new tunnel
                verify_mpls_stack(self, rx, mpls_labels, ttl, top)

                self.assertEqual(rx_ip.src, tx_ip.src)
                self.assertEqual(rx_ip.dst, tx_ip.dst)
                # IP processing post pop has decremented the TTL
                self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)

        except:
            raise

    def verify_capture_labelled(self, src_if, capture, sent,
                                mpls_labels, ttl=254, num=0):
        try:
            capture = verify_filter(capture, sent)

            self.assertEqual(len(capture), len(sent))

            for i in range(len(capture)):
                rx = capture[i]
                verify_mpls_stack(self, rx, mpls_labels, ttl, num)
        except:
            raise

    def verify_capture_ip6(self, src_if, capture, sent):
        try:
            self.assertEqual(len(capture), len(sent))

            for i in range(len(capture)):
                tx = sent[i]
                rx = capture[i]

                # the rx'd packet has the MPLS label popped
                eth = rx[Ether]
                self.assertEqual(eth.type, 0x86DD)

                tx_ip = tx[IPv6]
                rx_ip = rx[IPv6]

                self.assertEqual(rx_ip.src, tx_ip.src)
                self.assertEqual(rx_ip.dst, tx_ip.dst)
                # IP processing post pop has decremented the TTL
                self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)

        except:
            raise

    def verify_capture_ip6_icmp(self, src_if, capture, sent):
        try:
            self.assertEqual(len(capture), len(sent))

            for i in range(len(capture)):
                tx = sent[i]
                rx = capture[i]

                # the rx'd packet has the MPLS label popped
                eth = rx[Ether]
                self.assertEqual(eth.type, 0x86DD)

                tx_ip = tx[IPv6]
                rx_ip = rx[IPv6]

                self.assertEqual(rx_ip.dst, tx_ip.src)
                # ICMP sourced from the interface's address
                self.assertEqual(rx_ip.src, src_if.local_ip6)
                # hop-limit reset to 255 for IMCP packet
                self.assertEqual(rx_ip.hlim, 254)

                icmp = rx[ICMPv6TimeExceeded]

        except:
            raise

    def send_and_assert_no_replies(self, intf, pkts, remark):
        intf.add_stream(pkts)
        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()
        for i in self.pg_interfaces:
            i.assert_nothing_captured(remark=remark)

    def test_swap(self):
        """ MPLS label swap tests """

        #
        # A simple MPLS xconnect - eos label in label out
        #
        route_32_eos = VppMplsRoute(self, 32, 1,
                                    [VppRoutePath(self.pg0.remote_ip4,
                                                  self.pg0.sw_if_index,
                                                  labels=[33])])
        route_32_eos.add_vpp_config()

        #
        # a stream that matches the route for 10.0.0.1
        # PG0 is in the default table
        #
        self.vapi.cli("clear trace")
        tx = self.create_stream_labelled_ip4(self.pg0, [32])
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg0.get_capture()
        self.verify_capture_labelled(self.pg0, rx, tx, [33])

        #
        # A simple MPLS xconnect - non-eos label in label out
        #
        route_32_neos = VppMplsRoute(self, 32, 0,
                                     [VppRoutePath(self.pg0.remote_ip4,
                                                   self.pg0.sw_if_index,
                                                   labels=[33])])
        route_32_neos.add_vpp_config()

        #
        # a stream that matches the route for 10.0.0.1
        # PG0 is in the default table
        #
        self.vapi.cli("clear trace")
        tx = self.create_stream_labelled_ip4(self.pg0, [32, 99])
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg0.get_capture()
        self.verify_capture_labelled(self.pg0, rx, tx, [33, 99])

        #
        # An MPLS xconnect - EOS label in IP out
        #
        route_33_eos = VppMplsRoute(self, 33, 1,
                                    [VppRoutePath(self.pg0.remote_ip4,
                                                  self.pg0.sw_if_index,
                                                  labels=[])])
        route_33_eos.add_vpp_config()

        self.vapi.cli("clear trace")
        tx = self.create_stream_labelled_ip4(self.pg0, [33])
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg0.get_capture()
        self.verify_capture_ip4(self.pg0, rx, tx)

        #
        # disposed packets have an invalid IPv4 checkusm
        #
        tx = self.create_stream_labelled_ip4(self.pg0, [33],
                                             dst_ip=self.pg0.remote_ip4,
                                             n=65,
                                             chksum=1)
        self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")

        #
        # An MPLS xconnect - EOS label in IPv6 out
        #
        route_333_eos = VppMplsRoute(
            self, 333, 1,
            [VppRoutePath(self.pg0.remote_ip6,
                          self.pg0.sw_if_index,
                          labels=[],
                          proto=DpoProto.DPO_PROTO_IP6)])
        route_333_eos.add_vpp_config()

        self.vapi.cli("clear trace")
        tx = self.create_stream_labelled_ip6(self.pg0, [333], 64)
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg0.get_capture()
        self.verify_capture_ip6(self.pg0, rx, tx)

        #
        # disposed packets have an TTL expired
        #
        tx = self.create_stream_labelled_ip6(self.pg0, [333], 64,
                                             dst_ip=self.pg1.remote_ip6,
                                             hlim=1)

        self.vapi.cli("clear trace")
        tx = self.create_stream_labelled_ip6(self.pg0, [333], 64,
                                             dst_ip=self.pg1.remote_ip6,
                                             hlim=0)
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg0.get_capture()
        self.verify_capture_ip6_icmp(self.pg0, rx, tx)

        #
        # An MPLS xconnect - EOS label in IPv6 out w imp-null
        #
        route_334_eos = VppMplsRoute(
            self, 334, 1,
            [VppRoutePath(self.pg0.remote_ip6,
                          self.pg0.sw_if_index,
                          labels=[3],
                          proto=DpoProto.DPO_PROTO_IP6)])
        route_334_eos.add_vpp_config()

        self.vapi.cli("clear trace")
        tx = self.create_stream_labelled_ip6(self.pg0, [334], 64)
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg0.get_capture()
        self.verify_capture_ip6(self.pg0, rx, tx)

        #
        # disposed packets have an TTL expired
        #
        self.vapi.cli("clear trace")
        tx = self.create_stream_labelled_ip6(self.pg0, [334], 64,
                                             dst_ip=self.pg1.remote_ip6,
                                             hlim=0)
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg0.get_capture()
        self.verify_capture_ip6_icmp(self.pg0, rx, tx)

        #
        # An MPLS xconnect - non-EOS label in IP out - an invalid configuration
        # so this traffic should be dropped.
        #
        route_33_neos = VppMplsRoute(self, 33, 0,
                                     [VppRoutePath(self.pg0.remote_ip4,
                                                   self.pg0.sw_if_index,
                                                   labels=[])])
        route_33_neos.add_vpp_config()

        self.vapi.cli("clear trace")
        tx = self.create_stream_labelled_ip4(self.pg0, [33, 99])
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()
        self.pg0.assert_nothing_captured(
            remark="MPLS non-EOS packets popped and forwarded")

        #
        # A recursive EOS x-connect, which resolves through another x-connect
        #
        route_34_eos = VppMplsRoute(self, 34, 1,
                                    [VppRoutePath("0.0.0.0",
                                                  0xffffffff,
                                                  nh_via_label=32,
                                                  labels=[44, 45])])
        route_34_eos.add_vpp_config()

        tx = self.create_stream_labelled_ip4(self.pg0, [34])
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg0.get_capture()
        self.verify_capture_labelled(self.pg0, rx, tx, [33, 44, 45], num=2)

        #
        # A recursive non-EOS x-connect, which resolves through another
        # x-connect
        #
        route_34_neos = VppMplsRoute(self, 34, 0,
                                     [VppRoutePath("0.0.0.0",
                                                   0xffffffff,
                                                   nh_via_label=32,
                                                   labels=[44, 46])])
        route_34_neos.add_vpp_config()

        self.vapi.cli("clear trace")
        tx = self.create_stream_labelled_ip4(self.pg0, [34, 99])
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg0.get_capture()
        # it's the 2nd (counting from 0) label in the stack that is swapped
        self.verify_capture_labelled(self.pg0, rx, tx, [33, 44, 46, 99], num=2)

        #
        # an recursive IP route that resolves through the recursive non-eos
        # x-connect
        #
        ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
                                 [VppRoutePath("0.0.0.0",
                                               0xffffffff,
                                               nh_via_label=34,
                                               labels=[55])])
        ip_10_0_0_1.add_vpp_config()

        self.vapi.cli("clear trace")
        tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg0.get_capture()
        self.verify_capture_labelled_ip4(self.pg0, rx, tx, [33, 44, 46, 55])

        ip_10_0_0_1.remove_vpp_config()
        route_34_neos.remove_vpp_config()
        route_34_eos.remove_vpp_config()
        route_33_neos.remove_vpp_config()
        route_33_eos.remove_vpp_config()
        route_32_neos.remove_vpp_config()
        route_32_eos.remove_vpp_config()

    def test_bind(self):
        """ MPLS Local Label Binding test """

        #
        # Add a non-recursive route with a single out label
        #
        route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
                                    [VppRoutePath(self.pg0.remote_ip4,
                                                  self.pg0.sw_if_index,
                                                  labels=[45])])
        route_10_0_0_1.add_vpp_config()

        # bind a local label to the route
        binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
        binding.add_vpp_config()

        # non-EOS stream
        self.vapi.cli("clear trace")
        tx = self.create_stream_labelled_ip4(self.pg0, [44, 99])
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg0.get_capture()
        self.verify_capture_labelled(self.pg0, rx, tx, [45, 99])

        # EOS stream
        self.vapi.cli("clear trace")
        tx = self.create_stream_labelled_ip4(self.pg0, [44])
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg0.get_capture()
        self.verify_capture_labelled(self.pg0, rx, tx, [45])

        # IP stream
        self.vapi.cli("clear trace")
        tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg0.get_capture()
        self.verify_capture_labelled_ip4(self.pg0, rx, tx, [45])

        #
        # cleanup
        #
        binding.remove_vpp_config()
        route_10_0_0_1.remove_vpp_config()

    def test_imposition(self):
        """ MPLS label imposition test """

        #
        # Add a non-recursive route with a single out label
        #
        route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
                                    [VppRoutePath(self.pg0.remote_ip4,
                                                  self.pg0.sw_if_index,
                                                  labels=[32])])
        route_10_0_0_1.add_vpp_config()

        #
        # a stream that matches the route for 10.0.0.1
        # PG0 is in the default table
        #
        self.vapi.cli("clear trace")
        tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg0.get_capture()
        self.verify_capture_labelled_ip4(self.pg0, rx, tx, [32])

        #
        # Add a non-recursive route with a 3 out labels
        #
        route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
                                    [VppRoutePath(self.pg0.remote_ip4,
                                                  self.pg0.sw_if_index,
                                                  labels=[32, 33, 34])])
        route_10_0_0_2.add_vpp_config()

        #
        # a stream that matches the route for 10.0.0.1
        # PG0 is in the default table
        #
        self.vapi.cli("clear trace")
        tx = self.create_stream_ip4(self.pg0, "10.0.0.2")
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg0.get_capture()
        self.verify_capture_labelled_ip4(self.pg0, rx, tx, [32, 33, 34])

        #
        # add a recursive path, with output label, via the 1 label route
        #
        route_11_0_0_1 = VppIpRoute(self, "11.0.0.1", 32,
                                    [VppRoutePath("10.0.0.1",
                                                  0xffffffff,
                                                  labels=[44])])
        route_11_0_0_1.add_vpp_config()

        #
        # a stream that matches the route for 11.0.0.1, should pick up
        # the label stack for 11.0.0.1 and 10.0.0.1
        #
        self.vapi.cli("clear trace")
        tx = self.create_stream_ip4(self.pg0, "11.0.0.1")
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg0.get_capture()
        self.verify_capture_labelled_ip4(self.pg0, rx, tx, [32, 44])

        #
        # add a recursive path, with 2 labels, via the 3 label route
        #
        route_11_0_0_2 = VppIpRoute(self, "11.0.0.2", 32,
                                    [VppRoutePath("10.0.0.2",
                                                  0xffffffff,
                                                  labels=[44, 45])])
        route_11_0_0_2.add_vpp_config()

        #
        # a stream that matches the route for 11.0.0.1, should pick up
        # the label stack for 11.0.0.1 and 10.0.0.1
        #
        self.vapi.cli("clear trace")
        tx = self.create_stream_ip4(self.pg0, "11.0.0.2")
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg0.get_capture()
        self.verify_capture_labelled_ip4(
            self.pg0, rx, tx, [32, 33, 34, 44, 45])

        #
        # cleanup
        #
        route_11_0_0_2.remove_vpp_config()
        route_11_0_0_1.remove_vpp_config()
        route_10_0_0_2.remove_vpp_config()
        route_10_0_0_1.remove_vpp_config()

    def test_tunnel(self):
        """ MPLS Tunnel Tests """

        #
        # Create a tunnel with a single out label
        #
        mpls_tun = VppMPLSTunnelInterface(self,
                                          [VppRoutePath(self.pg0.remote_ip4,
                                                        self.pg0.sw_if_index,
                                                        labels=[44, 46])])
        mpls_tun.add_vpp_config()
        mpls_tun.admin_up()

        #
        # add an unlabelled route through the new tunnel
        #
        route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
                                    [VppRoutePath("0.0.0.0",
                                                  mpls_tun._sw_if_index)])
        route_10_0_0_3.add_vpp_config()

        self.vapi.cli("clear trace")
        tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg0.get_capture()
        self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [44, 46])

        #
        # add a labelled route through the new tunnel
        #
        route_10_0_0_4 = VppIpRoute(self, "10.0.0.4", 32,
                                    [VppRoutePath("0.0.0.0",
                                                  mpls_tun._sw_if_index,
                                                  labels=[33])])
        route_10_0_0_4.add_vpp_config()

        self.vapi.cli("clear trace")
        tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg0.get_capture()
        self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [44, 46, 33],
                                         ttl=63, top=2)

    def test_v4_exp_null(self):
        """ MPLS V4 Explicit NULL test """

        #
        # The first test case has an MPLS TTL of 0
        # all packet should be dropped
        #
        tx = self.create_stream_labelled_ip4(self.pg0, [0], 0)
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        self.pg0.assert_nothing_captured(remark="MPLS TTL=0 packets forwarded")

        #
        # a stream with a non-zero MPLS TTL
        # PG0 is in the default table
        #
        tx = self.create_stream_labelled_ip4(self.pg0, [0])
        self.pg0.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg0.get_capture()
        self.verify_capture_ip4(self.pg0, rx, tx)

        #
        # a stream with a non-zero MPLS TTL
        # PG1 is in table 1
        # we are ensuring the post-pop lookup occurs in the VRF table
        #
        self.vapi.cli("clear trace")
        tx = self.create_stream_labelled_ip4(self.pg1, [0])
        self.pg1.add_stream(tx)

        self.pg_enable_capture(self.pg_interfaces)
        self.pg_start()

        rx = self.pg1.get_capture()
        self.verify_capture_ip4(self.pg0, rx, tx)

    def test_v6_exp_null(self):
        """ MPLS V6 Explicit NULL test """

        #
        # a stream with a non-zero MPLS TTL
        # PG0 is in the default table
        #
        self.vapi.cli("clear trace")
        tx = self.create_stream_labelled_ip6(self.pg0, 2, 2)
        <style>.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */</style><div class="highlight"><pre><span></span>dpdk (17.05.1-1~git1) UNRELEASED; urgency=medium

  [ Luca Boccassi ]
  * New Upstream release 17.05.1.
  * Fix reproducibility of librte-eal linuxapp.

  [ Christian Ehrhardt ]
  * d/rules: fix reference path of dpdk-devbind to match the new
    subdirectory which is in /usr/share/dpdk/usertools
  * Fix d/p/fix-vhost-user-socket-permission.patch: add mis-dropped
    create_unix_socket call and reposition rte_eal_set_socket_permissions
  * Fix d/p/fix-vhost-user-socket-permission.patch
    - add accidenitally dropped create_unix_socket call
    - reposition rte_eal_set_socket_permissions to match 17.05 handling of
      vhost-user server sockets (and their late binding)

 -- Luca Boccassi &lt;luca.boccassi@gmail.com&gt;  Mon, 03 Jul 2017 15:15:40 +0100

dpdk (17.05-1~git1) UNRELEASED; urgency=medium

  [ Christian Ehrhardt ]
  * New Upstream release 17.05; For a full list of changes (LP: #1691661)
    see http://dpdk.org/doc/guides/rel_notes/release_17_05.html
    - adapt to use MAJOR_ABI configuration to avoid the sub-lib abi
      version breakage of the past.
    - add d/update-helper* to update d/control and d/*.symbols for new versions
    - adapt to new build trigger and location of tests; provide further
      test tools (testacl, testpipeline) together with the already
      provided &quot;test&quot; tool in /usr/share/dpdk/test/ of dpdk-dev.
      Note: testpmd is installed &quot;officially&quot; by install-sdk and therefore
      stays separate from other test tools.
    - updated library arch availability/dependency: librte-kni is
      available on ppc64el; librte-pmd-i40e on all arches;
      librte-pmd-fm10k gone on ppc64el
    - package the 19 new sub-libs / pmds that are now built by default
    - rename and update symbols files to match the update to DPDK 17.05

  [ Luca Boccassi ]
  * Rename libraries after ABI major version rather than source version.
  * Always set CONFIG_RTE_MAJOR_ABI, even for custom config files as all the
    packaging is tuned around it.
  * Drop patches merged upstream and refresh
    fix-vhost-user-socket-permission.patch
  * Add patches to make the documentation and linker script builds fully
    reproducible.
  * Add patches to make the libraries and PMDs builds fully reproducible,
    by making the listing order of headers, source files and objects in
    the makefiles stable (via sorting).
  * Install headers with arch-specific content in /usr/include/&lt;multiarch&gt;/dpdk
    to make libdpdk-dev multiarch-compliant.
    To ensure backward compatibility in x86_64, which is what most of the
    consumers use, symlink x86_64 headers in /usr/include/dpdk.
    pkg-config returns the arch-specific headers first so that other
    architectures are still compatible.
    Also create a full copy of the headers in the dpdk-dev SDK package, as it
    does not support multiple levels of headers.

 -- Christian Ehrhardt &lt;christian.ehrhardt@canonical.com&gt;  Tue, 16 May 2017 15:38:17 +0200

dpdk (16.11.2-1~git1) UNRELEASED; urgency=medium

  [ Christian Ehrhardt ]
  * Merge stable update to 16.11.2; For a list of changes
    see http://dpdk.org/ml/archives/announce/2017-May/000131.html
  * Dropped changes - patches that were included in 16.11.2 stable:
    - d/p/kni-fix-build-with-kernel-4.11.patch
    - d/p/nicvf-0002-net-thunderx-fix-32-bit-build.patch
    - d/p/nicvf-0006-mk-fix-lib-filtering-when-linking-app.patch
    - d/p/nicvf-0008-net-thunderx-fix-stats-access-out-of-bounds.patch
    - d/p/nicvf-0010-net-thunderx-fix-deadlock-in-Rx-path.patch

  [ Luca Boccassi ]
  * Optionally generate libdpdk-dbgsym metapackage that depends on every
    librte/PMD binary package&#39;s dbgsym. Keep it disabled by default, and
    let users choose to enable it by passing dbgsym_meta via DEB_BUILD_OPTIONS.
    Thanks Jan Blunck for the patch!
  * Generate dependency list of libdpdk-dev to all librte and PMDs packages
    dynamically at build time.
  * Generate list of recommends for dpdk dynamically at build time.
  * dpdk-modules-$KVERS: depend on same kernel version used to build rather than
    just recommend - in-kernel API/ABI is not stable.
  * Support for building packages for the new mempool framework has been added.
    In 17.05 and newer a mempool framework was added, that has to be loaded
    like a PMD. So any &quot;plugin&quot; will be linked in RTE_EAL_PMD_PATH just like
    the PMDs. No mempool plugins are built for now, so it is currently a no-op.
  * Drop libethdev4, librte-cryptodev1 and librte-eal2 transitional packages,
    no longer needed.
  * Fix some upstream documentation links in the packages metadata.
    Thanks Chas Williams!
  * Fix building debugging symbols for -dbgsym packages. Thanks Chas Williams!

 -- Christian Ehrhardt &lt;christian.ehrhardt@canonical.com&gt;  Thu, 08 Jun 2017 10:05:44 -0600

dpdk (16.11.1-1~git1) UNRELEASED; urgency=medium

  [ Christian Ehrhardt ]
  * Merge stable update to 16.11.1; For a list of changes
    see http://dpdk.org/ml/archives/dev/2017-March/058930.html
  * dpdk.conf: add info about unwanted effects of multiple hugepage
    mountpoints
  * d/p/dpdk-dev-v3-eal-sPAPR-IOMMU-support-in-pci-probing-for-vfio-pci-
    in-ppc64le.patch: sPAPR IOMMU based pci probing enabled for vfio-pci
    devices.
  * enable librte-pmd-i40e1 for ppc64el
    - debian/control: enable arch onpackage
    - d/p/dpdk-dev-v4-i40e-implement-vector-PMD-for-altivec.patch: add i40e
      PMD / vector PMD implementation and enable by default on ppc64el
  * fix library availability/dependency
    - librte-kni is built on ppc64el, fix dependency from libdpdk-dev
    - librte-pmd-fm10k1 is not built on ppc64el (empty pkg atm) adapt arch
    - librte-pmd-i40e is built on all architectures now
  * Fix up thunderx to make arm support useful on more devices (LP: #1691659)
    - d/p/nicvf-00[01-10]* backports of 17.02/17.05 fixes for thunderx
    - d/control: dependencies and package for librte-pmd-thunderx-nicvf
    - d/librte-pmd-thunderx-nicvf1.symbols: tracking library symbols
  * fix dpdk-rte-kni dkms issues with kernel 4.11 (LP: #1691830)
    - d/p/kni-fix-build-with-kernel-4.11.patch: fix pci_enable_msix usage
    - d/p/kni-fix-ethtool-build-with-kernel-4.11.patch: Use new signal header
  * ensure man pages are bundled with executables on all architectures
  * d/p/fix-vhost-user-socket-permission.patch: updated to work with newer
    openvswitch versions

  [ Luca Boccassi ]
  * Simplify debian/rules by using upstream&#39;s install target
    and Debian&#39;s multiarch dir. Thanks Jan Blunck!
  * Clarify that only the kni and igb_uio kernel modules are
    distributed exclusively under the GPL2 in debian/copyright
  * Add new DEB_BUILD_OPTIONS &quot;nodoc&quot; to allow users to avoid
    building the DPDK documentation
  * Add new DEB_BUILD_OPTIONS &quot;nostatic&quot; to allow users to avoid
    building the DPDK static libraries
  * Add try-restart to dpdk.init script
  * Update Standards-Version to 4.0.0

 -- Christian Ehrhardt &lt;christian.ehrhardt@canonical.com&gt;  Thu, 08 Dec 2016 16:58:37 +0100

dpdk (16.11-1~git1) UNRELEASED; urgency=medium

  [ Christian Ehrhardt ]
  * Merge stable release 16.11 and adapt patches
    - imported latest stable release from dpdk-16.11.tar.gz
      stable release changelog at
      http://dpdk.org/doc/guides-16.11/rel_notes/release_16_11.html
    - Delete patches that are upstream:
      - d/p/dpdk-dev-ppc-enable-*
      - d/p/dpdk-dev-v2-*-4*
      - d/p/rte-devel-build-env.patch
      - d/p/rte-compile-pre-cppflags.patch
      - d/p/make-load-devel-config-not-to-appear-as-executable.patch
      - d/p/dpdk-dev-doc-fix-old-dpdk-nic-bind.py-references.patch
      - d/p/fix-double-license-info.patch
  * Added changes
    - add qede pmd now built by default
    - add new librte-net library
    - update symbols files to match the new release
    - make autotest dep8 test always pass (failed fatally on e.g. LP).
      We want to stabilize and get more logs of different environments before
      we can enable it as a gating test.
    - Make dpdk-dev&#39;s ${RTE_SDK}/${RTE_TARGET}/lib symlink multiarch aware
    - d/control: apply wrap and sort
    - d/control: Make the python-pyelftools only a Suggests
    - d/t/test-linkage: fix issues on non-x86 architectures
    - provide older ABI levels via backward compatibility of new DPDK libraries
      - d/control: add compat packages for old ABI versions
      - d/rules: generate and use multiarch aware link files for the soname
        mapping

  [ Luca Boccassi ]
  * Make dpdk suggest dpdk-doc (Closes: #847626)

 -- Christian Ehrhardt &lt;christian.ehrhardt@canonical.com&gt;  Thu, 08 Dec 2016 16:58:37 +0100

dpdk (16.07.2-1~git1) UNRELEASED; urgency=medium

  * Merge stable release 16.07.2 and adapt patches
    - imported latest stable release from dpdk-16.07.2.tar.gz
      stable release changelog at
      http://dpdk.org/doc/guides-16.07/rel_notes/release_16_07.html
    - Deleted:
      - d/p/dpdk-dev-v2-kni-fix-build-with-kernel-4.8.patch
      - d/p/fix-unusual-interpreter.patch
      - d/p/dpdk-dev-examples-ip_pipeline-fix-pmd-driver-parameter.patch
      - d/p/dpdk-dev-kni-fix-build-with-kernel-4.9.patch
      - d/p/dpdk-dev-ppc-enable-7-7-examples-ip_pipeline-fix-lcore-mapping-for-
        ppc64.patch
    - Refreshed (only offset changes)
      - d/p/dpdk-dev-ppc-enable-1-7-lpm-add-AltiVec-for-ppc64.patch
      - d/p/dpdk-dev-ppc-enable-2-7-acl-add-AltiVec-for-ppc64.patch
      - d/p/dpdk-dev-ppc-enable-4-7-sched-enable-on-ppc64le.patch
      - d/p/dpdk-dev-ppc-enable-6-7-config-enable-packet-framework-on-
        ppc64le.patch
      - d/p/dpdk-dev-v2-2-4-doc-rendering-and-installation-of-man-pages.patch
      - d/p/dpdk-dev-v2-3-4-doc-add-basic-invocation-info-for-dpdk-pmdinfo.patch
      - d/p/dpdk-dev-v2-4-4-doc-add-basic-invocation-info-for-dpdk-devbind.patch

 -- Christian Ehrhardt &lt;christian.ehrhardt@canonical.com&gt;  Mon, 05 Dec 2016 07:08:01 +0100

dpdk (16.07-2~git1) UNRELEASED; urgency=medium

  * Team upload.

  [ Christian Ehrhardt ]
  * Fix d/p/fix-vhost-user-socket-permission.patch for dpdk 16.07
    server/client sockets.
  * d/control add python-elftools and hwdata dependencies to dpdk for the tool
    dpdk-pmdinfo.
  * d/rules utilize RTE_EAL_PMD_PATH to autoload pmd drivers
    - d/dpdk-doc.README.Debian document usage of RTE_EAL_PMD_PATH
    - d/control let the runtime of dpdk recommend the pmd drivers to make them
      available for auto-probing devices.
  * d/rules support DEB_BUILD_OPTIONS parallel
  * d/rules bundle autotest as it is ready after build into dpdk-dev
    to make it available for autopkgtest and likewise developers.
  * enable dpdk autotests
    - d/t/test-autotest enable autotests as dep8 test. These fail in many
      build environments, so put them in an adt where required characteristics
      can be specified

  [ Gowrishankar Muthukrishnan ]
  * d/p/dpdk-dev-examples-ip_pipeline-fix-pmd-driver-parameter.patch to make
    ip_pipeline work properly with -d eal parameter
  * Update to d/p/dpdk-dev-examples-ip_pipeline-fix-pmd-driver-parameter.patch
    fixing dl_open issues.

  [ Santiago R.R. ]
  * debian/rules: Only export hardening related building HOST_/EXTRA flags
    when dpkg-dev &lt; 1.18.11. On newer dpkg-dev versions, dpkg-buildflags
    handle them directly and are injected by gcc (6.x). Closes: #843685.

  [ Luca Boccassi ]
  * Fix DKMS build to use the requested kernel version rather than the running
    one. (Closes: #843864)
  * Fix kernel modules build failures due to the new -fPIE default by passing
    -fno-PIE.
  * Backport dpdk-dev-kni-fix-build-with-kernel-4.9.patch to fix kernel modules
    build failures on Linux 4.9.
  * Mark dpdk-doc as Multi-Arch: foreign

 -- Santiago Ruano Rincón &lt;santiagorr@riseup.net&gt;  Wed, 09 Nov 2016 16:04:15 +0100

dpdk (16.07-1) unstable; urgency=medium

  [ Christian Ehrhardt ]
  * Merge with upstream DPDK 16.07 release
  * Cleanup Lintian Warnings
    - d/p/fix-unusual-interpreter.patch fixes &quot;W: dpdk-doc:
      unusual-interpreter&quot;
    - d/p/fix-double-license-info.patch fixes &quot;W: dpdk-rte-kni-dkms:
      extra-license-file&quot;
  * Renamed d/p/ubuntu-fix-vhost-user-socket-permission.patch to
    d/p/fix-vhost-user-socket-permission.patch
  * Add lintian-overrides for: E: dpdk-dev: arch-dependent-file-in-usr-share
    These binaries are part of the sdk and meant to be shipped with the sdk.
  * d/p/dpdk-dev-doc-fix-old-dpdk-nic-bind.py-references.patch to fix the
    docs in regard to 16.07 changes renaming dpdk_nic_bind
  * d/p/make-load-devel-config-not-to-appear-as-executable.patch to avoid
    accidentally executing as script and to fix unusual-interpreter lintian
    warning.
  * fix d/t/test-initscripts on more recent systemd environments
  * enable dpdk for ppc64el
    - add ppc64el arch to valid dpdk pmds and rte libraries
    - select power config and machine for dpdk build system
    - disable xen pmd for ppc64el
    - d/tests: make tests compatible with ppc64el
    - d/dpdk.conf, d/dpdk-init add 16M huge page support
    - d/p/fix-power-default-config.patch enable bond PMD on ppc64el
  * add man pages for installed binaries
    - add backport of patches from upstream
    - call generation of man pages in d/rules
  * d/t/test-dkms retain dkms logs for debugging
  * fix rte_kni dkms build with kernel &gt;= 4.8
    - d/p/dpdk-dev-v2-kni-fix-build-with-kernel-4.8.patch replaced macro with
      its value in kni ethtool drivers.

  [ Anders Roxell ]
  * debian/control: add pciutils to the dpdk depends list, since lspci is used
    by the devbind script

  [ Luca Boccassi ]
  * Add ${shlib:Depends} to dpdk-dev dependencies
  * Install api and guides in dpdk-doc
  * Convert debian/rules to new style DH targets
  * Add Recommends: python to dpdk-doc since it ships python scripts among the
    examples, fixes Lintian warning about missing python dependencies
  * Fix typo in dpdk-doc.README.Debian, fixes &quot;W: dpdk-doc:
    spelling-error-in-readme-debian to to (duplicate word) to&quot;
  * Fix upstream rc versions by using &quot;~&quot; instead of &quot;-&quot;. 16.07-rc1 evaluates
    as newer than 16.07 which causes issues with Debian tools and Lintian
    errors and warnings:
    - W: libethdev4: latest-debian-changelog-entry-without-new-version
    - E: libethdev4: symbols-file-contains-current-version-with-debian-revision
      on symbol DPDK_16.04@DPDK_16.04 and 114 others
  * Add lintian-overrides for: &quot;W: dpdk-doc: embedded-javascript-library&quot;
  * Add optional binary kernel modules package, disabled by default (build with
    DEB_BUILD_OPTIONS=kernel_modules to enable). If enabled will build kernel
    modules against the local, current kernel version (override by adding
    ksrc=&lt;path/to/kernel/sources&gt; to DEB_BUILD_OPTIONS) into a
    dpdk-modules-&lt;kernel version&gt; package
  * Set HOST_/EXTRA/CPP/C/LDFLAGS in d/rules so that all built objects pick up
    all flags set by the dpkg environment, like hardening flags
  * Add rte-compile-pre-cppflags.patch to make all DPDK objects pick up the
    user specified or environment specified CPP/C/LDFLAGS.
    Fixes Lintian warning:
    - W: dpdk-dev: hardening-no-relro
         usr/share/dpdk/x86_64-default-linuxapp-gcc/app/dpdk-pmdinfogen
  * Add a brief HOWTO to debian/README.source with instructions to build the
    packages, for CI systems and the like.
  * Build with RTE_DEVEL_BUILD=n to avoid building test pmds with an rpath
    hardcoded to the package build PATH. Fixes Lintian Error:
    - E: dpdk: binary-or-shlib-defines-rpath usr/bin/dpdk-pdump
         /home/lboccass/git/dpdk_deb/debian/build/shared-root/lib
  * Fix d/watch file to point to fast.dpdk.org/rel
  * Allow DPDK_CONFIG, RTE_MACHINE, RTE_TARGET overrides via DEB_BUILD_OPTIONS
  * Initial Debian release. (Closes: #815760)
  * Use ?= to allow env var overrides in d/rules
  * Finalize changelog for upload to unstable.

  [ Santiago RR ]
  * improve debian/copyright
  * remove duplicate entries from d/control
  * debian/control:
    - dpdk: recommends dkms packages (dpdk-igb-uio-dkms, dpdk-rte-kni-dkms) on
      arm64 and suggest for other architectures.

  [ Gowrishankar Muthukrishnan ]
  * enable formerly disabled libraries in ppc64le config
  * d/control provide now supported packages for ppc64le
  * d/p/dpdk-dev-ppc-enable-* backports from dpdk to enable more features
    for ppc64le

 -- Luca Boccassi &lt;luca.boccassi@gmail.com&gt;  Tue, 27 Sep 2016 16:40:31 +0100

dpdk (16.07~rc5-1) UNRELEASED; urgency=medium

  [ Ricardo Salveti de Araujo ]
  * Merge with upstream DPDK 16.07-rc5 release

  [ Luca Boccassi ]
  * Generate pkgconfig and ship it in libdpdk-dev
  * Document use of dquilt for patches in debian/README.source

 -- Ricardo Salveti de Araujo &lt;rsalveti@rsalveti.net&gt;  Tue, 26 Jul 2016 14:13:38 -0300

dpdk (16.07~rc4-1) UNRELEASED; urgency=medium

  * Merge with upstream DPDK 16.07-rc4 release
    - Tools renamed, dpdk_nic_bind is now dpdk-devbind
  * Adapt d/p/ubuntu-fix-vhost-user-socket-permission.patch for dpdk 16.07-rc4

 -- Ricardo Salveti de Araujo &lt;rsalveti@rsalveti.net&gt;  Mon, 25 Jul 2016 13:38:13 -0300

dpdk (16.07~rc3-1) UNRELEASED; urgency=medium

  [ Christian Ehrhardt ]
  * Merge with upstream DPDK 16.07-rc3 release
  * droping patches/backports that are already upstream in DPDK 16.07-rc3
    - d/p/ubuntu-fix-bond-symbol-export.patch
    - d/p/ubuntu-backport-33-vhost-user-add-error-handling-for-fd-1023.patch
  * adapt d/p/ubuntu-fix-vhost-user-socket-permission.patch for dpdk 16.07-rc3
  * update symbols

  [ Ricardo Salveti de Araujo ]
  * debian/rules:
    - Allow all make commands to be verbose
    - Fix libdpdk-dev headers path
  * Renaming package librte-pmd-e10001 to librte-pmd-e1000-1, to avoid mixing
    package name with soversion (lintian package-name-doesnt-match-sonames)
  * Adding package librte-pmd-bnxt1
  * Merging symbols files, handling the arch differences inline instead

  [ Anders Roxell ]
  * debian/control: add libpcap-dev to libdpdk-dev&#39;s Depends list

 -- Christian Ehrhardt &lt;christian.ehrhardt@canonical.com&gt;  Tue, 19 Jul 2016 08:32:06 +0200

dpdk (16.07~rc1-1) UNRELEASED; urgency=medium

  [ Christian Ehrhardt ]
  * Merge with upstream DPDK 16.07-rc1 release
  * droping patches/backports that are already upstream in DPDK 16.07
    - d/p/ubuntu-backport-39-lpm-fix-freeing-in-compatibility-mode.patch
      This was formerly part of a combined patch that we dropped because the
      majority is upstream (d/p/ubuntu-fix-lpm-use-after-free-and-leak.patch).
    - d/p/ubuntu-backport-40-linking-fixes-stage-[1-4]-4.patch
      d/p/ubuntu-backport-44-linking-cleanup.patch
      Fixing underlinking and overlinking issues in apps and libraries.
    - d/p/ubuntu-backport-41-fix-install-tar-1.29.patch
      Fix issues with tar &gt;=1.29 (Yakkety)
    - d/p/ubuntu-backport-42-increase-default-logging-level.patch
      avoid default debug messages causing a perf degradation
    - d/p/ubuntu-backport-43-fix-level-type-retrieving.patch
      Fix type retrieving which was broken in standard threads
    - d/p/ubuntu-fix-xenvirt-support-dynamic-page-size.patch: fix build
      failure on arm64
  * droping patches/backports that are no more applicable
    - d/p/ubuntu-backport-38-* was never accepted despite looking good.
      Upstream discussion around proper successor started.
  * keeping patches:
    - d/p/ubuntu-backport-33-vhost-user-add-error-handling-for-fd-1023.patch
      Was never accepted, Upstream discussion around proper successor started.
  * adapt debian/* to upstream changes
    - update symbols and ABI versions
    - add librte-pdump1
  * adding changes
   - fix exported symbols of librte_pmd_bond (sent upstream, can be dropped
     later)

 -- Christian Ehrhardt &lt;christian.ehrhardt@canonical.com&gt;  Wed, 06 Jul 2016 09:40:49 +0200

dpdk (16.04-1) UNRELEASED; urgency=medium

  [ Christian Ehrhardt ]
  * Merge with upstream DPDK 16.04 release
  * droping patches/backports that are already upstream in DPDK 16.04
    - d/p/ubuntu-fix-doc-installpath.patch
    - d/p/ubuntu-fix-testpmd-without-xen.patch
    - d/p/ubuntu-fix-lpm-use-after-free-and-leak.patch
    - d/p/ubuntu-backport-[01-32,34-35] backports for stability
    - d/p/ubuntu-backport-[36-37] but keep doc and example changes in d/*
  * droping patches for soname / linking fixups.
    - Upstream now goes with proper soname/abi/api handling per sublib plus a
      linker script.
    - dropped d/p/ubuntu-combined-shared-lib-abiversion.patch
    - dropped d/p/ubuntu-fix-library-linkage.patch
  * keeping patches:
    - d/p/ubuntu-backport-38-* fix for memory leak
      this now applies as is, so changed from a modified backport to match the
      post 16.04 upstream commit now.
    - d/p/ubuntu-backport-33-vhost-user-add-error-handling-for-fd-1023.patch
    - doc and example changes that were related to d/p/ubuntu-backport-[36-37]
    - d/p/ubuntu-fix-vhost-user-socket-permission.patch adapted for dpdk-16.04:
      In the new build system with sublibs the exposed function needs to be
      listed in lib/librte_eal/linuxapp/eal/rte_eal_version.map
  * adding upstream backports - can be dropped when merging DPDK 16.07.
    - d/p/ubuntu-backport-39-lpm-fix-freeing-in-compatibility-mode.patch
      This was formerly part of a combined patch that we dropped because the
      majority is upstream (d/p/ubuntu-fix-lpm-use-after-free-and-leak.patch).
    - d/p/ubuntu-backport-40-linking-fixes-stage-[1-4]-4.patch
      d/p/ubuntu-backport-44-linking-cleanup.patch
      Fixing underlinking and overlinking issues in apps and libraries.
    - d/p/ubuntu-backport-41-fix-install-tar-1.29.patch
      Fix issues with tar &gt;=1.29 (Yakkety)
    - d/p/ubuntu-backport-42-increase-default-logging-level.patch
      avoid default debug messages causing a perf degradation
    - d/p/ubuntu-backport-43-fix-level-type-retrieving.patch
      Fix type retrieving which was broken in standard threads
  * adapt to new build system
    - drop enabling the following build config symbols as they no more exist
        CONFIG_RTE_BUILD_COMBINE_LIBS
    - Sub-Libraries are now packaged in a versioned package per library. That
      allows consumers of dpdk to just depend on what they need. As well as
      installation of multiple .so versions concurrently.
    - added the hidden dependency of librte_eal to librte_mempool
    - use dpkg-buildflags and properly enable hardening
  * Adding DKMS package for rte_kni (LP: #1592786)

  [ Ricardo Salveti ]
  * Adding support for ARM64:
    - debian/control: adding arm64 to the supported architecture list
    - debian/rules: supporting dpdk config and machine for arm64
    - d/p/ubuntu-fix-xenvirt-support-dynamic-page-size.patch: fix build
      failure on arm64
    - debian/dpdk-sdk-env.sh: generating the right RTE_TARGET during build
      time, so we can also make it compatible with ARM64
    - debian/tests: also making tests compatible with ARM64
  * Adding DKMS package for igb_uio
  * Build static dpdk with -fPIC so it can be used by shared libraries
  * debian/copyright: fixing Canonical&#39;s copyright entry
  * Renaming symbol files so they can match the right package
  * Drop the arch specific symbol files, as they are identical

  [ Anders Roxell ]
  * debian/dpdk.init: add remote_fs (lintian)
  * debian/control: fixing week-library-dev-dependency (lintian)

 -- Christian Ehrhardt &lt;christian.ehrhardt@canonical.com&gt;  Tue, 17 May 2016 14:23:21 +0200

dpdk (2.2.0-0ubuntu9) yakkety; urgency=medium

  * d/p/ubuntu-backport-[36-37] fix virtio issues (LP: #1570195):
    - don&#39;t let DPDK initialize virtio devices still in use by the kernel
    - this avoids conflicts between kernel and dpdk usage of those devices
    - an admin now has to unbind/bind devices as on physical hardware
    - this is in the dpdk 16.04 release and delta can then be dropped
    - d/dpdk-doc.README.Debian update for changes in virtio-pci handling
    - d/dpdk.interfaces update for changes in virtio-pci handling
  * d/p/ubuntu-backport-38... fix for memory leak (LP: #1570466):
    - call vhost_destroy_device on removing vhost user ports to fix memory leak
    - this likely is in the dpdk 16.07 release and delta can then be dropped
  * d/p/ubuntu-fix-vhost-user-socket-permission.patch fox (LP: #1546565):
    - when vhost_user sockets are created they are owner:group of the process
    - the DPDK api to create those has no way to specify owner:group
    - to fix that without breaking the API and potential workaround code in
      consumers of the library like openvswitch 2.6 for example. This patch
      adds an EAL commandline option to specify user:group created vhost_user
      sockets should have.

 -- Christian Ehrhardt &lt;christian.ehrhardt@canonical.com&gt;  Wed, 27 Apr 2016 07:52:48 -0500

dpdk (2.2.0-0ubuntu7) xenial; urgency=medium

  * Increase max_map_count after setting huge pages (LP: #1507921):
    - The default config of 65530 would cause issues as soon as about 64GB or
      more are used as 2M huge pages for dpdk.
    - Increase this value to base+2*#hugepages to avoid issues on huge systems.
  * d/p/ubuntu-backport-[28-32,34-35] backports for stability (LP: #1568838):
     - these will be in the 16.04 dpdk release, delta can then be dropped.
     - 5 fixes that do not change api/behaviour but fix serious issues.
        - 01 f82f705b lpm: fix allocation of an existing object
        - 02 f9bd3342 hash: fix multi-process support
        - 03 1aadacb5 hash: fix allocation of an existing object
        - 04 5d7bfb73 hash: fix race condition at creation
        - 05 fe671356 vfio: fix resource leak
        - 06 356445f9 port: fix ring writer buffer overflow
        - 07 52f7a5ae port: fix burst size mask type
  * d/p/ubuntu-backport-33-vhost-user-add-error-handling-for-fd-1023.patch
     - this will likely be in dpdk release 16.07 and delta can then be dropped.
     - fixes a crash on using fd&#39;s &gt;1023 (LP: #1566874)
  * d/p/ubuntu-fix-lpm-use-after-free-and-leak.patch fix lpm_free (LP: #1569375)
     - the old patches had an error freeing a pointer which had no meta data
     - that lead to a crash on any lpm_free call
     - folded into the fix that generally covers the lpm allocation and free
       weaknesses already (also there this particular mistake was added)

 -- Christian Ehrhardt &lt;christian.ehrhardt@canonical.com&gt;  Tue, 12 Apr 2016 16:13:47 +0200

dpdk (2.2.0-0ubuntu6) xenial; urgency=medium

  * d/dpdk-init fix handling of multiple huge page sizes (LP: #1557532):
     - dpdk-init now ensures non-default-hugepage-size mountpoints are
       available as well.
     - extra mountpoints are only created if requested in dpdk.conf and not yet
       available (e.g. by the admin).
  * d/dpdk-init fix issues with unassigned devices (LP: #1558485):
     - dpdk-init no more checks /sys/.../driver of the device unconditionally
     - removed the superfluous tr call in that path
  * d/p/ubuntu-fix-lpm-use-after-free-and-leak.patch lpm/lpm6 (LP: #1554009):
     - lpm/lpm6 fix use after free on lpm[6]_create
     - lpm/lpm6 fix missing frees of rules_tbl substructure
     - lpm/lpm6 fix missing free of lpm due to early exit
     - make RTE_LOG messages of the failed allocation unique
  * d/p/ubuntu-backport-[01-26] backport for stability (LP: #1559981):
     - these will be in the following dpdk release and delta can then be dropped
     - 26 fixes that do not change api/behaviour but fix serious issues
        - 01 d3a274ce app/testpmd: handle SIGINT and SIGTERM
        - 02 308df2bf Handle SIGINT and SIGTERM in l3fwd.
        - 03 da82ee17 tools: fix unbinding failure handling
        - 04 16c1814c tools: support Python 3 in bind script
        - 05 bb9f4085 tools: support binding to built-in kernel modules
        - 06 6e7caa1a eal/linux: support built-in kernel modules
        - 07 86f36ff9 mempool: fix leak when creation fails
        - 08 ca67ed28 vhost: fix leak of fds and mmaps
        - 09 fa11a8a7 port: fix crash for ring writer nodrop
        - 10 04f36690 port: fix crash for ethdev writer nodrop
        - 11 c7a4ff80 i40e: fix overflow
        - 12 097e920c i40e: fix inverted check for no refcount
        - 13 330aa319 i40e: fix VLAN filtering
        - 14 9f44dd3d i40e/base: fix missing check for stopped admin queue
        - 15 8a880736 i40e/base: fix driver load failure
        - 16 7656a546 fm10k: fix VLAN flag in scattered Rx
        - 17 c6fb0e55 pcap: fix captured frame length
        - 18 6e027237 bonding: fix detach of bonded device
        - 19 df3e8ad7 bonding: fix detach of slave devices
        - 20 786c990a bonding: copy entire config structure in mode 4
        - 21 6698820b bonding: do not ignore multicast in mode 4
        - 22 8997a10b bonding: fix active slaves with no primary
        - 23 7a7122ed bonding: do not activate slave twice
        - 24 2186fff3 bonding: fix crash when no slave device
        - 25 c680a4a8 virtio: fix crash in statistics functions
        - 26 3b1e3e4e virtio: fix descriptors pointing to the same buffer
  * d/p/ubuntu-backport-27-virtio-fix-restart.patch for (LP: #1559981):
     - fixing re-initializing the ethdev as openvswitch-dpdk does in the
       virtio pmd driver by moving the detection of already being initialized
       from virtio_dev_close to virtio_dev_start/stop
     - this will be in the following dpdk release and delta can then be dropped
  * d/rules build with debuginfo (LP: #1560839):
     - exporting CFLAGS for all dpdk build processes
     - dh_strip will automatically and create -dbgsym packages accordingly

 -- Christian Ehrhardt &lt;christian.ehrhardt@canonical.com&gt;  Wed, 23 Mar 2016 10:34:50 +0100

dpdk (2.2.0-0ubuntu5) xenial; urgency=medium

  * d/t/test-initscripts fix issues regarding 1G hugepages
     - the dep8 was already taking care of 1G hugepages being not supported in
       some environments. But it was failing when supported, but not enough
       memory available.

 -- Christian Ehrhardt &lt;christian.ehrhardt@canonical.com&gt;  Wed, 09 Mar 2016 17:19:24 +0000

dpdk (2.2.0-0ubuntu4) xenial; urgency=medium

  * harden d/dpdk-init for configuration issues (LP: #1551601):
     - detect and warn about bad bus specifications.
     - detect and warn about incomplete device specifications.
     - detect and warn about non existing pci IDs.
     - avoid failing when working with unassigned devices.
     - d/t/test-initscripts now testing various misconfigs.
     - d/t/test-initscripts now also verifying service status.
  * d/dpdk-init d/dpdk.conf now also support 1G hugepages (LP: #1551767):
     - detect and warn if 1G pages are not available but configured.
     - d/t/test-initscripts now also testing hugepage allocations.
     - d/dpdk.conf has an option to drop caches to incease the likeliness of
       successful 1G hugepage allocations (default off).
  * d/rules replaced uname -m with DEB_HOST_GNU_CPU (LP: #1551796):
  * fix testpmd to run without Xen environment (LP: #1551752):
     - upstream discussion is slow, but we need a fix now. We can drop this
       and change to the upstream solution when it is available.
  * avoid errors due to missing modules (LP: #1554397):
     - d/dpdk-init gracefully warns about missing modules.
     - d/control now suggests linux-image-generic.
     - d/dpdk.interfaces has a comment that makes the user aware.
  * d/dpdk-init fix failure loading vfio-pci (LP: #1554214):
     - d/dpdk-init no more converts &quot;-&quot; to &quot;_&quot; to make vfio-pci work
     - d/dpdk.interfaces enhanced comments and updated examples
     - d/dpdk-doc.README.debian got extra notes about using some modules
  * unify whitespace/tabs in packaging and scripts
     - tabs/spaces to just spaces in d/dpdk-init and d/dpdk.init.
     - few remaining spaces to tabs in d/rules
  * d/t/test-* now satisfy shellcheck
  * d/* fix various comments and guides to be more readable
  * d/dpdk-init and d/copyright updated copyright information

 -- Christian Ehrhardt &lt;christian.ehrhardt@cano