Docker: Forwarding Pods. 17/73017/1
authorSridhar K. N. Rao <sridhar.rao@spirent.com>
Fri, 12 Nov 2021 10:30:03 +0000 (16:00 +0530)
committerSridhar K. N. Rao <sridhar.rao@spirent.com>
Fri, 12 Nov 2021 10:31:30 +0000 (16:01 +0530)
This patch adds source file required to build 2 forwarding pods.
1. L2 and L3 Fowarding
2. VPP

Signed-off-by: Sridhar K. N. Rao <sridhar.rao@spirent.com>
Change-Id: Ibffea4ebe34a575d040778e45b6ba9e92af5e8b6

18 files changed:
tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/Dockerfile [moved from tools/docker/test-containers/dpdk-forwarding-pods/Dockerfile with 58% similarity]
tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/c_util.c [new file with mode: 0644]
tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/c_util.h [new file with mode: 0644]
tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/docker-entrypoint.sh [new file with mode: 0755]
tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/dpdk-args.c [new file with mode: 0644]
tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/dpdk-args.h [new file with mode: 0644]
tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/l2fwd_eal_init.txt [new file with mode: 0644]
tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/l2fwd_parse_args.txt [new file with mode: 0644]
tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/l2fwd_substitute.sh [new file with mode: 0755]
tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/l3fwd_eal_init.txt [new file with mode: 0644]
tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/l3fwd_parse_args.txt [new file with mode: 0644]
tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/l3fwd_substitute.sh [new file with mode: 0755]
tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/testpmd_eal_init.txt [new file with mode: 0644]
tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/testpmd_launch_args_parse.txt [new file with mode: 0644]
tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/testpmd_substitute.sh [new file with mode: 0755]
tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/vhost_substitute.sh [new file with mode: 0755]
tools/docker/test-containers/dpdk-forwarding-pods/vpp/Dockerfile [new file with mode: 0644]
tools/docker/test-containers/dpdk-forwarding-pods/vpp/get-vpp.sh [new file with mode: 0755]

@@ -6,14 +6,12 @@ FROM centos:7
 RUN rpm --import https://mirror.go-repo.io/centos/RPM-GPG-KEY-GO-REPO && curl -s https://mirror.go-repo.io/centos/go-repo.repo | tee /etc/yum.repos.d/go-repo.repo
 RUN yum groupinstall -y "Development Tools"
 RUN yum install -y wget numactl-devel git golang make; yum clean all
-# Debug Tools (if needed):
-#RUN yum install -y pciutils iproute; yum clean all
 
 #
 # Download and Build APP-NetUtil
 #
 WORKDIR /root/go/src/
-RUN go get github.com/openshift/app-netutil 2>&1 > /tmp/UserspaceDockerBuild.log || echo "Can ignore no GO files."
+RUN mkdir github.com && cd github.com && mkdir openshift && cd openshift && git clone https://github.com/openshift/app-netutil
 WORKDIR /root/go/src/github.com/openshift/app-netutil
 RUN make c_sample
 RUN cp bin/libnetutil_api.so /lib64/libnetutil_api.so; cp bin/libnetutil_api.h /usr/include/libnetutil_api.h
@@ -30,19 +28,10 @@ RUN tar -xpvf dpdk-${DPDK_VER}.tar.xz
 ENV RTE_TARGET=x86_64-native-linuxapp-gcc
 ENV RTE_SDK=${DPDK_DIR}
 WORKDIR ${DPDK_DIR}
-# DPDK_VER 19.08
 RUN sed -i -e 's/EAL_IGB_UIO=y/EAL_IGB_UIO=n/' config/common_linux
 RUN sed -i -e 's/KNI_KMOD=y/KNI_KMOD=n/' config/common_linux
 RUN sed -i -e 's/LIBRTE_KNI=y/LIBRTE_KNI=n/' config/common_linux
 RUN sed -i -e 's/LIBRTE_PMD_KNI=y/LIBRTE_PMD_KNI=n/' config/common_linux
-# Additional Debug if Needed
-#RUN sed -i -e 's/CONFIG_RTE_LIBRTE_ETHDEV_DEBUG=n/CONFIG_RTE_LIBRTE_ETHDEV_DEBUG=y/' config/common_base
-
-# DPDK_VER 19.02
-#RUN sed -i -e 's/EAL_IGB_UIO=y/EAL_IGB_UIO=n/' config/common_linuxapp
-#RUN sed -i -e 's/KNI_KMOD=y/KNI_KMOD=n/' config/common_linuxapp
-#RUN sed -i -e 's/LIBRTE_KNI=y/LIBRTE_KNI=n/' config/common_linuxapp
-#RUN sed -i -e 's/LIBRTE_PMD_KNI=y/LIBRTE_PMD_KNI=n/' config/common_linuxapp
 
 # Add vhost patch
 COPY ./vhost_substitute.sh ./vhost_substitute.sh
@@ -50,25 +39,14 @@ RUN ./vhost_substitute.sh
 
 RUN make install T=${RTE_TARGET} DESTDIR=${RTE_SDK}
 
-#
-# Build TestPmd
-#
-WORKDIR ${DPDK_DIR}/app/test-pmd
-COPY ./dpdk-args.c ./dpdk-args.c
-COPY ./dpdk-args.h ./dpdk-args.h
-COPY ./testpmd_eal_init.txt ./testpmd_eal_init.txt
-COPY ./testpmd_launch_args_parse.txt ./testpmd_launch_args_parse.txt
-COPY ./testpmd_substitute.sh ./testpmd_substitute.sh
-RUN ./testpmd_substitute.sh
-RUN make
-RUN cp testpmd /usr/bin/testpmd
-
 #
 # Build l2fwd
 #
 WORKDIR ${DPDK_DIR}/examples/l2fwd
 COPY ./dpdk-args.c ./dpdk-args.c
 COPY ./dpdk-args.h ./dpdk-args.h
+COPY ./c_util.c ./c_util.c
+COPY ./c_util.h ./c_util.h
 COPY ./l2fwd_eal_init.txt ./l2fwd_eal_init.txt
 COPY ./l2fwd_parse_args.txt ./l2fwd_parse_args.txt
 COPY ./l2fwd_substitute.sh ./l2fwd_substitute.sh
@@ -79,32 +57,31 @@ RUN cp build/l2fwd /usr/bin/l2fwd
 #
 # Build l3fwd
 #
-#WORKDIR ${DPDK_DIR}/examples/l3fwd
-#COPY ./dpdk-args.c ./dpdk-args.c
-#COPY ./dpdk-args.h ./dpdk-args.h
-#COPY ./l3fwd_eal_init.txt ./l3fwd_eal_init.txt
-#COPY ./l3fwd_parse_args.txt ./l3fwd_parse_args.txt
-#COPY ./l3fwd_substitute.sh ./l3fwd_substitute.sh
-#RUN ./l3fwd_substitute.sh
-#RUN make
-#RUN cp build/l3fwd /usr/bin/l3fwd
+WORKDIR ${DPDK_DIR}/examples/l3fwd
+COPY ./dpdk-args.c ./dpdk-args.c
+COPY ./dpdk-args.h ./dpdk-args.h
+COPY ./c_util.c ./c_util.c
+COPY ./c_util.h ./c_util.h
+COPY ./l3fwd_eal_init.txt ./l3fwd_eal_init.txt
+COPY ./l3fwd_parse_args.txt ./l3fwd_parse_args.txt
+COPY ./l3fwd_substitute.sh ./l3fwd_substitute.sh
+RUN ./l3fwd_substitute.sh
+RUN make
+RUN cp build/l3fwd /usr/bin/l3fwd
 
 # Copy default APP
 RUN cp /usr/bin/l2fwd /usr/bin/dpdk-app
 
 # -------- Import stage.
-# Docker 17.05 or higher
-# BEGIN
 FROM centos
 COPY --from=0 /usr/bin/dpdk-app /usr/bin/dpdk-app
 COPY --from=0 /usr/bin/l2fwd /usr/bin/l2fwd
-#COPY --from=0 /usr/bin/l3fwd /usr/bin/l3fwd
+COPY --from=0 /usr/bin/l3fwd /usr/bin/l3fwd
 COPY --from=0 /usr/bin/testpmd /usr/bin/testpmd
 COPY --from=0 /lib64/libnetutil_api.so /lib64/libnetutil_api.so
 COPY --from=0 /usr/lib64/libnuma.so.1 /usr/lib64/libnuma.so.1
+COPY --from=0 /root/go/src/github.com/openshift/app-netutil/bin/c_sample /usr/bin/c_sample
+
+RUN yum install -y pciutils iproute ethtool lshw; yum clean all
 # END
 
-# COPY ./docker-entrypoint.sh /
-# RUN chmod +x /docker-entrypoint.sh
-# ENTRYPOINT ["sleep", "5s"]
-#CMD ["l2fwd"]
diff --git a/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/c_util.c b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/c_util.c
new file mode 100644 (file)
index 0000000..73f46a9
--- /dev/null
@@ -0,0 +1,302 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright(c) 2021 Red Hat, Inc.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "libnetutil_api.h"
+#include "c_util.h"
+
+
+extern void dumpInterfaces(struct InterfaceResponse *pIfaceRsp) {
+       int i, j;
+       bool printReturn;
+
+       if ((pIfaceRsp) && (pIfaceRsp->pIface)) {
+               for (i = 0; i < pIfaceRsp->numIfacePopulated; i++) {
+                       printf("  Interface[%d]:\n", i);
+
+                       printf("  ");
+                       printf("  DeviceType=%s",
+                               (pIfaceRsp->pIface[i].DeviceType == NETUTIL_TYPE_HOST) ? "host" :
+                               (pIfaceRsp->pIface[i].DeviceType == NETUTIL_TYPE_SRIOV) ? "SR-IOV" :
+                               (pIfaceRsp->pIface[i].DeviceType == NETUTIL_TYPE_PCI) ? "PCI" :
+                               (pIfaceRsp->pIface[i].DeviceType == NETUTIL_TYPE_VHOST) ? "vHost" :
+                               (pIfaceRsp->pIface[i].DeviceType == NETUTIL_TYPE_MEMIF) ? "memif" :
+                               (pIfaceRsp->pIface[i].DeviceType == NETUTIL_TYPE_VDPA) ? "vDPA" :
+                               (pIfaceRsp->pIface[i].DeviceType == NETUTIL_TYPE_UNKNOWN) ? "unknown" : "error");
+
+                       if (pIfaceRsp->pIface[i].NetworkStatus.Name) {
+                               printf("  Name=\"%s\"", pIfaceRsp->pIface[i].NetworkStatus.Name);
+                       }
+                       if (pIfaceRsp->pIface[i].NetworkStatus.Interface) {
+                               printf("  Interface=\"%s\"", pIfaceRsp->pIface[i].NetworkStatus.Interface);
+                       }
+                       printf("\n");
+
+                       printReturn = false;
+                       if (pIfaceRsp->pIface[i].NetworkStatus.Mac) {
+                               if (printReturn == false) {
+                                       printReturn = true;
+                                       printf("  ");
+                               }
+                               printf("  MAC=\"%s\"", pIfaceRsp->pIface[i].NetworkStatus.Mac);
+                       }
+                       for (j = 0; j < NETUTIL_NUM_IPS; j++) {
+                               if (pIfaceRsp->pIface[i].NetworkStatus.IPs[j]) {
+                                       if (printReturn == false) {
+                                               printReturn = true;
+                                               printf("    DNS Nameservers: ");
+                                       }
+                                       printf("  IP=\"%s\"", pIfaceRsp->pIface[i].NetworkStatus.IPs[j]);
+                               }
+                       }
+                       if (printReturn) {
+                               printf("\n");
+                       }
+
+                       printReturn = false;
+                       for (j = 0; j < NETUTIL_NUM_DNS_NAMESERVERS; j++) {
+                               if (pIfaceRsp->pIface[i].NetworkStatus.DNS.Nameservers[j]) {
+                                       if (printReturn == false) {
+                                               printReturn = true;
+                                               printf("    DNS Nameservers: ");
+                                       }
+                                       printf(" \"%s\"", pIfaceRsp->pIface[i].NetworkStatus.DNS.Nameservers[j]);
+                               }
+                       }
+                       if (printReturn) {
+                               printf("\n");
+                       }
+
+                       if (pIfaceRsp->pIface[i].NetworkStatus.DNS.Domain) {
+                               printf("    DNS Domain: \"%s\"\n", pIfaceRsp->pIface[i].NetworkStatus.DNS.Domain);
+                       }
+
+                       printReturn = false;
+                       for (j = 0; j < NETUTIL_NUM_DNS_SEARCH; j++) {
+                               if (pIfaceRsp->pIface[i].NetworkStatus.DNS.Search[j]) {
+                                       if (printReturn == false) {
+                                               printReturn = true;
+                                               printf("    DNS Search: ");
+                                       }
+                                       printf(" \"%s\"", pIfaceRsp->pIface[i].NetworkStatus.DNS.Search[j]);
+                               }
+                       }
+                       if (printReturn) {
+                               printf("\n");
+                       }
+
+                       printReturn = false;
+                       for (j = 0; j < NETUTIL_NUM_DNS_OPTIONS; j++) {
+                               if (pIfaceRsp->pIface[i].NetworkStatus.DNS.Options[j]) {
+                                       if (printReturn == false) {
+                                               printReturn = true;
+                                               printf("    DNS Options: ");
+                                       }
+                                       printf(" \"%s\"", pIfaceRsp->pIface[i].NetworkStatus.DNS.Options[j]);
+                               }
+                       }
+                       if (printReturn) {
+                               printf("\n");
+                       }
+
+                       switch (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Type) {
+                               case NETUTIL_TYPE_PCI:
+                                       printf("    Type=PCI");
+                                       if (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Pci.PciAddress) {
+                                               printf("  PCIAddress=%s", pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Pci.PciAddress);
+                                       }
+                                       if (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Pci.Vhostnet) {
+                                               printf("  Vhostnet=%s", pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Pci.Vhostnet);
+                                       }
+                                       if (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Pci.RdmaDevice) {
+                                               printf("  RdmaDevice=%s", pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Pci.RdmaDevice);
+                                       }
+                                       if (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Pci.PfPciAddress) {
+                                               printf("  PF-PCIAddress=%s", pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Pci.PfPciAddress);
+                                       }
+                                       printf("\n");
+                                       break;
+                               case NETUTIL_TYPE_VHOST:
+                                       printf("    Type=vHOST");
+                                       printf("  Mode=%s",
+                                               (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.VhostUser.Mode == NETUTIL_VHOST_MODE_CLIENT) ? "client" :
+                                               (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.VhostUser.Mode == NETUTIL_VHOST_MODE_SERVER) ? "server" : "error");
+                                       if (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.VhostUser.Path) {
+                                               printf("  Path=%s", pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.VhostUser.Path);
+                                       }
+                                       printf("\n");
+                                       break;
+                               case NETUTIL_TYPE_MEMIF:
+                                       printf("    Type=Memif");
+                                       printf("  Role=%s",
+                                               (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Memif.Role == NETUTIL_MEMIF_ROLE_MASTER) ? "master" :
+                                               (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Memif.Role == NETUTIL_MEMIF_ROLE_SLAVE) ? "slave" : "error");
+                                       printf("  Mode=%s",
+                                               (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Memif.Mode == NETUTIL_MEMIF_MODE_ETHERNET) ? "ethernet" :
+                                               (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Memif.Mode == NETUTIL_MEMIF_MODE_IP) ? "ip" :
+                                               (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Memif.Mode == NETUTIL_MEMIF_MODE_INJECT_PUNT) ? "inject-punt" : "error");
+                                       if (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Memif.Path) {
+                                               printf("  Path=%s", pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Memif.Path);
+                                       }
+                                       printf("\n");
+                                       break;
+                               case NETUTIL_TYPE_VDPA:
+                                       printf("    Type=vDPA");
+                                       if (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Vdpa.ParentDevice) {
+                                               printf("  ParentDevice=%s", pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Vdpa.ParentDevice);
+                                       }
+                                       if (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Vdpa.Driver) {
+                                               printf("  Driver=%s", pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Vdpa.Driver);
+                                       }
+                                       if (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Vdpa.Path) {
+                                               printf("  Path=%s", pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Vdpa.Path);
+                                       }
+                                       if (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Vdpa.PciAddress) {
+                                               printf("  PCIAddress=%s", pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Vdpa.PciAddress);
+                                       }
+                                       if (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Vdpa.PfPciAddress) {
+                                               printf("  PF-PCIAddress=%s", pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Vdpa.PfPciAddress);
+                                       }
+                                       printf("\n");
+                                       break;
+                       }
+               }
+       }
+}
+
+extern void freeInterfaces(struct InterfaceResponse *pIfaceRsp) {
+       int i, j;
+
+       if ((pIfaceRsp) && (pIfaceRsp->pIface)) {
+               for (i = 0; i < pIfaceRsp->numIfacePopulated; i++) {
+                       if (pIfaceRsp->pIface[i].NetworkStatus.Name) {
+                               free(pIfaceRsp->pIface[i].NetworkStatus.Name);
+                       }
+                       if (pIfaceRsp->pIface[i].NetworkStatus.Interface) {
+                               free(pIfaceRsp->pIface[i].NetworkStatus.Interface);
+                       }
+
+                       if (pIfaceRsp->pIface[i].NetworkStatus.Mac) {
+                               free(pIfaceRsp->pIface[i].NetworkStatus.Mac);
+                       }
+                       for (j = 0; j < NETUTIL_NUM_IPS; j++) {
+                               if (pIfaceRsp->pIface[i].NetworkStatus.IPs[j]) {
+                                       free(pIfaceRsp->pIface[i].NetworkStatus.IPs[j]);
+                               }
+                       }
+
+                       for (j = 0; j < NETUTIL_NUM_DNS_NAMESERVERS; j++) {
+                               if (pIfaceRsp->pIface[i].NetworkStatus.DNS.Nameservers[j]) {
+                                       free(pIfaceRsp->pIface[i].NetworkStatus.DNS.Nameservers[j]);
+                               }
+                       }
+                       if (pIfaceRsp->pIface[i].NetworkStatus.DNS.Domain) {
+                               free(pIfaceRsp->pIface[i].NetworkStatus.DNS.Domain);
+                       }
+                       for (j = 0; j < NETUTIL_NUM_DNS_SEARCH; j++) {
+                               if (pIfaceRsp->pIface[i].NetworkStatus.DNS.Search[j]) {
+                                       free(pIfaceRsp->pIface[i].NetworkStatus.DNS.Search[j]);
+                               }
+                       }
+                       for (j = 0; j < NETUTIL_NUM_DNS_OPTIONS; j++) {
+                               if (pIfaceRsp->pIface[i].NetworkStatus.DNS.Options[j]) {
+                                       free(pIfaceRsp->pIface[i].NetworkStatus.DNS.Options[j]);
+                               }
+                       }
+
+                       switch (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Type) {
+                               case NETUTIL_TYPE_PCI:
+                                       if (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Pci.PciAddress) {
+                                               free(pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Pci.PciAddress);
+                                       }
+                                       if (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Pci.Vhostnet) {
+                                               free(pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Pci.Vhostnet);
+                                       }
+                                       if (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Pci.RdmaDevice) {
+                                               free(pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Pci.RdmaDevice);
+                                       }
+                                       if (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Pci.PfPciAddress) {
+                                               free(pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Pci.PfPciAddress);
+                                       }
+                                       break;
+                               case NETUTIL_TYPE_VHOST:
+                                       if (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.VhostUser.Path) {
+                                               free(pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.VhostUser.Path);
+                                       }
+                                       break;
+                               case NETUTIL_TYPE_MEMIF:
+                                       if (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Memif.Path) {
+                                               free(pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Memif.Path);
+                                       }
+                                       break;
+                               case NETUTIL_TYPE_VDPA:
+                                       if (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Vdpa.ParentDevice) {
+                                               free(pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Vdpa.ParentDevice);
+                                       }
+                                       if (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Vdpa.Driver) {
+                                               free(pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Vdpa.Driver);
+                                       }
+                                       if (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Vdpa.Path) {
+                                               free(pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Vdpa.Path);
+                                       }
+                                       if (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Vdpa.PciAddress) {
+                                               free(pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Vdpa.PciAddress);
+                                       }
+                                       if (pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Vdpa.PfPciAddress) {
+                                               free(pIfaceRsp->pIface[i].NetworkStatus.DeviceInfo.Vdpa.PfPciAddress);
+                                       }
+                                       break;
+                       }
+               }
+
+               free(pIfaceRsp->pIface);
+       }
+}
+
+extern void dumpHugepages(struct HugepagesResponse *pHugepagesRsp) {
+       int i;
+
+       if (pHugepagesRsp) {
+               if (pHugepagesRsp->MyContainerName) {
+                       printf("  MyContainerName=%s\n", pHugepagesRsp->MyContainerName);
+               }
+               if (pHugepagesRsp->pHugepages) {
+                       for (i = 0; i < pHugepagesRsp->numStructPopulated; i++) {
+                               printf("  Hugepages[%d]:\n", i);
+
+                               printf("  ");
+                               if (pHugepagesRsp->pHugepages[i].ContainerName) {
+                                       printf("  ContainerName=%s", pHugepagesRsp->pHugepages[i].ContainerName);
+                               }
+                               printf("  Request: 1G=%ld 2M=%ld Ukn=%ld  Limit: 1G=%ld 2M=%ld Ukn=%ld\n",
+                                       pHugepagesRsp->pHugepages[i].Request1G,
+                                       pHugepagesRsp->pHugepages[i].Request2M,
+                                       pHugepagesRsp->pHugepages[i].Request,
+                                       pHugepagesRsp->pHugepages[i].Limit1G,
+                                       pHugepagesRsp->pHugepages[i].Limit2M,
+                                       pHugepagesRsp->pHugepages[i].Limit);
+                       }
+               }
+       }
+}
+
+extern void freeHugepages(struct HugepagesResponse *pHugepagesRsp) {
+       int i;
+
+       if (pHugepagesRsp) {
+               if (pHugepagesRsp->MyContainerName) {
+                       free(pHugepagesRsp->MyContainerName);
+               }
+               if (pHugepagesRsp->pHugepages) {
+                       for (i = 0; i < pHugepagesRsp->numStructPopulated; i++) {
+                               if (pHugepagesRsp->pHugepages[i].ContainerName) {
+                                       free(pHugepagesRsp->pHugepages[i].ContainerName);
+                               }
+                       }
+                       free(pHugepagesRsp->pHugepages);
+               }
+       }
+}
+
diff --git a/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/c_util.h b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/c_util.h
new file mode 100644 (file)
index 0000000..5ce6dfa
--- /dev/null
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright(c) 2021 Red Hat, Inc.
+
+extern void dumpInterfaces(struct InterfaceResponse *pIfaceRsp);
+extern void freeInterfaces(struct InterfaceResponse *pIfaceRsp);
+extern void dumpHugepages(struct HugepagesResponse *pHugepagesRsp);
+extern void freeHugepages(struct HugepagesResponse *pHugepagesRsp);
diff --git a/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/docker-entrypoint.sh b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/docker-entrypoint.sh
new file mode 100755 (executable)
index 0000000..bd3b028
--- /dev/null
@@ -0,0 +1,18 @@
+#!/bin/bash
+set -e
+
+echo "DPDK_SAMPLE_APP is set as: $DPDK_SAMPLE_APP"
+
+if [[ $DPDK_SAMPLE_APP == l2fwd ]] ; then
+   echo "Calling: l2fwd"
+   exec "l2fwd"
+elif [[ $DPDK_SAMPLE_APP == l3fwd ]] ; then
+   echo "Calling: l3fwd"
+   exec "l3fwd"
+elif [[ $DPDK_SAMPLE_APP == testpmd ]] ; then
+   echo "Calling: testpmd"
+   exec "testpmd"
+else
+   echo "Net set so using default - Calling: $@"
+   exec "$@"
+fi
diff --git a/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/dpdk-args.c b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/dpdk-args.c
new file mode 100644 (file)
index 0000000..7803a97
--- /dev/null
@@ -0,0 +1,446 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright(c) 2021 Red Hat, Inc.
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "libnetutil_api.h"
+#include "dpdk-args.h"
+#include "c_util.h"
+
+bool debugArgs = true;
+
+#define DPDK_ARGS_MAX_ARGS (30)
+#define DPDK_ARGS_MAX_ARG_STRLEN (100)
+char myArgsArray[DPDK_ARGS_MAX_ARGS][DPDK_ARGS_MAX_ARG_STRLEN];
+char* myArgv[DPDK_ARGS_MAX_ARGS];
+
+//#define DPDK_ARGS_MAX_NUM_DIR (30)
+//static const char DEFAULT_DIR[] = "/var/lib/cni/";
+
+static char STR_MASTER[] = "master";
+static char STR_SLAVE[] = "slave";
+static char STR_ETHERNET[] = "ethernet";
+
+/* Large enough to hold: ",mac=aa:bb:cc:dd:ee:ff" */
+#define DPDK_ARGS_MAX_MAC_STRLEN (25)
+#define DPDK_ARGS_MAX_CONTAINERNAME_STRLEN (80)
+
+
+static int getInterfaces(int argc, int *pPortCnt, int *pPortMask) {
+       int i = 0;
+       int vhostCnt = 0;
+       int memifCnt = 1;
+       int sriovCnt = 0;
+       int err;
+       struct InterfaceResponse ifaceRsp;
+       char macStr[DPDK_ARGS_MAX_MAC_STRLEN];
+#if 0
+       // Refactor code later to find JSON file. Needs work so commented out for now.
+       DIR *d;
+       struct dirent *dir;
+       int currIndex = 0;
+       int freeIndex = 0;
+       char* dirList[DPDK_ARGS_MAX_NUM_DIR];
+       char* fileExt;
+
+       memset(dirList, 0, sizeof(char*)*DPDK_ARGS_MAX_NUM_DIR);
+
+       dirList[freeIndex] = malloc(sizeof(char) * (strlen(DEFAULT_DIR)+1));
+       strcpy(dirList[freeIndex++], DEFAULT_DIR);
+
+       while (dirList[currIndex] != NULL) {
+               printf("  Directory:%s\n", dirList[currIndex]);
+               d = opendir(dirList[currIndex]);
+               if (d)
+               {
+                       while ((dir = readdir(d)) != NULL)
+                       {
+                               if ((dir->d_name) &&
+                                       (strcmp(dir->d_name, ".") != 0) &&
+                                       (strcmp(dir->d_name, "..") != 0))
+                               {
+                                       printf("  Name:%s %d\n", dir->d_name, dir->d_type);
+                                       if (dir->d_type == DT_DIR) {
+                                               printf("    Add to Dir List:%s\n", dir->d_name);
+                                               dirList[freeIndex] = malloc(sizeof(char) * (strlen(DEFAULT_DIR)+strlen(dir->d_name)+1));
+                                               sprintf(dirList[freeIndex++], "%s%s/", DEFAULT_DIR, dir->d_name);
+                                       }
+                                       else
+                                       {
+                                               if (strstr(dir->d_name, "net") != NULL)
+                                               {
+                                                       fileExt = strrchr(dir->d_name, '.');
+                                                       if ((fileExt == NULL) || (strcmp(fileExt, ".json") != 0)) {
+                                                               printf("    Adding to vdev list:%s\n", dir->d_name);
+                                                               snprintf(&myArgsArray[argc++][0], DPDK_ARGS_MAX_ARG_STRLEN-1,
+                                                                                "--vdev=virtio_user%d,path=%s%s", i, dirList[currIndex], dir->d_name);
+                                                               i++;
+                                                       }
+                                                       else {
+                                                               printf("    Invalid FileExt\n");
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       closedir(d);
+               }
+               free(dirList[currIndex]);
+               currIndex++;
+       }
+#endif
+
+       ifaceRsp.numIfaceAllocated = NETUTIL_NUM_NETWORKINTERFACE;
+       ifaceRsp.numIfacePopulated = 0;
+       ifaceRsp.pIface = malloc(ifaceRsp.numIfaceAllocated * sizeof(struct InterfaceData));
+       if (ifaceRsp.pIface) {
+               memset(ifaceRsp.pIface, 0, (ifaceRsp.numIfaceAllocated * sizeof(struct InterfaceData)));
+               err = GetInterfaces(&ifaceRsp);
+               if ((err == NETUTIL_ERRNO_SUCCESS) || (err == NETUTIL_ERRNO_SIZE_ERROR)) {
+
+                       if (debugArgs) {
+                               dumpInterfaces(&ifaceRsp);
+                       }
+
+                       for (i = 0; i < ifaceRsp.numIfacePopulated; i++) {
+                               switch (ifaceRsp.pIface[i].DeviceType) {
+                                       case NETUTIL_TYPE_SRIOV:
+                                               if (ifaceRsp.pIface[i].NetworkStatus.DeviceInfo.Pci.PciAddress) {
+                                                       snprintf(&myArgsArray[argc++][0], DPDK_ARGS_MAX_ARG_STRLEN-1,
+                                                                        "-w %s", ifaceRsp.pIface[i].NetworkStatus.DeviceInfo.Pci.PciAddress);
+                                                       sriovCnt++;
+
+                                                       *pPortMask = *pPortMask | 1 << *pPortCnt;
+                                                       *pPortCnt  = *pPortCnt + 1;
+                                               } else {
+                                                       printf("ERROR: PCI Address not found. Type=%d\n",
+                                                               ifaceRsp.pIface[i].NetworkStatus.DeviceInfo.Type);
+                                               }
+                                               break;
+                                       case NETUTIL_TYPE_VHOST:
+                                               if (ifaceRsp.pIface[i].NetworkStatus.DeviceInfo.VhostUser.Path) {
+                                                       if (ifaceRsp.pIface[i].NetworkStatus.DeviceInfo.VhostUser.Mode == NETUTIL_VHOST_MODE_SERVER) {
+                                                               snprintf(&myArgsArray[argc++][0], DPDK_ARGS_MAX_ARG_STRLEN-1,
+                                                                                "--vdev=virtio_user%d,path=%s,server=1",
+                                                                                vhostCnt, ifaceRsp.pIface[i].NetworkStatus.DeviceInfo.VhostUser.Path);
+
+                                                               vhostCnt++;
+                                                               *pPortMask = *pPortMask | 1 << *pPortCnt;
+                                                               *pPortCnt  = *pPortCnt + 1;
+                                                       }
+                                                       else if (ifaceRsp.pIface[i].NetworkStatus.DeviceInfo.VhostUser.Mode == NETUTIL_VHOST_MODE_CLIENT) {
+                                                               snprintf(&myArgsArray[argc++][0], DPDK_ARGS_MAX_ARG_STRLEN-1,
+                                                                                "--vdev=virtio_user%d,path=%s,queues=1",
+                                                                                vhostCnt, ifaceRsp.pIface[i].NetworkStatus.DeviceInfo.VhostUser.Path);
+
+                                                               vhostCnt++;
+                                                               *pPortMask = *pPortMask | 1 << *pPortCnt;
+                                                               *pPortCnt  = *pPortCnt + 1;
+                                                       } else {
+                                                               printf("ERROR: Unknown vHost Mode=%d\n", ifaceRsp.pIface[i].NetworkStatus.DeviceInfo.VhostUser.Mode);
+                                                       }
+                                               } else {
+                                                       printf("ERROR: vHost Path not found. Type=%d\n",
+                                                               ifaceRsp.pIface[i].NetworkStatus.DeviceInfo.Type);
+                                               }
+                                               break;
+                                       case NETUTIL_TYPE_MEMIF:
+                                               if (ifaceRsp.pIface[i].NetworkStatus.DeviceInfo.Memif.Path) {
+                                                       char *pRole = NULL;
+                                                       char *pMode = NULL;
+
+                                                       if (ifaceRsp.pIface[i].NetworkStatus.DeviceInfo.Memif.Role == NETUTIL_MEMIF_ROLE_MASTER) {
+                                                               pRole = STR_MASTER;
+                                                       }
+                                                       else if (ifaceRsp.pIface[i].NetworkStatus.DeviceInfo.Memif.Role == NETUTIL_MEMIF_ROLE_SLAVE) {
+                                                               pRole = STR_SLAVE;
+                                                       }
+                                                       else {
+                                                               printf("ERROR: Unknown memif Role=%d\n", ifaceRsp.pIface[i].NetworkStatus.DeviceInfo.Memif.Role);
+                                                       }
+
+                                                       if (ifaceRsp.pIface[i].NetworkStatus.DeviceInfo.Memif.Mode == NETUTIL_MEMIF_MODE_ETHERNET) {
+                                                               pMode = STR_ETHERNET;
+                                                       }
+                                                       else if (ifaceRsp.pIface[i].NetworkStatus.DeviceInfo.Memif.Mode == NETUTIL_MEMIF_MODE_IP) {
+                                                               //pMode = "ip";
+                                                               printf("ERROR: memif Mode=%d - Not Supported in DPDK!\n",
+                                                                       ifaceRsp.pIface[i].NetworkStatus.DeviceInfo.Memif.Mode);
+                                                       }
+                                                       else if (ifaceRsp.pIface[i].NetworkStatus.DeviceInfo.Memif.Mode == NETUTIL_MEMIF_MODE_INJECT_PUNT) {
+                                                               //pMode = "inject-punt"";
+                                                               printf("ERROR: memif Mode=%d - Not Supported in DPDK!\n",
+                                                                       ifaceRsp.pIface[i].NetworkStatus.DeviceInfo.Memif.Mode);
+                                                       }
+                                                       else {
+                                                               printf("ERROR: Unknown memif Mode=%d\n",
+                                                                       ifaceRsp.pIface[i].NetworkStatus.DeviceInfo.Memif.Mode);
+                                                       }
+
+                                                       if ((ifaceRsp.pIface[i].NetworkStatus.Mac) &&
+                                                           (strcmp(ifaceRsp.pIface[i].NetworkStatus.Mac,"") != 0)) {
+                                                               snprintf(&macStr[0], DPDK_ARGS_MAX_MAC_STRLEN-1,
+                                                                                ",mac=%s", ifaceRsp.pIface[i].NetworkStatus.Mac);
+                                                       }
+                                                       else {
+                                                               macStr[0] = '\0';
+                                                       }
+
+                                                       if ((pRole) && (pMode)) {
+                                                               snprintf(&myArgsArray[argc++][0], DPDK_ARGS_MAX_ARG_STRLEN-1,
+                                                                                "--vdev=net_memif%d,socket=%s,role=%s%s", memifCnt,
+                                                                                ifaceRsp.pIface[i].NetworkStatus.DeviceInfo.Memif.Path, pRole, &macStr[0]);
+
+                                                               memifCnt++;
+                                                               *pPortMask = *pPortMask | 1 << *pPortCnt;
+                                                               *pPortCnt  = *pPortCnt + 1;
+                                                       }
+                                               } else {
+                                                       printf("ERROR: Memif Path not found. Type=%d\n",
+                                                               ifaceRsp.pIface[i].NetworkStatus.DeviceInfo.Type);
+                                               }
+                                               break;
+                               }
+                       } /* END of FOR EACH Interface */
+
+                       if (sriovCnt == 0) {
+                               strncpy(&myArgsArray[argc++][0], "--no-pci", DPDK_ARGS_MAX_ARG_STRLEN-1);
+                       }
+
+                       freeInterfaces(&ifaceRsp);
+               }
+               else {
+                       printf("Couldn't get network interface, err code: %d\n", err);
+               }
+       }
+
+       return(argc);
+}
+
+static int getHugepages(int argc) {
+       int i = 0;
+       int err;
+       int containerIndex = 0;
+       int64_t reqMemory = 0;
+       int64_t hugepageMemory = 1024;
+       struct HugepagesResponse hugepagesRsp;
+
+       memset(&hugepagesRsp, 0, sizeof(struct HugepagesResponse));
+       hugepagesRsp.numStructAllocated = NETUTIL_NUM_HUGEPAGES_DATA;
+       hugepagesRsp.pHugepages = malloc(hugepagesRsp.numStructAllocated * sizeof(struct HugepagesData));
+       if (hugepagesRsp.pHugepages) {
+               memset(hugepagesRsp.pHugepages, 0, (hugepagesRsp.numStructAllocated * sizeof(struct HugepagesData)));
+               err = GetHugepages(&hugepagesRsp);
+               if ((err == NETUTIL_ERRNO_SUCCESS) || (err == NETUTIL_ERRNO_SIZE_ERROR)) {
+
+                       if (debugArgs) {
+                               dumpHugepages(&hugepagesRsp);
+                       }
+
+                       /* Loop through the list of containers to match container name from env. */
+                       if (hugepagesRsp.MyContainerName) {
+                               for (i = 0; i < hugepagesRsp.numStructPopulated; i++) {
+                                       if (hugepagesRsp.pHugepages[i].ContainerName) {
+                                               if (strcmp(hugepagesRsp.MyContainerName, hugepagesRsp.pHugepages[i].ContainerName) == 0) {
+                                                       containerIndex = i;
+                                                       printf("  MATCH: ContainerName=%s, Index=%d\n", hugepagesRsp.pHugepages[i].ContainerName, containerIndex);
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+
+                       /* Limit can never be less than Request. So use Limit if non-zero.  */
+                       /* However, for hugepages, Limit and Request should be the same, so */
+                       /* either value should be fine.                                     */
+                       reqMemory =
+                               (hugepagesRsp.pHugepages[containerIndex].Limit1G != 0) ? hugepagesRsp.pHugepages[containerIndex].Limit1G :
+                               (hugepagesRsp.pHugepages[containerIndex].Limit2M != 0) ? hugepagesRsp.pHugepages[containerIndex].Limit2M :
+                               (hugepagesRsp.pHugepages[containerIndex].Limit != 0) ? hugepagesRsp.pHugepages[containerIndex].Limit :
+                               (hugepagesRsp.pHugepages[containerIndex].Request1G != 0) ? hugepagesRsp.pHugepages[containerIndex].Request1G :
+                               (hugepagesRsp.pHugepages[containerIndex].Request2M != 0) ? hugepagesRsp.pHugepages[containerIndex].Request2M :
+                               hugepagesRsp.pHugepages[containerIndex].Request;
+
+                       if (reqMemory != 0) {
+                               /* Assuming 2 NUMA sockets, only use what container has access too. */
+                               /* TBD: Manage NUMA properly. */ 
+                               hugepageMemory = reqMemory / 2;
+                       }
+
+                       freeHugepages(&hugepagesRsp);
+
+               } else {
+                       printf("  Couldn't get Hugepage info, defaulting to %ld, err code: %d\n", hugepageMemory, err);
+               }
+       }
+
+       /* Build up memory portion of DPDK Args. */
+       strncpy(&myArgsArray[argc++][0], "-m", DPDK_ARGS_MAX_ARG_STRLEN-1);
+       snprintf(&myArgsArray[argc++][0], DPDK_ARGS_MAX_ARG_STRLEN-1,
+               "%ld", hugepageMemory);
+
+       strncpy(&myArgsArray[argc++][0], "-n", DPDK_ARGS_MAX_ARG_STRLEN-1);
+       strncpy(&myArgsArray[argc++][0], "4", DPDK_ARGS_MAX_ARG_STRLEN-1);
+
+       return(argc);
+}
+
+char** GetArgs(int *pArgc, eDpdkAppType appType)
+{
+       int argc = 0;
+       int i;
+       struct CPUResponse cpuRsp;
+       int err;
+       int portMask = 0;
+       int portCnt = 0;
+       int lcoreBase = 0;
+       int port;
+       int length = 0;
+
+       sleep(2);
+
+       memset(&cpuRsp, 0, sizeof(cpuRsp));
+       err = GetCPUInfo(&cpuRsp);
+       if (err) {
+               printf("Couldn't get CPU info, err code: %d\n", err);
+       }
+       if (cpuRsp.CPUSet) {
+               printf("  cpuRsp.CPUSet = %s\n", cpuRsp.CPUSet);
+
+               // Free the string
+               free(cpuRsp.CPUSet);
+       }
+
+
+       memset(&myArgsArray[0][0], 0, sizeof(char)*DPDK_ARGS_MAX_ARG_STRLEN*DPDK_ARGS_MAX_ARGS);
+       memset(&myArgv[0], 0, sizeof(char)*DPDK_ARGS_MAX_ARGS);
+
+       if (pArgc) {
+               /*
+                * Initialize EAL Options
+                */
+               strncpy(&myArgsArray[argc++][0], "dpdk-app", DPDK_ARGS_MAX_ARG_STRLEN-1);
+
+               argc = getHugepages(argc);
+
+               //strncpy(&myArgsArray[argc++][0], "--file-prefix=dpdk-app_", DPDK_ARGS_MAX_ARG_STRLEN-1);
+
+               if (appType == DPDK_APP_TESTPMD) {
+                       strncpy(&myArgsArray[argc++][0], "-l", DPDK_ARGS_MAX_ARG_STRLEN-1);
+                       strncpy(&myArgsArray[argc++][0], "1-3", DPDK_ARGS_MAX_ARG_STRLEN-1);
+
+                       strncpy(&myArgsArray[argc++][0], "--master-lcore", DPDK_ARGS_MAX_ARG_STRLEN-1);
+                       strncpy(&myArgsArray[argc++][0], "1", DPDK_ARGS_MAX_ARG_STRLEN-1);
+
+                       argc = getInterfaces(argc, &portCnt, &portMask);
+
+                       /*
+                        * Initialize APP Specific Options
+                        */
+                       strncpy(&myArgsArray[argc++][0], "--", DPDK_ARGS_MAX_ARG_STRLEN-1);
+
+                       strncpy(&myArgsArray[argc++][0], "--auto-start", DPDK_ARGS_MAX_ARG_STRLEN-1);
+                       strncpy(&myArgsArray[argc++][0], "--tx-first", DPDK_ARGS_MAX_ARG_STRLEN-1);
+                       strncpy(&myArgsArray[argc++][0], "--no-lsc-interrupt", DPDK_ARGS_MAX_ARG_STRLEN-1);
+
+                       /* testpmd exits if there is not user enteraction, so print stats */
+                       /* every so often to keep program running. */
+                       strncpy(&myArgsArray[argc++][0], "--stats-period", DPDK_ARGS_MAX_ARG_STRLEN-1);
+                       strncpy(&myArgsArray[argc++][0], "60", DPDK_ARGS_MAX_ARG_STRLEN-1);
+               }
+               else if (appType == DPDK_APP_L3FWD) {
+                       /* NOTE: The l3fwd app requires a TX Queue per lcore. So seeting lcore to 1 */
+                       /*       until additional queues are added to underlying interface.         */
+                       strncpy(&myArgsArray[argc++][0], "-l", DPDK_ARGS_MAX_ARG_STRLEN-1);
+                       strncpy(&myArgsArray[argc++][0], "1", DPDK_ARGS_MAX_ARG_STRLEN-1);
+
+                       strncpy(&myArgsArray[argc++][0], "--master-lcore", DPDK_ARGS_MAX_ARG_STRLEN-1);
+                       strncpy(&myArgsArray[argc++][0], "1", DPDK_ARGS_MAX_ARG_STRLEN-1);
+                       lcoreBase = 1;
+
+                       argc = getInterfaces(argc, &portCnt, &portMask);
+
+                       /*
+                        * Initialize APP Specific Options
+                        */
+                       strncpy(&myArgsArray[argc++][0], "--", DPDK_ARGS_MAX_ARG_STRLEN-1);
+
+                       /* Set the PortMask, Hexadecimal bitmask of ports used by app. */
+                       strncpy(&myArgsArray[argc++][0], "-p", DPDK_ARGS_MAX_ARG_STRLEN-1);
+                       snprintf(&myArgsArray[argc++][0], DPDK_ARGS_MAX_ARG_STRLEN-1,
+                                       "0x%x", portMask);
+
+                       /* Set all ports to promiscuous mode so that packets are accepted */
+                       /* regardless of the packet’s Ethernet MAC destination address.   */
+                       strncpy(&myArgsArray[argc++][0], "-P", DPDK_ARGS_MAX_ARG_STRLEN-1);
+
+                       /* Determines which queues from which ports are mapped to which cores. */
+                       /* Usage: --config="(port,queue,lcore)[,(port,queue,lcore)]" */
+                       length = 0;
+                       for (port = 0; port < portCnt; port++) {
+                               /* If the first port, add '--config="' to string. */
+                               if (port == 0) {
+                                       length += snprintf(&myArgsArray[argc][length], DPDK_ARGS_MAX_ARG_STRLEN-length,
+                                                                       "--config=\"");
+                               }
+                               /* If not the first port, add a ',' to string. */
+                               else {
+                                       length += snprintf(&myArgsArray[argc][length], DPDK_ARGS_MAX_ARG_STRLEN-length, ",");
+                               }
+
+                               /* Add each port data */
+                               length += snprintf(&myArgsArray[argc][length], DPDK_ARGS_MAX_ARG_STRLEN-length,
+                                       "(%d,%d,%d)", port, 0 /* queue */, lcoreBase /*+port*/);
+
+                               /* If the last port, add a trailing " to string. */
+                               if (port == portCnt-1) {
+                                       length += snprintf(&myArgsArray[argc][length], DPDK_ARGS_MAX_ARG_STRLEN-length, "\"");
+                               }
+                       }
+                       argc++;
+
+                       /* Set to use software to analyze packet type. Without this option, */
+                       /* hardware will check the packet type. Not sure if vHost supports. */
+                       strncpy(&myArgsArray[argc++][0], "--parse-ptype", DPDK_ARGS_MAX_ARG_STRLEN-1);
+
+               }
+               else if (appType == DPDK_APP_L2FWD) {
+                       strncpy(&myArgsArray[argc++][0], "-l", DPDK_ARGS_MAX_ARG_STRLEN-1);
+                       strncpy(&myArgsArray[argc++][0], "1-3", DPDK_ARGS_MAX_ARG_STRLEN-1);
+
+                       argc = getInterfaces(argc, &portCnt, &portMask);
+
+                       /*
+                        * Initialize APP Specific Options
+                        */
+                       strncpy(&myArgsArray[argc++][0], "--", DPDK_ARGS_MAX_ARG_STRLEN-1);
+
+                       /* Set the PortMask, Hexadecimal bitmask of ports used by app. */
+                       strncpy(&myArgsArray[argc++][0], "-p", DPDK_ARGS_MAX_ARG_STRLEN-1);
+                       snprintf(&myArgsArray[argc++][0], DPDK_ARGS_MAX_ARG_STRLEN-1,
+                                       "0x%x", portMask);
+
+                       /* Set the PERIOD, statistics will be refreshed each PERIOD seconds. */
+                       strncpy(&myArgsArray[argc++][0], "-T", DPDK_ARGS_MAX_ARG_STRLEN-1);
+                       strncpy(&myArgsArray[argc++][0], "120", DPDK_ARGS_MAX_ARG_STRLEN-1);
+
+                       /* Set to no-mac-updating. When enabled: */
+                       /*  - source MAC address is replaced by the TX port MAC address */
+                   /*  - The destination MAC address is replaced by 02:00:00:00:00:TX_PORT_ID */
+                       strncpy(&myArgsArray[argc++][0], "--no-mac-updating", DPDK_ARGS_MAX_ARG_STRLEN-1);
+               }
+
+               for (i = 0; i < argc; i++) {
+                       myArgv[i] = &myArgsArray[i][0];
+               }
+               *pArgc = argc;
+       }
+
+       return(myArgv);
+}
diff --git a/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/dpdk-args.h b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/dpdk-args.h
new file mode 100644 (file)
index 0000000..69424c8
--- /dev/null
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright(c) 2021 Red Hat, Inc.
+
+#ifndef __DPDK_ARGS_H__
+#define __DPDK_ARGS_H__
+
+typedef enum {
+       DPDK_APP_TESTPMD = 1,
+       DPDK_APP_L3FWD,
+       DPDK_APP_L2FWD,
+       DPDK_APP_OTHER
+} eDpdkAppType;
+
+extern char** GetArgs(int *pArgc, eDpdkAppType appType);
+
+#endif  /* __DPDK_ARGS_H__ */
diff --git a/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/l2fwd_eal_init.txt b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/l2fwd_eal_init.txt
new file mode 100644 (file)
index 0000000..43fd6c9
--- /dev/null
@@ -0,0 +1,39 @@
+#if 0
+        ret = rte_eal_init(argc, argv);
+        if (ret < 0)
+                rte_exit(EXIT_FAILURE, "Invalid EAL parameters\n");
+        argc -= ret;
+        argv += ret;
+#else
+        int i;
+        int myArgc = 0;
+        char **myArgv = NULL;
+
+        printf("ENTER dpdk-app:\n");
+        printf(" argc=%d\n", argc);
+        for (i = 0; i < argc; i++) {
+                printf(" %s", argv[i]);
+        }
+        printf("\n");
+
+        if (argc > 1) {
+                ret = rte_eal_init(argc, argv);
+                if (ret < 0)
+                        rte_exit(EXIT_FAILURE, "Invalid EAL parameters\n");
+                argc -= ret;
+                argv += ret;
+        } else {
+                myArgv = GetArgs(&myArgc, DPDK_APP_L2FWD);
+                printf(" myArgc=%d\n", myArgc);
+                for (i = 0; i < myArgc; i++) {
+                        printf(" %s", myArgv[i]);
+                }
+                printf("\n");
+
+                ret = rte_eal_init(myArgc, myArgv);
+                if (ret < 0)
+                        rte_exit(EXIT_FAILURE, "Invalid EAL parameters\n");
+                myArgc -= ret;
+                myArgv += ret;
+        }
+#endif
diff --git a/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/l2fwd_parse_args.txt b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/l2fwd_parse_args.txt
new file mode 100644 (file)
index 0000000..a221ae9
--- /dev/null
@@ -0,0 +1,9 @@
+#if 0
+       ret = l2fwd_parse_args(argc, argv);
+#else
+       if (argc > 1) {
+               ret = l2fwd_parse_args(argc, argv);
+       } else {
+               ret = l2fwd_parse_args(myArgc, myArgv);
+       }
+#endif
diff --git a/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/l2fwd_substitute.sh b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/l2fwd_substitute.sh
new file mode 100755 (executable)
index 0000000..83c5dbd
--- /dev/null
@@ -0,0 +1,59 @@
+#!/bin/bash
+
+# SPDX-License-Identifier: Apache-2.0
+# Copyright(c) 2021 Red Hat, Inc.
+
+
+# Add new app-netutil headerfile to the main code so app-netutil
+# can be called to gather parameters.
+#
+# Search for line with: "#include <rte_mbuf.h>".
+# Append line:          "#include "dpdk-args.h"".
+sed -i -e '/#include <rte_mbuf.h>/a #include "dpdk-args.h"' main.c
+
+
+# Replace the call to rte_eal_init() to call app-netutil code first
+# if no input parametes were passed in. app-netutil code generates
+# its own set of DPDK parameters that are used instead. If input
+# parameters were passed in, call rte_eal_init() with input parameters
+# and run as if app-netutil wasn't there.
+#
+# Search for the line with "ret = rte_eal_init(argc, argv);"
+# Create a label 'a' and continue searching and copying until
+#   line with "argv += ret;" is found.
+# Replace that block of code with the contents of file 'l2fwd_eal_init.txt'.
+sed -i '/ret = rte_eal_init(argc, argv);/{
+:a;N;/argv += ret;/!ba;N;s/.*\n//g
+r l2fwd_eal_init.txt
+}' main.c
+
+
+# If no input parametes were passed in, use the parameter list generated
+# by app-netutil in the previous patch to call the local parameter
+# parsing code, l2fwd_parse_args(). If input parameters were passed in,
+# call l2fwd_parse_args() with input parameters and run as if app-netutil
+# wasn't there.
+#
+# Search for the line with "ret = l2fwd_parse_args(argc, argv);"
+# Replace that line of code with the contents of file
+#   'l2fwd_parse_args.txt'.
+sed -i '/ret = l2fwd_parse_args(argc, argv);/{
+s/ret = l2fwd_parse_args(argc, argv);//g
+r l2fwd_parse_args.txt
+}' main.c
+
+
+# Add new app-netutil source file to the Makefile.
+#
+# Search for line with: "SRCS-y :=".
+# Append line:          "SRCS-y += c_util.c dpdk-args.c".
+sed -i -e '/SRCS-y :=/a SRCS-y += c_util.c dpdk-args.c' Makefile
+
+
+# Add new app-netutil shared library to the Makefile.
+# Contains the C API and GO package which collects the
+# interface data.
+#
+# Search for line with: "SRCS-y += c_util.c dpdk-args.c".
+# Append line:          "LDLIBS += -lnetutil_api".
+sed -i -e '/SRCS-y += c_util.c dpdk-args.c/a LDLIBS += -lnetutil_api' Makefile
diff --git a/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/l3fwd_eal_init.txt b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/l3fwd_eal_init.txt
new file mode 100644 (file)
index 0000000..80e9af1
--- /dev/null
@@ -0,0 +1,39 @@
+#if 0
+        ret = rte_eal_init(argc, argv);
+        if (ret < 0)
+                rte_exit(EXIT_FAILURE, "Invalid EAL parameters\n");
+        argc -= ret;
+        argv += ret;
+#else
+        /* int i; */
+        int myArgc = 0;
+        char **myArgv = NULL;
+
+        printf("ENTER dpdk-app:\n");
+        printf(" argc=%d\n", argc);
+        for (i = 0; i < argc; i++) {
+                printf(" %s", argv[i]);
+        }
+        printf("\n");
+
+        if (argc > 1) {
+                ret = rte_eal_init(argc, argv);
+                if (ret < 0)
+                        rte_exit(EXIT_FAILURE, "Invalid EAL parameters\n");
+                argc -= ret;
+                argv += ret;
+        } else {
+                myArgv = GetArgs(&myArgc, DPDK_APP_L3FWD);
+                printf(" myArgc=%d\n", myArgc);
+                for (i = 0; i < myArgc; i++) {
+                        printf(" %s", myArgv[i]);
+                }
+                printf("\n");
+
+                ret = rte_eal_init(myArgc, myArgv);
+                if (ret < 0)
+                        rte_exit(EXIT_FAILURE, "Invalid EAL parameters\n");
+                myArgc -= ret;
+                myArgv += ret;
+        }
+#endif
diff --git a/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/l3fwd_parse_args.txt b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/l3fwd_parse_args.txt
new file mode 100644 (file)
index 0000000..57b4e8d
--- /dev/null
@@ -0,0 +1,9 @@
+#if 0
+       ret = parse_args(argc, argv);
+#else
+       if (argc > 1) {
+               ret = parse_args(argc, argv);
+       } else {
+               ret = parse_args(myArgc, myArgv);
+       }
+#endif
diff --git a/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/l3fwd_substitute.sh b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/l3fwd_substitute.sh
new file mode 100755 (executable)
index 0000000..020886f
--- /dev/null
@@ -0,0 +1,67 @@
+#!/bin/bash
+
+# SPDX-License-Identifier: Apache-2.0
+# Copyright(c) 2021 Red Hat, Inc.
+
+
+# Add new app-netutil headerfile to the main code so app-netutil
+# can be called to gather parameters.
+#
+# Search for line with: "#include "l3fwd.h"".
+# Append line:          "#include "dpdk-args.h"".
+sed -i -e '/#include "l3fwd.h"/a #include "dpdk-args.h"' main.c
+
+
+# L3fwd code defaults to using some Checksum Offload that doesn't
+# work on all hardware. Turned off.
+#
+# Search for:   ".offloads = DEV_RX_OFFLOAD_CHECKSUM,".
+# Replace with: ".offloads = 0, /*DEV_RX_OFFLOAD_CHECKSUM,*/".
+sed -i -e 's!.offloads = DEV_RX_OFFLOAD_CHECKSUM,!.offloads = 0, /*DEV_RX_OFFLOAD_CHECKSUM,*/!' main.c
+
+
+# Replace the call to rte_eal_init() to call app-netutil code first
+# if no input parametes were passed in. app-netutil code generates
+# its own set of DPDK parameters that are used instead. If input
+# parameters were passed in, call rte_eal_init() with input parameters
+# and run as if app-netutil wasn't there.
+#
+# Search for the line with "ret = rte_eal_init(argc, argv);"
+# Create a label 'a' and continue searching and copying until
+#   line with "argv += ret;" is found.
+# Replace that block of code with the contents of file 'l3fwd_eal_init.txt'.
+sed -i '/ret = rte_eal_init(argc, argv);/{
+:a;N;/argv += ret;/!ba;N;s/.*\n//g
+r l3fwd_eal_init.txt
+}' main.c
+
+
+# If no input parametes were passed in, use the parameter list generated
+# by app-netutil in the previous patch to call the local parameter
+# parsing code, parse_args(). If input parameters were passed in,
+# call parse_args() with input parameters and run as if app-netutil
+# wasn't there.
+#
+# Search for the line with "ret = parse_args(argc, argv);"
+# Replace that line of code with the contents of file
+#   'l3fwd_parse_args.txt'.
+sed -i '/ret = parse_args(argc, argv);/{
+s/ret = parse_args(argc, argv);//g
+r l3fwd_parse_args.txt
+}' main.c
+
+
+# Add new app-netutil source file to the Makefile.
+#
+# Search for line with: "SRCS-y :=".
+# Append line:          "SRCS-y += c_util.c dpdk-args.c".
+sed -i -e '/SRCS-y :=/a SRCS-y += c_util.c dpdk-args.c' Makefile
+
+
+# Add new app-netutil shared library to the Makefile.
+# Contains the C API and GO package which collects the
+# interface data.
+#
+# Search for line with: "SRCS-y += c_util.c dpdk-args.c".
+# Append line:          "LDLIBS += -lnetutil_api".
+sed -i -e '/SRCS-y += c_util.c dpdk-args.c/a LDLIBS += -lnetutil_api' Makefile
diff --git a/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/testpmd_eal_init.txt b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/testpmd_eal_init.txt
new file mode 100644 (file)
index 0000000..a0da4d5
--- /dev/null
@@ -0,0 +1,28 @@
+#if 0
+        diag = rte_eal_init(argc, argv);
+#else
+        int i;
+        int myArgc = 0;
+        char **myArgv = NULL;
+
+        printf("ENTER dpdk-app:\n");
+        printf(" argc=%d\n", argc);
+        for (i = 0; i < argc; i++) {
+                printf(" %s", argv[i]);
+        }
+        printf("\n");
+
+        if (argc > 1) {
+                diag = rte_eal_init(argc, argv);
+        } else {
+                myArgv = GetArgs(&myArgc, DPDK_APP_TESTPMD);
+                printf(" myArgc=%d\n", myArgc);
+                for (i = 0; i < myArgc; i++) {
+                        printf(" %s", myArgv[i]);
+                }
+                printf("\n");
+
+                diag = rte_eal_init(myArgc, myArgv);
+        }
+#endif
+
diff --git a/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/testpmd_launch_args_parse.txt b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/testpmd_launch_args_parse.txt
new file mode 100644 (file)
index 0000000..7c2254b
--- /dev/null
@@ -0,0 +1,19 @@
+#if 0
+       argc -= diag;
+       argv += diag;
+       if (argc > 1)
+               launch_args_parse(argc, argv);
+#else
+       if (argc > 1) {
+               argc -= diag;
+               argv += diag;
+               if (argc > 1)
+                       launch_args_parse(argc, argv);
+       } else {
+               myArgc -= diag;
+               myArgv += diag;
+               if (myArgc > 1)
+                       launch_args_parse(myArgc, myArgv);
+       }
+#endif
+
diff --git a/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/testpmd_substitute.sh b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/testpmd_substitute.sh
new file mode 100755 (executable)
index 0000000..30e222e
--- /dev/null
@@ -0,0 +1,61 @@
+#!/bin/bash
+
+# SPDX-License-Identifier: Apache-2.0
+# Copyright(c) 2021 Red Hat, Inc.
+
+
+# Add new app-netutil headerfile to the main code so app-netutil
+# can be called to gather parameters.
+#
+# Search for: "#include "testpmd.h"".
+# Append:     "#include "dpdk-args.h"".
+sed -i -e '/#include "testpmd.h"/a #include "dpdk-args.h"' testpmd.c
+
+
+# Replace the call to rte_eal_init() to call app-netutil code first
+# if no input parametes were passed in. app-netutil code generates
+# its own set of DPDK parameters that are used instead. If input
+# parameters were passed in, call rte_eal_init() with input parameters
+# and run as if app-netutil wasn't there.
+#
+# Search for the line with "diag = rte_eal_init(argc, argv);"
+# Replace that line of code with the contents of file
+#   'testpmd_eal_init.txt'.
+sed -i '/diag = rte_eal_init(argc, argv);/{
+s/diag = rte_eal_init(argc, argv);//g
+r testpmd_eal_init.txt
+}' testpmd.c
+
+
+# If no input parametes were passed in, use the parameter list generated
+# by app-netutil in the previous patch to call the local parameter
+# parsing code, launch_args_parse(). If input parameters were passed in,
+# call launch_args_parse() with input parameters and run as if app-netutil
+# wasn't there.
+#
+# Search for the line with "argc -= diag;"
+# Create a label 'a' and continue searching and copying until
+#   line with "launch_args_parse(argc, argv);" is found.
+# Replace that block of code with the contents of file
+#   'testpmd_launch_args_parse.txt'.
+sed -i '/argc -= diag;/{
+:a;N;/launch_args_parse(argc, argv);/!ba;N;s/.*\n//g
+r testpmd_launch_args_parse.txt
+}' testpmd.c
+
+
+# Add new app-netutil source file to the Makefile.
+#
+# Search for line with: "SRCS-y += parameters.c".
+# Replace with line:    "SRCS-y += parameters.c c_util.c dpdk-args.c".
+sed -i -e 's/SRCS-y += parameters.c/SRCS-y += parameters.c c_util.c dpdk-args.c/' Makefile
+
+
+# Add new app-netutil shared library to the Makefile.
+# Contains the C API and GO package which collects the
+# interface data.
+#
+# Search for line with: "SRCS-y += util.c".
+# Append line:          "LDLIBS += -lnetutil_api".
+sed -i -e '/SRCS-y += util.c/a LDLIBS += -lnetutil_api' Makefile
+
diff --git a/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/vhost_substitute.sh b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/vhost_substitute.sh
new file mode 100755 (executable)
index 0000000..471eecc
--- /dev/null
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+# SPDX-License-Identifier: Apache-2.0
+# Copyright(c) 2021 Red Hat, Inc.
+
+
+# The first two commands update one of the 'if' checks to remove
+# the check for 'master == VHOST_USER_SET_VRING_CALL'.
+#
+# Search for:   "                      !(dev->flags & VIRTIO_DEV_VDPA_CONFIGURED) &&".
+# Replace with: "                      !(dev->flags & VIRTIO_DEV_VDPA_CONFIGURED)) {".
+sed -i -e 's/                  !(dev->flags & VIRTIO_DEV_VDPA_CONFIGURED) &&/                  !(dev->flags \& VIRTIO_DEV_VDPA_CONFIGURED)) {/g' lib/librte_vhost/vhost_user.c
+#
+# Search for line with: "                      msg.request.master == VHOST_USER_SET_VRING_CALL) {".
+# Delete the line.
+sed -i -e '/                   msg\.request\.master == VHOST_USER_SET_VRING_CALL) {/d' lib/librte_vhost/vhost_user.c
+
+
+# Force an RARP message to be sent out.
+#
+# Search for line with: "      hw->started = true;".
+# Append line:          "      virtio_notify_peers(dev);".
+sed -i -e '/   hw->started = true;/a    virtio_notify_peers(dev);' drivers/net/virtio/virtio_ethdev.c
diff --git a/tools/docker/test-containers/dpdk-forwarding-pods/vpp/Dockerfile b/tools/docker/test-containers/dpdk-forwarding-pods/vpp/Dockerfile
new file mode 100644 (file)
index 0000000..1d7d086
--- /dev/null
@@ -0,0 +1,43 @@
+# Build with latest VPP release
+# docker build -t vpp .
+# Build with stable VPP 20.05
+# docker build --build-arg REPO='2005' -t vpp .
+# Build with exact VPP version
+# docker build --build-arg REPO='master' --build-arg VPP_VERSION='20.09-rc0~174-gbfeae8c57' -t vpp .
+# Build with specific VPP commit
+# docker build --build-arg REPO='master' --build-arg VPP_VERSION='20.09-rc0~[^ ]*-g<commit>' -t vpp .
+
+# Post-Build
+#vpp_version=$(docker run --rm $IMAGE_NAME cat /vpp/version)
+#vpp_release=$(echo $vpp_version | cut -d~ -f1)
+#vpp_commit=$(echo $vpp_version | sed -r 's/.*-g([0-9a-f]+).*/\1/')
+#VPP_VERSION=$(docker run --rm $IMAGE_NAME cat /vpp/version | cut -d~ -f1,2 | sed -e 's/~/./g')
+
+FROM ubuntu:18.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+               apt-transport-https \
+               ca-certificates \
+               curl \
+               gnupg \
+               iproute2 \
+               iputils-ping \
+       && rm -rf /var/lib/apt/lists/*
+
+ARG REPO
+ARG VPP_VERSION
+
+WORKDIR /vpp
+
+COPY get-vpp.sh /get-vpp.sh
+
+RUN set -eux; \
+       /get-vpp.sh; \
+       apt-get update && apt-get install -y -V ./*.deb; \
+       dpkg-query -f '${Version}\n' -W vpp > /vpp/version; \
+       rm -rf vom*.deb vpp-dbg*.deb; \
+       rm -rf /var/lib/apt/lists/*;
+
+RUN mkdir -p /var/log/vpp
+
+CMD ["/usr/bin/vpp", "-c", "/etc/vpp/startup.conf"]
diff --git a/tools/docker/test-containers/dpdk-forwarding-pods/vpp/get-vpp.sh b/tools/docker/test-containers/dpdk-forwarding-pods/vpp/get-vpp.sh
new file mode 100755 (executable)
index 0000000..5f57b7b
--- /dev/null
@@ -0,0 +1,106 @@
+#!/bin/bash
+
+[ -z "$REPO_URL" ] && REPO_URL="https://packagecloud.io/install/repositories/fdio/${REPO:=release}"
+
+# the code below comes from FDio's CSIT project.
+function get_vpp () {
+       # Get and/or install Ubuntu VPP artifacts from packagecloud.io.
+    #
+    # Variables read:
+    # - REPO_URL - FD.io Packagecloud repository.
+    # - VPP_VERSION - VPP version.
+    # - INSTALL - If install packages or download only. Default: download
+
+       ls "*.deb" 2>/dev/null && { die "remove existing *.deb files"; }
+
+       set -exuo pipefail
+       trap '' PIPE
+
+       curl -sS "${REPO_URL}"/script.deb.sh | bash || {
+               die "Packagecloud FD.io repo fetch failed."
+       }
+
+       # If version is set we will add suffix.
+       artifacts=()
+       both_quotes='"'"'"
+       match="[^${both_quotes}]*"
+       qmatch="[${both_quotes}]\?"
+       sed_command="s#.*apt_source_path=${qmatch}\(${match}\)${qmatch}#\1#p"
+       apt_fdio_repo_file=$(curl -s "${REPO_URL}"/script.deb.sh | \
+                                                sed -n ${sed_command}) || {
+                                                        die "Local fdio repo file path fetch failed."
+                                                }
+
+       if [ ! -f ${apt_fdio_repo_file} ]; then
+               die "${apt_fdio_repo_file} not found, \
+                       repository installation was not successful."
+       fi
+
+       packages=$(apt-cache -o Dir::Etc::SourceList=${apt_fdio_repo_file} \
+                          -o Dir::Etc::SourceParts=${apt_fdio_repo_file} dumpavail \
+                          | grep Package: | cut -d " " -f 2) || {
+                                  die "Retrieval of available VPP packages failed."
+                          }
+       if [ -z "${VPP_VERSION-}" ]; then
+               allVersions=$(apt-cache -o Dir::Etc::SourceList=${apt_fdio_repo_file} \
+                                         -o Dir::Etc::SourceParts=${apt_fdio_repo_file} \
+                                         show vpp | grep Version: | cut -d " " -f 2) || {
+                                                 die "Retrieval of available VPP versions failed."
+                                         }
+               if [ "${REPO}" != "master" ]; then
+                       nonRcVersions=$(echo "$allVersions" | grep -v "\-rc[0-9]") || true
+                       [ -n "${nonRcVersions}" ] && allVersions=$nonRcVersions
+               fi
+               VPP_VERSION=$(echo "$allVersions" | head -n1) || true
+       fi
+
+       set +x
+       echo "Finding packages with version: ${VPP_VERSION-}"
+       for package in ${packages}; do
+               # Filter packages with given version
+               pkg_info=$(apt-cache show -- ${package}) || {
+                       die "apt-cache show on ${package} failed."
+               }
+               ver=$(echo ${pkg_info} | grep -o "Version: ${VPP_VERSION-}[^ ]*" | head -1) || true
+               if [ -n "${ver-}" ]; then
+                       if [ "${package}" == "vom" ]; then
+                               echo " x '${package}' skipped"
+                       else
+                               echo "+++'${package}' found"
+                               ver=$(echo "$ver" | cut -d " " -f 2)
+                               artifacts+=(${package[@]/%/=${ver-}})
+                       fi
+               else
+                       echo " - '${package}'"
+               fi
+       done
+       set -x
+
+       if [ "${INSTALL:-false}" = true ]; then
+               apt-get -y install "${artifacts[@]}" || {
+                       die "Install VPP artifacts failed."
+               }
+       else
+               apt-get -y download "${artifacts[@]}" || {
+                       die "Download VPP artifacts failed."
+               }
+       fi
+}
+
+function die () {
+    # Print the message to standard error end exit with error code specified
+    # by the second argument.
+    #
+    # Hardcoded values:
+    # - The default error message.
+    # Arguments:
+    # - ${1} - The whole error message, be sure to quote. Optional
+    # - ${2} - the code to exit with, default: 1.
+
+    set -x
+    set +eu
+    echo "${1:-Unspecified run-time error occurred!}"
+    exit "${2:-1}"
+}
+
+get_vpp