diff options
Diffstat (limited to 'tools/docker')
18 files changed, 1309 insertions, 41 deletions
diff --git a/tools/docker/test-containers/dpdk-forwarding-pods/Dockerfile b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/Dockerfile index 58f558fb..c56e45cf 100644 --- a/tools/docker/test-containers/dpdk-forwarding-pods/Dockerfile +++ b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/Dockerfile @@ -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 @@ -51,24 +40,13 @@ 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 index 00000000..73f46a9e --- /dev/null +++ b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/c_util.c @@ -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 index 00000000..5ce6dfa1 --- /dev/null +++ b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/c_util.h @@ -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 index 00000000..bd3b0284 --- /dev/null +++ b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/docker-entrypoint.sh @@ -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 index 00000000..7803a971 --- /dev/null +++ b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/dpdk-args.c @@ -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 index 00000000..69424c8b --- /dev/null +++ b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/dpdk-args.h @@ -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 index 00000000..43fd6c91 --- /dev/null +++ b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/l2fwd_eal_init.txt @@ -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 index 00000000..a221ae94 --- /dev/null +++ b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/l2fwd_parse_args.txt @@ -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 index 00000000..83c5dbdb --- /dev/null +++ b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/l2fwd_substitute.sh @@ -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 index 00000000..80e9af1f --- /dev/null +++ b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/l3fwd_eal_init.txt @@ -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 index 00000000..57b4e8d3 --- /dev/null +++ b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/l3fwd_parse_args.txt @@ -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 index 00000000..020886f5 --- /dev/null +++ b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/l3fwd_substitute.sh @@ -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 index 00000000..a0da4d50 --- /dev/null +++ b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/testpmd_eal_init.txt @@ -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 index 00000000..7c2254bf --- /dev/null +++ b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/testpmd_launch_args_parse.txt @@ -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 index 00000000..30e222e9 --- /dev/null +++ b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/testpmd_substitute.sh @@ -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 index 00000000..471eecc5 --- /dev/null +++ b/tools/docker/test-containers/dpdk-forwarding-pods/l2l3fwd/vhost_substitute.sh @@ -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 index 00000000..1d7d0862 --- /dev/null +++ b/tools/docker/test-containers/dpdk-forwarding-pods/vpp/Dockerfile @@ -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 index 00000000..5f57b7b6 --- /dev/null +++ b/tools/docker/test-containers/dpdk-forwarding-pods/vpp/get-vpp.sh @@ -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 |