get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/66506/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 66506,
    "url": "http://patches.dpdk.org/api/patches/66506/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20200310111037.31451-4-aostruszka@marvell.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20200310111037.31451-4-aostruszka@marvell.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20200310111037.31451-4-aostruszka@marvell.com",
    "date": "2020-03-10T11:10:36",
    "name": "[v2,3/4] if_proxy: add simple functionality test",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "8362e9d5840061a207165fc0e2356b919e19e9ad",
    "submitter": {
        "id": 1429,
        "url": "http://patches.dpdk.org/api/people/1429/?format=api",
        "name": "Andrzej Ostruszka [C]",
        "email": "aostruszka@marvell.com"
    },
    "delegate": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20200310111037.31451-4-aostruszka@marvell.com/mbox/",
    "series": [
        {
            "id": 8868,
            "url": "http://patches.dpdk.org/api/series/8868/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=8868",
            "date": "2020-03-10T11:10:33",
            "name": "Introduce IF proxy library",
            "version": 2,
            "mbox": "http://patches.dpdk.org/series/8868/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/66506/comments/",
    "check": "fail",
    "checks": "http://patches.dpdk.org/api/patches/66506/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from dpdk.org (dpdk.org [92.243.14.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id D17B1A0565;\n\tTue, 10 Mar 2020 12:11:22 +0100 (CET)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 830F01C045;\n\tTue, 10 Mar 2020 12:10:52 +0100 (CET)",
            "from mx0b-0016f401.pphosted.com (mx0b-0016f401.pphosted.com\n [67.231.156.173]) by dpdk.org (Postfix) with ESMTP id 4F9B11C00D\n for <dev@dpdk.org>; Tue, 10 Mar 2020 12:10:48 +0100 (CET)",
            "from pps.filterd (m0045851.ppops.net [127.0.0.1])\n by mx0b-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id\n 02AB5es5007490; Tue, 10 Mar 2020 04:10:47 -0700",
            "from sc-exch03.marvell.com ([199.233.58.183])\n by mx0b-0016f401.pphosted.com with ESMTP id 2yp04fjt54-1\n (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT);\n Tue, 10 Mar 2020 04:10:47 -0700",
            "from SC-EXCH01.marvell.com (10.93.176.81) by SC-EXCH03.marvell.com\n (10.93.176.83) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Tue, 10 Mar\n 2020 04:10:45 -0700",
            "from maili.marvell.com (10.93.176.43) by SC-EXCH01.marvell.com\n (10.93.176.81) with Microsoft SMTP Server id 15.0.1497.2 via Frontend\n Transport; Tue, 10 Mar 2020 04:10:45 -0700",
            "from amok.marvell.com (unknown [10.95.130.113])\n by maili.marvell.com (Postfix) with ESMTP id 310153F703F;\n Tue, 10 Mar 2020 04:10:44 -0700 (PDT)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com;\n h=from : to : subject\n : date : message-id : in-reply-to : references : mime-version :\n content-transfer-encoding : content-type; s=pfpt0818;\n bh=nn/pvrdQXeqPZMHp68p+0XWc5xZiVP32OqRGxgtXMp8=;\n b=szMHT3CUx6qmQ4foRu+s9oB15+vqGy6QcjJxi2lt5ZqUymPe2+Be0atPWMBceV2r2OQi\n HsBlKepe+s7nmvcqsfxwUsDfgWBpnd/cG+UVhJbNR4v0Qgv0TGjPsjXbvbG4xsC67zmU\n dxTBsJJ5f5iD/aDFjbaN3hu+sCCuv4ojx9jndD7VevOjSOlszeJ5o09V5m0IF4PKMTsi\n VoQVoX5hebpd+HUwE639+OXTtKHMdBjp++zJCT4mQDUh6H11dFleYN944E17mhOmSlFF\n kMnSlwOmnZ0rPYiUkxHEDgQgirMli+89IrRUJyekVyx9ILSBqAgBoSY475OdTT+bBGUZ 4g==",
        "From": "Andrzej Ostruszka <aostruszka@marvell.com>",
        "To": "<dev@dpdk.org>, Thomas Monjalon <thomas@monjalon.net>",
        "Date": "Tue, 10 Mar 2020 12:10:36 +0100",
        "Message-ID": "<20200310111037.31451-4-aostruszka@marvell.com>",
        "X-Mailer": "git-send-email 2.17.1",
        "In-Reply-To": "<20200310111037.31451-1-aostruszka@marvell.com>",
        "References": "<20200306164104.15528-1-aostruszka@marvell.com>\n <20200310111037.31451-1-aostruszka@marvell.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Content-Type": "text/plain",
        "X-Proofpoint-Virus-Version": "vendor=fsecure engine=2.50.10434:6.0.138, 18.0.572\n definitions=2020-03-10_06:2020-03-10,\n 2020-03-10 signatures=0",
        "Subject": "[dpdk-dev] [PATCH v2 3/4] if_proxy: add simple functionality test",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "This commit adds simple test of the library notifications.\n\nSigned-off-by: Andrzej Ostruszka <aostruszka@marvell.com>\n---\n MAINTAINERS              |   1 +\n app/test/Makefile        |   5 +\n app/test/meson.build     |   4 +\n app/test/test_if_proxy.c | 707 +++++++++++++++++++++++++++++++++++++++\n 4 files changed, 717 insertions(+)\n create mode 100644 app/test/test_if_proxy.c",
    "diff": "diff --git a/MAINTAINERS b/MAINTAINERS\nindex 3854d7661..a92cb7356 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -1472,6 +1472,7 @@ F: doc/guides/prog_guide/bpf_lib.rst\n IF Proxy - EXPERIMENTAL\n M: Andrzej Ostruszka <aostruszka@marvell.com>\n F: lib/librte_if_proxy/\n+F: app/test/test_if_proxy.c\n F: doc/guides/prog_guide/if_proxy_lib.rst\n \n Test Applications\ndiff --git a/app/test/Makefile b/app/test/Makefile\nindex 1f080d162..dc287f94b 100644\n--- a/app/test/Makefile\n+++ b/app/test/Makefile\n@@ -231,6 +231,11 @@ SRCS-$(CONFIG_RTE_LIBRTE_BPF) += test_bpf.c\n \n SRCS-$(CONFIG_RTE_LIBRTE_RCU) += test_rcu_qsbr.c test_rcu_qsbr_perf.c\n \n+ifeq ($(CONFIG_RTE_LIBRTE_IF_PROXY),y)\n+SRCS-y += test_if_proxy.c\n+LDLIBS += -lrte_if_proxy\n+endif\n+\n SRCS-$(CONFIG_RTE_LIBRTE_IPSEC) += test_ipsec.c\n SRCS-$(CONFIG_RTE_LIBRTE_IPSEC) += test_ipsec_sad.c\n ifeq ($(CONFIG_RTE_LIBRTE_IPSEC),y)\ndiff --git a/app/test/meson.build b/app/test/meson.build\nindex 0a2ce710f..870c3a8bb 100644\n--- a/app/test/meson.build\n+++ b/app/test/meson.build\n@@ -352,6 +352,10 @@ endif\n if dpdk_conf.has('RTE_LIBRTE_PDUMP')\n \ttest_deps += 'pdump'\n endif\n+if dpdk_conf.has('RTE_LIBRTE_IF_PROXY')\n+\ttest_deps += 'if_proxy'\n+\ttest_sources += 'test_if_proxy.c'\n+endif\n \n cflags = machine_args\n if cc.has_argument('-Wno-format-truncation')\ndiff --git a/app/test/test_if_proxy.c b/app/test/test_if_proxy.c\nnew file mode 100644\nindex 000000000..72ff782b6\n--- /dev/null\n+++ b/app/test/test_if_proxy.c\n@@ -0,0 +1,707 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(C) 2020 Marvell International Ltd.\n+ */\n+\n+#include \"test.h\"\n+\n+#include <rte_ethdev.h>\n+#include <rte_if_proxy.h>\n+#include <rte_cycles.h>\n+\n+#include <string.h>\n+#include <unistd.h>\n+#include <signal.h>\n+#include <net/if.h>\n+#include <arpa/inet.h>\n+#include <pthread.h>\n+#include <time.h>\n+\n+/* There are two types of event notifications - one using callbacks and one\n+ * using event queues (rings).  We'll test them both and this \"bool\" will govern\n+ * the type of API to use.\n+ */\n+static int use_callbacks = 1;\n+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;\n+static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;\n+\n+static struct rte_ring *ev_queue;\n+\n+enum net_event_mask {\n+\tINITIALIZED\t= 1U << RTE_IFPX_CFG_DONE,\n+\tLINK_CHANGED\t= 1U << RTE_IFPX_LINK_CHANGE,\n+\tMAC_CHANGED\t= 1U << RTE_IFPX_MAC_CHANGE,\n+\tMTU_CHANGED\t= 1U << RTE_IFPX_MTU_CHANGE,\n+\tADDR_ADD\t= 1U << RTE_IFPX_ADDR_ADD,\n+\tADDR_DEL\t= 1U << RTE_IFPX_ADDR_DEL,\n+\tROUTE_ADD\t= 1U << RTE_IFPX_ROUTE_ADD,\n+\tROUTE_DEL\t= 1U << RTE_IFPX_ROUTE_DEL,\n+\tADDR6_ADD\t= 1U << RTE_IFPX_ADDR6_ADD,\n+\tADDR6_DEL\t= 1U << RTE_IFPX_ADDR6_DEL,\n+\tROUTE6_ADD\t= 1U << RTE_IFPX_ROUTE6_ADD,\n+\tROUTE6_DEL\t= 1U << RTE_IFPX_ROUTE6_DEL,\n+\tNEIGH_ADD\t= 1U << RTE_IFPX_NEIGH_ADD,\n+\tNEIGH_DEL\t= 1U << RTE_IFPX_NEIGH_DEL,\n+\tNEIGH6_ADD\t= 1U << RTE_IFPX_NEIGH6_ADD,\n+\tNEIGH6_DEL\t= 1U << RTE_IFPX_NEIGH6_DEL,\n+};\n+\n+static unsigned int state;\n+\n+static struct {\n+\tstruct rte_ether_addr mac_addr;\n+\tuint16_t port_id, mtu;\n+\tstruct in_addr ipv4, route4;\n+\tstruct in6_addr ipv6, route6;\n+\tuint16_t depth4, depth6;\n+\tint is_up;\n+} net_cfg;\n+\n+static\n+int unlock_notify(unsigned int op)\n+{\n+\t/* the mutex is expected to be locked on entry */\n+\tRTE_VERIFY(pthread_mutex_trylock(&mutex) == EBUSY);\n+\tstate |= op;\n+\n+\tpthread_mutex_unlock(&mutex);\n+\treturn pthread_cond_signal(&cond);\n+}\n+\n+static\n+void handle_event(struct rte_ifpx_event *ev);\n+\n+static\n+int wait_for(unsigned int op_mask, unsigned int sec)\n+{\n+\tint ec;\n+\n+\tif (use_callbacks) {\n+\t\tstruct timespec time;\n+\n+\t\tec = pthread_mutex_trylock(&mutex);\n+\t\t/* the mutex is expected to be locked on entry */\n+\t\tRTE_VERIFY(ec == EBUSY);\n+\n+\t\tec = 0;\n+\t\tclock_gettime(CLOCK_REALTIME, &time);\n+\t\ttime.tv_sec += sec;\n+\n+\t\twhile ((state & op_mask) != op_mask && ec == 0)\n+\t\t\tec = pthread_cond_timedwait(&cond, &mutex, &time);\n+\t} else {\n+\t\tuint64_t deadline;\n+\t\tstruct rte_ifpx_event *ev;\n+\n+\t\tec = 0;\n+\t\tdeadline = rte_get_timer_cycles() + sec * rte_get_timer_hz();\n+\n+\t\twhile ((state & op_mask) != op_mask) {\n+\t\t\tif (rte_get_timer_cycles() >= deadline) {\n+\t\t\t\tec = ETIMEDOUT;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (rte_ring_dequeue(ev_queue, (void **)&ev) == 0)\n+\t\t\t\thandle_event(ev);\n+\t\t}\n+\t}\n+\n+\treturn ec;\n+}\n+\n+static\n+int expect(unsigned int op_mask, const char *fmt, ...)\n+#if __GNUC__\n+\t__attribute__((format(printf, 2, 3)));\n+#endif\n+\n+static\n+int expect(unsigned int op_mask, const char *fmt, ...)\n+{\n+\tchar cmd[128];\n+\tva_list args;\n+\tint ret;\n+\n+\tstate &= ~op_mask;\n+\tva_start(args, fmt);\n+\tvsnprintf(cmd, sizeof(cmd), fmt, args);\n+\tva_end(args);\n+\tret = system(cmd);\n+\tif (ret == 0)\n+\t\t/* IPv6 address notifications seem to need that long delay. */\n+\t\treturn wait_for(op_mask, 2);\n+\treturn ret;\n+}\n+\n+static\n+int mac_change(const struct rte_ifpx_mac_change *ev)\n+{\n+\tpthread_mutex_lock(&mutex);\n+\tRTE_VERIFY(ev->port_id == net_cfg.port_id);\n+\tif (memcmp(ev->mac.addr_bytes, net_cfg.mac_addr.addr_bytes,\n+\t\t   RTE_ETHER_ADDR_LEN) == 0) {\n+\t\tunlock_notify(MAC_CHANGED);\n+\t\treturn 1;\n+\t}\n+\tpthread_mutex_unlock(&mutex);\n+\treturn 0;\n+}\n+\n+static\n+int mtu_change(const struct rte_ifpx_mtu_change *ev)\n+{\n+\tpthread_mutex_lock(&mutex);\n+\tRTE_VERIFY(ev->port_id == net_cfg.port_id);\n+\tif (ev->mtu == net_cfg.mtu) {\n+\t\tunlock_notify(MTU_CHANGED);\n+\t\treturn 1;\n+\t}\n+\tpthread_mutex_unlock(&mutex);\n+\treturn 0;\n+}\n+\n+static\n+int link_change(const struct rte_ifpx_link_change *ev)\n+{\n+\tpthread_mutex_lock(&mutex);\n+\tRTE_VERIFY(ev->port_id == net_cfg.port_id);\n+\tif (ev->is_up == net_cfg.is_up) {\n+\t\t/* Special case for testing of callbacks modification from\n+\t\t * inside of callback: we catch putting link down (the last\n+\t\t * operation in test) and remove callbacks registered.\n+\t\t */\n+\t\tif (!ev->is_up)\n+\t\t\trte_ifpx_callbacks_unregister();\n+\t\tunlock_notify(LINK_CHANGED);\n+\t\treturn 1;\n+\t}\n+\tpthread_mutex_unlock(&mutex);\n+\treturn 0;\n+}\n+\n+static\n+int addr_add(const struct rte_ifpx_addr_change *ev)\n+{\n+\tpthread_mutex_lock(&mutex);\n+\tRTE_VERIFY(ev->port_id == net_cfg.port_id);\n+\tif (ev->ip == net_cfg.ipv4.s_addr) {\n+\t\tunlock_notify(ADDR_ADD);\n+\t\treturn 1;\n+\t}\n+\tpthread_mutex_unlock(&mutex);\n+\treturn 0;\n+}\n+\n+static\n+int addr_del(const struct rte_ifpx_addr_change *ev)\n+{\n+\tpthread_mutex_lock(&mutex);\n+\tRTE_VERIFY(ev->port_id == net_cfg.port_id);\n+\tif (ev->ip == net_cfg.ipv4.s_addr) {\n+\t\tunlock_notify(ADDR_DEL);\n+\t\treturn 1;\n+\t}\n+\tpthread_mutex_unlock(&mutex);\n+\treturn 0;\n+}\n+\n+static\n+int addr6_add(const struct rte_ifpx_addr6_change *ev)\n+{\n+\tpthread_mutex_lock(&mutex);\n+\tRTE_VERIFY(ev->port_id == net_cfg.port_id);\n+\tif (memcmp(ev->ip, net_cfg.ipv6.s6_addr, 16) == 0) {\n+\t\tunlock_notify(ADDR6_ADD);\n+\t\treturn 1;\n+\t}\n+\tpthread_mutex_unlock(&mutex);\n+\treturn 0;\n+}\n+\n+static\n+int addr6_del(const struct rte_ifpx_addr6_change *ev)\n+{\n+\tpthread_mutex_lock(&mutex);\n+\tRTE_VERIFY(ev->port_id == net_cfg.port_id);\n+\tif (memcmp(ev->ip, net_cfg.ipv6.s6_addr, 16) == 0) {\n+\t\tunlock_notify(ADDR6_DEL);\n+\t\treturn 1;\n+\t}\n+\tpthread_mutex_unlock(&mutex);\n+\treturn 0;\n+}\n+\n+static\n+int route_add(const struct rte_ifpx_route_change *ev)\n+{\n+\tpthread_mutex_lock(&mutex);\n+\tRTE_VERIFY(ev->port_id == net_cfg.port_id);\n+\tif (net_cfg.depth4 == ev->depth && net_cfg.route4.s_addr == ev->ip) {\n+\t\tunlock_notify(ROUTE_ADD);\n+\t\treturn 1;\n+\t}\n+\tpthread_mutex_unlock(&mutex);\n+\treturn 0;\n+}\n+\n+static\n+int route_del(const struct rte_ifpx_route_change *ev)\n+{\n+\tpthread_mutex_lock(&mutex);\n+\tRTE_VERIFY(ev->port_id == net_cfg.port_id);\n+\tif (net_cfg.depth4 == ev->depth && net_cfg.route4.s_addr == ev->ip) {\n+\t\tunlock_notify(ROUTE_DEL);\n+\t\treturn 1;\n+\t}\n+\tpthread_mutex_unlock(&mutex);\n+\treturn 0;\n+}\n+\n+static\n+int route6_add(const struct rte_ifpx_route6_change *ev)\n+{\n+\tpthread_mutex_lock(&mutex);\n+\tRTE_VERIFY(ev->port_id == net_cfg.port_id);\n+\tif (net_cfg.depth6 == ev->depth &&\n+\t    /* don't check for trailing zeros */\n+\t    memcmp(ev->ip, net_cfg.route6.s6_addr, ev->depth/8) == 0) {\n+\t\tunlock_notify(ROUTE6_ADD);\n+\t\treturn 1;\n+\t}\n+\tpthread_mutex_unlock(&mutex);\n+\treturn 0;\n+}\n+\n+static\n+int route6_del(const struct rte_ifpx_route6_change *ev)\n+{\n+\tpthread_mutex_lock(&mutex);\n+\tRTE_VERIFY(ev->port_id == net_cfg.port_id);\n+\tif (net_cfg.depth6 == ev->depth &&\n+\t    /* don't check for trailing zeros */\n+\t    memcmp(ev->ip, net_cfg.route6.s6_addr, ev->depth/8) == 0) {\n+\t\tunlock_notify(ROUTE6_DEL);\n+\t\treturn 1;\n+\t}\n+\tpthread_mutex_unlock(&mutex);\n+\treturn 0;\n+}\n+\n+static\n+int neigh_add(const struct rte_ifpx_neigh_change *ev)\n+{\n+\tpthread_mutex_lock(&mutex);\n+\tRTE_VERIFY(ev->port_id == net_cfg.port_id);\n+\tif (net_cfg.ipv4.s_addr == ev->ip &&\n+\t    memcmp(ev->mac.addr_bytes, net_cfg.mac_addr.addr_bytes,\n+\t\t   RTE_ETHER_ADDR_LEN) == 0) {\n+\t\tunlock_notify(NEIGH_ADD);\n+\t\treturn 1;\n+\t}\n+\tpthread_mutex_unlock(&mutex);\n+\treturn 0;\n+}\n+\n+static\n+int neigh_del(const struct rte_ifpx_neigh_change *ev)\n+{\n+\tpthread_mutex_lock(&mutex);\n+\tRTE_VERIFY(ev->port_id == net_cfg.port_id);\n+\tif (net_cfg.ipv4.s_addr == ev->ip) {\n+\t\tunlock_notify(NEIGH_DEL);\n+\t\treturn 1;\n+\t}\n+\tpthread_mutex_unlock(&mutex);\n+\treturn 0;\n+}\n+\n+static\n+int neigh6_add(const struct rte_ifpx_neigh6_change *ev)\n+{\n+\tpthread_mutex_lock(&mutex);\n+\tRTE_VERIFY(ev->port_id == net_cfg.port_id);\n+\tif (memcmp(ev->ip, net_cfg.ipv6.s6_addr, 16) == 0 &&\n+\t    memcmp(ev->mac.addr_bytes, net_cfg.mac_addr.addr_bytes,\n+\t\t   RTE_ETHER_ADDR_LEN) == 0) {\n+\t\tunlock_notify(NEIGH6_ADD);\n+\t\treturn 1;\n+\t}\n+\tpthread_mutex_unlock(&mutex);\n+\treturn 0;\n+}\n+\n+static\n+int neigh6_del(const struct rte_ifpx_neigh6_change *ev)\n+{\n+\tpthread_mutex_lock(&mutex);\n+\tRTE_VERIFY(ev->port_id == net_cfg.port_id);\n+\tif (memcmp(ev->ip, net_cfg.ipv6.s6_addr, 16) == 0) {\n+\t\tunlock_notify(NEIGH6_DEL);\n+\t\treturn 1;\n+\t}\n+\tpthread_mutex_unlock(&mutex);\n+\treturn 0;\n+}\n+\n+static\n+int cfg_done(void)\n+{\n+\tpthread_mutex_lock(&mutex);\n+\tunlock_notify(INITIALIZED);\n+\treturn 1;\n+}\n+\n+static\n+void handle_event(struct rte_ifpx_event *ev)\n+{\n+\tif (ev->type != RTE_IFPX_CFG_DONE)\n+\t\tRTE_VERIFY(ev->data.port_id == net_cfg.port_id);\n+\n+\t/* If params do not match what we expect just free the event. */\n+\tswitch (ev->type) {\n+\tcase RTE_IFPX_MAC_CHANGE:\n+\t\tif (memcmp(ev->mac_change.mac.addr_bytes,\n+\t\t\t   net_cfg.mac_addr.addr_bytes,\n+\t\t\t   RTE_ETHER_ADDR_LEN) != 0)\n+\t\t\tgoto exit;\n+\t\tbreak;\n+\tcase RTE_IFPX_MTU_CHANGE:\n+\t\tif (ev->mtu_change.mtu != net_cfg.mtu)\n+\t\t\tgoto exit;\n+\t\tbreak;\n+\tcase RTE_IFPX_LINK_CHANGE:\n+\t\tif (ev->link_change.is_up != net_cfg.is_up)\n+\t\t\tgoto exit;\n+\t\tbreak;\n+\tcase RTE_IFPX_ADDR_ADD:\n+\t\tif (ev->addr_change.ip != net_cfg.ipv4.s_addr)\n+\t\t\tgoto exit;\n+\t\tbreak;\n+\tcase RTE_IFPX_ADDR_DEL:\n+\t\tif (ev->addr_change.ip != net_cfg.ipv4.s_addr)\n+\t\t\tgoto exit;\n+\t\tbreak;\n+\tcase RTE_IFPX_ADDR6_ADD:\n+\t\tif (memcmp(ev->addr6_change.ip, net_cfg.ipv6.s6_addr,\n+\t\t\t   16) != 0)\n+\t\t\tgoto exit;\n+\t\tbreak;\n+\tcase RTE_IFPX_ADDR6_DEL:\n+\t\tif (memcmp(ev->addr6_change.ip, net_cfg.ipv6.s6_addr,\n+\t\t\t   16) != 0)\n+\t\t\tgoto exit;\n+\t\tbreak;\n+\tcase RTE_IFPX_ROUTE_ADD:\n+\t\tif (net_cfg.depth4 != ev->route_change.depth ||\n+\t\t    net_cfg.route4.s_addr != ev->route_change.ip)\n+\t\t\tgoto exit;\n+\t\tbreak;\n+\tcase RTE_IFPX_ROUTE_DEL:\n+\t\tif (net_cfg.depth4 != ev->route_change.depth ||\n+\t\t    net_cfg.route4.s_addr != ev->route_change.ip)\n+\t\t\tgoto exit;\n+\t\tbreak;\n+\tcase RTE_IFPX_ROUTE6_ADD:\n+\t\tif (net_cfg.depth6 != ev->route6_change.depth ||\n+\t\t    /* don't check for trailing zeros */\n+\t\t    memcmp(ev->route6_change.ip, net_cfg.route6.s6_addr,\n+\t\t\t   ev->route6_change.depth/8) != 0)\n+\t\t\tgoto exit;\n+\t\tbreak;\n+\tcase RTE_IFPX_ROUTE6_DEL:\n+\t\tif (net_cfg.depth6 != ev->route6_change.depth ||\n+\t\t    /* don't check for trailing zeros */\n+\t\t    memcmp(ev->route6_change.ip, net_cfg.route6.s6_addr,\n+\t\t\t   ev->route6_change.depth/8) != 0)\n+\t\t\tgoto exit;\n+\t\tbreak;\n+\tcase RTE_IFPX_NEIGH_ADD:\n+\t\tif (net_cfg.ipv4.s_addr != ev->neigh_change.ip ||\n+\t\t    memcmp(ev->neigh_change.mac.addr_bytes,\n+\t\t\t   net_cfg.mac_addr.addr_bytes,\n+\t\t\t   RTE_ETHER_ADDR_LEN) != 0)\n+\t\t\tgoto exit;\n+\t\tbreak;\n+\tcase RTE_IFPX_NEIGH_DEL:\n+\t\tif (net_cfg.ipv4.s_addr != ev->neigh_change.ip)\n+\t\t\tgoto exit;\n+\t\tbreak;\n+\tcase RTE_IFPX_NEIGH6_ADD:\n+\t\tif (memcmp(ev->neigh6_change.ip,\n+\t\t\t   net_cfg.ipv6.s6_addr, 16) != 0 ||\n+\t\t    memcmp(ev->neigh6_change.mac.addr_bytes,\n+\t\t\t   net_cfg.mac_addr.addr_bytes,\n+\t\t\t   RTE_ETHER_ADDR_LEN) != 0)\n+\t\t\tgoto exit;\n+\t\tbreak;\n+\tcase RTE_IFPX_NEIGH6_DEL:\n+\t\tif (memcmp(ev->neigh6_change.ip, net_cfg.ipv6.s6_addr, 16) != 0)\n+\t\t\tgoto exit;\n+\t\tbreak;\n+\tcase RTE_IFPX_CFG_DONE:\n+\t\tbreak;\n+\tdefault:\n+\t\tRTE_VERIFY(0 && \"Unhandled event type\");\n+\t}\n+\n+\tstate |= 1U << ev->type;\n+exit:\n+\tfree(ev);\n+}\n+\n+static\n+struct rte_ifpx_callbacks cbs = {\n+\t.mac_change = mac_change,\n+\t.mtu_change = mtu_change,\n+\t.link_change = link_change,\n+\t.addr_add = addr_add,\n+\t.addr_del = addr_del,\n+\t.addr6_add = addr6_add,\n+\t.addr6_del = addr6_del,\n+\t.route_add = route_add,\n+\t.route_del = route_del,\n+\t.route6_add = route6_add,\n+\t.route6_del = route6_del,\n+\t.neigh_add = neigh_add,\n+\t.neigh_del = neigh_del,\n+\t.neigh6_add = neigh6_add,\n+\t.neigh6_del = neigh6_del,\n+\t/* lib specific callback */\n+\t.cfg_done = cfg_done,\n+};\n+\n+static\n+int test_notifications(const struct rte_ifpx_info *pinfo)\n+{\n+\tchar mac_buf[RTE_ETHER_ADDR_FMT_SIZE];\n+\tint ec;\n+\n+\t/* Test link up notification. */\n+\tnet_cfg.is_up = 1;\n+\tec = expect(LINK_CHANGED, \"ip link set dev %s up\", pinfo->if_name);\n+\tif (ec != 0) {\n+\t\tprintf(\"Failed to notify about link going up\\n\");\n+\t\treturn ec;\n+\t}\n+\n+\t/* Test for MAC changes notification. */\n+\trte_eth_random_addr(net_cfg.mac_addr.addr_bytes);\n+\trte_ether_format_addr(mac_buf, sizeof(mac_buf), &net_cfg.mac_addr);\n+\tec = expect(MAC_CHANGED, \"ip link set dev %s address %s\",\n+\t\t    pinfo->if_name, mac_buf);\n+\tif (ec != 0) {\n+\t\tprintf(\"Missing/wrong notification about mac change\\n\");\n+\t\treturn ec;\n+\t}\n+\n+\t/* Test for MTU changes notification. */\n+\tnet_cfg.mtu = pinfo->mtu + 100;\n+\tec = expect(MTU_CHANGED, \"ip link set dev %s mtu %d\",\n+\t\t    pinfo->if_name, net_cfg.mtu);\n+\tif (ec != 0) {\n+\t\tprintf(\"Missing/wrong notification about mtu change\\n\");\n+\t\treturn ec;\n+\t}\n+\n+\t/* Test for adding of IPv4 address - using address from TEST-2 pool.\n+\t * This test is specific to linux netlink behaviour - after adding\n+\t * address we get both notification about address being added and new\n+\t * route.  So I check both.\n+\t */\n+\tnet_cfg.ipv4.s_addr = RTE_IPV4(198, 51, 100, 14);\n+\tnet_cfg.route4.s_addr = net_cfg.ipv4.s_addr;\n+\tnet_cfg.depth4 = 32;\n+\tec = expect(ADDR_ADD | ROUTE_ADD, \"ip addr add 198.51.100.14 dev %s\",\n+\t\t    pinfo->if_name);\n+\tif (ec != 0) {\n+\t\tprintf(\"Missing/wrong notifications about IPv4 address add\\n\");\n+\t\treturn ec;\n+\t}\n+\n+\t/* Test for IPv4 address removal.  See comment above for 'addr add'. */\n+\tec = expect(ADDR_DEL | ROUTE_DEL, \"ip addr del 198.51.100.14/32 dev %s\",\n+\t\t    pinfo->if_name);\n+\tif (ec != 0) {\n+\t\tprintf(\"Missing/wrong notifications about IPv4 address del\\n\");\n+\t\treturn ec;\n+\t}\n+\n+\t/* Test for adding IPv4 route. */\n+\tnet_cfg.route4.s_addr = RTE_IPV4(198, 51, 100, 0);\n+\tnet_cfg.depth4 = 24;\n+\tec = expect(ROUTE_ADD, \"ip route add 198.51.100.0/24 dev %s\",\n+\t\t    pinfo->if_name);\n+\tif (ec != 0) {\n+\t\tprintf(\"Missing/wrong notifications about IPv4 route add\\n\");\n+\t\treturn ec;\n+\t}\n+\n+\t/* Test for IPv4 route removal. */\n+\tec = expect(ROUTE_DEL, \"ip route del 198.51.100.0/24 dev %s\",\n+\t\t    pinfo->if_name);\n+\tif (ec != 0) {\n+\t\tprintf(\"Missing/wrong notifications about IPv4 route del\\n\");\n+\t\treturn ec;\n+\t}\n+\n+\t/* Test for neighbour addresses notifications. */\n+\trte_eth_random_addr(net_cfg.mac_addr.addr_bytes);\n+\trte_ether_format_addr(mac_buf, sizeof(mac_buf), &net_cfg.mac_addr);\n+\n+\tec = expect(NEIGH_ADD,\n+\t\t    \"ip neigh add 198.51.100.14 dev %s lladdr %s nud noarp\",\n+\t\t    pinfo->if_name, mac_buf);\n+\tif (ec != 0) {\n+\t\tprintf(\"Missing/wrong notifications about IPv4 neighbour add\\n\");\n+\t\treturn ec;\n+\t}\n+\n+\tec = expect(NEIGH_DEL, \"ip neigh del 198.51.100.14 dev %s\",\n+\t\t    pinfo->if_name);\n+\tif (ec != 0) {\n+\t\tprintf(\"Missing/wrong notifications about IPv4 neighbour del\\n\");\n+\t\treturn ec;\n+\t}\n+\n+\t/* Now the same for IPv6 - with address from \"documentation pool\". */\n+\tinet_pton(AF_INET6, \"2001:db8::dead:beef\", net_cfg.ipv6.s6_addr);\n+\t/* This is specific to linux netlink behaviour - after adding address\n+\t * we get both notification about address being added and new route.\n+\t * So I wait for both.\n+\t */\n+\tmemcpy(net_cfg.route6.s6_addr, net_cfg.ipv6.s6_addr, 16);\n+\tnet_cfg.depth6 = 128;\n+\tec = expect(ADDR6_ADD | ROUTE6_ADD,\n+\t\t    \"ip addr add 2001:db8::dead:beef dev %s\",\n+\t\t    pinfo->if_name);\n+\tif (ec != 0) {\n+\t\tprintf(\"Missing/wrong notifications about IPv6 address add\\n\");\n+\t\treturn ec;\n+\t}\n+\n+\t/* See comment above for 'addr6 add'. */\n+\tec = expect(ADDR6_DEL | ROUTE6_DEL,\n+\t\t    \"ip addr del 2001:db8::dead:beef/128 dev %s\",\n+\t\t    pinfo->if_name);\n+\tif (ec != 0) {\n+\t\tprintf(\"Missing/wrong notifications about IPv6 address del\\n\");\n+\t\treturn ec;\n+\t}\n+\n+\tnet_cfg.depth6 = 96;\n+\tec = expect(ROUTE6_ADD, \"ip route add 2001:db8::dead:0/96 dev %s\",\n+\t\t    pinfo->if_name);\n+\tif (ec != 0) {\n+\t\tprintf(\"Missing/wrong notifications about IPv6 route add\\n\");\n+\t\treturn ec;\n+\t}\n+\n+\tec = expect(ROUTE6_DEL, \"ip route del 2001:db8::dead:0/96 dev %s\",\n+\t\t    pinfo->if_name);\n+\tif (ec != 0) {\n+\t\tprintf(\"Missing/wrong notifications about IPv6 route del\\n\");\n+\t\treturn ec;\n+\t}\n+\n+\tec = expect(NEIGH6_ADD,\n+\t\t    \"ip neigh add 2001:db8::dead:beef dev %s lladdr %s nud noarp\",\n+\t\t    pinfo->if_name, mac_buf);\n+\tif (ec != 0) {\n+\t\tprintf(\"Missing/wrong notifications about IPv6 neighbour add\\n\");\n+\t\treturn ec;\n+\t}\n+\n+\tec = expect(NEIGH6_DEL, \"ip neigh del 2001:db8::dead:beef dev %s\",\n+\t\t    pinfo->if_name);\n+\tif (ec != 0) {\n+\t\tprintf(\"Missing/wrong notifications about IPv6 neighbour del\\n\");\n+\t\treturn ec;\n+\t}\n+\n+\t/* Finally put link down and test for notification. */\n+\tnet_cfg.is_up = 0;\n+\tec = expect(LINK_CHANGED, \"ip link set dev %s down\", pinfo->if_name);\n+\tif (ec != 0) {\n+\t\tprintf(\"Failed to notify about link going down\\n\");\n+\t\treturn ec;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static\n+int test_if_proxy(void)\n+{\n+\tint ec;\n+\tconst struct rte_ifpx_info *pinfo;\n+\tuint16_t proxy_id;\n+\n+\tstate = 0;\n+\tmemset(&net_cfg, 0, sizeof(net_cfg));\n+\n+\tif (rte_eth_dev_count_avail() == 0) {\n+\t\tprintf(\"Run this test with at least one port configured\\n\");\n+\t\treturn 1;\n+\t}\n+\t/* User the first port available. */\n+\tRTE_ETH_FOREACH_DEV(net_cfg.port_id)\n+\t\tbreak;\n+\tproxy_id = rte_ifpx_proxy_create(RTE_IFPX_DEFAULT);\n+\tRTE_VERIFY(proxy_id != RTE_MAX_ETHPORTS);\n+\trte_ifpx_port_bind(net_cfg.port_id, proxy_id);\n+\trte_ifpx_callbacks_register(&cbs);\n+\trte_ifpx_listen();\n+\n+\t/* Let's start with callback based API. */\n+\tuse_callbacks = 1;\n+\tpthread_mutex_lock(&mutex);\n+\tec = wait_for(INITIALIZED, 2);\n+\tif (ec != 0) {\n+\t\tprintf(\"Failed to obtain network configuration\\n\");\n+\t\tgoto exit;\n+\t}\n+\tpinfo = rte_ifpx_info_get(net_cfg.port_id);\n+\tRTE_VERIFY(pinfo);\n+\n+\t/* Make sure the link is down. */\n+\tnet_cfg.is_up = 0;\n+\tec = expect(LINK_CHANGED, \"ip link set dev %s down\", pinfo->if_name);\n+\tRTE_VERIFY(ec == ETIMEDOUT || ec == 0);\n+\n+\tec = test_notifications(pinfo);\n+\tif (ec != 0) {\n+\t\tprintf(\"Failed test with callback based API\\n\");\n+\t\tgoto exit;\n+\t}\n+\t/* Switch to event queue based API and repeat tests. */\n+\tuse_callbacks = 0;\n+\tev_queue = rte_ring_create(\"IFPX-events\", 16, SOCKET_ID_ANY,\n+\t\t\t\t   RING_F_SP_ENQ | RING_F_SC_DEQ);\n+\tec = rte_ifpx_queue_add(ev_queue);\n+\tif (ec != 0) {\n+\t\tprintf(\"Failed to add a notification queue\\n\");\n+\t\tgoto exit;\n+\t}\n+\tec = test_notifications(pinfo);\n+\tif (ec != 0) {\n+\t\tprintf(\"Failed test with event queue based API\\n\");\n+\t\tgoto exit;\n+\t}\n+\n+exit:\n+\tpthread_mutex_unlock(&mutex);\n+\t/* Proxy ports are not owned by the lib.  Internal references to them\n+\t * are cleared on close, but the ports are not destroyed so we need to\n+\t * do that explicitly.\n+\t */\n+\trte_ifpx_proxy_destroy(proxy_id);\n+\trte_ifpx_close();\n+\t/* Queue is removed from the lib by rte_ifpx_close() - here we just\n+\t * free it.\n+\t */\n+\trte_ring_free(ev_queue);\n+\tev_queue = NULL;\n+\n+\treturn ec;\n+}\n+\n+REGISTER_TEST_COMMAND(if_proxy_autotest, test_if_proxy)\n",
    "prefixes": [
        "v2",
        "3/4"
    ]
}